~ubuntu-branches/ubuntu/karmic/recordmydesktop/karmic

« back to all changes in this revision

Viewing changes to src/rmd_cache_frame.c

  • Committer: Bazaar Package Importer
  • Author(s): Alan Pope
  • Date: 2009-04-21 10:57:22 UTC
  • mto: This revision was merged to the branch mainline in revision 7.
  • Revision ID: james.westby@ubuntu.com-20090421105722-6sgxtp7en3dbyjfs
Tags: upstream-0.3.8.1
ImportĀ upstreamĀ versionĀ 0.3.8.1

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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_cache_frame.h"
 
29
 
 
30
#include "rmd_yuv_utils.h"
 
31
#include "rmd_cache.h"
 
32
#include "rmd_types.h"
 
33
 
 
34
#include <signal.h>
 
35
#include <string.h>
 
36
#include <stdio.h>
 
37
#include <errno.h>
 
38
#include <math.h>
 
39
 
 
40
 
 
41
#define BYTES_PER_MB          (1024 * 1024)
 
42
#define CACHE_OUT_BUFFER_SIZE (4 * 1024)
 
43
#define CACHE_FILE_SIZE_LIMIT (500 * 1024 * 1024)
 
44
 
 
45
 
 
46
static int FlushBlock(unsigned char *buf,
 
47
                      int blockno,
 
48
                      int width,
 
49
                      int height,
 
50
                      int blockwidth,
 
51
                      gzFile *fp,
 
52
                      FILE *ucfp,
 
53
                      int flush) {
 
54
    int j,i,
 
55
        bytes_written=0,
 
56
        block_i=(!blockwidth)?0:(blockno/(width/blockwidth)),//place on the grid
 
57
        block_k=(!blockwidth)?0:(blockno%(width/blockwidth));
 
58
    register unsigned char *buf_reg=(&buf[(block_i*
 
59
                                         width+
 
60
                                         block_k)*blockwidth]);
 
61
    static unsigned char out_buffer[CACHE_OUT_BUFFER_SIZE];
 
62
    static unsigned int out_buffer_bytes=0;
 
63
 
 
64
    if(out_buffer_bytes+pow(blockwidth,2)>=CACHE_OUT_BUFFER_SIZE ||
 
65
       (flush && out_buffer_bytes)){
 
66
        if(ucfp==NULL)
 
67
            gzwrite(fp,(void *)out_buffer,out_buffer_bytes);
 
68
        else
 
69
            fwrite((void *)out_buffer,1,out_buffer_bytes,ucfp);
 
70
        bytes_written=out_buffer_bytes;
 
71
        out_buffer_bytes=0;
 
72
    }
 
73
    if(!flush){
 
74
        register unsigned char *out_buf_reg=&out_buffer[out_buffer_bytes];
 
75
        for(j=0;j<blockwidth;j++){
 
76
            for(i=0;i<blockwidth;i++)
 
77
                (*out_buf_reg++)=(*buf_reg++);
 
78
            out_buffer_bytes+=blockwidth;
 
79
            buf_reg+=width-blockwidth;
 
80
        }
 
81
    }
 
82
 
 
83
    return bytes_written;
 
84
}
 
