summaryrefslogtreecommitdiff
path: root/src/rmd_load_cache.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/rmd_load_cache.c')
-rw-r--r--src/rmd_load_cache.c336
1 files changed, 336 insertions, 0 deletions
diff --git a/src/rmd_load_cache.c b/src/rmd_load_cache.c
new file mode 100644
index 0000000..8ca37f6
--- /dev/null
+++ b/src/rmd_load_cache.c
@@ -0,0 +1,336 @@
+/******************************************************************************
+* 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 "rmd_load_cache.h"
+
+#include "rmd_cache.h"
+#include "rmd_encode_image_buffer.h"
+#include "rmd_encode_sound_buffer.h"
+#include "rmd_macro.h"
+#include "rmd_types.h"
+
+#include <pthread.h>
+#include <signal.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+
+//The number of bytes for every
+//sub-block of the y,u and v planes.
+//Since the blocks are square
+//these are obviously the squares
+//of the widths(specified above),
+//but the definitions bellow are only
+//for convenience anyway.
+#define Y_UNIT_BYTES 0x0100
+#define UV_UNIT_BYTES 0x0040
+
+
+//The frame after retrieval.
+//Based on the Header information
+//we can read the correct amount of bytes.
+typedef struct _CachedFrame{
+ FrameHeader *header;
+ u_int32_t *YBlocks, //identifying number on the grid,
+ *UBlocks, //starting at top left
+ *VBlocks; // >> >>
+ unsigned char *YData, //pointer to data for the blocks that have changed,
+ *UData, //which have to be remapped
+ *VData; //on the buffer when reading
+}CachedFrame;
+
+
+static void rmdLoadBlock(
+ unsigned char *dest,
+ unsigned char *source,
+ int blockno,
+ int width,
+ int height,
+ int blockwidth) {
+
+ int block_i = blockno / (width / blockwidth),//place on the grid
+ block_k = blockno % (width / blockwidth);
+
+ for (int j = 0; j < blockwidth; j++)//we copy rows
+ memcpy( &dest[(block_i * width + block_k) * blockwidth + j * width],
+ &source[j * blockwidth],
+ blockwidth);
+}
+
+//returns number of bytes
+static int rmdReadZF(void * buffer, size_t size, size_t nmemb, FILE *ucfp, gzFile ifp) {
+ if ((ifp != NULL && ucfp != NULL) ||
+ (ifp == NULL && ucfp == NULL))
+ return -1;
+ else if (ucfp != NULL) {
+ return size * fread(buffer, size, nmemb, ucfp);
+ } else
+ return gzread(ifp, buffer, size * nmemb);
+}
+
+static int rmdReadFrame(CachedFrame *frame, FILE *ucfp, gzFile ifp) {
+ int index_entry_size = sizeof(u_int32_t);
+
+ if (frame->header->Ynum > 0) {
+ if (rmdReadZF( frame->YBlocks,
+ index_entry_size,
+ frame->header->Ynum,
+ ucfp,
+ ifp) != index_entry_size * frame->header->Ynum) {
+ return -1;
+ }
+ }
+
+ if (frame->header->Unum > 0) {
+ if (rmdReadZF( frame->UBlocks,
+ index_entry_size,
+ frame->header->Unum,
+ ucfp,
+ ifp) != index_entry_size * frame->header->Unum) {
+ return -1;
+ }
+ }
+
+ if (frame->header->Vnum > 0) {
+ if (rmdReadZF( frame->VBlocks,
+ index_entry_size,
+ frame->header->Vnum,
+ ucfp,
+ ifp) != index_entry_size * frame->header->Vnum) {
+ return -1;
+ }
+ }
+
+ if (frame->header->Ynum > 0) {
+ if (rmdReadZF( frame->YData,
+ Y_UNIT_BYTES,
+ frame->header->Ynum,
+ ucfp,
+ ifp) != Y_UNIT_BYTES * frame->header->Ynum) {
+ return -2;
+ }
+ }
+
+ if (frame->header->Unum > 0) {
+ if (rmdReadZF( frame->UData,
+ UV_UNIT_BYTES,
+ frame->header->Unum,
+ ucfp,
+ ifp) != UV_UNIT_BYTES * frame->header->Unum) {
+ return -2;
+ }
+ }
+
+ if (frame->header->Vnum > 0) {
+ if (rmdReadZF( frame->VData,
+ UV_UNIT_BYTES,
+ frame->header->Vnum,
+ ucfp,
+ ifp) != UV_UNIT_BYTES * frame->header->Vnum) {
+ return -2;
+ }
+ }
+
+ return 0;
+}
+
+void *rmdLoadCache(ProgData *pdata) {
+
+ yuv_buffer *yuv = &pdata->enc_data->yuv;
+ gzFile ifp = NULL;
+ FILE *ucfp = NULL;
+ FILE *afp = pdata->cache_data->afp;
+ FrameHeader fheader;
+ CachedFrame frame;
+ int nth_cache = 1,
+ audio_end = 0,
+ extra_frames = 0, //total number of duplicated frames
+ missing_frames = 0, //if this is found >0 current run will not load
+ //a frame but it will proccess the previous
+ thread_exit = 0, //0 success, -1 couldn't find files,1 couldn't remove
+ blocknum_x = pdata->enc_data->yuv.y_width / Y_UNIT_WIDTH,
+ blocknum_y = pdata->enc_data->yuv.y_height / Y_UNIT_WIDTH,
+ blockszy = Y_UNIT_BYTES,//size of y plane block in bytes
+ blockszuv = UV_UNIT_BYTES;//size of u,v plane blocks in bytes
+ signed char *sound_data = (signed char *)malloc(pdata->periodsize * pdata->sound_framesize);
+
+ u_int32_t YBlocks[(yuv->y_width * yuv->y_height) / Y_UNIT_BYTES],
+ UBlocks[(yuv->uv_width * yuv->uv_height) / UV_UNIT_BYTES],
+ VBlocks[(yuv->uv_width * yuv->uv_height) / UV_UNIT_BYTES];
+
+ // We allocate the frame that we will use
+ frame.header = &fheader;
+ frame.YBlocks = YBlocks;
+ frame.UBlocks = UBlocks;
+ frame.VBlocks = VBlocks;
+ frame.YData = malloc(yuv->y_width * yuv->y_height);
+ frame.UData = malloc(yuv->uv_width * yuv->uv_height);
+ frame.VData = malloc(yuv->uv_width * yuv->uv_height);
+
+ //and the we open our files
+ if (!pdata->args.zerocompression) {
+ ifp = gzopen(pdata->cache_data->imgdata, "rb");
+ if (ifp == NULL) {
+ thread_exit = -1;
+ pthread_exit(&thread_exit);
+ }
+ } else {
+ ucfp = fopen(pdata->cache_data->imgdata, "rb");
+ if (ucfp == NULL) {
+ thread_exit = -1;
+ pthread_exit(&thread_exit);
+ }
+ }
+
+ if (!pdata->args.nosound) {
+ afp = fopen(pdata->cache_data->audiodata, "rb");
+ if (afp == NULL) {
+ thread_exit = -1;
+ pthread_exit(&thread_exit);
+ }
+ }
+
+ //this will be used now to define if we proccess audio or video
+ //on any given loop.
+ pdata->avd = 0;
+ //If sound finishes first,we go on with the video.
+ //If video ends we will do one more run to flush audio in the ogg file
+ while (pdata->running) {
+ //video load and encoding
+ if (pdata->avd <= 0 || pdata->args.nosound || audio_end) {
+ if (missing_frames > 0) {
+ extra_frames++;
+ missing_frames--;
+ rmdSyncEncodeImageBuffer(pdata);
+ } else if (((!pdata->args.zerocompression) &&
+ (gzread(ifp, frame.header, sizeof(FrameHeader)) ==
+ sizeof(FrameHeader) )) ||
+ ((pdata->args.zerocompression) &&
+ (fread(frame.header, sizeof(FrameHeader), 1, ucfp) == 1))) {
+ //sync
+ missing_frames += frame.header->current_total -
+ (extra_frames + frame.header->frameno);
+ if (pdata->frames_total) {
+ fprintf(stdout, "\r[%d%%] ",
+ ((frame.header->frameno + extra_frames) * 100) / pdata->frames_total);
+ } else
+ fprintf(stdout, "\r[%d frames rendered] ",
+ (frame.header->frameno + extra_frames));
+ fflush(stdout);
+ if ( (frame.header->Ynum <= blocknum_x * blocknum_y) &&
+ (frame.header->Unum <= blocknum_x * blocknum_y) &&
+ (frame.header->Vnum <= blocknum_x * blocknum_y) &&
+ !rmdReadFrame( &frame,
+ (pdata->args.zerocompression ? ucfp : NULL),
+ (pdata->args.zerocompression ? NULL : ifp))
+ ) {
+
+ //load the blocks for each buffer
+ if (frame.header->Ynum)
+ for (int j = 0; j < frame.header->Ynum; j++)
+ rmdLoadBlock( yuv->y,
+ &frame.YData[j * blockszy],
+ frame.YBlocks[j],
+ yuv->y_width,
+ yuv->y_height,
+ Y_UNIT_WIDTH);
+ if (frame.header->Unum)
+ for (int j = 0; j < frame.header->Unum; j++)
+ rmdLoadBlock( yuv->u,
+ &frame.UData[j * blockszuv],
+ frame.UBlocks[j],
+ yuv->uv_width,
+ yuv->uv_height,
+ UV_UNIT_WIDTH);
+ if (frame.header->Vnum)
+ for (int j = 0; j < frame.header->Vnum; j++)
+ rmdLoadBlock( yuv->v,
+ &frame.VData[j * blockszuv],
+ frame.VBlocks[j],
+ yuv->uv_width,
+ yuv->uv_height,
+ UV_UNIT_WIDTH);
+
+ //encode. This is not made in a thread since
+ //now blocking is not a problem
+ //and this way sync problems
+ //can be avoided more easily.
+ rmdSyncEncodeImageBuffer(pdata);
+ } else {
+ raise(SIGINT);
+ continue;
+ }
+ } else {
+ if (rmdSwapCacheFilesRead( pdata->cache_data->imgdata,
+ nth_cache,
+ &ifp,
+ &ucfp)) {
+ raise(SIGINT);
+ } else {
+ fprintf(stderr, "\t[Cache File %d]", nth_cache);
+ nth_cache++;
+ }
+ continue;
+ }
+ //audio load and encoding
+ } else {
+ if (!audio_end) {
+ int nbytes = fread(sound_data, 1, pdata->periodsize*
+ pdata->sound_framesize, afp);
+ if (nbytes <= 0)
+ audio_end = 1;
+ else
+ rmdSyncEncodeSoundBuffer(pdata, sound_data);
+ }
+ }
+ }
+
+ pthread_mutex_lock(&pdata->theora_lib_mutex);
+ pdata->th_encoding_clean = 1;
+ pthread_cond_signal(&pdata->theora_lib_clean);
+ pthread_mutex_unlock(&pdata->theora_lib_mutex);
+
+ pthread_mutex_lock(&pdata->vorbis_lib_mutex);
+ pdata->v_encoding_clean = 1;
+ pthread_cond_signal(&pdata->vorbis_lib_clean);
+ pthread_mutex_unlock(&pdata->vorbis_lib_mutex);
+ fprintf(stdout, "\n");
+
+ // Clear frame
+ free(frame.YData);
+ free(frame.UData);
+ free(frame.VData);
+
+ free(sound_data);
+
+ if (!pdata->args.nosound)
+ fclose(afp);
+
+ pthread_exit(&thread_exit);
+}
© All Rights Reserved