This is an automated email from the git hooks/post-receive script.

Git pushed a commit to branch master
in repository ffmpeg.

commit ca821e458aabe2fa211d9e94eac38cd69fe2ea09
Author:     James Almer <[email protected]>
AuthorDate: Mon Feb 10 23:43:13 2025 -0300
Commit:     James Almer <[email protected]>
CommitDate: Thu Aug 13 11:04:44 2026 -0300

    fftools/ffmpeg: support reinitializing the encoder
    
    With this, an encoding process can change certain values that until now were
    settable during init only.
    A graceful reconfiguration will be attempted first, which depends on the
    capabilities of the underlying encoder. If that fails, a full encoder 
restart
    is performed instead.
    
    The reconfiguration parameters are passed as a list of target timestamp and
    key=value pairs to be applied at that point during encoding. Future
    improvements may also include targetting encoded frame number, and extending
    the command feature to also support passing encoder runtime arguments and 
not
    just filter runtime change arguments.
    
    Example:
    
    ffmpeg -i INPUT -reinit_opts:v:0 
"pts=100000|crf=18,pts=200000|video_size=1280x720:crf=20" -crf 30 -c:v:0 
libx264 OUTPUT
    
    Signed-off-by: James Almer <[email protected]>
---
 doc/ffmpeg.texi           |   7 +++
 fftools/ffmpeg.c          |   4 ++
 fftools/ffmpeg.h          |  10 ++++
 fftools/ffmpeg_enc.c      | 145 +++++++++++++++++++++++++++++++++++++++++++++-
 fftools/ffmpeg_filter.c   | 136 ++++++++++++++++++++++++++++++++++++++++++-
 fftools/ffmpeg_mux_init.c |  16 ++++-
 fftools/ffmpeg_opt.c      |   5 ++
 7 files changed, 316 insertions(+), 7 deletions(-)

diff --git a/doc/ffmpeg.texi b/doc/ffmpeg.texi
index ad235b78c4..1cbb1ccbdd 100644
--- a/doc/ffmpeg.texi
+++ b/doc/ffmpeg.texi
@@ -1249,6 +1249,13 @@ ffmpeg -i input.iamf -c:a copy -stream_group 
map=0=0:st=0:st=1:st=2:st=3 -stream
 -streamid 0:0 -streamid 1:1 -streamid 2:2 -streamid 3:3 output.mp4
 @end example
 
+@item -reinit_opts[:@var{stream_specifier}] 
pts=@var{pts}|@var{key}=@var{value}[:force_reinit=1][:@var{key}=@var{value},pts=@var{pts}...]
 (@emph{output,per-stream})
+
+Creates a "," separated group of options to reconfigure an encoder at the
+specified output @var{pts} in AV_TIME_BASE units.
+The pseudo-option @var{force_reinit} ensures the encoder is fully reinitialized
+instead of simply reconfigured.
+
 @item -target @var{type} (@emph{output})
 Specify target file type (@code{vcd}, @code{svcd}, @code{dvd}, @code{dv},
 @code{dv50}). @var{type} may be prefixed with @code{pal-}, @code{ntsc-} or
diff --git a/fftools/ffmpeg.c b/fftools/ffmpeg.c
index d38acffbdf..186b549102 100644
--- a/fftools/ffmpeg.c
+++ b/fftools/ffmpeg.c
@@ -416,6 +416,7 @@ static void frame_data_free(void *opaque, uint8_t *data)
 
     av_frame_side_data_free(&fd->side_data, &fd->nb_side_data);
     avcodec_parameters_free(&fd->par_enc);
+    av_dict_free(&fd->reinit_opts);
 
     av_free(data);
 }
@@ -446,6 +447,7 @@ static int frame_data_ensure(AVBufferRef **dst, int 
writable)
             fd->par_enc = NULL;
             fd->side_data = NULL;
             fd->nb_side_data = 0;