85
 
 
86
void *CacheImageBuffer(ProgData *pdata){
 
87
 
 
88
    gzFile *fp=NULL;
 
89
    FILE *ucfp=NULL;
 
90
    int index_entry_size=sizeof(u_int32_t),
 
91
        blocknum_x=pdata->enc_data->yuv.y_width/Y_UNIT_WIDTH,
 
92
        blocknum_y=pdata->enc_data->yuv.y_height/Y_UNIT_WIDTH,
 
93
        firstrun=1,
 
94
        frameno=0,
 
95
        nbytes=0,
 
96
        nth_cache=1;
 
97
    u_int32_t   ynum,unum,vnum,
 
98
                y_short_blocks[blocknum_x*blocknum_y],
 
99
                u_short_blocks[blocknum_x*blocknum_y],
 
100
                v_short_blocks[blocknum_x*blocknum_y];
 
101
    unsigned long long int total_bytes          = 0;
 
102
    unsigned long long int total_received_bytes = 0;
 
103
 
 
104
    if(!pdata->args.zerocompression){
 
105
        fp=pdata->cache_data->ifp;
 
106
        if(fp==NULL)exit(13);
 
107
    }
 
108
    else{
 
109
        ucfp=pdata->cache_data->uncifp;
 
110
        if(ucfp==NULL)exit(13);
 
111
    }
 
112
 
 
113
 
 
114
    while(pdata->running){
 
115
        int j;
 
116
        FrameHeader fheader;
 
117
        ynum=unum=vnum=0;
 
118
 
 
119
        pdata->th_enc_thread_waiting=1;
 
120
        pthread_mutex_lock(&pdata->img_buff_ready_mutex);
 
121
        pthread_cond_wait(&pdata->image_buffer_ready,
 
122
                          &pdata->img_buff_ready_mutex);
 
123
        pthread_mutex_unlock(&pdata->img_buff_ready_mutex);
 
124
        pdata->th_enc_thread_waiting=0;
 
125
 
 
126
        if (pdata->paused) {
 
127
            pthread_mutex_lock(&pdata->pause_mutex);
 
128
            pthread_cond_wait(&pdata->pause_cond, &pdata->pause_mutex);
 
129
            pthread_mutex_unlock(&pdata->pause_mutex);
 
130
        }
 
131
 
 
132
        pthread_mutex_lock(&pdata->yuv_mutex);
 
133
 
 
134
        //find and flush different blocks
 
135
        if(firstrun){
 
136
            firstrun=0;
 
137
            for(j=0;j<blocknum_x*blocknum_y;j++){
 
138
                    ynum++;
 
139
                    yblocks[ynum-1]=1;
 
140
                    y_short_blocks[ynum-1]=j;
 
141
                    unum++;
 
142
                    ublocks[unum-1]=1;
 
143
                    u_short_blocks[ynum-1]=j;
 
144
                    vnum++;
 
145
                    vblocks[vnum-1]=1;
 
146
                    v_short_blocks[ynum-1]=j;
 
147
            }
 
148
        }
 
149
        else{
 
150
            /**COMPRESS ARRAYS*/
 
151
            for(j=0;j<blocknum_x*blocknum_y;j++){
 
152
                if(yblocks[j]){
 
153
                    ynum++;
 
154
                    y_short_blocks[ynum-1]=j;
 
155
                }
 
156
                if(ublocks[j]){
 
157
                    unum++;
 
158
                    u_short_blocks[unum-1]=j;
 
159
                }
 
160
                if(vblocks[j]){
 
161
                    vnum++;
 
162
                    v_short_blocks[vnum-1]=j;
 
163
                }
 
164
            }
 
165
        }
 
166
 
 
167
        /**WRITE FRAME TO DISK*/
 
168
        if(!pdata->args.zerocompression){
 
169
            if(ynum*4+unum+vnum>(blocknum_x*blocknum_y*6)/10)
 
170
                gzsetparams (fp,1,Z_FILTERED);
 
171
            else
 
172
                gzsetparams (fp,0,Z_FILTERED);
 
173
        }
 
174
 
 
175
        strncpy(fheader.frame_prefix,"FRAM",4);
 
176
        fheader.frameno=++frameno;
 
177
        fheader.current_total = pdata->frames_total;
 
178
 
 
179
        fheader.Ynum=ynum;
 
180
        fheader.Unum=unum;
 
181
        fheader.Vnum=vnum;
 
182
        if(!pdata->args.zerocompression){
 
183
            nbytes+=gzwrite(fp,(void*)&fheader,sizeof(FrameHeader));
 
184
            //flush indexes
 
185
            if(ynum)nbytes+=gzwrite(fp,
 
186
                                    (void*)y_short_blocks,
 
187
                                    ynum*index_entry_size);
 
188
            if(unum)nbytes+=gzwrite(fp,
 
189
                                    (void*)u_short_blocks,
 
190
                                    unum*index_entry_size);
 
191
            if(vnum)nbytes+=gzwrite(fp,
 
192
                                    (void*)v_short_blocks,
 
193
                                    vnum*index_entry_size);
 
194
        }
 
195
        else{
 
196
            nbytes+=sizeof(FrameHeader)*
 
197
                    fwrite((void*)&fheader,sizeof(FrameHeader),1,ucfp);
 
198
            //flush indexes
 
199
            if(ynum)nbytes+=index_entry_size*
 
200
                            fwrite(y_short_blocks,index_entry_size,ynum,ucfp);
 
201
            if(unum)nbytes+=index_entry_size*
 
202
                            fwrite(u_short_blocks,index_entry_size,unum,ucfp);
 
203
            if(vnum)nbytes+=index_entry_size*
 
204
                            fwrite(v_short_blocks,index_entry_size,vnum,ucfp);
 
205
        }
 
206
        //flush the blocks for each buffer
 
207
        if(ynum){
 
208
            for(j=0;j<ynum;j++)
 
209
                nbytes+=FlushBlock( pdata->enc_data->yuv.y,y_short_blocks[j],
 
210
                                    pdata->enc_data->yuv.y_width,
 
211
                                    pdata->enc_data->yuv.y_height,
 
212
                                    Y_UNIT_WIDTH,
 
213
                                    fp,
 
214
                                    ucfp,
 
215
                                    0);
 
216
        }
 
217
        if(unum){
 
218
            for(j=0;j<unum;j++)
 
219
                nbytes+=FlushBlock( pdata->enc_data->yuv.u,u_short_blocks[j],
 
220
                                    pdata->enc_data->yuv.uv_width,
 
221
                                    pdata->enc_data->yuv.uv_height,
 
222
                                    UV_UNIT_WIDTH,
 
223
                                    fp,
 
224
                                    ucfp,
 
225
                                    0);
 
226
        }
 
227
        if(vnum){
 
228
            for(j=0;j<vnum;j++)
 
229
                nbytes+=FlushBlock( pdata->enc_data->yuv.v,v_short_blocks[j],
 
230
                                    pdata->enc_data->yuv.uv_width,
 
231
                                    pdata->enc_data->yuv.uv_height,
 
232
                                    UV_UNIT_WIDTH,
 
233
                                    fp,
 
234
                                    ucfp,
 
235
                                    0);
 
236
        }
 
237
        //release main buffer
 
238
        pthread_mutex_unlock(&pdata->yuv_mutex);
 
239
 
 
240
        nbytes+=FlushBlock(NULL,0,0,0,0,fp,ucfp,1);
 
241
        /**@________________@**/
 
242
        pdata->avd+=pdata->frametime;
 
243
        if(nbytes>CACHE_FILE_SIZE_LIMIT){
 
244
            if(SwapCacheFilesWrite(pdata->cache_data->imgdata,
 
245
                                   nth_cache,&fp,&ucfp)){
 
246
                fprintf(stderr,"New cache file could not be created.\n"
 
247
                               "Ending recording...\n");
 
248
                fflush(stderr);
 
249
                raise(SIGINT);  //if for some reason we cannot make a new file
 
250
                                //we have to stop. If we are out of space,
 
251
                                //which means
 
252
                                //that encoding cannot happen either,
 
253
                                //InitEncoder will cause an abrupt end with an
 
254
                                //error code and the cache will remain intact.
 
255
                                //If we've chosen separate two-stages,
 
256
                                //the program will make a
 
257
                                //clean exit.
 
258
                                //In either case data will be preserved so if
 
259
                                //space is freed the recording
 
260
                                //can be proccessed later.
 
261
            }
 
262
            total_bytes += nbytes;
 
263
            nth_cache++;
 
264
            nbytes=0;
 
265
        }
 
266
    }
 
267
    total_bytes += nbytes;
 
268
 
 
269
    {
 
270
      unsigned int bytes_per_pixel  = pdata->specs.depth >= 24 ? 4 : 2;
 
271
      unsigned int pixels_per_frame = pdata->brwin.rrect.width * pdata->brwin.rrect.height;
 
272
      
 
273
      total_received_bytes = ((unsigned int)frameno) * bytes_per_pixel * pixels_per_frame;
 
274
    }
 
275
 
 
276
    if(total_received_bytes){
 
277
        double percent_of_data_left = (total_bytes / (double)total_received_bytes) * 100;
 
278
 
 
279
        fprintf(stderr,
 
280
                "\n"
 
281
                "*********************************************\n"
 
282
                "\n"
 
283
                "Cached %llu MB, from %llu MB that were received.\n"
 
284
                "Average cache compression ratio: %.1f %%\n"
 
285
                "\n"
 
286
                "*********************************************\n",
 
287
                total_bytes / BYTES_PER_MB,
 
288
                total_received_bytes / BYTES_PER_MB,
 
289
                100 - percent_of_data_left);
 
290
 
 
291
    }
 
292
 
 
293
    fprintf(stderr,
 
294
            "Saved %d frames in a total of %d requests\n",
 
295
            frameno,
 
296
            pdata->frames_total);
 
297
    fflush(stderr);
 
298
 
 
299
    if(!pdata->args.zerocompression){
 
300
        gzflush(fp,Z_FINISH);
 
301
        gzclose(fp);
 
302
    }
 
303
    else{
 
304
        fflush(ucfp);
 
305
        fclose(ucfp);
 
306
    }
 
307
    pthread_exit(&errno);
 
308
}