diff options
author | enselic <enselic@f606c939-3180-4ac9-a4b8-4b8779d57d0a> | 2008-09-14 13:06:20 +0000 |
---|---|---|
committer | enselic <enselic@f606c939-3180-4ac9-a4b8-4b8779d57d0a> | 2008-09-14 13:06:20 +0000 |
commit | e5cdc6d4fbec00a52d06414ca243664bb8b40942 (patch) | |
tree | 60f4145527722c135e72cbe451b63f7499dd32a5 /recordmydesktop/src/rmd_get_frame.c | |
parent | 187945d42050c99c614ccf76099944b338461a19 (diff) |
src/*.[ch]: Rename files so that the name becomes
rmd_some_file.[ch]. The exceptions are recordmydesktop.c which is the
main file and skeleton.[ch] which are external files.
src/Makefile.am: Adapt.
git-svn-id: https://recordmydesktop.svn.sourceforge.net/svnroot/recordmydesktop/trunk@546 f606c939-3180-4ac9-a4b8-4b8779d57d0a
Diffstat (limited to 'recordmydesktop/src/rmd_get_frame.c')
-rw-r--r-- | recordmydesktop/src/rmd_get_frame.c | 669 |
1 files changed, 669 insertions, 0 deletions
diff --git a/recordmydesktop/src/rmd_get_frame.c b/recordmydesktop/src/rmd_get_frame.c new file mode 100644 index 0000000..045368c --- /dev/null +++ b/recordmydesktop/src/rmd_get_frame.c @@ -0,0 +1,669 @@ +/****************************************************************************** +* recordMyDesktop * +******************************************************************************* +* * +* Copyright (C) 2006,2007,2008 John Varouhakis * +* * +* * +* This program is free software; you can redistribute it and/or modify * +* it under the terms of the GNU General Public License as published by * +* the Free Software Foundation; either version 2 of the License, or * +* (at your option) any later version. * +* * +* This program is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* GNU General Public License for more details. * +* * +* You should have received a copy of the GNU General Public License * +* along with this program; if not, write to the Free Software * +* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * +* * +* * +* * +* For further information contact me at johnvarouhakis@gmail.com * +******************************************************************************/ + +#include "config.h" + +#include <limits.h> +#include <pthread.h> +#include <sys/shm.h> + +#include <X11/extensions/Xfixes.h> +#include <X11/extensions/XShm.h> + +#include "rmd_types.h" + +#include "rmd_cache.h" +#include "rmd_frame.h" +#include "rmd_get_frame.h" +#include "rmd_getzpixmap.h" +#include "rmd_poll_events.h" +#include "rmd_rectinsert.h" +#include "rmd_update_image.h" +#include "rmd_yuv_utils.h" + + +#define AVG_4_PIXELS(data_array,width_img,k_tm,i_tm,offset)\ + ((data_array[(k_tm*width_img+i_tm)*RMD_ULONG_SIZE_T+offset]+\ + data_array[((k_tm-1)*width_img+i_tm)*RMD_ULONG_SIZE_T+offset]+\ + data_array[(k_tm*width_img+i_tm-1)*RMD_ULONG_SIZE_T+offset]+\ + data_array[((k_tm-1)*width_img+i_tm-1)*RMD_ULONG_SIZE_T+offset])/4) + +#define CLIP_DUMMY_POINTER_AREA(dummy_p_area,brwin,wgeom){\ + (wgeom)->x=((((dummy_p_area).x+\ + (dummy_p_area).width>=(brwin)->rgeom.x)&&\ + ((dummy_p_area).x<=(brwin)->rgeom.x+\ + (brwin)->rgeom.width))?\ + (((dummy_p_area).x<=(brwin)->rgeom.x)?\ + (brwin)->rgeom.x:(dummy_p_area).x):-1);\ + (wgeom)->y=((((dummy_p_area).y+\ + (dummy_p_area).height>=(brwin)->rgeom.y)&&\ + ((dummy_p_area).y<=(brwin)->rgeom.y+\ + (brwin)->rgeom.height))?\ + (((dummy_p_area).y<=(brwin)->rgeom.y)?\ + (brwin)->rgeom.y:(dummy_p_area).y):-1);\ + (wgeom)->width=((dummy_p_area).x<=(brwin)->rgeom.x)?\ + (dummy_p_area).width-\ + ((brwin)->rgeom.x-(dummy_p_area).x):\ + ((dummy_p_area).x<=(brwin)->rgeom.x+\ + (brwin)->rgeom.width)?\ + ((brwin)->rgeom.width-(dummy_p_area).x+\ + (brwin)->rgeom.x<(dummy_p_area).width)?\ + (brwin)->rgeom.width-(dummy_p_area).x+\ + (brwin)->rgeom.x:(dummy_p_area).width:-1;\ + (wgeom)->height=((dummy_p_area).y<=(brwin)->rgeom.y)?\ + (dummy_p_area).height-\ + ((brwin)->rgeom.y-(dummy_p_area).y):\ + ((dummy_p_area).y<=(brwin)->rgeom.y+\ + (brwin)->rgeom.height)?\ + ((brwin)->rgeom.height-(dummy_p_area).y+\ + (brwin)->rgeom.y<(dummy_p_area).height)?\ + (brwin)->rgeom.height-(dummy_p_area).y+\ + (brwin)->rgeom.y:(dummy_p_area).height:-1;\ + if((wgeom)->width>(brwin)->rgeom.width)\ + (wgeom)->width=(brwin)->rgeom.width;\ + if((wgeom)->height>(brwin)->rgeom.height)\ + (wgeom)->height=(brwin)->rgeom.height;\ +} + +#define XFIXES_POINTER_TO_YUV(yuv,\ + data,\ + x_tm,\ + y_tm,\ + width_tm,\ + height_tm,\ + x_offset,\ + y_offset,\ + column_discard_stride){\ + int i,k,j=0;\ + unsigned char avg0,avg1,avg2,avg3;\ + int x_2=x_tm/2,y_2=y_tm/2;\ + for(k=y_offset;k<y_offset+height_tm;k++){\ + for(i=x_offset;i<x_offset+width_tm;i++){\ + j=k*(width_tm+column_discard_stride)+i;\ + yuv->y[x_tm+(i-x_offset)+(k+y_tm-y_offset)*yuv->y_width]=\ + (yuv->y[x_tm+(i-x_offset)+(k-y_offset+y_tm)*yuv->y_width]*\ + (UCHAR_MAX-data[(j*RMD_ULONG_SIZE_T)+__ABYTE])+\ + (Yr[data[(j*RMD_ULONG_SIZE_T)+__RBYTE]]+\ + Yg[data[(j*RMD_ULONG_SIZE_T)+__GBYTE]] +\ + Yb[data[(j*RMD_ULONG_SIZE_T)+__BBYTE]])*\ + data[(j*RMD_ULONG_SIZE_T)+__ABYTE])/UCHAR_MAX ;\ + if((k%2)&&(i%2)){\ + avg3=AVG_4_PIXELS(data,\ + (width_tm+column_discard_stride),\ + k,i,__ABYTE);\ + avg2=AVG_4_PIXELS(data,\ + (width_tm+column_discard_stride),\ + k,i,__RBYTE);\ + avg1=AVG_4_PIXELS(data,\ + (width_tm+column_discard_stride),\ + k,i,__GBYTE);\ + avg0=AVG_4_PIXELS(data,\ + (width_tm+column_discard_stride),\ + k,i,__BBYTE);\ + yuv->u[x_2+(i-x_offset)/2+((k-y_offset)/2+y_2)*\ + yuv->uv_width]=\ + (yuv->u[x_2+(i-x_offset)/2+((k-y_offset)/2+y_2)*\ + yuv->uv_width]*\ + (UCHAR_MAX-avg3)+\ + (Ur[avg2] + Ug[avg1] +UbVr[avg0])*avg3)/UCHAR_MAX;\ + yuv->v[x_2+(i-x_offset)/2+((k-y_offset)/2+y_2)*\ + yuv->uv_width]=\ + (yuv->v[x_2+(i-x_offset)/2+((k-y_offset)/2+y_2)*\ + yuv->uv_width]*\ + (UCHAR_MAX-avg3)+\ + (UbVr[avg2] + Vg[avg1] +Vb[avg0])*avg3)/UCHAR_MAX;\ + }\ + }\ + }\ +} + +#define MARK_BACK_BUFFER_C( data,\ + x_tm,\ + y_tm,\ + width_tm,\ + height_tm,\ + buffer_width,\ + __bit_depth__){\ + int k,i;\ + register u_int##__bit_depth__##_t\ + *datapi=\ + ((u_int##__bit_depth__##_t *)data)+y_tm*buffer_width+x_tm;\ + for(k=0;k<height_tm;k++){\ + for(i=0;i<width_tm;i++){\ + *datapi+=1;\ + datapi++;\ + }\ + datapi+=buffer_width-width_tm;\ + }\ +} + +#define MARK_BACK_BUFFER( data,\ + x_tm,\ + y_tm,\ + width_tm,\ + height_tm,\ + buffer_width,\ + __bit_depth__){\ + if((__bit_depth__==24)||(__bit_depth__==32)){\ + MARK_BACK_BUFFER_C( data,\ + x_tm,\ + y_tm,\ + width_tm,\ + height_tm,\ + buffer_width,\ + 32)\ + }\ + else{\ + MARK_BACK_BUFFER_C( data,\ + x_tm,\ + y_tm,\ + width_tm,\ + height_tm,\ + buffer_width,\ + 16)\ + }\ +}\ + + +//besides taking the first screenshot, this functions primary purpose is to +//initialize the structures and memory. +static int FirstFrame(ProgData *pdata, + XImage **image, + XShmSegmentInfo *shminfo, + char **pxl_data) { + + if((pdata->args.noshared)){ + + *pxl_data=(char *)malloc(pdata->brwin.nbytes); + + (*image)=XCreateImage(pdata->dpy, + pdata->specs.visual, + pdata->specs.depth, + ZPixmap, + 0, + *pxl_data, + pdata->brwin.rgeom.width, + pdata->brwin.rgeom.height, + 8, + 0); + XInitImage((*image)); + GetZPixmap(pdata->dpy,pdata->specs.root, + (*image)->data, + pdata->brwin.rgeom.x, + pdata->brwin.rgeom.y, + pdata->brwin.rgeom.width, + pdata->brwin.rgeom.height); + } + else{ + (*image)=XShmCreateImage(pdata->dpy, + pdata->specs.visual, + pdata->specs.depth, + ZPixmap, + *pxl_data, + shminfo, + pdata->brwin.rgeom.width, + pdata->brwin.rgeom.height); + (*shminfo).shmid=shmget(IPC_PRIVATE, + (*image)->bytes_per_line* + (*image)->height, + IPC_CREAT|0777); + if((*shminfo).shmid==-1){ + fprintf(stderr,"Failed to obtain Shared Memory segment!\n"); + return 12; + } + (*shminfo).shmaddr=(*image)->data=shmat((*shminfo).shmid, + NULL,0); + (*shminfo).readOnly = False; + if(!XShmAttach(pdata->dpy,shminfo)){ + fprintf(stderr,"Failed to attach shared memory to proccess.\n"); + return 12; + } + XShmGetImage(pdata->dpy, + pdata->specs.root, + (*image), + pdata->brwin.rgeom.x, + pdata->brwin.rgeom.y, + AllPlanes); + } + + UPDATE_YUV_BUFFER((&pdata->enc_data->yuv), + ((unsigned char*)((*image))->data),NULL, + (pdata->enc_data->x_offset),(pdata->enc_data->y_offset), + (pdata->brwin.rgeom.width),(pdata->brwin.rgeom.height), + (pdata->args.no_quick_subsample), + pdata->specs.depth); + + return 0; +} + +//make a deep copy +static void BRWinCpy(BRWindow *target, BRWindow *source) { + + target->geom.x=source->geom.x; + target->geom.y=source->geom.y; + target->geom.width=source->geom.width; + target->geom.height=source->geom.height; + target->rgeom.x=source->rgeom.x; + target->rgeom.y=source->rgeom.y; + target->rgeom.width=source->rgeom.width; + target->rgeom.height=source->rgeom.height; + target->nbytes=source->nbytes; + target->windowid=source->windowid; + +} + +//recenters the capture area to the mouse +//without exiting the display bounding box +static void MoveCaptureArea(BRWindow *brwin, + int cursor_x, + int cursor_y, + int width, + int height) { + int t_x=0,t_y=0; + + t_x=cursor_x-brwin->rgeom.width/2; + t_x=(t_x>>1)<<1; + brwin->rgeom.x=(t_x<0)?0:((t_x+brwin->rgeom.width>width)? + width-brwin->rgeom.width:t_x); + t_y=cursor_y-brwin->rgeom.height/2; + t_y=(t_y>>1)<<1; + brwin->rgeom.y=(t_y<0)?0:((t_y+brwin->rgeom.height>height)? + height-brwin->rgeom.height:t_y); +} + +/** +* Extract cache blocks from damage list +* +* \param root Root entry of the list with damaged areas +* +* \param x_offset left x of the recording area +* +* \param x_offset upper y of the recording area +* +* \param blocknum_x Width of image in blocks +* +* \param blocknum_y Height of image in blocks +*/ +static void BlocksFromList (RectArea **root, + unsigned int x_offset, + unsigned int y_offset, + unsigned int blocknum_x, + unsigned int blocknum_y) { + + RectArea *temp; + unsigned int i, + j, + blockno, + row_start, + row_end, + column_start, + column_end; + + temp = *root; + + for (i = 0; i < blocknum_x * blocknum_y; i++) { + yblocks[i] = ublocks[i] = vblocks[i] = 0; + } + + while (temp != NULL) { + + column_start = (temp->geom.x - x_offset) / Y_UNIT_WIDTH; + column_end = (temp->geom.x + (temp->geom.width - 1) - x_offset) / Y_UNIT_WIDTH; + row_start = (temp->geom.y - y_offset) / Y_UNIT_WIDTH; + row_end = (temp->geom.y + (temp->geom.height - 1) - y_offset) / Y_UNIT_WIDTH; + + for (i = row_start; i < row_end + 1; i++) { + for (j = column_start; j < column_end + 1; j++) { + blockno = i * blocknum_x + j; + yblocks[blockno] = 1; + ublocks[blockno] = 1; + vblocks[blockno] = 1; + } + } + + temp = temp->next; + } +} + +void *GetFrame(ProgData *pdata){ + int i=0, + blocknum_x=pdata->enc_data->yuv.y_width/Y_UNIT_WIDTH, + blocknum_y=pdata->enc_data->yuv.y_height/Y_UNIT_WIDTH; + unsigned int msk_ret; + WGeometry mouse_pos_abs,mouse_pos_rel,mouse_pos_temp; + BRWindow temp_brwin; + Window root_ret, + child_ret; //Frame + XFixesCursorImage *xcim=NULL; + XImage *image=NULL,*image_back=NULL; //the image that holds + //the current full screenshot + XShmSegmentInfo shminfo,shminfo_back;//info structure for the image above. + int init_img1=0,init_img2=0, + img_sel,d_buff; + char *pxl_data=NULL,*pxl_data_back=NULL; + + + + + img_sel=d_buff=pdata->args.full_shots; + + if((init_img1=FirstFrame(pdata,&image,&shminfo,&pxl_data)!=0)){ + if(pdata->args.encOnTheFly){ + if(remove(pdata->args.filename)){ + perror("Error while removing file:\n"); + } + else{ + fprintf(stderr,"SIGABRT received,file %s removed\n", + pdata->args.filename); + } + } + else{ + PurgeCache(pdata->cache_data,!pdata->args.nosound); + } + exit(init_img1); + } + if(d_buff){ + if((init_img2=FirstFrame(pdata,&image_back,&shminfo_back, + &pxl_data_back)!=0)){ + if(pdata->args.encOnTheFly){ + if(remove(pdata->args.filename)){ + perror("Error while removing file:\n"); + } + else{ + fprintf(stderr,"SIGABRT received,file %s removed\n", + pdata->args.filename); + } + } + else{ + PurgeCache(pdata->cache_data,!pdata->args.nosound); + } + exit(init_img2); + } + + } + + if(!pdata->args.noframe){ + pdata->shaped_w=rmdFrameInit(pdata->dpy, + pdata->specs.screen, + pdata->specs.root, + pdata->brwin.rgeom.x, + pdata->brwin.rgeom.y, + pdata->brwin.rgeom.width, + pdata->brwin.rgeom.height); + XSelectInput(pdata->dpy,pdata->shaped_w,ExposureMask); + } + + mouse_pos_abs.x=mouse_pos_temp.x=0; + mouse_pos_abs.y=mouse_pos_temp.y=0; + mouse_pos_abs.width=mouse_pos_temp.width=pdata->dummy_p_size; + mouse_pos_abs.height=mouse_pos_temp.height=pdata->dummy_p_size; + + //This is the the place where we call XSelectInput + //and arrange so that we listen for damage on all + //windows + InitEventsPolling(pdata); + + while(pdata->running){ + + //if we are left behind we must not wait. + //also before actually pausing we must make sure the streams + //are synced. sound stops so this should only happen quickly. + if(pdata->avd>0 || pdata->args.nosound){ + pthread_mutex_lock(&pdata->time_mutex); + pthread_cond_wait(&pdata->time_cond, &pdata->time_mutex); + pthread_mutex_unlock(&pdata->time_mutex); + if (pdata->paused) { + //this is necessary since event loop processes + //the shortcuts which will unpause the program + EventLoop(pdata); + continue; + } + } + //read all events and construct list with damage + //events (if not full_shots) + EventLoop(pdata); + + //switch back and front buffers (full_shots only) + if(d_buff) + img_sel=(img_sel)?0:1; + pdata->capture_busy = TRUE; + + BRWinCpy(&temp_brwin,&pdata->brwin); + + + if(pdata->args.xfixes_cursor || + pdata->args.have_dummy_cursor|| + pdata->args.follow_mouse){ + //pointer sequence + //update previous_position + //(if full_shots is enabled the new cursor is + //entered on the list for update. + //When taking full shots we keep it for further + //bellow, to mark the area as dirty when dbuffering. + CLIP_DUMMY_POINTER_AREA(mouse_pos_abs,&temp_brwin, + &mouse_pos_temp); + if(!pdata->args.full_shots){ + if((mouse_pos_temp.x>=0)&& + (mouse_pos_temp.y>=0)&& + (mouse_pos_temp.width>0)&& + (mouse_pos_temp.height>0)) + RectInsert(&pdata->rect_root,&mouse_pos_temp); + } + //find new one + if(pdata->args.xfixes_cursor){ + xcim=XFixesGetCursorImage(pdata->dpy); + mouse_pos_abs.x=xcim->x-xcim->xhot; + mouse_pos_abs.y=xcim->y-xcim->yhot; + mouse_pos_abs.width=xcim->width; + mouse_pos_abs.height=xcim->height; + } + else{ + XQueryPointer(pdata->dpy, + pdata->specs.root, + &root_ret,&child_ret, + &mouse_pos_abs.x,&mouse_pos_abs.y, + &mouse_pos_rel.x,&mouse_pos_rel.y,&msk_ret); + } + } + if(pdata->args.follow_mouse){ + MoveCaptureArea(&pdata->brwin, + mouse_pos_abs.x+ + ((pdata->args.xfixes_cursor)?xcim->xhot:0), + mouse_pos_abs.y+ + ((pdata->args.xfixes_cursor)?xcim->yhot:0), + pdata->specs.width, + pdata->specs.height); + if(!pdata->args.noframe){ + rmdMoveFrame(pdata->dpy, + pdata->shaped_w, + temp_brwin.rgeom.x, + temp_brwin.rgeom.y); + + } + } + + if(!pdata->args.full_shots){ + pthread_mutex_lock(&pdata->yuv_mutex); + UpdateImage(pdata->dpy, + &pdata->enc_data->yuv, + &pdata->specs, + &pdata->rect_root, + &temp_brwin, + pdata->enc_data, + image->data, + pdata->args.noshared, + &shminfo, + pdata->shm_opcode, + pdata->args.no_quick_subsample); + BlocksFromList(&pdata->rect_root, + temp_brwin.rgeom.x, + temp_brwin.rgeom.y, + pdata->enc_data->yuv.y_width/Y_UNIT_WIDTH, + pdata->enc_data->yuv.y_height/Y_UNIT_WIDTH); + pthread_mutex_unlock(&pdata->yuv_mutex); + } + else{ + unsigned char *front_buff=(!img_sel)?((unsigned char*)image->data): + ((unsigned char*)image_back->data); + unsigned char *back_buff=(!d_buff)?NULL:((img_sel)? + ((unsigned char*)image->data): + ((unsigned char*)image_back->data)); + + if(!pdata->args.noshared){ + XShmGetImage(pdata->dpy,pdata->specs.root, + ((!img_sel)?image:image_back), + (temp_brwin.rgeom.x), + (temp_brwin.rgeom.y),AllPlanes); + } + if(pdata->args.noshared){ + GetZPixmap( pdata->dpy, + pdata->specs.root, + image->data, + temp_brwin.rgeom.x, + temp_brwin.rgeom.y, + temp_brwin.rgeom.width, + temp_brwin.rgeom.height); + } + pthread_mutex_lock(&pdata->yuv_mutex); + for(i=0;i<blocknum_x*blocknum_y;i++){ + yblocks[i]=ublocks[i]=vblocks[i]=0; + } + UPDATE_YUV_BUFFER((&pdata->enc_data->yuv), + front_buff,back_buff, + (pdata->enc_data->x_offset), + (pdata->enc_data->y_offset), + (temp_brwin.rgeom.width), + (temp_brwin.rgeom.height), + pdata->args.no_quick_subsample, + pdata->specs.depth); + pthread_mutex_unlock(&pdata->yuv_mutex); + } + if(pdata->args.xfixes_cursor || + pdata->args.have_dummy_cursor){ + int mouse_xoffset, + mouse_yoffset; + //avoid segfaults + CLIP_DUMMY_POINTER_AREA(mouse_pos_abs,&temp_brwin, + &mouse_pos_temp); + mouse_xoffset=mouse_pos_temp.x-mouse_pos_abs.x; + mouse_yoffset=mouse_pos_temp.y-mouse_pos_abs.y; + if((mouse_xoffset<0) || (mouse_xoffset>mouse_pos_abs.width)) + mouse_xoffset=0; + if((mouse_yoffset<0) || (mouse_yoffset>mouse_pos_abs.height)) + mouse_yoffset=0; + //draw the cursor + if((mouse_pos_temp.x>=0)&& + (mouse_pos_temp.y>=0)&& + (mouse_pos_temp.width>0)&& + (mouse_pos_temp.height>0)){ + if(pdata->args.xfixes_cursor){ + XFIXES_POINTER_TO_YUV((&pdata->enc_data->yuv), + ((unsigned char*)xcim->pixels), + (mouse_pos_temp.x- + temp_brwin.rgeom.x+ + pdata->enc_data->x_offset), + (mouse_pos_temp.y- + temp_brwin.rgeom.y+ + pdata->enc_data->y_offset), + mouse_pos_temp.width, + mouse_pos_temp.height, + mouse_xoffset, + mouse_yoffset, + (xcim->width-mouse_pos_temp.width)); + } + else{ + DUMMY_POINTER_TO_YUV((&pdata->enc_data->yuv), + pdata->dummy_pointer, + (mouse_pos_temp.x- + temp_brwin.rgeom.x+ + pdata->enc_data->x_offset), + (mouse_pos_temp.y- + temp_brwin.rgeom.y+ + pdata->enc_data->y_offset), + mouse_pos_temp.width, + mouse_pos_temp.height, + mouse_xoffset, + mouse_yoffset, + pdata->npxl); + } + if(d_buff){ + //make previous cursor position dirty + unsigned char *front_buff= + (!img_sel)?((unsigned char*)image->data): + ((unsigned char*)image_back->data); + + MARK_BACK_BUFFER( front_buff, + (mouse_pos_temp.x- + temp_brwin.rgeom.x+ + pdata->enc_data->x_offset), + (mouse_pos_temp.y- + temp_brwin.rgeom.y+ + pdata->enc_data->y_offset), + mouse_pos_temp.width, + mouse_pos_temp.height, + (temp_brwin.rgeom.width), + pdata->specs.depth) + } + + } + if(pdata->args.xfixes_cursor){ + XFree(xcim); + xcim=NULL; + } + } + if(!pdata->args.full_shots){ + ClearList(&pdata->rect_root); + } + if (pdata->encoder_busy) { + pdata->frames_lost++; + } + pthread_mutex_lock(&pdata->img_buff_ready_mutex); + pthread_cond_broadcast(&pdata->image_buffer_ready); + pthread_mutex_unlock(&pdata->img_buff_ready_mutex); + pdata->capture_busy = FALSE; + } + + if(!pdata->args.noframe){ + XDestroyWindow(pdata->dpy,pdata->shaped_w); + } + + + pthread_mutex_lock(&pdata->img_buff_ready_mutex); + pthread_cond_broadcast(&pdata->image_buffer_ready); + pthread_mutex_unlock(&pdata->img_buff_ready_mutex); + if(!pdata->args.noshared){ + XShmDetach (pdata->dpy, &shminfo); + shmdt (shminfo.shmaddr); + shmctl (shminfo.shmid, IPC_RMID, 0); + if(d_buff){ + XShmDetach (pdata->dpy, &shminfo_back); + shmdt (shminfo_back.shmaddr); + shmctl (shminfo_back.shmid, IPC_RMID, 0); + } + } + pthread_exit(&errno); +} + |