vaapi_decode: Make the frames context format selection more general

Examine the supported fourcc list manually and make the best choice, then
use the external attribute on the frames context to force that fourcc.
pull/279/head
Mark Thompson 7 years ago
parent 193e43e619
commit 99ab0a13dc
  1. 152
      libavcodec/vaapi_decode.c
  2. 2
      libavcodec/vaapi_decode.h

@ -232,6 +232,132 @@ int ff_vaapi_decode_cancel(AVCodecContext *avctx,
return 0;
}
static const struct {
uint32_t fourcc;
enum AVPixelFormat pix_fmt;
} vaapi_format_map[] = {
#define MAP(va, av) { VA_FOURCC_ ## va, AV_PIX_FMT_ ## av }
// 4:0:0
MAP(Y800, GRAY8),
// 4:2:0
MAP(NV12, NV12),
MAP(YV12, YUV420P),
MAP(IYUV, YUV420P),
#ifdef VA_FOURCC_I420
MAP(I420, YUV420P),
#endif
MAP(IMC3, YUV420P),
// 4:1:1
MAP(411P, YUV411P),
// 4:2:2
MAP(422H, YUV422P),
#ifdef VA_FOURCC_YV16
MAP(YV16, YUV422P),
#endif
// 4:4:0
MAP(422V, YUV440P),
// 4:4:4
MAP(444P, YUV444P),
// 4:2:0 10-bit
#ifdef VA_FOURCC_P010
MAP(P010, P010),
#endif
#ifdef VA_FOURCC_I010
MAP(I010, YUV420P10),
#endif
#undef MAP
};
static int vaapi_decode_find_best_format(AVCodecContext *avctx,
AVHWDeviceContext *device,
VAConfigID config_id,
AVHWFramesContext *frames)
{
AVVAAPIDeviceContext *hwctx = device->hwctx;
VAStatus vas;
VASurfaceAttrib *attr;
enum AVPixelFormat source_format, best_format, format;
uint32_t best_fourcc, fourcc;
int i, j, nb_attr;
source_format = avctx->sw_pix_fmt;
av_assert0(source_format != AV_PIX_FMT_NONE);
vas = vaQuerySurfaceAttributes(hwctx->display, config_id,
NULL, &nb_attr);
if (vas != VA_STATUS_SUCCESS) {
av_log(avctx, AV_LOG_ERROR, "Failed to query surface attributes: "
"%d (%s).\n", vas, vaErrorStr(vas));
return AVERROR(ENOSYS);
}
attr = av_malloc_array(nb_attr, sizeof(*attr));
if (!attr)
return AVERROR(ENOMEM);
vas = vaQuerySurfaceAttributes(hwctx->display, config_id,
attr, &nb_attr);
if (vas != VA_STATUS_SUCCESS) {
av_log(avctx, AV_LOG_ERROR, "Failed to query surface attributes: "
"%d (%s).\n", vas, vaErrorStr(vas));
av_freep(&attr);
return AVERROR(ENOSYS);
}
best_format = AV_PIX_FMT_NONE;
for (i = 0; i < nb_attr; i++) {
if (attr[i].type != VASurfaceAttribPixelFormat)
continue;
fourcc = attr[i].value.value.i;
for (j = 0; j < FF_ARRAY_ELEMS(vaapi_format_map); j++) {
if (fourcc == vaapi_format_map[j].fourcc)
break;
}
if (j >= FF_ARRAY_ELEMS(vaapi_format_map)) {
av_log(avctx, AV_LOG_DEBUG, "Ignoring unknown format %#x.\n",
fourcc);
continue;
}
format = vaapi_format_map[j].pix_fmt;
av_log(avctx, AV_LOG_DEBUG, "Considering format %#x -> %s.\n",
fourcc, av_get_pix_fmt_name(format));
best_format = av_find_best_pix_fmt_of_2(format, best_format,
source_format, 0, NULL);
if (format == best_format)
best_fourcc = fourcc;
}
av_freep(&attr);
if (best_format == AV_PIX_FMT_NONE) {
av_log(avctx, AV_LOG_ERROR, "No usable formats for decoding!\n");
return AVERROR(EINVAL);
}
av_log(avctx, AV_LOG_DEBUG, "Picked %s (%#x) as best match for %s.\n",
av_get_pix_fmt_name(best_format), best_fourcc,
av_get_pix_fmt_name(source_format));
frames->sw_format = best_format;
if (avctx->internal->hwaccel_priv_data) {
VAAPIDecodeContext *ctx = avctx->internal->hwaccel_priv_data;
AVVAAPIFramesContext *avfc = frames->hwctx;
ctx->pixel_format_attribute = (VASurfaceAttrib) {
.type = VASurfaceAttribPixelFormat,
.value.value.i = best_fourcc,
};
avfc->attributes = &ctx->pixel_format_attribute;
avfc->nb_attributes = 1;
}
return 0;
}
static const struct {
enum AVCodecID codec_id;
int codec_profile;
@ -289,7 +415,6 @@ static int vaapi_decode_make_config(AVCodecContext *avctx,
const AVCodecDescriptor *codec_desc;
VAProfile *profile_list = NULL, matched_va_profile;
int profile_count, exact_match, matched_ff_profile;
const AVPixFmtDescriptor *sw_desc, *desc;
AVHWDeviceContext *device = (AVHWDeviceContext*)device_ref->data;
AVVAAPIDeviceContext *hwctx = device->hwctx;
@ -417,27 +542,10 @@ static int vaapi_decode_make_config(AVCodecContext *avctx,
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;
}
err = vaapi_decode_find_best_format(avctx, device,
*va_config, frames);
if (err < 0)
goto fail;
frames->initial_pool_size = 1;
// Add per-codec number of surfaces used for storing reference frames.

@ -72,6 +72,8 @@ FF_ENABLE_DEPRECATION_WARNINGS
enum AVPixelFormat surface_format;
int surface_count;
VASurfaceAttrib pixel_format_attribute;
} VAAPIDecodeContext;

Loading…
Cancel
Save