Hi! Using transcode with ffmpeg+h264 causes some trouble with libx264 erroring out with "broken ffmpeg default settings detected". libx264 further suggests: "use an encoding preset (vpre)".
The attached patch adds two config parameters to ffmpeg.cfg, "vpre" and "ffmpeg_datadir". The former sets the video presets and accepts a comma separated list, e.g. "fast,baseline", default being "medium". The latter is used to determine the path to the system ffmpeg presets, default being "/usr/share/ffmpeg". These presets are used to override the broken ffmpeg default values. Important: I had to load the presets after the setup of all other options (thus any transcode options will be overriden by any presets loaded), because apparently transcode's internal defaults (which are in turn used to override ffmpeg's defaults) are just as broken as the ffmpeg ones... (See the FIXME I included) Licensing and origin: All code (almost) is copied from ffmpeg-0.5_p22846, files ffmpeg.c and cmdutils.c. Known issues: None known, but the code may be buggy, especially since it is only ripped from ffmpeg. In the beginning I had some trouble with uninitialised pointers. This should be fixed now (see the GLUE comments), but I don't guarantee for anything. Kind regards, Dennis
diff -wur transcode-1.1.5.orig//export/export_ffmpeg.c transcode-1.1.5/export/export_ffmpeg.c --- transcode-1.1.5.orig//export/export_ffmpeg.c 2010-06-06 10:57:38.128996193 +0200 +++ transcode-1.1.5/export/export_ffmpeg.c 2010-06-06 14:43:50.492250764 +0200 @@ -168,6 +168,191 @@ return -10.0 * log(d) / log(10); } + +// Could be using GNU extension 'strchrnul' instead: +static char *tc_strchrnul(const char *s, int c) { + char *tmp = strchr(s, c); + if (tmp == NULL) { + tmp = s + strlen(s); + } + return tmp; +} + + +/* START: COPIED FROM ffmpeg-0.5_p22846(ffmpeg.c, cmdutils.c) */ +#include <libavcodec/opt.h> +#include <libavutil/avstring.h> +#include <libswscale/swscale.h> + +/* GLUE: */ +#define FFMPEG_DATADIR lavc_param_ffmpeg_datadir + +/* GLUE: */ +static AVCodecContext *avcodec_opts[AVMEDIA_TYPE_NB] = {NULL}; + +static // GLUE +const char **opt_names; +static int opt_name_count; + +static char *audio_codec_name = NULL; +static char *subtitle_codec_name = NULL; +static char *video_codec_name = NULL; +static int audio_stream_copy = 0; +static int video_stream_copy = 0; +static int subtitle_stream_copy = 0; + +static int av_exit(int ret) +{ + av_free(opt_names); + + av_free(video_codec_name); + av_free(audio_codec_name); + av_free(subtitle_codec_name); + + exit(ret); /* not all OS-es handle main() return value */ + return ret; +} + +static void opt_codec(int *pstream_copy, char **pcodec_name, + int codec_type, const char *arg) +{ + av_freep(pcodec_name); + if (!strcmp(arg, "copy")) { + *pstream_copy = 1; + } else { + *pcodec_name = av_strdup(arg); + } +} + +static void opt_audio_codec(const char *arg) +{ + opt_codec(&audio_stream_copy, &audio_codec_name, AVMEDIA_TYPE_AUDIO, arg); +} + +static void opt_video_codec(const char *arg) +{ + opt_codec(&video_stream_copy, &video_codec_name, AVMEDIA_TYPE_VIDEO, arg); +} + +static void opt_subtitle_codec(const char *arg) +{ + opt_codec(&subtitle_stream_copy, &subtitle_codec_name, AVMEDIA_TYPE_SUBTITLE, arg); +} + +static +int opt_default(const char *opt, const char *arg){ + int type; + int ret= 0; + const AVOption *o= NULL; + int opt_types[]={AV_OPT_FLAG_VIDEO_PARAM, AV_OPT_FLAG_AUDIO_PARAM, 0, AV_OPT_FLAG_SUBTITLE_PARAM, 0}; + + for(type=0; type<AVMEDIA_TYPE_NB && ret>= 0; type++){ + /* GLUE: +if */ + if (type == AVMEDIA_TYPE_VIDEO) { + const AVOption *o2 = av_find_opt(avcodec_opts[0], opt, NULL, opt_types[type], opt_types[type]); + if(o2) + ret = av_set_string3(avcodec_opts[type], opt, arg, 1, &o); + /* GLUE: +if */ + } + } + /* GLUE: disabling + if(!o) + ret = av_set_string3(avformat_opts, opt, arg, 1, &o); + if(!o && sws_opts) + ret = av_set_string3(sws_opts, opt, arg, 1, &o); + */ + if(!o){ + /* GLUE: disabling + if(opt[0] == 'a') + ret = av_set_string3(avcodec_opts[AVMEDIA_TYPE_AUDIO], opt+1, arg, 1, &o); + else */ if(opt[0] == 'v') + ret = av_set_string3(avcodec_opts[AVMEDIA_TYPE_VIDEO], opt+1, arg, 1, &o); + /* GLUE: disabling + else if(opt[0] == 's') + ret = av_set_string3(avcodec_opts[AVMEDIA_TYPE_SUBTITLE], opt+1, arg, 1, &o); + */ + } + if (o && ret < 0) { + fprintf(stderr, "Invalid value '%s' for option '%s'\n", arg, opt); + exit(1); + } + if (!o) { + fprintf(stderr, "Unrecognized option '%s'\n", opt); + exit(1); + } + +// av_log(NULL, AV_LOG_ERROR, "%s:%s: %f 0x%0X\n", opt, arg, av_get_double(avcodec_opts, opt, NULL), (int)av_get_int(avcodec_opts, opt, NULL)); + + //FIXME we should always use avcodec_opts, ... for storing options so there will not be any need to keep track of what i set over this + opt_names= av_realloc(opt_names, sizeof(void*)*(opt_name_count+1)); + opt_names[opt_name_count++]= o->name; + + /* GLUE: disabling + if(avcodec_opts[0]->debug || avformat_opts->debug) + av_log_set_level(AV_LOG_DEBUG); + */ + return 0; +} + +static int opt_preset(const char *opt, const char *arg) +{ + FILE *f=NULL; + char filename[1000], tmp[1000], tmp2[1000], line[1000]; + int i; + const char *base[2]= { getenv("HOME"), + FFMPEG_DATADIR, + }; + + if (*opt != 'f') { + for(i=!base[0]; i<2 && !f; i++){ + snprintf(filename, sizeof(filename), "%s%s/%s.ffpreset", base[i], i ? "" : "/.ffmpeg", arg); + f= fopen(filename, "r"); + if(!f){ + char *codec_name= *opt == 'v' ? video_codec_name : + *opt == 'a' ? audio_codec_name : + subtitle_codec_name; + snprintf(filename, sizeof(filename), "%s%s/%s-%s.ffpreset", base[i], i ? "" : "/.ffmpeg", codec_name, arg); + f= fopen(filename, "r"); + } + } + } else { + av_strlcpy(filename, arg, sizeof(filename)); + f= fopen(filename, "r"); + } + + if(!f){ + fprintf(stderr, "File for preset '%s' not found\n", arg); + av_exit(1); + } + + while(!feof(f)){ + int e= fscanf(f, "%999[^\n]\n", line) - 1; + if(line[0] == '#' && !e) + continue; + e|= sscanf(line, "%999[^=]=%999[^\n]\n", tmp, tmp2) - 2; + if(e){ + fprintf(stderr, "%s: Invalid syntax: '%s'\n", filename, line); + av_exit(1); + } + if(!strcmp(tmp, "acodec")){ + opt_audio_codec(tmp2); + }else if(!strcmp(tmp, "vcodec")){ + opt_video_codec(tmp2); + }else if(!strcmp(tmp, "scodec")){ + opt_subtitle_codec(tmp2); + }else if(opt_default(tmp, tmp2) < 0){ + fprintf(stderr, "%s: Invalid option or argument: '%s', parsed as '%s' = '%s'\n", filename, line, tmp, tmp2); + av_exit(1); + } + } + + fclose(f); + + return 0; +} +/* END: COPIED FROM ffmpeg-0.5_p22846(ffmpeg.c, cmdutils.c) */ + + /* ------------------------------------------------------------ * * init codec @@ -1020,6 +1205,45 @@ lavc_venc_context->me_method = ME_ZERO + lavc_param_vme; + + /* FIXME: transcode itself contains "broken ffmpeg default settings", thus we need to override them! */ + if (lavc_param_video_preset) { + avcodec_opts[AVMEDIA_TYPE_VIDEO] = lavc_venc_context; + video_codec_name = ffmpeg_codec_name(codec->name); + + const char *preset_start = lavc_param_video_preset; + while (preset_start) { + const char *preset_end = tc_strchrnul(preset_start, ','); + char preset_name[255] = {'\0'}; + + if (strncpy(preset_name, preset_start, preset_end-preset_start) != preset_name) { + tc_log_warn(MOD_NAME, "Extracting preset name failed"); + return TC_EXPORT_ERROR; + } + + if (verbose) { + tc_log_info(MOD_NAME, "Parsing ffmpeg preset '%s'", preset_name); + } + if (opt_preset("vpre", preset_name) != 0) { + tc_log_warn(MOD_NAME, "Parsing ffmpeg preset '%s' failed", preset_name); + } + if (verbose) { + int i; + tc_log_info(MOD_NAME, "After parsing preset '%s', %i options are overridden:", preset_name, opt_name_count); + for (i=0; i < opt_name_count; i++) + tc_log_info(MOD_NAME, "-- %s", opt_names[i]); + } + + if (*preset_end != '\0') { + preset_start = preset_end+1; + } + else { + preset_start = NULL; + } + } + } + + //-- open codec -- //---------------- TC_LOCK_LIBAVCODEC; diff -wur transcode-1.1.5.orig//export/ffmpeg_cfg.c transcode-1.1.5/export/ffmpeg_cfg.c --- transcode-1.1.5.orig//export/ffmpeg_cfg.c 2010-06-06 10:57:38.128996193 +0200 +++ transcode-1.1.5/export/ffmpeg_cfg.c 2010-06-06 14:32:32.675996285 +0200 @@ -126,6 +126,9 @@ //int lavc_param_atag = 0; //int lavc_param_abitrate = 224; +char *lavc_param_video_preset = "medium"; +char *lavc_param_ffmpeg_datadir = "/usr/share/ffmpeg"; + TCConfigEntry lavcopts_conf[]={ // {"acodec", &lavc_param_acodec, TCCONF_TYPE_STRING, 0, 0, 0}, // {"abitrate", &lavc_param_abitrate, TCCONF_TYPE_INT, TCCONF_FLAG_RANGE, 1, 1000}, @@ -234,5 +237,7 @@ {"skip_top", &lavc_param_skip_top, TCCONF_TYPE_INT, TCCONF_FLAG_RANGE, 0, 1000}, {"skip_bottom", &lavc_param_skip_bottom, TCCONF_TYPE_INT, TCCONF_FLAG_RANGE, 0, 1000}, {"fps_code", &lavc_param_fps_code, TCCONF_TYPE_INT, TCCONF_FLAG_RANGE, 0, 9}, + {"vpre", &lavc_param_video_preset, TCCONF_TYPE_STRING, 0, 0, 0}, + {"ffmpeg_datadir", &lavc_param_ffmpeg_datadir, TCCONF_TYPE_STRING, 0, 0, 0}, {NULL, NULL, 0, 0, 0, 0} }; diff -wur transcode-1.1.5.orig//export/ffmpeg_cfg.h transcode-1.1.5/export/ffmpeg_cfg.h --- transcode-1.1.5.orig//export/ffmpeg_cfg.h 2010-06-06 10:57:38.126994375 +0200 +++ transcode-1.1.5/export/ffmpeg_cfg.h 2010-06-06 14:29:41.327995477 +0200 @@ -100,6 +100,9 @@ extern int lavc_param_skip_top; extern int lavc_param_skip_bottom; +extern char *lavc_param_video_preset; +extern char *lavc_param_ffmpeg_datadir; + extern TCConfigEntry lavcopts_conf[]; #endif
signature.asc
Description: This is a digitally signed message part.