[FFmpeg-devel] [PATCH 2/2] lavc/vaapi_hevc: Don't require exact profiles

Xiang, Haihao haihao.xiang at intel.com
Wed Apr 24 16:45:16 EEST 2024


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 */



More information about the ffmpeg-devel mailing list