[FFmpeg-devel,v4] lavc/vaapi_decode: find exact va_profile for HEVC_REXT

Submitted by Linjie Fu on April 9, 2019, 2:33 a.m.

Details

Message ID 20190409023306.16745-1-linjie.fu@intel.com
State New
Headers show

Commit Message

Linjie Fu April 9, 2019, 2:33 a.m.
Use the profile constraint flags to determine the exact va_profile for
HEVC_REXT.

Directly cast PTLCommon to H265RawProfileTierLevel, and use ff_h265_get_profile
to get the exact profile.

Add h265_profile_level.o to build objects for vaapi_decode to fix the compile
dependency issue.

Signed-off-by: Linjie Fu <linjie.fu@intel.com>
---
[v2]: use constraint flags to determine the exact profile, expose the
codec-specific stuff at the beginning.
[v3]: move the VA version check to fix the compile issue.
[v4]: fix the build issue.

 libavcodec/Makefile       |  2 +-
 libavcodec/vaapi_decode.c | 73 +++++++++++++++++++++++++++++++--------
 2 files changed, 59 insertions(+), 16 deletions(-)

Comments

Mark Thompson April 9, 2019, 11:20 p.m.
On 09/04/2019 03:33, Linjie Fu wrote:
> Use the profile constraint flags to determine the exact va_profile for
> HEVC_REXT.
> 
> Directly cast PTLCommon to H265RawProfileTierLevel,

Please don't.  The two structures aren't really connected, they shouldn't be assumed to be compatible.

