mirror of
https://github.com/wang-bin/QtAV.git
synced 2026-10-28 19:16:48 +08:00
vaapi: correctly check profile
This commit is contained in:
@@ -93,6 +93,67 @@ void RegisterVideoDecoderVAAPI_Man()
|
||||
{
|
||||
FACTORY_REGISTER_ID_MAN(VideoDecoder, VAAPI, "VAAPI")
|
||||
}
|
||||
const char* getProfileName(AVCodecID id, int profile)
|
||||
{
|
||||
AVCodec *c = avcodec_find_decoder(id);
|
||||
if (!c)
|
||||
return "Unknow";
|
||||
return av_get_profile_name(c, profile);
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
AVCodecID codec;
|
||||
int profile;
|
||||
VAProfile va_profile;
|
||||
} codec_profile_t;
|
||||
#define VAProfileNone ((VAProfile)-1) //maybe not defined for old va
|
||||
|
||||
static const codec_profile_t va_profiles[] = {
|
||||
{ QTAV_CODEC_ID(MPEG1VIDEO), FF_PROFILE_UNKNOWN, VAProfileMPEG2Main }, //vlc
|
||||
{ QTAV_CODEC_ID(MPEG2VIDEO), FF_PROFILE_MPEG2_MAIN, VAProfileMPEG2Main },
|
||||
{ QTAV_CODEC_ID(MPEG2VIDEO), FF_PROFILE_MPEG2_SIMPLE, VAProfileMPEG2Simple },
|
||||
{ QTAV_CODEC_ID(H263), FF_PROFILE_UNKNOWN, VAProfileMPEG4AdvancedSimple }, //xbmc
|
||||
{ QTAV_CODEC_ID(MPEG4), FF_PROFILE_MPEG4_ADVANCED_SIMPLE, VAProfileMPEG4AdvancedSimple },
|
||||
{ QTAV_CODEC_ID(MPEG4), FF_PROFILE_MPEG4_MAIN, VAProfileMPEG4Main },
|
||||
{ QTAV_CODEC_ID(MPEG4), FF_PROFILE_MPEG4_SIMPLE, VAProfileMPEG4Simple },
|
||||
{ QTAV_CODEC_ID(H264), FF_PROFILE_H264_HIGH, VAProfileH264High },
|
||||
{ QTAV_CODEC_ID(H264), FF_PROFILE_H264_MAIN, VAProfileH264Main },
|
||||
{ QTAV_CODEC_ID(H264), FF_PROFILE_H264_BASELINE, VAProfileH264Baseline },
|
||||
{ QTAV_CODEC_ID(H264), FF_PROFILE_H264_CONSTRAINED_BASELINE, VAProfileH264ConstrainedBaseline }, //mpv force main
|
||||
{ QTAV_CODEC_ID(VC1), FF_PROFILE_VC1_ADVANCED, VAProfileVC1Advanced },
|
||||
{ QTAV_CODEC_ID(VC1), FF_PROFILE_VC1_MAIN, VAProfileVC1Main },
|
||||
{ QTAV_CODEC_ID(VC1), FF_PROFILE_VC1_SIMPLE, VAProfileVC1Simple },
|
||||
{ QTAV_CODEC_ID(WMV3), FF_PROFILE_VC1_ADVANCED, VAProfileVC1Advanced },
|
||||
{ QTAV_CODEC_ID(WMV3), FF_PROFILE_VC1_MAIN, VAProfileVC1Main },
|
||||
{ QTAV_CODEC_ID(WMV3), FF_PROFILE_VC1_SIMPLE, VAProfileVC1Simple },
|
||||
{ QTAV_CODEC_ID(NONE), FF_PROFILE_UNKNOWN, VAProfileNone }
|
||||
};
|
||||
|
||||
static bool isProfileSupportedByRuntime(const VAProfile *profiles, int count, VAProfile p)
|
||||
{
|
||||
for (int i = 0; i < count; ++i) {
|
||||
if (profiles[i] == p)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
const codec_profile_t* findProfileEntry(AVCodecID codec, int profile)
|
||||
{
|
||||
if (codec == QTAV_CODEC_ID(NONE))
|
||||
return 0;
|
||||
for (int i = 0; va_profiles[i].codec != QTAV_CODEC_ID(NONE); ++i) {
|
||||
const codec_profile_t* p = &va_profiles[i];
|
||||
if (codec != p->codec || profile != p->profile)
|
||||
continue;
|
||||
// return the first profile entry if given profile is unknow
|
||||
if (profile == FF_PROFILE_UNKNOWN
|
||||
|| p->profile == FF_PROFILE_UNKNOWN // force the profile
|
||||
|| profile == p->profile)
|
||||
return p;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
class VideoDecoderVAAPIPrivate : public VideoDecoderFFmpegHWPrivate, public VAAPI_DRM, public VAAPI_X11, public VAAPI_GLX
|
||||
, public X11_API
|
||||
@@ -356,41 +417,18 @@ QStringList VideoDecoderVAAPI::displayPriority() const
|
||||
|
||||
bool VideoDecoderVAAPIPrivate::open()
|
||||
{
|
||||
#define VAProfileNone ((VAProfile)-1) //maybe not defined for old va
|
||||
VAProfile i_profile = VAProfileNone;
|
||||
int i_surfaces = 0;
|
||||
switch (codec_ctx->codec_id) {
|
||||
case QTAV_CODEC_ID(MPEG1VIDEO):
|
||||
case QTAV_CODEC_ID(MPEG2VIDEO):
|
||||
i_profile = VAProfileMPEG2Main;
|
||||
i_surfaces = 2+1;
|
||||
break;
|
||||
case QTAV_CODEC_ID(MPEG4):
|
||||
i_profile = VAProfileMPEG4AdvancedSimple;
|
||||
i_surfaces = 2+1;
|
||||
break;
|
||||
case QTAV_CODEC_ID(WMV3):
|
||||
i_profile = VAProfileVC1Main;
|
||||
i_surfaces = 2+1;
|
||||
break;
|
||||
case QTAV_CODEC_ID(VC1):
|
||||
i_profile = VAProfileVC1Advanced;
|
||||
i_surfaces = 2+1;
|
||||
break;
|
||||
case QTAV_CODEC_ID(H264):
|
||||
i_profile = VAProfileH264High;
|
||||
i_surfaces = 16+2 + codec_ctx->thread_count;
|
||||
break;
|
||||
default:
|
||||
const codec_profile_t* pe = findProfileEntry(codec_ctx->codec_id, codec_ctx->profile);
|
||||
if (!pe) {
|
||||
qWarning("codec(%s) or profile(%s) is not supported", avcodec_get_name(codec_ctx->codec_id), getProfileName(codec_ctx->codec_id, codec_ctx->profile));
|
||||
return false;
|
||||
}
|
||||
if (surface_auto) {
|
||||
nb_surfaces = i_surfaces;
|
||||
}
|
||||
if (nb_surfaces <= 0) {
|
||||
qWarning("internal error: wrong surface count. %u auto=%d", nb_surfaces, surface_auto);
|
||||
nb_surfaces = 17;
|
||||
}
|
||||
int surface_count = 2 + 1;
|
||||
if (codec_ctx->codec_id == QTAV_CODEC_ID(H264))
|
||||
surface_count = 16+2 + codec_ctx->thread_count;
|
||||
if (surface_auto)
|
||||
nb_surfaces = surface_count;
|
||||
if (nb_surfaces <= 0)
|
||||
nb_surfaces = surface_count;
|
||||
config_id = VA_INVALID_ID;
|
||||
context_id = VA_INVALID_ID;
|
||||
image.image_id = VA_INVALID_ID;
|
||||
@@ -482,42 +520,37 @@ bool VideoDecoderVAAPIPrivate::open()
|
||||
qWarning("VAAPI: frame size (%dx%d) is too large", codec_ctx->width, codec_ctx->height);
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Check if the selected profile is supported */
|
||||
int i_profiles_nb = vaMaxNumProfiles(disp);
|
||||
VAProfile *p_profiles_list = (VAProfile*)calloc(i_profiles_nb, sizeof(VAProfile));
|
||||
if (!p_profiles_list)
|
||||
qDebug("checking profile: %s, %s", avcodec_get_name(codec_ctx->codec_id), getProfileName(pe->codec, pe->profile));
|
||||
int nb_profiles = vaMaxNumProfiles(disp);
|
||||
if (nb_profiles <= 0) {
|
||||
qWarning("No profile supported");
|
||||
return false;
|
||||
|
||||
bool b_supported_profile = false;
|
||||
VAStatus status = vaQueryConfigProfiles(disp, p_profiles_list, &i_profiles_nb);
|
||||
if (status == VA_STATUS_SUCCESS) {
|
||||
for (int i = 0; i < i_profiles_nb; i++) {
|
||||
if (p_profiles_list[i] == i_profile) {
|
||||
b_supported_profile = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
free(p_profiles_list);
|
||||
if (!b_supported_profile) {
|
||||
qDebug("Codec and profile not supported by the hardware");
|
||||
QVector<VAProfile> supported_profiles(nb_profiles, VAProfileNone);
|
||||
VAStatus status = vaQueryConfigProfiles(disp, supported_profiles.data(), &nb_profiles);
|
||||
if (status != VA_STATUS_SUCCESS) {
|
||||
qWarning("Failed to query profiles: %#x %s", status, vaErrorStr(status));
|
||||
return false;
|
||||
}
|
||||
if (!isProfileSupportedByRuntime(supported_profiles.constData(), nb_profiles, pe->va_profile)) {
|
||||
qDebug("Codec or profile is not supported by the hardware");
|
||||
return false;
|
||||
}
|
||||
/* Create a VA configuration */
|
||||
VAConfigAttrib attrib;
|
||||
memset(&attrib, 0, sizeof(attrib));
|
||||
attrib.type = VAConfigAttribRTFormat;
|
||||
if ((status = vaGetConfigAttributes(disp, i_profile, VAEntrypointVLD, &attrib, 1)) != VA_STATUS_SUCCESS) {
|
||||
qWarning("vaGetConfigAttributes(VADisplay:%p, VAProfile:%d, VAEntrypointVLD, VAConfigAttrib*:%p, num_attrib:1) == %#x", disp, i_profile, &attrib, status);
|
||||
if ((status = vaGetConfigAttributes(disp, pe->va_profile, VAEntrypointVLD, &attrib, 1)) != VA_STATUS_SUCCESS) {
|
||||
qWarning("vaGetConfigAttributes(VADisplay:%p, VAProfile:%d, VAEntrypointVLD, VAConfigAttrib*:%p, num_attrib:1) == %#x", disp, pe->va_profile, &attrib, status);
|
||||
return false;
|
||||
}
|
||||
/* Not sure what to do if not, I don't have a way to test */
|
||||
if ((attrib.value & VA_RT_FORMAT_YUV420) == 0)
|
||||
return false;
|
||||
//vaCreateConfig(display, i_profile, VAEntrypointVLD, NULL, 0, &config_id)
|
||||
if ((status = vaCreateConfig(disp, i_profile, VAEntrypointVLD, &attrib, 1, &config_id)) != VA_STATUS_SUCCESS) {
|
||||
qWarning("vaCreateConfig(VADisplay:%p, VAProfile:%d, VAEntrypointVLD, VAConfigAttrib*:%p, num_attrib:1, VAConfigID*:%p) == %#x", disp, i_profile, &attrib, &config_id, status);
|
||||
//vaCreateConfig(display, pe->va_profile, VAEntrypointVLD, NULL, 0, &config_id)
|
||||
if ((status = vaCreateConfig(disp, pe->va_profile, VAEntrypointVLD, &attrib, 1, &config_id)) != VA_STATUS_SUCCESS) {
|
||||
qWarning("vaCreateConfig(VADisplay:%p, VAProfile:%d, VAEntrypointVLD, VAConfigAttrib*:%p, num_attrib:1, VAConfigID*:%p) == %#x", disp, pe->va_profile, &attrib, &config_id, status);
|
||||
config_id = VA_INVALID_ID;
|
||||
return false;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user