vaapi_encode: Check config attributes before creating config
This prevents attempts to use unsupported modes, such as low-power H.264 mode on non-Skylake targets. Also fixes a crash on invalid configuration, when trying to destroy an invalid VA config/context.
This commit is contained in:
parent
6641819fee
commit
2bfa067d0b
@ -20,6 +20,7 @@
|
|||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
#include "libavutil/avassert.h"
|
#include "libavutil/avassert.h"
|
||||||
|
#include "libavutil/common.h"
|
||||||
#include "libavutil/log.h"
|
#include "libavutil/log.h"
|
||||||
#include "libavutil/pixdesc.h"
|
#include "libavutil/pixdesc.h"
|
||||||
|
|
||||||
@ -887,6 +888,122 @@ fail:
|
|||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static av_cold int vaapi_encode_check_config(AVCodecContext *avctx)
|
||||||
|
{
|
||||||
|
VAAPIEncodeContext *ctx = avctx->priv_data;
|
||||||
|
VAStatus vas;
|
||||||
|
int i, n, err;
|
||||||
|
VAProfile *profiles = NULL;
|
||||||
|
VAEntrypoint *entrypoints = NULL;
|
||||||
|
VAConfigAttrib attr[] = {
|
||||||
|
{ VAConfigAttribRateControl },
|
||||||
|
{ VAConfigAttribEncMaxRefFrames },
|
||||||
|
};
|
||||||
|
|
||||||
|
n = vaMaxNumProfiles(ctx->hwctx->display);
|
||||||
|
profiles = av_malloc_array(n, sizeof(VAProfile));
|
||||||
|
if (!profiles) {
|
||||||
|
err = AVERROR(ENOMEM);
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
vas = vaQueryConfigProfiles(ctx->hwctx->display, profiles, &n);
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
for (i = 0; i < n; i++) {
|
||||||
|
if (profiles[i] == ctx->va_profile)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (i >= n) {
|
||||||
|
av_log(ctx, AV_LOG_ERROR, "Encoding profile not found (%d).\n",
|
||||||
|
ctx->va_profile);
|
||||||
|
err = AVERROR(ENOSYS);
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
n = vaMaxNumEntrypoints(ctx->hwctx->display);
|
||||||
|
entrypoints = av_malloc_array(n, sizeof(VAEntrypoint));
|
||||||
|
if (!entrypoints) {
|
||||||
|
err = AVERROR(ENOMEM);
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
vas = vaQueryConfigEntrypoints(ctx->hwctx->display, ctx->va_profile,
|
||||||
|
entrypoints, &n);
|
||||||
|
if (vas != VA_STATUS_SUCCESS) {
|
||||||
|
av_log(ctx, AV_LOG_ERROR, "Failed to query entrypoints for "
|
||||||
|
"profile %u: %d (%s).\n", ctx->va_profile,
|
||||||
|
vas, vaErrorStr(vas));
|
||||||
|
err = AVERROR(ENOSYS);
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
for (i = 0; i < n; i++) {
|
||||||
|
if (entrypoints[i] == ctx->va_entrypoint)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (i >= n) {
|
||||||
|
av_log(ctx, AV_LOG_ERROR, "Encoding entrypoint not found "
|
||||||
|
"(%d / %d).\n", ctx->va_profile, ctx->va_entrypoint);
|
||||||
|
err = AVERROR(ENOSYS);
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
vas = vaGetConfigAttributes(ctx->hwctx->display,
|
||||||
|
ctx->va_profile, ctx->va_entrypoint,
|
||||||
|
attr, FF_ARRAY_ELEMS(attr));
|
||||||
|
if (vas != VA_STATUS_SUCCESS) {
|
||||||
|
av_log(avctx, AV_LOG_ERROR, "Failed to fetch config "
|
||||||
|
"attributes: %d (%s).\n", vas, vaErrorStr(vas));
|
||||||
|
return AVERROR(EINVAL);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < FF_ARRAY_ELEMS(attr); i++) {
|
||||||
|
if (attr[i].value == VA_ATTRIB_NOT_SUPPORTED) {
|
||||||
|
// Unfortunately we have to treat this as "don't know" and hope
|
||||||
|
// for the best, because the Intel MJPEG encoder returns this
|
||||||
|
// for all the interesting attributes.
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
switch (attr[i].type) {
|
||||||
|
case VAConfigAttribRateControl:
|
||||||
|
if (!(ctx->va_rc_mode & attr[i].value)) {
|
||||||
|
av_log(avctx, AV_LOG_ERROR, "Rate control mode is not "
|
||||||
|
"supported: %x\n", attr[i].value);
|
||||||
|
err = AVERROR(EINVAL);
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case VAConfigAttribEncMaxRefFrames:
|
||||||
|
{
|
||||||
|
unsigned int ref_l0 = attr[i].value & 0xffff;
|
||||||
|
unsigned int ref_l1 = (attr[i].value >> 16) & 0xffff;
|
||||||
|
|
||||||
|
if (avctx->gop_size > 1 && ref_l0 < 1) {
|
||||||
|
av_log(avctx, AV_LOG_ERROR, "P frames are not "
|
||||||
|
"supported (%x).\n", attr[i].value);
|
||||||
|
err = AVERROR(EINVAL);
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
if (avctx->max_b_frames > 0 && ref_l1 < 1) {
|
||||||
|
av_log(avctx, AV_LOG_ERROR, "B frames are not "
|
||||||
|
"supported (%x).\n", attr[i].value);
|
||||||
|
err = AVERROR(EINVAL);
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
err = 0;
|
||||||
|
fail:
|
||||||
|
av_freep(&profiles);
|
||||||
|
av_freep(&entrypoints);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
av_cold int ff_vaapi_encode_init(AVCodecContext *avctx,
|
av_cold int ff_vaapi_encode_init(AVCodecContext *avctx,
|
||||||
const VAAPIEncodeType *type)
|
const VAAPIEncodeType *type)
|
||||||
{
|
{
|
||||||
@ -907,6 +1024,9 @@ av_cold int ff_vaapi_encode_init(AVCodecContext *avctx,
|
|||||||
ctx->codec = type;
|
ctx->codec = type;
|
||||||
ctx->codec_options = ctx->codec_options_data;
|
ctx->codec_options = ctx->codec_options_data;
|
||||||
|
|
||||||
|
ctx->va_config = VA_INVALID_ID;
|
||||||
|
ctx->va_context = VA_INVALID_ID;
|
||||||
|
|
||||||
ctx->priv_data = av_mallocz(type->priv_data_size);
|
ctx->priv_data = av_mallocz(type->priv_data_size);
|
||||||
if (!ctx->priv_data) {
|
if (!ctx->priv_data) {
|
||||||
err = AVERROR(ENOMEM);
|
err = AVERROR(ENOMEM);
|
||||||
@ -932,6 +1052,10 @@ av_cold int ff_vaapi_encode_init(AVCodecContext *avctx,
|
|||||||
if (err < 0)
|
if (err < 0)
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
||||||
|
err = vaapi_encode_check_config(avctx);
|
||||||
|
if (err < 0)
|
||||||
|
goto fail;
|
||||||
|
|
||||||
vas = vaCreateConfig(ctx->hwctx->display,
|
vas = vaCreateConfig(ctx->hwctx->display,
|
||||||
ctx->va_profile, ctx->va_entrypoint,
|
ctx->va_profile, ctx->va_entrypoint,
|
||||||
ctx->config_attributes, ctx->nb_config_attributes,
|
ctx->config_attributes, ctx->nb_config_attributes,
|
||||||
@ -1088,11 +1212,15 @@ av_cold int ff_vaapi_encode_close(AVCodecContext *avctx)
|
|||||||
vaapi_encode_free(avctx, pic);
|
vaapi_encode_free(avctx, pic);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ctx->va_context != VA_INVALID_ID)
|
if (ctx->va_context != VA_INVALID_ID) {
|
||||||
vaDestroyContext(ctx->hwctx->display, ctx->va_context);
|
vaDestroyContext(ctx->hwctx->display, ctx->va_context);
|
||||||
|
ctx->va_context = VA_INVALID_ID;
|
||||||
|
}
|
||||||
|
|
||||||
if (ctx->va_config != VA_INVALID_ID)
|
if (ctx->va_config != VA_INVALID_ID) {
|
||||||
vaDestroyConfig(ctx->hwctx->display, ctx->va_config);
|
vaDestroyConfig(ctx->hwctx->display, ctx->va_config);
|
||||||
|
ctx->va_config = VA_INVALID_ID;
|
||||||
|
}
|
||||||
|
|
||||||
if (ctx->codec->close)
|
if (ctx->codec->close)
|
||||||
ctx->codec->close(avctx);
|
ctx->codec->close(avctx);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user