32
32
#include <config.h>
45
#include <sys/types.h>
54
#include <X11/Xlibint.h>
55
#include <X11/Xatom.h>
56
#include <X11/extensions/Xfixes.h>
57
#include <X11/extensions/Xdamage.h>
58
#include <X11/extensions/XShm.h>
59
#include <theora/theora.h>
60
#include <vorbis/codec.h>
61
#include <vorbis/vorbisenc.h>
63
#include <alsa/asoundlib.h>
66
//define whcih way we are reading a pixmap
67
#if __BYTE_ORDER == __LITTLE_ENDIAN
73
#elif __BYTE_ORDER == __BIG_ENDIAN
81
#error Only little-endian and big-endian systems are supported
84
#define __RVALUE(tmp_val) (((tmp_val)&0x00ff0000)>>16)
85
#define __GVALUE(tmp_val) (((tmp_val)&0x0000ff00)>>8)
86
#define __BVALUE(tmp_val) (((tmp_val)&0x000000ff))
89
#define CACHE_FILE_SIZE_LIMIT (500*1<<20)
95
typedef struct _DisplaySpecs{ //this struct holds some basic information
96
int screen; //about the display,needed mostly for
97
uint width; //validity checks at startup
103
unsigned long bpixel;
104
unsigned long wpixel;
107
typedef struct _WGeometry{ //basic geometry of a window or area
114
typedef struct _RectArea{ //an area that has been damaged gets stored
115
WGeometry geom; //in a list comprised of structs of this type
116
struct _RectArea *prev,*next;
119
typedef struct _BRWindow{ //'basic recorded window' specs
120
WGeometry geom; //window attributes
121
WGeometry rgeom; //part of window that is recorded
122
int nbytes; //size of zpixmap when screenshoting
123
Window windowid; //id
126
//defaults in the following comment lines may be out of sync with reality
127
//check DEFAULT_ARGS macro further bellow
128
typedef struct _ProgArgs{
129
int delay; //start up delay
130
Window windowid; //window to record(default root)
131
char *display; //display to connect(default :0)
132
int x,y; //x,y offset(default 0,0)
133
int width,height; //defaults to window width and height
134
int quietmode; //no messages to stderr,stdout
135
char *filename; //output file(default out.[ogg|*])
136
int cursor_color; //black or white=>1 or 0
137
int have_dummy_cursor;//disable/enable drawing of the dummy cursor
138
int xfixes_cursor; //disable/enable drawing of a cursor obtained
139
//through the xfixes extension
140
float fps; //desired framerate(default 15)
141
unsigned int frequency; //desired frequency (default 22050)
142
unsigned int channels; //no of channels(default 2)
143
char *device; //default sound device(default according to alsa or oss)
144
snd_pcm_uframes_t buffsize;//buffer size(in frames) for sound capturing
145
int nosound; //do not record sound(default 0)
146
int noshared; //do not use shared memory extension(default 1)
147
int nocondshared; //do not use shared memory on large image aquititions
148
int nowmcheck; //do not check if there's a 3d comp window manager
149
//(which changes full-shots and with-shared to 1)
150
int shared_thres; //threshold to use shared memory
151
int full_shots; //do not poll damage, take full screenshots
152
int no_quick_subsample;//average pixels in chroma planes
153
int v_bitrate,v_quality,s_quality;//video bitrate,video-sound quality
154
int dropframes; //option for theora encoder
155
int encOnTheFly; //encode while recording, no caching(default 0)
156
char *workdir; //directory to be used for cache files(default $HOME)
157
int zerocompression;//image data are always flushed uncompressed
158
int overwrite;//overwite a previously existing file(do not add a .number postfix)
162
//this struct holds anything related to encoding AND
163
//writting out to file.
164
typedef struct _EncData{
165
ogg_stream_state m_ogg_ts;//theora
166
ogg_stream_state m_ogg_vs;//vorbis
167
ogg_page m_ogg_pg;//this could be avoided since
168
// it is used only while initializing
169
ogg_packet m_ogg_pckt1;//theora stream
170
ogg_packet m_ogg_pckt2;//vorbis stream
172
theora_state m_th_st;
173
theora_info m_th_inf;
174
theora_comment m_th_cmmnt;
177
vorbis_info m_vo_inf;
178
vorbis_comment m_vo_cmmnt;
179
vorbis_dsp_state m_vo_dsp;
180
vorbis_block m_vo_block;
181
//these should be 0, since area is quantized
189
//this struct will hold a few basic
190
//information, needed for caching the frames.
191
typedef struct _CacheData{
192
char *workdir, //The directory were the project will be stored, while recording.
193
//Since this will take a lot of space, the user must be
194
//able to change the location.
195
*projname, //This is the name of the folder that will hold the project.
196
//It is rMD-session-%d where %d is the pid of the current proccess.
197
//This way, running two instances will not create problems
198
//and also, a frontend can identify leftovers from a possible crash
200
*imgdata, //workdir+projname+img.out.gz
201
*audiodata; //workdir+projname+audio.pcm
203
gzFile *ifp; //image data file pointer
204
FILE *uncifp; //uncompressed image data file pointer
206
FILE *afp; //audio data file pointer
211
//sound keeps coming so we que it in this list
212
//which we then traverse
213
typedef struct _SndBuffer{
215
struct _SndBuffer *next;
218
//this structure holds any data related to the program
219
//It's usage is mostly to be given as an argument to the
220
//threads,so they will have access to the program data, avoiding
221
//at the same time usage of any globals.
222
typedef struct _ProgData{
223
ProgArgs args;//the program arguments
224
DisplaySpecs specs;//Display specific information
225
BRWindow brwin;//recording window
226
Display *dpy;//curtrent display
227
char *window_manager;//name of the window manager at program launch
228
XImage *image;//the image that holds the current full screenshot
229
XImage *shimage;//the image that holds the current full screenshot(shared memory)
230
unsigned char *dummy_pointer;//a dummy pointer to be drawn in every frame
231
//data is casted to unsigned for later use in YUV buffer
232
int dummy_p_size;//initially 16x16,always square
233
unsigned char npxl;//this is the no pixel convention when drawing the dummy pointer
234
char *datamain,//the data of image
235
*datash,//the data of shimage
236
*datatemp;//buffer for the temporary image,which will be
237
//preallocated in case shared memory is not used.
238
RectArea *rect_root[2];//the interchanging list roots for storing the changed regions
239
int list_selector,//selector for the above
240
damage_event,//damage event base code
241
damage_error,//damage error base code
243
SndBuffer *sound_buffer;
245
CacheData *cache_data;
246
int hard_pause;//if sound device doesn't support pause
247
//we have to close and reopen
248
int avd;//syncronization among audio and video
249
unsigned int periodtime,
251
pthread_mutex_t list_mutex[2],//mutexes for concurrency protection of the lists
253
libogg_mutex,//libogg is not thread safe,
254
// libtheora_mutex,//same for libtheora
255
// libvorbis_mutex,//and libvorbis.
256
yuv_mutex;//this might not be needed since we only have
257
//one read-only and one write-only thread
258
//also on previous versions, y component was looped separately
259
//and then u and v so this was needed to avoid wrong coloring to render
260
//Currently this mutex only prevents the cursor from flickering
261
pthread_cond_t time_cond,//this gets a broadcast by the handler whenever it's time to get a screenshot
262
pause_cond,//this is blocks execution, when program is paused
263
sound_buffer_ready,//sound encoding finished
264
sound_data_read,//a buffer is ready for proccessing
265
image_buffer_ready,//image encoding finished
266
theora_lib_clean,//the flush_ogg thread cannot procceed to creating last
267
vorbis_lib_clean;//packages until these two libs are no longer used, by other threads
268
int th_encoding_clean,//these indicate a wait condition on the above cond vars
270
int v_enc_thread_waiting,
271
th_enc_thread_waiting;
272
snd_pcm_t *sound_handle;
273
snd_pcm_uframes_t periodsize;
277
//This is the header of every frame.
278
//Reconstruction will be correct only if made on
281
//We need the total number of blocks
284
//The number of the frame compared to the
285
//number of time expirations at the time of
286
//caching, will enable us to make up for lost frames.
288
//default 4+4+2+2+2=14!bad!
289
//me add pad, make god of 2 happy!
290
typedef struct _FrameHeader{
291
char frame_prefix[4];//always FRAM
292
u_int32_t frameno,//number of frame(cached frames)
293
current_total;//number of frames that should have been
294
//taken at time of caching this one
295
u_int16_t Ynum,//number of changed blocks in the Y plane
296
Unum,//number of changed blocks in the U plane
297
Vnum;//number of changed blocks in the V plane
298
u_int16_t pad;//always zero
302
//The frame after retrieval.
303
//Based on the Header information
304
//we can read the correct amount of bytes.
307
typedef struct _CachedFrame{
309
unsigned char *YBlocks;//identifying number on the grid, starting at top left
310
unsigned char *UBlocks;// >> >>
311
unsigned char *VBlocks;// >> >>
312
unsigned char *YData;//pointer to data for the blocks that have changed,
313
unsigned char *UData;//which have to be remapped on the buffer when reading
314
unsigned char *VData;
321
44
int Paused,*Running,Aborted;
322
45
pthread_cond_t *time_cond,*pause_cond;
46
pthread_mutex_t pause_mutex,time_mutex;
323
47
unsigned char Yr[256],Yg[256],Yb[256],
324
48
Ur[256],Ug[256],Ub[256],
325
49
Vr[256],Vg[256],Vb[256];
326
50
//the following values are of no effect
327
51
//but they might be usefull later for profiling
328
unsigned int frames_total,//frames calculated by total time expirations
329
frames_lost;//the value of shame
52
unsigned int frames_total, //frames calculated by total time expirations
53
frames_lost; //the value of shame
330
54
//used to determine frame drop which can
331
55
//happen on failure to receive a signal over a condition variable
338
#define CLIP_EVENT_AREA(e,brwin,wgeom){\
339
if(((e)->area.x<=(brwin)->rgeom.x)&&((e)->area.y<=(brwin)->rgeom.y)&&\
340
((e)->area.width>=(brwin)->rgeom.width)&&((e)->area.height<(brwin)->rgeom.height)){\
341
(wgeom)->x=(brwin)->rgeom.x;\
342
(wgeom)->y=(brwin)->rgeom.y;\
343
(wgeom)->width=(brwin)->rgeom.width;\
344
(wgeom)->height=(brwin)->rgeom.height;\
347
(wgeom)->x=((((e)->area.x+(e)->area.width>=(brwin)->rgeom.x)&&\
348
((e)->area.x<=(brwin)->rgeom.x+(brwin)->rgeom.width))?\
349
(((e)->area.x<=(brwin)->rgeom.x)?(brwin)->rgeom.x:(e)->area.x):-1);\
351
(wgeom)->y=((((e)->area.y+(e)->area.height>=(brwin)->rgeom.y)&&\
352
((e)->area.y<=(brwin)->rgeom.y+(brwin)->rgeom.height))?\
353
(((e)->area.y<=(brwin)->rgeom.y)?(brwin)->rgeom.y:(e)->area.y):-1);\
355
(wgeom)->width=((e)->area.x<=(brwin)->rgeom.x)?\
356
(e)->area.width-((brwin)->rgeom.x-(e)->area.x):\
357
((e)->area.x<=(brwin)->rgeom.x+(brwin)->rgeom.width)?\
358
(((brwin)->rgeom.width-(e)->area.x+(brwin)->rgeom.x<(e)->area.width)?\
359
(brwin)->rgeom.width-(e)->area.x+(brwin)->rgeom.x:e->area.width):-1;\
361
(wgeom)->height=((e)->area.y<=(brwin)->rgeom.y)?\
362
(e)->area.height-((brwin)->rgeom.y-(e)->area.y):\
363
((e)->area.y<=(brwin)->rgeom.y+(brwin)->rgeom.height)?\
364
(((brwin)->rgeom.height-(e)->area.y+(brwin)->rgeom.y<(e)->area.height)?\
365
(brwin)->rgeom.height-(e)->area.y+(brwin)->rgeom.y:(e)->area.height):-1;\
367
if((wgeom)->width>(brwin)->rgeom.width)(wgeom)->width=(brwin)->rgeom.width;\
368
if((wgeom)->height>(brwin)->rgeom.height)(wgeom)->height=(brwin)->rgeom.height;\
372
#define CLIP_DUMMY_POINTER_AREA(dummy_p_area,brwin,wgeom){\
373
(wgeom)->x=((((dummy_p_area).x+(dummy_p_area).width>=(brwin)->rgeom.x)&&\
374
((dummy_p_area).x<=(brwin)->rgeom.x+(brwin)->rgeom.width))?\
375
(((dummy_p_area).x<=(brwin)->rgeom.x)?(brwin)->rgeom.x:(dummy_p_area).x):-1);\
376
(wgeom)->y=((((dummy_p_area).y+(dummy_p_area).height>=(brwin)->rgeom.y)&&\
377
((dummy_p_area).y<=(brwin)->rgeom.y+(brwin)->rgeom.height))?\
378
(((dummy_p_area).y<=(brwin)->rgeom.y)?(brwin)->rgeom.y:(dummy_p_area).y):-1);\
379
(wgeom)->width=((dummy_p_area).x<=(brwin)->rgeom.x)?\
380
(dummy_p_area).width-((brwin)->rgeom.x-(dummy_p_area).x):\
381
((dummy_p_area).x<=(brwin)->rgeom.x+(brwin)->rgeom.width)?\
382
((brwin)->rgeom.width-(dummy_p_area).x+(brwin)->rgeom.x<(dummy_p_area).width)?\
383
(brwin)->rgeom.width-(dummy_p_area).x+(brwin)->rgeom.x:(dummy_p_area).width:-1;\
384
(wgeom)->height=((dummy_p_area).y<=(brwin)->rgeom.y)?\
385
(dummy_p_area).height-((brwin)->rgeom.y-(dummy_p_area).y):\
386
((dummy_p_area).y<=(brwin)->rgeom.y+(brwin)->rgeom.height)?\
387
((brwin)->rgeom.height-(dummy_p_area).y+(brwin)->rgeom.y<(dummy_p_area).height)?\
388
(brwin)->rgeom.height-(dummy_p_area).y+(brwin)->rgeom.y:(dummy_p_area).height:-1;\
389
if((wgeom)->width>(brwin)->rgeom.width)(wgeom)->width=(brwin)->rgeom.width;\
390
if((wgeom)->height>(brwin)->rgeom.height)(wgeom)->height=(brwin)->rgeom.height;\
395
#define DEFAULT_ARGS(args){\
397
if(getenv("DISPLAY")!=NULL){\
398
(args)->display=(char *)malloc(strlen(getenv("DISPLAY"))+1);\
399
strcpy((args)->display,getenv("DISPLAY"));\
402
(args)->display=NULL;\
411
(args)->encOnTheFly=\
412
(args)->zerocompression=\
416
(args)->nocondshared=0;\
417
(args)->no_quick_subsample=\
419
(args)->filename=(char *)malloc(8);\
420
strcpy((args)->filename,"out.ogg");\
421
(args)->cursor_color=1;\
422
(args)->shared_thres=75;\
423
(args)->have_dummy_cursor=0;\
424
(args)->xfixes_cursor=1;\
425
(args)->device=(char *)malloc(8);\
426
strcpy((args)->device,"hw:0,0");\
429
(args)->frequency=22050;\
430
(args)->buffsize=4096;\
431
(args)->v_bitrate=45000;\
432
(args)->v_quality=63;\
433
(args)->s_quality=10;\
434
(args)->workdir=(char *)malloc(5);\
435
strcpy((args)->workdir,"/tmp");\
438
#define QUERY_DISPLAY_SPECS(display,specstruct){\
439
(specstruct)->screen=DefaultScreen(display);\
440
(specstruct)->width=DisplayWidth(display,(specstruct)->screen);\
441
(specstruct)->height=DisplayHeight(display,(specstruct)->screen);\
442
(specstruct)->root=RootWindow(display,(specstruct)->screen);\
443
(specstruct)->visual=DefaultVisual(display,(specstruct)->screen);\
444
(specstruct)->gc=DefaultGC(display,(specstruct)->screen);\
445
(specstruct)->depth=DefaultDepth(display,(specstruct)->screen);\
446
(specstruct)->bpixel=XBlackPixel(display,(specstruct)->screen);\
447
(specstruct)->wpixel=XWhitePixel(display,(specstruct)->screen);\
450
#define AVG_4_PIXELS(data_array,width_img,k_tm,i_tm,offset)\
451
((data_array[(k_tm*width_img+i_tm)*4+offset]+data_array[((k_tm-1)*width_img+i_tm)*4+offset]\
452
+data_array[(k_tm*width_img+i_tm-1)*4+offset]+data_array[((k_tm-1)*width_img+i_tm-1)*4+offset])/4)
454
#define UPDATE_YUV_BUFFER_SH(yuv,data,x_tm,y_tm,width_tm,height_tm){\
456
register unsigned int t_val;\
457
register unsigned int *datapi=(unsigned int*)data+x_tm+y_tm*yuv->y_width;\
458
register unsigned char *yuv_y=yuv->y+x_tm+y_tm*yuv->y_width,\
459
*yuv_u=yuv->u+x_tm/2+(y_tm*yuv->uv_width)/2,\
460
*yuv_v=yuv->v+x_tm/2+(y_tm*yuv->uv_width)/2,\
461
*_yr=Yr,*_yg=Yg,*_yb=Yb,\
462
*_ur=Ur,*_ug=Ug,*_ub=Ub,\
463
*_vr=Vr,*_vg=Vg,*_vb=Vb;\
465
for(k=0;k<height_tm;k++){\
466
for(i=0;i<width_tm;i++){\
468
*yuv_y=_yr[__RVALUE(t_val)] + _yg[__GVALUE(t_val)] + _yb[__BVALUE(t_val)] ;\
472
yuv_y+=yuv->y_width-width_tm;\
473
datapi+=yuv->y_width-width_tm;\
475
datapi=(unsigned int*)data+x_tm+y_tm*yuv->y_width;\
476
for(k=0;k<height_tm;k+=2){\
477
for(i=0;i<width_tm;i+=2){\
480
_ur[__RVALUE(t_val)] + _ug[__GVALUE(t_val)] + _ub[__BVALUE(t_val)];\
482
_vr[__RVALUE(t_val)] + _vg[__GVALUE(t_val)] + _vb[__BVALUE(t_val)];\
487
yuv_u+=(yuv->y_width-width_tm)/2;\
488
yuv_v+=(yuv->y_width-width_tm)/2;\
489
datapi+=(2*yuv->y_width-width_tm);\
493
#define UPDATE_YUV_BUFFER_SH_AVG(yuv,data,x_tm,y_tm,width_tm,height_tm){\
495
register unsigned int t_val,t1,t2,t3,t4;\
496
register unsigned int *datapi=(unsigned int*)data+x_tm+y_tm*yuv->y_width,\
497
*datapi_next=(unsigned int*)data+x_tm+(y_tm+1)*yuv->y_width;\
498
register unsigned char *yuv_y=yuv->y+x_tm+y_tm*yuv->y_width,\
499
*yuv_u=yuv->u+x_tm/2+(y_tm*yuv->uv_width)/2,\
500
*yuv_v=yuv->v+x_tm/2+(y_tm*yuv->uv_width)/2,\
501
*_yr=Yr,*_yg=Yg,*_yb=Yb,\
502
*_ur=Ur,*_ug=Ug,*_ub=Ub,\
503
*_vr=Vr,*_vg=Vg,*_vb=Vb;\
505
for(k=0;k<height_tm;k++){\
506
for(i=0;i<width_tm;i++){\
508
*yuv_y=_yr[__RVALUE(t_val)] + _yg[__GVALUE(t_val)] + _yb[__BVALUE(t_val)] ;\
512
yuv_y+=yuv->y_width-width_tm;\
513
datapi+=yuv->y_width-width_tm;\
515
datapi=(unsigned int*)data+x_tm+y_tm*yuv->y_width;\
516
for(k=0;k<height_tm;k+=2){\
517
for(i=0;i<width_tm;i+=2){\
521
t4=*(datapi_next+1);\
522
t_val=((((t1&0xff000000) +(t2&0xff000000)+\
523
(t3&0xff000000)+(t4&0xff000000))/4)&0xff000000) \
524
+((((t1&0x00ff0000) +(t2&0x00ff0000)+\
525
(t3&0x00ff0000)+(t4&0x00ff0000))/4)&0x00ff0000)\
526
+((((t1&0x0000ff00) +(t2&0x0000ff00)+\
527
(t3&0x0000ff00)+(t4&0x0000ff00))/4)&0x0000ff00)\
528
+((((t1&0x000000ff) +(t2&0x000000ff)+\
529
(t3&0x000000ff)+(t4&0x000000ff))/4)&0x000000ff);\
532
_ur[__RVALUE(t_val)] + _ug[__GVALUE(t_val)] + _ub[__BVALUE(t_val)];\
534
_vr[__RVALUE(t_val)] + _vg[__GVALUE(t_val)] + _vb[__BVALUE(t_val)];\
540
yuv_u+=(yuv->y_width-width_tm)/2;\
541
yuv_v+=(yuv->y_width-width_tm)/2;\
542
datapi+=(2*yuv->y_width-width_tm);\
543
datapi_next+=(2*yuv->y_width-width_tm);\
549
#define UPDATE_YUV_BUFFER_IM(yuv,data,x_tm,y_tm,width_tm,height_tm){\
551
register unsigned int t_val;\
552
register unsigned int *datapi=(unsigned int*)data;\
553
register unsigned char *yuv_y=yuv->y+x_tm+y_tm*yuv->y_width,\
554
*yuv_u=yuv->u+x_tm/2+(y_tm*yuv->uv_width)/2,\
555
*yuv_v=yuv->v+x_tm/2+(y_tm*yuv->uv_width)/2,\
556
*_yr=Yr,*_yg=Yg,*_yb=Yb,\
557
*_ur=Ur,*_ug=Ug,*_ub=Ub,\
558
*_vr=Vr,*_vg=Vg,*_vb=Vb;\
560
for(k=0;k<height_tm;k++){\
561
for(i=0;i<width_tm;i++){\
563
*yuv_y=_yr[__RVALUE(t_val)] + _yg[__GVALUE(t_val)] + _yb[__BVALUE(t_val)] ;\
567
yuv_y+=yuv->y_width-width_tm;\
569
datapi=(unsigned int*)data;\
570
for(k=0;k<height_tm;k+=2){\
571
for(i=0;i<width_tm;i+=2){\
574
_ur[__RVALUE(t_val)] + _ug[__GVALUE(t_val)] + _ub[__BVALUE(t_val)];\
576
_vr[__RVALUE(t_val)] + _vg[__GVALUE(t_val)] + _vb[__BVALUE(t_val)];\
581
yuv_u+=(yuv->y_width-width_tm)/2;\
582
yuv_v+=(yuv->y_width-width_tm)/2;\
587
#define UPDATE_YUV_BUFFER_IM_AVG(yuv,data,x_tm,y_tm,width_tm,height_tm){\
589
register unsigned int t_val,t1,t2,t3,t4;\
590
register unsigned int *datapi=(unsigned int*)data,\
591
*datapi_next=(unsigned int*)data+width_tm;\
592
register unsigned char *yuv_y=yuv->y+x_tm+y_tm*yuv->y_width,\
593
*yuv_u=yuv->u+x_tm/2+(y_tm*yuv->uv_width)/2,\
594
*yuv_v=yuv->v+x_tm/2+(y_tm*yuv->uv_width)/2,\
595
*_yr=Yr,*_yg=Yg,*_yb=Yb,\
596
*_ur=Ur,*_ug=Ug,*_ub=Ub,\
597
*_vr=Vr,*_vg=Vg,*_vb=Vb;\
599
for(k=0;k<height_tm;k++){\
600
for(i=0;i<width_tm;i++){\
602
*yuv_y=_yr[__RVALUE(t_val)] + _yg[__GVALUE(t_val)] + _yb[__BVALUE(t_val)] ;\
606
yuv_y+=yuv->y_width-width_tm;\
608
datapi=(unsigned int*)data;\
609
for(k=0;k<height_tm;k+=2){\
610
for(i=0;i<width_tm;i+=2){\
614
t4=*(datapi_next+1);\
615
t_val=((((t1&0xff000000) +(t2&0xff000000)+\
616
(t3&0xff000000)+(t4&0xff000000))/4)&0xff000000) \
617
+((((t1&0x00ff0000) +(t2&0x00ff0000)+\
618
(t3&0x00ff0000)+(t4&0x00ff0000))/4)&0x00ff0000)\
619
+((((t1&0x0000ff00) +(t2&0x0000ff00)+\
620
(t3&0x0000ff00)+(t4&0x0000ff00))/4)&0x0000ff00)\
621
+((((t1&0x000000ff) +(t2&0x000000ff)+\
622
(t3&0x000000ff)+(t4&0x000000ff))/4)&0x000000ff);\
625
_ur[__RVALUE(t_val)] + _ug[__GVALUE(t_val)] + _ub[__BVALUE(t_val)];\
627
_vr[__RVALUE(t_val)] + _vg[__GVALUE(t_val)] + _vb[__BVALUE(t_val)];\
633
yuv_u+=(yuv->y_width-width_tm)/2;\
634
yuv_v+=(yuv->y_width-width_tm)/2;\
636
datapi_next+=width_tm;\
642
#define XFIXES_POINTER_TO_YUV(yuv,data,x_tm,y_tm,width_tm,height_tm,column_discard_stride){\
644
unsigned char avg0,avg1,avg2,avg3;\
645
int x_2=x_tm/2,y_2=y_tm/2;\
646
for(k=0;k<height_tm;k++){\
647
for(i=0;i<width_tm;i++){\
648
yuv->y[x_tm+i+(k+y_tm)*yuv->y_width]=\
649
(yuv->y[x_tm+i+(k+y_tm)*yuv->y_width]*(UCHAR_MAX-data[(j*4)+__ABYTE])+\
650
(Yr[data[(j*4)+__RBYTE]] + Yg[data[(j*4)+__GBYTE]] + Yb[data[(j*4)+__BBYTE]])*data[(j*4)+__ABYTE])/UCHAR_MAX ;\
652
avg3=AVG_4_PIXELS(data,(width_tm+column_discard_stride),k,i,__ABYTE);\
653
avg2=AVG_4_PIXELS(data,(width_tm+column_discard_stride),k,i,__RBYTE);\
654
avg1=AVG_4_PIXELS(data,(width_tm+column_discard_stride),k,i,__GBYTE);\
655
avg0=AVG_4_PIXELS(data,(width_tm+column_discard_stride),k,i,__BBYTE);\
656
yuv->u[x_2+i/2+(k/2+y_2)*yuv->uv_width]=\
657
(yuv->u[x_2+i/2+(k/2+y_2)*yuv->uv_width]*(UCHAR_MAX-avg3)+\
658
(Ur[avg2] + Ug[avg1] +Ub[avg0])*avg3)/UCHAR_MAX;\
659
yuv->v[x_2+i/2+(k/2+y_2)*yuv->uv_width]=\
660
(yuv->v[x_2+i/2+(k/2+y_2)*yuv->uv_width]*(UCHAR_MAX-avg3)+\
661
(Vr[avg2] + Vg[avg1] +Vb[avg0])*avg3)/UCHAR_MAX;\
665
j+=column_discard_stride;\
669
#define DUMMY_POINTER_TO_YUV(yuv,data_tm,x_tm,y_tm,width_tm,height_tm,no_pixel){\
671
int x_2=x_tm/2,y_2=y_tm/2,y_width_2=(yuv)->y_width/2;\
672
for(k=0;k<height_tm;k++){\
673
for(i=0;i<width_tm;i++){\
674
if(data_tm[(j*4)]!=(no_pixel)){\
675
(yuv)->y[x_tm+i+(k+y_tm)*(yuv)->y_width]=Yr[data_tm[(j*4)+__RBYTE]] + Yg[data_tm[(j*4)+__GBYTE]] + Yb[data_tm[(j*4)+__BBYTE]];\
677
yuv->u[x_2+i/2+(k/2+y_2)*y_width_2]=Ur[data_tm[(k*width_tm+i)*4+__RBYTE]] + Ug[data_tm[(k*width_tm+i)*4+__GBYTE]] + Ub[data_tm[(k*width_tm+i)*4+__BBYTE]];\
678
yuv->v[x_2+i/2+(k/2+y_2)*y_width_2]=Vr[data_tm[(k*width_tm+i)*4+__RBYTE]] + Vg[data_tm[(k*width_tm+i)*4+__GBYTE]] + Vb[data_tm[(k*width_tm+i)*4+__BBYTE]] ;\
688
#define I16TOA(number,buffer){\
689
int t_num=(number),__k=0,__i=0;\
690
char *t_buf=malloc(8);\
691
t_num=t_num&((2<<15)-1);\
694
t_buf[__k]=digit+48;\
700
(buffer)[__i++]=t_buf[--__k];\
705
#define INIT_FRAME(frame_t,fheader_t,yuv_t){\
706
(frame_t)->header=(fheader_t);\
707
(frame_t)->YBlocks=malloc(256);\
708
(frame_t)->UBlocks=malloc(64);\
709
(frame_t)->VBlocks=malloc(64);\
710
(frame_t)->YData=malloc((yuv_t)->y_width*(yuv_t)->y_height);\
711
(frame_t)->UData=malloc((yuv_t)->uv_width*(yuv_t)->uv_height);\
712
(frame_t)->VData=malloc((yuv_t)->uv_width*(yuv_t)->uv_height);\
715
#define CLEAR_FRAME(frame_t){\
716
free((frame_t)->YBlocks);\
717
free((frame_t)->UBlocks);\
718
free((frame_t)->VBlocks);\
719
free((frame_t)->YData);\
720
free((frame_t)->UData);\
721
free((frame_t)->VData);\
724
/**Function prototypes*/
727
* Loop calling XNextEvent.Retrieve and place on
728
* list damage events that arive, create damage for new windows.
729
* \param pdata ProgData struct containing all program data
731
void *PollDamage(ProgData *pdata);
734
* Retrieve frame form xserver, and transform to a yuv buffer,
735
* either directly(full shots) or by calling UpdateImage.
736
* \param pdata ProgData struct containing all program data
738
void *GetFrame(ProgData *pdata);
741
* feed a yuv buffer to the theora encoder and submit outcome to
743
* \param pdata ProgData struct containing all program data
745
void *EncodeImageBuffer(ProgData *pdata);
748
* Query theora and vorbis streams for ready packages and
749
* flush them on the disk
750
* \param pdata ProgData struct containing all program data
752
void *FlushToOgg(ProgData *pdata);
755
* Clean up a list of areas marked for update.
756
* \param root Root entry of the list
758
void ClearList(RectArea **root);
761
* Insert a new rectangle on the list, making sure it doesn't overlap
762
* with the existing ones
763
* \param root Root entry of the list
765
* \param wgeom New area to be inserted
767
* \returns Number of insertions during operation
769
* \note This function is reentrant and recursive. The number
770
* of insertions takes this into account.
772
int RectInsert(RectArea **root,WGeometry *wgeom);
775
* Collide two rectangles and dictate most sane action for insertion,
776
* as well as provide the updated rectangle(s)
777
* \param wgeom1 resident rectangle
779
* \param wgeom2 New rectangle
781
* \param wgeom_return Pointer to rectangles to be inserted
783
* \param ngeoms number of entries in wgeom_return
785
* \retval 0 No collision
787
* \retval 1 wgeom1 is covered by wgeom2
789
* \retval 2 wgeom2 is covered by wgeom1
791
* \retval -1 wgeom1 was broken (new is picked up in wgeom_return)
793
* \retval -2 wgeom2 was broken (new is picked up in wgeom_return)
795
* \retval -10 Grouping the two geoms is possible
798
int CollideRects(WGeometry *wgeom1,WGeometry *wgeom2,WGeometry **wgeom_return,int *ngeoms);
801
* Broadcast time condition variable, increment frame count.
803
* \param signum Number of signal received(unused, always SIGALRM)
806
void SetExpired(int signum);
809
* Set up all callbacks and signal handlers
810
* \param pdata ProgData struct containing all program data
812
void RegisterCallbacks(ProgArgs *args);
815
* Retrieve and apply all changes, if xdamage is used.
817
* \param dpy Connection to the server
819
* \param yuv yuv_buffer that is to be modified
821
* \param yuv_mutex lock on the buffer
823
* \param specs DisplaySpecs struct with information about the display to be recorded
825
* \param root Root entry of the list with damaged areas
827
* \param brwin BRWindow struct contaning the recording window specs
829
* \param enc Encoding options
831
* \param datatemp Buffer for pixel data to be retrieved before placed on the yuv buffer
833
* \param noshmem don't use MIT_Shm extension
835
* \param no_quick_subsample Don't do quick subsampling
838
void UpdateImage(Display * dpy,
840
pthread_mutex_t *yuv_mutex,
847
int no_quick_subsample);
850
* Rerieve pixmap data from xserver
852
* \param dpy Connection to the server
854
* \param root root window of the display
856
* \param data (preallocated)buffer to place the data
858
* \param x x position of the screenshot
860
* \param y y position of the screenshot
862
* \param x x position of the screenshot
864
* \param width width of the screenshot
866
* \param height height position of the screenshot
868
* \param x x position of the screenshot
870
* \returns 0 on Success 1 on Failure
872
int GetZPixmap(Display *dpy,Window root,char *data,int x,int y,int width,int height);
875
* Fill ProgArgs struct with arguments entered at execution
877
* \param argc argc as entered from main
879
* \param argv argv as entered from main
881
* \param arg_return ProgArgs struct to be filled with the options
883
* \returns 0 on Success 1 on Failure
885
int ParseArgs(int argc,char **argv,ProgArgs *arg_return);
888
* Check if needed extensions are present
890
* \param dpy Connection to the server
892
* \param args ProgArgs struct containing the user-set options
894
* \param damage_event gets filled with damage event number
896
* \param damage_error gets filled with damage error number
898
* \note Can be an exit point if extensions are not found
900
void QueryExtensions(Display *dpy,ProgArgs *args,int *damage_event,int *damage_error);
903
* Check and align window size
905
* \param dpy Connection to the server
907
* \param brwin BRWindow struct contaning the initial and final window
909
* \param specs DisplaySpecs struct with information about the display to be recorded
911
* \param args ProgArgs struct containing the user-set options
913
* \returns 0 on Success 1 on Failure
915
int SetBRWindow(Display *dpy,BRWindow *brwin,DisplaySpecs *specs,ProgArgs *args);
918
* Create an array containing the data for the dummy pointer
920
* \param specs DisplaySpecs struct with information about the display to be recorded
922
* \param size Pointer size, always square, always 16.(exists only for the possibility to create
923
* more dummy cursors)
924
* \param color 0 white, 1 black
926
* \param type Always 0.(exists only for the possibility to create
927
* more dummy cursors)
929
* \param npxl Return of pixel value that denotes non-drawing, while applying the cursor
930
* on the target image
932
* \returns Pointer to pixel data of the cursor
934
unsigned char *MakeDummyPointer(DisplaySpecs *specs,int size,int color,int type,unsigned char *npxl);
937
* Sound capturing thread. Data are placed on a list to be picked up by other threads.
939
* \param pdata ProgData struct containing all program data
941
void *CaptureSound(ProgData *pdata);
944
* Sound encoding thread. Picks up data from the buffer queue , encodes and places them
945
* on the vorbis stream.
947
* \param pdata ProgData struct containing all program data
949
void *EncodeSoundBuffer(ProgData *pdata);
952
* Try to open sound device, with the desired parameters,
953
* and place the obtained ones on their place
955
* \param pcm_dev name of the device
957
* \param channels desired number of channels(gets modified with the acieved value)
959
* \param frequency desired frequency(gets modified with the acieved value)
961
* \param buffsize Size of buffer
963
* \param periodsize Size of a period(can be NULL)
965
* \param periodtime Duration of a period(can be NULL)
967
* \param hardpause Set to 1 when the device has to be stopped during pause
968
* and to 0 when it supports pausing
971
* \returns snd_pcm_t handle on success, NULL on failure
973
snd_pcm_t *OpenDev( const char *pcm_dev,
974
unsigned int *channels,
975
unsigned int *frequency,
976
snd_pcm_uframes_t *buffsize,
977
snd_pcm_uframes_t *periodsize,
978
unsigned int *periodtime,
981
* Initialize theora,vorbis encoders, and their respective ogg streams.
983
* \param pdata ProgData struct containing all program data
985
* \param enc_data_t Encoding options
987
* \param buffer_ready when 1, the yuv buffer must be preallocated
988
* when 0 InitEncoder will alocate a new one
991
void InitEncoder(ProgData *pdata,EncData *enc_data_t,int buffer_ready);
994
* Fill Yr,Yg,Yb,Ur,Ug.Ub,Vr,Vg,Vb arrays(globals) with values.
998
*Align the recording window to a divisible by 2 pixel start and
999
*and a size divisible by 16.
1001
* \param start x or y of the recording window
1003
* \param size width or height of the recording window
1005
* \param limit width or height of the Display
1007
* \note This is called separately for width and height.
1009
void SizePack2_8_16(int *start,int *size,int limit);
1012
* Image caching thread. Copies the yuv buffer, compares with the last one and
1013
* caches the result.
1015
* \param pdata ProgData struct containing all program data
1018
void *CacheImageBuffer(ProgData *pdata);
1021
* Initializes paths and everything else needed to start caching
1023
* \param pdata ProgData struct containing all program data
1025
* \param enc_data_t Encoding options
1027
* \param cache_data_t Caching options
1030
void InitCacheData(ProgData *pdata,EncData *enc_data_t,CacheData *cache_data_t);
1033
* Sound caching thread. Simply writes the pcm buffers on disk
1035
* \param pdata ProgData struct containing all program data
1038
void *CacheSoundBuffer(ProgData *pdata);
1041
* Cache loading and processing thread
1043
* \param pdata ProgData struct containing all program data
1046
void *LoadCache(ProgData *pdata);
1049
* As EncodeImageBuffer, only with the assumption that this is not a thread on it's own
1051
* \param pdata ProgData struct containing all program data
1054
void SyncEncodeImageBuffer(ProgData *pdata);
1059
void CancelTimer(void);
1062
* As EncodeSoundBuffer, only with the assumption that this is not a thread on it's own
1064
* \param pdata ProgData struct containing all program data
1067
void SyncEncodeSoundBuffer(ProgData *pdata,signed char *buff);
1070
*Check current running window manager.
1072
* \param dpy Connection to the server
1074
* \param root root window of the display
1076
* \returns Window manager name
1078
char *rmdWMCheck(Display *dpy,Window root);
1081
*Construct an number postfixed name
1083
* \param name base name
1085
* \param newname modified name
1087
* \n number to be used as a postfix
1090
void CacheFileN(char *name,char **newname,int n);
1093
* Change file pointer to a new file while writting
1094
* (file name is incremented with CacheFileN)
1096
* \param name base file name
1098
* \param n number to be used as a postfix
1100
* \param fp File pointer if compression is used(must be NULL otherwise)
1102
* \param ucfp File pointer if compression is NOT used(must be NULL otherwise)
1104
* \returns 0 on Success 1 on Failure
1106
int SwapCacheFilesWrite(char *name,int n,gzFile **fp,FILE **ucfp);
1109
* Change file pointer to a new file while reading
1110
* (file name is incremented with CacheFileN)
1112
* \param name base file name
1114
* \param n number to be used as a postfix
1116
* \param fp File pointer if compression is used(must be NULL otherwise)
1118
* \param ucfp File pointer if compression is NOT used(must be NULL otherwise)
1120
* \returns 0 on Success 1 on Failure
1122
int SwapCacheFilesRead(char *name,int n,gzFile **fp,FILE **ucfp);
1125
* Delete all cache files
1127
* \param cache_data_t Caching options(file names etc.)
1129
* \returns 0 if all files and folders where deleted, 1 otherwise
1131
int PurgeCache(CacheData *cache_data_t,int sound);