summaryrefslogtreecommitdiff
path: root/src/rmd_cache_frame.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/rmd_cache_frame.c')
-rw-r--r--src/rmd_cache_frame.c319
1 files changed, 319 insertions, 0 deletions
diff --git a/src/rmd_cache_frame.c b/src/rmd_cache_frame.c
new file mode 100644
index 0000000..7b8a2f3
--- /dev/null
+++ b/src/rmd_cache_frame.c
@@ -0,0 +1,319 @@
+/******************************************************************************
+* 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_cache_frame.h"
+
+#include "rmd_yuv_utils.h"
+#include "rmd_cache.h"
+#include "rmd_types.h"
+
+#include <signal.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <math.h>
+
+
+#define BYTES_PER_MB (1024 * 1024)
+#define CACHE_OUT_BUFFER_SIZE (4 * 1024)
+#define CACHE_FILE_SIZE_LIMIT (500 * 1024 * 1024)
+
+
+static int rmdFlushBlock(
+ unsigned char *buf,
+ int blockno,
+ int width,
+ int height,
+ int blockwidth,
+ gzFile fp,
+ FILE *ucfp,
+ int flush) {
+
+ int bytes_written = 0,
+ block_i = (!blockwidth) ? 0 : (blockno / (width / blockwidth)),//place on the grid
+ block_k = (!blockwidth) ? 0 : (blockno % (width / blockwidth));
+ register unsigned char *buf_reg = (&buf[(block_i * width + block_k) * blockwidth]);
+ static unsigned char out_buffer[CACHE_OUT_BUFFER_SIZE];
+ static unsigned int out_buffer_bytes = 0;
+
+ if (out_buffer_bytes + pow(blockwidth, 2) >= CACHE_OUT_BUFFER_SIZE || (flush && out_buffer_bytes)) {
+ if (ucfp == NULL)
+ gzwrite(fp, (void *)out_buffer, out_buffer_bytes);
+ else
+ fwrite((void *)out_buffer, 1, out_buffer_bytes, ucfp);
+
+ bytes_written = out_buffer_bytes;
+ out_buffer_bytes = 0;
+ }
+
+ if (!flush) {
+ register unsigned char *out_buf_reg = &out_buffer[out_buffer_bytes];
+
+ for (int j = 0;j < blockwidth; j++) {
+
+ for(int i = 0;i < blockwidth; i++)
+ (*out_buf_reg++) = (*buf_reg++);
+
+ out_buffer_bytes += blockwidth;
+ buf_reg += width - blockwidth;
+ }
+ }
+
+ return bytes_written;
+}
+
+void *rmdCacheImageBuffer(ProgData *pdata) {
+
+ gzFile fp = NULL;
+ FILE *ucfp = NULL;
+ int index_entry_size = sizeof(u_int32_t),
+ blocknum_x = pdata->enc_data->yuv.y_width / Y_UNIT_WIDTH,
+ blocknum_y = pdata->enc_data->yuv.y_height / Y_UNIT_WIDTH,
+ firstrun = 1,
+ frameno = 0,
+ nbytes = 0,
+ nth_cache = 1;
+ u_int32_t ynum, unum, vnum,
+ y_short_blocks[blocknum_x * blocknum_y],
+ u_short_blocks[blocknum_x * blocknum_y],
+ v_short_blocks[blocknum_x * blocknum_y];
+ unsigned long long int total_bytes = 0;
+ unsigned long long int total_received_bytes = 0;
+ unsigned int capture_frameno = 0;
+
+ if (!pdata->args.zerocompression) {
+ fp = pdata->cache_data->ifp;
+
+ if (fp == NULL)
+ exit(13);
+ } else {
+ ucfp = pdata->cache_data->uncifp;
+
+ if (ucfp == NULL)
+ exit(13);
+ }
+
+ while (pdata->running) {
+ FrameHeader fheader;
+
+ ynum = unum = vnum = 0;
+
+ pthread_mutex_lock(&pdata->img_buff_ready_mutex);
+ while (pdata->running && capture_frameno >= pdata->capture_frameno)
+ pthread_cond_wait(&pdata->image_buffer_ready, &pdata->img_buff_ready_mutex);
+
+ capture_frameno = pdata->capture_frameno;
+ pthread_mutex_unlock(&pdata->img_buff_ready_mutex);
+
+ pthread_mutex_lock(&pdata->pause_mutex);
+ while (pdata->paused)
+ pthread_cond_wait(&pdata->pause_cond, &pdata->pause_mutex);
+ pthread_mutex_unlock(&pdata->pause_mutex);
+
+ pthread_mutex_lock(&pdata->yuv_mutex);
+
+ //find and flush different blocks
+ if (firstrun) {
+ firstrun = 0;
+ for(int j = 0; j < blocknum_x * blocknum_y; j++) {
+ yblocks[ynum] = 1;
+ y_short_blocks[ynum] = j;
+ ynum++;
+ ublocks[unum] = 1;
+ u_short_blocks[unum] = j;
+ unum++;
+ vblocks[vnum] = 1;
+ v_short_blocks[vnum] = j;
+ vnum++;
+ }
+ } else {
+ /**COMPRESS ARRAYS*/
+ for(int j = 0; j < blocknum_x * blocknum_y; j++) {
+ if (yblocks[j]) {
+ y_short_blocks[ynum] = j;
+ ynum++;
+ }
+ if (ublocks[j]) {
+ u_short_blocks[unum] = j;
+ unum++;
+ }
+ if (vblocks[j]) {
+ v_short_blocks[vnum] = j;
+ vnum++;
+ }
+ }
+ }
+
+ /**WRITE FRAME TO DISK*/
+ if (!pdata->args.zerocompression) {
+ if (ynum * 4 + unum + vnum > (blocknum_x * blocknum_y * 6) / 10)
+ gzsetparams(fp, 1, Z_FILTERED);
+ else
+ gzsetparams(fp, 0, Z_FILTERED);
+ }
+
+ strncpy(fheader.frame_prefix, "FRAM", 4);
+ fheader.frameno = ++frameno;
+ fheader.current_total = pdata->frames_total;
+
+ fheader.Ynum = ynum;
+ fheader.Unum = unum;
+ fheader.Vnum = vnum;
+
+ if (!pdata->args.zerocompression) {
+ nbytes += gzwrite(fp, (void*)&fheader, sizeof(FrameHeader));
+ //flush indexes
+ if (ynum)
+ nbytes += gzwrite(fp, (void*)y_short_blocks, ynum * index_entry_size);
+
+ if (unum)
+ nbytes += gzwrite(fp, (void*)u_short_blocks, unum * index_entry_size);
+
+ if (vnum)
+ nbytes += gzwrite(fp, (void*)v_short_blocks, vnum * index_entry_size);
+ } else {
+ nbytes += sizeof(FrameHeader)*
+ fwrite((void*)&fheader, sizeof(FrameHeader), 1, ucfp);
+ //flush indexes
+ if (ynum)
+ nbytes += index_entry_size * fwrite(y_short_blocks, index_entry_size, ynum, ucfp);
+
+ if (unum)
+ nbytes += index_entry_size * fwrite(u_short_blocks, index_entry_size, unum, ucfp);
+
+ if (vnum)
+ nbytes += index_entry_size * fwrite(v_short_blocks, index_entry_size, vnum, ucfp);
+ }
+
+ //flush the blocks for each buffer
+ if (ynum) {
+ for(int j = 0; j < ynum; j++)
+ nbytes += rmdFlushBlock(pdata->enc_data->yuv.y,
+ y_short_blocks[j],
+ pdata->enc_data->yuv.y_width,
+ pdata->enc_data->yuv.y_height,
+ Y_UNIT_WIDTH,
+ fp,
+ ucfp,
+ 0);
+ }
+
+ if (unum) {
+ for(int j = 0; j < unum; j++)
+ nbytes += rmdFlushBlock(pdata->enc_data->yuv.u,
+ u_short_blocks[j],
+ pdata->enc_data->yuv.uv_width,
+ pdata->enc_data->yuv.uv_height,
+ UV_UNIT_WIDTH,
+ fp,
+ ucfp,
+ 0);
+ }
+
+ if (vnum) {
+ for(int j = 0; j < vnum; j++)
+ nbytes += rmdFlushBlock(pdata->enc_data->yuv.v,
+ v_short_blocks[j],
+ pdata->enc_data->yuv.uv_width,
+ pdata->enc_data->yuv.uv_height,
+ UV_UNIT_WIDTH,
+ fp,
+ ucfp,
+ 0);
+ }
+
+ //release main buffer
+ pthread_mutex_unlock(&pdata->yuv_mutex);
+
+ nbytes += rmdFlushBlock(NULL, 0, 0, 0, 0, fp, ucfp, 1);
+ /**@________________@**/
+ pdata->avd += pdata->frametime;
+
+ if (nbytes > CACHE_FILE_SIZE_LIMIT) {
+ if (rmdSwapCacheFilesWrite(pdata->cache_data->imgdata, nth_cache, &fp, &ucfp)) {
+ fprintf(stderr, "New cache file could not be created.\n"
+ "Ending recording...\n");
+ fflush(stderr);
+ raise(SIGINT); //if for some reason we cannot make a new file
+ //we have to stop. If we are out of space,
+ //which means
+ //that encoding cannot happen either,
+ //InitEncoder will cause an abrupt end with an
+ //error code and the cache will remain intact.
+ //If we've chosen separate two-stages,
+ //the program will make a
+ //clean exit.
+ //In either case data will be preserved so if
+ //space is freed the recording
+ //can be proccessed later.
+ }
+ total_bytes += nbytes;
+ nth_cache++;
+ nbytes = 0;
+ }
+ }
+ total_bytes += nbytes;
+
+ {
+ unsigned int bytes_per_pixel = pdata->specs.depth >= 24 ? 4 : 2;
+ unsigned int pixels_per_frame = pdata->enc_data->yuv.y_width * pdata->enc_data->yuv.y_height;
+
+ total_received_bytes = ((unsigned long long int)frameno) * bytes_per_pixel * pixels_per_frame;
+ }
+
+ if (total_received_bytes) {
+ double percent_of_data_left = (total_bytes / (double)total_received_bytes) * 100;
+
+ fprintf(stderr, "\n"
+ "*********************************************\n"
+ "\n"
+ "Cached %llu MB, from %llu MB that were received.\n"
+ "Average cache compression ratio: %.1f %%\n"
+ "\n"
+ "*********************************************\n",
+ total_bytes / BYTES_PER_MB,
+ total_received_bytes / BYTES_PER_MB,
+ 100 - percent_of_data_left);
+
+ }
+
+ fprintf(stderr, "Saved %d frames in a total of %d requests\n",
+ frameno,
+ pdata->frames_total);
+ fflush(stderr);
+
+ if (!pdata->args.zerocompression) {
+ gzflush(fp, Z_FINISH);
+ gzclose(fp);
+ } else {
+ fflush(ucfp);
+ fclose(ucfp);
+ }
+
+ pthread_exit(&errno);
+}
© All Rights Reserved