diff --git a/libavcodec/dxva2.c b/libavcodec/dxva2.c index e0c54068d6..9f4a5294a4 100644 --- a/libavcodec/dxva2.c +++ b/libavcodec/dxva2.c @@ -49,18 +49,34 @@ DEFINE_GUID(ff_IID_IDirectXVideoDecoderService, 0xfc51a551,0xd5e7,0x11d9,0xaf,0x typedef struct dxva_mode { const GUID *guid; enum AVCodecID codec; + // List of supported profiles, terminated by a FF_PROFILE_UNKNOWN entry. + // If NULL, don't check profile. + const int *profiles; } dxva_mode; +static const int prof_mpeg2_main[] = {FF_PROFILE_MPEG2_SIMPLE, + FF_PROFILE_MPEG2_MAIN, + FF_PROFILE_UNKNOWN}; +static const int prof_h264_high[] = {FF_PROFILE_H264_CONSTRAINED_BASELINE, + FF_PROFILE_H264_MAIN, + FF_PROFILE_H264_HIGH, + FF_PROFILE_UNKNOWN}; +static const int prof_hevc_main[] = {FF_PROFILE_HEVC_MAIN, + FF_PROFILE_UNKNOWN}; +static const int prof_hevc_main10[] = {FF_PROFILE_HEVC_MAIN, + FF_PROFILE_HEVC_MAIN_10, + FF_PROFILE_UNKNOWN}; + static const dxva_mode dxva_modes[] = { /* MPEG-2 */ - { &ff_DXVA2_ModeMPEG2_VLD, AV_CODEC_ID_MPEG2VIDEO }, - { &ff_DXVA2_ModeMPEG2and1_VLD, AV_CODEC_ID_MPEG2VIDEO }, + { &ff_DXVA2_ModeMPEG2_VLD, AV_CODEC_ID_MPEG2VIDEO, prof_mpeg2_main }, + { &ff_DXVA2_ModeMPEG2and1_VLD, AV_CODEC_ID_MPEG2VIDEO, prof_mpeg2_main }, /* H.264 */ - { &ff_DXVA2_ModeH264_F, AV_CODEC_ID_H264 }, - { &ff_DXVA2_ModeH264_E, AV_CODEC_ID_H264 }, + { &ff_DXVA2_ModeH264_F, AV_CODEC_ID_H264, prof_h264_high }, + { &ff_DXVA2_ModeH264_E, AV_CODEC_ID_H264, prof_h264_high }, /* Intel specific H.264 mode */ - { &ff_DXVADDI_Intel_ModeH264_E, AV_CODEC_ID_H264 }, + { &ff_DXVADDI_Intel_ModeH264_E, AV_CODEC_ID_H264, prof_h264_high }, /* VC-1 / WMV3 */ { &ff_DXVA2_ModeVC1_D2010, AV_CODEC_ID_VC1 }, @@ -69,8 +85,8 @@ static const dxva_mode dxva_modes[] = { { &ff_DXVA2_ModeVC1_D, AV_CODEC_ID_WMV3 }, /* HEVC/H.265 */ - { &ff_DXVA2_ModeHEVC_VLD_Main, AV_CODEC_ID_HEVC }, - { &ff_DXVA2_ModeHEVC_VLD_Main10, AV_CODEC_ID_HEVC }, + { &ff_DXVA2_ModeHEVC_VLD_Main10, AV_CODEC_ID_HEVC, prof_hevc_main10 }, + { &ff_DXVA2_ModeHEVC_VLD_Main, AV_CODEC_ID_HEVC, prof_hevc_main }, { NULL, 0 }, }; @@ -160,6 +176,26 @@ static int dxva2_validate_output(void *decoder_service, GUID guid, void *surface } #endif +static int dxva_check_codec_compatibility(AVCodecContext *avctx, const dxva_mode *mode) +{ + if (mode->codec != avctx->codec_id) + return 0; + + if (mode->profiles && !(avctx->hwaccel_flags & AV_HWACCEL_FLAG_ALLOW_PROFILE_MISMATCH)) { + int i, found = 0; + for (i = 0; mode->profiles[i] != FF_PROFILE_UNKNOWN; i++) { + if (avctx->profile == mode->profiles[i]) { + found = 1; + break; + } + } + if (!found) + return 0; + } + + return 1; +} + static int dxva_get_decoder_guid(AVCodecContext *avctx, void *service, void *surface_format, unsigned guid_count, const GUID *guid_list, GUID *decoder_guid) { @@ -170,7 +206,7 @@ static int dxva_get_decoder_guid(AVCodecContext *avctx, void *service, void *sur for (i = 0; dxva_modes[i].guid; i++) { const dxva_mode *mode = &dxva_modes[i]; int validate; - if (mode->codec != avctx->codec_id) + if (!dxva_check_codec_compatibility(avctx, mode)) continue; for (j = 0; j < guid_count; j++) { @@ -552,18 +588,6 @@ int ff_dxva2_decode_init(AVCodecContext *avctx) // (avctx->pix_fmt is not updated yet at this point) sctx->pix_fmt = avctx->hwaccel->pix_fmt; - if (avctx->codec_id == AV_CODEC_ID_H264 && - (avctx->profile & ~FF_PROFILE_H264_CONSTRAINED) > FF_PROFILE_H264_HIGH) { - av_log(avctx, AV_LOG_VERBOSE, "Unsupported H.264 profile for DXVA HWAccel: %d\n",avctx->profile); - return AVERROR(ENOTSUP); - } - - if (avctx->codec_id == AV_CODEC_ID_HEVC && - avctx->profile != FF_PROFILE_HEVC_MAIN && avctx->profile != FF_PROFILE_HEVC_MAIN_10) { - av_log(avctx, AV_LOG_VERBOSE, "Unsupported HEVC profile for DXVA HWAccel: %d\n", avctx->profile); - return AVERROR(ENOTSUP); - } - if (!avctx->hw_frames_ctx && !avctx->hw_device_ctx) { av_log(avctx, AV_LOG_ERROR, "Either a hw_frames_ctx or a hw_device_ctx needs to be set for hardware decoding.\n"); return AVERROR(EINVAL);