Adds a new hwaccel flag REUSE_CONTEXT for the user to indicate that this is desired, and adds an additional refcounted state structure hwaccel_priv_persistent which persists across hwaccel reinitialisation and can be used to store context information for reuse. --- doc/APIchanges | 3 +++ libavcodec/avcodec.h | 6 ++++++ libavcodec/decode.c | 15 +++++++++++++-- libavcodec/internal.h | 8 ++++++++ libavcodec/pthread_frame.c | 9 +++++++++ libavcodec/utils.c | 1 + 6 files changed, 40 insertions(+), 2 deletions(-)
diff --git a/doc/APIchanges b/doc/APIchanges index 6de6971fb..6f70f3c96 100644 --- a/doc/APIchanges +++ b/doc/APIchanges @@ -13,6 +13,9 @@ libavutil: 2017-03-23 API changes, most recent first: +2017-xx-xx - xxxxxxx - lavc 58.x+1.0 - avcodec.h + Add AV_HWACCEL_FLAG_REUSE_CONTEXT. + 2017-xx-xx - xxxxxxx - lavfi 7.x+1.0 - avfilter.h Add AVFilterContext.extra_hw_frames. diff --git a/libavcodec/avcodec.h b/libavcodec/avcodec.h index 680a7b5e4..89e432d16 100644 --- a/libavcodec/avcodec.h +++ b/libavcodec/avcodec.h @@ -3058,6 +3058,12 @@ typedef struct AVHWAccel { #define AV_HWACCEL_FLAG_ALLOW_PROFILE_MISMATCH (1 << 2) /** + * Hardware acceleration may reuse an existing context when a stream changes + * but parameters are still compatible. + */ +#define AV_HWACCEL_FLAG_REUSE_CONTEXT (1 << 3) + +/** * @} */ diff --git a/libavcodec/decode.c b/libavcodec/decode.c index 2f4ebd12a..c2cc009ff 100644 --- a/libavcodec/decode.c +++ b/libavcodec/decode.c @@ -672,7 +672,7 @@ static AVHWAccel *find_hwaccel(enum AVCodecID codec_id, static int setup_hwaccel(AVCodecContext *avctx, const enum AVPixelFormat fmt, - const char *name) + const char *name, AVHWAccel *prev_hwaccel) { AVHWAccel *hwa = find_hwaccel(avctx->codec_id, fmt); int ret = 0; @@ -690,6 +690,12 @@ static int setup_hwaccel(AVCodecContext *avctx, return AVERROR(ENOMEM); } + if (hwa != prev_hwaccel) { + // Persistent context only applies to the same hwaccel, so + // unreference it if the hwaccel changes. + av_buffer_unref(&avctx->internal->hwaccel_priv_persistent); + } + avctx->hwaccel = hwa; if (hwa->init) { ret = hwa->init(avctx); @@ -705,6 +711,7 @@ static int setup_hwaccel(AVCodecContext *avctx, int ff_get_format(AVCodecContext *avctx, const enum AVPixelFormat *fmt) { + AVHWAccel *prev_hwaccel; const AVPixFmtDescriptor *desc; enum AVPixelFormat *choices; enum AVPixelFormat ret; @@ -723,9 +730,13 @@ int ff_get_format(AVCodecContext *avctx, const enum AVPixelFormat *fmt) memcpy(choices, fmt, (n + 1) * sizeof(*choices)); + prev_hwaccel = avctx->hwaccel; + for (;;) { if (avctx->hwaccel && avctx->hwaccel->uninit) avctx->hwaccel->uninit(avctx); + if (!(avctx->hwaccel_flags & AV_HWACCEL_FLAG_REUSE_CONTEXT)) + av_buffer_unref(&avctx->internal->hwaccel_priv_persistent); av_freep(&avctx->internal->hwaccel_priv_data); avctx->hwaccel = NULL; @@ -752,7 +763,7 @@ int ff_get_format(AVCodecContext *avctx, const enum AVPixelFormat *fmt) } } - if (!setup_hwaccel(avctx, ret, desc->name)) + if (!setup_hwaccel(avctx, ret, desc->name, prev_hwaccel)) break; /* Remove failed hwaccel from choices */ diff --git a/libavcodec/internal.h b/libavcodec/internal.h index da1b2fa7d..c9f29d913 100644 --- a/libavcodec/internal.h +++ b/libavcodec/internal.h @@ -159,6 +159,14 @@ typedef struct AVCodecInternal { void *hwaccel_priv_data; /** + * Reference to any persistent private data for the current hwaccel. + * + * It will be unreferenced when the context is closed or when the hwaccel + * is changed, but persists across hwaccel uninitialisation. + */ + AVBufferRef *hwaccel_priv_persistent; + + /** * checks API usage: after codec draining, flush is required to resume operation */ int draining; diff --git a/libavcodec/pthread_frame.c b/libavcodec/pthread_frame.c index a72391ba3..90cd8492a 100644 --- a/libavcodec/pthread_frame.c +++ b/libavcodec/pthread_frame.c @@ -256,6 +256,14 @@ static int update_context_from_thread(AVCodecContext *dst, AVCodecContext *src, dst->hwaccel_context = src->hwaccel_context; dst->internal->hwaccel_priv_data = src->internal->hwaccel_priv_data; + av_buffer_unref(&dst->internal->hwaccel_priv_persistent); + if (src->internal->hwaccel_priv_persistent) { + dst->internal->hwaccel_priv_persistent = + av_buffer_ref(src->internal->hwaccel_priv_persistent); + if (!dst->internal->hwaccel_priv_persistent) + return AVERROR(ENOMEM); + } + if (!!dst->hw_frames_ctx != !!src->hw_frames_ctx || (dst->hw_frames_ctx && dst->hw_frames_ctx->data != src->hw_frames_ctx->data)) { av_buffer_unref(&dst->hw_frames_ctx); @@ -634,6 +642,7 @@ void ff_frame_thread_free(AVCodecContext *avctx, int thread_count) av_freep(&p->avctx->slice_offset); } + av_buffer_unref(&p->avctx->internal->hwaccel_priv_persistent); av_buffer_unref(&p->avctx->hw_frames_ctx); av_freep(&p->avctx->internal); diff --git a/libavcodec/utils.c b/libavcodec/utils.c index bc421f67f..e28cdb32d 100644 --- a/libavcodec/utils.c +++ b/libavcodec/utils.c @@ -758,6 +758,7 @@ av_cold int avcodec_close(AVCodecContext *avctx) if (avctx->hwaccel && avctx->hwaccel->uninit) avctx->hwaccel->uninit(avctx); av_freep(&avctx->internal->hwaccel_priv_data); + av_buffer_unref(&avctx->internal->hwaccel_priv_persistent); ff_decode_bsfs_uninit(avctx); -- 2.11.0 _______________________________________________ libav-devel mailing list libav-devel@libav.org https://lists.libav.org/mailman/listinfo/libav-devel