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