diff --git a/libavcodec/avcodec.h b/libavcodec/avcodec.h index 12d9b3d47c1e4cd6a9d0b51e59031f2b2e24b57e..251e47dbc62182798109e2946a99bb3ab64fa30f 100644 --- a/libavcodec/avcodec.h +++ b/libavcodec/avcodec.h @@ -3258,6 +3258,19 @@ AVCodecContext *avcodec_alloc_context(void); * we WILL change its arguments and name a few times! */ AVCodecContext *avcodec_alloc_context2(enum AVMediaType); +/** + * Copy the settings of the source AVCodecContext into the destination + * AVCodecContext. The resulting destination codec context will be + * unopened, i.e. you are required to call avcodec_open() before you + * can use this AVCodecContext to decode/encode video/audio data. + * + * @param dest target codec context, should be initialized with + * avcodec_alloc_context(), but otherwise uninitialized + * @param src source codec context + * @return AVERROR() on error (e.g. memory allocation error), 0 on success + */ +int avcodec_copy_context(AVCodecContext *dest, const AVCodecContext *src); + /** * Sets the fields of the given AVFrame to default values. * diff --git a/libavcodec/options.c b/libavcodec/options.c index 89b25483c219378610bdee7b59876244b2c507d8..04fd3ba496991f493beebcd5b1c713974c436e42 100644 --- a/libavcodec/options.c +++ b/libavcodec/options.c @@ -471,3 +471,63 @@ AVCodecContext *avcodec_alloc_context(void){ return avcodec_alloc_context2(AVMEDIA_TYPE_UNKNOWN); } +int avcodec_copy_context(AVCodecContext *dest, const AVCodecContext *src) +{ + if (dest->codec) { // check that the dest context is uninitialized + av_log(dest, AV_LOG_ERROR, + "Tried to copy AVCodecContext %p into already-initialized %p\n", + src, dest); + return AVERROR(EINVAL); + } + memcpy(dest, src, sizeof(*dest)); + + /* set values specific to opened codecs back to their default state */ + dest->priv_data = NULL; + dest->codec = NULL; + dest->palctrl = NULL; + dest->slice_offset = NULL; + dest->internal_buffer = NULL; + dest->hwaccel = NULL; + dest->execute = NULL; + dest->execute2 = NULL; + dest->reget_buffer = NULL; + dest->thread_opaque = NULL; + + /* reallocate values that should be allocated separately */ + dest->rc_eq = NULL; + dest->extradata = NULL; + dest->intra_matrix = NULL; + dest->inter_matrix = NULL; + dest->rc_override = NULL; + if (src->rc_eq) { + dest->rc_eq = av_strdup(src->rc_eq); + if (!dest->rc_eq) + return AVERROR(ENOMEM); + } + +#define alloc_and_copy_or_fail(obj, size, pad) \ + if (src->obj && size > 0) { \ + dest->obj = av_malloc(size + pad); \ + if (!dest->obj) \ + goto fail; \ + memcpy(dest->obj, src->obj, size); \ + if (pad) \ + memset(((uint8_t *) dest->obj) + size, 0, pad); \ + } + alloc_and_copy_or_fail(extradata, src->extradata_size, + FF_INPUT_BUFFER_PADDING_SIZE); + alloc_and_copy_or_fail(intra_matrix, 64 * sizeof(int16_t), 0); + alloc_and_copy_or_fail(inter_matrix, 64 * sizeof(int16_t), 0); + alloc_and_copy_or_fail(rc_override, src->rc_override_count * sizeof(*src->rc_override), 0); +#undef alloc_and_copy_or_fail + + return 0; + +fail: + av_freep(&dest->rc_override); + av_freep(&dest->intra_matrix); + av_freep(&dest->inter_matrix); + av_freep(&dest->extradata); + av_freep(&dest->rc_eq); + return AVERROR(ENOMEM); +}