[FFmpeg-devel] [PATCH 3/4] fftools/ffmpeg_mux_init: apply encoder options manually

Anton Khirnov anton at khirnov.net
Thu May 23 12:03:38 EEST 2024


Do not pass an options dictionary to the avcodec_open2() in enc_open().

This is cleaner and more robust, as previously various bits of code
would try to interpret the contents of the options dictionary, with
varying degrees of correctness. Now they can just access the encoder
AVCodecContext directly.

Cf. 372c78dd42f2b1ca743473b9c32fad71c65919e0 - analogous change for
decoding.

A non-progressive field order is now written on the container level in
interlaced ProRes encoding tests.
---
 fftools/ffmpeg_enc.c                        | 18 ++----
 fftools/ffmpeg_mux_init.c                   | 66 +++++++++++----------
 tests/ref/vsynth/vsynth1-prores_444_int     |  2 +-
 tests/ref/vsynth/vsynth1-prores_int         |  2 +-
 tests/ref/vsynth/vsynth2-prores_444_int     |  2 +-
 tests/ref/vsynth/vsynth2-prores_int         |  2 +-
 tests/ref/vsynth/vsynth3-prores_444_int     |  2 +-
 tests/ref/vsynth/vsynth3-prores_int         |  2 +-
 tests/ref/vsynth/vsynth_lena-prores_444_int |  2 +-
 tests/ref/vsynth/vsynth_lena-prores_int     |  2 +-
 10 files changed, 47 insertions(+), 53 deletions(-)

diff --git a/fftools/ffmpeg_enc.c b/fftools/ffmpeg_enc.c
index 618ba193ff..029980063d 100644
--- a/fftools/ffmpeg_enc.c
+++ b/fftools/ffmpeg_enc.c
@@ -307,16 +307,10 @@ int enc_open(void *opaque, const AVFrame *frame)
     if (ost->bitexact)
         enc_ctx->flags |= AV_CODEC_FLAG_BITEXACT;
 
-    if (!av_dict_get(ost->encoder_opts, "threads", NULL, 0))
-        av_dict_set(&ost->encoder_opts, "threads", "auto", 0);
+    if (enc->capabilities & AV_CODEC_CAP_ENCODER_REORDERED_OPAQUE)
+        enc_ctx->flags |= AV_CODEC_FLAG_COPY_OPAQUE;
 
-    if (enc->capabilities & AV_CODEC_CAP_ENCODER_REORDERED_OPAQUE) {
-        ret = av_dict_set(&ost->encoder_opts, "flags", "+copy_opaque", AV_DICT_MULTIKEY);
-        if (ret < 0)
-            return ret;
-    }
-
-    av_dict_set(&ost->encoder_opts, "flags", "+frame_duration", AV_DICT_MULTIKEY);
+    enc_ctx->flags |= AV_CODEC_FLAG_FRAME_DURATION;
 
     ret = hw_device_setup_for_encode(ost, frame ? frame->hw_frames_ctx : NULL);
     if (ret < 0) {
@@ -325,7 +319,7 @@ int enc_open(void *opaque, const AVFrame *frame)
         return ret;
     }
 
