diff options
Diffstat (limited to 'debian/transcode/transcode-1.1.7/encode/encode_xvid.c')
| -rw-r--r-- | debian/transcode/transcode-1.1.7/encode/encode_xvid.c | 1078 |
1 files changed, 1078 insertions, 0 deletions
diff --git a/debian/transcode/transcode-1.1.7/encode/encode_xvid.c b/debian/transcode/transcode-1.1.7/encode/encode_xvid.c new file mode 100644 index 00000000..ebeae7d9 --- /dev/null +++ b/debian/transcode/transcode-1.1.7/encode/encode_xvid.c @@ -0,0 +1,1078 @@ +/***************************************************************************** + * - XviD Transcode Export Module - + * + * Copyright (C) 2001-2003 - Thomas Oestreich + * + * Author : Edouard Gomez <ed.gomez@free.fr> + * + * Port to transcode 1.1.0+ Module System: + * (C) 2005-2010 Francesco Romani <fromani at gmail dot com> + * + * This file is part of transcode, a video stream processing tool + * + * transcode 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 + * + *****************************************************************************/ + +/***************************************************************************** + * Includes + ****************************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <string.h> +#include <math.h> + +#include "transcode.h" +#include "libtcvideo/tcvideo.h" +#include "libtc/cfgfile.h" +#include "libtc/optstr.h" +#include "libtc/tcmodule-plugin.h" +#include "libtc/tccodecs.h" + +#include <xvid.h> + +/* + * notes: + * - tc_xvid_ prefix is used to avoid any possible name clash with XviD code + * - export_xvid4.c was a really nice and well-written module, this module + * is largely based on such module and share a large portion of code with + * it. So hopefully it should work nicely :) + * - handling of dynamic loading of further shared objects (XviD codec, here) + * isn't optimal, such details should be handled by libtc. + * libdldarwin too should be merged with libtc, or maybe we should switch + * to libtool wizardry. + */ +/***************************************************************************** + * Transcode module binding functions and strings + ****************************************************************************/ + +#define MOD_NAME "encode_xvid.so" +#define MOD_VERSION "v0.0.6 (2008-03-14)" +#define MOD_CAP "XviD 1.1.x encoder" + +#define MOD_FEATURES \ + TC_MODULE_FEATURE_ENCODE|TC_MODULE_FEATURE_VIDEO + +#define MOD_FLAGS \ + TC_MODULE_FLAG_RECONFIGURABLE + + +#define XVID_CONFIG_FILE "xvid.cfg" + +static const char xvid_help[] = "" + "Overview:\n" + " this module encodes raw RGB/YUV video frames in MPEG4, using XviD.\n" + " XviD is a high quality/performance ISO MPEG4 codec.\n" + "Options:\n" + " help produce module overview and options explanations\n"; + +/***************************************************************************** + * XviD symbols grouped in a nice struct. + ****************************************************************************/ + +typedef int (*xvid_function_t)(void *handle, int opt, + void *param1, void *param2); + +/***************************************************************************** + * Transcode module private data + ****************************************************************************/ + +typedef struct { + /* Instance related global vars */ + void *instance; + xvid_gbl_init_t xvid_gbl_init; + xvid_enc_create_t xvid_enc_create; + xvid_enc_frame_t xvid_enc_frame; + + /* This data must survive local block scope, so here it is */ + xvid_enc_plugin_t plugins[7]; + xvid_enc_zone_t zones[2]; + xvid_plugin_single_t onepass; + xvid_plugin_2pass1_t pass1; + xvid_plugin_2pass2_t pass2; + + /* Options from the config file */ + xvid_enc_create_t cfg_create; + xvid_enc_frame_t cfg_frame; + xvid_plugin_single_t cfg_onepass; + xvid_plugin_2pass2_t cfg_pass2; + char *cfg_intra_matrix_file; + char *cfg_inter_matrix_file; + char *cfg_quant_method; + int cfg_packed; + int cfg_closed_gop; + int cfg_interlaced; + int cfg_quarterpel; + int cfg_gmc; + int cfg_trellis; + int cfg_cartoon; + int cfg_hqacpred; + int cfg_chromame; + int cfg_vhq; + int cfg_bvhq; + int cfg_motion; + int cfg_stats; + int cfg_greyscale; + int cfg_turbo; + int cfg_full1pass; + int cfg_lumimask; + + /* MPEG4 stream buffer */ + int stream_size; + uint8_t *stream; + + /* Stats accumulators */ + int frames; + int64_t sse_y; + int64_t sse_u; + int64_t sse_v; + + /* Image format conversion handle */ + TCVHandle tcvhandle; + + int flush_flag; +} XviDPrivateData; + +static const char *errorstring(int err); +static void reset_module(XviDPrivateData *mod); +static void cleanup_module(XviDPrivateData *mod); +static void read_config_file(XviDPrivateData *mod); +static void dispatch_settings(XviDPrivateData *mod); +static void set_create_struct(XviDPrivateData *mod, const vob_t *vob); +static void set_frame_struct(XviDPrivateData *mod, vob_t *vob, + const vframe_list_t *inframe, + vframe_list_t *outframe); + +/***************************************************************************/ + +static int tc_xvid_configure(TCModuleInstance *self, + const char *options, vob_t *vob) +{ + int ret; + XviDPrivateData *pd = NULL; + + TC_MODULE_SELF_CHECK(self, "configure"); + TC_MODULE_SELF_CHECK(vob, "configure"); /* uhu, hackish? */ + + pd = self->userdata; + + pd->flush_flag = vob->encoder_flush; + + /* Load the config file settings */ + read_config_file(pd); + + /* Dispatch settings to xvid structures that hold the config ready to + * be copied to encoder structures */ + dispatch_settings(pd); + + /* Init the xvidcore lib */ + memset(&pd->xvid_gbl_init, 0, sizeof(xvid_gbl_init_t)); + pd->xvid_gbl_init.version = XVID_VERSION; + + ret = xvid_global(NULL, XVID_GBL_INIT, &pd->xvid_gbl_init, NULL); + if (ret < 0) { + tc_log_error(MOD_NAME, "configure: library initialization failed"); + return TC_ERROR; + } + + /* Combine both the config settings with the transcode direct options + * into the final xvid_enc_create_t struct */ + set_create_struct(pd, vob); + ret = xvid_encore(NULL, XVID_ENC_CREATE, &pd->xvid_enc_create, NULL); + + if (ret < 0) { + tc_log_error(MOD_NAME, "configure: encoder initialization failed" + " (XviD returned %i)", ret); + return TC_ERROR; + } + + /* Attach returned instance */ + pd->instance = pd->xvid_enc_create.handle; + + return TC_OK; +} + + +static int tc_xvid_init(TCModuleInstance *self, uint32_t features) +{ + XviDPrivateData *pd = NULL; + vob_t *vob = tc_get_vob(); + + TC_MODULE_SELF_CHECK(self, "init"); + TC_MODULE_INIT_CHECK(self, MOD_FEATURES, features); + + /* Check frame dimensions */ + if (vob->ex_v_width % 2 || vob->ex_v_height % 2) { + tc_log_warn(MOD_NAME, "init: only even dimensions allowed (%dx%d)", + vob->ex_v_width, vob->ex_v_height); + return TC_ERROR; + } + + pd = tc_malloc(sizeof(XviDPrivateData)); + if (!pd) { + tc_log_error(MOD_NAME, "init: can't allocate XviD private data"); + return TC_ERROR; + } + + /* Buffer allocation + * We allocate width*height*bpp/8 to "receive" the compressed stream + * I don't think the codec will ever return more than that. It's and + * encoder, so if it fails delivering smaller frames than original + * ones, something really odd occurs somewhere and i prefer the + * application crash */ + if (vob->im_v_codec == CODEC_RGB || vob->im_v_codec == CODEC_YUV422) { + pd->tcvhandle = tcv_init(); + if (!pd->tcvhandle) { + tc_log_warn(MOD_NAME, "init: tcv_init failed"); + goto init_failed; + } + } + + reset_module(pd); + self->userdata = pd; + + if (verbose) { + tc_log_info(MOD_NAME, "%s %s", MOD_VERSION, MOD_CAP); + } + return TC_OK; + +init_failed: + tc_free(pd); + self->userdata = NULL; /* paranoia */ + return TC_ERROR; +} + +static int tc_xvid_inspect(TCModuleInstance *self, + const char *param, const char **value) +{ + TC_MODULE_SELF_CHECK(self, "inspect"); + + if (optstr_lookup(param, "help")) { + *value = xvid_help; + } + + return TC_OK; +} + +static int tc_xvid_flush(TCModuleInstance *self, vframe_list_t *outframe) +{ + int bytes; + xvid_enc_stats_t xvid_enc_stats; + vob_t *vob = tc_get_vob(); + XviDPrivateData *pd = NULL; + + TC_MODULE_SELF_CHECK(self, "encode_video"); + + pd = self->userdata; + + /* Init the stat structure */ + memset(&xvid_enc_stats, 0, sizeof(xvid_enc_stats_t)); + xvid_enc_stats.version = XVID_VERSION; + + /* Combine both the config settings with the transcode direct options + * into the final xvid_enc_frame_t struct */ + set_frame_struct(pd, vob, NULL, outframe); + + bytes = xvid_encore(pd->instance, XVID_ENC_ENCODE, + &pd->xvid_enc_frame, &xvid_enc_stats); + + outframe->video_len = bytes; + if (bytes > 0) { + /* Extract stats info */ + if (xvid_enc_stats.type > 0 && pd->cfg_stats) { + pd->frames++; + pd->sse_y += xvid_enc_stats.sse_y; + pd->sse_u += xvid_enc_stats.sse_u; + pd->sse_v += xvid_enc_stats.sse_v; + } + + if (pd->xvid_enc_frame.out_flags & XVID_KEYFRAME) { + outframe->attributes |= TC_FRAME_IS_KEYFRAME; + } + } + return TC_OK; +} + + +static int tc_xvid_encode_video(TCModuleInstance *self, + vframe_list_t *inframe, vframe_list_t *outframe) +{ + int bytes; + xvid_enc_stats_t xvid_enc_stats; + vob_t *vob = tc_get_vob(); + XviDPrivateData *pd = NULL; + + TC_MODULE_SELF_CHECK(self, "encode_video"); + + pd = self->userdata; + + if (inframe == NULL && pd->flush_flag) { + return tc_xvid_flush(self, outframe); // FIXME + } + + /* Init the stat structure */ + memset(&xvid_enc_stats, 0, sizeof(xvid_enc_stats_t)); + xvid_enc_stats.version = XVID_VERSION; + + if(vob->im_v_codec == CODEC_YUV422) { + /* Convert to UYVY */ + tcv_convert(pd->tcvhandle, inframe->video_buf, inframe->video_buf, + vob->ex_v_width, vob->ex_v_height, IMG_YUV422P, IMG_UYVY); + } else if (vob->im_v_codec == CODEC_RGB) { + /* Convert to BGR (why isn't RGB supported??) */ + tcv_convert(pd->tcvhandle, inframe->video_buf, inframe->video_buf, + vob->ex_v_width, vob->ex_v_height, IMG_RGB24, IMG_BGR24); + } + /* Combine both the config settings with the transcode direct options + * into the final xvid_enc_frame_t struct */ + set_frame_struct(pd, vob, inframe, outframe); + + bytes = xvid_encore(pd->instance, XVID_ENC_ENCODE, + &pd->xvid_enc_frame, &xvid_enc_stats); + + /* Error handling */ + if (bytes < 0) { + tc_log_error(MOD_NAME, "encode_video: xvidcore returned" + " an error: \"%s\"", + errorstring(bytes)); + return TC_ERROR; + } + outframe->video_len = bytes; + + /* Extract stats info */ + if (xvid_enc_stats.type > 0 && pd->cfg_stats) { + pd->frames++; + pd->sse_y += xvid_enc_stats.sse_y; + pd->sse_u += xvid_enc_stats.sse_u; + pd->sse_v += xvid_enc_stats.sse_v; + } + + /* XviD Core rame buffering handling + * We must make sure audio A/V is still good and does not run away */ + if (bytes == 0) { + outframe->attributes |= TC_FRAME_IS_DELAYED; + return TC_OK; + } + + if (pd->xvid_enc_frame.out_flags & XVID_KEYFRAME) { + outframe->attributes |= TC_FRAME_IS_KEYFRAME; + } + + return TC_OK; +} + +#define SSE2PSNR(sse, width, height) \ +((!(sse)) ? (99.0f) : (48.131f - 10*(float)log10((float)(sse)/((float)((width)*(height)))))) + +static int tc_xvid_stop(TCModuleInstance *self) +{ + int ret; + XviDPrivateData *pd = NULL; + + TC_MODULE_SELF_CHECK(self, "stop"); + + pd = self->userdata; + + /* ToDo: Can we flush the last frames here ? */ + + if (pd->instance != NULL) { + /* Destroy the encoder instance */ + ret = xvid_encore(pd->instance, XVID_ENC_DESTROY, NULL, NULL); + if (ret < 0) { + tc_log_warn(MOD_NAME, "stop: encoder instance releasing failed"); + return TC_ERROR; + } + + /* Print stats before resting the complete module structure */ + if (pd->cfg_stats) { + if(pd->frames > 0) { + pd->sse_y /= pd->frames; + pd->sse_u /= pd->frames; + pd->sse_v /= pd->frames; + } else { + pd->sse_y = 0; + pd->sse_u = 0; + pd->sse_v = 0; + } + + tc_log_info(MOD_NAME, + "psnr y = %.2f dB, " + "psnr u = %.2f dB, " + "psnr v = %.2f dB", + SSE2PSNR(pd->sse_y, + pd->xvid_enc_create.width, + pd->xvid_enc_create.height), + SSE2PSNR(pd->sse_u, + pd->xvid_enc_create.width/2, + pd->xvid_enc_create.height/2), + SSE2PSNR(pd->sse_v, + pd->xvid_enc_create.width/2, + pd->xvid_enc_create.height/2)); + } + pd->instance = NULL; + } + return TC_OK; +} +#undef SSE2PSNR + +static int tc_xvid_fini(TCModuleInstance *self) +{ + XviDPrivateData *pd = NULL; + + TC_MODULE_SELF_CHECK(self, "fini"); + + tc_xvid_stop(self); + + pd = self->userdata; + + /* Free all dynamic memory allocated in the module structure */ + cleanup_module(pd); + + /* This is the last function according to the transcode API + * this should be safe to reset the module structure */ + reset_module(pd); + + tc_free(self->userdata); + self->userdata = NULL; + + return TC_OK; +} + +/*************************************************************************/ + +static const TCCodecID tc_xvid_codecs_in[] = { + TC_CODEC_RGB, TC_CODEC_YUV422P, TC_CODEC_YUV420P, + TC_CODEC_ERROR +}; + +static const TCCodecID tc_xvid_codecs_out[] = { + TC_CODEC_MPEG4VIDEO, + TC_CODEC_ERROR +}; + +TC_MODULE_CODEC_FORMATS(tc_xvid); + +TC_MODULE_INFO(tc_xvid); + +static const TCModuleClass xvid_class = { + TC_MODULE_CLASS_HEAD(tc_xvid), + + .init = tc_xvid_init, + .fini = tc_xvid_fini, + .configure = tc_xvid_configure, + .stop = tc_xvid_stop, + .inspect = tc_xvid_inspect, + + .encode_video = tc_xvid_encode_video +}; + +TC_MODULE_ENTRY_POINT(xvid) + + +/***************************************************************************** + * Transcode module helper functions + ****************************************************************************/ + +static void reset_module(XviDPrivateData *mod) +{ + /* Default options */ + mod->cfg_packed = 0; + mod->cfg_closed_gop = 1; + mod->cfg_interlaced = 0; + mod->cfg_quarterpel = 0; + mod->cfg_gmc = 0; + mod->cfg_trellis = 0; + mod->cfg_cartoon = 0; + mod->cfg_hqacpred = 1; + mod->cfg_chromame = 1; + mod->cfg_vhq = 1; + mod->cfg_bvhq = 0; + mod->cfg_motion = 6; + mod->cfg_turbo = 0; + mod->cfg_full1pass = 0; + mod->cfg_stats = 0; + mod->cfg_greyscale = 0; + mod->cfg_quant_method = "h263"; + mod->cfg_create.max_bframes = 1; + mod->cfg_create.bquant_ratio = 150; + mod->cfg_create.bquant_offset = 100; + mod->cfg_lumimask = 0; +} + +static void cleanup_module(XviDPrivateData *mod) +{ + + /* Free tcvideo handle */ + if (mod->tcvhandle != NULL) { + tcv_free(mod->tcvhandle); + mod->tcvhandle = NULL; + } + + /* Release stream buffer memory */ + if(mod->stream != NULL) { + free(mod->stream); + mod->stream = NULL; + } + + /* Release the matrix file name string */ + if(mod->cfg_inter_matrix_file != NULL) { + tc_free(mod->cfg_inter_matrix_file); + mod->cfg_inter_matrix_file = NULL; + } + + /* Release the matrix definition */ + if(mod->cfg_frame.quant_inter_matrix != NULL) { + tc_free(mod->cfg_frame.quant_inter_matrix); + mod->cfg_frame.quant_inter_matrix = NULL; + } + + /* Release the matrix file name string */ + if(mod->cfg_intra_matrix_file != NULL) { + tc_free(mod->cfg_intra_matrix_file); + mod->cfg_intra_matrix_file = NULL; + } + + /* Release the matrix definition */ + if(mod->cfg_frame.quant_intra_matrix != NULL) { + tc_free(mod->cfg_frame.quant_intra_matrix); + mod->cfg_frame.quant_intra_matrix = NULL; + } +} + +/***************************************************************************** + * Configuration functions + * + * They fill the .cfg_xxx members of the module structure. + * - read_config_file reads the values from the config file and sets .cfg_xxx + * members of the module structure. + * - dispatch_settings uses the values retrieved by read_config_file and + * turns them into XviD settings in the cfg_xxx xvid structure available + * in the module structure. + * - set_create_struct sets a xvid_enc_create structure according to the + * settings generated by the two previous functions calls. + * - set_frame_struct same as above for a xvid_enc_frame_t struct. + ****************************************************************************/ + +#define INTRA_MATRIX 0 +#define INTER_MATRIX 1 + +static void load_matrix(XviDPrivateData *mod, int type) +{ + xvid_enc_frame_t *frame = &mod->cfg_frame; + const char *filename = (type == INTER_MATRIX) + ?mod->cfg_inter_matrix_file + :mod->cfg_intra_matrix_file; + uint8_t *matrix = NULL; + + if (!filename) { + return; + } + + matrix = tc_malloc(TC_MATRIX_SIZE); + if (matrix != NULL) { + int ret = tc_read_matrix(filename, matrix, NULL); + + if (ret == 0) { + tc_log_info(MOD_NAME, "Loaded %s matrix (switching to " + "mpeg quantization type)", + (type == INTER_MATRIX) ?"Inter" :"Intra"); + //print_matrix(matrix, NULL); + //free(mod->cfg_quant_method); + mod->cfg_quant_method = "mpeg"; + } else { + tc_free(matrix); + matrix = NULL; + } + } + + if (type == INTER_MATRIX) { + frame->quant_inter_matrix = matrix; + } else { + frame->quant_intra_matrix = matrix; + } +} + +static void read_config_file(XviDPrivateData *mod) +{ + xvid_plugin_single_t *onepass = &mod->cfg_onepass; + xvid_plugin_2pass2_t *pass2 = &mod->cfg_pass2; + xvid_enc_create_t *create = &mod->cfg_create; + xvid_enc_frame_t *frame = &mod->cfg_frame; + + TCConfigEntry xvid_config[] = { + /* Section [features] */ +// {"features", "Feature settings", TCCONF_TYPE_SECTION, 0, 0, 0}, + {"quant_type", &mod->cfg_quant_method, TCCONF_TYPE_STRING, 0, 0, 0}, + {"motion", &mod->cfg_motion, TCCONF_TYPE_INT, TCCONF_FLAG_RANGE, 0, 6}, + {"chromame", &mod->cfg_chromame, TCCONF_TYPE_FLAG, 0, 0, 1}, + {"vhq", &mod->cfg_vhq, TCCONF_TYPE_INT, TCCONF_FLAG_RANGE, 0, 4}, + {"bvhq", &mod->cfg_bvhq, TCCONF_TYPE_FLAG, 0, 0, 1}, + {"max_bframes", &create->max_bframes, TCCONF_TYPE_INT, TCCONF_FLAG_RANGE, 0, 20}, + {"bquant_ratio", &create->bquant_ratio, TCCONF_TYPE_INT, TCCONF_FLAG_RANGE, 0, 200}, + {"bquant_offset", &create->bquant_offset, TCCONF_TYPE_INT, TCCONF_FLAG_RANGE, 0, 200}, + {"bframe_threshold", &frame->bframe_threshold, TCCONF_TYPE_INT, TCCONF_FLAG_RANGE, -255, 255}, + {"quarterpel", &mod->cfg_quarterpel, TCCONF_TYPE_FLAG, 0, 0, 1}, + {"gmc", &mod->cfg_gmc, TCCONF_TYPE_FLAG, 0, 0, 1}, + {"trellis", &mod->cfg_trellis, TCCONF_TYPE_FLAG, 0, 0, 1}, + {"packed", &mod->cfg_packed, TCCONF_TYPE_FLAG, 0, 0, 1}, + {"closed_gop", &mod->cfg_closed_gop, TCCONF_TYPE_FLAG, 0, 0, 1}, + {"interlaced", &mod->cfg_interlaced, TCCONF_TYPE_FLAG, 0, 0, 1}, + {"cartoon", &mod->cfg_cartoon, TCCONF_TYPE_FLAG, 0, 0, 1}, + {"hqacpred", &mod->cfg_hqacpred, TCCONF_TYPE_FLAG, 0, 0, 1}, + {"frame_drop_ratio", &create->frame_drop_ratio, TCCONF_TYPE_INT, TCCONF_FLAG_RANGE, 0, 100}, + {"stats", &mod->cfg_stats, TCCONF_TYPE_FLAG, 0, 0, 1}, + {"greyscale", &mod->cfg_greyscale, TCCONF_TYPE_FLAG, 0, 0, 1}, + {"turbo", &mod->cfg_turbo, TCCONF_TYPE_FLAG, 0, 0, 1}, +#if XVID_API >= XVID_MAKE_API(4,1) + {"threads", &create->num_threads, TCCONF_TYPE_INT, TCCONF_FLAG_RANGE, 1, 8}, +#endif + {"full1pass", &mod->cfg_full1pass, TCCONF_TYPE_FLAG, 0, 0, 1}, + {"luminance_masking", &mod->cfg_lumimask, TCCONF_TYPE_FLAG, 0, 0, 1}, + + /* section [quantizer] */ +// {"quantizer", "Quantizer settings", TCCONF_TYPE_SECTION, 0, 0, 0}, + {"min_iquant", &create->min_quant[0], TCCONF_TYPE_INT, TCCONF_FLAG_RANGE, 1, 31}, + {"max_iquant", &create->max_quant[0], TCCONF_TYPE_INT, TCCONF_FLAG_RANGE, 1, 31}, + {"min_pquant", &create->min_quant[1], TCCONF_TYPE_INT, TCCONF_FLAG_RANGE, 1, 31}, + {"max_pquant", &create->max_quant[1], TCCONF_TYPE_INT, TCCONF_FLAG_RANGE, 1, 31}, + {"min_bquant", &create->min_quant[2], TCCONF_TYPE_INT, TCCONF_FLAG_RANGE, 1, 31}, + {"max_bquant", &create->max_quant[2], TCCONF_TYPE_INT, TCCONF_FLAG_RANGE, 1, 31}, + {"quant_intra_matrix", &mod->cfg_intra_matrix_file, TCCONF_TYPE_STRING, 0, 0, 100}, + {"quant_inter_matrix", &mod->cfg_inter_matrix_file, TCCONF_TYPE_STRING, 0, 0, 100}, + + /* section [cbr] */ +// {"cbr", "CBR settings", TCCONF_TYPE_SECTION, 0, 0, 0}, + {"reaction_delay_factor", &onepass->reaction_delay_factor, TCCONF_TYPE_INT, TCCONF_FLAG_RANGE, 0, 100}, + {"averaging_period", &onepass->averaging_period, TCCONF_TYPE_INT, TCCONF_FLAG_MIN, 0, 0}, + {"buffer", &onepass->buffer, TCCONF_TYPE_INT, TCCONF_FLAG_MIN, 0, 0}, + + /* section [vbr] */ +// {"vbr", "VBR settings", TCCONF_TYPE_SECTION, 0, 0, 0}, + {"keyframe_boost", &pass2->keyframe_boost, TCCONF_TYPE_INT, TCCONF_FLAG_RANGE, 0, 100}, + {"curve_compression_high", &pass2->curve_compression_high, TCCONF_TYPE_INT, TCCONF_FLAG_RANGE, 0, 100}, + {"curve_compression_low", &pass2->curve_compression_low, TCCONF_TYPE_INT, TCCONF_FLAG_RANGE, 0, 100}, + {"overflow_control_strength", &pass2->overflow_control_strength, TCCONF_TYPE_INT, TCCONF_FLAG_RANGE, 0, 100}, + {"max_overflow_improvement", &pass2->max_overflow_improvement, TCCONF_TYPE_INT, TCCONF_FLAG_RANGE, 0, 100}, + {"max_overflow_degradation", &pass2->max_overflow_degradation, TCCONF_TYPE_INT, TCCONF_FLAG_RANGE, 0, 100}, + {"kfreduction", &pass2->kfreduction, TCCONF_TYPE_INT, TCCONF_FLAG_RANGE, 0, 100}, + {"kfthreshold", &pass2->kfthreshold, TCCONF_TYPE_INT, TCCONF_FLAG_MIN, 0, 0}, + {"container_frame_overhead", &pass2->container_frame_overhead, TCCONF_TYPE_INT, TCCONF_FLAG_MIN, 0, 0}, + + /* End of the config file */ + {NULL, 0, 0, 0, 0, 0} + }; + + /* Read the values */ + module_read_config(XVID_CONFIG_FILE, NULL, xvid_config, MOD_NAME); + + /* Print the values */ + if (verbose & TC_DEBUG) { + module_print_config(xvid_config, MOD_NAME); + } + + return; +} + +static void dispatch_settings(XviDPrivateData *mod) +{ + + xvid_enc_create_t *create = &mod->cfg_create; + xvid_enc_frame_t *frame = &mod->cfg_frame; + + const int motion_presets[7] = + { + 0, + 0, + 0, + 0, + XVID_ME_HALFPELREFINE16, + XVID_ME_HALFPELREFINE16 | XVID_ME_ADVANCEDDIAMOND16, + XVID_ME_HALFPELREFINE16 | XVID_ME_EXTSEARCH16 | + XVID_ME_HALFPELREFINE8 | XVID_ME_USESQUARES16 + }; + + + /* Dispatch all settings having an impact on the "create" structure */ + create->global = 0; + + if (mod->cfg_packed) { + create->global |= XVID_GLOBAL_PACKED; + } + if (mod->cfg_closed_gop) { + create->global |= XVID_GLOBAL_CLOSED_GOP; + } + if (mod->cfg_stats) { + create->global |= XVID_GLOBAL_EXTRASTATS_ENABLE; + } + /* Dispatch all settings having an impact on the "frame" structure */ + frame->vol_flags = 0; + frame->vop_flags = 0; + frame->motion = 0; + + frame->vop_flags |= XVID_VOP_HALFPEL; + frame->motion |= motion_presets[mod->cfg_motion]; + + if (mod->cfg_stats) { + frame->vol_flags |= XVID_VOL_EXTRASTATS; + } + if (mod->cfg_greyscale) { + frame->vop_flags |= XVID_VOP_GREYSCALE; + } + if (mod->cfg_cartoon) { + frame->vop_flags |= XVID_VOP_CARTOON; + frame->motion |= XVID_ME_DETECT_STATIC_MOTION; + } + + load_matrix(mod, INTRA_MATRIX); + load_matrix(mod, INTER_MATRIX); + + if (!strcasecmp(mod->cfg_quant_method, "mpeg")) { + frame->vol_flags |= XVID_VOL_MPEGQUANT; + } + if (mod->cfg_quarterpel) { + frame->vol_flags |= XVID_VOL_QUARTERPEL; + frame->motion |= XVID_ME_QUARTERPELREFINE16; + frame->motion |= XVID_ME_QUARTERPELREFINE8; + } + if (mod->cfg_gmc) { + frame->vol_flags |= XVID_VOL_GMC; + frame->motion |= XVID_ME_GME_REFINE; + } + if (mod->cfg_interlaced) { + frame->vol_flags |= XVID_VOL_INTERLACING; + } + if (mod->cfg_trellis) { + frame->vop_flags |= XVID_VOP_TRELLISQUANT; + } + if (mod->cfg_hqacpred) { + frame->vop_flags |= XVID_VOP_HQACPRED; + } + if (mod->cfg_motion > 4) { + frame->vop_flags |= XVID_VOP_INTER4V; + } + if (mod->cfg_chromame) { + frame->motion |= XVID_ME_CHROMA_PVOP; + frame->motion |= XVID_ME_CHROMA_BVOP; + } + if (mod->cfg_vhq >= 1) { + frame->vop_flags |= XVID_VOP_MODEDECISION_RD; + } + if (mod->cfg_vhq >= 2) { + frame->motion |= XVID_ME_HALFPELREFINE16_RD; + frame->motion |= XVID_ME_QUARTERPELREFINE16_RD; + } + if (mod->cfg_vhq >= 3) { + frame->motion |= XVID_ME_HALFPELREFINE8_RD; + frame->motion |= XVID_ME_QUARTERPELREFINE8_RD; + frame->motion |= XVID_ME_CHECKPREDICTION_RD; + } + if (mod->cfg_vhq >= 4) { + frame->motion |= XVID_ME_EXTSEARCH_RD; + } + if (mod->cfg_turbo) { + frame->motion |= XVID_ME_FASTREFINE16; + frame->motion |= XVID_ME_FASTREFINE8; + frame->motion |= XVID_ME_SKIP_DELTASEARCH; + frame->motion |= XVID_ME_FAST_MODEINTERPOLATE; + frame->motion |= XVID_ME_BFRAME_EARLYSTOP; + } + if (mod->cfg_bvhq) { +#if XVID_API >= XVID_MAKE_API(4,1) + frame->vop_flags |= XVID_VOP_RD_BVOP; +#endif + } + + /* motion level == 0 means no motion search which is equivalent to + * intra coding only */ + if (mod->cfg_motion == 0) { + frame->type = XVID_TYPE_IVOP; + } else { + frame->type = XVID_TYPE_AUTO; + } + + return; +} + +static void set_create_struct(XviDPrivateData *mod, const vob_t *vob) +{ + xvid_enc_create_t *x = &mod->xvid_enc_create; + xvid_enc_create_t *xcfg = &mod->cfg_create; + + memset(x, 0, sizeof(xvid_enc_create_t)); + x->version = XVID_VERSION; + + /* Global encoder options */ + x->global = xcfg->global; + + /* Width and Height */ + x->width = vob->ex_v_width; + x->height = vob->ex_v_height; + + /* Max keyframe interval */ + x->max_key_interval = vob->divxkeyframes; + + /* FPS : we take care of non integer values */ + if ((vob->ex_fps - (int)vob->ex_fps) == 0) { + x->fincr = 1; + x->fbase = (int)vob->ex_fps; + } else { + x->fincr = 1001; + x->fbase = (int)(1001 * vob->ex_fps); + } + + /* BFrames settings */ + x->max_bframes = xcfg->max_bframes; + x->bquant_ratio = xcfg->bquant_ratio; + x->bquant_offset = xcfg->bquant_offset; + + /* Frame dropping factor */ + x->frame_drop_ratio = xcfg->frame_drop_ratio; + + /* Quantizers */ + x->min_quant[0] = xcfg->min_quant[0]; + x->min_quant[1] = xcfg->min_quant[1]; + x->min_quant[2] = xcfg->min_quant[2]; + x->max_quant[0] = xcfg->max_quant[0]; + x->max_quant[1] = xcfg->max_quant[1]; + x->max_quant[2] = xcfg->max_quant[2]; + + /* Encodings zones + * ToDo?: Allow zones definitions */ + memset(mod->zones, 0, sizeof(mod->zones)); + x->zones = mod->zones; + + if (1 == vob->divxmultipass && mod->cfg_full1pass) + { + x->zones[0].frame = 0; + x->zones[0].mode = XVID_ZONE_QUANT; + x->zones[0].increment = 200; + x->zones[0].base = 100; + x->num_zones = 1; + } else { + x->num_zones = 0; + } + + /* Plugins */ + memset(mod->plugins, 0, sizeof(mod->plugins)); + x->plugins = mod->plugins; + x->num_plugins = 0; + + /* Initialize rate controller plugin */ + + /* This is the first pass of a Two pass process */ + if (vob->divxmultipass == 1) { + xvid_plugin_2pass1_t *pass1 = &mod->pass1; + + memset(pass1, 0, sizeof(xvid_plugin_2pass1_t)); + pass1->version = XVID_VERSION; + pass1->filename = (char*)vob->divxlogfile; /* XXX: ugh */ + + x->plugins[x->num_plugins].func = xvid_plugin_2pass1; + x->plugins[x->num_plugins].param = pass1; + x->num_plugins++; + } + + /* This is the second pass of a Two pass process */ + if (vob->divxmultipass == 2) { + xvid_plugin_2pass2_t *pass2 = &mod->pass2; + xvid_plugin_2pass2_t *pass2cfg = &mod->cfg_pass2; + + memset(pass2, 0, sizeof(xvid_plugin_2pass2_t)); + pass2->version = XVID_VERSION; + pass2->filename = (char*)vob->divxlogfile; /* XXX: ugh */ + + /* Apply config file settings if any, or all 0s which lets XviD + * apply its defaults */ + pass2->keyframe_boost = pass2cfg->keyframe_boost; + pass2->curve_compression_high = pass2cfg->curve_compression_high; + pass2->curve_compression_low = pass2cfg->curve_compression_low; + pass2->overflow_control_strength = pass2cfg->overflow_control_strength; + pass2->max_overflow_improvement = pass2cfg->max_overflow_improvement; + pass2->max_overflow_degradation = pass2cfg->max_overflow_degradation; + pass2->kfreduction = pass2cfg->kfreduction; + pass2->kfthreshold = pass2cfg->kfthreshold; + pass2->container_frame_overhead = pass2cfg->container_frame_overhead; + + /* Positive bitrate values are bitrates as usual but if the + * value is negative it is considered as being a total size + * to reach (in kilobytes) */ + if (vob->divxbitrate > 0) { + pass2->bitrate = vob->divxbitrate*1000; + } else { + pass2->bitrate = vob->divxbitrate; + } + x->plugins[x->num_plugins].func = xvid_plugin_2pass2; + x->plugins[x->num_plugins].param = pass2; + x->num_plugins++; + } + + /* This is a single pass encoding: either a CBR pass or a constant + * quantizer pass */ + if (vob->divxmultipass == 0 || vob->divxmultipass == 3) { + xvid_plugin_single_t *onepass = &mod->onepass; + xvid_plugin_single_t *cfgonepass = &mod->cfg_onepass; + + memset(onepass, 0, sizeof(xvid_plugin_single_t)); + onepass->version = XVID_VERSION; + onepass->bitrate = vob->divxbitrate*1000; + + /* Apply config file settings if any, or all 0s which lets XviD + * apply its defaults */ + onepass->reaction_delay_factor = cfgonepass->reaction_delay_factor; + onepass->averaging_period = cfgonepass->averaging_period; + onepass->buffer = cfgonepass->buffer; + + /* Quantizer mode uses the same plugin, we have only to define + * a constant quantizer zone beginning at frame 0 */ + if (vob->divxmultipass == 3) { + x->zones[x->num_zones].mode = XVID_ZONE_QUANT; + x->zones[x->num_zones].frame = 1; + x->zones[x->num_zones].increment = vob->divxbitrate; + x->zones[x->num_zones].base = 1; + x->num_zones++; + } + + + x->plugins[x->num_plugins].func = xvid_plugin_single; + x->plugins[x->num_plugins].param = onepass; + x->num_plugins++; + } + + if (mod->cfg_lumimask) { +#if XVID_API >= XVID_MAKE_API(4,1) + x->plugins[x->num_plugins].func = xvid_plugin_lumimasking; + x->plugins[x->num_plugins].param = NULL; + x->num_plugins++; +#endif + } + + return; +} + +static void set_frame_struct(XviDPrivateData *mod, vob_t *vob, + const vframe_list_t *inframe, vframe_list_t *outframe) +{ + xvid_enc_frame_t *x = &mod->xvid_enc_frame; + xvid_enc_frame_t *xcfg = &mod->cfg_frame; + + memset(x, 0, sizeof(xvid_enc_frame_t)); + x->version = XVID_VERSION; + + /* Bind output buffer */ + x->bitstream = outframe->video_buf; + + if (!inframe) { /* flush request */ + x->length = -1; + x->input.csp = XVID_CSP_NULL; + x->input.plane[0] = NULL; +// x->input.plane[1] = NULL; +// x->input.plane[2] = NULL; + x->input.stride[0] = 0; +// x->input.stride[1] = 0; +// x->input.stride[2] = 0; + } else { + x->length = outframe->video_size; + + /* Bind source frame */ + x->input.plane[0] = inframe->video_buf; + if (vob->im_v_codec == CODEC_RGB) { + x->input.csp = XVID_CSP_BGR; + x->input.stride[0] = vob->ex_v_width*3; + } else if (vob->im_v_codec == CODEC_YUV422) { + x->input.csp = XVID_CSP_UYVY; + x->input.stride[0] = vob->ex_v_width*2; + } else { + x->input.csp = XVID_CSP_I420; + x->input.stride[0] = vob->ex_v_width; + } + } + /* Set up core's VOL level features */ + x->vol_flags = xcfg->vol_flags; + + /* Set up core's VOP level features */ + x->vop_flags = xcfg->vop_flags; + + /* Frame type -- let core decide for us */ + x->type = xcfg->type; + + /* Force the right quantizer -- It is internally managed by RC + * plugins */ + x->quant = 0; + + /* Set up motion estimation flags */ + x->motion = xcfg->motion; + + /* We don't use special matrices */ + x->quant_intra_matrix = xcfg->quant_intra_matrix; + x->quant_inter_matrix = xcfg->quant_inter_matrix; + + /* pixel aspect ratio + * transcode.c uses 0 for EXT instead of 15 */ + if (vob->ex_par == 0) { + x->par = XVID_PAR_EXT; + x->par_width = vob->ex_par_width; + x->par_height = vob->ex_par_height; + } else { + x->par = vob->ex_par; + /* par_{width,height} already set to zero above */ + } + return; +} + +/***************************************************************************** + * Returns an error string corresponding to the XviD err code + ****************************************************************************/ + +static const char *errorstring(int err) +{ + const char *error; + + switch(err) { + case XVID_ERR_FAIL: + error = "General fault"; + break; + case XVID_ERR_MEMORY: + error = "Memory allocation error"; + break; + case XVID_ERR_FORMAT: + error = "File format error"; + break; + case XVID_ERR_VERSION: + error = "Structure version not supported"; + break; + case XVID_ERR_END: + error = "End of stream reached"; + break; + default: + error = "Unknown"; + } + + return error; +} + +/*************************************************************************/ + +/* + * Local variables: + * c-file-style: "stroustrup" + * c-file-offsets: ((case-label . *) (statement-case-intro . *)) + * indent-tabs-mode: nil + * End: + * + * vim: expandtab shiftwidth=4: + */ |
