| From 697965857d110810df876d09f96ec17a5aa98e52 Mon Sep 17 00:00:00 2001 |
| From: Fei Wang <fei.w.wang@intel.com> |
| Date: Wed, 2 Nov 2022 16:27:02 +0800 |
| Subject: [PATCH 1/2] lavc: add HWACCEL_CAP_RESET_WITHOUT_UNINIT capacity for |
| hwaccel |
| |
| The capacity can avoid hwaccel being uninited when do the reset. It |
| provides the method for hwaccel if it still want to use the previous |
| initialized configuration after reset. And the configuration can be |
| updated in AVHWAccel.init() if needed. |
| |
| For example, when use vaapi vp9 decode dynamic resolution clips, need |
| to avoid changing vaContext in avctx->internal->hwaccel_priv_data if |
| current frame resolution change and it reference a pervious frame with |
| different resolution. Otherwise reference frame's information bound |
| in vaContext will be lost, then corrupt current frame. |
| |
| Signed-off-by: Fei Wang <fei.w.wang@intel.com> |
| --- |
| libavcodec/decode.c | 10 ++++++---- |
| libavcodec/hwconfig.h | 7 +++++++ |
| 2 files changed, 13 insertions(+), 4 deletions(-) |
| |
| diff --git a/libavcodec/decode.c b/libavcodec/decode.c |
| index 6be2d3d6edf..cfada048e8b 100644 |
| --- a/libavcodec/decode.c |
| +++ b/libavcodec/decode.c |
| @@ -1109,7 +1109,7 @@ static int hwaccel_init(AVCodecContext *avctx, |
| return AVERROR_PATCHWELCOME; |
| } |
| |
| - if (hwaccel->priv_data_size) { |
| + if (hwaccel->priv_data_size && !avctx->internal->hwaccel_priv_data) { |
| avctx->internal->hwaccel_priv_data = |
| av_mallocz(hwaccel->priv_data_size); |
| if (!avctx->internal->hwaccel_priv_data) |
| @@ -1134,10 +1134,12 @@ static int hwaccel_init(AVCodecContext *avctx, |
| |
| static void hwaccel_uninit(AVCodecContext *avctx) |
| { |
| - if (avctx->hwaccel && avctx->hwaccel->uninit) |
| - avctx->hwaccel->uninit(avctx); |
| + if (avctx->hwaccel && !(avctx->hwaccel->caps_internal & HWACCEL_CAP_RESET_WITHOUT_UNINIT)) { |
| + if (avctx->hwaccel->uninit) |
| + avctx->hwaccel->uninit(avctx); |
| |
| - av_freep(&avctx->internal->hwaccel_priv_data); |
| + av_freep(&avctx->internal->hwaccel_priv_data); |
| + } |
| |
| avctx->hwaccel = NULL; |
| |
| diff --git a/libavcodec/hwconfig.h b/libavcodec/hwconfig.h |
| index 721424912c4..5fb4e06d5f8 100644 |
| --- a/libavcodec/hwconfig.h |
| +++ b/libavcodec/hwconfig.h |
| @@ -25,6 +25,13 @@ |
| |
| #define HWACCEL_CAP_ASYNC_SAFE (1 << 0) |
| |
| +/** |
| + * The hwaccel supports reset without calling back AVHWAccel.uninit() |
| + * and realloc avctx->internal->hwaccel_priv_data. |
| + * |
| + * New configuration can set up through AVHWAccel.init(). |
| + */ |
| +#define HWACCEL_CAP_RESET_WITHOUT_UNINIT (1 << 1) |
| |
| typedef struct AVCodecHWConfigInternal { |
| /** |
| |
| From 5ab8ccfa1853b1dc57db5097f7f8df64e989a704 Mon Sep 17 00:00:00 2001 |
| From: Fei Wang <fei.w.wang@intel.com> |
| Date: Wed, 2 Nov 2022 16:49:29 +0800 |
| Subject: [PATCH 2/2] lavc/vaapi_decode: add support for |
| HWACCEL_CAP_RESET_WITHOUT_UNINIT |
| |
| This can fix vp9 decode image corruption when the frame size is change, |
| but the pervious frames still be referenced. |
| |
| Surfaces don't need to be bound to vaContext only after VAAPI 1.0.0: |
| https://github.com/intel/libva/commit/492b692005ccd0d8da190209d5b3ae7b7825f4b8 |
| |
| Signed-off-by: Fei Wang <fei.w.wang@intel.com> |
| --- |
| libavcodec/vaapi_decode.c | 23 +++++++++++++++++++++-- |
| libavcodec/vaapi_decode.h | 1 + |
| libavcodec/vaapi_vp9.c | 4 ++++ |
| 3 files changed, 26 insertions(+), 2 deletions(-) |
| |
| diff --git a/libavcodec/vaapi_decode.c b/libavcodec/vaapi_decode.c |
| index 134f10eca5f..078a8f7806b 100644 |
| --- a/libavcodec/vaapi_decode.c |
| +++ b/libavcodec/vaapi_decode.c |
| @@ -658,8 +658,10 @@ int ff_vaapi_decode_init(AVCodecContext *avctx) |
| VAStatus vas; |
| int err; |
| |
| - ctx->va_config = VA_INVALID_ID; |
| - ctx->va_context = VA_INVALID_ID; |
| + if (!ctx->inited) { |
| + ctx->va_config = VA_INVALID_ID; |
| + ctx->va_context = VA_INVALID_ID; |
| + } |
| |
| err = ff_decode_get_hw_frames_ctx(avctx, AV_HWDEVICE_TYPE_VAAPI); |
| if (err < 0) |
| @@ -670,11 +672,26 @@ int ff_vaapi_decode_init(AVCodecContext *avctx) |
| ctx->device = ctx->frames->device_ctx; |
| ctx->hwctx = ctx->device->hwctx; |
| |
| + if (ctx->va_config != VA_INVALID_ID) |
| + { |
| + vas = vaDestroyConfig(ctx->hwctx->display, ctx->va_config); |
| + if (vas != VA_STATUS_SUCCESS) { |
| + av_log(avctx, AV_LOG_ERROR, "Failed to destroy decode " |
| + "configuration %#x: %d (%s).\n", |
| + ctx->va_config, vas, vaErrorStr(vas)); |
| + err = AVERROR(EIO); |
| + goto fail; |
| + } |
| + } |
| + |
| err = vaapi_decode_make_config(avctx, ctx->frames->device_ref, |
| &ctx->va_config, NULL); |
| if (err) |
| goto fail; |
| |
| + if (ctx->inited) |
| + return 0; |
| + |
| vas = vaCreateContext(ctx->hwctx->display, ctx->va_config, |
| avctx->coded_width, avctx->coded_height, |
| VA_PROGRESSIVE, |
| @@ -691,6 +708,8 @@ int ff_vaapi_decode_init(AVCodecContext *avctx) |
| av_log(avctx, AV_LOG_DEBUG, "Decode context initialised: " |
| "%#x/%#x.\n", ctx->va_config, ctx->va_context); |
| |
| + ctx->inited = 1; |
| + |
| return 0; |
| |
| fail: |
| diff --git a/libavcodec/vaapi_decode.h b/libavcodec/vaapi_decode.h |
| index 6beda14e52e..62a4f37ed92 100644 |
| --- a/libavcodec/vaapi_decode.h |
| +++ b/libavcodec/vaapi_decode.h |
| @@ -61,6 +61,7 @@ typedef struct VAAPIDecodeContext { |
| int surface_count; |
| |
| VASurfaceAttrib pixel_format_attribute; |
| + int inited; |
| } VAAPIDecodeContext; |
| |
| |
| diff --git a/libavcodec/vaapi_vp9.c b/libavcodec/vaapi_vp9.c |
| index 776382f6837..245b7a1b3ab 100644 |
| --- a/libavcodec/vaapi_vp9.c |
| +++ b/libavcodec/vaapi_vp9.c |
| @@ -181,5 +181,9 @@ const AVHWAccel ff_vp9_vaapi_hwaccel = { |
| .uninit = ff_vaapi_decode_uninit, |
| .frame_params = ff_vaapi_common_frame_params, |
| .priv_data_size = sizeof(VAAPIDecodeContext), |
| +#if VA_CHECK_VERSION(1, 0, 0) |
| + .caps_internal = HWACCEL_CAP_ASYNC_SAFE | HWACCEL_CAP_RESET_WITHOUT_UNINIT, |
| +#else |
| .caps_internal = HWACCEL_CAP_ASYNC_SAFE, |
| +#endif |
| }; |