summaryrefslogtreecommitdiff
path: root/src/rmd_init_encoder.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/rmd_init_encoder.c')
-rw-r--r--src/rmd_init_encoder.c346
1 files changed, 346 insertions, 0 deletions
diff --git a/src/rmd_init_encoder.c b/src/rmd_init_encoder.c
new file mode 100644
index 0000000..a0d81e6
--- /dev/null
+++ b/src/rmd_init_encoder.c
@@ -0,0 +1,346 @@
+/******************************************************************************
+* 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_init_encoder.h"
+
+#include "rmd_types.h"
+
+#include "skeleton.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+
+
+
+static void m_add_fishead_packet(ogg_stream_state *m_ogg_state) {
+ fishead_packet skel_fp;
+
+ skel_fp.ptime_n = skel_fp.btime_n = 0;
+ skel_fp.ptime_d = skel_fp.btime_d = 1000;
+
+ add_fishead_to_stream(m_ogg_state, &skel_fp);
+}
+
+
+static int rmdIncrementalNaming(char **name) {
+ struct stat buff;
+ char *base_name__;
+ int i = 0, fname_length = strlen(*name)-4;
+
+ base_name__ = malloc(fname_length+1);
+ strncpy(base_name__, *name, fname_length);
+ base_name__[fname_length] = '\0';
+
+ //this will go on an endless loop if you have 65536?
+ //files with the same name
+ //or it will crash and die.anyone interested in trying ?
+ while (stat(*name, &buff)==0) {
+ //create new name
+ char *tname = malloc(strlen(*name)+10);
+ char numbuf[8];
+
+ strcpy(tname, base_name__);
+ strcat(tname, "-");
+ i++;
+ snprintf( numbuf, 8, "%d", i );
+ strcat(tname, numbuf);
+ strcat(tname, ".ogv");
+ //save new name
+
+ free(*name);
+ *name = malloc(strlen(tname)+1);
+ strcpy(*name, tname);
+ free(tname);
+ }
+
+ free(base_name__);
+ return 0;
+}
+
+void rmdInitEncoder(ProgData *pdata, EncData *enc_data_t, int buffer_ready) {
+ int y0, y1, y2, fname_length;
+ ogg_stream_state m_ogg_skel;
+ ogg_page skel_og_pg;
+ fisbone_packet skel_fbv, //video fisbone packet
+ skel_fba; //audio fisbone packet
+ const char *fname;
+
+ pdata->enc_data = enc_data_t;
+
+ fname = pdata->args.filename;
+ fname_length = strlen(fname);
+ if (!(fname_length>4 && !strcasecmp(&fname[fname_length-3], "ogv"))) {
+
+ char *new_name = malloc(fname_length + 5);
+ strcpy(new_name, fname);
+ strcat(new_name, ".ogv");
+
+ free(pdata->args.filename);
+ pdata->args.filename = new_name;
+ }
+
+ if (!pdata->args.overwrite) {
+ rmdIncrementalNaming(&(pdata)->args.filename);
+ fprintf(stderr, "Output file: %s\n", pdata->args.filename);
+ }
+
+ enc_data_t->fp = fopen((pdata)->args.filename, "w");
+ if (enc_data_t->fp == NULL) {
+ fprintf(stderr, "Cannot open file %s for writting!\n", (pdata)->args.filename);
+ exit(13);
+ }
+
+ //each stream must have a unique
+ srand(time(NULL));
+ y0 = rand() + 1;
+ y1 = rand() + 1;
+ y2 = rand() + 1;
+ y2 += (y1 == y2);
+ y0 = (((y0 == y1) || (y0 == y2)) ? (y1 + y2) : y0);
+
+ //init ogg streams
+ //skeleton first
+ ogg_stream_init(&m_ogg_skel, y0);
+ m_add_fishead_packet(&m_ogg_skel);
+ if (ogg_stream_pageout(&m_ogg_skel, &skel_og_pg) != 1) {
+ fprintf (stderr, "Internal Ogg library error.\n");
+ exit (2);
+ }
+ fwrite(skel_og_pg.header, 1, skel_og_pg.header_len, enc_data_t->fp);
+ fwrite(skel_og_pg.body, 1, skel_og_pg.body_len, enc_data_t->fp);
+
+ ogg_stream_init(&enc_data_t->m_ogg_ts, y1);
+ if (!pdata->args.nosound)
+ ogg_stream_init(&enc_data_t->m_ogg_vs, y2);
+
+ theora_info_init(&enc_data_t->m_th_inf);
+ enc_data_t->m_th_inf.frame_width = pdata->brwin.rrect.width;
+ enc_data_t->m_th_inf.frame_height = pdata->brwin.rrect.height;
+ enc_data_t->m_th_inf.width = ((enc_data_t->m_th_inf.frame_width + 15) >> 4) << 4;
+ enc_data_t->m_th_inf.height = ((enc_data_t->m_th_inf.frame_height + 15) >> 4) << 4;
+ enc_data_t->m_th_inf.offset_x = 0;
+ enc_data_t->m_th_inf.offset_y = 0;
+
+ enc_data_t->m_th_inf.fps_numerator = pdata->args.fps * 100.0;
+ enc_data_t->m_th_inf.fps_denominator = 100;
+ enc_data_t->m_th_inf.aspect_numerator = 1;
+ enc_data_t->m_th_inf.aspect_denominator = 1;
+
+ enc_data_t->m_th_inf.colorspace = OC_CS_UNSPECIFIED;
+ enc_data_t->m_th_inf.pixelformat = OC_PF_420;
+
+ enc_data_t->m_th_inf.target_bitrate = pdata->args.v_bitrate;
+ enc_data_t->m_th_inf.quality = pdata->args.v_quality;
+ enc_data_t->m_th_inf.dropframes_p = 0;
+ enc_data_t->m_th_inf.quick_p = 1;
+ enc_data_t->m_th_inf.keyframe_auto_p = 1;
+ enc_data_t->m_th_inf.keyframe_frequency = 64;
+ enc_data_t->m_th_inf.keyframe_frequency_force = 64;
+ enc_data_t->m_th_inf.keyframe_data_target_bitrate = enc_data_t->m_th_inf.quality * 1.5;
+ enc_data_t->m_th_inf.keyframe_auto_threshold = 80;
+ enc_data_t->m_th_inf.keyframe_mindistance = 8;
+ enc_data_t->m_th_inf.noise_sensitivity = 1;
+ enc_data_t->m_th_inf.sharpness = 2;
+
+ if (!pdata->args.nosound) {
+ int ret;
+ vorbis_info_init(&enc_data_t->m_vo_inf);
+ ret = vorbis_encode_init_vbr( &enc_data_t->m_vo_inf,
+ pdata->args.channels,
+ pdata->args.frequency,
+ (float)pdata->args.s_quality*0.1);
+ if (ret) {
+ fprintf(stderr, "Error while setting up vorbis stream quality!\n");
+ exit(2);
+ }
+ vorbis_comment_init(&enc_data_t->m_vo_cmmnt);
+ vorbis_analysis_init(&enc_data_t->m_vo_dsp, &enc_data_t->m_vo_inf);
+ vorbis_block_init(&enc_data_t->m_vo_dsp, &enc_data_t->m_vo_block);
+ }
+
+ if (theora_encode_init(&enc_data_t->m_th_st, &enc_data_t->m_th_inf)) {
+ fprintf(stderr, "Theora encoder initialization failure.\n");
+ exit(2);
+ }
+
+ if (theora_encode_header(&enc_data_t->m_th_st, &enc_data_t->m_ogg_pckt1)) {
+ fprintf(stderr, "Theora enocde header failure.\n");
+ exit(2);
+ }
+
+ ogg_stream_packetin(&enc_data_t->m_ogg_ts, &enc_data_t->m_ogg_pckt1);
+ if (ogg_stream_pageout(&enc_data_t->m_ogg_ts, &enc_data_t->m_ogg_pg) != 1) {
+ fprintf(stderr, "Internal Ogg library error.\n");
+ exit(2);
+ }
+ fwrite(enc_data_t->m_ogg_pg.header, 1,
+ enc_data_t->m_ogg_pg.header_len,
+ enc_data_t->fp);
+ fwrite(enc_data_t->m_ogg_pg.body, 1,
+ enc_data_t->m_ogg_pg.body_len,
+ enc_data_t->fp);
+
+ theora_comment_init(&enc_data_t->m_th_cmmnt);
+ theora_comment_add_tag(&enc_data_t->m_th_cmmnt, "recordMyDesktop", VERSION);
+ theora_encode_comment(&enc_data_t->m_th_cmmnt, &enc_data_t->m_ogg_pckt1);
+ ogg_stream_packetin(&enc_data_t->m_ogg_ts, &enc_data_t->m_ogg_pckt1);
+ theora_encode_tables(&enc_data_t->m_th_st, &enc_data_t->m_ogg_pckt1);
+ ogg_stream_packetin(&enc_data_t->m_ogg_ts, &enc_data_t->m_ogg_pckt1);
+
+ if (!pdata->args.nosound) {
+ ogg_packet header;
+ ogg_packet header_comm;
+ ogg_packet header_code;
+
+ vorbis_analysis_headerout( &enc_data_t->m_vo_dsp,
+ &enc_data_t->m_vo_cmmnt,
+ &header, &header_comm,
+ &header_code);
+ ogg_stream_packetin(&enc_data_t->m_ogg_vs, &header);
+ if (ogg_stream_pageout(&enc_data_t->m_ogg_vs, &enc_data_t->m_ogg_pg) != 1) {
+ fprintf(stderr, "Internal Ogg library error.\n");
+ exit(2);
+ }
+
+ fwrite(enc_data_t->m_ogg_pg.header, 1,
+ enc_data_t->m_ogg_pg.header_len,
+ enc_data_t->fp);
+
+ fwrite(enc_data_t->m_ogg_pg.body, 1,
+ enc_data_t->m_ogg_pg.body_len,
+ enc_data_t->fp);
+
+ ogg_stream_packetin(&enc_data_t->m_ogg_vs, &header_comm);
+ ogg_stream_packetin(&enc_data_t->m_ogg_vs, &header_code);
+ }
+
+ //fishbone packets go here
+ memset(&skel_fbv, 0, sizeof(skel_fbv));
+ skel_fbv.serial_no = enc_data_t->m_ogg_ts.serialno;
+ skel_fbv.nr_header_packet = 3;
+ skel_fbv.granule_rate_n = enc_data_t->m_th_inf.fps_numerator;
+ skel_fbv.granule_rate_d = enc_data_t->m_th_inf.fps_denominator;
+ skel_fbv.start_granule = 0;
+ skel_fbv.preroll = 0;
+ skel_fbv.granule_shift = theora_granule_shift(&enc_data_t->m_th_inf);
+ add_message_header_field(&skel_fbv, "Content-Type", "video/theora");
+
+ add_fisbone_to_stream(&m_ogg_skel, &skel_fbv);
+
+ if (!pdata->args.nosound) {
+
+ memset(&skel_fba, 0, sizeof(skel_fba));
+ skel_fba.serial_no = enc_data_t->m_ogg_vs.serialno;
+ skel_fba.nr_header_packet = 3;
+ skel_fba.granule_rate_n = pdata->args.frequency;
+ skel_fba.granule_rate_d = (ogg_int64_t)1;
+ skel_fba.start_granule = 0;
+ skel_fba.preroll = 2;
+ skel_fba.granule_shift = 0;
+ add_message_header_field(&skel_fba, "Content-Type", "audio/vorbis");
+
+ add_fisbone_to_stream(&m_ogg_skel, &skel_fba);
+ }
+
+ while (1) {
+ int result = ogg_stream_flush(&m_ogg_skel, &skel_og_pg);
+ if (result < 0) {
+ fprintf (stderr, "Internal Ogg library error.\n");
+ exit(2);
+ }
+
+ if (result == 0)
+ break;
+
+ fwrite(skel_og_pg.header, 1, skel_og_pg.header_len, enc_data_t->fp);
+ fwrite(skel_og_pg.body, 1, skel_og_pg.body_len, enc_data_t->fp);
+ }
+
+ while (1) {
+ int result = ogg_stream_flush(&enc_data_t->m_ogg_ts, &enc_data_t->m_ogg_pg);
+ if (result < 0) {
+ fprintf(stderr, "Internal Ogg library error.\n");
+ exit(2);
+ }
+
+ if (result == 0)
+ break;
+
+ fwrite( enc_data_t->m_ogg_pg.header, 1,
+ enc_data_t->m_ogg_pg.header_len,
+ enc_data_t->fp);
+ fwrite( enc_data_t->m_ogg_pg.body, 1,
+ enc_data_t->m_ogg_pg.body_len,
+ enc_data_t->fp);
+ }
+
+ if (!pdata->args.nosound) {
+ while (1) {
+ int result = ogg_stream_flush(&enc_data_t->m_ogg_vs, &enc_data_t->m_ogg_pg);
+ if (result < 0) {
+ fprintf(stderr, "Internal Ogg library error.\n");
+ exit(2);
+ }
+
+ if (result == 0)
+ break;
+
+ fwrite( enc_data_t->m_ogg_pg.header, 1,
+ enc_data_t->m_ogg_pg.header_len,
+ enc_data_t->fp);
+ fwrite( enc_data_t->m_ogg_pg.body, 1,
+ enc_data_t->m_ogg_pg.body_len,
+ enc_data_t->fp);
+ }
+ }
+
+ //skeleton eos
+ add_eos_packet_to_stream(&m_ogg_skel);
+ if (ogg_stream_flush(&m_ogg_skel, &skel_og_pg) < 0) {
+ fprintf(stderr, "Internal Ogg library error.\n");
+ exit(2);
+ }
+ fwrite(skel_og_pg.header, 1, skel_og_pg.header_len, enc_data_t->fp);
+
+ //theora buffer allocation, if any
+ if (!buffer_ready) {
+ enc_data_t->yuv.y = malloc(enc_data_t->m_th_inf.height * enc_data_t->m_th_inf.width);
+ enc_data_t->yuv.u = malloc(enc_data_t->m_th_inf.height * enc_data_t->m_th_inf.width / 4);
+ enc_data_t->yuv.v = malloc(enc_data_t->m_th_inf.height * enc_data_t->m_th_inf.width / 4);
+ enc_data_t->yuv.y_width = enc_data_t->m_th_inf.width;
+ enc_data_t->yuv.y_height = enc_data_t->m_th_inf.height;
+ enc_data_t->yuv.y_stride = enc_data_t->m_th_inf.width;
+
+ enc_data_t->yuv.uv_width = enc_data_t->m_th_inf.width / 2;
+ enc_data_t->yuv.uv_height = enc_data_t->m_th_inf.height / 2;
+ enc_data_t->yuv.uv_stride = enc_data_t->m_th_inf.width / 2;
+ }
+
+ theora_info_clear(&enc_data_t->m_th_inf);
+}
© All Rights Reserved