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".