-    if ((ret = avcodec_open2(ost->enc_ctx, enc, &ost->encoder_opts)) < 0) {
+    if ((ret = avcodec_open2(ost->enc_ctx, enc, NULL)) < 0) {
         if (ret != AVERROR_EXPERIMENTAL)
             av_log(ost, AV_LOG_ERROR, "Error while opening encoder - maybe "
                    "incorrect parameters such as bit_rate, rate, width or height.\n");
@@ -337,10 +331,6 @@ int enc_open(void *opaque, const AVFrame *frame)
     if (ost->enc_ctx->frame_size)
         frame_samples = ost->enc_ctx->frame_size;
 
-    ret = check_avoptions(ost->encoder_opts);
-    if (ret < 0)
-        return ret;
-
     if (ost->enc_ctx->bit_rate && ost->enc_ctx->bit_rate < 1000 &&
         ost->enc_ctx->codec_id != AV_CODEC_ID_CODEC2 /* don't complain about 700 bit/s modes */)
         av_log(ost, AV_LOG_WARNING, "The bitrate parameter is set too low."
diff --git a/fftools/ffmpeg_mux_init.c b/fftools/ffmpeg_mux_init.c
index 41afe8259d..61a0d8658f 100644
--- a/fftools/ffmpeg_mux_init.c
+++ b/fftools/ffmpeg_mux_init.c
@@ -711,14 +711,10 @@ static int new_stream_video(Muxer *mux, const OptionsContext *o,
         /* two pass mode */
         MATCH_PER_STREAM_OPT(pass, i, do_pass, oc, st);
         if (do_pass) {
-            if (do_pass & 1) {
+            if (do_pass & 1)
                 video_enc->flags |= AV_CODEC_FLAG_PASS1;
-                av_dict_set(&ost->encoder_opts, "flags", "+pass1", AV_DICT_APPEND);
-            }
-            if (do_pass & 2) {
+            if (do_pass & 2)
                 video_enc->flags |= AV_CODEC_FLAG_PASS2;
-                av_dict_set(&ost->encoder_opts, "flags", "+pass2", AV_DICT_APPEND);
-            }
         }
 
         MATCH_PER_STREAM_OPT(passlogfiles, str, ost->logfile_prefix, oc, st);
@@ -740,7 +736,10 @@ static int new_stream_video(Muxer *mux, const OptionsContext *o,
                                            DEFAULT_PASS_LOGFILENAME_PREFIX,
                      ost_idx);
             if (!strcmp(ost->enc_ctx->codec->name, "libx264")) {
-                av_dict_set(&ost->encoder_opts, "stats", logfilename, AV_DICT_DONT_OVERWRITE);
+                if (av_opt_is_set_to_default_by_name(ost->enc_ctx, "stats",
+                                                     AV_OPT_SEARCH_CHILDREN) > 0)
+                    av_opt_set(ost->enc_ctx, "stats", logfilename,
+                               AV_OPT_SEARCH_CHILDREN);
             } else {
                 if (video_enc->flags & AV_CODEC_FLAG_PASS2) {
                     char  *logbuffer = file_read(logfilename);
@@ -1041,6 +1040,7 @@ static int ost_add(Muxer *mux, const OptionsContext *o, enum AVMediaType type,
     const AVCodec *enc;
     AVStream *st;
     int ret = 0, keep_pix_fmt = 0, autoscale = 1;
+    int threads_manual = 0;
     AVRational enc_tb = { 0, 0 };
     enum VideoSyncMethod vsync_method = VSYNC_AUTO;
     const char *bsfs = NULL, *time_base = NULL;
@@ -1264,6 +1264,23 @@ static int ost_add(Muxer *mux, const OptionsContext *o, enum AVMediaType type,
 
             enc_tb = q;
         }
+
+        threads_manual = !!av_dict_get(ost->encoder_opts, "threads", NULL, 0);
+
+        ret = av_opt_set_dict2(ost->enc_ctx, &ost->encoder_opts, AV_OPT_SEARCH_CHILDREN);
+        if (ret < 0) {
+            av_log(ost, AV_LOG_ERROR, "Error applying encoder options: %s\n",
+                   av_err2str(ret));
+            return ret;
+        }
+
+        ret = check_avoptions(ost->encoder_opts);
+        if (ret < 0)
+            return ret;
+
+        // default to automatic thread count
+        if (!threads_manual)
+            ost->enc_ctx->thread_count = 0;
     } else {
         ret = filter_codec_opts(o->g->codec_opts, AV_CODEC_ID_NONE, oc, st,
                                 NULL, &ost->encoder_opts,
@@ -1276,8 +1293,7 @@ static int ost_add(Muxer *mux, const OptionsContext *o, enum AVMediaType type,
     if (o->bitexact) {
         ost->bitexact        = 1;
     } else if (ost->enc_ctx) {
-        ost->bitexact        = check_opt_bitexact(ost->enc_ctx, ost->encoder_opts, "flags",
-                                                  AV_CODEC_FLAG_BITEXACT);
+        ost->bitexact        = !!(ost->enc_ctx->flags & AV_CODEC_FLAG_BITEXACT);
     }
 
     MATCH_PER_STREAM_OPT(time_bases, str, time_base, oc, st);
@@ -1372,7 +1388,6 @@ static int ost_add(Muxer *mux, const OptionsContext *o, enum AVMediaType type,
 
     if (ost->enc &&
         (type == AVMEDIA_TYPE_VIDEO || type == AVMEDIA_TYPE_AUDIO)) {
-        const AVDictionaryEntry *e;
         char name[16];
         OutputFilterOptions opts = {
             .enc = enc,
@@ -1398,10 +1413,6 @@ static int ost_add(Muxer *mux, const OptionsContext *o, enum AVMediaType type,
 
         snprintf(name, sizeof(name), "#%d:%d", mux->of.index, ost->index);
 
-        e = av_dict_get(ost->encoder_opts, "threads", NULL, 0);
-        if (e)
-            opts.nb_threads = e->value;
-
         // MJPEG encoder exports a full list of supported pixel formats,
         // but the full-range ones are experimental-only.
         // Restrict the auto-conversion list unless -strict experimental
@@ -1413,33 +1424,26 @@ static int ost_add(Muxer *mux, const OptionsContext *o, enum AVMediaType type,
                 { AV_PIX_FMT_YUVJ420P, AV_PIX_FMT_YUVJ422P, AV_PIX_FMT_YUVJ444P,
                   AV_PIX_FMT_NONE };
 
-            const AVDictionaryEntry *strict = av_dict_get(ost->encoder_opts, "strict", NULL, 0);
-            int strict_val = ost->enc_ctx->strict_std_compliance;
-
-            if (strict) {
-                const AVOption *o = av_opt_find(ost->enc_ctx, strict->key, NULL, 0, 0);
-                av_assert0(o);
-                av_opt_eval_int(ost->enc_ctx, o, strict->value, &strict_val);
-            }
-
-            if (strict_val > FF_COMPLIANCE_UNOFFICIAL)
+            if (ost->enc_ctx->strict_std_compliance > FF_COMPLIANCE_UNOFFICIAL)
                 opts.pix_fmts = mjpeg_formats;
         }
 
+        if (threads_manual) {
+            ret = av_opt_get(ost->enc_ctx, "threads", 0, (uint8_t**)&opts.nb_threads);
+            if (ret < 0)
+                return ret;
+        }
+
         if (ofilter) {
             ost->filter       = ofilter;
             ret = ofilter_bind_ost(ofilter, ost, ms->sch_idx_enc, &opts);
-            if (ret < 0)
-                return ret;
         } else {
             ret = init_simple_filtergraph(ost->ist, ost, filters,
                                           mux->sch, ms->sch_idx_enc, &opts);
-            if (ret < 0) {
-                av_log(ost, AV_LOG_ERROR,
-                       "Error initializing a simple filtergraph\n");
-                return ret;
-            }
         }
+        av_freep(&opts.nb_threads);
+        if (ret < 0)
+            return ret;
 
         ret = sch_connect(mux->sch, SCH_ENC(ms->sch_idx_enc),
                                     SCH_MSTREAM(mux->sch_idx, ms->sch_idx));
diff --git a/tests/ref/vsynth/vsynth1-prores_444_int b/tests/ref/vsynth/vsynth1-prores_444_int
index 76db62d4e9..3d4c616c7a 100644
--- a/tests/ref/vsynth/vsynth1-prores_444_int
+++ b/tests/ref/vsynth/vsynth1-prores_444_int
@@ -1,4 +1,4 @@
-fd2a2f49c61817c2338f39d5736d5fd2 *tests/data/fate/vsynth1-prores_444_int.mov
+bd1502671ce7144c106a6a460b2af404 *tests/data/fate/vsynth1-prores_444_int.mov
 9940947 tests/data/fate/vsynth1-prores_444_int.mov
 732ceeb6887524e0aee98762fe50578b *tests/data/fate/vsynth1-prores_444_int.out.rawvideo
 stddev:    2.83 PSNR: 39.08 MAXDIFF:   45 bytes:  7603200/  7603200
diff --git a/tests/ref/vsynth/vsynth1-prores_int b/tests/ref/vsynth/vsynth1-prores_int
index 3e2bbeff2a..c3b57631c8 100644
--- a/tests/ref/vsynth/vsynth1-prores_int
+++ b/tests/ref/vsynth/vsynth1-prores_int
@@ -1,4 +1,4 @@
-1f1b246dfabe028f04c78887e5da51ed *tests/data/fate/vsynth1-prores_int.mov
+842f92426e56cf6208cc94360d29fc69 *tests/data/fate/vsynth1-prores_int.mov
 6308688 tests/data/fate/vsynth1-prores_int.mov
 164a4ca890695cf594293d1acec9463c *tests/data/fate/vsynth1-prores_int.out.rawvideo
 stddev:    2.66 PSNR: 39.62 MAXDIFF:   34 bytes:  7603200/  7603200
diff --git a/tests/ref/vsynth/vsynth2-prores_444_int b/tests/ref/vsynth/vsynth2-prores_444_int
index a2ee569c49..8d2a13b91b 100644
--- a/tests/ref/vsynth/vsynth2-prores_444_int
+++ b/tests/ref/vsynth/vsynth2-prores_444_int
@@ -1,4 +1,4 @@
-5ac517fc2380a6cf11b7d86d2fafee0a *tests/data/fate/vsynth2-prores_444_int.mov
+6f5fa77609698fbed3a7eef1c91bb9ea *tests/data/fate/vsynth2-prores_444_int.mov
 6420787 tests/data/fate/vsynth2-prores_444_int.mov
 33a5db4f0423168d4ae4f1db3610928e *tests/data/fate/vsynth2-prores_444_int.out.rawvideo
 stddev:    0.93 PSNR: 48.73 MAXDIFF:   14 bytes:  7603200/  7603200
diff --git a/tests/ref/vsynth/vsynth2-prores_int b/tests/ref/vsynth/vsynth2-prores_int
index 72139ee6c3..f80ff34601 100644
--- a/tests/ref/vsynth/vsynth2-prores_int
+++ b/tests/ref/vsynth/vsynth2-prores_int
@@ -1,4 +1,4 @@
-4062c74196d95a64e642bd917377ed93 *tests/data/fate/vsynth2-prores_int.mov
+a9a9812dd8944a58c2c2b3b0ce41247d *tests/data/fate/vsynth2-prores_int.mov
 4070996 tests/data/fate/vsynth2-prores_int.mov
 bef9e38387a1fbb1ce2e4401b6d41674 *tests/data/fate/vsynth2-prores_int.out.rawvideo
 stddev:    1.54 PSNR: 44.37 MAXDIFF:   13 bytes:  7603200/  7603200
diff --git a/tests/ref/vsynth/vsynth3-prores_444_int b/tests/ref/vsynth/vsynth3-prores_444_int
index ac30691143..ca30db5383 100644
--- a/tests/ref/vsynth/vsynth3-prores_444_int
+++ b/tests/ref/vsynth/vsynth3-prores_444_int
@@ -1,4 +1,4 @@
-50db4bbc4674de3dfdd41f306af1cb17 *tests/data/fate/vsynth3-prores_444_int.mov
+b61864cafb35ad8e592b4f899bdd84b6 *tests/data/fate/vsynth3-prores_444_int.mov
 184397 tests/data/fate/vsynth3-prores_444_int.mov
 a8852aa2841c2ce5f2aa86176ceda4ef *tests/data/fate/vsynth3-prores_444_int.out.rawvideo
 stddev:    3.24 PSNR: 37.91 MAXDIFF:   41 bytes:    86700/    86700
diff --git a/tests/ref/vsynth/vsynth3-prores_int b/tests/ref/vsynth/vsynth3-prores_int
index 86fc2266b5..0feee26de1 100644
--- a/tests/ref/vsynth/vsynth3-prores_int
+++ b/tests/ref/vsynth/vsynth3-prores_int
@@ -1,4 +1,4 @@
-24b765064b4aec754fdd0cc3658bba19 *tests/data/fate/vsynth3-prores_int.mov
+2e89dfb5e2b5146337c1d65ccc4fe196 *tests/data/fate/vsynth3-prores_int.mov
 120484 tests/data/fate/vsynth3-prores_int.mov
 e5859ba47a99f9e53c1ddcaa68a8f8f8 *tests/data/fate/vsynth3-prores_int.out.rawvideo
 stddev:    2.92 PSNR: 38.81 MAXDIFF:   29 bytes:    86700/    86700
diff --git a/tests/ref/vsynth/vsynth_lena-prores_444_int b/tests/ref/vsynth/vsynth_lena-prores_444_int
index f05f1fe775..b13a7a126a 100644
--- a/tests/ref/vsynth/vsynth_lena-prores_444_int
+++ b/tests/ref/vsynth/vsynth_lena-prores_444_int
@@ -1,4 +1,4 @@
-09b5dffd1a484e2152a3b5a0bcceed32 *tests/data/fate/vsynth_lena-prores_444_int.mov
+e76d98c772c65c7ac75f7d43484883d3 *tests/data/fate/vsynth_lena-prores_444_int.mov
 5696258 tests/data/fate/vsynth_lena-prores_444_int.mov
 466380156e4d2b811f4ffb9c5a8bca72 *tests/data/fate/vsynth_lena-prores_444_int.out.rawvideo
 stddev:    0.88 PSNR: 49.23 MAXDIFF:    9 bytes:  7603200/  7603200
diff --git a/tests/ref/vsynth/vsynth_lena-prores_int b/tests/ref/vsynth/vsynth_lena-prores_int
index ea08089745..cec45a59b9 100644
--- a/tests/ref/vsynth/vsynth_lena-prores_int
+++ b/tests/ref/vsynth/vsynth_lena-prores_int
@@ -1,4 +1,4 @@
-c7e9a61054f44fe372a3bce619b68ce9 *tests/data/fate/vsynth_lena-prores_int.mov
+21d328216b194500a3c87c45afa5e927 *tests/data/fate/vsynth_lena-prores_int.mov
 3532698 tests/data/fate/vsynth_lena-prores_int.mov
 eb5caa9824ca294f403cd13f33c40f23 *tests/data/fate/vsynth_lena-prores_int.out.rawvideo
 stddev:    1.47 PSNR: 44.78 MAXDIFF:   12 bytes:  7603200/  7603200
-- 
2.43.0



More information about the ffmpeg-devel mailing list