From ad5b05712d9ed8650fcc145373ac878f8e6b8829 Mon Sep 17 00:00:00 2001 From: iovar Date: Wed, 8 Nov 2006 16:26:44 +0000 Subject: Replaced all files with the ones in the rMD-exp module. (this should have been a branch not a module, but it's too late now. rMD-exp module will be purged but if anyone's interested on the not-so descriptive commit logs, they'll be on the attic. This is the start of the 0.3 branch. Files will will be tagged as v0_3_0 in a new branch before final release. Snapshot prior to this release has tagged as v0_2_7 in a new branch. All releases will be tagged and branched from now on. git-svn-id: https://recordmydesktop.svn.sourceforge.net/svnroot/recordmydesktop/trunk@153 f606c939-3180-4ac9-a4b8-4b8779d57d0a --- recordmydesktop/include/recordmydesktop.h | 397 ++++++++++++++++++++++++------ 1 file changed, 317 insertions(+), 80 deletions(-) (limited to 'recordmydesktop/include') diff --git a/recordmydesktop/include/recordmydesktop.h b/recordmydesktop/include/recordmydesktop.h index 4533b87..4c3ad18 100644 --- a/recordmydesktop/include/recordmydesktop.h +++ b/recordmydesktop/include/recordmydesktop.h @@ -37,7 +37,7 @@ #include #include #include -#include +#include #include #include #include @@ -49,8 +49,10 @@ #include #include #include +#include #include #include +#include #include #include #include @@ -67,18 +69,29 @@ #define __RBYTE 2 #define __GBYTE 1 #define __BBYTE 0 + +#define __RVALUE(tmp_val) (((tmp_val)&0x00ff0000)>>16) +#define __GVALUE(tmp_val) (((tmp_val)&0x0000ff00)>>8) +#define __BVALUE(tmp_val) (((tmp_val)&0x000000ff)) + #elif __BYTE_ORDER == __BIG_ENDIAN + #define __ABYTE 0 #define __RBYTE 1 #define __GBYTE 2 #define __BBYTE 3 + +#define __RVALUE(tmp_val) (((tmp_val)&0x0000ff00)>>8) +#define __GVALUE(tmp_val) (((tmp_val)&0x00ff0000)>>16) +#define __BVALUE(tmp_val) (((tmp_val)&0xff000000)>>24) + #else #error Only little-endian and big-endian systems are supported #endif //do not be confused -//this is useless and obsolete. +//this is useless and obsolete. //There are no plans for other fotmats enum {UNSPECIFIED,OGG_THEORA_VORBIS}; @@ -86,7 +99,7 @@ enum {UNSPECIFIED,OGG_THEORA_VORBIS}; /**Structs*/ typedef struct _DisplaySpecs{ //this struct holds some basic information - int screen; //about the display,needed mostly for + int screen; //about the display,needed mostly for uint width; //validity checks at startup uint height; Window root; @@ -102,7 +115,7 @@ typedef struct _WGeometry{ //basic geometry of a window or area int y; int width; int height; -}WGeometry; +}WGeometry; typedef struct _RectArea{ //an area that has been damaged gets stored WGeometry geom; //in a list comprised of structs of this type @@ -129,7 +142,7 @@ typedef struct _ProgArgs{ int encoding; //encoding(default OGG_THEORA_VORBIS) int cursor_color; //black or white=>1 or 0 int have_dummy_cursor;//disable/enable drawing of the dummy cursor - int xfixes_cursor; //disable/enable drawing of a cursor obtained + int xfixes_cursor; //disable/enable drawing of a cursor obtained //through the xfixes extension float fps; //desired framerate(default 15) unsigned int frequency; //desired frequency (default 22050) @@ -137,23 +150,27 @@ typedef struct _ProgArgs{ char *device; //default sound device(default according to alsa or oss) int nosound; //do not record sound(default 0) int noshared; //do not use shared memory extension(default 1) - int nocondshared; //de not use shared memory on large image aquititions + int nocondshared; //do not use shared memory on large image aquititions + int nowmcheck; //do not check if there's a 3d comp window manager + //(which changes full-shots and with-shared to 1) int shared_thres; //threshold to use shared memory int full_shots; //do not poll damage, take full screenshots int no_quick_subsample;//average pixels in chroma planes - int scshot; //take screenshot and exit(default 0) - int scale_shot; //screenshot subscale factor(default 1) int v_bitrate,v_quality,s_quality;//video bitrate,video-sound quality int dropframes; //option for theora encoder + int encOnTheFly; //encode while recording, no caching(default 0) + char *workdir; //directory to be used for cache files(default $HOME) + int zerocompression;//image data are always flushed uncompressed + int overwrite;//overwite a previously existing file(do not add a .number postfix) }ProgArgs; -//this struct holds anything related to encoding AND -//writting out to file. +//this struct holds anything related to encoding AND +//writting out to file. typedef struct _EncData{ ogg_stream_state m_ogg_ts;//theora ogg_stream_state m_ogg_vs;//vorbis - ogg_page m_ogg_pg;//this could be avoided since + ogg_page m_ogg_pg;//this could be avoided since // it is used only while initializing ogg_packet m_ogg_pckt1;//theora stream ogg_packet m_ogg_pckt2;//vorbis stream @@ -165,7 +182,7 @@ typedef struct _EncData{ //vorbis data vorbis_info m_vo_inf; vorbis_comment m_vo_cmmnt; - vorbis_dsp_state m_vo_dsp; + vorbis_dsp_state m_vo_dsp; vorbis_block m_vo_block; //these should be 0, since area is quantized //before input @@ -175,8 +192,27 @@ typedef struct _EncData{ FILE *fp; }EncData; +//this struct will hold a few basic +//information, needed for caching the frames. +typedef struct _CacheData{ + char *workdir, //The directory were the project will be stored, while recording. + //Since this will take a lot of space, the user must be + //able to change the location. + *projname, //This is the name of the folder that will hold the project. + //It is rMD-session-%d where %d is the pid of the current proccess. + //This way, running two instances will not create problems + //and also, a frontend can identify leftovers from a possible crash + //and delete them + *imgdata, //workdir+projname+img.out.gz + *audiodata; //workdir+projname+audio.pcm + + gzFile *ifp; //image data file pointer + FILE *afp; //audio data file pointer + +}CacheData; + //sound buffer -//sound keeps coming so we que it in this list +//sound keeps coming so we que it in this list //which we then traverse typedef struct _SndBuffer{ signed char *data; @@ -184,23 +220,24 @@ typedef struct _SndBuffer{ }SndBuffer; //this structure holds any data related to the program -//It's usage is mostly to be given as an argument to the -//threads,so they will have access to the program data, avoiding -//at the same time usage of any globals. +//It's usage is mostly to be given as an argument to the +//threads,so they will have access to the program data, avoiding +//at the same time usage of any globals. typedef struct _ProgData{ ProgArgs args;//the program arguments DisplaySpecs specs;//Display specific information BRWindow brwin;//recording window Display *dpy;//curtrent display + char *window_manager;//name of the window manager at program launch XImage *image;//the image that holds the current full screenshot XImage *shimage;//the image that holds the current full screenshot(shared memory) unsigned char *dummy_pointer;//a dummy pointer to be drawn in every frame //data is casted to unsigned for later use in YUV buffer int dummy_p_size;//initially 16x16,always square unsigned char npxl;//this is the no pixel convention when drawing the dummy pointer - char *datamain,//the data of image + char *datamain,//the data of image *datash,//the data of shimage - *datatemp;//buffer for the temporary image,which will be + *datatemp;//buffer for the temporary image,which will be //preallocated in case shared memory is not used. RectArea *rect_root[2];//the interchanging list roots for storing the changed regions int list_selector,//selector for the above @@ -209,6 +246,7 @@ typedef struct _ProgData{ running; SndBuffer *sound_buffer; EncData *enc_data; + CacheData *cache_data; int hard_pause;//if sound device doesn't support pause //we have to close and reopen int avd;//syncronization among audio and video @@ -217,7 +255,7 @@ typedef struct _ProgData{ pthread_mutex_t list_mutex[2],//mutexes for concurrency protection of the lists sound_buffer_mutex, libogg_mutex,//libogg is not thread safe - yuv_mutex;//this might not be needed since we only have + yuv_mutex;//this might not be needed since we only have //one read-only and one write-only thread //also on previous versions, y component was looped separately //and then u and v so this was needed to avoid wrong coloring to render @@ -231,6 +269,48 @@ typedef struct _ProgData{ snd_pcm_uframes_t periodsize; }ProgData; + +//This is the header of every frame. +//Reconstruction will be correct only if made on +//the same platform. + +//We need the total number of blocks +//for each plane. + +//The number of the frame compared to the +//number of time expirations at the time of +//caching, will enable us to make up for lost frames. + +//default 4+4+2+2+2=14!bad! +//me add pad, make god of 2 happy! +typedef struct _FrameHeader{ + char frame_prefix[4];//always FRAM + u_int32_t frameno,//number of frame(cached frames) + current_total;//number of frames that should have been + //taken at time of caching this one + u_int16_t Ynum,//number of changed blocks in the Y plane + Unum,//number of changed blocks in the U plane + Vnum;//number of changed blocks in the V plane + u_int16_t pad;//always zero + +}FrameHeader; + +//The frame after retrieval. +//Based on the Header information +//we can read the correct amount of bytes. + + +typedef struct _CachedFrame{ + FrameHeader *header; + unsigned char *YBlocks;//identifying number on the grid, starting at top left + unsigned char *UBlocks;// >> >> + unsigned char *VBlocks;// >> >> + unsigned char *YData;//pointer to data for the blocks that have changed, + unsigned char *UData;//which have to be remapped on the buffer when reading + unsigned char *VData; +}CachedFrame; + + /**Globals*/ //I've read somewhere that I'll go to hell for using globals... @@ -241,9 +321,9 @@ unsigned char Yr[256],Yg[256],Yb[256], Vr[256],Vg[256],Vb[256]; //the following values are of no effect //but they might be usefull later for profiling -unsigned int frames_total,//frames calculated by total time expirations - frames_lost;//the value of shame -//used to determine frame drop which can +unsigned int frames_total,//frames calculated by total time expirations + frames_lost;//the value of shame +//used to determine frame drop which can //happen on failure to receive a signal over a condition variable int capture_busy, encoder_busy; @@ -318,8 +398,10 @@ int capture_busy, (args)->display=NULL;\ (args)->windowid=(args)->x=(args)->y\ =(args)->width=(args)->height=(args)->quietmode\ - =(args)->nosound=(args)->scshot=(args)->full_shots=0;\ - (args)->noshared=(args)->scale_shot=1;\ + =(args)->nosound=(args)->full_shots=(args)->encOnTheFly\ + =(args)->zerocompression=(args)->nowmcheck\ + =(args)->overwrite=0;\ + (args)->noshared=1;\ (args)->dropframes=(args)->nocondshared=0;\ (args)->no_quick_subsample=1;\ (args)->filename=(char *)malloc(8);\ @@ -337,6 +419,8 @@ int capture_busy, (args)->v_bitrate=45000;\ (args)->v_quality=63;\ (args)->s_quality=10;\ + (args)->workdir=(char *)malloc(strlen(getenv("HOME"))+1);\ + strcpy((args)->workdir,getenv("HOME"));\ } #define QUERY_DISPLAY_SPECS(display,specstruct){\ @@ -356,83 +440,193 @@ int capture_busy, +data_array[(k_tm*width_img+i_tm-1)*4+offset]+data_array[((k_tm-1)*width_img+i_tm-1)*4+offset])/4) #define UPDATE_YUV_BUFFER_SH(yuv,data,x_tm,y_tm,width_tm,height_tm){\ - int i,k;\ - for(k=y_tm;ky[i+k*yuv->y_width]=Yr[data[(i+k*yuv->y_width)*4+__RBYTE]] + Yg[data[(i+k*yuv->y_width)*4+__GBYTE]] + Yb[data[(i+k*yuv->y_width)*4+__BBYTE]];\ - if((k%2)&&(i%2)){\ - yuv->u[i/2+k/2*yuv->uv_width]=Ur[data[(i+k*yuv->y_width)*4+__RBYTE]] + Ug[data[(i+k*yuv->y_width)*4+__GBYTE]] + Ub[data[(i+k*yuv->y_width)*4+__BBYTE]] ;\ - yuv->v[i/2+k/2*yuv->uv_width]=Vr[data[(i+k*yuv->y_width)*4+__RBYTE]] + Vg[data[(i+k*yuv->y_width)*4+__GBYTE]] + Vb[data[(i+k*yuv->y_width)*4+__BBYTE]] ;\ - }\ + int k,i;\ + register unsigned int t_val;\ + register unsigned int *datapi=(unsigned int*)data+x_tm+y_tm*yuv->y_width;\ + register unsigned char *yuv_y=yuv->y+x_tm+y_tm*yuv->y_width,\ + *yuv_u=yuv->u+x_tm/2+(y_tm*yuv->uv_width)/2,\ + *yuv_v=yuv->v+x_tm/2+(y_tm*yuv->uv_width)/2,\ + *_yr=Yr,*_yg=Yg,*_yb=Yb,\ + *_ur=Ur,*_ug=Ug,*_ub=Ub,\ + *_vr=Vr,*_vg=Vg,*_vb=Vb;\ +\ + for(k=0;ky_width-width_tm;\ + datapi+=yuv->y_width-width_tm;\ + }\ + datapi=(unsigned int*)data+x_tm+y_tm*yuv->y_width;\ + for(k=0;ky_width-width_tm)/2;\ + yuv_v+=(yuv->y_width-width_tm)/2;\ + datapi+=(2*yuv->y_width-width_tm);\ }\ } #define UPDATE_YUV_BUFFER_SH_AVG(yuv,data,x_tm,y_tm,width_tm,height_tm){\ - int i,k;\ - unsigned char avg0,avg1,avg2;\ - for(k=y_tm;ky[i+k*yuv->y_width]=Yr[data[(i+k*yuv->y_width)*4+__RBYTE]] + Yg[data[(i+k*yuv->y_width)*4+__GBYTE]] + Yb[data[(i+k*yuv->y_width)*4+__BBYTE]];\ - if((k%2)&&(i%2)){\ - avg2=AVG_4_PIXELS(data,(yuv->y_width),k,i,__RBYTE);\ - avg1=AVG_4_PIXELS(data,(yuv->y_width),k,i,__GBYTE);\ - avg0=AVG_4_PIXELS(data,(yuv->y_width),k,i,__BBYTE);\ - yuv->u[i/2+k/2*yuv->uv_width]=Ur[avg2] +\ - Ug[avg1] +\ - Ub[avg0] ;\ - yuv->v[i/2+k/2*yuv->uv_width]=Vr[avg2] +\ - Vg[avg1] +\ - Vb[avg0] ;\ - }\ + int k,i;\ + register unsigned int t_val,t1,t2,t3,t4;\ + register unsigned int *datapi=(unsigned int*)data+x_tm+y_tm*yuv->y_width,\ + *datapi_next=(unsigned int*)data+x_tm+(y_tm+1)*yuv->y_width;\ + register unsigned char *yuv_y=yuv->y+x_tm+y_tm*yuv->y_width,\ + *yuv_u=yuv->u+x_tm/2+(y_tm*yuv->uv_width)/2,\ + *yuv_v=yuv->v+x_tm/2+(y_tm*yuv->uv_width)/2,\ + *_yr=Yr,*_yg=Yg,*_yb=Yb,\ + *_ur=Ur,*_ug=Ug,*_ub=Ub,\ + *_vr=Vr,*_vg=Vg,*_vb=Vb;\ +\ + for(k=0;ky_width-width_tm;\ + datapi+=yuv->y_width-width_tm;\ + }\ + datapi=(unsigned int*)data+x_tm+y_tm*yuv->y_width;\ + for(k=0;ky_width-width_tm)/2;\ + yuv_v+=(yuv->y_width-width_tm)/2;\ + datapi+=(2*yuv->y_width-width_tm);\ + datapi_next+=(2*yuv->y_width-width_tm);\ }\ } + + #define UPDATE_YUV_BUFFER_IM(yuv,data,x_tm,y_tm,width_tm,height_tm){\ - int i,k,j=0;\ - int x_2=x_tm/2,y_2=y_tm/2;\ + int k,i;\ + register unsigned int t_val;\ + register unsigned int *datapi=(unsigned int*)data;\ + register unsigned char *yuv_y=yuv->y+x_tm+y_tm*yuv->y_width,\ + *yuv_u=yuv->u+x_tm/2+(y_tm*yuv->uv_width)/2,\ + *yuv_v=yuv->v+x_tm/2+(y_tm*yuv->uv_width)/2,\ + *_yr=Yr,*_yg=Yg,*_yb=Yb,\ + *_ur=Ur,*_ug=Ug,*_ub=Ub,\ + *_vr=Vr,*_vg=Vg,*_vb=Vb;\ +\ for(k=0;ky[x_tm+i+(k+y_tm)*yuv->y_width]=Yr[data[(j*4)+__RBYTE]] + Yg[data[(j*4)+__GBYTE]] + Yb[data[(j*4)+__BBYTE]] ;\ - if((k%2)&&(i%2)){\ - yuv->u[x_2+i/2+(k/2+y_2)*yuv->uv_width]=\ - Ur[data[(k*width_tm+i)*4+__RBYTE]] + Ug[data[(k*width_tm+i)*4+__GBYTE]] + Ub[data[(k*width_tm+i)*4+__BBYTE]];\ - yuv->v[x_2+i/2+(k/2+y_2)*yuv->uv_width]=\ - Vr[data[(k*width_tm+i)*4+__RBYTE]] + Vg[data[(k*width_tm+i)*4+__GBYTE]] + Vb[data[(k*width_tm+i)*4+__BBYTE]];\ - }\ - \ - j++;\ + t_val=*datapi;\ + *yuv_y=_yr[__RVALUE(t_val)] + _yg[__GVALUE(t_val)] + _yb[__BVALUE(t_val)] ;\ + datapi++;\ + yuv_y++;\ }\ + yuv_y+=yuv->y_width-width_tm;\ + }\ + datapi=(unsigned int*)data;\ + for(k=0;ky_width-width_tm)/2;\ + yuv_v+=(yuv->y_width-width_tm)/2;\ + datapi+=width_tm;\ }\ } - - #define UPDATE_YUV_BUFFER_IM_AVG(yuv,data,x_tm,y_tm,width_tm,height_tm){\ - int i,k,j=0;\ - unsigned char avg0,avg1,avg2;\ - int x_2=x_tm/2,y_2=y_tm/2;\ + int k,i;\ + register unsigned int t_val,t1,t2,t3,t4;\ + register unsigned int *datapi=(unsigned int*)data,\ + *datapi_next=(unsigned int*)data+width_tm;\ + register unsigned char *yuv_y=yuv->y+x_tm+y_tm*yuv->y_width,\ + *yuv_u=yuv->u+x_tm/2+(y_tm*yuv->uv_width)/2,\ + *yuv_v=yuv->v+x_tm/2+(y_tm*yuv->uv_width)/2,\ + *_yr=Yr,*_yg=Yg,*_yb=Yb,\ + *_ur=Ur,*_ug=Ug,*_ub=Ub,\ + *_vr=Vr,*_vg=Vg,*_vb=Vb;\ +\ for(k=0;ky[x_tm+i+(k+y_tm)*yuv->y_width]=Yr[data[(j*4)+__RBYTE]] + Yg[data[(j*4)+__GBYTE]] + Yb[data[(j*4)+__BBYTE]] ;\ - if((k%2)&&(i%2)){\ - avg2=AVG_4_PIXELS(data,width_tm,k,i,__RBYTE);\ - avg1=AVG_4_PIXELS(data,width_tm,k,i,__GBYTE);\ - avg0=AVG_4_PIXELS(data,width_tm,k,i,__BBYTE);\ - yuv->u[x_2+i/2+(k/2+y_2)*yuv->uv_width]=\ - Ur[avg2] + Ug[avg1] +\ - Ub[avg0];\ - yuv->v[x_2+i/2+(k/2+y_2)*yuv->uv_width]=\ - Vr[avg2] + Vg[avg1] +\ - Vb[avg0];\ - }\ - \ - j++;\ + t_val=*datapi;\ + *yuv_y=_yr[__RVALUE(t_val)] + _yg[__GVALUE(t_val)] + _yb[__BVALUE(t_val)] ;\ + datapi++;\ + yuv_y++;\ }\ + yuv_y+=yuv->y_width-width_tm;\ + }\ + datapi=(unsigned int*)data;\ + for(k=0;ky_width-width_tm)/2;\ + yuv_v+=(yuv->y_width-width_tm)/2;\ + datapi+=width_tm;\ + datapi_next+=width_tm;\ }\ } + + #define XFIXES_POINTER_TO_YUV(yuv,data,x_tm,y_tm,width_tm,height_tm,column_discard_stride){\ int i,k,j=0;\ unsigned char avg0,avg1,avg2,avg3;\ @@ -479,6 +673,42 @@ int capture_busy, } +#define I16TOA(number,buffer){\ + int t_num=(number),k=0,i=0;\ + char *t_buf=malloc(8);\ + t_num=t_num&((2<<15)-1);\ + while(t_num>0){\ + int digit=t_num%10;\ + t_buf[k]=digit+48;\ + t_num-=digit;\ + t_num/=10;\ + k++;\ + }\ + while(k>0)\ + (buffer)[i++]=t_buf[--k];\ + (buffer)[i]='\0';\ + free(t_buf);\ +};\ + +#define INIT_FRAME(frame_t,fheader_t,yuv_t){\ + (frame_t)->header=(fheader_t);\ + (frame_t)->YBlocks=malloc(256);\ + (frame_t)->UBlocks=malloc(64);\ + (frame_t)->VBlocks=malloc(64);\ + (frame_t)->YData=malloc((yuv_t)->y_width*(yuv_t)->y_height);\ + (frame_t)->UData=malloc((yuv_t)->uv_width*(yuv_t)->uv_height);\ + (frame_t)->VData=malloc((yuv_t)->uv_width*(yuv_t)->uv_height);\ +}; + +#define CLEAR_FRAME(frame_t){\ + free((frame_t)->YBlocks);\ + free((frame_t)->UBlocks);\ + free((frame_t)->VBlocks);\ + free((frame_t)->YData);\ + free((frame_t)->UData);\ + free((frame_t)->VData);\ +}; + /**Function prototypes*/ void *PollDamage(void *pdata); @@ -496,13 +726,20 @@ int GetZPixmap(Display *dpy,Window root,char *data,int x,int y,int width,int hei int ParseArgs(int argc,char **argv,ProgArgs *arg_return); void QueryExtensions(Display *dpy,ProgArgs *args,int *damage_event,int *damage_error); int SetBRWindow(Display *dpy,BRWindow *brwin,DisplaySpecs *specs,ProgArgs *args); -int ZPixmapToBMP(XImage *imgz,BRWindow *brwin,char *fname,int nbytes,int scale); unsigned char *MakeDummyPointer(DisplaySpecs *specs,int size,int color,int type,unsigned char *npxl); void *CaptureSound(void *pdata); void *EncodeSoundBuffer(void *pdata); snd_pcm_t *OpenDev(const char *pcm_dev,unsigned int *channels,unsigned int *frequency,snd_pcm_uframes_t *periodsize,unsigned int *periodtime,int *hardpause); -void InitEncoder(ProgData *pdata,EncData *enc_data_t); +void InitEncoder(ProgData *pdata,EncData *enc_data_t,int buffer_ready); void MakeMatrices(); void SizePack2_8_16(int *start,int *size,int limit); +void *CacheImageBuffer(void *pdata); +void InitCacheData(ProgData *pdata,EncData *enc_data_t,CacheData *cache_data_t); +void *CacheSoundBuffer(void *pdata); +void *LoadCache(void *pdata); +void SyncEncodeImageBuffer(ProgData *pdata); +void CancelTimer(void); +void SyncEncodeSoundBuffer(ProgData *pdata,signed char *buff); +char *rmdWMCheck(Display *dpy,Window root); #endif -- cgit v1.2.1