Carpe diem, c'est la vie.
Posts: 6,433
Karma: 10773668
Join Date: Nov 2011
Location: Multiverse 6627A
Device: K1 to PW3
|
Movies with sound, coming soon to a kindle near you!
This is a "Work In Progress". It is gmplay 2.0 (now with sound). This is just a demo showing multithreaded sound and video. The main thread is where future GUI stuff will go. The video thread exits after the video is done playing. The audio continues indefinately, until killed when the main program exits.
The sound in this demo is synthesized, as described in the "noisy rhythms" demo in the "geekmaster's sound demos" thread).
The next step is to add sound to the .gmv.gz movie files, and replace synthesized sound with recorded sound.
On a K3, if you get periodic sound dropouts, turn down your sound a bit with the Vol- button.
PHP Code:
//==================================================== // gmplay 2.0 - geekmaster's kindle video player // Copyright (C) 2012 by geekmaster, with MIT license: // http://www.opensource.org/licenses/mit-license.php // This version has algorithmically synthesized sound! //---------------------------------------------------- // Tested on DX,DXG,K3,K4main,K4diags,K5main,K5diags. //---------------------------------------------------- #include <pthread.h> // pthread_ #include <asoundlib.h> // snd_pcm_ #include <sys/ioctl.h> // ioctl #include <sys/mman.h> // mmap, munmap #include <stdio.h> // printf #include <stdlib.h> // malloc, free #include <linux/fb.h> // screeninfo #include <sys/time.h> // gettimeofday #include <unistd.h> // usleep #include <string.h> // memset, memcpy #include <fcntl.h> // open, close, write #include <time.h> // time typedef unsigned long u64; typedef unsigned int u32; typedef unsigned short u16; typedef unsigned char u8; u32 __invalid_size_argument_for_IOC; // ioctl.h bug fix for tcc //----- eink definitions from eink_fb.h and mxcfb.h ----- #define EU3 0x46dd #define EU50 0x4040462e #define EU51 0x4048462e struct update_area_t {int x1,y1,x2,y2,which_fx;u8 *buffer;}; struct mxcfb_rect {u32 top,left,width,height;}; struct mxcfb_alt_buffer_data {u32 phys_addr,width,height; struct mxcfb_rect alt_update_region;}; struct mxcfb_update_data {struct mxcfb_rect update_region; u32 waveform_mode,update_mode,update_marker;int temp;uint flags; struct mxcfb_alt_buffer_data alt_buffer_data;}; struct mxcfb_update_data51 {struct mxcfb_rect update_region; u32 waveform_mode,update_mode,update_marker; u32 hist_bw_waveform_mode,hist_gray_waveform_mode; int temp;uint flags;struct mxcfb_alt_buffer_data alt_buffer_data;}; //----- function prototypes ----- void sndplay(void); void gmplay4(void); void gmplay8(void); int getmsec(void); int gmlib(int); //----- gmlib global vars ----- enum GMLIB_op {GMLIB_INIT,GMLIB_CLOSE,GMLIB_UPDATE,GMLIB_VSYNC}; snd_pcm_t *hp; // sound play handle u8 *fb0=NULL; // framebuffer pointer int fdFB=0; // fb0 file descriptor int teu=0; // eink update time u32 fs=0; // fb0 stride u32 MX=0; // xres (visible) u32 MY=0; // yres (visible) u32 VY=0; // (VY>MY): mxcfb driver u8 ppb=0; // pixels per byte u32 fc=0; // frame counter #define FBSIZE (600/8*800) //============================ // sndplay - play sound buffer // this plays until we kill it //---------------------------- void sndplay(void) { unsigned char buf[1024]; // play buffer snd_pcm_sframes_t fc; // frame count unsigned int i,j; for (i=0;;i++) { // forever for (j=0;j<sizeof(buf);j++) buf[j]=(random()&3)*i*350; fc=snd_pcm_writei(hp,buf,sizeof(buf)); // play buffer if (fc<0) fc=snd_pcm_recover(hp,fc,0); // error recovery } } //================================== // gmplay4 - play video on 4-bit fb0 //---------------------------------- void gmplay4(void) { u32 i,x,y,b,p,off=(MY/2-400)*fs+MX/4-150,fbsize=FBSIZE; u8 fbt[FBSIZE]; while (fread(fbt,fbsize,1,stdin)) { teu+=130; // teu: next update time if (getmsec()>teu+1000) continue; // drop frame if > 1 sec behind gmlib(GMLIB_VSYNC); // wait for fb0 ready for (y=0;y<800;y++) for (x=0;x<600;x+=8) { b=fbt[600/8*y+x/8]; i=y*fs+x/2+off; p=(b&1)*240; b>>=1; fb0[i]=p|(b&1)*15; b>>=1; p=(b&1)*240; b>>=1; fb0[i+1]=p|(b&1)*15; b>>=1; p=(b&1)*240; b>>=1; fb0[i+2]=p|(b&1)*15; b>>=1; p=(b&1)*240; b>>=1; fb0[i+3]=p|(b&1)*15; } fc++; gmlib(GMLIB_UPDATE); } } //================================== // gmplay8 - play video on 8-bit fb0 //---------------------------------- void gmplay8(void) { u32 i,x,y,b,fbsize=FBSIZE; u8 fbt[FBSIZE]; while (fread(fbt,fbsize,1,stdin)) { teu+=130; // teu: next update time if (getmsec()>teu+1000) continue; // drop frame if > 1 sec behind gmlib(GMLIB_VSYNC); // wait for fb0 ready for (y=0;y<800;y++) for (x=0;x<600;x+=8) { b=fbt[600/8*y+x/8]; i=y*fs+x; fb0[i]=(b&1)*255; b>>=1; fb0[i+1]=(b&1)*255; b>>=1; fb0[i+2]=(b&1)*255; b>>=1; fb0[i+3]=(b&1)*255; b>>=1; fb0[i+4]=(b&1)*255; b>>=1; fb0[i+5]=(b&1)*255; b>>=1; fb0[i+6]=(b&1)*255; b>>=1; fb0[i+7]=(b&1)*255; } fc++; gmlib(GMLIB_UPDATE); } } //==================================== // gmlib - geekmaster function library // op (init, update, vsync, close) //------------------------------------ int gmlib(int op) { static struct update_area_t ua={0,0,600,800,21,NULL}; static struct mxcfb_update_data ur={ {0,0,600,800},257,0,1,0x1001,0,{0,0,0,{0,0,0,0}}}; static struct mxcfb_update_data51 ur51={ {0,0,600,800},257,0,1,0,0,0x1001,0,{0,0,0,{0,0,0,0}}}; static int eupcode; static void *eupdata=NULL; struct fb_var_screeninfo screeninfo; if (GMLIB_INIT==op) { teu=getmsec(); fdFB=open("/dev/fb0",O_RDWR); snd_pcm_open(&hp,"default",SND_PCM_STREAM_PLAYBACK,0); snd_pcm_set_params(hp,SND_PCM_FORMAT_U8, SND_PCM_ACCESS_RW_INTERLEAVED,1,8000,1,500000); // 0.5 sec latency ioctl(fdFB,FBIOGET_VSCREENINFO,&screeninfo); ppb=8/screeninfo.bits_per_pixel; fs=screeninfo.xres_virtual/ppb; VY=screeninfo.yres_virtual; MX=screeninfo.xres; MY=screeninfo.yres; ua.x2=MX; ua.y2=MY; ur.update_region.width=MX; ur.update_region.height=MY; fb0=(u8 *)mmap(0,MY*fs,PROT_READ|PROT_WRITE,MAP_SHARED,fdFB,0); // map fb0 if (VY>MY) { eupcode=EU50; eupdata=&ur; ur.update_mode=0; if (ioctl(fdFB,eupcode,eupdata)<0) { eupcode=EU51; eupdata=&ur51; } } else { eupcode=EU3; eupdata=&ua; } system("eips -f -c;eips -c"); sleep(1); } else if (GMLIB_UPDATE==op) { if (ioctl(fdFB,eupcode,eupdata)<0) system("eips ''"); // 5.1.0 fallback } else if (GMLIB_VSYNC==op) { while (teu>getmsec()) usleep(1000); // fb0 busy } else if (GMLIB_CLOSE==op) { gmlib(GMLIB_UPDATE); sleep(1); // last screen system("eips -f -c;eips -c"); munmap(fb0,MY*fs); close(fdFB); snd_pcm_close(hp); } else { return -1; } return 0; } //==================================== // getmsec - get msec since first call // (tick counter wraps every 12 days) //------------------------------------ int getmsec(void) { int tc; static int ts=0; struct timeval tv; gettimeofday(&tv,NULL); tc=tv.tv_usec/1000+1000*(0xFFFFF&tv.tv_sec); if (0==ts) ts=tc; return tc-ts; } //================== // main - start here //------------------ int main(void) { pthread_t athread,vthread; int i; gmlib(GMLIB_INIT); pthread_create(&athread,NULL,(void *)sndplay,NULL); pthread_create(&vthread,NULL,(void *)(ppb-1?gmplay4:gmplay8),NULL); pthread_join(vthread,NULL); // wait vthread done i=getmsec()/100; printf("%d frames in %0.1f secs = %2.1f FPS\n", fc,(double)i/10.0,(double)fc*10.0/i); gmlib(GMLIB_CLOSE); return 0; }
Last edited by geekmaster; 07-17-2012 at 10:31 PM.
|