>                                                     and use ff_h265_get_profile
> to get the exact profile.
> 
> Add h265_profile_level.o to build objects for vaapi_decode to fix the compile
> dependency issue.
> 
> Signed-off-by: Linjie Fu <linjie.fu@intel.com>
> ---
> [v2]: use constraint flags to determine the exact profile, expose the
> codec-specific stuff at the beginning.
> [v3]: move the VA version check to fix the compile issue.
> [v4]: fix the build issue.
> 
>  libavcodec/Makefile       |  2 +-
>  libavcodec/vaapi_decode.c | 73 +++++++++++++++++++++++++++++++--------
>  2 files changed, 59 insertions(+), 16 deletions(-)
> 
> diff --git a/libavcodec/Makefile b/libavcodec/Makefile
> index 15c43a8a6a..c0df0ad90a 100644
> --- a/libavcodec/Makefile
> +++ b/libavcodec/Makefile
> @@ -857,7 +857,7 @@ OBJS-$(CONFIG_ADPCM_YAMAHA_ENCODER)       += adpcmenc.o adpcm_data.o
>  OBJS-$(CONFIG_D3D11VA)                    += dxva2.o
>  OBJS-$(CONFIG_DXVA2)                      += dxva2.o
>  OBJS-$(CONFIG_NVDEC)                      += nvdec.o
> -OBJS-$(CONFIG_VAAPI)                      += vaapi_decode.o
> +OBJS-$(CONFIG_VAAPI)                      += vaapi_decode.o h265_profile_level.o
>  OBJS-$(CONFIG_VIDEOTOOLBOX)               += videotoolbox.o
>  OBJS-$(CONFIG_VDPAU)                      += vdpau.o
>  
> diff --git a/libavcodec/vaapi_decode.c b/libavcodec/vaapi_decode.c
> index 69512e1d45..47db6c874a 100644
> --- a/libavcodec/vaapi_decode.c
> +++ b/libavcodec/vaapi_decode.c
> @@ -24,6 +24,8 @@
>  #include "decode.h"
>  #include "internal.h"
>  #include "vaapi_decode.h"
> +#include "hevcdec.h"
> +#include "h265_profile_level.h"
>  
>  
>  int ff_vaapi_decode_make_param_buffer(AVCodecContext *avctx,
> @@ -401,6 +403,33 @@ static const struct {
>  #undef MAP
>  };
>  
> +/*
> + * Find exact va_profile for HEVC Range Extension
> + */
> +static VAProfile vaapi_decode_find_exact_profile(AVCodecContext *avctx)
> +{
> +    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;
> +
> +    /* PTLCommon should match the member sequence in H265RawProfileTierLevel*/
> +    profile = ff_h265_get_profile((H265RawProfileTierLevel *)general_ptl);

This can return NULL.

> +
> +#if VA_CHECK_VERSION(1, 2, 0)
> +    if (!strcmp(profile->name, "Main 4:2:2 10"))
> +        return VAProfileHEVCMain422_10;
> +    else if (!strcmp(profile->name, "Main 4:4:4"))
> +        return VAProfileHEVCMain444;
> +    else if (!strcmp(profile->name, "Main 4:4:4 10"))
> +        return VAProfileHEVCMain444_10;
> +#else
> +    av_log(avctx, AV_LOG_WARNING, "HEVC profile %s is "
> +                        "not supported with this VA version.\n", profile->name);
> +#endif
> +    return VAProfileNone;
> +}
>  /*
>   * Set *va_config and the frames_ref fields from the current codec parameters
>   * in avctx.
> @@ -447,24 +476,38 @@ static int vaapi_decode_make_config(AVCodecContext *avctx,
>      matched_va_profile = VAProfileNone;
>      exact_match = 0;
>  
> -    for (i = 0; i < FF_ARRAY_ELEMS(vaapi_profile_map); i++) {
> -        int profile_match = 0;
> -        if (avctx->codec_id != vaapi_profile_map[i].codec_id)
> -            continue;
> -        if (avctx->profile == vaapi_profile_map[i].codec_profile ||
> -            vaapi_profile_map[i].codec_profile == FF_PROFILE_UNKNOWN)
> -            profile_match = 1;
> -        for (j = 0; j < profile_count; j++) {
> -            if (vaapi_profile_map[i].va_profile == profile_list[j]) {
> -                exact_match = profile_match;
> +    if (avctx->profile == FF_PROFILE_HEVC_REXT) {
> +        /* find the exact va_profile for HEVC_REXT */
> +        VAProfile va_profile = vaapi_decode_find_exact_profile(avctx);
> +        for (i = 0; i < profile_count; i++) {
> +            if (va_profile == profile_list[i]) {
> +                exact_match = 1;
> +                matched_va_profile = va_profile;
> +                matched_ff_profile = FF_PROFILE_HEVC_REXT;
>                  break;
>              }
>          }
> -        if (j < profile_count) {
> -            matched_va_profile = vaapi_profile_map[i].va_profile;
> -            matched_ff_profile = vaapi_profile_map[i].codec_profile;
> -            if (exact_match)
> -                break;
> +    } else {
> +        /* find the exact va_profile according to codec_id and profile */
> +        for (i = 0; i < FF_ARRAY_ELEMS(vaapi_profile_map); i++) {
> +            int profile_match = 0;
> +            if (avctx->codec_id != vaapi_profile_map[i].codec_id)
> +                continue;
> +            if (avctx->profile == vaapi_profile_map[i].codec_profile ||
> +                vaapi_profile_map[i].codec_profile == FF_PROFILE_UNKNOWN)
> +                profile_match = 1;
> +            for (j = 0; j < profile_count; j++) {
> +                if (vaapi_profile_map[i].va_profile == profile_list[j]) {
> +                    exact_match = profile_match;
> +                    break;
> +                }
> +            }
> +            if (j < profile_count) {
> +                matched_va_profile = vaapi_profile_map[i].va_profile;
> +                matched_ff_profile = vaapi_profile_map[i].codec_profile;
> +                if (exact_match)
> +                    break;
> +            }
>          }
>      }
>      av_freep(&profile_list);
> 

This misses compatible profiles, and it's still mashing the specific support into the generic code in a way I'm not particularly fond of.

Suppose you split the existing profile matching code inside the loop out into a new function, then add a new function pointer field to vaapi_profile_map[] (NULL for all existing entries) which redirects it to a different implementation in vaapi_hevc.c only for RExt?


Doesn't this also need to pass the SPS range extension fields to the decoder as well to actually support these profiles?  The intent is that if the hwaccel init has returned success then you believe the hardware definitely supports the stream and decoding will succeed - if it's not sure (e.g. it might fail if some feature is enabled), then it should return failure unless the PROFILE_MISMATCH flag is set to allow that case.

- Mark
Linjie Fu April 10, 2019, 9:16 a.m.
> -----Original Message-----

> From: ffmpeg-devel [mailto:ffmpeg-devel-bounces@ffmpeg.org] On Behalf

> Of Mark Thompson

> Sent: Wednesday, April 10, 2019 07:20

> To: ffmpeg-devel@ffmpeg.org

> Subject: Re: [FFmpeg-devel] [PATCH, v4] lavc/vaapi_decode: find exact

> va_profile for HEVC_REXT

> 

> On 09/04/2019 03:33, Linjie Fu wrote:

> > Use the profile constraint flags to determine the exact va_profile for

> > HEVC_REXT.

> >

> > Directly cast PTLCommon to H265RawProfileTierLevel,

> 

> Please don't.  The two structures aren't really connected, they shouldn't be

> assumed to be compatible.

I'm trying to avoid the repeated value passing code from these two structures, and wonder if it's acceptable in community.
Well,  will find some other ways to pass the flags.
> 

> >                                                     and use ff_h265_get_profile

> > to get the exact profile.

> >

> > Add h265_profile_level.o to build objects for vaapi_decode to fix the

> compile

> > dependency issue.

> >

> > Signed-off-by: Linjie Fu <linjie.fu@intel.com>

> > ---

> > [v2]: use constraint flags to determine the exact profile, expose the

> > codec-specific stuff at the beginning.

> > [v3]: move the VA version check to fix the compile issue.

> > [v4]: fix the build issue.

> >

> >  libavcodec/Makefile       |  2 +-

> >  libavcodec/vaapi_decode.c | 73 +++++++++++++++++++++++++++++++--

> ------

> >  2 files changed, 59 insertions(+), 16 deletions(-)

> >

> > diff --git a/libavcodec/Makefile b/libavcodec/Makefile

> > index 15c43a8a6a..c0df0ad90a 100644

> > --- a/libavcodec/Makefile

> > +++ b/libavcodec/Makefile

> > @@ -857,7 +857,7 @@ OBJS-$(CONFIG_ADPCM_YAMAHA_ENCODER)

> += adpcmenc.o adpcm_data.o

> >  OBJS-$(CONFIG_D3D11VA)                    += dxva2.o

> >  OBJS-$(CONFIG_DXVA2)                      += dxva2.o

> >  OBJS-$(CONFIG_NVDEC)                      += nvdec.o

> > -OBJS-$(CONFIG_VAAPI)                      += vaapi_decode.o

> > +OBJS-$(CONFIG_VAAPI)                      += vaapi_decode.o

> h265_profile_level.o

> >  OBJS-$(CONFIG_VIDEOTOOLBOX)               += videotoolbox.o

> >  OBJS-$(CONFIG_VDPAU)                      += vdpau.o

> >

> > diff --git a/libavcodec/vaapi_decode.c b/libavcodec/vaapi_decode.c

> > index 69512e1d45..47db6c874a 100644

> > --- a/libavcodec/vaapi_decode.c

> > +++ b/libavcodec/vaapi_decode.c

> > @@ -24,6 +24,8 @@

> >  #include "decode.h"

> >  #include "internal.h"

> >  #include "vaapi_decode.h"

> > +#include "hevcdec.h"

> > +#include "h265_profile_level.h"

> >

> >

> >  int ff_vaapi_decode_make_param_buffer(AVCodecContext *avctx,

> > @@ -401,6 +403,33 @@ static const struct {

> >  #undef MAP

> >  };

> >

> > +/*

> > + * Find exact va_profile for HEVC Range Extension

> > + */

> > +static VAProfile vaapi_decode_find_exact_profile(AVCodecContext

> *avctx)

> > +{

> > +    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;

> > +

> > +    /* PTLCommon should match the member sequence in

> H265RawProfileTierLevel*/

> > +    profile = ff_h265_get_profile((H265RawProfileTierLevel *)general_ptl);

> 

> This can return NULL.


Opus, this should be checked, thanks.

> > +

> > +#if VA_CHECK_VERSION(1, 2, 0)

> > +    if (!strcmp(profile->name, "Main 4:2:2 10"))

> > +        return VAProfileHEVCMain422_10;

> > +    else if (!strcmp(profile->name, "Main 4:4:4"))

> > +        return VAProfileHEVCMain444;

> > +    else if (!strcmp(profile->name, "Main 4:4:4 10"))

> > +        return VAProfileHEVCMain444_10;

> > +#else

> > +    av_log(avctx, AV_LOG_WARNING, "HEVC profile %s is "

> > +                        "not supported with this VA version.\n", profile->name);

> > +#endif

> > +    return VAProfileNone;

> > +}

> >  /*

> >   * Set *va_config and the frames_ref fields from the current codec

> parameters

> >   * in avctx.

> > @@ -447,24 +476,38 @@ static int

> vaapi_decode_make_config(AVCodecContext *avctx,

> >      matched_va_profile = VAProfileNone;

> >      exact_match = 0;

> >

> > -    for (i = 0; i < FF_ARRAY_ELEMS(vaapi_profile_map); i++) {

> > -        int profile_match = 0;

> > -        if (avctx->codec_id != vaapi_profile_map[i].codec_id)

> > -            continue;

> > -        if (avctx->profile == vaapi_profile_map[i].codec_profile ||

> > -            vaapi_profile_map[i].codec_profile == FF_PROFILE_UNKNOWN)

> > -            profile_match = 1;

> > -        for (j = 0; j < profile_count; j++) {

> > -            if (vaapi_profile_map[i].va_profile == profile_list[j]) {

> > -                exact_match = profile_match;

> > +    if (avctx->profile == FF_PROFILE_HEVC_REXT) {

> > +        /* find the exact va_profile for HEVC_REXT */

> > +        VAProfile va_profile = vaapi_decode_find_exact_profile(avctx);

> > +        for (i = 0; i < profile_count; i++) {

> > +            if (va_profile == profile_list[i]) {

> > +                exact_match = 1;

> > +                matched_va_profile = va_profile;

> > +                matched_ff_profile = FF_PROFILE_HEVC_REXT;

> >                  break;

> >              }

> >          }

> > -        if (j < profile_count) {

> > -            matched_va_profile = vaapi_profile_map[i].va_profile;

> > -            matched_ff_profile = vaapi_profile_map[i].codec_profile;

> > -            if (exact_match)

> > -                break;

> > +    } else {

> > +        /* find the exact va_profile according to codec_id and profile */

> > +        for (i = 0; i < FF_ARRAY_ELEMS(vaapi_profile_map); i++) {

> > +            int profile_match = 0;

> > +            if (avctx->codec_id != vaapi_profile_map[i].codec_id)

> > +                continue;

> > +            if (avctx->profile == vaapi_profile_map[i].codec_profile ||

> > +                vaapi_profile_map[i].codec_profile == FF_PROFILE_UNKNOWN)

> > +                profile_match = 1;

> > +            for (j = 0; j < profile_count; j++) {

> > +                if (vaapi_profile_map[i].va_profile == profile_list[j]) {

> > +                    exact_match = profile_match;

> > +                    break;

> > +                }

> > +            }

> > +            if (j < profile_count) {

> > +                matched_va_profile = vaapi_profile_map[i].va_profile;

> > +                matched_ff_profile = vaapi_profile_map[i].codec_profile;

> > +                if (exact_match)

> > +                    break;

> > +            }

> >          }

> >      }

> >      av_freep(&profile_list);

> >

> 

> This misses compatible profiles, and it's still mashing the specific support into

> the generic code in a way I'm not particularly fond of.

> 

Did you mean "general_profile_compatibility_flag[]"?
general_profile_compatibility_flags are also taken into account  and used in ff_h265_get_profile();

> Suppose you split the existing profile matching code inside the loop out into a

> new function, then add a new function pointer field to vaapi_profile_map[]

> (NULL for all existing entries) which redirects it to a different implementation

> in vaapi_hevc.c only for RExt?

> 

Will try to move the code, thanks for the advice.
> 

> Doesn't this also need to pass the SPS range extension fields to the decoder

> as well to actually support these profiles?  The intent is that if the hwaccel init

> has returned success then you believe the hardware definitely supports the

> stream and decoding will succeed - if it's not sure (e.g. it might fail if some

> feature is enabled), then it should return failure unless the

> PROFILE_MISMATCH flag is set to allow that case.

Patch hide | download patch | download mbox

diff --git a/libavcodec/Makefile b/libavcodec/Makefile
index 15c43a8a6a..c0df0ad90a 100644
--- a/libavcodec/Makefile
+++ b/libavcodec/Makefile
@@ -857,7 +857,7 @@  OBJS-$(CONFIG_ADPCM_YAMAHA_ENCODER)       += adpcmenc.o adpcm_data.o
 OBJS-$(CONFIG_D3D11VA)                    += dxva2.o
 OBJS-$(CONFIG_DXVA2)                      += dxva2.o
 OBJS-$(CONFIG_NVDEC)                      += nvdec.o
-OBJS-$(CONFIG_VAAPI)                      += vaapi_decode.o
+OBJS-$(CONFIG_VAAPI)                      += vaapi_decode.o h265_profile_level.o
 OBJS-$(CONFIG_VIDEOTOOLBOX)               += videotoolbox.o
 OBJS-$(CONFIG_VDPAU)                      += vdpau.o
 
diff --git a/libavcodec/vaapi_decode.c b/libavcodec/vaapi_decode.c
index 69512e1d45..47db6c874a 100644
--- a/libavcodec/vaapi_decode.c
+++ b/libavcodec/vaapi_decode.c
@@ -24,6 +24,8 @@ 
 #include "decode.h"
 #include "internal.h"
 #include "vaapi_decode.h"
+#include "hevcdec.h"
+#include "h265_profile_level.h"
 
 
 int ff_vaapi_decode_make_param_buffer(AVCodecContext *avctx,
@@ -401,6 +403,33 @@  static const struct {
 #undef MAP
 };
 
+/*
+ * Find exact va_profile for HEVC Range Extension
+ */
+static VAProfile vaapi_decode_find_exact_profile(AVCodecContext *avctx)
+{
+    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;
+
+    /* PTLCommon should match the member sequence in H265RawProfileTierLevel*/
+    profile = ff_h265_get_profile((H265RawProfileTierLevel *)general_ptl);
+
+#if VA_CHECK_VERSION(1, 2, 0)
+    if (!strcmp(profile->name, "Main 4:2:2 10"))
+        return VAProfileHEVCMain422_10;
+    else if (!strcmp(profile->name, "Main 4:4:4"))
+        return VAProfileHEVCMain444;
+    else if (!strcmp(profile->name, "Main 4:4:4 10"))
+        return VAProfileHEVCMain444_10;
+#else
+    av_log(avctx, AV_LOG_WARNING, "HEVC profile %s is "
+                        "not supported with this VA version.\n", profile->name);
+#endif
+    return VAProfileNone;
+}
 /*
  * Set *va_config and the frames_ref fields from the current codec parameters
  * in avctx.
@@ -447,24 +476,38 @@  static int vaapi_decode_make_config(AVCodecContext *avctx,
     matched_va_profile = VAProfileNone;
     exact_match = 0;
 
-    for (i = 0; i < FF_ARRAY_ELEMS(vaapi_profile_map); i++) {
-        int profile_match = 0;
-        if (avctx->codec_id != vaapi_profile_map[i].codec_id)
-            continue;
-        if (avctx->profile == vaapi_profile_map[i].codec_profile ||
-            vaapi_profile_map[i].codec_profile == FF_PROFILE_UNKNOWN)
-            profile_match = 1;
-        for (j = 0; j < profile_count; j++) {
-            if (vaapi_profile_map[i].va_profile == profile_list[j]) {
-                exact_match = profile_match;
+    if (avctx->profile == FF_PROFILE_HEVC_REXT) {
+        /* find the exact va_profile for HEVC_REXT */
+        VAProfile va_profile = vaapi_decode_find_exact_profile(avctx);
+        for (i = 0; i < profile_count; i++) {
+            if (va_profile == profile_list[i]) {
+                exact_match = 1;
+                matched_va_profile = va_profile;
+                matched_ff_profile = FF_PROFILE_HEVC_REXT;
                 break;
             }
         }
-        if (j < profile_count) {
-            matched_va_profile = vaapi_profile_map[i].va_profile;
-            matched_ff_profile = vaapi_profile_map[i].codec_profile;
-            if (exact_match)
-                break;
+    } else {
+        /* find the exact va_profile according to codec_id and profile */
+        for (i = 0; i < FF_ARRAY_ELEMS(vaapi_profile_map); i++) {
+            int profile_match = 0;
+            if (avctx->codec_id != vaapi_profile_map[i].codec_id)
+                continue;
+            if (avctx->profile == vaapi_profile_map[i].codec_profile ||
+                vaapi_profile_map[i].codec_profile == FF_PROFILE_UNKNOWN)
+                profile_match = 1;
+            for (j = 0; j < profile_count; j++) {
+                if (vaapi_profile_map[i].va_profile == profile_list[j]) {
+                    exact_match = profile_match;
+                    break;
+                }
+            }
+            if (j < profile_count) {
+                matched_va_profile = vaapi_profile_map[i].va_profile;
+                matched_ff_profile = vaapi_profile_map[i].codec_profile;
+                if (exact_match)
+                    break;
+            }
         }
     }
     av_freep(&profile_list);