Message ID | e547ab6f-a86d-46e3-abbb-7e6233195992@jkqxz.net |
---|---|
State | New |
Headers | show |
Series | [FFmpeg-devel,1/2] lavc/h265_profile_level: Expand profile compatibility checking | expand |
Context | Check | Description |
---|---|---|
yinshiyou/make_loongarch64 | success | Make finished |
yinshiyou/make_fate_loongarch64 | fail | Make fate failed |
andriy/make_x86 | success | Make finished |
andriy/make_fate_x86 | fail | Make fate failed |
On Ma, 2024-04-22 at 22:23 +0100, Mark Thompson wrote: > Rather than turning the constraint flags into a single profile and then > searching for that profile (and failing if it doesn't match any profile > exactly), instead search all supported profiles and use the first one > which supports the given set of constraint flags. > --- > This fixes decode of rext 8-bit 4:2:0; it will correctly pick Main 12 or Main > 4:2:2 10 or Main 4:4:4 (first one available) to use as the decoding profile > after this patch. sw decoding and vaapi decoding might have different bits (There is the same issue if applying Fei's patchset). For example: $ ffmpeg -hwaccel vaapi -f lavfi -i testsrc -vf 'format=nv12,hwupload' -c:v hevc_vaapi -profile:v rext -vframes 30 -y out.mp4 8bit ouput if using sw decoding: $ ffmpeg -i out.mp4 -f null - [...] Stream #0:0(und): Video: wrapped_avframe, yuv420p(tv, progressive), 320x240 [SAR 1:1 DAR 4:3], q=2-31, 200 kb/s, 25 fps, 25 tbn (default) 12bit output if using vaapi decoding: $ ffmpeg -hwaccel vaapi -i out.mp4 -f null - [...] Stream #0:0(und): Video: wrapped_avframe, p012le(tv, progressive), 320x240 [SAR 1:1 DAR 4:3], q=2-31, 200 kb/s, 25 fps, 25 tbn (default) Thanks Haihao > > libavcodec/vaapi_decode.c | 45 ++++++++++++------- > libavcodec/vaapi_hevc.c | 95 +++++++++++++++++++++------------------ > libavcodec/vaapi_hevc.h | 4 +- > 3 files changed, 83 insertions(+), 61 deletions(-) > > diff --git a/libavcodec/vaapi_decode.c b/libavcodec/vaapi_decode.c > index 21b273cd0f..f1327464f5 100644 > --- a/libavcodec/vaapi_decode.c > +++ b/libavcodec/vaapi_decode.c > @@ -387,7 +387,9 @@ static const struct { > enum AVCodecID codec_id; > int codec_profile; > VAProfile va_profile; > - VAProfile (*profile_parser)(AVCodecContext *avctx); > + VAProfile (*match_profile)(AVCodecContext *avctx, > + const VAProfile *profile_list, > + int profile_count); > } vaapi_profile_map[] = { > #define MAP(c, p, v, ...) { AV_CODEC_ID_ ## c, AV_PROFILE_ ## p, VAProfile ## > v, __VA_ARGS__ } > MAP(MPEG2VIDEO, MPEG2_SIMPLE, MPEG2Simple ), > @@ -414,9 +416,9 @@ static const struct { > #endif > #if VA_CHECK_VERSION(1, 2, 0) && CONFIG_HEVC_VAAPI_HWACCEL > MAP(HEVC, HEVC_REXT, None, > - ff_vaapi_parse_hevc_rext_scc_profile ), > + ff_vaapi_hevc_match_rext_scc_profile ), > MAP(HEVC, HEVC_SCC, None, > - ff_vaapi_parse_hevc_rext_scc_profile ), > + ff_vaapi_hevc_match_rext_scc_profile ), > #endif > MAP(MJPEG, MJPEG_HUFFMAN_BASELINE_DCT, > JPEGBaseline), > @@ -499,22 +501,33 @@ static int vaapi_decode_make_config(AVCodecContext > *avctx, > vaapi_profile_map[i].codec_profile == AV_PROFILE_UNKNOWN) > profile_match = 1; > > - va_profile = vaapi_profile_map[i].profile_parser ? > - vaapi_profile_map[i].profile_parser(avctx) : > - vaapi_profile_map[i].va_profile; > codec_profile = vaapi_profile_map[i].codec_profile; > - > - for (j = 0; j < profile_count; j++) { > - if (va_profile == profile_list[j]) { > - exact_match = profile_match; > + if (vaapi_profile_map[i].match_profile) { > + va_profile = > + vaapi_profile_map[i].match_profile(avctx, profile_list, > + profile_count); > + if (va_profile != VAProfileNone) { > + matched_va_profile = va_profile; > + matched_ff_profile = codec_profile; > + exact_match = 1; > break; > } > - } > - if (j < profile_count) { > - matched_va_profile = va_profile; > - matched_ff_profile = codec_profile; > - if (exact_match) > - break; > + } else { > + va_profile = vaapi_profile_map[i].va_profile; > + > + for (j = 0; j < profile_count; j++) { > + if (va_profile == profile_list[j]) { > + exact_match = profile_match; > + break; > + } > + } > + > + if (j < profile_count) { > + matched_va_profile = va_profile; > + matched_ff_profile = codec_profile; > + if (exact_match) > + break; > + } > } > } > av_freep(&profile_list); > diff --git a/libavcodec/vaapi_hevc.c b/libavcodec/vaapi_hevc.c > index 77f55ff8b1..28f7c9280e 100644 > --- a/libavcodec/vaapi_hevc.c > +++ b/libavcodec/vaapi_hevc.c > @@ -590,63 +590,70 @@ static int ptl_convert(const PTLCommon *general_ptl, > H265RawProfileTierLevel *h2 > } > > /* > - * Find exact va_profile for HEVC Range Extension and Screen Content Coding > Extension > + * Find compatible va_profile for HEVC Range Extension and Screen > + * Content Coding Extension profiles. > */ > -VAProfile ff_vaapi_parse_hevc_rext_scc_profile(AVCodecContext *avctx) > +VAProfile ff_vaapi_hevc_match_rext_scc_profile(AVCodecContext *avctx, > + const VAProfile *profile_list, > + int profile_count) > { > const HEVCContext *h = avctx->priv_data; > const HEVCSPS *sps = h->ps.sps; > const PTL *ptl = &sps->ptl; > const PTLCommon *general_ptl = &ptl->general_ptl; > - const H265ProfileDescriptor *profile; > H265RawProfileTierLevel h265_raw_ptl = {0}; > > + static const struct { > + int profile; > + VAProfile va_profile; > + } map[] = { > +#if VA_CHECK_VERSION(1, 2, 0) > + { H265_PROFILE_MAIN_12, > + VAProfileHEVCMain12 }, > + { H265_PROFILE_MAIN_422_10, > + VAProfileHEVCMain422_10 }, > + { H265_PROFILE_MAIN_444, > + VAProfileHEVCMain444 }, > + { H265_PROFILE_MAIN_444_10, > + VAProfileHEVCMain444_10 }, > + { H265_PROFILE_MAIN_444_12, > + VAProfileHEVCMain444_12 }, > + { H265_PROFILE_SCREEN_EXTENDED_MAIN, > + VAProfileHEVCSccMain }, > + { H265_PROFILE_SCREEN_EXTENDED_MAIN_10, > + VAProfileHEVCSccMain10 }, > +#endif > +#if VA_CHECK_VERSION(1, 8, 0) > + { H265_PROFILE_SCREEN_EXTENDED_MAIN_444, > + VAProfileHEVCSccMain444 }, > +#endif > + }; > + > /* convert PTLCommon to H265RawProfileTierLevel */ > ptl_convert(general_ptl, &h265_raw_ptl); > > - profile = ff_h265_find_profile(&h265_raw_ptl); > - if (!profile) { > - av_log(avctx, AV_LOG_WARNING, "HEVC profile is not found.\n"); > - goto end; > - } else { > - av_log(avctx, AV_LOG_VERBOSE, "HEVC profile %s is found.\n", profile- > >name); > + for (int i = 0; i < FF_ARRAY_ELEMS(map); i++) { > + int available = 0; > + for (int j = 0; j < profile_count; j++) { > + if (profile_list[j] == map[i].va_profile) { > + available = 1; > + break; > + } > + } > + if (!available) > + continue; > + > + if (ff_h265_profile_compatible(&h265_raw_ptl, > + map[i].profile)) { > + const H265ProfileDescriptor *profile_desc = > + ff_h265_get_profile(map[i].profile); > + av_log(avctx, AV_LOG_VERBOSE, > + "Decoding with HEVC profile %s.\n", > + profile_desc->name); > + return map[i].va_profile; > + } > } > > -#if VA_CHECK_VERSION(1, 2, 0) > - if (!strcmp(profile->name, "Main 12") || > - !strcmp(profile->name, "Main 12 Intra")) > - return VAProfileHEVCMain12; > - else if (!strcmp(profile->name, "Main 4:2:2 10") || > - !strcmp(profile->name, "Main 4:2:2 10 Intra")) > - return VAProfileHEVCMain422_10; > - else if (!strcmp(profile->name, "Main 4:2:2 12") || > - !strcmp(profile->name, "Main 4:2:2 12 Intra")) > - return VAProfileHEVCMain422_12; > - else if (!strcmp(profile->name, "Main 4:4:4") || > - !strcmp(profile->name, "Main 4:4:4 Intra")) > - return VAProfileHEVCMain444; > - else if (!strcmp(profile->name, "Main 4:4:4 10") || > - !strcmp(profile->name, "Main 4:4:4 10 Intra")) > - return VAProfileHEVCMain444_10; > - else if (!strcmp(profile->name, "Main 4:4:4 12") || > - !strcmp(profile->name, "Main 4:4:4 12 Intra")) > - return VAProfileHEVCMain444_12; > - else if (!strcmp(profile->name, "Screen-Extended Main")) > - return VAProfileHEVCSccMain; > - else if (!strcmp(profile->name, "Screen-Extended Main 10")) > - return VAProfileHEVCSccMain10; > - else if (!strcmp(profile->name, "Screen-Extended Main 4:4:4")) > - return VAProfileHEVCSccMain444; > -#if VA_CHECK_VERSION(1, 8, 0) > - else if (!strcmp(profile->name, "Screen-Extended Main 4:4:4 10")) > - return VAProfileHEVCSccMain444_10; > -#endif > -#else > - av_log(avctx, AV_LOG_WARNING, "HEVC profile %s is " > - "not supported with this VA version.\n", profile->name); > -#endif > - > -end: > if (avctx->hwaccel_flags & AV_HWACCEL_FLAG_ALLOW_PROFILE_MISMATCH) { > // Default to selecting Main profile if profile mismatch is allowed > return VAProfileHEVCMain; > diff --git a/libavcodec/vaapi_hevc.h b/libavcodec/vaapi_hevc.h > index 449635d0d7..455c68e6ba 100644 > --- a/libavcodec/vaapi_hevc.h > +++ b/libavcodec/vaapi_hevc.h > @@ -22,6 +22,8 @@ > #include <va/va.h> > #include "avcodec.h" > > -VAProfile ff_vaapi_parse_hevc_rext_scc_profile(AVCodecContext *avctx); > +VAProfile ff_vaapi_hevc_match_rext_scc_profile(AVCodecContext *avctx, > + const VAProfile *profile_list, > + int profile_count); > > #endif /* AVCODEC_VAAPI_HEVC_H */
On 24/04/2024 14:45, Xiang, Haihao wrote: > On Ma, 2024-04-22 at 22:23 +0100, Mark Thompson wrote: >> Rather than turning the constraint flags into a single profile and then >> searching for that profile (and failing if it doesn't match any profile >> exactly), instead search all supported profiles and use the first one >> which supports the given set of constraint flags. >> --- >> This fixes decode of rext 8-bit 4:2:0; it will correctly pick Main 12 or Main >> 4:2:2 10 or Main 4:4:4 (first one available) to use as the decoding profile >> after this patch. > > sw decoding and vaapi decoding might have different bits (There is the same > issue if applying Fei's patchset). > > For example: > $ ffmpeg -hwaccel vaapi -f lavfi -i testsrc -vf 'format=nv12,hwupload' -c:v > hevc_vaapi -profile:v rext -vframes 30 -y out.mp4 > > 8bit ouput if using sw decoding: > $ ffmpeg -i out.mp4 -f null - > [...] > Stream #0:0(und): Video: wrapped_avframe, yuv420p(tv, progressive), 320x240 [SAR > 1:1 DAR 4:3], q=2-31, 200 kb/s, 25 fps, 25 tbn (default) > > 12bit output if using vaapi decoding: > $ ffmpeg -hwaccel vaapi -i out.mp4 -f null - > [...] > Stream #0:0(und): Video: wrapped_avframe, p012le(tv, progressive), 320x240 [SAR > 1:1 DAR 4:3], q=2-31, 200 kb/s, 25 fps, 25 tbn (default) That comes from what the driver reports support for, though? E.g. with the Intel iHD driver, I have { "profile": 23, "name": "HEVCMain12", ... "surface_formats": [ { "rt_format": "YUV420", "max_width": 16384, "max_height": 16384, "memory_types": [ "VA", "DRM_PRIME_2", ], "pixel_formats": [ "P012", "P016", ], }, So to decode a 4:2:0 8-bit input it is asking for a P012 or P016 surface. If the driver reported that a Main 12 profile 4:2:0 8-bit input could be decoded to an NV12 surface then it would be picked by the logic in vaapi_decode_find_best_format(), since it would be a better match than the higher-depth formats. Thanks, - Mark
On So, 2024-04-28 at 15:14 +0100, Mark Thompson wrote: > On 24/04/2024 14:45, Xiang, Haihao wrote: > > On Ma, 2024-04-22 at 22:23 +0100, Mark Thompson wrote: > > > Rather than turning the constraint flags into a single profile and then > > > searching for that profile (and failing if it doesn't match any profile > > > exactly), instead search all supported profiles and use the first one > > > which supports the given set of constraint flags. > > > --- > > > This fixes decode of rext 8-bit 4:2:0; it will correctly pick Main 12 or > > > Main > > > 4:2:2 10 or Main 4:4:4 (first one available) to use as the decoding > > > profile > > > after this patch. > > > > sw decoding and vaapi decoding might have different bits (There is the same > > issue if applying Fei's patchset). > > > > For example: > > $ ffmpeg -hwaccel vaapi -f lavfi -i testsrc -vf 'format=nv12,hwupload' -c:v > > hevc_vaapi -profile:v rext -vframes 30 -y out.mp4 > > > > 8bit ouput if using sw decoding: > > $ ffmpeg -i out.mp4 -f null - > > [...] > > Stream #0:0(und): Video: wrapped_avframe, yuv420p(tv, progressive), 320x240 > > [SAR > > 1:1 DAR 4:3], q=2-31, 200 kb/s, 25 fps, 25 tbn (default) > > > > 12bit output if using vaapi decoding: > > $ ffmpeg -hwaccel vaapi -i out.mp4 -f null - > > [...] > > Stream #0:0(und): Video: wrapped_avframe, p012le(tv, progressive), 320x240 > > [SAR > > 1:1 DAR 4:3], q=2-31, 200 kb/s, 25 fps, 25 tbn (default) > > That comes from what the driver reports support for, though? > > E.g. with the Intel iHD driver, I have > > { > "profile": 23, > "name": "HEVCMain12", > ... > "surface_formats": [ > { > "rt_format": "YUV420", > "max_width": 16384, > "max_height": 16384, > "memory_types": [ > "VA", > "DRM_PRIME_2", > ], > "pixel_formats": [ > "P012", > "P016", > ], > }, > > So to decode a 4:2:0 8-bit input it is asking for a P012 or P016 surface. > > If the driver reported that a Main 12 profile 4:2:0 8-bit input could be > decoded to an NV12 surface then it would be picked by the logic in > vaapi_decode_find_best_format(), since it would be a better match than the > higher-depth formats. You are right, the iHD driver doesn't report the support for HEVCMain12 8bit. Thanks Haihao
diff --git a/libavcodec/vaapi_decode.c b/libavcodec/vaapi_decode.c index 21b273cd0f..f1327464f5 100644 --- a/libavcodec/vaapi_decode.c +++ b/libavcodec/vaapi_decode.c @@ -387,7 +387,9 @@ static const struct { enum AVCodecID codec_id; int codec_profile; VAProfile va_profile; - VAProfile (*profile_parser)(AVCodecContext *avctx); + VAProfile (*match_profile)(AVCodecContext *avctx, + const VAProfile *profile_list, + int profile_count); } vaapi_profile_map[] = { #define MAP(c, p, v, ...) { AV_CODEC_ID_ ## c, AV_PROFILE_ ## p, VAProfile ## v, __VA_ARGS__ } MAP(MPEG2VIDEO, MPEG2_SIMPLE, MPEG2Simple ), @@ -414,9 +416,9 @@ static const struct { #endif #if VA_CHECK_VERSION(1, 2, 0) && CONFIG_HEVC_VAAPI_HWACCEL MAP(HEVC, HEVC_REXT, None, - ff_vaapi_parse_hevc_rext_scc_profile ), + ff_vaapi_hevc_match_rext_scc_profile ), MAP(HEVC, HEVC_SCC, None, - ff_vaapi_parse_hevc_rext_scc_profile ), + ff_vaapi_hevc_match_rext_scc_profile ), #endif MAP(MJPEG, MJPEG_HUFFMAN_BASELINE_DCT, JPEGBaseline), @@ -499,22 +501,33 @@ static int vaapi_decode_make_config(AVCodecContext *avctx, vaapi_profile_map[i].codec_profile == AV_PROFILE_UNKNOWN) profile_match = 1; - va_profile = vaapi_profile_map[i].profile_parser ? - vaapi_profile_map[i].profile_parser(avctx) : - vaapi_profile_map[i].va_profile; codec_profile = vaapi_profile_map[i].codec_profile; - - for (j = 0; j < profile_count; j++) { - if (va_profile == profile_list[j]) { - exact_match = profile_match; + if (vaapi_profile_map[i].match_profile) { + va_profile = + vaapi_profile_map[i].match_profile(avctx, profile_list, + profile_count); + if (va_profile != VAProfileNone) { + matched_va_profile = va_profile; + matched_ff_profile = codec_profile; + exact_match = 1; break; } - } - if (j < profile_count) { - matched_va_profile = va_profile; - matched_ff_profile = codec_profile; - if (exact_match) - break; + } else { + va_profile = vaapi_profile_map[i].va_profile; + + for (j = 0; j < profile_count; j++) { + if (va_profile == profile_list[j]) { + exact_match = profile_match; + break; + } + } + + if (j < profile_count) { + matched_va_profile = va_profile; + matched_ff_profile = codec_profile; + if (exact_match) + break; + } } } av_freep(&profile_list); diff --git a/libavcodec/vaapi_hevc.c b/libavcodec/vaapi_hevc.c index 77f55ff8b1..28f7c9280e 100644 --- a/libavcodec/vaapi_hevc.c +++ b/libavcodec/vaapi_hevc.c @@ -590,63 +590,70 @@ static int ptl_convert(const PTLCommon *general_ptl, H265RawProfileTierLevel *h2 } /* - * Find exact va_profile for HEVC Range Extension and Screen Content Coding Extension + * Find compatible va_profile for HEVC Range Extension and Screen + * Content Coding Extension profiles. */ -VAProfile ff_vaapi_parse_hevc_rext_scc_profile(AVCodecContext *avctx) +VAProfile ff_vaapi_hevc_match_rext_scc_profile(AVCodecContext *avctx, + const VAProfile *profile_list, + int profile_count) { const HEVCContext *h = avctx->priv_data; const HEVCSPS *sps = h->ps.sps; const PTL *ptl = &sps->ptl; const PTLCommon *general_ptl = &ptl->general_ptl; - const H265ProfileDescriptor *profile; H265RawProfileTierLevel h265_raw_ptl = {0}; + static const struct { + int profile; + VAProfile va_profile; + } map[] = { +#if VA_CHECK_VERSION(1, 2, 0) + { H265_PROFILE_MAIN_12, + VAProfileHEVCMain12 }, + { H265_PROFILE_MAIN_422_10, + VAProfileHEVCMain422_10 }, + { H265_PROFILE_MAIN_444, + VAProfileHEVCMain444 }, + { H265_PROFILE_MAIN_444_10, + VAProfileHEVCMain444_10 }, + { H265_PROFILE_MAIN_444_12, + VAProfileHEVCMain444_12 }, + { H265_PROFILE_SCREEN_EXTENDED_MAIN, + VAProfileHEVCSccMain }, + { H265_PROFILE_SCREEN_EXTENDED_MAIN_10, + VAProfileHEVCSccMain10 }, +#endif +#if VA_CHECK_VERSION(1, 8, 0) + { H265_PROFILE_SCREEN_EXTENDED_MAIN_444, + VAProfileHEVCSccMain444 }, +#endif + }; + /* convert PTLCommon to H265RawProfileTierLevel */ ptl_convert(general_ptl, &h265_raw_ptl); - profile = ff_h265_find_profile(&h265_raw_ptl); - if (!profile) { - av_log(avctx, AV_LOG_WARNING, "HEVC profile is not found.\n"); - goto end; - } else { - av_log(avctx, AV_LOG_VERBOSE, "HEVC profile %s is found.\n", profile->name); + for (int i = 0; i < FF_ARRAY_ELEMS(map); i++) { + int available = 0; + for (int j = 0; j < profile_count; j++) { + if (profile_list[j] == map[i].va_profile) { + available = 1; + break; + } + } + if (!available) + continue; + + if (ff_h265_profile_compatible(&h265_raw_ptl, + map[i].profile)) { + const H265ProfileDescriptor *profile_desc = + ff_h265_get_profile(map[i].profile); + av_log(avctx, AV_LOG_VERBOSE, + "Decoding with HEVC profile %s.\n", + profile_desc->name); + return map[i].va_profile; + } } -#if VA_CHECK_VERSION(1, 2, 0) - if (!strcmp(profile->name, "Main 12") || - !strcmp(profile->name, "Main 12 Intra")) - return VAProfileHEVCMain12; - else if (!strcmp(profile->name, "Main 4:2:2 10") || - !strcmp(profile->name, "Main 4:2:2 10 Intra")) - return VAProfileHEVCMain422_10; - else if (!strcmp(profile->name, "Main 4:2:2 12") || - !strcmp(profile->name, "Main 4:2:2 12 Intra")) - return VAProfileHEVCMain422_12; - else if (!strcmp(profile->name, "Main 4:4:4") || - !strcmp(profile->name, "Main 4:4:4 Intra")) - return VAProfileHEVCMain444; - else if (!strcmp(profile->name, "Main 4:4:4 10") || - !strcmp(profile->name, "Main 4:4:4 10 Intra")) - return VAProfileHEVCMain444_10; - else if (!strcmp(profile->name, "Main 4:4:4 12") || - !strcmp(profile->name, "Main 4:4:4 12 Intra")) - return VAProfileHEVCMain444_12; - else if (!strcmp(profile->name, "Screen-Extended Main")) - return VAProfileHEVCSccMain; - else if (!strcmp(profile->name, "Screen-Extended Main 10")) - return VAProfileHEVCSccMain10; - else if (!strcmp(profile->name, "Screen-Extended Main 4:4:4")) - return VAProfileHEVCSccMain444; -#if VA_CHECK_VERSION(1, 8, 0) - else if (!strcmp(profile->name, "Screen-Extended Main 4:4:4 10")) - return VAProfileHEVCSccMain444_10; -#endif -#else - av_log(avctx, AV_LOG_WARNING, "HEVC profile %s is " - "not supported with this VA version.\n", profile->name); -#endif - -end: if (avctx->hwaccel_flags & AV_HWACCEL_FLAG_ALLOW_PROFILE_MISMATCH) { // Default to selecting Main profile if profile mismatch is allowed return VAProfileHEVCMain; diff --git a/libavcodec/vaapi_hevc.h b/libavcodec/vaapi_hevc.h index 449635d0d7..455c68e6ba 100644 --- a/libavcodec/vaapi_hevc.h +++ b/libavcodec/vaapi_hevc.h @@ -22,6 +22,8 @@ #include <va/va.h> #include "avcodec.h" -VAProfile ff_vaapi_parse_hevc_rext_scc_profile(AVCodecContext *avctx); +VAProfile ff_vaapi_hevc_match_rext_scc_profile(AVCodecContext *avctx, + const VAProfile *profile_list, + int profile_count); #endif /* AVCODEC_VAAPI_HEVC_H */