1 /******************************************************************************
2 * recordMyDesktop *
3 *******************************************************************************
4 * *
5 * Copyright (C) 2006,2007,2008 John Varouhakis *
6 * *
7 * *
8 * This program is free software; you can redistribute it and/or modify *
9 * it under the terms of the GNU General Public License as published by *
10 * the Free Software Foundation; either version 2 of the License, or *
11 * (at your option) any later version. *
12 * *
13 * This program is distributed in the hope that it will be useful, *
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
16 * GNU General Public License for more details. *
17 * *
18 * You should have received a copy of the GNU General Public License *
19 * along with this program; if not, write to the Free Software *
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA *
21 * *
22 * *
23 * *
24 * For further information contact me at johnvarouhakis@gmail.com *
25 ******************************************************************************/
26
27 #include "config.h"
28 #include "rmd_load_cache.h"
29
30 #include "rmd_cache.h"
31 #include "rmd_encode_image_buffer.h"
32 #include "rmd_encode_sound_buffer.h"
33 #include "rmd_macro.h"
34 #include "rmd_types.h"
35
36 #include <pthread.h>
37 #include <signal.h>
38
39 #include <stdio.h>
40 #include <stdlib.h>
41 #include <string.h>
42
43
44 //The number of bytes for every
45 //sub-block of the y,u and v planes.
46 //Since the blocks are square
47 //these are obviously the squares
48 //of the widths(specified above),
49 //but the definitions bellow are only
50 //for convenience anyway.
51 #define Y_UNIT_BYTES 0x0100
52 #define UV_UNIT_BYTES 0x0040
53
54
55 //The frame after retrieval.
56 //Based on the Header information
57 //we can read the correct amount of bytes.
58 typedef struct _CachedFrame{
59 FrameHeader *header;
60 u_int32_t *YBlocks, //identifying number on the grid,
61 *UBlocks, //starting at top left
62 *VBlocks; // >> >>
63 unsigned char *YData, //pointer to data for the blocks that have changed,
64 *UData, //which have to be remapped
65 *VData; //on the buffer when reading
66 }CachedFrame;
67
68
LoadBlock(unsigned char * dest,unsigned char * source,int blockno,int width,int height,int blockwidth)69 static void LoadBlock(unsigned char *dest,
70 unsigned char *source,
71 int blockno,
72 int width,
73 int height,
74 int blockwidth) {
75 int j,
76 block_i=blockno/(width/blockwidth),//place on the grid
77 block_k=blockno%(width/blockwidth);
78 for(j=0;j<blockwidth;j++)//we copy rows
79 memcpy( &dest[(block_i*width+block_k)*blockwidth+j*width],
80 &source[j*blockwidth],
81 blockwidth);
82 }
83
84 //returns number of bytes
ReadZF(void * buffer,size_t size,size_t nmemb,FILE * ucfp,gzFile * ifp)85 static int ReadZF(void * buffer, size_t size, size_t nmemb, FILE *ucfp, gzFile *ifp) {
86 if((ifp!=NULL && ucfp!=NULL)||
87 (ifp==NULL && ucfp==NULL))
88 return -1;
89 else if(ucfp!=NULL){
90 return (size*fread(buffer,size,nmemb,ucfp));
91 }
92 else
93 return gzread(ifp,buffer,size*nmemb);
94 }
95
ReadFrame(CachedFrame * frame,FILE * ucfp,gzFile * ifp)96 static int ReadFrame(CachedFrame *frame, FILE *ucfp, gzFile *ifp) {
97 int index_entry_size=sizeof(u_int32_t);
98 if(frame->header->Ynum>0){
99 if(ReadZF(frame->YBlocks,
100 index_entry_size,
101 frame->header->Ynum,
102 ucfp,
103 ifp)!=index_entry_size*frame->header->Ynum){
104 return -1;
105 }
106 }
107 if(frame->header->Unum>0){
108 if(ReadZF(frame->UBlocks,
109 index_entry_size,
110 frame->header->Unum,
111 ucfp,
112 ifp)!=index_entry_size*frame->header->Unum){
113 return -1;
114 }
115 }
116 if(frame->header->Vnum>0){
117 if(ReadZF(frame->VBlocks,
118 index_entry_size,
119 frame->header->Vnum,
120 ucfp,
121 ifp)!=index_entry_size*frame->header->Vnum){
122 return -1;
123 }
124 }
125 if(frame->header->Ynum>0){
126 if(ReadZF(frame->YData,
127 Y_UNIT_BYTES,
128 frame->header->Ynum,
129 ucfp,
130 ifp)!=Y_UNIT_BYTES*frame->header->Ynum){
131 return -2;
132 }
133 }
134 if(frame->header->Unum>0){
135 if(ReadZF(frame->UData,
136 UV_UNIT_BYTES,
137 frame->header->Unum,
138 ucfp,
139 ifp)!=UV_UNIT_BYTES*frame->header->Unum){
140 return -2;
141 }
142 }
143 if(frame->header->Vnum>0){
144 if(ReadZF(frame->VData,
145 UV_UNIT_BYTES,
146 frame->header->Vnum,
147 ucfp,
148 ifp)!=UV_UNIT_BYTES*frame->header->Vnum){
149 return -2;
150 }
151 }
152 return 0;
153 }
154
LoadCache(ProgData * pdata)155 void *LoadCache(ProgData *pdata){
156
157 yuv_buffer *yuv=&pdata->enc_data->yuv;
158 gzFile *ifp=NULL;
159 FILE *ucfp=NULL;
160 FILE *afp=pdata->cache_data->afp;
161 FrameHeader fheader;
162 CachedFrame frame;
163 int j=0,
164 nth_cache=1,
165 audio_end=0,
166 extra_frames=0,//total number of duplicated frames
167 missing_frames=0,//if this is found >0 current run will not load
168 //a frame but it will proccess the previous
169 thread_exit=0,//0 success, -1 couldn't find files,1 couldn't remove
170 blocknum_x=pdata->enc_data->yuv.y_width/Y_UNIT_WIDTH,
171 blocknum_y=pdata->enc_data->yuv.y_height/Y_UNIT_WIDTH,
172 blockszy=Y_UNIT_BYTES,//size of y plane block in bytes
173 blockszuv=UV_UNIT_BYTES;//size of u,v plane blocks in bytes
174 signed char *sound_data=(signed char *)malloc(pdata->periodsize*
175 pdata->sound_framesize);
176
177 u_int32_t YBlocks[(yuv->y_width*yuv->y_height)/Y_UNIT_BYTES],
178 UBlocks[(yuv->uv_width*yuv->uv_height)/UV_UNIT_BYTES],
179 VBlocks[(yuv->uv_width*yuv->uv_height)/UV_UNIT_BYTES];
180
181 // We allocate the frame that we will use
182 frame.header = &fheader;
183 frame.YBlocks = YBlocks;
184 frame.UBlocks = UBlocks;
185 frame.VBlocks = VBlocks;
186 frame.YData = malloc(yuv->y_width * yuv->y_height);
187 frame.UData = malloc(yuv->uv_width * yuv->uv_height);
188 frame.VData = malloc(yuv->uv_width * yuv->uv_height);
189
190 //and the we open our files
191 if(!pdata->args.zerocompression){
192 ifp=gzopen(pdata->cache_data->imgdata,"rb");
193 if(ifp==NULL){
194 thread_exit=-1;
195 pthread_exit(&thread_exit);
196 }
197 }
198 else{
199 ucfp=fopen(pdata->cache_data->imgdata,"rb");
200 if(ucfp==NULL){
201 thread_exit=-1;
202 pthread_exit(&thread_exit);
203 }
204 }
205
206
207 if(!pdata->args.nosound){
208 afp=fopen(pdata->cache_data->audiodata,"rb");
209 if(afp==NULL){
210 thread_exit=-1;
211 pthread_exit(&thread_exit);
212 }
213 }
214
215 //this will be used now to define if we proccess audio or video
216 //on any given loop.
217 pdata->avd=0;
218 //If sound finishes first,we go on with the video.
219 //If video ends we will do one more run to flush audio in the ogg file
220 while(pdata->running){
221 //video load and encoding
222 if(pdata->avd<=0 || pdata->args.nosound || audio_end){
223 if(missing_frames>0){
224 extra_frames++;
225 missing_frames--;
226 SyncEncodeImageBuffer(pdata);
227 }
228 else if(((!pdata->args.zerocompression)&&
229 (gzread(ifp,frame.header,sizeof(FrameHeader))==
230 sizeof(FrameHeader) ))||
231 ((pdata->args.zerocompression)&&
232 (fread(frame.header,sizeof(FrameHeader),1,ucfp)==1))){
233 //sync
234 missing_frames+=frame.header->current_total-
235 (extra_frames+frame.header->frameno);
236 if (pdata->frames_total) {
237 fprintf(stdout,
238 "\r[%d%%] ",
239 ((frame.header->frameno + extra_frames) * 100) / pdata->frames_total);
240 }
241 else
242 fprintf(stdout,"\r[%d frames rendered] ",
243 (frame.header->frameno+extra_frames));
244 fflush(stdout);
245 if( (frame.header->Ynum<=blocknum_x*blocknum_y) &&
246 (frame.header->Unum<=blocknum_x*blocknum_y) &&
247 (frame.header->Vnum<=blocknum_x*blocknum_y) &&
248 (!ReadFrame(&frame,
249 ((pdata->args.zerocompression)?ucfp:NULL),
250 ((pdata->args.zerocompression)?NULL:ifp)))
251 ){
252 //load the blocks for each buffer
253 if(frame.header->Ynum)
254 for(j=0;j<frame.header->Ynum;j++)
255 LoadBlock( yuv->y,
256 &frame.YData[j*blockszy],
257 frame.YBlocks[j],
258 yuv->y_width,
259 yuv->y_height,
260 Y_UNIT_WIDTH);
261 if(frame.header->Unum)
262 for(j=0;j<frame.header->Unum;j++)
263 LoadBlock( yuv->u,
264 &frame.UData[j*blockszuv],
265 frame.UBlocks[j],
266 yuv->uv_width,
267 yuv->uv_height,
268 UV_UNIT_WIDTH);
269 if(frame.header->Vnum)
270 for(j=0;j<frame.header->Vnum;j++)
271 LoadBlock( yuv->v,
272 &frame.VData[j*blockszuv],
273 frame.VBlocks[j],
274 yuv->uv_width,
275 yuv->uv_height,
276 UV_UNIT_WIDTH);
277 //encode. This is not made in a thread since
278 //now blocking is not a problem
279 //and this way sync problems
280 //can be avoided more easily.
281 SyncEncodeImageBuffer(pdata);
282 }
283 else{
284 raise(SIGINT);
285 continue;
286 }
287 }
288 else{
289 if(SwapCacheFilesRead(pdata->cache_data->imgdata,
290 nth_cache,
291 &ifp,
292 &ucfp)){
293 raise(SIGINT);
294 }
295 else{
296 fprintf(stderr,"\t[Cache File %d]",nth_cache);
297 nth_cache++;
298 }
299 continue;
300 }
301 }
302 //audio load and encoding
303 else{
304 if(!audio_end){
305 int nbytes=fread(sound_data,1,pdata->periodsize*
306 pdata->sound_framesize,afp);
307 if(nbytes<=0)
308 audio_end=1;
309 else
310 SyncEncodeSoundBuffer(pdata,sound_data);
311 }
312 }
313 }
314
315 pdata->v_encoding_clean=pdata->th_encoding_clean=1;
316 pthread_mutex_lock(&pdata->theora_lib_mutex);
317 pthread_cond_signal(&pdata->theora_lib_clean);
318 pthread_mutex_unlock(&pdata->theora_lib_mutex);
319 pthread_mutex_lock(&pdata->vorbis_lib_mutex);
320 pthread_cond_signal(&pdata->vorbis_lib_clean);
321 pthread_mutex_unlock(&pdata->vorbis_lib_mutex);
322 fprintf(stdout,"\n");
323
324 // Clear frame
325 free(frame.YData);
326 free(frame.UData);
327 free(frame.VData);
328
329 free(sound_data);
330
331 if(!pdata->args.nosound){
332 fclose(afp);
333 }
334
335 pthread_exit(&thread_exit);
336
337
338 }
339
340