diff options
-rw-r--r-- | recordmydesktop/ChangeLog | 1 | ||||
-rw-r--r-- | recordmydesktop/doc/recordmydesktop.1 | 11 | ||||
-rw-r--r-- | recordmydesktop/include/recordmydesktop.h | 61 | ||||
-rw-r--r-- | recordmydesktop/src/bgr_to_yuv.c | 29 | ||||
-rw-r--r-- | recordmydesktop/src/get_frame.c | 9 | ||||
-rw-r--r-- | recordmydesktop/src/parseargs.c | 6 | ||||
-rw-r--r-- | recordmydesktop/src/recordmydesktop.c | 4 | ||||
-rw-r--r-- | recordmydesktop/src/update_image.c | 25 |
8 files changed, 120 insertions, 26 deletions
diff --git a/recordmydesktop/ChangeLog b/recordmydesktop/ChangeLog index 0f06b4c..ac217b0 100644 --- a/recordmydesktop/ChangeLog +++ b/recordmydesktop/ChangeLog @@ -8,6 +8,7 @@ or missing pixels at borders has been corrected. *The option to drop frames has been added. *Default behavior now is to use shared memory when size of image gets over 75% of total (or a user set threshold). +*Many other minor bugfixes. diff --git a/recordmydesktop/doc/recordmydesktop.1 b/recordmydesktop/doc/recordmydesktop.1 index 0bffe9a..81d7e35 100644 --- a/recordmydesktop/doc/recordmydesktop.1 +++ b/recordmydesktop/doc/recordmydesktop.1 @@ -198,6 +198,11 @@ Image Options: .br .TP .B + \-\-no\-quick\-subsampling + Do subsampling of the chroma planes by averaging,not discarding extra pixels. +.br +.TP +.B \-fps N(number>0.0) A positive number denoting desired framerate. .br @@ -297,7 +302,7 @@ If no other option is specified, filename can be given without the \-o switch. .br \-\-nosound| \-\-with\-shared| \-\-no\-cond\-shared| \-shared\-threshold n| \-\-full\-shots| .br -\-\-scshot| \-scale\-shot N| \-o filename]^filename +\-\-no\-quick\-subsampling| \-\-scshot| \-scale\-shot N| \-o filename]^filename .br .br .br @@ -353,9 +358,7 @@ It can even perform resizing on the size of the recording, or change the overall .br .br .SH BUGS -Too resource intensive, straightforward subsampling of chroma plane degrades quality -.br -(though fixing this with averaraging would make the program even more cpu-hungry). +Too resource intensive. .br .SH AUTHORS John Varouhakis(biocrasher@gmail.com) diff --git a/recordmydesktop/include/recordmydesktop.h b/recordmydesktop/include/recordmydesktop.h index a3c9782..84b647b 100644 --- a/recordmydesktop/include/recordmydesktop.h +++ b/recordmydesktop/include/recordmydesktop.h @@ -115,6 +115,7 @@ typedef struct _ProgArgs{ int nocondshared; //de not use shared memory on large image aquititions 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 @@ -271,7 +272,8 @@ unsigned char Yr[256],Yg[256],Yb[256], =(args)->width=(args)->height=(args)->quietmode\ =(args)->nosound=(args)->scshot=(args)->full_shots=0;\ (args)->noshared=(args)->scale_shot=1;\ - (args)->dropframes=(args)->nocondshared=0;\ + (args)->dropframes=(args)->nocondshared==0;\ + (args)->no_quick_subsample=0;\ (args)->filename=(char *)malloc(8);\ strcpy((args)->filename,"out.ogg");\ (args)->encoding=OGG_THEORA_VORBIS;\ @@ -300,6 +302,10 @@ unsigned char Yr[256],Yg[256],Yb[256], (specstruct)->wpixel=XWhitePixel(display,(specstruct)->screen);\ } +#define AVG_4_PIXELS(data_array,width_img,k_tm,i_tm,offset)\ + ((data_array[(k_tm*width_img+i_tm)*4+offset]+data_array[((k_tm-1)*width_img+i_tm)*4+offset]\ + +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;k<y_tm+height_tm;k++){\ @@ -313,6 +319,27 @@ unsigned char Yr[256],Yg[256],Yb[256], }\ } +#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;k<y_tm+height_tm;k++){\ + for(i=x_tm;i<x_tm+width_tm;i++){\ + yuv->y[i+k*yuv->y_width]=Yr[data[(i+k*yuv->y_width)*4+2]] + Yg[data[(i+k*yuv->y_width)*4+1]] + Yb[data[(i+k*yuv->y_width)*4]];\ + if((k%2)&&(i%2)){\ + avg2=AVG_4_PIXELS(data,(yuv->y_width),k,i,2);\ + avg1=AVG_4_PIXELS(data,(yuv->y_width),k,i,1);\ + avg0=AVG_4_PIXELS(data,(yuv->y_width),k,i,0);\ + 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] ;\ + }\ + }\ + }\ +} + #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;\ @@ -331,6 +358,34 @@ unsigned char Yr[256],Yg[256],Yb[256], }\ } + + +#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;\ + for(k=0;k<height_tm;k++){\ + for(i=0;i<width_tm;i++){\ + yuv->y[x_tm+i+(k+y_tm)*yuv->y_width]=Yr[data[(j*4)+2]] + Yg[data[(j*4)+1]] + Yb[data[(j*4)]] ;\ + if((k%2)&&(i%2)){\ + avg2=AVG_4_PIXELS(data,width_tm,k,i,2);\ + avg1=AVG_4_PIXELS(data,width_tm,k,i,1);\ + avg0=AVG_4_PIXELS(data,width_tm,k,i,0);\ + 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++;\ + }\ + }\ +} + + + #define DUMMY_POINTER_TO_YUV(yuv,data_tm,x_tm,y_tm,width_tm,height_tm,no_pixel){\ int i,k,j=0;\ int x_2=x_tm/2,y_2=y_tm/2,y_width_2=(yuv)->y_width/2;\ @@ -362,8 +417,8 @@ int RectInsert(RectArea **root,WGeometry *wgeom); int CollideRects(WGeometry *wgeom1,WGeometry *wgeom2,WGeometry **wgeom_return,int *ngeoms); void SetExpired(int signum); void RegisterCallbacks(ProgArgs *args); -void UpdateImage(Display * dpy,yuv_buffer *yuv,pthread_mutex_t *yuv_mutex,DisplaySpecs *specs,RectArea **root,BRWindow *brwin,EncData *enc,char *datatemp,int noshmem); -void XImageToYUV(XImage *imgz,yuv_buffer *yuv); +void UpdateImage(Display * dpy,yuv_buffer *yuv,pthread_mutex_t *yuv_mutex,DisplaySpecs *specs,RectArea **root,BRWindow *brwin,EncData *enc,char *datatemp,int noshmem,int no_quick_subsample); +void XImageToYUV(XImage *imgz,yuv_buffer *yuv,int no_quick_subsample); int GetZPixmap(Display *dpy,Window root,char *data,int x,int y,int width,int height); int ParseArgs(int argc,char **argv,ProgArgs *arg_return); int QueryExtensions(Display *dpy,ProgArgs *args,int *damage_event,int *damage_error); diff --git a/recordmydesktop/src/bgr_to_yuv.c b/recordmydesktop/src/bgr_to_yuv.c index 81c7fed..d2b14f4 100644 --- a/recordmydesktop/src/bgr_to_yuv.c +++ b/recordmydesktop/src/bgr_to_yuv.c @@ -27,19 +27,34 @@ #include <recordmydesktop.h> -void XImageToYUV(XImage *imgz,yuv_buffer *yuv){ +void XImageToYUV(XImage *imgz,yuv_buffer *yuv,int no_quick_subsample){ unsigned char *dtap=(unsigned char *)imgz->data; + unsigned char avg2,avg1,avg0; int i,k,j=0; for(k=0;k<(imgz->width*imgz->height);k++){ yuv->y[k]=Yr[dtap[(k*4)+2]] + Yg[dtap[(k*4)+1]] + Yb[dtap[(k*4)]]; } - - for(i=0;i<(imgz->height);i+=2){ - for(k=0;k<(imgz->width);k+=2){ - yuv->u[j]=Ur[dtap[i*imgz->bytes_per_line+k*4+2]] + Ug[dtap[i*imgz->bytes_per_line+k*4+1]] + Ub[dtap[i*imgz->bytes_per_line+k*4]]; - yuv->v[j]=Vr[dtap[i*imgz->bytes_per_line+k*4+2]] + Vg[dtap[i*imgz->bytes_per_line+k*4+1]] + Vb[dtap[i*imgz->bytes_per_line+k*4]] ; - j++; + if(!no_quick_subsample){ + for(i=0;i<(imgz->height);i+=2){ + for(k=0;k<(imgz->width);k+=2){ + yuv->u[j]=Ur[dtap[i*imgz->bytes_per_line+k*4+2]] + Ug[dtap[i*imgz->bytes_per_line+k*4+1]] + Ub[dtap[i*imgz->bytes_per_line+k*4]]; + yuv->v[j]=Vr[dtap[i*imgz->bytes_per_line+k*4+2]] + Vg[dtap[i*imgz->bytes_per_line+k*4+1]] + Vb[dtap[i*imgz->bytes_per_line+k*4]] ; + j++; + } + } + } + else{ + for(i=0;i<(imgz->height);i+=2){ + for(k=0;k<(imgz->width);k+=2){ + avg2=AVG_4_PIXELS(dtap,(imgz->width),i,k,2); + avg1=AVG_4_PIXELS(dtap,(imgz->width),i,k,1); + avg0=AVG_4_PIXELS(dtap,(imgz->width),i,k,0); + + yuv->u[j]=Ur[avg2] + Ug[avg1] + Ub[avg0]; + yuv->v[j]=Vr[avg2] + Vg[avg1] + Vb[avg0] ; + j++; + } } } } diff --git a/recordmydesktop/src/get_frame.c b/recordmydesktop/src/get_frame.c index 1d6a126..6a93ceb 100644 --- a/recordmydesktop/src/get_frame.c +++ b/recordmydesktop/src/get_frame.c @@ -99,7 +99,8 @@ void *GetFrame(void *pdata){ &((ProgData *)pdata)->brwin, ((ProgData *)pdata)->enc_data, ((((ProgData *)pdata)->args.noshared)?(((ProgData *)pdata)->datatemp):((ProgData *)pdata)->shimage->data), - ((ProgData *)pdata)->args.noshared); + ((ProgData *)pdata)->args.noshared, + ((ProgData *)pdata)->args.no_quick_subsample); else{ if(((ProgData *)pdata)->args.noshared){ GetZPixmap( ((ProgData *)pdata)->dpy, @@ -110,12 +111,14 @@ void *GetFrame(void *pdata){ ((ProgData *)pdata)->brwin.rgeom.width, ((ProgData *)pdata)->brwin.rgeom.height); pthread_mutex_lock(&((ProgData *)pdata)->yuv_mutex); - XImageToYUV(((ProgData *)pdata)->image,&((ProgData *)pdata)->enc_data->yuv); + XImageToYUV(((ProgData *)pdata)->image,&((ProgData *)pdata)->enc_data->yuv, + ((ProgData *)pdata)->args.no_quick_subsample); pthread_mutex_unlock(&((ProgData *)pdata)->yuv_mutex); } else{ pthread_mutex_lock(&((ProgData *)pdata)->yuv_mutex); - XImageToYUV(((ProgData *)pdata)->shimage,&((ProgData *)pdata)->enc_data->yuv); + XImageToYUV(((ProgData *)pdata)->shimage,&((ProgData *)pdata)->enc_data->yuv, + ((ProgData *)pdata)->args.no_quick_subsample); pthread_mutex_unlock(&((ProgData *)pdata)->yuv_mutex); } } diff --git a/recordmydesktop/src/parseargs.c b/recordmydesktop/src/parseargs.c index 8125972..55dfbcd 100644 --- a/recordmydesktop/src/parseargs.c +++ b/recordmydesktop/src/parseargs.c @@ -36,7 +36,7 @@ int ParseArgs(int argc,char **argv,ProgArgs *arg_return){ "\t -v_quality n| -s_quality n| -v_bitrate n| --no-framedrop| -dummy-cursor color|\n" "\t --no-dummy-cursor| -freq N(number>0)| -channels N(number>0)| -device SOUND_DEVICE|\n" "\t --nosound| --with-shared| --no-cond-shared| -shared-threshold n| --full-shots|\n" - "\t --scshot| -scale-shot N| -o filename]^filename\n\n\n" + "\t --no-quick-subsampling| --scshot| -scale-shot N| -o filename]^filename\n\n\n" "General Options:\n" "\t-h or --help\t\tPrint this help and exit.\n" @@ -56,6 +56,7 @@ int ParseArgs(int argc,char **argv,ProgArgs *arg_return){ "\t--no-cond-shared\tDo not use the MIT-shared memory extension when aquiring large areas.\n" "\t-shared-threshold n\tThreshold over which shared memory is used(default 75).\n" "\t--full-shots\t\tTake full screenshot at every frame(Not recomended!).\n" + "\t--no-quick-subsampling\tDo subsampling of the chroma planes by averaging,not discarding.\n" "\t-fps N(number>0.0)\tA positive number denoting desired framerate.\n\n" "Sound Options:\n" @@ -397,6 +398,9 @@ int ParseArgs(int argc,char **argv,ProgArgs *arg_return){ arg_return->scshot=1; arg_return->nocondshared=1; } + else if(!strcmp(argv[i],"--no-quick-subsampling")){ + arg_return->no_quick_subsample=1; + } else if(!strcmp(argv[i],"--help")||!strcmp(argv[i],"-h")){ fprintf(stderr,"%s",usage); return 1; diff --git a/recordmydesktop/src/recordmydesktop.c b/recordmydesktop/src/recordmydesktop.c index 5588b52..9f6d596 100644 --- a/recordmydesktop/src/recordmydesktop.c +++ b/recordmydesktop/src/recordmydesktop.c @@ -140,9 +140,9 @@ int main(int argc,char **argv){ } InitEncoder(&pdata,&enc_data); if((pdata.args.nocondshared)&&(!pdata.args.noshared)) - XImageToYUV(pdata.shimage,&pdata.enc_data->yuv); + XImageToYUV(pdata.shimage,&pdata.enc_data->yuv,pdata.args.no_quick_subsample); else - XImageToYUV(pdata.shimage,&pdata.enc_data->yuv); + XImageToYUV(pdata.shimage,&pdata.enc_data->yuv,pdata.args.no_quick_subsample); pdata.frametime=(1000000)/pdata.args.fps; diff --git a/recordmydesktop/src/update_image.c b/recordmydesktop/src/update_image.c index bf319e2..0de3f0a 100644 --- a/recordmydesktop/src/update_image.c +++ b/recordmydesktop/src/update_image.c @@ -35,7 +35,8 @@ void UpdateImage(Display * dpy, BRWindow *brwin, EncData *enc, char *datatemp, - int noshmem){ + int noshmem, + int no_quick_subsample){ RectArea *temp; unsigned char *dtap=(unsigned char*)datatemp; temp=*root; @@ -52,18 +53,30 @@ void UpdateImage(Display * dpy, temp->geom.height); pthread_mutex_lock(yuv_mutex); - - UPDATE_YUV_BUFFER_IM(yuv,dtap, - (temp->geom.x-brwin->rgeom.x+enc->x_offset),(temp->geom.y-brwin->rgeom.y+enc->y_offset), - (temp->geom.width),(temp->geom.height)); + if(no_quick_subsample){ + UPDATE_YUV_BUFFER_IM_AVG(yuv,dtap, + (temp->geom.x-brwin->rgeom.x+enc->x_offset),(temp->geom.y-brwin->rgeom.y+enc->y_offset), + (temp->geom.width),(temp->geom.height)); + } + else{ + UPDATE_YUV_BUFFER_IM(yuv,dtap, + (temp->geom.x-brwin->rgeom.x+enc->x_offset),(temp->geom.y-brwin->rgeom.y+enc->y_offset), + (temp->geom.width),(temp->geom.height)); + } pthread_mutex_unlock(yuv_mutex); } else{ + if(no_quick_subsample){ + UPDATE_YUV_BUFFER_SH_AVG(yuv,dtap, + (temp->geom.x-brwin->rgeom.x+enc->x_offset),(temp->geom.y-brwin->rgeom.y+enc->y_offset), + (temp->geom.width),(temp->geom.height)); + } + else{ UPDATE_YUV_BUFFER_SH(yuv,dtap, (temp->geom.x-brwin->rgeom.x+enc->x_offset),(temp->geom.y-brwin->rgeom.y+enc->y_offset), (temp->geom.width),(temp->geom.height)); - + } } temp=temp->next; |