diff options
Diffstat (limited to 'video/decode')
-rw-r--r-- | video/decode/lavc.h | 13 | ||||
-rw-r--r-- | video/decode/vaapi.c | 77 | ||||
-rw-r--r-- | video/decode/vd_lavc.c | 43 | ||||
-rw-r--r-- | video/decode/vdpau.c | 69 |
4 files changed, 130 insertions, 72 deletions
diff --git a/video/decode/lavc.h b/video/decode/lavc.h index 32b827b964..9e2533cbd5 100644 --- a/video/decode/lavc.h +++ b/video/decode/lavc.h @@ -22,6 +22,7 @@ enum hwdec_type { }; typedef struct lavc_ctx { + struct MPOpts *opts; AVCodecContext *avctx; AVFrame *pic; struct vd_lavc_hwdec *hwdec; @@ -73,6 +74,18 @@ enum { HWDEC_ERR_NO_CODEC = -3, }; +struct hwdec_profile_entry { + enum AVCodecID av_codec; + int ff_profile; + uint64_t hw_profile; +}; + +const struct hwdec_profile_entry *hwdec_find_profile( + struct lavc_ctx *ctx, const struct hwdec_profile_entry *table); +bool hwdec_check_codec_support(const char *decoder, + const struct hwdec_profile_entry *table); +int hwdec_get_max_refs(struct lavc_ctx *ctx); + // lavc_dr1.c int mp_codec_get_buffer(AVCodecContext *s, AVFrame *frame); void mp_codec_release_buffer(AVCodecContext *s, AVFrame *frame); diff --git a/video/decode/vaapi.c b/video/decode/vaapi.c index 65c75d1677..bb2a6c1049 100644 --- a/video/decode/vaapi.c +++ b/video/decode/vaapi.c @@ -73,38 +73,28 @@ struct priv { bool printed_readback_warning; }; -struct profile_entry { - enum AVCodecID av_codec; - int maxrefs; - const VAProfile *va_profiles; +#define PE(av_codec_id, ff_profile, vdp_profile) \ + {AV_CODEC_ID_ ## av_codec_id, FF_PROFILE_ ## ff_profile, \ + VAProfile ## vdp_profile} + +static const struct hwdec_profile_entry profiles[] = { + PE(MPEG2VIDEO, MPEG2_MAIN, MPEG2Main), + PE(MPEG2VIDEO, MPEG2_SIMPLE, MPEG2Simple), + PE(MPEG4, MPEG4_ADVANCED_SIMPLE, MPEG4AdvancedSimple), + PE(MPEG4, MPEG4_MAIN, MPEG4Main), + PE(MPEG4, MPEG4_SIMPLE, MPEG4Simple), + PE(H264, H264_HIGH, H264High), + PE(H264, H264_MAIN, H264Main), + PE(H264, H264_BASELINE, H264Baseline), + PE(VC1, VC1_ADVANCED, VC1Advanced), + PE(VC1, VC1_MAIN, VC1Main), + PE(VC1, VC1_SIMPLE, VC1Simple), + PE(WMV3, VC1_ADVANCED, VC1Advanced), + PE(WMV3, VC1_MAIN, VC1Main), + PE(WMV3, VC1_SIMPLE, VC1Simple), + {0} }; -#define RP(...) __VA_ARGS__ - -#define PE(av_codec_id, maxrefs, ...) \ - {AV_CODEC_ID_ ## av_codec_id, \ - maxrefs, (const VAProfile[]) {RP __VA_ARGS__, -1}} - -static const struct profile_entry profiles[] = { - PE(MPEG2VIDEO, 2, (VAProfileMPEG2Main, VAProfileMPEG2Simple)), - PE(H264, 16, (VAProfileH264High, VAProfileH264Main, - VAProfileH264Baseline)), - PE(WMV3, 2, (VAProfileVC1Main, VAProfileVC1Simple)), - PE(VC1, 2, (VAProfileVC1Advanced)), - PE(MPEG4, 2, (VAProfileMPEG4Main, VAProfileMPEG4AdvancedSimple, - VAProfileMPEG4Simple)), -}; - -static const struct profile_entry *find_codec(enum AVCodecID id) -{ - for (int n = 0; n < MP_ARRAY_SIZE(profiles); n++) { - if (profiles[n].av_codec == id) - return &profiles[n]; - } - return NULL; -} - - static const char *str_va_profile(VAProfile profile) { switch (profile) { @@ -226,9 +216,9 @@ static int create_decoder(struct lavc_ctx *ctx) destroy_decoder(ctx); - const struct profile_entry *pe = find_codec(ctx->avctx->codec_id); + const struct hwdec_profile_entry *pe = hwdec_find_profile(ctx, profiles); if (!pe) { - mp_msg(MSGT_VO, MSGL_ERR, "[vaapi] Unknown codec!\n"); + mp_msg(MSGT_VO, MSGL_ERR, "[vaapi] Unsupported codec or profile.\n"); goto error; } @@ -241,23 +231,18 @@ static int create_decoder(struct lavc_ctx *ctx) for (int i = 0; i < num_profiles; i++) mp_msg(MSGT_VO, MSGL_DBG2, " %s\n", str_va_profile(va_profiles[i])); - VAProfile va_profile = -1; - for (int n = 0; ; n++) { - if (pe->va_profiles[n] == -1) - break; - if (has_profile(va_profiles, num_profiles, pe->va_profiles[n])) { - va_profile = pe->va_profiles[n]; - break; - } - } - if (va_profile == -1) { - mp_msg(MSGT_VO, MSGL_ERR, "[vaapi] No decoder profile available.\n"); + VAProfile va_profile = pe->hw_profile; + if (!has_profile(va_profiles, num_profiles, va_profile)) { + mp_msg(MSGT_VO, MSGL_ERR, + "[vaapi] Decoder profile '%s' not available.\n", + str_va_profile(va_profile)); goto error; } + mp_msg(MSGT_VO, MSGL_V, "[vaapi] Using profile '%s'.\n", str_va_profile(va_profile)); - int num_surfaces = pe->maxrefs; + int num_surfaces = hwdec_get_max_refs(ctx); if (!is_direct_mapping(p->display)) { mp_msg(MSGT_VO, MSGL_V, "[vaapi] No direct mapping.\n"); // Note: not sure why it has to be *=2 rather than +=1. @@ -438,7 +423,7 @@ static int probe(struct vd_lavc_hwdec *hwdec, struct mp_hwdec_info *info, { if (!info || !info->vaapi_ctx) return HWDEC_ERR_NO_CTX; - if (!find_codec(mp_codec_to_av_codec_id(decoder))) + if (!hwdec_check_codec_support(decoder, profiles)) return HWDEC_ERR_NO_CODEC; return 0; } @@ -450,7 +435,7 @@ static int probe_copy(struct vd_lavc_hwdec *hwdec, struct mp_hwdec_info *info, if (!create_va_dummy_ctx(&dummy)) return HWDEC_ERR_NO_CTX; destroy_va_dummy_ctx(&dummy); - if (!find_codec(mp_codec_to_av_codec_id(decoder))) + if (!hwdec_check_codec_support(decoder, profiles)) return HWDEC_ERR_NO_CODEC; return 0; } diff --git a/video/decode/vd_lavc.c b/video/decode/vd_lavc.c index 479e36df6a..309d5dbcfd 100644 --- a/video/decode/vd_lavc.c +++ b/video/decode/vd_lavc.c @@ -78,6 +78,7 @@ const m_option_t lavc_decode_opts_conf[] = { OPT_STRING("skipframe", lavc_param.skip_frame_str, 0), OPT_INTRANGE("threads", lavc_param.threads, 0, 0, 16), OPT_FLAG_CONSTANTS("bitexact", lavc_param.bitexact, 0, 0, CODEC_FLAG_BITEXACT), + OPT_FLAG("check-hw-profile", lavc_param.check_hw_profile, 0), OPT_STRING("o", lavc_param.avopt, 0), {NULL, NULL, 0, 0, 0, 0, NULL} }; @@ -154,6 +155,47 @@ static enum AVDiscard str2AVDiscard(char *str) return AVDISCARD_DEFAULT; } +// Find the correct profile entry for the current codec and profile. +// Assumes the table has higher profiles first (for each codec). +const struct hwdec_profile_entry *hwdec_find_profile( + struct lavc_ctx *ctx, const struct hwdec_profile_entry *table) +{ + assert(AV_CODEC_ID_NONE == 0); + struct lavc_param *lavc_param = &ctx->opts->lavc_param; + enum AVCodecID codec = ctx->avctx->codec_id; + int profile = ctx->avctx->profile; + // Assume nobody cares about these aspects of the profile + if (codec == AV_CODEC_ID_H264) + profile &= ~(FF_PROFILE_H264_CONSTRAINED | FF_PROFILE_H264_INTRA); + for (int n = 0; table[n].av_codec; n++) { + if (table[n].av_codec == codec) { + if (table[n].ff_profile == FF_PROFILE_UNKNOWN || + profile == FF_PROFILE_UNKNOWN || + table[n].ff_profile == profile || + !lavc_param->check_hw_profile) + return &table[n]; + } + } + return NULL; +} + +// Check codec support, without checking the profile. +bool hwdec_check_codec_support(const char *decoder, + const struct hwdec_profile_entry *table) +{ + enum AVCodecID codec = mp_codec_to_av_codec_id(decoder); + for (int n = 0; table[n].av_codec; n++) { + if (table[n].av_codec == codec) + return true; + } + return false; +} + +int hwdec_get_max_refs(struct lavc_ctx *ctx) +{ + return ctx->avctx->codec_id == AV_CODEC_ID_H264 ? 16 : 2; +} + static int hwdec_probe(struct vd_lavc_hwdec *hwdec, struct mp_hwdec_info *info, const char *decoder, const char **hw_decoder) { @@ -208,6 +250,7 @@ static int init(sh_video_t *sh, const char *decoder) { vd_ffmpeg_ctx *ctx; ctx = sh->context = talloc_zero(NULL, vd_ffmpeg_ctx); + ctx->opts = sh->opts; ctx->non_dr1_pool = talloc_steal(ctx, mp_image_pool_new(16)); if (bstr_endswith0(bstr0(decoder), "_vdpau")) { diff --git a/video/decode/vdpau.c b/video/decode/vdpau.c index 57e29693c5..756c8e4d8e 100644 --- a/video/decode/vdpau.c +++ b/video/decode/vdpau.c @@ -47,18 +47,26 @@ struct profile_entry { int maxrefs; }; -#define PE(av_codec_id, vdp_dcoder_profile, maxrefs) \ - {AV_CODEC_ID_ ## av_codec_id, \ - VDP_DECODER_PROFILE_ ## vdp_dcoder_profile, \ - maxrefs} - -static const struct profile_entry profiles[] = { - PE(MPEG1VIDEO, MPEG1, 2), - PE(MPEG2VIDEO, MPEG2_MAIN, 2), - PE(H264, H264_HIGH, 16), - PE(WMV3, VC1_MAIN, 2), - PE(VC1, VC1_ADVANCED, 2), - PE(MPEG4, MPEG4_PART2_ASP,2), +#define PE(av_codec_id, ff_profile, vdp_profile) \ + {AV_CODEC_ID_ ## av_codec_id, FF_PROFILE_ ## ff_profile, \ + VDP_DECODER_PROFILE_ ## vdp_profile} + +static const struct hwdec_profile_entry profiles[] = { + PE(MPEG1VIDEO, UNKNOWN, MPEG1), + PE(MPEG2VIDEO, MPEG2_MAIN, MPEG2_MAIN), + PE(MPEG2VIDEO, MPEG2_SIMPLE, MPEG2_SIMPLE), + PE(MPEG4, MPEG4_ADVANCED_SIMPLE, MPEG4_PART2_ASP), + PE(MPEG4, MPEG4_SIMPLE, MPEG4_PART2_SP), + PE(H264, H264_HIGH, H264_HIGH), + PE(H264, H264_MAIN, H264_MAIN), + PE(H264, H264_BASELINE, H264_BASELINE), + PE(VC1, VC1_ADVANCED, VC1_ADVANCED), + PE(VC1, VC1_MAIN, VC1_MAIN), + PE(VC1, VC1_SIMPLE, VC1_SIMPLE), + PE(WMV3, VC1_ADVANCED, VC1_ADVANCED), + PE(WMV3, VC1_MAIN, VC1_MAIN), + PE(WMV3, VC1_SIMPLE, VC1_SIMPLE), + {0} }; // libavcodec absolutely wants a non-NULL render callback @@ -100,15 +108,6 @@ static int handle_preemption(struct lavc_ctx *ctx) return 0; } -static const struct profile_entry *find_codec(enum AVCodecID id) -{ - for (int n = 0; n < MP_ARRAY_SIZE(profiles); n++) { - if (profiles[n].av_codec == id) - return &profiles[n]; - } - return NULL; -} - static bool create_vdp_decoder(struct lavc_ctx *ctx) { struct priv *p = ctx->hwdec_priv; @@ -121,14 +120,32 @@ static bool create_vdp_decoder(struct lavc_ctx *ctx) if (p->context.decoder != VDP_INVALID_HANDLE) vdp->decoder_destroy(p->context.decoder); - const struct profile_entry *pe = find_codec(ctx->avctx->codec_id); + const struct hwdec_profile_entry *pe = hwdec_find_profile(ctx, profiles); if (!pe) { - mp_msg(MSGT_VO, MSGL_ERR, "[vdpau] Unknown codec!\n"); + mp_msg(MSGT_VO, MSGL_ERR, "[vdpau] Unsupported codec or profile.\n"); + goto fail; + } + + VdpBool supported; + uint32_t maxl, maxm, maxw, maxh; + vdp_st = vdp->decoder_query_capabilities(p->vdp_device, pe->hw_profile, + &supported, &maxl, &maxm, + &maxw, &maxh); + CHECK_ST_WARNING("Querying VDPAU decoder capabilities"); + if (!supported) { + mp_msg(MSGT_VO, MSGL_ERR, + "[vdpau] Codec or profile not supported by hardware.\n"); goto fail; } + if (p->vid_width > maxw || p->vid_height > maxh) { + mp_msg(MSGT_VO, MSGL_ERR, "[vdpau] Video too large.\n"); + goto fail; + } + + int maxrefs = hwdec_get_max_refs(ctx); - vdp_st = vdp->decoder_create(p->vdp_device, pe->vdp_profile, - p->vid_width, p->vid_height, pe->maxrefs, + vdp_st = vdp->decoder_create(p->vdp_device, pe->hw_profile, + p->vid_width, p->vid_height, maxrefs, &p->context.decoder); CHECK_ST_WARNING("Failed creating VDPAU decoder"); p->context.render = p->vdp->decoder_render; @@ -209,7 +226,7 @@ static int probe(struct vd_lavc_hwdec *hwdec, struct mp_hwdec_info *info, { if (!info || !info->vdpau_ctx) return HWDEC_ERR_NO_CTX; - if (!find_codec(mp_codec_to_av_codec_id(decoder))) + if (!hwdec_check_codec_support(decoder, profiles)) return HWDEC_ERR_NO_CODEC; return 0; } |