Moves much of the setup logic for VAAPI decoding into lavc; the user
now need only provide the hw_frames_ctx.
Also deprecates struct vaapi_context and installed header vaapi.h
which contains it, while continuing to support it in the new code.
---
I've ducked the interlacing problem by allowing the picture structure to be
reused. I don't think there is a better way to fix it (it really is the same
picture, we just render twice to it).
Still wondering whether we want an "ignore capabilities" flag somehow.
Tested with i965 (Skylake) and mesa/gallium (Bonaire).
doc/APIchanges | 3 +
libavcodec/Makefile | 5 +-
libavcodec/vaapi_decode.c | 602 ++++++++++++++++++++++++++++++++++++++++++++++
libavcodec/vaapi_decode.h | 97 ++++++++
libavcodec/version.h | 5 +-
5 files changed, 709 insertions(+), 3 deletions(-)
create mode 100644 libavcodec/vaapi_decode.c
create mode 100644 libavcodec/vaapi_decode.h
diff --git a/doc/APIchanges b/doc/APIchanges
index 1b65c4b..74f65f2 100644
--- a/doc/APIchanges
+++ b/doc/APIchanges
@@ -13,6 +13,9 @@ libavutil: 2015-08-28
API changes, most recent first:
+2016-xx-xx - xxxxxxx - lavc 59.26.0 - vaapi.h
+ Deprecate struct vaapi_context and the vaapi.h installed header.
+
2016-07-20 - xxxxxxx - lavu 55.20.0 - cpu.h
Add AV_CPU_FLAG_SSSE3SLOW.
diff --git a/libavcodec/Makefile b/libavcodec/Makefile
index 8eb7d36..4d04d6a 100644
--- a/libavcodec/Makefile
+++ b/libavcodec/Makefile
@@ -610,7 +610,7 @@ OBJS-$(CONFIG_ADPCM_YAMAHA_ENCODER) += adpcmenc.o
adpcm_data.o
# hardware accelerators
OBJS-$(CONFIG_D3D11VA) += dxva2.o
OBJS-$(CONFIG_DXVA2) += dxva2.o
-OBJS-$(CONFIG_VAAPI) += vaapi.o
+OBJS-$(CONFIG_VAAPI) += vaapi.o vaapi_decode.o
OBJS-$(CONFIG_VDA) += vda.o
OBJS-$(CONFIG_VDPAU) += vdpau.o
@@ -777,7 +777,8 @@ SKIPHEADERS-$(CONFIG_NVENC) += nvenc.h
SKIPHEADERS-$(CONFIG_QSV) += qsv.h qsv_internal.h
SKIPHEADERS-$(CONFIG_QSVDEC) += qsvdec.h
SKIPHEADERS-$(CONFIG_QSVENC) += qsvenc.h
-SKIPHEADERS-$(CONFIG_VAAPI) += vaapi_encode.h vaapi_internal.h
+SKIPHEADERS-$(CONFIG_VAAPI) += vaapi_decode.h vaapi_encode.h \
+ vaapi_internal.h
SKIPHEADERS-$(CONFIG_VDA) += vda.h vda_internal.h
SKIPHEADERS-$(CONFIG_VDPAU) += vdpau.h vdpau_internal.h
diff --git a/libavcodec/vaapi_decode.c b/libavcodec/vaapi_decode.c
new file mode 100644
index 0000000..0ccdff3
--- /dev/null
+++ b/libavcodec/vaapi_decode.c
@@ -0,0 +1,602 @@
+/*
+ * This file is part of Libav.
+ *
+ * Libav is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * Libav is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with Libav; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "libavutil/avassert.h"
+#include "libavutil/common.h"
+
+#include "avcodec.h"
+#include "internal.h"
+#include "vaapi_decode.h"
+
+
+void *ff_vaapi_decode_alloc_param_buffer(AVCodecContext *avctx,
+ VAAPIDecodePicture *pic,
+ int type, size_t size)
+{
+ VAAPIDecodeContext *ctx = avctx->internal->hwaccel_priv_data;
+ VAStatus vas;
+ VABufferID buffer;
+ void *addr;
+
+ av_assert0(pic->nb_param_buffers + 1 <= MAX_PARAM_BUFFERS);
+
+ vas = vaCreateBuffer(ctx->hwctx->display, ctx->va_context,
+ type, size, 1, NULL, &buffer);
+ if (vas != VA_STATUS_SUCCESS) {
+ av_log(avctx, AV_LOG_ERROR, "Failed to create parameter "
+ "buffer (type %d): %d (%s).\n",
+ type, vas, vaErrorStr(vas));
+ return NULL;
+ }
+
+ vas = vaMapBuffer(ctx->hwctx->display, buffer, &addr);
+ if (vas != VA_STATUS_SUCCESS) {
+ av_log(avctx, AV_LOG_ERROR, "Failed to map parameter "
+ "buffer (%#x, type %d): %d (%s).\n",
+ buffer, type, vas, vaErrorStr(vas));
+ vaDestroyBuffer(ctx->hwctx->display, buffer);
+ return NULL;
+ }
+
+ pic->param_buffers[pic->nb_param_buffers++] = buffer;
+
+ av_log(avctx, AV_LOG_DEBUG, "Param buffer (type %d, %zu bytes) "
+ "is %#x.\n", type, size, buffer);
+ return addr;
+}
+
+void *ff_vaapi_decode_alloc_slice_buffer(AVCodecContext *avctx,
+ VAAPIDecodePicture *pic,
+ size_t params_size,
+ const void *slice_data,
+ size_t data_size)
+{
+ VAAPIDecodeContext *ctx = avctx->internal->hwaccel_priv_data;
+ VAAPIDecodeSlice *slice = NULL;
+ VAStatus vas;
+ void *addr = NULL;
+ VASliceParameterBufferBase *slice_param;
+
+ if (pic->nb_slices == pic->slices_allocated) {
+ if (pic->slices_allocated > 0)
+ pic->slices_allocated *= 2;
+ else
+ pic->slices_allocated = 64;
+
+ pic->slices = av_realloc_array(pic->slices,
+ pic->slices_allocated,
+ sizeof(*pic->slices));
+ if (!pic->slices)
+ return NULL;
+ }
+
+ av_assert0(pic->nb_slices < pic->slices_allocated);
+ slice = &pic->slices[pic->nb_slices];
+ slice->param_buffer = VA_INVALID_ID;
+ slice->data_buffer = VA_INVALID_ID;
+
+ vas = vaCreateBuffer(ctx->hwctx->display, ctx->va_context,
+ VASliceParameterBufferType, params_size,
+ 1, NULL, &slice->param_buffer);
+ if (vas != VA_STATUS_SUCCESS) {
+ av_log(avctx, AV_LOG_ERROR, "Failed to create slice "
+ "parameter buffer: %d (%s).\n", vas, vaErrorStr(vas));
+ goto fail;
+ }
+
+ av_log(avctx, AV_LOG_DEBUG, "Slice %d param buffer (%zu bytes) "
+ "is %#x.\n", pic->nb_slices, params_size,
+ slice->param_buffer);
+
+ vas = vaCreateBuffer(ctx->hwctx->display, ctx->va_context,
+ VASliceDataBufferType, data_size,
+ 1, (void*)slice_data, &slice->data_buffer);
+ if (vas != VA_STATUS_SUCCESS) {
+ av_log(avctx, AV_LOG_ERROR, "Failed to create slice "
+ "data buffer (size %zu): %d (%s).\n",
+ data_size, vas, vaErrorStr(vas));
+ goto fail;
+ }
+
+ av_log(avctx, AV_LOG_DEBUG, "Slice %d data buffer (%zu bytes) "
+ "is %#x.\n", pic->nb_slices, data_size,
+ slice->data_buffer);
+
+ vas = vaMapBuffer(ctx->hwctx->display,
+ slice->param_buffer, &addr);
+ if (vas != VA_STATUS_SUCCESS) {
+ av_log(avctx, AV_LOG_ERROR, "Failed to map slice parameter "
+ "buffer: %d (%s).\n", vas, vaErrorStr(vas));
+ goto fail;
+ }
+
+ slice_param = addr;
+ slice_param->slice_data_size = data_size;
+ slice_param->slice_data_offset = 0;
+ slice_param->slice_data_flag = VA_SLICE_DATA_FLAG_ALL;
+
+ ++pic->nb_slices;
+
+ return addr;
+
+fail:
+ if (slice) {
+ if (addr)
+ vaUnmapBuffer(ctx->hwctx->display,
+ slice->param_buffer);
+ if (slice->param_buffer != VA_INVALID_ID)
+ vaDestroyBuffer(ctx->hwctx->display,
+ slice->param_buffer);
+ if (slice->data_buffer != VA_INVALID_ID)
+ vaDestroyBuffer(ctx->hwctx->display,
+ slice->data_buffer);
+ }
+ return NULL;
+}
+
+static void ff_vaapi_decode_destroy_buffers(AVCodecContext *avctx,
+ VAAPIDecodePicture *pic)
+{
+ VAAPIDecodeContext *ctx = avctx->internal->hwaccel_priv_data;
+ VAStatus vas;
+ int i;
+
+ for (i = 0; i < pic->nb_param_buffers; i++) {
+ vas = vaDestroyBuffer(ctx->hwctx->display,
+ pic->param_buffers[i]);
+ if (vas != VA_STATUS_SUCCESS) {
+ av_log(avctx, AV_LOG_ERROR, "Failed to destroy "
+ "parameter buffer %#x: %d (%s).\n",
+ pic->param_buffers[i], vas, vaErrorStr(vas));
+ }
+ }
+
+ for (i = 0; i < pic->nb_slices; i++) {
+ VAAPIDecodeSlice *slice = &pic->slices[i];
+
+ vas = vaDestroyBuffer(ctx->hwctx->display,
+ slice->param_buffer);
+ if (vas != VA_STATUS_SUCCESS) {
+ av_log(avctx, AV_LOG_ERROR, "Failed to destroy slice %d "
+ "parameter buffer %#x: %d (%s).\n",
+ i, slice->param_buffer, vas, vaErrorStr(vas));
+ }
+
+ vas = vaDestroyBuffer(ctx->hwctx->display,
+ slice->data_buffer);
+ if (vas != VA_STATUS_SUCCESS) {
+ av_log(avctx, AV_LOG_ERROR, "Failed to destroy slice %d "
+ "data buffer %#x: %d (%s).\n",
+ i, slice->data_buffer, vas, vaErrorStr(vas));
+ }
+ }
+}
+
+int ff_vaapi_decode_issue(AVCodecContext *avctx,
+ VAAPIDecodePicture *pic)
+{
+ VAAPIDecodeContext *ctx = avctx->internal->hwaccel_priv_data;
+ VAStatus vas;
+ int err, i;
+
+ av_log(avctx, AV_LOG_DEBUG, "Decode to surface %#x.\n",
+ pic->output_surface);
+
+ for (i = 0; i < pic->nb_param_buffers; i++)
+ vaUnmapBuffer(ctx->hwctx->display, pic->param_buffers[i]);
+
+ vas = vaBeginPicture(ctx->hwctx->display, ctx->va_context,
+ pic->output_surface);
+ if (vas != VA_STATUS_SUCCESS) {
+ av_log(avctx, AV_LOG_ERROR, "Failed to begin picture decode "
+ "issue: %d (%s).\n", vas, vaErrorStr(vas));
+ err = AVERROR(EIO);
+ goto fail_with_picture;
+ }
+
+ vas = vaRenderPicture(ctx->hwctx->display, ctx->va_context,
+ pic->param_buffers, pic->nb_param_buffers);
+ if (vas != VA_STATUS_SUCCESS) {
+ av_log(avctx, AV_LOG_ERROR, "Failed to upload decode "
+ "parameters: %d (%s).\n", vas, vaErrorStr(vas));
+ err = AVERROR(EIO);
+ goto fail_with_picture;
+ }
+
+ for (i = 0; i < pic->nb_slices; i++) {
+ VAAPIDecodeSlice *slice = &pic->slices[i];
+
+ vas = vaUnmapBuffer(ctx->hwctx->display, slice->param_buffer);
+ if (vas != VA_STATUS_SUCCESS) {
+ av_log(avctx, AV_LOG_ERROR, "Failed to unmap slice %d "
+ "parameters: %d (%s).\n", i, vas, vaErrorStr(vas));
+ }
+
+ vas = vaRenderPicture(ctx->hwctx->display, ctx->va_context,
+ &slice->param_buffer, 1);
+ if (vas != VA_STATUS_SUCCESS) {
+ av_log(avctx, AV_LOG_ERROR, "Failed to upload slice %d "
+ "parameters: %d (%s).\n", i, vas, vaErrorStr(vas));
+ err = AVERROR(EIO);
+ goto fail_with_picture;
+ }
+
+ vas = vaRenderPicture(ctx->hwctx->display, ctx->va_context,
+ &slice->data_buffer, 1);
+ if (vas != VA_STATUS_SUCCESS) {
+ av_log(avctx, AV_LOG_ERROR, "Failed to upload slice %d "
+ "data: %d (%s).\n", i, vas, vaErrorStr(vas));
+ err = AVERROR(EIO);
+ goto fail_with_picture;
+ }
+ }
+
+ vas = vaEndPicture(ctx->hwctx->display, ctx->va_context);
+ if (vas != VA_STATUS_SUCCESS) {
+ av_log(avctx, AV_LOG_ERROR, "Failed to end picture decode "
+ "issue: %d (%s).\n", vas, vaErrorStr(vas));
+ err = AVERROR(EIO);
+ if (ctx->hwctx->driver_quirks &
+ AV_VAAPI_DRIVER_QUIRK_RENDER_PARAM_BUFFERS)
+ goto fail;
+ else
+ goto fail_at_end;
+ }
+
+ if (ctx->hwctx->driver_quirks &
+ AV_VAAPI_DRIVER_QUIRK_RENDER_PARAM_BUFFERS)
+ ff_vaapi_decode_destroy_buffers(avctx, pic);
+
+ pic->nb_param_buffers = 0;
+ pic->nb_slices = 0;
+ pic->slices_allocated = 0;
+ av_freep(&pic->slices);
+
+ return 0;
+
+fail_with_picture:
+ vas = vaEndPicture(ctx->hwctx->display, ctx->va_context);
+ if (vas != VA_STATUS_SUCCESS) {
+ av_log(avctx, AV_LOG_ERROR, "Failed to end picture decode "
+ "after error: %d (%s).\n", vas, vaErrorStr(vas));
+ }
+fail:
+ ff_vaapi_decode_destroy_buffers(avctx, pic);
+fail_at_end:
+ return err;
+}
+
+int ff_vaapi_decode_cancel(AVCodecContext *avctx,
+ VAAPIDecodePicture *pic)
+{
+ ff_vaapi_decode_destroy_buffers(avctx, pic);
+
+ pic->nb_param_buffers = 0;
+ pic->nb_slices = 0;
+ pic->slices_allocated = 0;
+ av_freep(&pic->slices);
+
+ return 0;
+}
+
+static const struct {
+ enum AVCodecID codec_id;
+ int codec_profile;
+ VAProfile va_profile;
+} vaapi_profile_map[] = {
+#define MAP(c, p, v) { AV_CODEC_ID_ ## c, FF_PROFILE_ ## p, VAProfile ## v }
+ MAP(MPEG2VIDEO, MPEG2_SIMPLE, MPEG2Simple ),
+ MAP(MPEG2VIDEO, MPEG2_MAIN, MPEG2Main ),
+ MAP(H263, UNKNOWN, H263Baseline),
+ MAP(MPEG4, MPEG4_SIMPLE, MPEG4Simple ),
+ MAP(MPEG4, MPEG4_ADVANCED_SIMPLE,
+ MPEG4AdvancedSimple),
+ MAP(MPEG4, MPEG4_MAIN, MPEG4Main ),
+ MAP(H264, H264_CONSTRAINED_BASELINE,
+ H264ConstrainedBaseline),
+ MAP(H264, H264_BASELINE, H264Baseline),
+ MAP(H264, H264_MAIN, H264Main ),
+ MAP(H264, H264_HIGH, H264High ),
+#if VA_CHECK_VERSION(0, 37, 0)
+ MAP(HEVC, HEVC_MAIN, HEVCMain ),
+#endif
+ MAP(WMV3, VC1_SIMPLE, VC1Simple ),
+ MAP(WMV3, VC1_MAIN, VC1Main ),
+ MAP(WMV3, VC1_COMPLEX, VC1Advanced ),
+ MAP(WMV3, VC1_ADVANCED, VC1Advanced ),
+ MAP(VC1, VC1_SIMPLE, VC1Simple ),
+ MAP(VC1, VC1_MAIN, VC1Main ),
+ MAP(VC1, VC1_COMPLEX, VC1Advanced ),
+ MAP(VC1, VC1_ADVANCED, VC1Advanced ),
+#if VA_CHECK_VERSION(0, 35, 0)
+ MAP(VP8, UNKNOWN, VP8Version0_3 ),
+#endif
+#if VA_CHECK_VERSION(0, 37, 1)
+ MAP(VP9, VP9_0, VP9Profile0 ),
+#endif
+#undef MAP
+};
+
+static int vaapi_decode_make_config(AVCodecContext *avctx)
+{
+ VAAPIDecodeContext *ctx = avctx->internal->hwaccel_priv_data;
+
+ AVVAAPIHWConfig *hwconfig = NULL;
+ AVHWFramesConstraints *constraints = NULL;
+ VAStatus vas;
+ int err, i, j;
+ const AVCodecDescriptor *codec_desc;
+ VAProfile profile, *profile_list = NULL;
+ int profile_count, exact_match, alt_profile;
+
+ // Set by AV_HWACCEL_FLAG_IGNORE_PROFILE, or something?
+ int allow_profile_mismatch = 0;
+
+ codec_desc = avcodec_descriptor_get(avctx->codec_id);
+ if (!codec_desc) {
+ err = AVERROR(EINVAL);
+ goto fail;
+ }
+
+ profile_count = vaMaxNumProfiles(ctx->hwctx->display);
+ profile_list = av_malloc_array(profile_count,
+ sizeof(VAProfile));
+ if (!profile_list) {
+ err = AVERROR(ENOMEM);
+ goto fail;
+ }
+
+ vas = vaQueryConfigProfiles(ctx->hwctx->display,
+ profile_list, &profile_count);
+ if (vas != VA_STATUS_SUCCESS) {
+ av_log(ctx, AV_LOG_ERROR, "Failed to query profiles: "
+ "%d (%s).\n", vas, vaErrorStr(vas));
+ err = AVERROR(ENOSYS);
+ goto fail;
+ }
+
+ profile = VAProfileNone;
+ exact_match = 0;
+
+ for (i = 0; i < FF_ARRAY_ELEMS(vaapi_profile_map); i++) {
+ int profile_match = 0;
+ if (avctx->codec_id != vaapi_profile_map[i].codec_id)
+ continue;
+ if (avctx->profile == vaapi_profile_map[i].codec_profile)
+ profile_match = 1;
+ profile = vaapi_profile_map[i].va_profile;
+ for (j = 0; j < profile_count; j++) {
+ if (profile == profile_list[j]) {
+ exact_match = profile_match;
+ break;
+ }
+ }
+ if (j < profile_count) {
+ if (exact_match)
+ break;
+ alt_profile = vaapi_profile_map[i].codec_profile;
+ }
+ }
+ av_freep(&profile_list);
+
+ if (profile == VAProfileNone) {
+ av_log(ctx, AV_LOG_ERROR, "No support for codec %s "
+ "profile %d.\n", codec_desc->name, avctx->profile);
+ err = AVERROR(ENOSYS);
+ goto fail;
+ }
+ if (!exact_match) {
+ if (allow_profile_mismatch) {
+ av_log(avctx, AV_LOG_VERBOSE, "Codec %s profile %d not "
+ "supported for hardware decode.\n",
+ codec_desc->name, avctx->profile);
+ av_log(avctx, AV_LOG_WARNING, "Using possibly-"
+ "incompatible profile %d instead.\n",
+ alt_profile);
+ } else {
+ av_log(avctx, AV_LOG_VERBOSE, "Codec %s profile %d not "
+ "supported for hardware decode.\n",
+ codec_desc->name, avctx->profile);
+ err = AVERROR(EINVAL);
+ goto fail;
+ }
+ }
+
+ 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;
+ }
+
+ hwconfig = av_hwdevice_hwconfig_alloc(ctx->frames->device_ref);
+ if (!hwconfig) {
+ err = AVERROR(ENOMEM);
+ goto fail;
+ }
+ hwconfig->config_id = ctx->va_config;
+
+ constraints =
+ av_hwdevice_get_hwframe_constraints(ctx->frames->device_ref,
+ hwconfig);
+ if (!constraints) {
+ // Ignore.
+ } else {
+ if (avctx->coded_width < constraints->min_width ||
+ avctx->coded_height < constraints->min_height ||
+ avctx->coded_width > constraints->max_width ||
+ avctx->coded_height >constraints->max_height) {
+ av_log(ctx, AV_LOG_ERROR, "Hardware does not support image "
+ "size %dx%d (constraints: width %d-%d height %d-%d).\n",
+ avctx->coded_width, avctx->coded_height,
+ constraints->min_width, constraints->max_width,
+ constraints->min_height, constraints->max_height);
+ err = AVERROR(EINVAL);
+ goto fail;
+ }
+ }
+
+ av_hwframe_constraints_free(&constraints);
+ av_freep(&hwconfig);
+
+ return 0;
+
+fail:
+ av_hwframe_constraints_free(&constraints);
+ av_freep(&hwconfig);
+ if (ctx->va_config != VA_INVALID_ID) {
+ vaDestroyConfig(ctx->hwctx->display, ctx->va_config);
+ ctx->va_config = VA_INVALID_ID;
+ }
+ av_freep(&profile_list);
+ return err;
+}
+
+int ff_vaapi_decode_init(AVCodecContext *avctx)
+{
+ VAAPIDecodeContext *ctx = avctx->internal->hwaccel_priv_data;
+ VAStatus vas;
+ int err;
+
+ ctx->va_config = VA_INVALID_ID;
+ ctx->va_context = VA_INVALID_ID;
+
+#if FF_API_VAAPI_CONTEXT
+ if (avctx->hwaccel_context) {
+ static int warned = 0;
+ if (!warned) {
+ av_log(avctx, AV_LOG_WARNING, "Using deprecated struct "
+ "vaapi_context in decode.\n");
+ warned = 1;
+ }
+
+ ctx->have_old_context = 1;
+ ctx->old_context = avctx->hwaccel_context;
+
+ ctx->hwctx = av_malloc(sizeof(*ctx->hwctx));
+ if (!ctx->hwctx) {
+ err = AVERROR(ENOMEM);
+ goto fail;
+ }
+
+ ctx->hwctx->display = ctx->old_context->display;
+
+ // The old VAAPI decode setup assumed this quirk was always
+ // present, so set it here to avoid the behaviour changing.
+ ctx->hwctx->driver_quirks =
+ AV_VAAPI_DRIVER_QUIRK_RENDER_PARAM_BUFFERS;
+
+ } else
+#endif
+ if (avctx->hw_frames_ctx) {
+ // Should we actually make separate references to the hw
+ // frames and device contexts here?
+
+ ctx->frames = (AVHWFramesContext*)avctx->hw_frames_ctx->data;
+ ctx->hwfc = ctx->frames->hwctx;
+
+ ctx->device = ctx->frames->device_ctx;
+ ctx->hwctx = ctx->device->hwctx;
+
+ } else {
+ av_log(avctx, AV_LOG_ERROR, "A hardware frames context is "
+ "required for VAAPI decoding.\n");
+ err = AVERROR(EINVAL);
+ goto fail;
+ }
+
+#if FF_API_VAAPI_CONTEXT
+ if (ctx->have_old_context) {
+ ctx->va_config = ctx->old_context->config_id;
+ ctx->va_context = ctx->old_context->context_id;
+
+ av_log(avctx, AV_LOG_DEBUG, "Using user-supplied decoder "
+ "context: %#x/%#x.\n", ctx->va_config, ctx->va_context);
+ } else {
+#endif
+
+ err = vaapi_decode_make_config(avctx);
+ if (err)
+ goto fail;
+
+ 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: "
+ "%#x/%#x.\n", ctx->va_config, ctx->va_context);
+#if FF_API_VAAPI_CONTEXT
+ }
+#endif
+
+ return 0;
+
+fail:
+ ff_vaapi_decode_uninit(avctx);
+ return err;
+}
+
+int ff_vaapi_decode_uninit(AVCodecContext *avctx)
+{
+ VAAPIDecodeContext *ctx = avctx->internal->hwaccel_priv_data;
+ VAStatus vas;
+
+#if FF_API_VAAPI_CONTEXT
+ if (ctx->have_old_context) {
+ av_freep(&ctx->hwctx);
+ } 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
new file mode 100644
index 0000000..b9dc489
--- /dev/null
+++ b/libavcodec/vaapi_decode.h
@@ -0,0 +1,97 @@
+/*
+ * This file is part of Libav.
+ *
+ * Libav is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * Libav is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with Libav; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef AVCODEC_VAAPI_DECODE_H
+#define AVCODEC_VAAPI_DECODE_H
+
+#include <va/va.h>
+
+#include "libavutil/frame.h"
+#include "libavutil/hwcontext.h"
+#include "libavutil/hwcontext_vaapi.h"
+
+#include "avcodec.h"
+#include "version.h"
+
+#if FF_API_VAAPI_CONTEXT
+#include "vaapi.h"
+#endif
+
+static inline VASurfaceID ff_vaapi_get_surface_id(AVFrame *pic)
+{
+ return (uintptr_t)pic->data[3];
+}
+
+enum {
+ MAX_PARAM_BUFFERS = 16,
+};
+
+typedef struct VAAPIDecodeSlice {
+ VABufferID param_buffer;
+ VABufferID data_buffer;
+} VAAPIDecodeSlice;
+
+typedef struct VAAPIDecodePicture {
+ VASurfaceID output_surface;
+
+ int nb_param_buffers;
+ VABufferID param_buffers[MAX_PARAM_BUFFERS];
+
+ int nb_slices;
+ VAAPIDecodeSlice *slices;
+ int slices_allocated;
+} VAAPIDecodePicture;
+
+typedef struct VAAPIDecodeContext {
+ VAProfile va_profile;
+ VAEntrypoint va_entrypoint;
+ VAConfigID va_config;
+ VAContextID va_context;
+
+#if FF_API_VAAPI_CONTEXT
+ int have_old_context;
+ struct vaapi_context *old_context;
+#endif
+
+ AVHWDeviceContext *device;
+ AVVAAPIDeviceContext *hwctx;
+
+ AVHWFramesContext *frames;
+ AVVAAPIFramesContext *hwfc;
+} VAAPIDecodeContext;
+
+
+void *ff_vaapi_decode_alloc_param_buffer(AVCodecContext *avctx,
+ VAAPIDecodePicture *pic,
+ int type, size_t size);
+
+void *ff_vaapi_decode_alloc_slice_buffer(AVCodecContext *avctx,
+ VAAPIDecodePicture *pic,
+ size_t params_size,
+ const void *slice_data,
+ size_t data_size);
+
+int ff_vaapi_decode_issue(AVCodecContext *avctx,
+ VAAPIDecodePicture *pic);
+int ff_vaapi_decode_cancel(AVCodecContext *avctx,
+ VAAPIDecodePicture *pic);
+
+int ff_vaapi_decode_init(AVCodecContext *avctx);
+int ff_vaapi_decode_uninit(AVCodecContext *avctx);
+
+#endif /* AVCODEC_VAAPI_DECODE_H */
diff --git a/libavcodec/version.h b/libavcodec/version.h
index f944709..b132bf7 100644
--- a/libavcodec/version.h
+++ b/libavcodec/version.h
@@ -28,7 +28,7 @@
#include "libavutil/version.h"
#define LIBAVCODEC_VERSION_MAJOR 57
-#define LIBAVCODEC_VERSION_MINOR 25
+#define LIBAVCODEC_VERSION_MINOR 26
#define LIBAVCODEC_VERSION_MICRO 0
#define LIBAVCODEC_VERSION_INT AV_VERSION_INT(LIBAVCODEC_VERSION_MAJOR, \
@@ -206,5 +206,8 @@
#ifndef FF_API_GET_CONTEXT_DEFAULTS
#define FF_API_GET_CONTEXT_DEFAULTS (LIBAVCODEC_VERSION_MAJOR < 59)
#endif
+#ifndef FF_API_VAAPI_CONTEXT
+#define FF_API_VAAPI_CONTEXT (LIBAVCODEC_VERSION_MAJOR < 59)
+#endif
#endif /* AVCODEC_VERSION_H */
--
2.8.1
_______________________________________________
libav-devel mailing list
[email protected]
https://lists.libav.org/mailman/listinfo/libav-devel