Skip to content

Commit 66e30e7

Browse files
committed
hwdec/vaapi: improve probing of supported sw formats
The logic around trying to establish what formats are supported by vaapi is confusing, and it turns out that we've been doing it wrong. Up until now, we've been going through the list of decoding profile endpoints and checking the formats declared in those profiles to build our list. However, the set of formats that the vaapi driver can actually support is potentially a superset of those supported by any given profile endpoint. This master list is exposed by libavutil via the av_hwframe_transfer_get_formats() function, and so we should use that list as our starting point. Perhaps surprisingly, this change actually removes no code, because we still want the logic that enumerates endpoints and finds supported formats for endpoints. We need this because we must have at least one known sw format to initialise the hwframe_ctx with. Additionally, while in the general case, av_hwframe_transfer_get_formats can return different formats depending on what format you initialise the hwframe_ctx with, I happen to have read the libavutil code, and it doesn't care, so we just need to call it once, we know we'll get back all known formats. In practice, with an Intel vaapi driver, this will result in us supporting a handful of extra formats for hwuploads - particularly yuv420p (so no need to convert to nv12 first) and various orderings of rgb(a).
1 parent dfb5b0c commit 66e30e7

File tree

1 file changed

+47
-3
lines changed

1 file changed

+47
-3
lines changed

video/out/hwdec/hwdec_vaapi.c

Lines changed: 47 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -380,16 +380,51 @@ static void try_format_pixfmt(struct ra_hwdec *hw, enum AVPixelFormat pixfmt)
380380
static void try_format_config(struct ra_hwdec *hw, AVVAAPIHWConfig *hwconfig)
381381
{
382382
struct priv_owner *p = hw->priv;
383+
enum AVPixelFormat *fmts = NULL;
384+
383385
AVHWFramesConstraints *fc =
384386
av_hwdevice_get_hwframe_constraints(p->ctx->av_device_ref, hwconfig);
385387
if (!fc) {
386388
MP_WARN(hw, "failed to retrieve libavutil frame constraints\n");
387389
return;
388390
}
389-
for (int n = 0; fc->valid_sw_formats &&
390-
fc->valid_sw_formats[n] != AV_PIX_FMT_NONE; n++)
391-
try_format_pixfmt(hw, fc->valid_sw_formats[n]);
391+
392+
/*
393+
* We need a hwframe_ctx to be able to get the valid formats, but to
394+
* initialise it, we need a format, so we get the first format from the
395+
* hwconfig. We don't care about the other formats in the config because the
396+
* transfer formats list will already include them.
397+
*/
398+
AVBufferRef *fref = NULL;
399+
fref = av_hwframe_ctx_alloc(p->ctx->av_device_ref);
400+
if (!fref) {
401+
MP_WARN(hw, "failed to alloc libavutil frame context\n");
402+
goto err;
403+
}
404+
AVHWFramesContext *fctx = (void *)fref->data;
405+
fctx->format = AV_PIX_FMT_VAAPI;
406+
fctx->sw_format = fc->valid_sw_formats[0];
407+
fctx->width = 128;
408+
fctx->height = 128;
409+
if (av_hwframe_ctx_init(fref) < 0) {
410+
MP_WARN(hw, "failed to init libavutil frame context\n");
411+
goto err;
412+
}
413+
414+
int ret = av_hwframe_transfer_get_formats(fref, AV_HWFRAME_TRANSFER_DIRECTION_TO, &fmts, 0);
415+
if (ret) {
416+
MP_WARN(hw, "failed to get libavutil frame context supported formats\n");
417+
goto err;
418+
}
419+
420+
for (int n = 0; fmts &&
421+
fmts[n] != AV_PIX_FMT_NONE; n++)
422+
try_format_pixfmt(hw, fmts[n]);
423+
424+
err:
392425
av_hwframe_constraints_free(&fc);
426+
av_buffer_unref(&fref);
427+
av_free(fmts);
393428
}
394429

395430
static void determine_working_formats(struct ra_hwdec *hw)
@@ -416,6 +451,12 @@ static void determine_working_formats(struct ra_hwdec *hw)
416451
if (!CHECK_VA_STATUS(hw, "vaQueryConfigProfiles()"))
417452
num_profiles = 0;
418453

454+
/*
455+
* We need to find one declared format to bootstrap probing. So find a valid
456+
* decoding profile and use its config. If try_format_config() finds any
457+
* formats, they will be all the supported formats, and we don't need to
458+
* look at any other profiles.
459+
*/
419460
for (int n = 0; n < num_profiles; n++) {
420461
VAProfile profile = profiles[n];
421462
if (profile == VAProfileNone) {
@@ -448,6 +489,9 @@ static void determine_working_formats(struct ra_hwdec *hw)
448489
try_format_config(hw, hwconfig);
449490

450491
vaDestroyConfig(p->display, config);
492+
if (p->formats && p->formats[0]) {
493+
goto done;
494+
}
451495
}
452496
}
453497

0 commit comments

Comments
 (0)