---
Saves the VA config, the frame pool, and the VA context (in that order). The
device reference is held so that freeing the persistent data is possible (the
transient context is already gone when it happens).
libavcodec/vaapi_decode.c | 241 +++++++++++++++++++++++++++++++++-------------
libavcodec/vaapi_decode.h | 18 ++++
2 files changed, 192 insertions(+), 67 deletions(-)
diff --git a/libavcodec/vaapi_decode.c b/libavcodec/vaapi_decode.c
index 847db1a42..52e9b5c3a 100644
--- a/libavcodec/vaapi_decode.c
+++ b/libavcodec/vaapi_decode.c
@@ -273,7 +273,8 @@ static const struct {
static int vaapi_decode_make_config(AVCodecContext *avctx)
{
- VAAPIDecodeContext *ctx = avctx->internal->hwaccel_priv_data;
+ VAAPIDecodeContext *ctx = avctx->internal->hwaccel_priv_data;
+ VAAPIDecodePersistent *pc = NULL;
AVVAAPIHWConfig *hwconfig = NULL;
AVHWFramesConstraints *constraints = NULL;
@@ -359,14 +360,28 @@ static int vaapi_decode_make_config(AVCodecContext *avctx)
ctx->va_profile = profile;
ctx->va_entrypoint = VAEntrypointVLD;
- vas = vaCreateConfig(ctx->hwctx->display, ctx->va_profile,
- ctx->va_entrypoint, NULL, 0,
- &ctx->va_config);
- if (vas != VA_STATUS_SUCCESS) {
- av_log(avctx, AV_LOG_ERROR, "Failed to create decode "
- "configuration: %d (%s).\n", vas, vaErrorStr(vas));
- err = AVERROR(EIO);
- goto fail;
+ if (avctx->internal->hwaccel_priv_persistent) {
+ pc = (VAAPIDecodePersistent*)
+ avctx->internal->hwaccel_priv_persistent->data;
+ }
+ if (pc && pc->va_profile == ctx->va_profile &&
+ pc->va_entrypoint == ctx->va_entrypoint) {
+ av_log(avctx, AV_LOG_DEBUG, "Reusing VA config %#x.\n",
+ pc->va_config);
+ ctx->va_config = pc->va_config;
+ pc->va_config = VA_INVALID_ID;
+ } else {
+ av_buffer_unref(&avctx->internal->hwaccel_priv_persistent);
+
+ vas = vaCreateConfig(ctx->hwctx->display, ctx->va_profile,
+ ctx->va_entrypoint, NULL, 0,
+ &ctx->va_config);
+ if (vas != VA_STATUS_SUCCESS) {
+ av_log(avctx, AV_LOG_ERROR, "Failed to create decode "
+ "configuration: %d (%s).\n", vas, vaErrorStr(vas));
+ err = AVERROR(EIO);
+ goto fail;
+ }
}
hwconfig = av_hwdevice_hwconfig_alloc(avctx->hw_device_ctx ?
@@ -467,9 +482,47 @@ fail:
return err;
}
+static void vaapi_decode_free_persistent(void *opaque, uint8_t *data)
+{
+ AVCodecContext *avctx = opaque;
+ VAAPIDecodePersistent *pc = (VAAPIDecodePersistent*)data;
+ VAStatus vas;
+
+ if (pc->device_ref) {
+ AVHWDeviceContext *device =
+ (AVHWDeviceContext*)pc->device_ref->data;
+ AVVAAPIDeviceContext *hwctx = device->hwctx;
+
+ if (pc->va_context != VA_INVALID_ID) {
+ vas = vaDestroyContext(hwctx->display, pc->va_context);
+ if (vas != VA_STATUS_SUCCESS) {
+ av_log(avctx, AV_LOG_ERROR, "Failed to destroy decode "
+ "context %#x: %d (%s).\n",
+ pc->va_context, vas, vaErrorStr(vas));
+ }
+ }
+
+ av_buffer_unref(&pc->frames_ref);
+
+ if (pc->va_config != VA_INVALID_ID) {
+ vas = vaDestroyConfig(hwctx->display, pc->va_config);
+ if (vas != VA_STATUS_SUCCESS) {
+ av_log(avctx, AV_LOG_ERROR, "Failed to destroy decode "
+ "configuration %#x: %d (%s).\n",
+ pc->va_config, vas, vaErrorStr(vas));
+ }
+ }
+
+ av_buffer_unref(&pc->device_ref);
+ }
+
+ av_free(data);
+}
+
int ff_vaapi_decode_init(AVCodecContext *avctx)
{
- VAAPIDecodeContext *ctx = avctx->internal->hwaccel_priv_data;
+ VAAPIDecodeContext *ctx = avctx->internal->hwaccel_priv_data;
+ VAAPIDecodePersistent *pc = NULL;
VAStatus vas;
int err;
@@ -549,48 +602,78 @@ int ff_vaapi_decode_init(AVCodecContext *avctx)
goto fail;
if (!avctx->hw_frames_ctx) {
- avctx->hw_frames_ctx = av_hwframe_ctx_alloc(avctx->hw_device_ctx);
- if (!avctx->hw_frames_ctx) {
- err = AVERROR(ENOMEM);
- goto fail;
+ if (avctx->internal->hwaccel_priv_persistent) {
+ pc = (VAAPIDecodePersistent*)
+ avctx->internal->hwaccel_priv_persistent->data;
}
- ctx->frames = (AVHWFramesContext*)avctx->hw_frames_ctx->data;
+ if (pc &&
+ pc->surface_width == avctx->coded_width &&
+ pc->surface_height == avctx->coded_height &&
+ pc->surface_format == ctx->surface_format &&
+ pc->surface_count == ctx->surface_count) {
+ av_log(avctx, AV_LOG_DEBUG, "Reusing hardware frames context "
+ "(%dx%d, %d surfaces of type %s).\n",
+ pc->surface_width, pc->surface_height, pc->surface_count,
+ av_get_pix_fmt_name(pc->surface_format));
+
+ avctx->hw_frames_ctx = pc->frames_ref;
+ pc->frames_ref = NULL;
+
+ ctx->frames = (AVHWFramesContext*)avctx->hw_frames_ctx->data;
+ } else {
+ av_buffer_unref(&avctx->internal->hwaccel_priv_persistent);
+ pc = NULL;
- ctx->frames->format = AV_PIX_FMT_VAAPI;
- ctx->frames->width = avctx->coded_width;
- ctx->frames->height = avctx->coded_height;
+ avctx->hw_frames_ctx = av_hwframe_ctx_alloc(avctx->hw_device_ctx);
+ if (!avctx->hw_frames_ctx) {
+ err = AVERROR(ENOMEM);
+ goto fail;
+ }
+ ctx->frames = (AVHWFramesContext*)avctx->hw_frames_ctx->data;
- ctx->frames->sw_format = ctx->surface_format;
- ctx->frames->initial_pool_size = ctx->surface_count;
+ ctx->frames->format = AV_PIX_FMT_VAAPI;
+ ctx->frames->width = avctx->coded_width;
+ ctx->frames->height = avctx->coded_height;
- err = ff_init_hw_frames(avctx);
- if (err < 0) {
- av_log(avctx, AV_LOG_ERROR, "User initialisation of internal "
- "frames context failed: %d.\n", err);
- goto fail;
- }
+ ctx->frames->sw_format = ctx->surface_format;
+ ctx->frames->initial_pool_size = ctx->surface_count;
- err = av_hwframe_ctx_init(avctx->hw_frames_ctx);
- if (err < 0) {
- av_log(avctx, AV_LOG_ERROR, "Failed to initialise internal "
- "frames context: %d.\n", err);
- goto fail;
+ err = ff_init_hw_frames(avctx);
+ if (err < 0) {
+ av_log(avctx, AV_LOG_ERROR, "User initialisation of internal "
+ "frames context failed: %d.\n", err);
+ goto fail;
+ }
+
+ err = av_hwframe_ctx_init(avctx->hw_frames_ctx);
+ if (err < 0) {
+ av_log(avctx, AV_LOG_ERROR, "Failed to initialise internal "
+ "frames context: %d.\n", err);
+ goto fail;
+ }
}
ctx->hwfc = ctx->frames->hwctx;
}
- vas = vaCreateContext(ctx->hwctx->display, ctx->va_config,
- avctx->coded_width, avctx->coded_height,
- VA_PROGRESSIVE,
- ctx->hwfc->surface_ids,
- ctx->hwfc->nb_surfaces,
- &ctx->va_context);
- if (vas != VA_STATUS_SUCCESS) {
- av_log(avctx, AV_LOG_ERROR, "Failed to create decode "
- "context: %d (%s).\n", vas, vaErrorStr(vas));
- err = AVERROR(EIO);
- goto fail;
+ if (pc) {
+ av_log(avctx, AV_LOG_DEBUG, "Reusing VA context %#x.\n",
+ pc->va_context);
+ ctx->va_context = pc->va_context;
+ pc->va_context = VA_INVALID_ID;
+ } else {
+ vas = vaCreateContext(ctx->hwctx->display, ctx->va_config,
+ avctx->coded_width, avctx->coded_height,
+ VA_PROGRESSIVE,
+ ctx->hwfc->surface_ids,
+ ctx->hwfc->nb_surfaces,
+ &ctx->va_context);
+ if (vas != VA_STATUS_SUCCESS) {
+ av_log(avctx, AV_LOG_ERROR, "Failed to create decode "
+ "context: %d (%s).\n", vas, vaErrorStr(vas));
+ err = AVERROR(EIO);
+ goto fail;
+ }
}
av_log(avctx, AV_LOG_DEBUG, "Decode context initialised: "
@@ -599,6 +682,53 @@ int ff_vaapi_decode_init(AVCodecContext *avctx)
}
#endif
+ av_buffer_unref(&avctx->internal->hwaccel_priv_persistent);
+ if (avctx->hwaccel_flags & AV_HWACCEL_FLAG_REUSE_CONTEXT) {
+ AVBufferRef *pc_ref;
+
+ pc = av_mallocz(sizeof(*pc));
+ if (!pc) {
+ err = AVERROR(ENOMEM);
+ goto fail;
+ }
+
+ pc_ref = av_buffer_create((uint8_t*)pc, sizeof(*pc),
+ &vaapi_decode_free_persistent,
+ avctx, 0);
+ if (!pc_ref) {
+ av_free(pc);
+ err = AVERROR(ENOMEM);
+ goto fail;
+ }
+ pc = (VAAPIDecodePersistent*)pc_ref->data;
+
+ pc->device_ref = av_buffer_ref(ctx->frames->device_ref);
+ if (!pc->device_ref) {
+ av_buffer_unref(&pc_ref);
+ err = AVERROR(ENOMEM);
+ goto fail;
+ }
+
+ pc->va_profile = ctx->va_profile;
+ pc->va_entrypoint = ctx->va_entrypoint;
+ pc->va_config = ctx->va_config;
+ pc->va_context = ctx->va_context;
+
+ pc->frames_ref = av_buffer_ref(avctx->hw_frames_ctx);
+ if (!pc->frames_ref) {
+ av_buffer_unref(&pc_ref);
+ err = AVERROR(ENOMEM);
+ goto fail;
+ }
+
+ pc->surface_width = avctx->coded_width;
+ pc->surface_height = avctx->coded_height;
+ pc->surface_format = ctx->surface_format;
+ pc->surface_count = ctx->surface_count;
+
+ avctx->internal->hwaccel_priv_persistent = pc_ref;
+ }
+
return 0;
fail:
@@ -608,34 +738,11 @@ fail:
int ff_vaapi_decode_uninit(AVCodecContext *avctx)
{
+#if FF_API_VAAPI_CONTEXT
VAAPIDecodeContext *ctx = avctx->internal->hwaccel_priv_data;
- VAStatus vas;
-#if FF_API_VAAPI_CONTEXT
- if (ctx->have_old_context) {
+ if (ctx->have_old_context)
av_buffer_unref(&ctx->device_ref);
- } else {
-#endif
-
- if (ctx->va_context != VA_INVALID_ID) {
- vas = vaDestroyContext(ctx->hwctx->display, ctx->va_context);
- if (vas != VA_STATUS_SUCCESS) {
- av_log(avctx, AV_LOG_ERROR, "Failed to destroy decode "
- "context %#x: %d (%s).\n",
- ctx->va_context, vas, vaErrorStr(vas));
- }
- }
- 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));
- }
- }
-
-#if FF_API_VAAPI_CONTEXT
- }
#endif
return 0;
diff --git a/libavcodec/vaapi_decode.h b/libavcodec/vaapi_decode.h
index 0ff400e34..baa93db97 100644
--- a/libavcodec/vaapi_decode.h
+++ b/libavcodec/vaapi_decode.h
@@ -74,6 +74,24 @@ typedef struct VAAPIDecodeContext {
int surface_count;
} VAAPIDecodeContext;
+typedef struct VAAPIDecodePersistent {
+ AVBufferRef *device_ref;
+
+ VAProfile va_profile;
+ VAEntrypoint va_entrypoint;
+ VAConfigID va_config;
+ VAContextID va_context;
+
+ AVBufferRef *frames_ref;
+
+ // Hardware frame properties used at creation - we may reuse
+ // frames_ref if these are all identical in the new context.
+ int surface_width;
+ int surface_height;
+ enum AVPixelFormat surface_format;
+ int surface_count;
+} VAAPIDecodePersistent;
+
int ff_vaapi_decode_make_param_buffer(AVCodecContext *avctx,
VAAPIDecodePicture *pic,
--
2.11.0
_______________________________________________
libav-devel mailing list
[email protected]
https://lists.libav.org/mailman/listinfo/libav-devel