+            fd->reinit_opts = NULL;
 
             if (fd_src->par_enc) {
                 int ret = 0;
@@ -454,6 +456,8 @@ static int frame_data_ensure(AVBufferRef **dst, int 
writable)
                 ret = fd->par_enc ?
                       avcodec_parameters_copy(fd->par_enc, fd_src->par_enc) :
                       AVERROR(ENOMEM);
+                if (!ret && fd_src->reinit_opts)
+                    ret = av_dict_copy(&fd->reinit_opts, fd_src->reinit_opts, 
0);
                 if (ret < 0) {
                     av_buffer_unref(dst);
                     av_buffer_unref(&src);
diff --git a/fftools/ffmpeg.h b/fftools/ffmpeg.h
index 11682b34bb..c403acdb59 100644
--- a/fftools/ffmpeg.h
+++ b/fftools/ffmpeg.h
@@ -236,6 +236,7 @@ typedef struct OptionsContext {
     SpecifierOptList enc_time_bases;
     SpecifierOptList autoscale;
     SpecifierOptList bits_per_raw_sample;
+    SpecifierOptList enc_reinit_opts;
     SpecifierOptList enc_stats_pre;
     SpecifierOptList enc_stats_post;
     SpecifierOptList mux_stats;
@@ -347,6 +348,8 @@ typedef struct OutputFilterOptions {
     AVFrameSideData   **side_data;
     int                 nb_side_data;
 
+    const char *reinit_opts;
+
     // for simple filtergraphs only, view specifier passed
     // along to the decoder
     const ViewSpecifier *vs;
@@ -607,6 +610,11 @@ typedef struct Encoder {
 
     AVCodecContext         *enc_ctx;
 
+    // initial encoder options
+    AVDictionary           *encoder_opts;
+    // pts|key=value list of options to reinitialize encoder
+    char                   *reinit_opts;
+
     uint32_t                codec_tag;
     int                     flags;
     int                     flags2;
@@ -716,6 +724,8 @@ typedef struct FrameData {
 
     AVFrameSideData   **side_data;
     int                 nb_side_data;
+
+    AVDictionary *reinit_opts;
 } FrameData;
 
 extern InputFile   **input_files;
diff --git a/fftools/ffmpeg_enc.c b/fftools/ffmpeg_enc.c
index dfc7d5e9d8..8cf45bbf53 100644
--- a/fftools/ffmpeg_enc.c
+++ b/fftools/ffmpeg_enc.c
@@ -31,6 +31,7 @@
 #include "libavutil/intreadwrite.h"
 #include "libavutil/log.h"
 #include "libavutil/mem.h"
+#include "libavutil/opt.h"
 #include "libavutil/pixdesc.h"
 #include "libavutil/rational.h"
 #include "libavutil/time.h"
@@ -49,6 +50,7 @@ typedef struct EncoderPriv {
 
     // number of packets received from the encoder
     uint64_t packets_encoded;
+    int got_first_packet;
 
     int opened;
     int attach_par;
@@ -78,6 +80,7 @@ void enc_free(Encoder **penc)
     if (enc->enc_ctx)
         av_freep(&enc->enc_ctx->stats_in);
     avcodec_free_context(&enc->enc_ctx);
+    av_dict_free(&enc->encoder_opts);
 
     av_freep(penc);
 }
@@ -96,6 +99,29 @@ static const AVClass enc_class = {
     .item_name                 = enc_item_name,
 };
 
+static int enc_realloc(Encoder *enc, const AVCodec *codec)
+{
+    EncoderPriv *ep = ep_from_enc(enc);
+    char *stats_in = NULL;
+
+    if (enc->enc_ctx)
+        stats_in = enc->enc_ctx->stats_in;
+    avcodec_free_context(&enc->enc_ctx);
+
+    ep->opened = 0;
+    ep->got_first_packet = 0;
+
+    enc->enc_ctx = avcodec_alloc_context3(codec);
+    if (!enc->enc_ctx) {
+        av_freep(&stats_in);
+        return AVERROR(ENOMEM);
+    }
+
+    enc->enc_ctx->stats_in = stats_in;
+
+    return 0;
+}
+
 int enc_alloc(Encoder **penc, const AVCodec *codec,
               Scheduler *sch, unsigned sch_idx, void *log_parent)
 {
@@ -181,7 +207,26 @@ static int hw_device_setup_for_encode(Encoder *e, 
AVCodecContext *enc_ctx,
     return 0;
 }
 
-static int enc_reopen(void *opaque, const AVFrame *frame)
+static int apply_enc_options(Encoder *e, AVDictionary **opts)
+{
+    AVCodecContext *enc_ctx = e->enc_ctx;
+
+    int ret = av_opt_set_dict2(enc_ctx, opts, AV_OPT_SEARCH_CHILDREN);
+    if (ret < 0) {
+        av_log(e, AV_LOG_ERROR, "Error applying encoder options: %s\n",
+               av_err2str(ret));
+        return ret;
+    }
+
+    ret = check_avoptions(*opts);
+    if (ret < 0)
+        return ret;
+
+    return 0;
+}
+
+static int enc_reopen(void *opaque, const AVFrame *frame,
+                      AVDictionary **extra_encoder_opts)
 {
     OutputStream *ost = opaque;
     InputStream *ist = ost->ist;
@@ -190,9 +235,32 @@ static int enc_reopen(void *opaque, const AVFrame *frame)
     AVCodecContext *enc_ctx = e->enc_ctx;
     Decoder            *dec = NULL;
     const AVCodec      *enc = enc_ctx->codec;
+    AVDictionary       *encoder_opts = NULL;
     FrameData *fd;
+    int threads_manual;
     int ret;
 
+    ret = av_dict_copy(&encoder_opts, ost->enc->encoder_opts, 0);
+    if (ret < 0)
+        return ret;
+
+    threads_manual = !!av_dict_get(encoder_opts, "threads", NULL, 0);
+    ret = apply_enc_options(e, &encoder_opts);
+    av_dict_free(&encoder_opts);
+    if (ret < 0)
+        return ret;
+
+    if (extra_encoder_opts) {
+        threads_manual |= !!av_dict_get(*extra_encoder_opts, "threads", NULL, 
0);
+        ret = apply_enc_options(e, extra_encoder_opts);
+        if (ret < 0)
+            return ret;
+    }
+
+    // default to automatic thread count
+    if (!threads_manual)
+        enc_ctx->thread_count = 0;
+
     // frame is always non-NULL for audio and video
     av_assert0(frame || (enc->type != AVMEDIA_TYPE_VIDEO && enc->type != 
AVMEDIA_TYPE_AUDIO));
 
@@ -366,7 +434,7 @@ int enc_open(void *opaque, const AVFrame *frame)
     if (ep->opened)
         return 0;
 
-    ret = enc_reopen(opaque, frame);
+    ret = enc_reopen(opaque, frame, NULL);
     if (ret < 0)
         return ret;
 
@@ -698,9 +766,19 @@ static int encode_frame(OutputFile *of, OutputStream *ost, 
AVFrame *frame,
             return AVERROR(ENOMEM);
         fd->wallclock[LATENCY_PROBE_ENC_POST] = av_gettime_relative();
 
+        // attach extradata to first packet if the encoder was reinitialized
+        if (!ep->got_first_packet && ep->packets_encoded && 
enc->extradata_size) {
+            uint8_t *extradata = av_packet_new_side_data(pkt, 
AV_PKT_DATA_NEW_EXTRADATA,
+                                                         enc->extradata_size);
+            if (!extradata)
+                return AVERROR(ENOMEM);
+            memcpy(extradata, enc->extradata, enc->extradata_size);
+            ep->got_first_packet = 1;
+        }
         // attach stream parameters to first packet if requested
         avcodec_parameters_free(&fd->par_enc);
-        if (ep->attach_par && !ep->packets_encoded) {
+        if (!ep->packets_encoded) {
+            if (ep->attach_par) {
             fd->par_enc = avcodec_parameters_alloc();
             if (!fd->par_enc)
                 return AVERROR(ENOMEM);
@@ -708,6 +786,8 @@ static int encode_frame(OutputFile *of, OutputStream *ost, 
AVFrame *frame,
             ret = avcodec_parameters_from_context(fd->par_enc, enc);
             if (ret < 0)
                 return ret;
+            }
+            ep->got_first_packet = 1;
         }
 
         pkt->flags |= AV_PKT_FLAG_TRUSTED;
@@ -878,12 +958,61 @@ static int flush_encoder(OutputStream *ost, EncoderThread 
*et)
     return ret;
 }
 
+static int reinit_encoder(OutputStream *ost, EncoderThread *et)
+{
+    Encoder     *e = ost->enc;
+    AVDictionary *copy = NULL;
+    const FrameData *fd = frame_data_c(et->frame);
+    int force_reinit, ret = AVERROR_BUG;
+
+    ret = av_dict_copy(&copy, fd->reinit_opts, 0);
+    if (ret < 0)
+        return ret;
+
+    force_reinit = !!av_dict_get(copy, "force_reinit", NULL, 0);
+    if (force_reinit)
+        av_dict_set(&copy, "force_reinit", NULL, 0);
+    // Lets try a graceful reconfiguration first
+    else if (e->enc_ctx->codec->capabilities & AV_CODEC_CAP_RECONF) {
+        ret = avcodec_encode_reconfigure(e->enc_ctx, &copy);
+        if (!ret)
+            goto end;
+
+        ret = av_dict_copy(&copy, fd->reinit_opts, AV_DICT_DONT_OVERWRITE);
+        if (ret < 0)
+            goto end;
+        av_dict_set(&copy, "force_reinit", NULL, 0);
+
+        av_log(e, AV_LOG_INFO, "Could not reconfigure the encoder."
+                               " Trying to restart it instead\n");
+    }
+
+    // Go ahead and do a full restart of the encoder
+    ret = flush_encoder(ost, et);
+    if (ret < 0 && ret != AVERROR_EOF)
+        goto end;
+
+    ret = enc_realloc(e, e->enc_ctx->codec);
+    if (ret < 0)
+        goto end;
+    av_log(e, AV_LOG_DEBUG, "Restarting encoder\n");
+    ret = enc_reopen(ost, et->frame, &copy);
+    if (ret < 0)
+        goto end;
+
+    ret = 0;
+end:
+    av_dict_free(&copy);
+    return ret;
+}
+
 int encoder_thread(void *arg)
 {
     OutputStream *ost = arg;
     Encoder        *e = ost->enc;
     EncoderPriv   *ep = ep_from_enc(e);
     EncoderThread et;
+    const FrameData *fd;
     int ret = 0, input_status = 0;
     int name_set = 0;
 
@@ -927,6 +1056,16 @@ int encoder_thread(void *arg)
             name_set = 1;
         }
 
+        fd = frame_data_c(et.frame);
+        if (fd && fd->reinit_opts) {
+            ret = reinit_encoder(ost, &et);
+            if (ret < 0) {
+                av_log(e, AV_LOG_ERROR, "Error reconfiguring or restarting 
encoder: %s\n",
+                       av_err2str(ret));
+                goto finish;
+            }
+        }
+
         ret = frame_encode(ost, et.frame, et.pkt);
 
         av_packet_unref(et.pkt);
diff --git a/fftools/ffmpeg_filter.c b/fftools/ffmpeg_filter.c
index 79528a784d..114a694c0c 100644
--- a/fftools/ffmpeg_filter.c
+++ b/fftools/ffmpeg_filter.c
@@ -187,6 +187,11 @@ typedef struct FPSConvContext {
     int               framerate_clip;
 } FPSConvContext;
 
+typedef struct ReinitOpts {
+    int64_t pts;
+    AVDictionary *dict;
+} ReinitOpts;
+
 typedef struct OutputFilterPriv {
     OutputFilter            ofilter;
 
@@ -246,6 +251,9 @@ typedef struct OutputFilterPriv {
     int64_t                 next_pts;
     FPSConvContext          fps;
 
+    AVFifo                 *reinit_opts_fifo;
+    ReinitOpts              reinit_opts;
+
     unsigned                flags;
 } OutputFilterPriv;
 
@@ -682,6 +690,7 @@ static OutputFilter *ofilter_alloc(FilterGraph *fg, enum 
AVMediaType type)
     ofilter->graph    = fg;
     ofilter->type     = type;
     av_opt_set_defaults(ofp);
+    ofp->reinit_opts  = (ReinitOpts){ .pts = AV_NOPTS_VALUE };
     ofilter->index    = fg->nb_outputs - 1;
 
     snprintf(ofp->log_name, sizeof(ofp->log_name), "%co%d",
@@ -822,6 +831,75 @@ static int set_channel_layout(OutputFilterPriv *f, const 
AVChannelLayout *layout
     return 0;
 }
 
+static int parse_reinit_opts(AVFifo **pout, const char *opts, void *logctx)
+{
+    AVFifo *out;
+    int ret = AVERROR_BUG;
+    char *ptr, *str, *substr = NULL;
+    const char *token;
+
+    str = av_strdup(opts);
+    if (!str)
+        return AVERROR(ENOMEM);
+
+    out = av_fifo_alloc2(1, sizeof(ReinitOpts), AV_FIFO_FLAG_AUTO_GROW);
+    if (!out) {
+        ret = AVERROR(ENOMEM);
+        goto end;
+    }
+
+    token = av_strtok(str, ",", &ptr);
+    while (token) {
+        ReinitOpts o = { 0 };
+        const char *subtoken;
+        char *subptr, *endptr;
+
+        substr = av_strdup(token);
+        if (!substr) {
+            ret = AVERROR(ENOMEM);
+            goto end;
+        }
+        subtoken = av_strtok(substr, "|", &subptr);
+        if (subtoken && subptr) {
+            if (!av_strstart(subtoken, "pts=", &subtoken)) {
+                av_log(logctx, AV_LOG_ERROR, "Invalid reinit identifier\n");
+                ret = AVERROR(ENOMEM);
+                goto end;
+            }
+            o.pts = strtoll(subtoken, &endptr, 0);
+            if (*endptr || o.pts < 0) {
+                ret = AVERROR(EINVAL);
+                goto end;
+            }
+            ret = av_dict_parse_string(&o.dict, subptr, "=", ":", 0);
+            if (ret < 0) {
+                av_log(logctx, AV_LOG_ERROR, "Error parsing encoder 
options\n");
+                goto end;
+            }
+            ret = av_fifo_write(out, &o, 1);
+            if (ret < 0) {
+                av_dict_free(&o.dict);
+                goto end;
+            }
+        } else {
+            ret = AVERROR(EINVAL);
+            goto end;
+        }
+        av_freep(&substr);
+        if (ptr)
+            ptr += strspn(ptr, " \n\t\r");
+        token = av_strtok(NULL, ",", &ptr);
+    }
+
+    ret = 0;
+end:
+    *pout = out;
+    av_free(substr);
+    av_free(str);
+
+    return ret;
+}
+
 int ofilter_bind_enc(OutputFilter *ofilter, unsigned sched_idx_enc,
                      const OutputFilterOptions *opts)
 {
@@ -848,6 +926,12 @@ int ofilter_bind_enc(OutputFilter *ofilter, unsigned 
sched_idx_enc,
     if (!ofilter->output_name)
         return AVERROR(EINVAL);
 
+    if (opts->reinit_opts) {
+        ret = parse_reinit_opts(&ofp->reinit_opts_fifo, opts->reinit_opts, 
ofilter);
+        if (ret < 0)
+            return ret;
+    }
+
     ret = av_dict_copy(&ofp->sws_opts, opts->sws_opts, 0);
     if (ret < 0)
         return ret;
@@ -1072,6 +1156,12 @@ void fg_free(FilterGraph **pfg)
         av_freep(&ofilter->name);
         av_freep(&ofilter->output_name);
         av_freep(&ofilter->apad);
+        av_dict_free(&ofp->reinit_opts.dict);
+        if (ofp->reinit_opts_fifo) {
+            while (av_fifo_read(ofp->reinit_opts_fifo, &ofp->reinit_opts, 1) 
>= 0)
+                av_dict_free(&ofp->reinit_opts.dict);
+            av_fifo_freep2(&ofp->reinit_opts_fifo);
+        }
         av_channel_layout_uninit(&ofp->ch_layout);
         av_frame_side_data_free(&ofp->side_data, &ofp->nb_side_data);
         av_freep(&fg->outputs[j]);
@@ -3088,7 +3178,7 @@ static const char *unknown_if_null(const char *str)
 }
 
 static int send_frame(FilterGraph *fg, FilterGraphThread *fgt,
-                      InputFilter *ifilter, AVFrame *frame)
+                      InputFilter *ifilter, AVFrame *frame, int force_reinit)
 {
     FilterGraphPriv *fgp = fgp_from_fg(fg);
     InputFilterPriv *ifp = ifp_from_ifilter(ifilter);
@@ -3165,7 +3255,7 @@ static int send_frame(FilterGraph *fg, FilterGraphThread 
*fgt,
     }
 
     /* (re)init the graph if possible, otherwise buffer the frame and return */
-    if (need_reinit || !fgt->graph) {
+    if (need_reinit || force_reinit || !fgt->graph) {
         AVFrame *tmp = av_frame_alloc();
 
         if (!tmp)
@@ -3211,6 +3301,8 @@ static int send_frame(FilterGraph *fg, FilterGraphThread 
*fgt,
                 av_bprintf(&reason, "downmix medatata changed, ");
             if (need_reinit & HWACCEL_CHANGED)
                 av_bprintf(&reason, "hwaccel changed, ");
+            if (force_reinit)
+                av_bprintf(&reason, "reinitialization arguments were provided, 
");
             if (reason.len > 1)
                 reason.str[reason.len - 2] = '\0'; // remove last comma
             av_log(fg, AV_LOG_INFO, "Reconfiguring filter graph%s%s\n", 
reason.len ? " because " : "", reason.str);
@@ -3312,6 +3404,42 @@ fail:
     return AVERROR(ENOMEM);
 }
 
+static int check_reinit(FilterGraph *fg, FilterGraphThread *fgt)
+{
+    int ret, reinit = 0;
+
+    for (unsigned i = 0; i < fg->nb_outputs; i++) {
+        OutputFilterPriv *ofp = ofp_from_ofilter(fg->outputs[i]);
+
+        if (ofp->reinit_opts.pts == AV_NOPTS_VALUE && ofp->reinit_opts_fifo &&
+            av_fifo_can_read(ofp->reinit_opts_fifo)) {
+            av_fifo_read(ofp->reinit_opts_fifo, &ofp->reinit_opts, 1);
+        }
+        if (ofp->reinit_opts.pts != AV_NOPTS_VALUE &&
+            ofp->reinit_opts.pts <= av_rescale_q(fgt->frame->pts, 
fgt->frame->time_base, AV_TIME_BASE_Q)) {
+           FrameData *fd = frame_data(fgt->frame);
+           if (!fd)
+               return AVERROR(ENOMEM);
+
+           av_dict_free(&fd->reinit_opts);
+           ret = av_dict_copy(&fd->reinit_opts, ofp->reinit_opts.dict, 0);
+           if (ret < 0)
+               return ret;
+
+           av_opt_set_dict(ofp, &ofp->reinit_opts.dict);
+           av_dict_free(&ofp->reinit_opts.dict);
+
+           if (av_fifo_can_read(ofp->reinit_opts_fifo))
+               av_fifo_read(ofp->reinit_opts_fifo, &ofp->reinit_opts, 1);
+           else
+               ofp->reinit_opts = (ReinitOpts){ .pts = AV_NOPTS_VALUE };
+           reinit = 1;
+        }
+    }
+
+    return reinit;
+}
+
 static int filter_thread(void *arg)
 {
     FilterGraphPriv *fgp = arg;
@@ -3378,7 +3506,9 @@ static int filter_thread(void *arg)
             ret = sub2video_frame(ifilter, (fgt.frame->buf[0] || hb_frame) ? 
fgt.frame : NULL,
                                   !fgt.graph);
         } else if (fgt.frame->buf[0]) {
-            ret = send_frame(fg, &fgt, ifilter, fgt.frame);
+            ret = check_reinit(fg, &fgt);
+            if (ret >= 0)
+                ret = send_frame(fg, &fgt, ifilter, fgt.frame, ret);
         } else {
             av_assert1(o == FRAME_OPAQUE_EOF);
             ret = send_eof(&fgt, ifilter, fgt.frame->pts, 
fgt.frame->time_base);
diff --git a/fftools/ffmpeg_mux_init.c b/fftools/ffmpeg_mux_init.c
index 702a39c8d7..f80b4427b4 100644
--- a/fftools/ffmpeg_mux_init.c
+++ b/fftools/ffmpeg_mux_init.c
@@ -896,6 +896,7 @@ ost_bind_filter(const Muxer *mux, MuxStream *ms, 
OutputFilter *ofilter,
                             0 : mux->of.start_time,
         .vs               = vs,
         .nb_threads       = -1,
+        .reinit_opts      = ost->enc->reinit_opts,
 
         .flags = OFILTER_FLAG_DISABLE_CONVERT * !!keep_pix_fmt |
                  OFILTER_FLAG_AUTOSCALE       * !!autoscale    |
@@ -1255,7 +1256,7 @@ static int ost_add(Muxer *mux, const OptionsContext *o, 
enum AVMediaType type,
         AVIOContext *s = NULL;
         char *buf = NULL, *arg = NULL;
         const char *enc_stats_pre = NULL, *enc_stats_post = NULL, *mux_stats = 
NULL;
-        const char *enc_time_base = NULL, *preset = NULL;
+        const char *enc_time_base = NULL, *enc_reinit_opts = NULL, *preset = 
NULL;
 
         ret = filter_codec_opts(o->g->codec_opts, enc->id,
                                 oc, st, enc, &encoder_opts,
@@ -1295,6 +1296,16 @@ static int ost_add(Muxer *mux, const OptionsContext *o, 
enum AVMediaType type,
             goto fail;
         }
 
+        opt_match_per_stream_str(ost, &o->enc_reinit_opts, oc, st, 
&enc_reinit_opts);
+        if (enc_reinit_opts &&
+            (type == AVMEDIA_TYPE_VIDEO || type == AVMEDIA_TYPE_AUDIO)) {
+            ost->enc->reinit_opts = av_strdup(enc_reinit_opts);
+            if (!ost->enc->reinit_opts) {
+                ret = AVERROR(ENOMEM);
+                goto fail;
+            }
+        }
+
         opt_match_per_stream_str(ost, &o->enc_stats_pre, oc, st, 
&enc_stats_pre);
         if (enc_stats_pre &&
             (type == AVMEDIA_TYPE_VIDEO || type == AVMEDIA_TYPE_AUDIO)) {
@@ -1356,6 +1367,9 @@ static int ost_add(Muxer *mux, const OptionsContext *o, 
enum AVMediaType type,
 
         threads_manual = !!av_dict_get(encoder_opts, "threads", NULL, 0);
 
+        ret = av_dict_copy(&ost->enc->encoder_opts, encoder_opts, 0);
+        if (ret < 0)
+            goto fail;
         ret = av_opt_set_dict2(ost->enc->enc_ctx, &encoder_opts, 
AV_OPT_SEARCH_CHILDREN);
         if (ret < 0) {
             av_log(ost, AV_LOG_ERROR, "Error applying encoder options: %s\n",
diff --git a/fftools/ffmpeg_opt.c b/fftools/ffmpeg_opt.c
index 12fbd3bda8..fdbc0fdc13 100644
--- a/fftools/ffmpeg_opt.c
+++ b/fftools/ffmpeg_opt.c
@@ -1831,6 +1831,11 @@ const OptionDef options[] = {
         { .off = OFFSET(mux_stats_fmt)      },
         "format of the stats written with -stats_mux_pre" },
 
+    { "reinit_opts",        OPT_TYPE_STRING, OPT_PERSTREAM | OPT_EXPERT | 
OPT_OUTPUT,
+        { .off = OFFSET(enc_reinit_opts) },
+        "List of encoder options to use to reinitialize the encoder at given 
timestamps",
+        "pts1|video_size=size:g=12,pts2|video_size=size..." },
+
     /* video options */
     { "vframes",                    OPT_TYPE_FUNC,   OPT_VIDEO | OPT_FUNC_ARG 
| OPT_PERFILE | OPT_OUTPUT | OPT_EXPERT | OPT_HAS_CANON,
         { .func_arg = opt_video_frames },

_______________________________________________
ffmpeg-cvslog mailing list -- [email protected]
To unsubscribe send an email to [email protected]

Reply via email to