#include "libavutil/avassert.h"
#include "libavutil/common.h"
+#include "libavutil/pixdesc.h"
#include "avcodec.h"
+#include "decode.h"
#include "internal.h"
#include "vaapi_decode.h"
{
VAAPIDecodeContext *ctx = avctx->internal->hwaccel_priv_data;
VAStatus vas;
- int err, i;
+ int err;
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 end picture decode "
"issue: %d (%s).\n", vas, vaErrorStr(vas));
err = AVERROR(EIO);
- if (ctx->hwctx->driver_quirks &
+ if (HAVE_VAAPI_1 || ctx->hwctx->driver_quirks &
AV_VAAPI_DRIVER_QUIRK_RENDER_PARAM_BUFFERS)
goto fail;
else
goto fail_at_end;
}
- if (ctx->hwctx->driver_quirks &
+ if (HAVE_VAAPI_1 || 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->slice_buffers);
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 ),
+ MAP(HEVC, HEVC_MAIN_10, HEVCMain10 ),
#endif
MAP(WMV3, VC1_SIMPLE, VC1Simple ),
MAP(WMV3, VC1_MAIN, VC1Main ),
#undef MAP
};
-static int vaapi_decode_make_config(AVCodecContext *avctx)
+/*
+ * Set *va_config and the frames_ref fields from the current codec parameters
+ * in avctx.
+ */
+static int vaapi_decode_make_config(AVCodecContext *avctx,
+ AVBufferRef *device_ref,
+ VAConfigID *va_config,
+ AVBufferRef *frames_ref)
{
- 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;
+ VAProfile *profile_list = NULL, matched_va_profile;
+ int profile_count, exact_match, matched_ff_profile;
+ const AVPixFmtDescriptor *sw_desc, *desc;
- // Allowing a profile mismatch can be useful because streams may
- // over-declare their required capabilities - in particular, many
- // H.264 baseline profile streams (notably some of those in FATE)
- // only use the feature set of constrained baseline. This flag
- // would have to be be set by some external means in order to
- // actually be useful. (AV_HWACCEL_FLAG_IGNORE_PROFILE?)
- int allow_profile_mismatch = 0;
+ AVHWDeviceContext *device = (AVHWDeviceContext*)device_ref->data;
+ AVVAAPIDeviceContext *hwctx = device->hwctx;
codec_desc = avcodec_descriptor_get(avctx->codec_id);
if (!codec_desc) {
goto fail;
}
- profile_count = vaMaxNumProfiles(ctx->hwctx->display);
+ profile_count = vaMaxNumProfiles(hwctx->display);
profile_list = av_malloc_array(profile_count,
sizeof(VAProfile));
if (!profile_list) {
goto fail;
}
- vas = vaQueryConfigProfiles(ctx->hwctx->display,
+ vas = vaQueryConfigProfiles(hwctx->display,
profile_list, &profile_count);
if (vas != VA_STATUS_SUCCESS) {
- av_log(ctx, AV_LOG_ERROR, "Failed to query profiles: "
+ av_log(avctx, AV_LOG_ERROR, "Failed to query profiles: "
"%d (%s).\n", vas, vaErrorStr(vas));
err = AVERROR(ENOSYS);
goto fail;
}
- profile = VAProfileNone;
+ matched_va_profile = VAProfileNone;
exact_match = 0;
for (i = 0; i < FF_ARRAY_ELEMS(vaapi_profile_map); i++) {
if (avctx->profile == vaapi_profile_map[i].codec_profile ||
vaapi_profile_map[i].codec_profile == FF_PROFILE_UNKNOWN)
profile_match = 1;
- profile = vaapi_profile_map[i].va_profile;
for (j = 0; j < profile_count; j++) {
- if (profile == profile_list[j]) {
+ if (vaapi_profile_map[i].va_profile == profile_list[j]) {
exact_match = profile_match;
break;
}
}
if (j < profile_count) {
+ matched_va_profile = vaapi_profile_map[i].va_profile;
+ matched_ff_profile = vaapi_profile_map[i].codec_profile;
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 "
+ if (matched_va_profile == VAProfileNone) {
+ av_log(avctx, 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) {
+ if (avctx->hwaccel_flags &
+ AV_HWACCEL_FLAG_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);
+ matched_ff_profile);
} else {
av_log(avctx, AV_LOG_VERBOSE, "Codec %s profile %d not "
"supported for hardware decode.\n",
}
}
- ctx->va_profile = profile;
- ctx->va_entrypoint = VAEntrypointVLD;
-
- vas = vaCreateConfig(ctx->hwctx->display, ctx->va_profile,
- ctx->va_entrypoint, NULL, 0,
- &ctx->va_config);
+ vas = vaCreateConfig(hwctx->display, matched_va_profile,
+ VAEntrypointVLD, NULL, 0,
+ va_config);
if (vas != VA_STATUS_SUCCESS) {
av_log(avctx, AV_LOG_ERROR, "Failed to create decode "
"configuration: %d (%s).\n", vas, vaErrorStr(vas));
goto fail;
}
- hwconfig = av_hwdevice_hwconfig_alloc(ctx->frames->device_ref);
+ hwconfig = av_hwdevice_hwconfig_alloc(device_ref);
if (!hwconfig) {
err = AVERROR(ENOMEM);
goto fail;
}
- hwconfig->config_id = ctx->va_config;
+ hwconfig->config_id = *va_config;
constraints =
- av_hwdevice_get_hwframe_constraints(ctx->frames->device_ref,
- hwconfig);
+ av_hwdevice_get_hwframe_constraints(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;
+ err = AVERROR(ENOMEM);
+ goto fail;
+ }
+
+ 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(avctx, 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;
+ }
+ if (!constraints->valid_sw_formats ||
+ constraints->valid_sw_formats[0] == AV_PIX_FMT_NONE) {
+ av_log(avctx, AV_LOG_ERROR, "Hardware does not offer any "
+ "usable surface formats.\n");
+ err = AVERROR(EINVAL);
+ goto fail;
+ }
+
+ if (frames_ref) {
+ AVHWFramesContext *frames = (AVHWFramesContext *)frames_ref->data;
+
+ frames->format = AV_PIX_FMT_VAAPI;
+ frames->width = avctx->coded_width;
+ frames->height = avctx->coded_height;
+
+ // Find the first format in the list which matches the expected
+ // bit depth and subsampling. If none are found (this can happen
+ // when 10-bit streams are decoded to 8-bit surfaces, for example)
+ // then just take the first format on the list.
+ frames->sw_format = constraints->valid_sw_formats[0];
+ sw_desc = av_pix_fmt_desc_get(avctx->sw_pix_fmt);
+ for (i = 0; constraints->valid_sw_formats[i] != AV_PIX_FMT_NONE; i++) {
+ desc = av_pix_fmt_desc_get(constraints->valid_sw_formats[i]);
+ if (desc->nb_components != sw_desc->nb_components ||
+ desc->log2_chroma_w != sw_desc->log2_chroma_w ||
+ desc->log2_chroma_h != sw_desc->log2_chroma_h)
+ continue;
+ for (j = 0; j < desc->nb_components; j++) {
+ if (desc->comp[j].depth != sw_desc->comp[j].depth)
+ break;
+ }
+ if (j < desc->nb_components)
+ continue;
+ frames->sw_format = constraints->valid_sw_formats[i];
+ break;
+ }
+
+ frames->initial_pool_size = 1;
+ // Add per-codec number of surfaces used for storing reference frames.
+ switch (avctx->codec_id) {
+ case AV_CODEC_ID_H264:
+ case AV_CODEC_ID_HEVC:
+ frames->initial_pool_size += 16;
+ break;
+ case AV_CODEC_ID_VP9:
+ frames->initial_pool_size += 8;
+ break;
+ case AV_CODEC_ID_VP8:
+ frames->initial_pool_size += 3;
+ break;
+ default:
+ frames->initial_pool_size += 2;
}
}
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;
+ if (*va_config != VA_INVALID_ID) {
+ vaDestroyConfig(hwctx->display, *va_config);
+ *va_config = VA_INVALID_ID;
}
av_freep(&profile_list);
return err;
}
+int ff_vaapi_common_frame_params(AVCodecContext *avctx,
+ AVBufferRef *hw_frames_ctx)
+{
+ AVHWFramesContext *hw_frames = (AVHWFramesContext *)hw_frames_ctx->data;
+ AVHWDeviceContext *device_ctx = hw_frames->device_ctx;
+ AVVAAPIDeviceContext *hwctx;
+ VAConfigID va_config = VA_INVALID_ID;
+ int err;
+
+ if (device_ctx->type != AV_HWDEVICE_TYPE_VAAPI)
+ return AVERROR(EINVAL);
+ hwctx = device_ctx->hwctx;
+
+ err = vaapi_decode_make_config(avctx, hw_frames->device_ref, &va_config,
+ hw_frames_ctx);
+ if (err)
+ return err;
+
+ if (va_config != VA_INVALID_ID)
+ vaDestroyConfig(hwctx->display, va_config);
+
+ return 0;
+}
+
int ff_vaapi_decode_init(AVCodecContext *avctx)
{
VAAPIDecodeContext *ctx = avctx->internal->hwaccel_priv_data;
ctx->hwctx->driver_quirks =
AV_VAAPI_DRIVER_QUIRK_RENDER_PARAM_BUFFERS;
- } else
-#endif
- if (avctx->hw_frames_ctx) {
- // This structure has a shorter lifetime than the enclosing
- // AVCodecContext, so we inherit the references from there
- // and do not need to make separate ones.
-
- 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;
}
+#endif
#if FF_API_VAAPI_CONTEXT
if (ctx->have_old_context) {
} else {
#endif
- err = vaapi_decode_make_config(avctx);
+ err = ff_decode_get_hw_frames_ctx(avctx, AV_HWDEVICE_TYPE_VAAPI);
+ if (err < 0)
+ goto fail;
+
+ ctx->frames = (AVHWFramesContext*)avctx->hw_frames_ctx->data;
+ ctx->hwfc = ctx->frames->hwctx;
+ ctx->device = ctx->frames->device_ctx;
+ ctx->hwctx = ctx->device->hwctx;
+
+ err = vaapi_decode_make_config(avctx, ctx->frames->device_ref,
+ &ctx->va_config, avctx->hw_frames_ctx);
if (err)
goto fail;