With this, callers can signal supported encoders to reinitialize using certain
parameters, which should allow for more graceful (but potentially more limited
in scope) reinitialization than closing and reopening the encoder, or even
simply on-the-fly changes of trivial values that would not require any kind
or flushing or reinitialization by the encoder.

Signed-off-by: James Almer <jamr...@gmail.com>
---
 libavcodec/codec_internal.h |  2 ++
 libavcodec/encode.c         | 69 +++++++++++++++++++++++++++++++++++++
 2 files changed, 71 insertions(+)

diff --git a/libavcodec/codec_internal.h b/libavcodec/codec_internal.h
index 5b2db74590..e38402d2f5 100644
--- a/libavcodec/codec_internal.h
+++ b/libavcodec/codec_internal.h
@@ -243,6 +243,8 @@ typedef struct FFCodec {
      */
     void (*flush)(struct AVCodecContext *);
 
+    int (*reconf)(struct AVCodecContext *);
+
     /**
      * Decoding only, a comma-separated list of bitstream filters to apply to
      * packets before decoding.
diff --git a/libavcodec/encode.c b/libavcodec/encode.c
index 3baf5b8103..187b4015f1 100644
--- a/libavcodec/encode.c
+++ b/libavcodec/encode.c
@@ -31,6 +31,7 @@
 
 #include "avcodec.h"
 #include "avcodec_internal.h"
+#include "bytestream.h"
 #include "codec_desc.h"
 #include "codec_internal.h"
 #include "encode.h"
@@ -59,6 +60,69 @@ static EncodeContext *encode_ctx(AVCodecInternal *avci)
     return (EncodeContext*)avci;
 }
 
+static int apply_param_change(AVCodecContext *avctx, const AVFrame *frame)
+{
+    int ret = AVERROR_BUG;
+    const AVFrameSideData *sd;
+    GetByteContext gbc;
+    uint32_t flags;
+
+    sd = av_frame_get_side_data(frame, AV_FRAME_DATA_PARAM_CHANGE);
+    if (!sd)
+        return 0;
+
+    if (!(avctx->codec->capabilities & AV_CODEC_CAP_PARAM_CHANGE)) {
+        av_log(avctx, AV_LOG_ERROR, "This encoder does not support parameter "
+               "changes, but PARAM_CHANGE side data was sent to it.\n");
+        ret = AVERROR(EINVAL);
+        goto fail2;
+    }
+
+    if (sd->size < 4)
+        goto fail;
+
+    bytestream2_init(&gbc, sd->data, sd->size);
+    flags = bytestream2_get_le32(&gbc);
+
+    if (flags & AV_SIDE_DATA_PARAM_CHANGE_SAMPLE_RATE) {
+        if (frame->sample_rate <= 0 || frame->sample_rate > INT_MAX) {
+            av_log(avctx, AV_LOG_ERROR, "Invalid sample rate");
+            ret = AVERROR_INVALIDDATA;
+            goto fail2;
+        }
+        avctx->sample_rate = frame->sample_rate;
+    }
+    if (flags & AV_SIDE_DATA_PARAM_CHANGE_DIMENSIONS) {
+        av_image_check_size2(frame->width, frame->height, avctx->max_pixels, 
avctx->pix_fmt, 0, avctx);
+        if (ret < 0) {
+            av_log(avctx, AV_LOG_ERROR, "Invalid dimensions");
+            goto fail2;
+        }
+        avctx->width  = frame->width;
+        avctx->height = frame->height;
+    }
+
+    if (flags) {
+        ret = 0;
+        if (ffcodec(avctx->codec)->reconf)
+            ret = ffcodec(avctx->codec)->reconf(avctx);
+        if (ret < 0)
+            goto fail2;
+    }
+
+    return 0;
+fail:
+    av_log(avctx, AV_LOG_ERROR, "PARAM_CHANGE side data too small.\n");
+    ret = AVERROR_INVALIDDATA;
+fail2:
+    if (ret < 0) {
+        av_log(avctx, AV_LOG_ERROR, "Error applying parameter changes.\n");
+        if (avctx->err_recognition & AV_EF_EXPLODE)
+            return ret;
+    }
+    return 0;
+}
+
 int ff_alloc_packet(AVCodecContext *avctx, AVPacket *avpkt, int64_t size)
 {
     if (size < 0 || size > INT_MAX - AV_INPUT_BUFFER_PADDING_SIZE) {
@@ -205,6 +269,7 @@ int avcodec_encode_subtitle(AVCodecContext *avctx, uint8_t 
*buf, int buf_size,
 int ff_encode_get_frame(AVCodecContext *avctx, AVFrame *frame)
 {
     AVCodecInternal *avci = avctx->internal;
+    int ret;
 
     if (avci->draining)
         return AVERROR_EOF;
@@ -229,6 +294,10 @@ FF_DISABLE_DEPRECATION_WARNINGS
 FF_ENABLE_DEPRECATION_WARNINGS
 #endif
 
+    ret = apply_param_change(avctx, frame);
+    if (ret < 0)
+        return ret;
+
     return 0;
 }
 
-- 
2.48.1

_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel

To unsubscribe, visit link above, or email
ffmpeg-devel-requ...@ffmpeg.org with subject "unsubscribe".

Reply via email to