diff options
Diffstat (limited to 'src/rmd_init_encoder.c')
-rw-r--r-- | src/rmd_init_encoder.c | 346 |
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); +} |