diff --git a/libavcodec/avcodec.h b/libavcodec/avcodec.h index 65c7da4ec9..c76ee04cf5 100644 --- a/libavcodec/avcodec.h +++ b/libavcodec/avcodec.h @@ -2999,6 +2999,29 @@ typedef struct AVHWAccel { * AVCodecContext.release_buffer(). */ int frame_priv_data_size; + + /** + * Initialize the hwaccel private data. + * + * This will be called from ff_get_format(), after hwaccel and + * hwaccel_context are set and the hwaccel private data in AVCodecInternal + * is allocated. + */ + int (*init)(AVCodecContext *avctx); + + /** + * Uninitialize the hwaccel private data. + * + * This will be called from get_format() or avcodec_close(), after hwaccel + * and hwaccel_context are already uninitialized. + */ + int (*uninit)(AVCodecContext *avctx); + + /** + * Size of the private data to allocate in + * AVCodecInternal.hwaccel_priv_data. + */ + int priv_data_size; } AVHWAccel; /** diff --git a/libavcodec/internal.h b/libavcodec/internal.h index 78af94ecc4..6aaaf4c2cb 100644 --- a/libavcodec/internal.h +++ b/libavcodec/internal.h @@ -95,6 +95,11 @@ typedef struct AVCodecInternal { * packet into every function. */ AVPacket *pkt; + + /** + * hwaccel-specific private data + */ + void *hwaccel_priv_data; } AVCodecInternal; struct AVCodecDefault { diff --git a/libavcodec/pthread_frame.c b/libavcodec/pthread_frame.c index ca36be2958..34ca9a6fb7 100644 --- a/libavcodec/pthread_frame.c +++ b/libavcodec/pthread_frame.c @@ -206,6 +206,7 @@ static int update_context_from_thread(AVCodecContext *dst, AVCodecContext *src, dst->hwaccel = src->hwaccel; dst->hwaccel_context = src->hwaccel_context; + dst->internal->hwaccel_priv_data = src->internal->hwaccel_priv_data; } if (for_user) { diff --git a/libavcodec/utils.c b/libavcodec/utils.c index c002c9c4e8..d5c307042e 100644 --- a/libavcodec/utils.c +++ b/libavcodec/utils.c @@ -893,16 +893,37 @@ int ff_get_format(AVCodecContext *avctx, const enum AVPixelFormat *fmt) if (!desc) return AV_PIX_FMT_NONE; + if (avctx->hwaccel && avctx->hwaccel->uninit) + avctx->hwaccel->uninit(avctx); + av_freep(&avctx->internal->hwaccel_priv_data); + avctx->hwaccel = NULL; + if (desc->flags & AV_PIX_FMT_FLAG_HWACCEL) { - avctx->hwaccel = find_hwaccel(avctx->codec_id, ret); - if (!avctx->hwaccel) { + AVHWAccel *hwaccel; + int err; + + hwaccel = find_hwaccel(avctx->codec_id, ret); + if (!hwaccel) { av_log(avctx, AV_LOG_ERROR, "Could not find an AVHWAccel for the pixel format: %s", desc->name); return AV_PIX_FMT_NONE; } - } else { - avctx->hwaccel = NULL; + + if (hwaccel->priv_data_size) { + avctx->internal->hwaccel_priv_data = av_mallocz(hwaccel->priv_data_size); + if (!avctx->internal->hwaccel_priv_data) + return AV_PIX_FMT_NONE; + } + + if (hwaccel->init) { + err = hwaccel->init(avctx); + if (err < 0) { + av_freep(&avctx->internal->hwaccel_priv_data); + return AV_PIX_FMT_NONE; + } + } + avctx->hwaccel = hwaccel; } return ret; @@ -1688,6 +1709,11 @@ av_cold int avcodec_close(AVCodecContext *avctx) for (i = 0; i < FF_ARRAY_ELEMS(pool->pools); i++) av_buffer_pool_uninit(&pool->pools[i]); av_freep(&avctx->internal->pool); + + if (avctx->hwaccel && avctx->hwaccel->uninit) + avctx->hwaccel->uninit(avctx); + av_freep(&avctx->internal->hwaccel_priv_data); + av_freep(&avctx->internal); }