[PATCH] ffmpeg preset support
Dennis Schridde <[email protected]> Sun, 6 Jun 2010 17:23:55 +0200
| Newsgroups | gmane.comp.video.transcode.devel |
|---|---|
| Message-ID | <[email protected]> |
--nextPart1595698.fXnU5UVfEi
Content-Type: multipart/mixed;
boundary="Boundary-01=_L27CMXyb8oY2MZg"
Content-Transfer-Encoding: 7bit
--Boundary-01=_L27CMXyb8oY2MZg
Content-Type: text/plain;
charset="us-ascii"
Content-Transfer-Encoding: quoted-printable
Content-Disposition: inline
Hi!
Using transcode with ffmpeg+h264 causes some trouble with libx264 erroring =
out=20
with "broken ffmpeg default settings detected". libx264 further suggests: "=
use=20
an encoding preset (vpre)".
The attached patch adds two config parameters to ffmpeg.cfg, "vpre" and=20
"ffmpeg_datadir".
The former sets the video presets and accepts a comma separated list, e.g.=
=20
"fast,baseline", default being "medium".
The latter is used to determine the path to the system ffmpeg presets, defa=
ult=20
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=20
(thus any transcode options will be overriden by any presets loaded), becau=
se=20
apparently transcode's internal defaults (which are in turn used to overrid=
e=20
ffmpeg's defaults) are just as broken as the ffmpeg ones... (See the FIXME =
I=20
included)
Licensing and origin: All code (almost) is copied from ffmpeg-0.5_p22846,=20
files ffmpeg.c and cmdutils.c.
Known issues: None known, but the code may be buggy, especially since it is=
=20
only ripped from ffmpeg.
In the beginning I had some trouble with uninitialised pointers. This shoul=
d=20
be fixed now (see the GLUE comments), but I don't guarantee for anything.
Kind regards,
Dennis
--Boundary-01=_L27CMXyb8oY2MZg
Content-Type: text/x-patch; charset="utf-8";
name="transcode-1.1.5-ffmpeg-presets.patch"
Content-Transfer-Encoding: quoted-printable
Content-Disposition: attachment;
filename="transcode-1.1.5-ffmpeg-presets.patch"
diff -wur transcode-1.1.5.orig//export/export_ffmpeg.c transcode-1.1.5/expo=
rt/export_ffmpeg.c
=2D-- transcode-1.1.5.orig//export/export_ffmpeg.c 2010-06-06 10:57:38.1289=
96193 +0200
+++ transcode-1.1.5/export/export_ffmpeg.c 2010-06-06 14:43:50.492250764 +0=
200
@@ -168,6 +168,191 @@
return -10.0 * log(d) / log(10);
}
=20
+
+// Could be using GNU extension 'strchrnul' instead:
+static char *tc_strchrnul(const char *s, int c) {
+ char *tmp =3D strchr(s, c);
+ if (tmp =3D=3D NULL) {
+ tmp =3D 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] =3D {NULL};
+
+static // GLUE
+const char **opt_names;
+static int opt_name_count;
+
+static char *audio_codec_name =3D NULL;
+static char *subtitle_codec_name =3D NULL;
+static char *video_codec_name =3D NULL;
+static int audio_stream_copy =3D 0;
+static int video_stream_copy =3D 0;
+static int subtitle_stream_copy =3D 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 =3D 1;
+ } else {
+ *pcodec_name =3D av_strdup(arg);
+ }
+}
+
+static void opt_audio_codec(const char *arg)
+{
+ opt_codec(&audio_stream_copy, &audio_codec_name, AVMEDIA_TYPE_AUDIO, a=
rg);
+}
+
+static void opt_video_codec(const char *arg)
+{
+ opt_codec(&video_stream_copy, &video_codec_name, AVMEDIA_TYPE_VIDEO, a=
rg);
+}
+
+static void opt_subtitle_codec(const char *arg)
+{
+ opt_codec(&subtitle_stream_copy, &subtitle_codec_name, AVMEDIA_TYPE_SU=
BTITLE, arg);
+}
+
+static
+int opt_default(const char *opt, const char *arg){
+ int type;
+ int ret=3D 0;
+ const AVOption *o=3D NULL;
+ int opt_types[]=3D{AV_OPT_FLAG_VIDEO_PARAM, AV_OPT_FLAG_AUDIO_PARAM, 0=
, AV_OPT_FLAG_SUBTITLE_PARAM, 0};
+
+ for(type=3D0; type<AVMEDIA_TYPE_NB && ret>=3D 0; type++){
+ /* GLUE: +if */
+ if (type =3D=3D AVMEDIA_TYPE_VIDEO) {
+ const AVOption *o2 =3D av_find_opt(avcodec_opts[0], opt, NULL, opt=
_types[type], opt_types[type]);
+ if(o2)
+ ret =3D av_set_string3(avcodec_opts[type], opt, arg, 1, &o);
+ /* GLUE: +if */
+ }
+ }
+ /* GLUE: disabling
+ if(!o)
+ ret =3D av_set_string3(avformat_opts, opt, arg, 1, &o);
+ if(!o && sws_opts)
+ ret =3D av_set_string3(sws_opts, opt, arg, 1, &o);
+ */
+ if(!o){
+ /* GLUE: disabling
+ if(opt[0] =3D=3D 'a')
+ ret =3D av_set_string3(avcodec_opts[AVMEDIA_TYPE_AUDIO], opt+1=
, arg, 1, &o);
+ else */ if(opt[0] =3D=3D 'v')
+ ret =3D av_set_string3(avcodec_opts[AVMEDIA_TYPE_VIDEO], opt+1=
, arg, 1, &o);
+ /* GLUE: disabling
+ else if(opt[0] =3D=3D 's')
+ ret =3D av_set_string3(avcodec_opts[AVMEDIA_TYPE_SUBTITLE], op=
t+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_dou=
ble(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=3D av_realloc(opt_names, sizeof(void*)*(opt_name_count+1));
+ opt_names[opt_name_count++]=3D 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=3DNULL;
+ char filename[1000], tmp[1000], tmp2[1000], line[1000];
+ int i;
+ const char *base[2]=3D { getenv("HOME"),
+ FFMPEG_DATADIR,
+ };
+
+ if (*opt !=3D 'f') {
+ for(i=3D!base[0]; i<2 && !f; i++){
+ snprintf(filename, sizeof(filename), "%s%s/%s.ffpreset", base[=
i], i ? "" : "/.ffmpeg", arg);
+ f=3D fopen(filename, "r");
+ if(!f){
+ char *codec_name=3D *opt =3D=3D 'v' ? video_codec_name :
+ *opt =3D=3D 'a' ? audio_codec_name :
+ subtitle_codec_name;
+ snprintf(filename, sizeof(filename), "%s%s/%s-%s.ffpreset"=
, base[i], i ? "" : "/.ffmpeg", codec_name, arg);
+ f=3D fopen(filename, "r");
+ }
+ }
+ } else {
+ av_strlcpy(filename, arg, sizeof(filename));
+ f=3D fopen(filename, "r");
+ }
+
+ if(!f){
+ fprintf(stderr, "File for preset '%s' not found\n", arg);
+ av_exit(1);
+ }
+
+ while(!feof(f)){
+ int e=3D fscanf(f, "%999[^\n]\n", line) - 1;
+ if(line[0] =3D=3D '#' && !e)
+ continue;
+ e|=3D sscanf(line, "%999[^=3D]=3D%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' =3D '%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 @@
=20
lavc_venc_context->me_method =3D ME_ZERO + lavc_param_vme;
=20
+
+ /* FIXME: transcode itself contains "broken ffmpeg default settings", thu=
s we need to override them! */
+ if (lavc_param_video_preset) {
+ avcodec_opts[AVMEDIA_TYPE_VIDEO] =3D lavc_venc_context;
+ video_codec_name =3D ffmpeg_codec_name(codec->name);
+
+ const char *preset_start =3D lavc_param_video_preset;
+ while (preset_start) {
+ const char *preset_end =3D tc_strchrnul(preset_start, ',');
+ char preset_name[255] =3D {'\0'};
+
+ if (strncpy(preset_name, preset_start, preset_end-preset_start) !=3D pr=
eset_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) !=3D 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 overr=
idden:", preset_name, opt_name_count);
+ for (i=3D0; i < opt_name_count; i++)
+ tc_log_info(MOD_NAME, "-- %s", opt_names[i]);
+ }
+
+ if (*preset_end !=3D '\0') {
+ preset_start =3D preset_end+1;
+ }
+ else {
+ preset_start =3D 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
=2D-- transcode-1.1.5.orig//export/ffmpeg_cfg.c 2010-06-06 10:57:38.1289961=
93 +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 =3D 0;
//int lavc_param_abitrate =3D 224;
=20
+char *lavc_param_video_preset =3D "medium";
+char *lavc_param_ffmpeg_datadir =3D "/usr/share/ffmpeg";
+
TCConfigEntry lavcopts_conf[]=3D{
// {"acodec", &lavc_param_acodec, TCCONF_TYPE_STRING, 0, 0, 0},
// {"abitrate", &lavc_param_abitrate, TCCONF_TYPE_INT, TCCONF_FLAG_RANG=
E, 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
=2D-- transcode-1.1.5.orig//export/ffmpeg_cfg.h 2010-06-06 10:57:38.1269943=
75 +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;
=20
+extern char *lavc_param_video_preset;
+extern char *lavc_param_ffmpeg_datadir;
+
extern TCConfigEntry lavcopts_conf[];
=20
#endif
--Boundary-01=_L27CMXyb8oY2MZg--
--nextPart1595698.fXnU5UVfEi
Content-Type: application/pgp-signature; name=signature.asc
Content-Description: This is a digitally signed message part.
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v2.0.15 (GNU/Linux)
iEYEABECAAYFAkwLvYsACgkQjqfyF1DtJW4ZiQCfWVUVWwWO0v6u/cDjkd5wnbWN
gWkAmwdScJ1+pq2zNUihKxzGSqI83qZt
=9UXt
-----END PGP SIGNATURE-----
--nextPart1595698.fXnU5UVfEi--