Git Inbox Mirror of the ffmpeg-devel mailing list - see https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
 help / color / mirror / Atom feed
* [FFmpeg-devel] [PATCH v7 3/4] avcodec/hevc: Add alpha layer support
@ 2025-02-11 13:21 Zhao Zhili
  2025-02-11 15:37 ` Andreas Rheinhardt
  0 siblings, 1 reply; 11+ messages in thread
From: Zhao Zhili @ 2025-02-11 13:21 UTC (permalink / raw)
  To: ffmpeg-devel; +Cc: Zhao Zhili

From: Zhao Zhili <zhilizhao@tencent.com>

Signed-off-by: Zhao Zhili <zhilizhao@tencent.com>
---
 libavcodec/hevc/hevcdec.c | 73 ++++++++++++++++++++++++++++++++++++++-
 libavcodec/hevc/hevcdec.h |  2 ++
 libavcodec/hevc/refs.c    | 35 ++++++++++++++++++-
 3 files changed, 108 insertions(+), 2 deletions(-)

diff --git a/libavcodec/hevc/hevcdec.c b/libavcodec/hevc/hevcdec.c
index e9c045f7a1..f71edf213b 100644
--- a/libavcodec/hevc/hevcdec.c
+++ b/libavcodec/hevc/hevcdec.c
@@ -466,6 +466,25 @@ static int export_multilayer(HEVCContext *s, const HEVCVPS *vps)
     return 0;
 }
 
+int ff_hevc_is_alpha_video(const HEVCContext *s)
+{
+    const HEVCVPS *vps = s->vps;
+    int ret = 0;
+
+    if (vps->nb_layers != 2 || !vps->layer_id_in_nuh[1])
+        return 0;
+
+    /* decode_vps_ext() guarantees that SCALABILITY_AUXILIARY with AuxId other
+     * than alpha cannot reach here.
+     */
+    ret = (s->vps->scalability_mask_flag & HEVC_SCALABILITY_AUXILIARY);
+
+    av_log(s->avctx, AV_LOG_DEBUG, "Multi layer video, %s alpha video\n",
+           ret ? "is" : "not");
+
+    return ret;
+}
+
 static int setup_multilayer(HEVCContext *s, const HEVCVPS *vps)
 {
     unsigned layers_active_output = 0, highest_layer;
@@ -473,6 +492,18 @@ static int setup_multilayer(HEVCContext *s, const HEVCVPS *vps)
     s->layers_active_output = 1;
     s->layers_active_decode = 1;
 
+    if (ff_hevc_is_alpha_video(s)) {
+        const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(s->avctx->pix_fmt);
+
+        if (!(desc->flags & AV_PIX_FMT_FLAG_ALPHA))
+            return 0;
+
+        s->layers_active_decode = (1 << vps->nb_layers) - 1;
+        s->layers_active_output = 1;
+
+        return 0;
+    }
+
     // nothing requested - decode base layer only
     if (!s->nb_view_ids)
         return 0;
@@ -530,6 +561,34 @@ static int setup_multilayer(HEVCContext *s, const HEVCVPS *vps)
     return 0;
 }
 
+static enum AVPixelFormat map_to_alpha_format(HEVCContext *s,
+                                              enum AVPixelFormat pix_fmt)
+{
+    switch (pix_fmt) {
+    case AV_PIX_FMT_YUV420P:
+    case AV_PIX_FMT_YUVJ420P:
+        return AV_PIX_FMT_YUVA420P;
+    case AV_PIX_FMT_YUV420P10:
+        return AV_PIX_FMT_YUVA420P10;
+    case AV_PIX_FMT_YUV444P:
+        return AV_PIX_FMT_YUVA444P;
+    case AV_PIX_FMT_YUV422P:
+        return AV_PIX_FMT_YUVA422P;
+    case AV_PIX_FMT_YUV422P10LE:
+        return AV_PIX_FMT_YUVA422P10LE;
+    case AV_PIX_FMT_YUV444P10:
+        return AV_PIX_FMT_YUVA444P10;
+    case AV_PIX_FMT_YUV444P12:
+        return AV_PIX_FMT_YUVA444P12;
+    case AV_PIX_FMT_YUV422P12:
+        return AV_PIX_FMT_YUVA422P12;
+    default:
+        av_log(s->avctx, AV_LOG_WARNING, "No alpha pixel format map for %s\n",
+               av_get_pix_fmt_name(pix_fmt));
+        return AV_PIX_FMT_NONE;
+    }
+}
+
 static enum AVPixelFormat get_format(HEVCContext *s, const HEVCSPS *sps)
 {
 #define HWACCEL_MAX (CONFIG_HEVC_DXVA2_HWACCEL + \
@@ -540,9 +599,13 @@ static enum AVPixelFormat get_format(HEVCContext *s, const HEVCSPS *sps)
                      CONFIG_HEVC_VIDEOTOOLBOX_HWACCEL + \
                      CONFIG_HEVC_VDPAU_HWACCEL + \
                      CONFIG_HEVC_VULKAN_HWACCEL)
-    enum AVPixelFormat pix_fmts[HWACCEL_MAX + 2], *fmt = pix_fmts;
+    enum AVPixelFormat pix_fmts[HWACCEL_MAX + 3], *fmt = pix_fmts;
+    enum AVPixelFormat alpha_fmt = AV_PIX_FMT_NONE;
     int ret;
 
+    if (ff_hevc_is_alpha_video(s))
+        alpha_fmt = map_to_alpha_format(s, sps->pix_fmt);
+
     switch (sps->pix_fmt) {
     case AV_PIX_FMT_YUV420P:
     case AV_PIX_FMT_YUVJ420P:
@@ -664,6 +727,8 @@ static enum AVPixelFormat get_format(HEVCContext *s, const HEVCSPS *sps)
         break;
     }
 
+    if (alpha_fmt != AV_PIX_FMT_NONE)
+        *fmt++ = alpha_fmt;
     *fmt++ = sps->pix_fmt;
     *fmt = AV_PIX_FMT_NONE;
 
@@ -3194,6 +3259,12 @@ static int hevc_frame_start(HEVCContext *s, HEVCLayerContext *l,
                 !sps->vui.common.video_signal_type_present_flag)
                 pix_fmt = sps_base->pix_fmt;
 
+            // Ignore range mismatch between base layer and alpha layer
+            if (ff_hevc_is_alpha_video(s) &&
+                sps_base->pix_fmt == AV_PIX_FMT_YUV420P &&
+                pix_fmt == AV_PIX_FMT_YUVJ420P)
+                pix_fmt = sps_base->pix_fmt;
+
             if (pix_fmt     != sps_base->pix_fmt ||
                 sps->width  != sps_base->width   ||
                 sps->height != sps_base->height) {
diff --git a/libavcodec/hevc/hevcdec.h b/libavcodec/hevc/hevcdec.h
index 4e95035688..b2b725b5cd 100644
--- a/libavcodec/hevc/hevcdec.h
+++ b/libavcodec/hevc/hevcdec.h
@@ -714,6 +714,8 @@ void ff_hevc_hls_residual_coding(HEVCLocalContext *lc, const HEVCPPS *pps,
 
 void ff_hevc_hls_mvd_coding(HEVCLocalContext *lc, int x0, int y0, int log2_cb_size);
 
+int ff_hevc_is_alpha_video(const HEVCContext *s);
+
 extern const uint8_t ff_hevc_qpel_extra_before[4];
 extern const uint8_t ff_hevc_qpel_extra_after[4];
 extern const uint8_t ff_hevc_qpel_extra[4];
diff --git a/libavcodec/hevc/refs.c b/libavcodec/hevc/refs.c
index dd7f7f95a8..6f10efd0ac 100644
--- a/libavcodec/hevc/refs.c
+++ b/libavcodec/hevc/refs.c
@@ -79,6 +79,31 @@ void ff_hevc_flush_dpb(HEVCContext *s)
     }
 }
 
+static int replace_alpha_plane(AVFrame *alpha, AVFrame *base)
+{
+    AVBufferRef *base_a = av_frame_get_plane_buffer(base, 3);
+    uintptr_t data = (uintptr_t)alpha->data[0];
+    int ret;
+
+    for (int i = 0; i < FF_ARRAY_ELEMS(alpha->buf) && alpha->buf[i]; i++) {
+        AVBufferRef *buf = alpha->buf[i];
+        uintptr_t buf_begin = (uintptr_t)buf->data;
+
+        if (data >=  buf_begin && data < buf_begin + buf->size) {
+            ret = av_buffer_replace(&alpha->buf[i], base_a);
+            if (ret < 0)
+                return ret;
+
+            alpha->linesize[0] = base->linesize[3];
+            alpha->data[0] = base->data[3];
+
+            return 0;
+        }
+    }
+
+    return AVERROR_BUG;
+}
+
 static HEVCFrame *alloc_frame(HEVCContext *s, HEVCLayerContext *l)
 {
     const HEVCVPS *vps = l->sps->vps;
@@ -103,7 +128,7 @@ static HEVCFrame *alloc_frame(HEVCContext *s, HEVCLayerContext *l)
         }
 
         // add view ID side data if it's nontrivial
-        if (vps->nb_layers > 1 || view_id) {
+        if (!ff_hevc_is_alpha_video(s) && (vps->nb_layers > 1 || view_id)) {
             HEVCSEITDRDI *tdrdi = &s->sei.tdrdi;
             AVFrameSideData *sd = av_frame_side_data_new(&frame->f->side_data,
                                                          &frame->f->nb_side_data,
@@ -161,7 +186,15 @@ static HEVCFrame *alloc_frame(HEVCContext *s, HEVCLayerContext *l)
         if (ret < 0)
             goto fail;
 
+
         frame->pps = av_refstruct_ref_c(s->pps);
+        if (l != &s->layers[0] && ff_hevc_is_alpha_video(s)) {
+            AVFrame *alpha = frame->f;
+            AVFrame *base = s->layers[0].cur_frame->f;
+            ret = replace_alpha_plane(alpha, base);
+            if (ret < 0)
+                goto fail;
+        }
 
         return frame;
 fail:
-- 
2.46.0

_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel

To unsubscribe, visit link above, or email
ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [FFmpeg-devel] [PATCH v7 3/4] avcodec/hevc: Add alpha layer support
  2025-02-11 13:21 [FFmpeg-devel] [PATCH v7 3/4] avcodec/hevc: Add alpha layer support Zhao Zhili
@ 2025-02-11 15:37 ` Andreas Rheinhardt
  2025-02-11 15:57   ` Zhao Zhili
  0 siblings, 1 reply; 11+ messages in thread
From: Andreas Rheinhardt @ 2025-02-11 15:37 UTC (permalink / raw)
  To: ffmpeg-devel

Zhao Zhili:
> From: Zhao Zhili <zhilizhao@tencent.com>
> 
> Signed-off-by: Zhao Zhili <zhilizhao@tencent.com>
> ---
>  libavcodec/hevc/hevcdec.c | 73 ++++++++++++++++++++++++++++++++++++++-
>  libavcodec/hevc/hevcdec.h |  2 ++
>  libavcodec/hevc/refs.c    | 35 ++++++++++++++++++-
>  3 files changed, 108 insertions(+), 2 deletions(-)
> 
> diff --git a/libavcodec/hevc/hevcdec.c b/libavcodec/hevc/hevcdec.c
> index e9c045f7a1..f71edf213b 100644
> --- a/libavcodec/hevc/hevcdec.c
> +++ b/libavcodec/hevc/hevcdec.c
> @@ -466,6 +466,25 @@ static int export_multilayer(HEVCContext *s, const HEVCVPS *vps)
>      return 0;
>  }
>  
> +int ff_hevc_is_alpha_video(const HEVCContext *s)
> +{
> +    const HEVCVPS *vps = s->vps;
> +    int ret = 0;
> +
> +    if (vps->nb_layers != 2 || !vps->layer_id_in_nuh[1])
> +        return 0;
> +
> +    /* decode_vps_ext() guarantees that SCALABILITY_AUXILIARY with AuxId other
> +     * than alpha cannot reach here.
> +     */
> +    ret = (s->vps->scalability_mask_flag & HEVC_SCALABILITY_AUXILIARY);
> +
> +    av_log(s->avctx, AV_LOG_DEBUG, "Multi layer video, %s alpha video\n",
> +           ret ? "is" : "not");
> +
> +    return ret;
> +}
> +
>  static int setup_multilayer(HEVCContext *s, const HEVCVPS *vps)
>  {
>      unsigned layers_active_output = 0, highest_layer;
> @@ -473,6 +492,18 @@ static int setup_multilayer(HEVCContext *s, const HEVCVPS *vps)
>      s->layers_active_output = 1;
>      s->layers_active_decode = 1;
>  
> +    if (ff_hevc_is_alpha_video(s)) {
> +        const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(s->avctx->pix_fmt);
> +
> +        if (!(desc->flags & AV_PIX_FMT_FLAG_ALPHA))
> +            return 0;
> +
> +        s->layers_active_decode = (1 << vps->nb_layers) - 1;
> +        s->layers_active_output = 1;
> +
> +        return 0;
> +    }
> +
>      // nothing requested - decode base layer only
>      if (!s->nb_view_ids)
>          return 0;
> @@ -530,6 +561,34 @@ static int setup_multilayer(HEVCContext *s, const HEVCVPS *vps)
>      return 0;
>  }
>  
> +static enum AVPixelFormat map_to_alpha_format(HEVCContext *s,
> +                                              enum AVPixelFormat pix_fmt)
> +{
> +    switch (pix_fmt) {
> +    case AV_PIX_FMT_YUV420P:
> +    case AV_PIX_FMT_YUVJ420P:
> +        return AV_PIX_FMT_YUVA420P;
> +    case AV_PIX_FMT_YUV420P10:
> +        return AV_PIX_FMT_YUVA420P10;
> +    case AV_PIX_FMT_YUV444P:
> +        return AV_PIX_FMT_YUVA444P;
> +    case AV_PIX_FMT_YUV422P:
> +        return AV_PIX_FMT_YUVA422P;
> +    case AV_PIX_FMT_YUV422P10LE:
> +        return AV_PIX_FMT_YUVA422P10LE;
> +    case AV_PIX_FMT_YUV444P10:
> +        return AV_PIX_FMT_YUVA444P10;
> +    case AV_PIX_FMT_YUV444P12:
> +        return AV_PIX_FMT_YUVA444P12;
> +    case AV_PIX_FMT_YUV422P12:
> +        return AV_PIX_FMT_YUVA422P12;
> +    default:
> +        av_log(s->avctx, AV_LOG_WARNING, "No alpha pixel format map for %s\n",
> +               av_get_pix_fmt_name(pix_fmt));
> +        return AV_PIX_FMT_NONE;
> +    }
> +}
> +
>  static enum AVPixelFormat get_format(HEVCContext *s, const HEVCSPS *sps)
>  {
>  #define HWACCEL_MAX (CONFIG_HEVC_DXVA2_HWACCEL + \
> @@ -540,9 +599,13 @@ static enum AVPixelFormat get_format(HEVCContext *s, const HEVCSPS *sps)
>                       CONFIG_HEVC_VIDEOTOOLBOX_HWACCEL + \
>                       CONFIG_HEVC_VDPAU_HWACCEL + \
>                       CONFIG_HEVC_VULKAN_HWACCEL)
> -    enum AVPixelFormat pix_fmts[HWACCEL_MAX + 2], *fmt = pix_fmts;
> +    enum AVPixelFormat pix_fmts[HWACCEL_MAX + 3], *fmt = pix_fmts;
> +    enum AVPixelFormat alpha_fmt = AV_PIX_FMT_NONE;
>      int ret;
>  
> +    if (ff_hevc_is_alpha_video(s))
> +        alpha_fmt = map_to_alpha_format(s, sps->pix_fmt);
> +
>      switch (sps->pix_fmt) {
>      case AV_PIX_FMT_YUV420P:
>      case AV_PIX_FMT_YUVJ420P:
> @@ -664,6 +727,8 @@ static enum AVPixelFormat get_format(HEVCContext *s, const HEVCSPS *sps)
>          break;
>      }
>  
> +    if (alpha_fmt != AV_PIX_FMT_NONE)
> +        *fmt++ = alpha_fmt;
>      *fmt++ = sps->pix_fmt;
>      *fmt = AV_PIX_FMT_NONE;
>  
> @@ -3194,6 +3259,12 @@ static int hevc_frame_start(HEVCContext *s, HEVCLayerContext *l,
>                  !sps->vui.common.video_signal_type_present_flag)
>                  pix_fmt = sps_base->pix_fmt;
>  
> +            // Ignore range mismatch between base layer and alpha layer
> +            if (ff_hevc_is_alpha_video(s) &&
> +                sps_base->pix_fmt == AV_PIX_FMT_YUV420P &&
> +                pix_fmt == AV_PIX_FMT_YUVJ420P)
> +                pix_fmt = sps_base->pix_fmt;
> +
>              if (pix_fmt     != sps_base->pix_fmt ||
>                  sps->width  != sps_base->width   ||
>                  sps->height != sps_base->height) {
> diff --git a/libavcodec/hevc/hevcdec.h b/libavcodec/hevc/hevcdec.h
> index 4e95035688..b2b725b5cd 100644
> --- a/libavcodec/hevc/hevcdec.h
> +++ b/libavcodec/hevc/hevcdec.h
> @@ -714,6 +714,8 @@ void ff_hevc_hls_residual_coding(HEVCLocalContext *lc, const HEVCPPS *pps,
>  
>  void ff_hevc_hls_mvd_coding(HEVCLocalContext *lc, int x0, int y0, int log2_cb_size);
>  
> +int ff_hevc_is_alpha_video(const HEVCContext *s);
> +
>  extern const uint8_t ff_hevc_qpel_extra_before[4];
>  extern const uint8_t ff_hevc_qpel_extra_after[4];
>  extern const uint8_t ff_hevc_qpel_extra[4];
> diff --git a/libavcodec/hevc/refs.c b/libavcodec/hevc/refs.c
> index dd7f7f95a8..6f10efd0ac 100644
> --- a/libavcodec/hevc/refs.c
> +++ b/libavcodec/hevc/refs.c
> @@ -79,6 +79,31 @@ void ff_hevc_flush_dpb(HEVCContext *s)
>      }
>  }
>  
> +static int replace_alpha_plane(AVFrame *alpha, AVFrame *base)
> +{
> +    AVBufferRef *base_a = av_frame_get_plane_buffer(base, 3);
> +    uintptr_t data = (uintptr_t)alpha->data[0];
> +    int ret;
> +
> +    for (int i = 0; i < FF_ARRAY_ELEMS(alpha->buf) && alpha->buf[i]; i++) {
> +        AVBufferRef *buf = alpha->buf[i];
> +        uintptr_t buf_begin = (uintptr_t)buf->data;
> +
> +        if (data >=  buf_begin && data < buf_begin + buf->size) {
> +            ret = av_buffer_replace(&alpha->buf[i], base_a);
> +            if (ret < 0)
> +                return ret;
> +
> +            alpha->linesize[0] = base->linesize[3];
> +            alpha->data[0] = base->data[3];
> +
> +            return 0;
> +        }
> +    }

Why does the decoding process actually need multiple references to the
buffer of the alpha plane?

> +
> +    return AVERROR_BUG;
> +}
> +
>  static HEVCFrame *alloc_frame(HEVCContext *s, HEVCLayerContext *l)
>  {
>      const HEVCVPS *vps = l->sps->vps;
> @@ -103,7 +128,7 @@ static HEVCFrame *alloc_frame(HEVCContext *s, HEVCLayerContext *l)
>          }
>  
>          // add view ID side data if it's nontrivial
> -        if (vps->nb_layers > 1 || view_id) {
> +        if (!ff_hevc_is_alpha_video(s) && (vps->nb_layers > 1 || view_id)) {
>              HEVCSEITDRDI *tdrdi = &s->sei.tdrdi;
>              AVFrameSideData *sd = av_frame_side_data_new(&frame->f->side_data,
>                                                           &frame->f->nb_side_data,
> @@ -161,7 +186,15 @@ static HEVCFrame *alloc_frame(HEVCContext *s, HEVCLayerContext *l)
>          if (ret < 0)
>              goto fail;
>  
> +
>          frame->pps = av_refstruct_ref_c(s->pps);
> +        if (l != &s->layers[0] && ff_hevc_is_alpha_video(s)) {
> +            AVFrame *alpha = frame->f;
> +            AVFrame *base = s->layers[0].cur_frame->f;
> +            ret = replace_alpha_plane(alpha, base);
> +            if (ret < 0)
> +                goto fail;
> +        }
>  
>          return frame;
>  fail:

_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel

To unsubscribe, visit link above, or email
ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [FFmpeg-devel] [PATCH v7 3/4] avcodec/hevc: Add alpha layer support
  2025-02-11 15:37 ` Andreas Rheinhardt
@ 2025-02-11 15:57   ` Zhao Zhili
  2025-02-11 16:02     ` James Almer
  2025-02-11 16:10     ` Andreas Rheinhardt
  0 siblings, 2 replies; 11+ messages in thread
From: Zhao Zhili @ 2025-02-11 15:57 UTC (permalink / raw)
  To: FFmpeg development discussions and patches



> On Feb 11, 2025, at 23:37, Andreas Rheinhardt <andreas.rheinhardt@outlook.com> wrote:
> 
> Zhao Zhili:
>> From: Zhao Zhili <zhilizhao@tencent.com>
>> 
>> Signed-off-by: Zhao Zhili <zhilizhao@tencent.com>
>> ---
>> libavcodec/hevc/hevcdec.c | 73 ++++++++++++++++++++++++++++++++++++++-
>> libavcodec/hevc/hevcdec.h |  2 ++
>> libavcodec/hevc/refs.c    | 35 ++++++++++++++++++-
>> 3 files changed, 108 insertions(+), 2 deletions(-)
>> 
>> diff --git a/libavcodec/hevc/hevcdec.c b/libavcodec/hevc/hevcdec.c
>> index e9c045f7a1..f71edf213b 100644
>> --- a/libavcodec/hevc/hevcdec.c
>> +++ b/libavcodec/hevc/hevcdec.c
>> @@ -466,6 +466,25 @@ static int export_multilayer(HEVCContext *s, const HEVCVPS *vps)
>>     return 0;
>> }
>> 
>> +int ff_hevc_is_alpha_video(const HEVCContext *s)
>> +{
>> +    const HEVCVPS *vps = s->vps;
>> +    int ret = 0;
>> +
>> +    if (vps->nb_layers != 2 || !vps->layer_id_in_nuh[1])
>> +        return 0;
>> +
>> +    /* decode_vps_ext() guarantees that SCALABILITY_AUXILIARY with AuxId other
>> +     * than alpha cannot reach here.
>> +     */
>> +    ret = (s->vps->scalability_mask_flag & HEVC_SCALABILITY_AUXILIARY);
>> +
>> +    av_log(s->avctx, AV_LOG_DEBUG, "Multi layer video, %s alpha video\n",
>> +           ret ? "is" : "not");
>> +
>> +    return ret;
>> +}
>> +
>> static int setup_multilayer(HEVCContext *s, const HEVCVPS *vps)
>> {
>>     unsigned layers_active_output = 0, highest_layer;
>> @@ -473,6 +492,18 @@ static int setup_multilayer(HEVCContext *s, const HEVCVPS *vps)
>>     s->layers_active_output = 1;
>>     s->layers_active_decode = 1;
>> 
>> +    if (ff_hevc_is_alpha_video(s)) {
>> +        const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(s->avctx->pix_fmt);
>> +
>> +        if (!(desc->flags & AV_PIX_FMT_FLAG_ALPHA))
>> +            return 0;
>> +
>> +        s->layers_active_decode = (1 << vps->nb_layers) - 1;
>> +        s->layers_active_output = 1;
>> +
>> +        return 0;
>> +    }
>> +
>>     // nothing requested - decode base layer only
>>     if (!s->nb_view_ids)
>>         return 0;
>> @@ -530,6 +561,34 @@ static int setup_multilayer(HEVCContext *s, const HEVCVPS *vps)
>>     return 0;
>> }
>> 
>> +static enum AVPixelFormat map_to_alpha_format(HEVCContext *s,
>> +                                              enum AVPixelFormat pix_fmt)
>> +{
>> +    switch (pix_fmt) {
>> +    case AV_PIX_FMT_YUV420P:
>> +    case AV_PIX_FMT_YUVJ420P:
>> +        return AV_PIX_FMT_YUVA420P;
>> +    case AV_PIX_FMT_YUV420P10:
>> +        return AV_PIX_FMT_YUVA420P10;
>> +    case AV_PIX_FMT_YUV444P:
>> +        return AV_PIX_FMT_YUVA444P;
>> +    case AV_PIX_FMT_YUV422P:
>> +        return AV_PIX_FMT_YUVA422P;
>> +    case AV_PIX_FMT_YUV422P10LE:
>> +        return AV_PIX_FMT_YUVA422P10LE;
>> +    case AV_PIX_FMT_YUV444P10:
>> +        return AV_PIX_FMT_YUVA444P10;
>> +    case AV_PIX_FMT_YUV444P12:
>> +        return AV_PIX_FMT_YUVA444P12;
>> +    case AV_PIX_FMT_YUV422P12:
>> +        return AV_PIX_FMT_YUVA422P12;
>> +    default:
>> +        av_log(s->avctx, AV_LOG_WARNING, "No alpha pixel format map for %s\n",
>> +               av_get_pix_fmt_name(pix_fmt));
>> +        return AV_PIX_FMT_NONE;
>> +    }
>> +}
>> +
>> static enum AVPixelFormat get_format(HEVCContext *s, const HEVCSPS *sps)
>> {
>> #define HWACCEL_MAX (CONFIG_HEVC_DXVA2_HWACCEL + \
>> @@ -540,9 +599,13 @@ static enum AVPixelFormat get_format(HEVCContext *s, const HEVCSPS *sps)
>>                      CONFIG_HEVC_VIDEOTOOLBOX_HWACCEL + \
>>                      CONFIG_HEVC_VDPAU_HWACCEL + \
>>                      CONFIG_HEVC_VULKAN_HWACCEL)
>> -    enum AVPixelFormat pix_fmts[HWACCEL_MAX + 2], *fmt = pix_fmts;
>> +    enum AVPixelFormat pix_fmts[HWACCEL_MAX + 3], *fmt = pix_fmts;
>> +    enum AVPixelFormat alpha_fmt = AV_PIX_FMT_NONE;
>>     int ret;
>> 
>> +    if (ff_hevc_is_alpha_video(s))
>> +        alpha_fmt = map_to_alpha_format(s, sps->pix_fmt);
>> +
>>     switch (sps->pix_fmt) {
>>     case AV_PIX_FMT_YUV420P:
>>     case AV_PIX_FMT_YUVJ420P:
>> @@ -664,6 +727,8 @@ static enum AVPixelFormat get_format(HEVCContext *s, const HEVCSPS *sps)
>>         break;
>>     }
>> 
>> +    if (alpha_fmt != AV_PIX_FMT_NONE)
>> +        *fmt++ = alpha_fmt;
>>     *fmt++ = sps->pix_fmt;
>>     *fmt = AV_PIX_FMT_NONE;
>> 
>> @@ -3194,6 +3259,12 @@ static int hevc_frame_start(HEVCContext *s, HEVCLayerContext *l,
>>                 !sps->vui.common.video_signal_type_present_flag)
>>                 pix_fmt = sps_base->pix_fmt;
>> 
>> +            // Ignore range mismatch between base layer and alpha layer
>> +            if (ff_hevc_is_alpha_video(s) &&
>> +                sps_base->pix_fmt == AV_PIX_FMT_YUV420P &&
>> +                pix_fmt == AV_PIX_FMT_YUVJ420P)
>> +                pix_fmt = sps_base->pix_fmt;
>> +
>>             if (pix_fmt     != sps_base->pix_fmt ||
>>                 sps->width  != sps_base->width   ||
>>                 sps->height != sps_base->height) {
>> diff --git a/libavcodec/hevc/hevcdec.h b/libavcodec/hevc/hevcdec.h
>> index 4e95035688..b2b725b5cd 100644
>> --- a/libavcodec/hevc/hevcdec.h
>> +++ b/libavcodec/hevc/hevcdec.h
>> @@ -714,6 +714,8 @@ void ff_hevc_hls_residual_coding(HEVCLocalContext *lc, const HEVCPPS *pps,
>> 
>> void ff_hevc_hls_mvd_coding(HEVCLocalContext *lc, int x0, int y0, int log2_cb_size);
>> 
>> +int ff_hevc_is_alpha_video(const HEVCContext *s);
>> +
>> extern const uint8_t ff_hevc_qpel_extra_before[4];
>> extern const uint8_t ff_hevc_qpel_extra_after[4];
>> extern const uint8_t ff_hevc_qpel_extra[4];
>> diff --git a/libavcodec/hevc/refs.c b/libavcodec/hevc/refs.c
>> index dd7f7f95a8..6f10efd0ac 100644
>> --- a/libavcodec/hevc/refs.c
>> +++ b/libavcodec/hevc/refs.c
>> @@ -79,6 +79,31 @@ void ff_hevc_flush_dpb(HEVCContext *s)
>>     }
>> }
>> 
>> +static int replace_alpha_plane(AVFrame *alpha, AVFrame *base)
>> +{
>> +    AVBufferRef *base_a = av_frame_get_plane_buffer(base, 3);
>> +    uintptr_t data = (uintptr_t)alpha->data[0];
>> +    int ret;
>> +
>> +    for (int i = 0; i < FF_ARRAY_ELEMS(alpha->buf) && alpha->buf[i]; i++) {
>> +        AVBufferRef *buf = alpha->buf[i];
>> +        uintptr_t buf_begin = (uintptr_t)buf->data;
>> +
>> +        if (data >=  buf_begin && data < buf_begin + buf->size) {
>> +            ret = av_buffer_replace(&alpha->buf[i], base_a);
>> +            if (ret < 0)
>> +                return ret;
>> +
>> +            alpha->linesize[0] = base->linesize[3];
>> +            alpha->data[0] = base->data[3];
>> +
>> +            return 0;
>> +        }
>> +    }
> 
> Why does the decoding process actually need multiple references to the
> buffer of the alpha plane?

I’m not sure if I understand your question correctly.

1. Both the base layer and the alpha layer are decoded as yuv420p.
2. The y plane of alpha layer is actually alpha.
3. The decoder finally output yuva, not two yuv420p.

So here make y plane of alpha frame reference the alpha plane of base frame.
When output, the base frame will contain YUV and alpha from two layers.

> 
>> +
>> +    return AVERROR_BUG;
>> +}
>> +
>> static HEVCFrame *alloc_frame(HEVCContext *s, HEVCLayerContext *l)
>> {
>>     const HEVCVPS *vps = l->sps->vps;
>> @@ -103,7 +128,7 @@ static HEVCFrame *alloc_frame(HEVCContext *s, HEVCLayerContext *l)
>>         }
>> 
>>         // add view ID side data if it's nontrivial
>> -        if (vps->nb_layers > 1 || view_id) {
>> +        if (!ff_hevc_is_alpha_video(s) && (vps->nb_layers > 1 || view_id)) {
>>             HEVCSEITDRDI *tdrdi = &s->sei.tdrdi;
>>             AVFrameSideData *sd = av_frame_side_data_new(&frame->f->side_data,
>>                                                          &frame->f->nb_side_data,
>> @@ -161,7 +186,15 @@ static HEVCFrame *alloc_frame(HEVCContext *s, HEVCLayerContext *l)
>>         if (ret < 0)
>>             goto fail;
>> 
>> +
>>         frame->pps = av_refstruct_ref_c(s->pps);
>> +        if (l != &s->layers[0] && ff_hevc_is_alpha_video(s)) {
>> +            AVFrame *alpha = frame->f;
>> +            AVFrame *base = s->layers[0].cur_frame->f;
>> +            ret = replace_alpha_plane(alpha, base);
>> +            if (ret < 0)
>> +                goto fail;
>> +        }
>> 
>>         return frame;
>> fail:
> 
> _______________________________________________
> ffmpeg-devel mailing list
> ffmpeg-devel@ffmpeg.org
> https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
> 
> To unsubscribe, visit link above, or email
> ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".

_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel

To unsubscribe, visit link above, or email
ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [FFmpeg-devel] [PATCH v7 3/4] avcodec/hevc: Add alpha layer support
  2025-02-11 15:57   ` Zhao Zhili
@ 2025-02-11 16:02     ` James Almer
  2025-02-11 16:11       ` Zhao Zhili
  2025-02-11 16:10     ` Andreas Rheinhardt
  1 sibling, 1 reply; 11+ messages in thread
From: James Almer @ 2025-02-11 16:02 UTC (permalink / raw)
  To: ffmpeg-devel


[-- Attachment #1.1.1: Type: text/plain, Size: 9497 bytes --]

On 2/11/2025 12:57 PM, Zhao Zhili wrote:
> 
> 
>> On Feb 11, 2025, at 23:37, Andreas Rheinhardt <andreas.rheinhardt@outlook.com> wrote:
>>
>> Zhao Zhili:
>>> From: Zhao Zhili <zhilizhao@tencent.com>
>>>
>>> Signed-off-by: Zhao Zhili <zhilizhao@tencent.com>
>>> ---
>>> libavcodec/hevc/hevcdec.c | 73 ++++++++++++++++++++++++++++++++++++++-
>>> libavcodec/hevc/hevcdec.h |  2 ++
>>> libavcodec/hevc/refs.c    | 35 ++++++++++++++++++-
>>> 3 files changed, 108 insertions(+), 2 deletions(-)
>>>
>>> diff --git a/libavcodec/hevc/hevcdec.c b/libavcodec/hevc/hevcdec.c
>>> index e9c045f7a1..f71edf213b 100644
>>> --- a/libavcodec/hevc/hevcdec.c
>>> +++ b/libavcodec/hevc/hevcdec.c
>>> @@ -466,6 +466,25 @@ static int export_multilayer(HEVCContext *s, const HEVCVPS *vps)
>>>      return 0;
>>> }
>>>
>>> +int ff_hevc_is_alpha_video(const HEVCContext *s)
>>> +{
>>> +    const HEVCVPS *vps = s->vps;
>>> +    int ret = 0;
>>> +
>>> +    if (vps->nb_layers != 2 || !vps->layer_id_in_nuh[1])
>>> +        return 0;
>>> +
>>> +    /* decode_vps_ext() guarantees that SCALABILITY_AUXILIARY with AuxId other
>>> +     * than alpha cannot reach here.
>>> +     */
>>> +    ret = (s->vps->scalability_mask_flag & HEVC_SCALABILITY_AUXILIARY);
>>> +
>>> +    av_log(s->avctx, AV_LOG_DEBUG, "Multi layer video, %s alpha video\n",
>>> +           ret ? "is" : "not");
>>> +
>>> +    return ret;
>>> +}
>>> +
>>> static int setup_multilayer(HEVCContext *s, const HEVCVPS *vps)
>>> {
>>>      unsigned layers_active_output = 0, highest_layer;
>>> @@ -473,6 +492,18 @@ static int setup_multilayer(HEVCContext *s, const HEVCVPS *vps)
>>>      s->layers_active_output = 1;
>>>      s->layers_active_decode = 1;
>>>
>>> +    if (ff_hevc_is_alpha_video(s)) {
>>> +        const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(s->avctx->pix_fmt);
>>> +
>>> +        if (!(desc->flags & AV_PIX_FMT_FLAG_ALPHA))
>>> +            return 0;
>>> +
>>> +        s->layers_active_decode = (1 << vps->nb_layers) - 1;
>>> +        s->layers_active_output = 1;
>>> +
>>> +        return 0;
>>> +    }
>>> +
>>>      // nothing requested - decode base layer only
>>>      if (!s->nb_view_ids)
>>>          return 0;
>>> @@ -530,6 +561,34 @@ static int setup_multilayer(HEVCContext *s, const HEVCVPS *vps)
>>>      return 0;
>>> }
>>>
>>> +static enum AVPixelFormat map_to_alpha_format(HEVCContext *s,
>>> +                                              enum AVPixelFormat pix_fmt)
>>> +{
>>> +    switch (pix_fmt) {
>>> +    case AV_PIX_FMT_YUV420P:
>>> +    case AV_PIX_FMT_YUVJ420P:
>>> +        return AV_PIX_FMT_YUVA420P;
>>> +    case AV_PIX_FMT_YUV420P10:
>>> +        return AV_PIX_FMT_YUVA420P10;
>>> +    case AV_PIX_FMT_YUV444P:
>>> +        return AV_PIX_FMT_YUVA444P;
>>> +    case AV_PIX_FMT_YUV422P:
>>> +        return AV_PIX_FMT_YUVA422P;
>>> +    case AV_PIX_FMT_YUV422P10LE:
>>> +        return AV_PIX_FMT_YUVA422P10LE;
>>> +    case AV_PIX_FMT_YUV444P10:
>>> +        return AV_PIX_FMT_YUVA444P10;
>>> +    case AV_PIX_FMT_YUV444P12:
>>> +        return AV_PIX_FMT_YUVA444P12;
>>> +    case AV_PIX_FMT_YUV422P12:
>>> +        return AV_PIX_FMT_YUVA422P12;
>>> +    default:
>>> +        av_log(s->avctx, AV_LOG_WARNING, "No alpha pixel format map for %s\n",
>>> +               av_get_pix_fmt_name(pix_fmt));
>>> +        return AV_PIX_FMT_NONE;
>>> +    }
>>> +}
>>> +
>>> static enum AVPixelFormat get_format(HEVCContext *s, const HEVCSPS *sps)
>>> {
>>> #define HWACCEL_MAX (CONFIG_HEVC_DXVA2_HWACCEL + \
>>> @@ -540,9 +599,13 @@ static enum AVPixelFormat get_format(HEVCContext *s, const HEVCSPS *sps)
>>>                       CONFIG_HEVC_VIDEOTOOLBOX_HWACCEL + \
>>>                       CONFIG_HEVC_VDPAU_HWACCEL + \
>>>                       CONFIG_HEVC_VULKAN_HWACCEL)
>>> -    enum AVPixelFormat pix_fmts[HWACCEL_MAX + 2], *fmt = pix_fmts;
>>> +    enum AVPixelFormat pix_fmts[HWACCEL_MAX + 3], *fmt = pix_fmts;
>>> +    enum AVPixelFormat alpha_fmt = AV_PIX_FMT_NONE;
>>>      int ret;
>>>
>>> +    if (ff_hevc_is_alpha_video(s))
>>> +        alpha_fmt = map_to_alpha_format(s, sps->pix_fmt);
>>> +
>>>      switch (sps->pix_fmt) {
>>>      case AV_PIX_FMT_YUV420P:
>>>      case AV_PIX_FMT_YUVJ420P:
>>> @@ -664,6 +727,8 @@ static enum AVPixelFormat get_format(HEVCContext *s, const HEVCSPS *sps)
>>>          break;
>>>      }
>>>
>>> +    if (alpha_fmt != AV_PIX_FMT_NONE)
>>> +        *fmt++ = alpha_fmt;
>>>      *fmt++ = sps->pix_fmt;
>>>      *fmt = AV_PIX_FMT_NONE;
>>>
>>> @@ -3194,6 +3259,12 @@ static int hevc_frame_start(HEVCContext *s, HEVCLayerContext *l,
>>>                  !sps->vui.common.video_signal_type_present_flag)
>>>                  pix_fmt = sps_base->pix_fmt;
>>>
>>> +            // Ignore range mismatch between base layer and alpha layer
>>> +            if (ff_hevc_is_alpha_video(s) &&
>>> +                sps_base->pix_fmt == AV_PIX_FMT_YUV420P &&
>>> +                pix_fmt == AV_PIX_FMT_YUVJ420P)
>>> +                pix_fmt = sps_base->pix_fmt;
>>> +
>>>              if (pix_fmt     != sps_base->pix_fmt ||
>>>                  sps->width  != sps_base->width   ||
>>>                  sps->height != sps_base->height) {
>>> diff --git a/libavcodec/hevc/hevcdec.h b/libavcodec/hevc/hevcdec.h
>>> index 4e95035688..b2b725b5cd 100644
>>> --- a/libavcodec/hevc/hevcdec.h
>>> +++ b/libavcodec/hevc/hevcdec.h
>>> @@ -714,6 +714,8 @@ void ff_hevc_hls_residual_coding(HEVCLocalContext *lc, const HEVCPPS *pps,
>>>
>>> void ff_hevc_hls_mvd_coding(HEVCLocalContext *lc, int x0, int y0, int log2_cb_size);
>>>
>>> +int ff_hevc_is_alpha_video(const HEVCContext *s);
>>> +
>>> extern const uint8_t ff_hevc_qpel_extra_before[4];
>>> extern const uint8_t ff_hevc_qpel_extra_after[4];
>>> extern const uint8_t ff_hevc_qpel_extra[4];
>>> diff --git a/libavcodec/hevc/refs.c b/libavcodec/hevc/refs.c
>>> index dd7f7f95a8..6f10efd0ac 100644
>>> --- a/libavcodec/hevc/refs.c
>>> +++ b/libavcodec/hevc/refs.c
>>> @@ -79,6 +79,31 @@ void ff_hevc_flush_dpb(HEVCContext *s)
>>>      }
>>> }
>>>
>>> +static int replace_alpha_plane(AVFrame *alpha, AVFrame *base)
>>> +{
>>> +    AVBufferRef *base_a = av_frame_get_plane_buffer(base, 3);
>>> +    uintptr_t data = (uintptr_t)alpha->data[0];
>>> +    int ret;
>>> +
>>> +    for (int i = 0; i < FF_ARRAY_ELEMS(alpha->buf) && alpha->buf[i]; i++) {
>>> +        AVBufferRef *buf = alpha->buf[i];
>>> +        uintptr_t buf_begin = (uintptr_t)buf->data;
>>> +
>>> +        if (data >=  buf_begin && data < buf_begin + buf->size) {
>>> +            ret = av_buffer_replace(&alpha->buf[i], base_a);
>>> +            if (ret < 0)
>>> +                return ret;
>>> +
>>> +            alpha->linesize[0] = base->linesize[3];
>>> +            alpha->data[0] = base->data[3];
>>> +
>>> +            return 0;
>>> +        }
>>> +    }
>>
>> Why does the decoding process actually need multiple references to the
>> buffer of the alpha plane?
> 
> I’m not sure if I understand your question correctly.
> 
> 1. Both the base layer and the alpha layer are decoded as yuv420p.
> 2. The y plane of alpha layer is actually alpha.
> 3. The decoder finally output yuva, not two yuv420p.
> 
> So here make y plane of alpha frame reference the alpha plane of base frame.
> When output, the base frame will contain YUV and alpha from two layers.

The loop makes it look like you're potentially creating references to 
base_a in all buf[] entries from alpha, when all you need is one in 
alpha->buf[0], right?

> 
>>
>>> +
>>> +    return AVERROR_BUG;
>>> +}
>>> +
>>> static HEVCFrame *alloc_frame(HEVCContext *s, HEVCLayerContext *l)
>>> {
>>>      const HEVCVPS *vps = l->sps->vps;
>>> @@ -103,7 +128,7 @@ static HEVCFrame *alloc_frame(HEVCContext *s, HEVCLayerContext *l)
>>>          }
>>>
>>>          // add view ID side data if it's nontrivial
>>> -        if (vps->nb_layers > 1 || view_id) {
>>> +        if (!ff_hevc_is_alpha_video(s) && (vps->nb_layers > 1 || view_id)) {
>>>              HEVCSEITDRDI *tdrdi = &s->sei.tdrdi;
>>>              AVFrameSideData *sd = av_frame_side_data_new(&frame->f->side_data,
>>>                                                           &frame->f->nb_side_data,
>>> @@ -161,7 +186,15 @@ static HEVCFrame *alloc_frame(HEVCContext *s, HEVCLayerContext *l)
>>>          if (ret < 0)
>>>              goto fail;
>>>
>>> +
>>>          frame->pps = av_refstruct_ref_c(s->pps);
>>> +        if (l != &s->layers[0] && ff_hevc_is_alpha_video(s)) {
>>> +            AVFrame *alpha = frame->f;
>>> +            AVFrame *base = s->layers[0].cur_frame->f;
>>> +            ret = replace_alpha_plane(alpha, base);
>>> +            if (ret < 0)
>>> +                goto fail;
>>> +        }
>>>
>>>          return frame;
>>> fail:
>>
>> _______________________________________________
>> ffmpeg-devel mailing list
>> ffmpeg-devel@ffmpeg.org
>> https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
>>
>> To unsubscribe, visit link above, or email
>> ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".
> 
> _______________________________________________
> ffmpeg-devel mailing list
> ffmpeg-devel@ffmpeg.org
> https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
> 
> To unsubscribe, visit link above, or email
> ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".


[-- Attachment #1.2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 495 bytes --]

[-- Attachment #2: Type: text/plain, Size: 251 bytes --]

_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel

To unsubscribe, visit link above, or email
ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [FFmpeg-devel] [PATCH v7 3/4] avcodec/hevc: Add alpha layer support
  2025-02-11 15:57   ` Zhao Zhili
  2025-02-11 16:02     ` James Almer
@ 2025-02-11 16:10     ` Andreas Rheinhardt
  2025-02-11 16:21       ` Zhao Zhili
  2025-02-11 16:27       ` James Almer
  1 sibling, 2 replies; 11+ messages in thread
From: Andreas Rheinhardt @ 2025-02-11 16:10 UTC (permalink / raw)
  To: ffmpeg-devel

Zhao Zhili:
> 
> 
>> On Feb 11, 2025, at 23:37, Andreas Rheinhardt <andreas.rheinhardt@outlook.com> wrote:
>>
>> Zhao Zhili:
>>> From: Zhao Zhili <zhilizhao@tencent.com>
>>>
>>> Signed-off-by: Zhao Zhili <zhilizhao@tencent.com>
>>> ---
>>> libavcodec/hevc/hevcdec.c | 73 ++++++++++++++++++++++++++++++++++++++-
>>> libavcodec/hevc/hevcdec.h |  2 ++
>>> libavcodec/hevc/refs.c    | 35 ++++++++++++++++++-
>>> 3 files changed, 108 insertions(+), 2 deletions(-)
>>>
>>> diff --git a/libavcodec/hevc/hevcdec.c b/libavcodec/hevc/hevcdec.c
>>> index e9c045f7a1..f71edf213b 100644
>>> --- a/libavcodec/hevc/hevcdec.c
>>> +++ b/libavcodec/hevc/hevcdec.c
>>> @@ -466,6 +466,25 @@ static int export_multilayer(HEVCContext *s, const HEVCVPS *vps)
>>>     return 0;
>>> }
>>>
>>> +int ff_hevc_is_alpha_video(const HEVCContext *s)
>>> +{
>>> +    const HEVCVPS *vps = s->vps;
>>> +    int ret = 0;
>>> +
>>> +    if (vps->nb_layers != 2 || !vps->layer_id_in_nuh[1])
>>> +        return 0;
>>> +
>>> +    /* decode_vps_ext() guarantees that SCALABILITY_AUXILIARY with AuxId other
>>> +     * than alpha cannot reach here.
>>> +     */
>>> +    ret = (s->vps->scalability_mask_flag & HEVC_SCALABILITY_AUXILIARY);
>>> +
>>> +    av_log(s->avctx, AV_LOG_DEBUG, "Multi layer video, %s alpha video\n",
>>> +           ret ? "is" : "not");
>>> +
>>> +    return ret;
>>> +}
>>> +
>>> static int setup_multilayer(HEVCContext *s, const HEVCVPS *vps)
>>> {
>>>     unsigned layers_active_output = 0, highest_layer;
>>> @@ -473,6 +492,18 @@ static int setup_multilayer(HEVCContext *s, const HEVCVPS *vps)
>>>     s->layers_active_output = 1;
>>>     s->layers_active_decode = 1;
>>>
>>> +    if (ff_hevc_is_alpha_video(s)) {
>>> +        const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(s->avctx->pix_fmt);
>>> +
>>> +        if (!(desc->flags & AV_PIX_FMT_FLAG_ALPHA))
>>> +            return 0;
>>> +
>>> +        s->layers_active_decode = (1 << vps->nb_layers) - 1;
>>> +        s->layers_active_output = 1;
>>> +
>>> +        return 0;
>>> +    }
>>> +
>>>     // nothing requested - decode base layer only
>>>     if (!s->nb_view_ids)
>>>         return 0;
>>> @@ -530,6 +561,34 @@ static int setup_multilayer(HEVCContext *s, const HEVCVPS *vps)
>>>     return 0;
>>> }
>>>
>>> +static enum AVPixelFormat map_to_alpha_format(HEVCContext *s,
>>> +                                              enum AVPixelFormat pix_fmt)
>>> +{
>>> +    switch (pix_fmt) {
>>> +    case AV_PIX_FMT_YUV420P:
>>> +    case AV_PIX_FMT_YUVJ420P:
>>> +        return AV_PIX_FMT_YUVA420P;
>>> +    case AV_PIX_FMT_YUV420P10:
>>> +        return AV_PIX_FMT_YUVA420P10;
>>> +    case AV_PIX_FMT_YUV444P:
>>> +        return AV_PIX_FMT_YUVA444P;
>>> +    case AV_PIX_FMT_YUV422P:
>>> +        return AV_PIX_FMT_YUVA422P;
>>> +    case AV_PIX_FMT_YUV422P10LE:
>>> +        return AV_PIX_FMT_YUVA422P10LE;
>>> +    case AV_PIX_FMT_YUV444P10:
>>> +        return AV_PIX_FMT_YUVA444P10;
>>> +    case AV_PIX_FMT_YUV444P12:
>>> +        return AV_PIX_FMT_YUVA444P12;
>>> +    case AV_PIX_FMT_YUV422P12:
>>> +        return AV_PIX_FMT_YUVA422P12;
>>> +    default:
>>> +        av_log(s->avctx, AV_LOG_WARNING, "No alpha pixel format map for %s\n",
>>> +               av_get_pix_fmt_name(pix_fmt));
>>> +        return AV_PIX_FMT_NONE;
>>> +    }
>>> +}
>>> +
>>> static enum AVPixelFormat get_format(HEVCContext *s, const HEVCSPS *sps)
>>> {
>>> #define HWACCEL_MAX (CONFIG_HEVC_DXVA2_HWACCEL + \
>>> @@ -540,9 +599,13 @@ static enum AVPixelFormat get_format(HEVCContext *s, const HEVCSPS *sps)
>>>                      CONFIG_HEVC_VIDEOTOOLBOX_HWACCEL + \
>>>                      CONFIG_HEVC_VDPAU_HWACCEL + \
>>>                      CONFIG_HEVC_VULKAN_HWACCEL)
>>> -    enum AVPixelFormat pix_fmts[HWACCEL_MAX + 2], *fmt = pix_fmts;
>>> +    enum AVPixelFormat pix_fmts[HWACCEL_MAX + 3], *fmt = pix_fmts;
>>> +    enum AVPixelFormat alpha_fmt = AV_PIX_FMT_NONE;
>>>     int ret;
>>>
>>> +    if (ff_hevc_is_alpha_video(s))
>>> +        alpha_fmt = map_to_alpha_format(s, sps->pix_fmt);
>>> +
>>>     switch (sps->pix_fmt) {
>>>     case AV_PIX_FMT_YUV420P:
>>>     case AV_PIX_FMT_YUVJ420P:
>>> @@ -664,6 +727,8 @@ static enum AVPixelFormat get_format(HEVCContext *s, const HEVCSPS *sps)
>>>         break;
>>>     }
>>>
>>> +    if (alpha_fmt != AV_PIX_FMT_NONE)
>>> +        *fmt++ = alpha_fmt;
>>>     *fmt++ = sps->pix_fmt;
>>>     *fmt = AV_PIX_FMT_NONE;
>>>
>>> @@ -3194,6 +3259,12 @@ static int hevc_frame_start(HEVCContext *s, HEVCLayerContext *l,
>>>                 !sps->vui.common.video_signal_type_present_flag)
>>>                 pix_fmt = sps_base->pix_fmt;
>>>
>>> +            // Ignore range mismatch between base layer and alpha layer
>>> +            if (ff_hevc_is_alpha_video(s) &&
>>> +                sps_base->pix_fmt == AV_PIX_FMT_YUV420P &&
>>> +                pix_fmt == AV_PIX_FMT_YUVJ420P)
>>> +                pix_fmt = sps_base->pix_fmt;
>>> +
>>>             if (pix_fmt     != sps_base->pix_fmt ||
>>>                 sps->width  != sps_base->width   ||
>>>                 sps->height != sps_base->height) {
>>> diff --git a/libavcodec/hevc/hevcdec.h b/libavcodec/hevc/hevcdec.h
>>> index 4e95035688..b2b725b5cd 100644
>>> --- a/libavcodec/hevc/hevcdec.h
>>> +++ b/libavcodec/hevc/hevcdec.h
>>> @@ -714,6 +714,8 @@ void ff_hevc_hls_residual_coding(HEVCLocalContext *lc, const HEVCPPS *pps,
>>>
>>> void ff_hevc_hls_mvd_coding(HEVCLocalContext *lc, int x0, int y0, int log2_cb_size);
>>>
>>> +int ff_hevc_is_alpha_video(const HEVCContext *s);
>>> +
>>> extern const uint8_t ff_hevc_qpel_extra_before[4];
>>> extern const uint8_t ff_hevc_qpel_extra_after[4];
>>> extern const uint8_t ff_hevc_qpel_extra[4];
>>> diff --git a/libavcodec/hevc/refs.c b/libavcodec/hevc/refs.c
>>> index dd7f7f95a8..6f10efd0ac 100644
>>> --- a/libavcodec/hevc/refs.c
>>> +++ b/libavcodec/hevc/refs.c
>>> @@ -79,6 +79,31 @@ void ff_hevc_flush_dpb(HEVCContext *s)
>>>     }
>>> }
>>>
>>> +static int replace_alpha_plane(AVFrame *alpha, AVFrame *base)
>>> +{
>>> +    AVBufferRef *base_a = av_frame_get_plane_buffer(base, 3);
>>> +    uintptr_t data = (uintptr_t)alpha->data[0];
>>> +    int ret;
>>> +
>>> +    for (int i = 0; i < FF_ARRAY_ELEMS(alpha->buf) && alpha->buf[i]; i++) {
>>> +        AVBufferRef *buf = alpha->buf[i];
>>> +        uintptr_t buf_begin = (uintptr_t)buf->data;
>>> +
>>> +        if (data >=  buf_begin && data < buf_begin + buf->size) {
>>> +            ret = av_buffer_replace(&alpha->buf[i], base_a);
>>> +            if (ret < 0)
>>> +                return ret;
>>> +
>>> +            alpha->linesize[0] = base->linesize[3];
>>> +            alpha->data[0] = base->data[3];
>>> +
>>> +            return 0;
>>> +        }
>>> +    }
>>
>> Why does the decoding process actually need multiple references to the
>> buffer of the alpha plane?
> 
> I’m not sure if I understand your question correctly.
> 
> 1. Both the base layer and the alpha layer are decoded as yuv420p.
> 2. The y plane of alpha layer is actually alpha.
> 3. The decoder finally output yuva, not two yuv420p.
> 
> So here make y plane of alpha frame reference the alpha plane of base frame.
> When output, the base frame will contain YUV and alpha from two layers.
> 

The base layer AVFrame already contains a reference to the alpha plane;
so why do we need another one? Does the base AVFrame get unreferenced
before the alpha plane is finished decoding?

>>
>>> +
>>> +    return AVERROR_BUG;
>>> +}
>>> +
>>> static HEVCFrame *alloc_frame(HEVCContext *s, HEVCLayerContext *l)
>>> {
>>>     const HEVCVPS *vps = l->sps->vps;
>>> @@ -103,7 +128,7 @@ static HEVCFrame *alloc_frame(HEVCContext *s, HEVCLayerContext *l)
>>>         }
>>>
>>>         // add view ID side data if it's nontrivial
>>> -        if (vps->nb_layers > 1 || view_id) {
>>> +        if (!ff_hevc_is_alpha_video(s) && (vps->nb_layers > 1 || view_id)) {
>>>             HEVCSEITDRDI *tdrdi = &s->sei.tdrdi;
>>>             AVFrameSideData *sd = av_frame_side_data_new(&frame->f->side_data,
>>>                                                          &frame->f->nb_side_data,
>>> @@ -161,7 +186,15 @@ static HEVCFrame *alloc_frame(HEVCContext *s, HEVCLayerContext *l)
>>>         if (ret < 0)
>>>             goto fail;
>>>
>>> +
>>>         frame->pps = av_refstruct_ref_c(s->pps);
>>> +        if (l != &s->layers[0] && ff_hevc_is_alpha_video(s)) {
>>> +            AVFrame *alpha = frame->f;
>>> +            AVFrame *base = s->layers[0].cur_frame->f;
>>> +            ret = replace_alpha_plane(alpha, base);
>>> +            if (ret < 0)
>>> +                goto fail;
>>> +        }
>>>
>>>         return frame;
>>> fail:
>>
>> _______________________________________________
>> ffmpeg-devel mailing list
>> ffmpeg-devel@ffmpeg.org
>> https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
>>
>> To unsubscribe, visit link above, or email
>> ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".
> 
> _______________________________________________
> ffmpeg-devel mailing list
> ffmpeg-devel@ffmpeg.org
> https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
> 
> To unsubscribe, visit link above, or email
> ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".

_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel

To unsubscribe, visit link above, or email
ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [FFmpeg-devel] [PATCH v7 3/4] avcodec/hevc: Add alpha layer support
  2025-02-11 16:02     ` James Almer
@ 2025-02-11 16:11       ` Zhao Zhili
  2025-02-11 16:13         ` James Almer
  0 siblings, 1 reply; 11+ messages in thread
From: Zhao Zhili @ 2025-02-11 16:11 UTC (permalink / raw)
  To: FFmpeg development discussions and patches



> On Feb 12, 2025, at 00:02, James Almer <jamrial@gmail.com> wrote:
> 
> On 2/11/2025 12:57 PM, Zhao Zhili wrote:
>>> On Feb 11, 2025, at 23:37, Andreas Rheinhardt <andreas.rheinhardt@outlook.com> wrote:
>>> 
>>> Zhao Zhili:
>>>> From: Zhao Zhili <zhilizhao@tencent.com>
>>>> 
>>>> Signed-off-by: Zhao Zhili <zhilizhao@tencent.com>
>>>> ---
>>>> libavcodec/hevc/hevcdec.c | 73 ++++++++++++++++++++++++++++++++++++++-
>>>> libavcodec/hevc/hevcdec.h |  2 ++
>>>> libavcodec/hevc/refs.c    | 35 ++++++++++++++++++-
>>>> 3 files changed, 108 insertions(+), 2 deletions(-)
>>>> 
>>>> diff --git a/libavcodec/hevc/hevcdec.c b/libavcodec/hevc/hevcdec.c
>>>> index e9c045f7a1..f71edf213b 100644
>>>> --- a/libavcodec/hevc/hevcdec.c
>>>> +++ b/libavcodec/hevc/hevcdec.c
>>>> @@ -466,6 +466,25 @@ static int export_multilayer(HEVCContext *s, const HEVCVPS *vps)
>>>>     return 0;
>>>> }
>>>> 
>>>> +int ff_hevc_is_alpha_video(const HEVCContext *s)
>>>> +{
>>>> +    const HEVCVPS *vps = s->vps;
>>>> +    int ret = 0;
>>>> +
>>>> +    if (vps->nb_layers != 2 || !vps->layer_id_in_nuh[1])
>>>> +        return 0;
>>>> +
>>>> +    /* decode_vps_ext() guarantees that SCALABILITY_AUXILIARY with AuxId other
>>>> +     * than alpha cannot reach here.
>>>> +     */
>>>> +    ret = (s->vps->scalability_mask_flag & HEVC_SCALABILITY_AUXILIARY);
>>>> +
>>>> +    av_log(s->avctx, AV_LOG_DEBUG, "Multi layer video, %s alpha video\n",
>>>> +           ret ? "is" : "not");
>>>> +
>>>> +    return ret;
>>>> +}
>>>> +
>>>> static int setup_multilayer(HEVCContext *s, const HEVCVPS *vps)
>>>> {
>>>>     unsigned layers_active_output = 0, highest_layer;
>>>> @@ -473,6 +492,18 @@ static int setup_multilayer(HEVCContext *s, const HEVCVPS *vps)
>>>>     s->layers_active_output = 1;
>>>>     s->layers_active_decode = 1;
>>>> 
>>>> +    if (ff_hevc_is_alpha_video(s)) {
>>>> +        const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(s->avctx->pix_fmt);
>>>> +
>>>> +        if (!(desc->flags & AV_PIX_FMT_FLAG_ALPHA))
>>>> +            return 0;
>>>> +
>>>> +        s->layers_active_decode = (1 << vps->nb_layers) - 1;
>>>> +        s->layers_active_output = 1;
>>>> +
>>>> +        return 0;
>>>> +    }
>>>> +
>>>>     // nothing requested - decode base layer only
>>>>     if (!s->nb_view_ids)
>>>>         return 0;
>>>> @@ -530,6 +561,34 @@ static int setup_multilayer(HEVCContext *s, const HEVCVPS *vps)
>>>>     return 0;
>>>> }
>>>> 
>>>> +static enum AVPixelFormat map_to_alpha_format(HEVCContext *s,
>>>> +                                              enum AVPixelFormat pix_fmt)
>>>> +{
>>>> +    switch (pix_fmt) {
>>>> +    case AV_PIX_FMT_YUV420P:
>>>> +    case AV_PIX_FMT_YUVJ420P:
>>>> +        return AV_PIX_FMT_YUVA420P;
>>>> +    case AV_PIX_FMT_YUV420P10:
>>>> +        return AV_PIX_FMT_YUVA420P10;
>>>> +    case AV_PIX_FMT_YUV444P:
>>>> +        return AV_PIX_FMT_YUVA444P;
>>>> +    case AV_PIX_FMT_YUV422P:
>>>> +        return AV_PIX_FMT_YUVA422P;
>>>> +    case AV_PIX_FMT_YUV422P10LE:
>>>> +        return AV_PIX_FMT_YUVA422P10LE;
>>>> +    case AV_PIX_FMT_YUV444P10:
>>>> +        return AV_PIX_FMT_YUVA444P10;
>>>> +    case AV_PIX_FMT_YUV444P12:
>>>> +        return AV_PIX_FMT_YUVA444P12;
>>>> +    case AV_PIX_FMT_YUV422P12:
>>>> +        return AV_PIX_FMT_YUVA422P12;
>>>> +    default:
>>>> +        av_log(s->avctx, AV_LOG_WARNING, "No alpha pixel format map for %s\n",
>>>> +               av_get_pix_fmt_name(pix_fmt));
>>>> +        return AV_PIX_FMT_NONE;
>>>> +    }
>>>> +}
>>>> +
>>>> static enum AVPixelFormat get_format(HEVCContext *s, const HEVCSPS *sps)
>>>> {
>>>> #define HWACCEL_MAX (CONFIG_HEVC_DXVA2_HWACCEL + \
>>>> @@ -540,9 +599,13 @@ static enum AVPixelFormat get_format(HEVCContext *s, const HEVCSPS *sps)
>>>>                      CONFIG_HEVC_VIDEOTOOLBOX_HWACCEL + \
>>>>                      CONFIG_HEVC_VDPAU_HWACCEL + \
>>>>                      CONFIG_HEVC_VULKAN_HWACCEL)
>>>> -    enum AVPixelFormat pix_fmts[HWACCEL_MAX + 2], *fmt = pix_fmts;
>>>> +    enum AVPixelFormat pix_fmts[HWACCEL_MAX + 3], *fmt = pix_fmts;
>>>> +    enum AVPixelFormat alpha_fmt = AV_PIX_FMT_NONE;
>>>>     int ret;
>>>> 
>>>> +    if (ff_hevc_is_alpha_video(s))
>>>> +        alpha_fmt = map_to_alpha_format(s, sps->pix_fmt);
>>>> +
>>>>     switch (sps->pix_fmt) {
>>>>     case AV_PIX_FMT_YUV420P:
>>>>     case AV_PIX_FMT_YUVJ420P:
>>>> @@ -664,6 +727,8 @@ static enum AVPixelFormat get_format(HEVCContext *s, const HEVCSPS *sps)
>>>>         break;
>>>>     }
>>>> 
>>>> +    if (alpha_fmt != AV_PIX_FMT_NONE)
>>>> +        *fmt++ = alpha_fmt;
>>>>     *fmt++ = sps->pix_fmt;
>>>>     *fmt = AV_PIX_FMT_NONE;
>>>> 
>>>> @@ -3194,6 +3259,12 @@ static int hevc_frame_start(HEVCContext *s, HEVCLayerContext *l,
>>>>                 !sps->vui.common.video_signal_type_present_flag)
>>>>                 pix_fmt = sps_base->pix_fmt;
>>>> 
>>>> +            // Ignore range mismatch between base layer and alpha layer
>>>> +            if (ff_hevc_is_alpha_video(s) &&
>>>> +                sps_base->pix_fmt == AV_PIX_FMT_YUV420P &&
>>>> +                pix_fmt == AV_PIX_FMT_YUVJ420P)
>>>> +                pix_fmt = sps_base->pix_fmt;
>>>> +
>>>>             if (pix_fmt     != sps_base->pix_fmt ||
>>>>                 sps->width  != sps_base->width   ||
>>>>                 sps->height != sps_base->height) {
>>>> diff --git a/libavcodec/hevc/hevcdec.h b/libavcodec/hevc/hevcdec.h
>>>> index 4e95035688..b2b725b5cd 100644
>>>> --- a/libavcodec/hevc/hevcdec.h
>>>> +++ b/libavcodec/hevc/hevcdec.h
>>>> @@ -714,6 +714,8 @@ void ff_hevc_hls_residual_coding(HEVCLocalContext *lc, const HEVCPPS *pps,
>>>> 
>>>> void ff_hevc_hls_mvd_coding(HEVCLocalContext *lc, int x0, int y0, int log2_cb_size);
>>>> 
>>>> +int ff_hevc_is_alpha_video(const HEVCContext *s);
>>>> +
>>>> extern const uint8_t ff_hevc_qpel_extra_before[4];
>>>> extern const uint8_t ff_hevc_qpel_extra_after[4];
>>>> extern const uint8_t ff_hevc_qpel_extra[4];
>>>> diff --git a/libavcodec/hevc/refs.c b/libavcodec/hevc/refs.c
>>>> index dd7f7f95a8..6f10efd0ac 100644
>>>> --- a/libavcodec/hevc/refs.c
>>>> +++ b/libavcodec/hevc/refs.c
>>>> @@ -79,6 +79,31 @@ void ff_hevc_flush_dpb(HEVCContext *s)
>>>>     }
>>>> }
>>>> 
>>>> +static int replace_alpha_plane(AVFrame *alpha, AVFrame *base)
>>>> +{
>>>> +    AVBufferRef *base_a = av_frame_get_plane_buffer(base, 3);
>>>> +    uintptr_t data = (uintptr_t)alpha->data[0];
>>>> +    int ret;
>>>> +
>>>> +    for (int i = 0; i < FF_ARRAY_ELEMS(alpha->buf) && alpha->buf[i]; i++) {
>>>> +        AVBufferRef *buf = alpha->buf[i];
>>>> +        uintptr_t buf_begin = (uintptr_t)buf->data;
>>>> +
>>>> +        if (data >=  buf_begin && data < buf_begin + buf->size) {
>>>> +            ret = av_buffer_replace(&alpha->buf[i], base_a);
>>>> +            if (ret < 0)
>>>> +                return ret;
>>>> +
>>>> +            alpha->linesize[0] = base->linesize[3];
>>>> +            alpha->data[0] = base->data[3];
>>>> +
>>>> +            return 0;
>>>> +        }
>>>> +    }
>>> 
>>> Why does the decoding process actually need multiple references to the
>>> buffer of the alpha plane?
>> I’m not sure if I understand your question correctly.
>> 1. Both the base layer and the alpha layer are decoded as yuv420p.
>> 2. The y plane of alpha layer is actually alpha.
>> 3. The decoder finally output yuva, not two yuv420p.
>> So here make y plane of alpha frame reference the alpha plane of base frame.
>> When output, the base frame will contain YUV and alpha from two layers.
> 
> The loop makes it look like you're potentially creating references to base_a in all buf[] entries from alpha, when all you need is one in alpha->buf[0], right?

That’s what I did before patch v6. Andreas pointed out that alpha->buf[0] doesn’t means the first plane.
frame->data[0] can pointed to frame->buf[2]. So I need a loop to find out which buf frame->data[0] pointed to.

> 
>>> 
>>>> +
>>>> +    return AVERROR_BUG;
>>>> +}
>>>> +
>>>> static HEVCFrame *alloc_frame(HEVCContext *s, HEVCLayerContext *l)
>>>> {
>>>>     const HEVCVPS *vps = l->sps->vps;
>>>> @@ -103,7 +128,7 @@ static HEVCFrame *alloc_frame(HEVCContext *s, HEVCLayerContext *l)
>>>>         }
>>>> 
>>>>         // add view ID side data if it's nontrivial
>>>> -        if (vps->nb_layers > 1 || view_id) {
>>>> +        if (!ff_hevc_is_alpha_video(s) && (vps->nb_layers > 1 || view_id)) {
>>>>             HEVCSEITDRDI *tdrdi = &s->sei.tdrdi;
>>>>             AVFrameSideData *sd = av_frame_side_data_new(&frame->f->side_data,
>>>>                                                          &frame->f->nb_side_data,
>>>> @@ -161,7 +186,15 @@ static HEVCFrame *alloc_frame(HEVCContext *s, HEVCLayerContext *l)
>>>>         if (ret < 0)
>>>>             goto fail;
>>>> 
>>>> +
>>>>         frame->pps = av_refstruct_ref_c(s->pps);
>>>> +        if (l != &s->layers[0] && ff_hevc_is_alpha_video(s)) {
>>>> +            AVFrame *alpha = frame->f;
>>>> +            AVFrame *base = s->layers[0].cur_frame->f;
>>>> +            ret = replace_alpha_plane(alpha, base);
>>>> +            if (ret < 0)
>>>> +                goto fail;
>>>> +        }
>>>> 
>>>>         return frame;
>>>> fail:
>>> 
>>> _______________________________________________
>>> ffmpeg-devel mailing list
>>> ffmpeg-devel@ffmpeg.org
>>> https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
>>> 
>>> To unsubscribe, visit link above, or email
>>> ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".
>> _______________________________________________
>> ffmpeg-devel mailing list
>> ffmpeg-devel@ffmpeg.org
>> https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
>> To unsubscribe, visit link above, or email
>> ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".
> 
> _______________________________________________
> ffmpeg-devel mailing list
> ffmpeg-devel@ffmpeg.org
> https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
> 
> To unsubscribe, visit link above, or email
> ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".
> 

_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel

To unsubscribe, visit link above, or email
ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [FFmpeg-devel] [PATCH v7 3/4] avcodec/hevc: Add alpha layer support
  2025-02-11 16:11       ` Zhao Zhili
@ 2025-02-11 16:13         ` James Almer
  0 siblings, 0 replies; 11+ messages in thread
From: James Almer @ 2025-02-11 16:13 UTC (permalink / raw)
  To: ffmpeg-devel


[-- Attachment #1.1.1: Type: text/plain, Size: 8419 bytes --]

On 2/11/2025 1:11 PM, Zhao Zhili wrote:
> 
> 
>> On Feb 12, 2025, at 00:02, James Almer <jamrial@gmail.com> wrote:
>>
>> On 2/11/2025 12:57 PM, Zhao Zhili wrote:
>>>> On Feb 11, 2025, at 23:37, Andreas Rheinhardt <andreas.rheinhardt@outlook.com> wrote:
>>>>
>>>> Zhao Zhili:
>>>>> From: Zhao Zhili <zhilizhao@tencent.com>
>>>>>
>>>>> Signed-off-by: Zhao Zhili <zhilizhao@tencent.com>
>>>>> ---
>>>>> libavcodec/hevc/hevcdec.c | 73 ++++++++++++++++++++++++++++++++++++++-
>>>>> libavcodec/hevc/hevcdec.h |  2 ++
>>>>> libavcodec/hevc/refs.c    | 35 ++++++++++++++++++-
>>>>> 3 files changed, 108 insertions(+), 2 deletions(-)
>>>>>
>>>>> diff --git a/libavcodec/hevc/hevcdec.c b/libavcodec/hevc/hevcdec.c
>>>>> index e9c045f7a1..f71edf213b 100644
>>>>> --- a/libavcodec/hevc/hevcdec.c
>>>>> +++ b/libavcodec/hevc/hevcdec.c
>>>>> @@ -466,6 +466,25 @@ static int export_multilayer(HEVCContext *s, const HEVCVPS *vps)
>>>>>      return 0;
>>>>> }
>>>>>
>>>>> +int ff_hevc_is_alpha_video(const HEVCContext *s)
>>>>> +{
>>>>> +    const HEVCVPS *vps = s->vps;
>>>>> +    int ret = 0;
>>>>> +
>>>>> +    if (vps->nb_layers != 2 || !vps->layer_id_in_nuh[1])
>>>>> +        return 0;
>>>>> +
>>>>> +    /* decode_vps_ext() guarantees that SCALABILITY_AUXILIARY with AuxId other
>>>>> +     * than alpha cannot reach here.
>>>>> +     */
>>>>> +    ret = (s->vps->scalability_mask_flag & HEVC_SCALABILITY_AUXILIARY);
>>>>> +
>>>>> +    av_log(s->avctx, AV_LOG_DEBUG, "Multi layer video, %s alpha video\n",
>>>>> +           ret ? "is" : "not");
>>>>> +
>>>>> +    return ret;
>>>>> +}
>>>>> +
>>>>> static int setup_multilayer(HEVCContext *s, const HEVCVPS *vps)
>>>>> {
>>>>>      unsigned layers_active_output = 0, highest_layer;
>>>>> @@ -473,6 +492,18 @@ static int setup_multilayer(HEVCContext *s, const HEVCVPS *vps)
>>>>>      s->layers_active_output = 1;
>>>>>      s->layers_active_decode = 1;
>>>>>
>>>>> +    if (ff_hevc_is_alpha_video(s)) {
>>>>> +        const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(s->avctx->pix_fmt);
>>>>> +
>>>>> +        if (!(desc->flags & AV_PIX_FMT_FLAG_ALPHA))
>>>>> +            return 0;
>>>>> +
>>>>> +        s->layers_active_decode = (1 << vps->nb_layers) - 1;
>>>>> +        s->layers_active_output = 1;
>>>>> +
>>>>> +        return 0;
>>>>> +    }
>>>>> +
>>>>>      // nothing requested - decode base layer only
>>>>>      if (!s->nb_view_ids)
>>>>>          return 0;
>>>>> @@ -530,6 +561,34 @@ static int setup_multilayer(HEVCContext *s, const HEVCVPS *vps)
>>>>>      return 0;
>>>>> }
>>>>>
>>>>> +static enum AVPixelFormat map_to_alpha_format(HEVCContext *s,
>>>>> +                                              enum AVPixelFormat pix_fmt)
>>>>> +{
>>>>> +    switch (pix_fmt) {
>>>>> +    case AV_PIX_FMT_YUV420P:
>>>>> +    case AV_PIX_FMT_YUVJ420P:
>>>>> +        return AV_PIX_FMT_YUVA420P;
>>>>> +    case AV_PIX_FMT_YUV420P10:
>>>>> +        return AV_PIX_FMT_YUVA420P10;
>>>>> +    case AV_PIX_FMT_YUV444P:
>>>>> +        return AV_PIX_FMT_YUVA444P;
>>>>> +    case AV_PIX_FMT_YUV422P:
>>>>> +        return AV_PIX_FMT_YUVA422P;
>>>>> +    case AV_PIX_FMT_YUV422P10LE:
>>>>> +        return AV_PIX_FMT_YUVA422P10LE;
>>>>> +    case AV_PIX_FMT_YUV444P10:
>>>>> +        return AV_PIX_FMT_YUVA444P10;
>>>>> +    case AV_PIX_FMT_YUV444P12:
>>>>> +        return AV_PIX_FMT_YUVA444P12;
>>>>> +    case AV_PIX_FMT_YUV422P12:
>>>>> +        return AV_PIX_FMT_YUVA422P12;
>>>>> +    default:
>>>>> +        av_log(s->avctx, AV_LOG_WARNING, "No alpha pixel format map for %s\n",
>>>>> +               av_get_pix_fmt_name(pix_fmt));
>>>>> +        return AV_PIX_FMT_NONE;
>>>>> +    }
>>>>> +}
>>>>> +
>>>>> static enum AVPixelFormat get_format(HEVCContext *s, const HEVCSPS *sps)
>>>>> {
>>>>> #define HWACCEL_MAX (CONFIG_HEVC_DXVA2_HWACCEL + \
>>>>> @@ -540,9 +599,13 @@ static enum AVPixelFormat get_format(HEVCContext *s, const HEVCSPS *sps)
>>>>>                       CONFIG_HEVC_VIDEOTOOLBOX_HWACCEL + \
>>>>>                       CONFIG_HEVC_VDPAU_HWACCEL + \
>>>>>                       CONFIG_HEVC_VULKAN_HWACCEL)
>>>>> -    enum AVPixelFormat pix_fmts[HWACCEL_MAX + 2], *fmt = pix_fmts;
>>>>> +    enum AVPixelFormat pix_fmts[HWACCEL_MAX + 3], *fmt = pix_fmts;
>>>>> +    enum AVPixelFormat alpha_fmt = AV_PIX_FMT_NONE;
>>>>>      int ret;
>>>>>
>>>>> +    if (ff_hevc_is_alpha_video(s))
>>>>> +        alpha_fmt = map_to_alpha_format(s, sps->pix_fmt);
>>>>> +
>>>>>      switch (sps->pix_fmt) {
>>>>>      case AV_PIX_FMT_YUV420P:
>>>>>      case AV_PIX_FMT_YUVJ420P:
>>>>> @@ -664,6 +727,8 @@ static enum AVPixelFormat get_format(HEVCContext *s, const HEVCSPS *sps)
>>>>>          break;
>>>>>      }
>>>>>
>>>>> +    if (alpha_fmt != AV_PIX_FMT_NONE)
>>>>> +        *fmt++ = alpha_fmt;
>>>>>      *fmt++ = sps->pix_fmt;
>>>>>      *fmt = AV_PIX_FMT_NONE;
>>>>>
>>>>> @@ -3194,6 +3259,12 @@ static int hevc_frame_start(HEVCContext *s, HEVCLayerContext *l,
>>>>>                  !sps->vui.common.video_signal_type_present_flag)
>>>>>                  pix_fmt = sps_base->pix_fmt;
>>>>>
>>>>> +            // Ignore range mismatch between base layer and alpha layer
>>>>> +            if (ff_hevc_is_alpha_video(s) &&
>>>>> +                sps_base->pix_fmt == AV_PIX_FMT_YUV420P &&
>>>>> +                pix_fmt == AV_PIX_FMT_YUVJ420P)
>>>>> +                pix_fmt = sps_base->pix_fmt;
>>>>> +
>>>>>              if (pix_fmt     != sps_base->pix_fmt ||
>>>>>                  sps->width  != sps_base->width   ||
>>>>>                  sps->height != sps_base->height) {
>>>>> diff --git a/libavcodec/hevc/hevcdec.h b/libavcodec/hevc/hevcdec.h
>>>>> index 4e95035688..b2b725b5cd 100644
>>>>> --- a/libavcodec/hevc/hevcdec.h
>>>>> +++ b/libavcodec/hevc/hevcdec.h
>>>>> @@ -714,6 +714,8 @@ void ff_hevc_hls_residual_coding(HEVCLocalContext *lc, const HEVCPPS *pps,
>>>>>
>>>>> void ff_hevc_hls_mvd_coding(HEVCLocalContext *lc, int x0, int y0, int log2_cb_size);
>>>>>
>>>>> +int ff_hevc_is_alpha_video(const HEVCContext *s);
>>>>> +
>>>>> extern const uint8_t ff_hevc_qpel_extra_before[4];
>>>>> extern const uint8_t ff_hevc_qpel_extra_after[4];
>>>>> extern const uint8_t ff_hevc_qpel_extra[4];
>>>>> diff --git a/libavcodec/hevc/refs.c b/libavcodec/hevc/refs.c
>>>>> index dd7f7f95a8..6f10efd0ac 100644
>>>>> --- a/libavcodec/hevc/refs.c
>>>>> +++ b/libavcodec/hevc/refs.c
>>>>> @@ -79,6 +79,31 @@ void ff_hevc_flush_dpb(HEVCContext *s)
>>>>>      }
>>>>> }
>>>>>
>>>>> +static int replace_alpha_plane(AVFrame *alpha, AVFrame *base)
>>>>> +{
>>>>> +    AVBufferRef *base_a = av_frame_get_plane_buffer(base, 3);
>>>>> +    uintptr_t data = (uintptr_t)alpha->data[0];
>>>>> +    int ret;
>>>>> +
>>>>> +    for (int i = 0; i < FF_ARRAY_ELEMS(alpha->buf) && alpha->buf[i]; i++) {
>>>>> +        AVBufferRef *buf = alpha->buf[i];
>>>>> +        uintptr_t buf_begin = (uintptr_t)buf->data;
>>>>> +
>>>>> +        if (data >=  buf_begin && data < buf_begin + buf->size) {
>>>>> +            ret = av_buffer_replace(&alpha->buf[i], base_a);
>>>>> +            if (ret < 0)
>>>>> +                return ret;
>>>>> +
>>>>> +            alpha->linesize[0] = base->linesize[3];
>>>>> +            alpha->data[0] = base->data[3];
>>>>> +
>>>>> +            return 0;
>>>>> +        }
>>>>> +    }
>>>>
>>>> Why does the decoding process actually need multiple references to the
>>>> buffer of the alpha plane?
>>> I’m not sure if I understand your question correctly.
>>> 1. Both the base layer and the alpha layer are decoded as yuv420p.
>>> 2. The y plane of alpha layer is actually alpha.
>>> 3. The decoder finally output yuva, not two yuv420p.
>>> So here make y plane of alpha frame reference the alpha plane of base frame.
>>> When output, the base frame will contain YUV and alpha from two layers.
>>
>> The loop makes it look like you're potentially creating references to base_a in all buf[] entries from alpha, when all you need is one in alpha->buf[0], right?
> 
> That’s what I did before patch v6. Andreas pointed out that alpha->buf[0] doesn’t means the first plane.
> frame->data[0] can pointed to frame->buf[2]. So I need a loop to find out which buf frame->data[0] pointed to.

Oh, you're right, i see now the return 0 that breaks the loop.


[-- Attachment #1.2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 491 bytes --]

[-- Attachment #2: Type: text/plain, Size: 251 bytes --]

_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel

To unsubscribe, visit link above, or email
ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [FFmpeg-devel] [PATCH v7 3/4] avcodec/hevc: Add alpha layer support
  2025-02-11 16:10     ` Andreas Rheinhardt
@ 2025-02-11 16:21       ` Zhao Zhili
  2025-02-11 16:25         ` Andreas Rheinhardt
  2025-02-11 16:27       ` James Almer
  1 sibling, 1 reply; 11+ messages in thread
From: Zhao Zhili @ 2025-02-11 16:21 UTC (permalink / raw)
  To: FFmpeg development discussions and patches



> On Feb 12, 2025, at 00:10, Andreas Rheinhardt <andreas.rheinhardt@outlook.com> wrote:
> 
> Zhao Zhili:
>> 
>> 
>>> On Feb 11, 2025, at 23:37, Andreas Rheinhardt <andreas.rheinhardt@outlook.com> wrote:
>>> 
>>> Zhao Zhili:
>>>> From: Zhao Zhili <zhilizhao@tencent.com>
>>>> 
>>>> Signed-off-by: Zhao Zhili <zhilizhao@tencent.com>
>>>> ---
>>>> libavcodec/hevc/hevcdec.c | 73 ++++++++++++++++++++++++++++++++++++++-
>>>> libavcodec/hevc/hevcdec.h |  2 ++
>>>> libavcodec/hevc/refs.c    | 35 ++++++++++++++++++-
>>>> 3 files changed, 108 insertions(+), 2 deletions(-)
>>>> 
>>>> diff --git a/libavcodec/hevc/hevcdec.c b/libavcodec/hevc/hevcdec.c
>>>> index e9c045f7a1..f71edf213b 100644
>>>> --- a/libavcodec/hevc/hevcdec.c
>>>> +++ b/libavcodec/hevc/hevcdec.c
>>>> @@ -466,6 +466,25 @@ static int export_multilayer(HEVCContext *s, const HEVCVPS *vps)
>>>>    return 0;
>>>> }
>>>> 
>>>> +int ff_hevc_is_alpha_video(const HEVCContext *s)
>>>> +{
>>>> +    const HEVCVPS *vps = s->vps;
>>>> +    int ret = 0;
>>>> +
>>>> +    if (vps->nb_layers != 2 || !vps->layer_id_in_nuh[1])
>>>> +        return 0;
>>>> +
>>>> +    /* decode_vps_ext() guarantees that SCALABILITY_AUXILIARY with AuxId other
>>>> +     * than alpha cannot reach here.
>>>> +     */
>>>> +    ret = (s->vps->scalability_mask_flag & HEVC_SCALABILITY_AUXILIARY);
>>>> +
>>>> +    av_log(s->avctx, AV_LOG_DEBUG, "Multi layer video, %s alpha video\n",
>>>> +           ret ? "is" : "not");
>>>> +
>>>> +    return ret;
>>>> +}
>>>> +
>>>> static int setup_multilayer(HEVCContext *s, const HEVCVPS *vps)
>>>> {
>>>>    unsigned layers_active_output = 0, highest_layer;
>>>> @@ -473,6 +492,18 @@ static int setup_multilayer(HEVCContext *s, const HEVCVPS *vps)
>>>>    s->layers_active_output = 1;
>>>>    s->layers_active_decode = 1;
>>>> 
>>>> +    if (ff_hevc_is_alpha_video(s)) {
>>>> +        const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(s->avctx->pix_fmt);
>>>> +
>>>> +        if (!(desc->flags & AV_PIX_FMT_FLAG_ALPHA))
>>>> +            return 0;
>>>> +
>>>> +        s->layers_active_decode = (1 << vps->nb_layers) - 1;
>>>> +        s->layers_active_output = 1;
>>>> +
>>>> +        return 0;
>>>> +    }
>>>> +
>>>>    // nothing requested - decode base layer only
>>>>    if (!s->nb_view_ids)
>>>>        return 0;
>>>> @@ -530,6 +561,34 @@ static int setup_multilayer(HEVCContext *s, const HEVCVPS *vps)
>>>>    return 0;
>>>> }
>>>> 
>>>> +static enum AVPixelFormat map_to_alpha_format(HEVCContext *s,
>>>> +                                              enum AVPixelFormat pix_fmt)
>>>> +{
>>>> +    switch (pix_fmt) {
>>>> +    case AV_PIX_FMT_YUV420P:
>>>> +    case AV_PIX_FMT_YUVJ420P:
>>>> +        return AV_PIX_FMT_YUVA420P;
>>>> +    case AV_PIX_FMT_YUV420P10:
>>>> +        return AV_PIX_FMT_YUVA420P10;
>>>> +    case AV_PIX_FMT_YUV444P:
>>>> +        return AV_PIX_FMT_YUVA444P;
>>>> +    case AV_PIX_FMT_YUV422P:
>>>> +        return AV_PIX_FMT_YUVA422P;
>>>> +    case AV_PIX_FMT_YUV422P10LE:
>>>> +        return AV_PIX_FMT_YUVA422P10LE;
>>>> +    case AV_PIX_FMT_YUV444P10:
>>>> +        return AV_PIX_FMT_YUVA444P10;
>>>> +    case AV_PIX_FMT_YUV444P12:
>>>> +        return AV_PIX_FMT_YUVA444P12;
>>>> +    case AV_PIX_FMT_YUV422P12:
>>>> +        return AV_PIX_FMT_YUVA422P12;
>>>> +    default:
>>>> +        av_log(s->avctx, AV_LOG_WARNING, "No alpha pixel format map for %s\n",
>>>> +               av_get_pix_fmt_name(pix_fmt));
>>>> +        return AV_PIX_FMT_NONE;
>>>> +    }
>>>> +}
>>>> +
>>>> static enum AVPixelFormat get_format(HEVCContext *s, const HEVCSPS *sps)
>>>> {
>>>> #define HWACCEL_MAX (CONFIG_HEVC_DXVA2_HWACCEL + \
>>>> @@ -540,9 +599,13 @@ static enum AVPixelFormat get_format(HEVCContext *s, const HEVCSPS *sps)
>>>>                     CONFIG_HEVC_VIDEOTOOLBOX_HWACCEL + \
>>>>                     CONFIG_HEVC_VDPAU_HWACCEL + \
>>>>                     CONFIG_HEVC_VULKAN_HWACCEL)
>>>> -    enum AVPixelFormat pix_fmts[HWACCEL_MAX + 2], *fmt = pix_fmts;
>>>> +    enum AVPixelFormat pix_fmts[HWACCEL_MAX + 3], *fmt = pix_fmts;
>>>> +    enum AVPixelFormat alpha_fmt = AV_PIX_FMT_NONE;
>>>>    int ret;
>>>> 
>>>> +    if (ff_hevc_is_alpha_video(s))
>>>> +        alpha_fmt = map_to_alpha_format(s, sps->pix_fmt);
>>>> +
>>>>    switch (sps->pix_fmt) {
>>>>    case AV_PIX_FMT_YUV420P:
>>>>    case AV_PIX_FMT_YUVJ420P:
>>>> @@ -664,6 +727,8 @@ static enum AVPixelFormat get_format(HEVCContext *s, const HEVCSPS *sps)
>>>>        break;
>>>>    }
>>>> 
>>>> +    if (alpha_fmt != AV_PIX_FMT_NONE)
>>>> +        *fmt++ = alpha_fmt;
>>>>    *fmt++ = sps->pix_fmt;
>>>>    *fmt = AV_PIX_FMT_NONE;
>>>> 
>>>> @@ -3194,6 +3259,12 @@ static int hevc_frame_start(HEVCContext *s, HEVCLayerContext *l,
>>>>                !sps->vui.common.video_signal_type_present_flag)
>>>>                pix_fmt = sps_base->pix_fmt;
>>>> 
>>>> +            // Ignore range mismatch between base layer and alpha layer
>>>> +            if (ff_hevc_is_alpha_video(s) &&
>>>> +                sps_base->pix_fmt == AV_PIX_FMT_YUV420P &&
>>>> +                pix_fmt == AV_PIX_FMT_YUVJ420P)
>>>> +                pix_fmt = sps_base->pix_fmt;
>>>> +
>>>>            if (pix_fmt     != sps_base->pix_fmt ||
>>>>                sps->width  != sps_base->width   ||
>>>>                sps->height != sps_base->height) {
>>>> diff --git a/libavcodec/hevc/hevcdec.h b/libavcodec/hevc/hevcdec.h
>>>> index 4e95035688..b2b725b5cd 100644
>>>> --- a/libavcodec/hevc/hevcdec.h
>>>> +++ b/libavcodec/hevc/hevcdec.h
>>>> @@ -714,6 +714,8 @@ void ff_hevc_hls_residual_coding(HEVCLocalContext *lc, const HEVCPPS *pps,
>>>> 
>>>> void ff_hevc_hls_mvd_coding(HEVCLocalContext *lc, int x0, int y0, int log2_cb_size);
>>>> 
>>>> +int ff_hevc_is_alpha_video(const HEVCContext *s);
>>>> +
>>>> extern const uint8_t ff_hevc_qpel_extra_before[4];
>>>> extern const uint8_t ff_hevc_qpel_extra_after[4];
>>>> extern const uint8_t ff_hevc_qpel_extra[4];
>>>> diff --git a/libavcodec/hevc/refs.c b/libavcodec/hevc/refs.c
>>>> index dd7f7f95a8..6f10efd0ac 100644
>>>> --- a/libavcodec/hevc/refs.c
>>>> +++ b/libavcodec/hevc/refs.c
>>>> @@ -79,6 +79,31 @@ void ff_hevc_flush_dpb(HEVCContext *s)
>>>>    }
>>>> }
>>>> 
>>>> +static int replace_alpha_plane(AVFrame *alpha, AVFrame *base)
>>>> +{
>>>> +    AVBufferRef *base_a = av_frame_get_plane_buffer(base, 3);
>>>> +    uintptr_t data = (uintptr_t)alpha->data[0];
>>>> +    int ret;
>>>> +
>>>> +    for (int i = 0; i < FF_ARRAY_ELEMS(alpha->buf) && alpha->buf[i]; i++) {
>>>> +        AVBufferRef *buf = alpha->buf[i];
>>>> +        uintptr_t buf_begin = (uintptr_t)buf->data;
>>>> +
>>>> +        if (data >=  buf_begin && data < buf_begin + buf->size) {
>>>> +            ret = av_buffer_replace(&alpha->buf[i], base_a);
>>>> +            if (ret < 0)
>>>> +                return ret;
>>>> +
>>>> +            alpha->linesize[0] = base->linesize[3];
>>>> +            alpha->data[0] = base->data[3];
>>>> +
>>>> +            return 0;
>>>> +        }
>>>> +    }
>>> 
>>> Why does the decoding process actually need multiple references to the
>>> buffer of the alpha plane?
>> 
>> I’m not sure if I understand your question correctly.
>> 
>> 1. Both the base layer and the alpha layer are decoded as yuv420p.
>> 2. The y plane of alpha layer is actually alpha.
>> 3. The decoder finally output yuva, not two yuv420p.
>> 
>> So here make y plane of alpha frame reference the alpha plane of base frame.
>> When output, the base frame will contain YUV and alpha from two layers.
>> 
> 
> The base layer AVFrame already contains a reference to the alpha plane;
> so why do we need another one? Does the base AVFrame get unreferenced
> before the alpha plane is finished decoding?

In the decoding process, it’s almost the same as MV-HEVC:
1. The base layer is decoded to the YUV of base frame, without touching the alpha plane.
2. The alpha layer is decoded to YUV of alpha frame.

We can output the two frames like MV-HEVC, but it’s user friendly to output in YUVA format.
So I’m letting the alpha layer decoded to the alpha plane of the base layer. Or I can do the
reverse. It’s the same.

We can skip the alpha frame totally. Then the decoding process and DPB buffer management
will be different. Current method is simple but use more memory. I can work on that lately.

> 
>>> 
>>>> +
>>>> +    return AVERROR_BUG;
>>>> +}
>>>> +
>>>> static HEVCFrame *alloc_frame(HEVCContext *s, HEVCLayerContext *l)
>>>> {
>>>>    const HEVCVPS *vps = l->sps->vps;
>>>> @@ -103,7 +128,7 @@ static HEVCFrame *alloc_frame(HEVCContext *s, HEVCLayerContext *l)
>>>>        }
>>>> 
>>>>        // add view ID side data if it's nontrivial
>>>> -        if (vps->nb_layers > 1 || view_id) {
>>>> +        if (!ff_hevc_is_alpha_video(s) && (vps->nb_layers > 1 || view_id)) {
>>>>            HEVCSEITDRDI *tdrdi = &s->sei.tdrdi;
>>>>            AVFrameSideData *sd = av_frame_side_data_new(&frame->f->side_data,
>>>>                                                         &frame->f->nb_side_data,
>>>> @@ -161,7 +186,15 @@ static HEVCFrame *alloc_frame(HEVCContext *s, HEVCLayerContext *l)
>>>>        if (ret < 0)
>>>>            goto fail;
>>>> 
>>>> +
>>>>        frame->pps = av_refstruct_ref_c(s->pps);
>>>> +        if (l != &s->layers[0] && ff_hevc_is_alpha_video(s)) {
>>>> +            AVFrame *alpha = frame->f;
>>>> +            AVFrame *base = s->layers[0].cur_frame->f;
>>>> +            ret = replace_alpha_plane(alpha, base);
>>>> +            if (ret < 0)
>>>> +                goto fail;
>>>> +        }
>>>> 
>>>>        return frame;
>>>> fail:
>>> 
>>> _______________________________________________
>>> ffmpeg-devel mailing list
>>> ffmpeg-devel@ffmpeg.org
>>> https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
>>> 
>>> To unsubscribe, visit link above, or email
>>> ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".
>> 
>> _______________________________________________
>> ffmpeg-devel mailing list
>> ffmpeg-devel@ffmpeg.org
>> https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
>> 
>> To unsubscribe, visit link above, or email
>> ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".
> 
> _______________________________________________
> ffmpeg-devel mailing list
> ffmpeg-devel@ffmpeg.org
> https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
> 
> To unsubscribe, visit link above, or email
> ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".

_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel

To unsubscribe, visit link above, or email
ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [FFmpeg-devel] [PATCH v7 3/4] avcodec/hevc: Add alpha layer support
  2025-02-11 16:21       ` Zhao Zhili
@ 2025-02-11 16:25         ` Andreas Rheinhardt
  2025-02-11 16:50           ` Zhao Zhili
  0 siblings, 1 reply; 11+ messages in thread
From: Andreas Rheinhardt @ 2025-02-11 16:25 UTC (permalink / raw)
  To: ffmpeg-devel

Zhao Zhili:
> 
> 
>> On Feb 12, 2025, at 00:10, Andreas Rheinhardt <andreas.rheinhardt@outlook.com> wrote:
>>
>> Zhao Zhili:
>>>
>>>
>>>> On Feb 11, 2025, at 23:37, Andreas Rheinhardt <andreas.rheinhardt@outlook.com> wrote:
>>>>
>>>> Zhao Zhili:
>>>>> From: Zhao Zhili <zhilizhao@tencent.com>
>>>>>
>>>>> Signed-off-by: Zhao Zhili <zhilizhao@tencent.com>
>>>>> ---
>>>>> libavcodec/hevc/hevcdec.c | 73 ++++++++++++++++++++++++++++++++++++++-
>>>>> libavcodec/hevc/hevcdec.h |  2 ++
>>>>> libavcodec/hevc/refs.c    | 35 ++++++++++++++++++-
>>>>> 3 files changed, 108 insertions(+), 2 deletions(-)
>>>>>
>>>>> diff --git a/libavcodec/hevc/hevcdec.c b/libavcodec/hevc/hevcdec.c
>>>>> index e9c045f7a1..f71edf213b 100644
>>>>> --- a/libavcodec/hevc/hevcdec.c
>>>>> +++ b/libavcodec/hevc/hevcdec.c
>>>>> @@ -466,6 +466,25 @@ static int export_multilayer(HEVCContext *s, const HEVCVPS *vps)
>>>>>    return 0;
>>>>> }
>>>>>
>>>>> +int ff_hevc_is_alpha_video(const HEVCContext *s)
>>>>> +{
>>>>> +    const HEVCVPS *vps = s->vps;
>>>>> +    int ret = 0;
>>>>> +
>>>>> +    if (vps->nb_layers != 2 || !vps->layer_id_in_nuh[1])
>>>>> +        return 0;
>>>>> +
>>>>> +    /* decode_vps_ext() guarantees that SCALABILITY_AUXILIARY with AuxId other
>>>>> +     * than alpha cannot reach here.
>>>>> +     */
>>>>> +    ret = (s->vps->scalability_mask_flag & HEVC_SCALABILITY_AUXILIARY);
>>>>> +
>>>>> +    av_log(s->avctx, AV_LOG_DEBUG, "Multi layer video, %s alpha video\n",
>>>>> +           ret ? "is" : "not");
>>>>> +
>>>>> +    return ret;
>>>>> +}
>>>>> +
>>>>> static int setup_multilayer(HEVCContext *s, const HEVCVPS *vps)
>>>>> {
>>>>>    unsigned layers_active_output = 0, highest_layer;
>>>>> @@ -473,6 +492,18 @@ static int setup_multilayer(HEVCContext *s, const HEVCVPS *vps)
>>>>>    s->layers_active_output = 1;
>>>>>    s->layers_active_decode = 1;
>>>>>
>>>>> +    if (ff_hevc_is_alpha_video(s)) {
>>>>> +        const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(s->avctx->pix_fmt);
>>>>> +
>>>>> +        if (!(desc->flags & AV_PIX_FMT_FLAG_ALPHA))
>>>>> +            return 0;
>>>>> +
>>>>> +        s->layers_active_decode = (1 << vps->nb_layers) - 1;
>>>>> +        s->layers_active_output = 1;
>>>>> +
>>>>> +        return 0;
>>>>> +    }
>>>>> +
>>>>>    // nothing requested - decode base layer only
>>>>>    if (!s->nb_view_ids)
>>>>>        return 0;
>>>>> @@ -530,6 +561,34 @@ static int setup_multilayer(HEVCContext *s, const HEVCVPS *vps)
>>>>>    return 0;
>>>>> }
>>>>>
>>>>> +static enum AVPixelFormat map_to_alpha_format(HEVCContext *s,
>>>>> +                                              enum AVPixelFormat pix_fmt)
>>>>> +{
>>>>> +    switch (pix_fmt) {
>>>>> +    case AV_PIX_FMT_YUV420P:
>>>>> +    case AV_PIX_FMT_YUVJ420P:
>>>>> +        return AV_PIX_FMT_YUVA420P;
>>>>> +    case AV_PIX_FMT_YUV420P10:
>>>>> +        return AV_PIX_FMT_YUVA420P10;
>>>>> +    case AV_PIX_FMT_YUV444P:
>>>>> +        return AV_PIX_FMT_YUVA444P;
>>>>> +    case AV_PIX_FMT_YUV422P:
>>>>> +        return AV_PIX_FMT_YUVA422P;
>>>>> +    case AV_PIX_FMT_YUV422P10LE:
>>>>> +        return AV_PIX_FMT_YUVA422P10LE;
>>>>> +    case AV_PIX_FMT_YUV444P10:
>>>>> +        return AV_PIX_FMT_YUVA444P10;
>>>>> +    case AV_PIX_FMT_YUV444P12:
>>>>> +        return AV_PIX_FMT_YUVA444P12;
>>>>> +    case AV_PIX_FMT_YUV422P12:
>>>>> +        return AV_PIX_FMT_YUVA422P12;
>>>>> +    default:
>>>>> +        av_log(s->avctx, AV_LOG_WARNING, "No alpha pixel format map for %s\n",
>>>>> +               av_get_pix_fmt_name(pix_fmt));
>>>>> +        return AV_PIX_FMT_NONE;
>>>>> +    }
>>>>> +}
>>>>> +
>>>>> static enum AVPixelFormat get_format(HEVCContext *s, const HEVCSPS *sps)
>>>>> {
>>>>> #define HWACCEL_MAX (CONFIG_HEVC_DXVA2_HWACCEL + \
>>>>> @@ -540,9 +599,13 @@ static enum AVPixelFormat get_format(HEVCContext *s, const HEVCSPS *sps)
>>>>>                     CONFIG_HEVC_VIDEOTOOLBOX_HWACCEL + \
>>>>>                     CONFIG_HEVC_VDPAU_HWACCEL + \
>>>>>                     CONFIG_HEVC_VULKAN_HWACCEL)
>>>>> -    enum AVPixelFormat pix_fmts[HWACCEL_MAX + 2], *fmt = pix_fmts;
>>>>> +    enum AVPixelFormat pix_fmts[HWACCEL_MAX + 3], *fmt = pix_fmts;
>>>>> +    enum AVPixelFormat alpha_fmt = AV_PIX_FMT_NONE;
>>>>>    int ret;
>>>>>
>>>>> +    if (ff_hevc_is_alpha_video(s))
>>>>> +        alpha_fmt = map_to_alpha_format(s, sps->pix_fmt);
>>>>> +
>>>>>    switch (sps->pix_fmt) {
>>>>>    case AV_PIX_FMT_YUV420P:
>>>>>    case AV_PIX_FMT_YUVJ420P:
>>>>> @@ -664,6 +727,8 @@ static enum AVPixelFormat get_format(HEVCContext *s, const HEVCSPS *sps)
>>>>>        break;
>>>>>    }
>>>>>
>>>>> +    if (alpha_fmt != AV_PIX_FMT_NONE)
>>>>> +        *fmt++ = alpha_fmt;
>>>>>    *fmt++ = sps->pix_fmt;
>>>>>    *fmt = AV_PIX_FMT_NONE;
>>>>>
>>>>> @@ -3194,6 +3259,12 @@ static int hevc_frame_start(HEVCContext *s, HEVCLayerContext *l,
>>>>>                !sps->vui.common.video_signal_type_present_flag)
>>>>>                pix_fmt = sps_base->pix_fmt;
>>>>>
>>>>> +            // Ignore range mismatch between base layer and alpha layer
>>>>> +            if (ff_hevc_is_alpha_video(s) &&
>>>>> +                sps_base->pix_fmt == AV_PIX_FMT_YUV420P &&
>>>>> +                pix_fmt == AV_PIX_FMT_YUVJ420P)
>>>>> +                pix_fmt = sps_base->pix_fmt;
>>>>> +
>>>>>            if (pix_fmt     != sps_base->pix_fmt ||
>>>>>                sps->width  != sps_base->width   ||
>>>>>                sps->height != sps_base->height) {
>>>>> diff --git a/libavcodec/hevc/hevcdec.h b/libavcodec/hevc/hevcdec.h
>>>>> index 4e95035688..b2b725b5cd 100644
>>>>> --- a/libavcodec/hevc/hevcdec.h
>>>>> +++ b/libavcodec/hevc/hevcdec.h
>>>>> @@ -714,6 +714,8 @@ void ff_hevc_hls_residual_coding(HEVCLocalContext *lc, const HEVCPPS *pps,
>>>>>
>>>>> void ff_hevc_hls_mvd_coding(HEVCLocalContext *lc, int x0, int y0, int log2_cb_size);
>>>>>
>>>>> +int ff_hevc_is_alpha_video(const HEVCContext *s);
>>>>> +
>>>>> extern const uint8_t ff_hevc_qpel_extra_before[4];
>>>>> extern const uint8_t ff_hevc_qpel_extra_after[4];
>>>>> extern const uint8_t ff_hevc_qpel_extra[4];
>>>>> diff --git a/libavcodec/hevc/refs.c b/libavcodec/hevc/refs.c
>>>>> index dd7f7f95a8..6f10efd0ac 100644
>>>>> --- a/libavcodec/hevc/refs.c
>>>>> +++ b/libavcodec/hevc/refs.c
>>>>> @@ -79,6 +79,31 @@ void ff_hevc_flush_dpb(HEVCContext *s)
>>>>>    }
>>>>> }
>>>>>
>>>>> +static int replace_alpha_plane(AVFrame *alpha, AVFrame *base)
>>>>> +{
>>>>> +    AVBufferRef *base_a = av_frame_get_plane_buffer(base, 3);
>>>>> +    uintptr_t data = (uintptr_t)alpha->data[0];
>>>>> +    int ret;
>>>>> +
>>>>> +    for (int i = 0; i < FF_ARRAY_ELEMS(alpha->buf) && alpha->buf[i]; i++) {
>>>>> +        AVBufferRef *buf = alpha->buf[i];
>>>>> +        uintptr_t buf_begin = (uintptr_t)buf->data;
>>>>> +
>>>>> +        if (data >=  buf_begin && data < buf_begin + buf->size) {
>>>>> +            ret = av_buffer_replace(&alpha->buf[i], base_a);
>>>>> +            if (ret < 0)
>>>>> +                return ret;
>>>>> +
>>>>> +            alpha->linesize[0] = base->linesize[3];
>>>>> +            alpha->data[0] = base->data[3];
>>>>> +
>>>>> +            return 0;
>>>>> +        }
>>>>> +    }
>>>>
>>>> Why does the decoding process actually need multiple references to the
>>>> buffer of the alpha plane?
>>>
>>> I’m not sure if I understand your question correctly.
>>>
>>> 1. Both the base layer and the alpha layer are decoded as yuv420p.
>>> 2. The y plane of alpha layer is actually alpha.
>>> 3. The decoder finally output yuva, not two yuv420p.
>>>
>>> So here make y plane of alpha frame reference the alpha plane of base frame.
>>> When output, the base frame will contain YUV and alpha from two layers.
>>>
>>
>> The base layer AVFrame already contains a reference to the alpha plane;
>> so why do we need another one? Does the base AVFrame get unreferenced
>> before the alpha plane is finished decoding?
> 
> In the decoding process, it’s almost the same as MV-HEVC:
> 1. The base layer is decoded to the YUV of base frame, without touching the alpha plane.
> 2. The alpha layer is decoded to YUV of alpha frame.
> 
> We can output the two frames like MV-HEVC, but it’s user friendly to output in YUVA format.
> So I’m letting the alpha layer decoded to the alpha plane of the base layer. Or I can do the
> reverse. It’s the same.
> 
> We can skip the alpha frame totally. Then the decoding process and DPB buffer management
> will be different. Current method is simple but use more memory. I can work on that lately.
> 
It seems like you still don't get my question. Let me give it another
try: What would happen if you simply did not set alpha->buf[0] (but
still data[0] and linesize[0])? Would it crash? Or would it work because
the actual alpha plane is always referenced by the base layer AVFrame?

- Andreas

_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel

To unsubscribe, visit link above, or email
ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [FFmpeg-devel] [PATCH v7 3/4] avcodec/hevc: Add alpha layer support
  2025-02-11 16:10     ` Andreas Rheinhardt
  2025-02-11 16:21       ` Zhao Zhili
@ 2025-02-11 16:27       ` James Almer
  1 sibling, 0 replies; 11+ messages in thread
From: James Almer @ 2025-02-11 16:27 UTC (permalink / raw)
  To: ffmpeg-devel


[-- Attachment #1.1.1: Type: text/plain, Size: 10510 bytes --]

On 2/11/2025 1:10 PM, Andreas Rheinhardt wrote:
> Zhao Zhili:
>>
>>
>>> On Feb 11, 2025, at 23:37, Andreas Rheinhardt <andreas.rheinhardt@outlook.com> wrote:
>>>
>>> Zhao Zhili:
>>>> From: Zhao Zhili <zhilizhao@tencent.com>
>>>>
>>>> Signed-off-by: Zhao Zhili <zhilizhao@tencent.com>
>>>> ---
>>>> libavcodec/hevc/hevcdec.c | 73 ++++++++++++++++++++++++++++++++++++++-
>>>> libavcodec/hevc/hevcdec.h |  2 ++
>>>> libavcodec/hevc/refs.c    | 35 ++++++++++++++++++-
>>>> 3 files changed, 108 insertions(+), 2 deletions(-)
>>>>
>>>> diff --git a/libavcodec/hevc/hevcdec.c b/libavcodec/hevc/hevcdec.c
>>>> index e9c045f7a1..f71edf213b 100644
>>>> --- a/libavcodec/hevc/hevcdec.c
>>>> +++ b/libavcodec/hevc/hevcdec.c
>>>> @@ -466,6 +466,25 @@ static int export_multilayer(HEVCContext *s, const HEVCVPS *vps)
>>>>      return 0;
>>>> }
>>>>
>>>> +int ff_hevc_is_alpha_video(const HEVCContext *s)
>>>> +{
>>>> +    const HEVCVPS *vps = s->vps;
>>>> +    int ret = 0;
>>>> +
>>>> +    if (vps->nb_layers != 2 || !vps->layer_id_in_nuh[1])
>>>> +        return 0;
>>>> +
>>>> +    /* decode_vps_ext() guarantees that SCALABILITY_AUXILIARY with AuxId other
>>>> +     * than alpha cannot reach here.
>>>> +     */
>>>> +    ret = (s->vps->scalability_mask_flag & HEVC_SCALABILITY_AUXILIARY);
>>>> +
>>>> +    av_log(s->avctx, AV_LOG_DEBUG, "Multi layer video, %s alpha video\n",
>>>> +           ret ? "is" : "not");
>>>> +
>>>> +    return ret;
>>>> +}
>>>> +
>>>> static int setup_multilayer(HEVCContext *s, const HEVCVPS *vps)
>>>> {
>>>>      unsigned layers_active_output = 0, highest_layer;
>>>> @@ -473,6 +492,18 @@ static int setup_multilayer(HEVCContext *s, const HEVCVPS *vps)
>>>>      s->layers_active_output = 1;
>>>>      s->layers_active_decode = 1;
>>>>
>>>> +    if (ff_hevc_is_alpha_video(s)) {
>>>> +        const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(s->avctx->pix_fmt);
>>>> +
>>>> +        if (!(desc->flags & AV_PIX_FMT_FLAG_ALPHA))
>>>> +            return 0;
>>>> +
>>>> +        s->layers_active_decode = (1 << vps->nb_layers) - 1;
>>>> +        s->layers_active_output = 1;
>>>> +
>>>> +        return 0;
>>>> +    }
>>>> +
>>>>      // nothing requested - decode base layer only
>>>>      if (!s->nb_view_ids)
>>>>          return 0;
>>>> @@ -530,6 +561,34 @@ static int setup_multilayer(HEVCContext *s, const HEVCVPS *vps)
>>>>      return 0;
>>>> }
>>>>
>>>> +static enum AVPixelFormat map_to_alpha_format(HEVCContext *s,
>>>> +                                              enum AVPixelFormat pix_fmt)
>>>> +{
>>>> +    switch (pix_fmt) {
>>>> +    case AV_PIX_FMT_YUV420P:
>>>> +    case AV_PIX_FMT_YUVJ420P:
>>>> +        return AV_PIX_FMT_YUVA420P;
>>>> +    case AV_PIX_FMT_YUV420P10:
>>>> +        return AV_PIX_FMT_YUVA420P10;
>>>> +    case AV_PIX_FMT_YUV444P:
>>>> +        return AV_PIX_FMT_YUVA444P;
>>>> +    case AV_PIX_FMT_YUV422P:
>>>> +        return AV_PIX_FMT_YUVA422P;
>>>> +    case AV_PIX_FMT_YUV422P10LE:
>>>> +        return AV_PIX_FMT_YUVA422P10LE;
>>>> +    case AV_PIX_FMT_YUV444P10:
>>>> +        return AV_PIX_FMT_YUVA444P10;
>>>> +    case AV_PIX_FMT_YUV444P12:
>>>> +        return AV_PIX_FMT_YUVA444P12;
>>>> +    case AV_PIX_FMT_YUV422P12:
>>>> +        return AV_PIX_FMT_YUVA422P12;
>>>> +    default:
>>>> +        av_log(s->avctx, AV_LOG_WARNING, "No alpha pixel format map for %s\n",
>>>> +               av_get_pix_fmt_name(pix_fmt));
>>>> +        return AV_PIX_FMT_NONE;
>>>> +    }
>>>> +}
>>>> +
>>>> static enum AVPixelFormat get_format(HEVCContext *s, const HEVCSPS *sps)
>>>> {
>>>> #define HWACCEL_MAX (CONFIG_HEVC_DXVA2_HWACCEL + \
>>>> @@ -540,9 +599,13 @@ static enum AVPixelFormat get_format(HEVCContext *s, const HEVCSPS *sps)
>>>>                       CONFIG_HEVC_VIDEOTOOLBOX_HWACCEL + \
>>>>                       CONFIG_HEVC_VDPAU_HWACCEL + \
>>>>                       CONFIG_HEVC_VULKAN_HWACCEL)
>>>> -    enum AVPixelFormat pix_fmts[HWACCEL_MAX + 2], *fmt = pix_fmts;
>>>> +    enum AVPixelFormat pix_fmts[HWACCEL_MAX + 3], *fmt = pix_fmts;
>>>> +    enum AVPixelFormat alpha_fmt = AV_PIX_FMT_NONE;
>>>>      int ret;
>>>>
>>>> +    if (ff_hevc_is_alpha_video(s))
>>>> +        alpha_fmt = map_to_alpha_format(s, sps->pix_fmt);
>>>> +
>>>>      switch (sps->pix_fmt) {
>>>>      case AV_PIX_FMT_YUV420P:
>>>>      case AV_PIX_FMT_YUVJ420P:
>>>> @@ -664,6 +727,8 @@ static enum AVPixelFormat get_format(HEVCContext *s, const HEVCSPS *sps)
>>>>          break;
>>>>      }
>>>>
>>>> +    if (alpha_fmt != AV_PIX_FMT_NONE)
>>>> +        *fmt++ = alpha_fmt;
>>>>      *fmt++ = sps->pix_fmt;
>>>>      *fmt = AV_PIX_FMT_NONE;
>>>>
>>>> @@ -3194,6 +3259,12 @@ static int hevc_frame_start(HEVCContext *s, HEVCLayerContext *l,
>>>>                  !sps->vui.common.video_signal_type_present_flag)
>>>>                  pix_fmt = sps_base->pix_fmt;
>>>>
>>>> +            // Ignore range mismatch between base layer and alpha layer
>>>> +            if (ff_hevc_is_alpha_video(s) &&
>>>> +                sps_base->pix_fmt == AV_PIX_FMT_YUV420P &&
>>>> +                pix_fmt == AV_PIX_FMT_YUVJ420P)
>>>> +                pix_fmt = sps_base->pix_fmt;
>>>> +
>>>>              if (pix_fmt     != sps_base->pix_fmt ||
>>>>                  sps->width  != sps_base->width   ||
>>>>                  sps->height != sps_base->height) {
>>>> diff --git a/libavcodec/hevc/hevcdec.h b/libavcodec/hevc/hevcdec.h
>>>> index 4e95035688..b2b725b5cd 100644
>>>> --- a/libavcodec/hevc/hevcdec.h
>>>> +++ b/libavcodec/hevc/hevcdec.h
>>>> @@ -714,6 +714,8 @@ void ff_hevc_hls_residual_coding(HEVCLocalContext *lc, const HEVCPPS *pps,
>>>>
>>>> void ff_hevc_hls_mvd_coding(HEVCLocalContext *lc, int x0, int y0, int log2_cb_size);
>>>>
>>>> +int ff_hevc_is_alpha_video(const HEVCContext *s);
>>>> +
>>>> extern const uint8_t ff_hevc_qpel_extra_before[4];
>>>> extern const uint8_t ff_hevc_qpel_extra_after[4];
>>>> extern const uint8_t ff_hevc_qpel_extra[4];
>>>> diff --git a/libavcodec/hevc/refs.c b/libavcodec/hevc/refs.c
>>>> index dd7f7f95a8..6f10efd0ac 100644
>>>> --- a/libavcodec/hevc/refs.c
>>>> +++ b/libavcodec/hevc/refs.c
>>>> @@ -79,6 +79,31 @@ void ff_hevc_flush_dpb(HEVCContext *s)
>>>>      }
>>>> }
>>>>
>>>> +static int replace_alpha_plane(AVFrame *alpha, AVFrame *base)
>>>> +{
>>>> +    AVBufferRef *base_a = av_frame_get_plane_buffer(base, 3);
>>>> +    uintptr_t data = (uintptr_t)alpha->data[0];
>>>> +    int ret;
>>>> +
>>>> +    for (int i = 0; i < FF_ARRAY_ELEMS(alpha->buf) && alpha->buf[i]; i++) {
>>>> +        AVBufferRef *buf = alpha->buf[i];
>>>> +        uintptr_t buf_begin = (uintptr_t)buf->data;
>>>> +
>>>> +        if (data >=  buf_begin && data < buf_begin + buf->size) {
>>>> +            ret = av_buffer_replace(&alpha->buf[i], base_a);
>>>> +            if (ret < 0)
>>>> +                return ret;
>>>> +
>>>> +            alpha->linesize[0] = base->linesize[3];
>>>> +            alpha->data[0] = base->data[3];
>>>> +
>>>> +            return 0;
>>>> +        }
>>>> +    }
>>>
>>> Why does the decoding process actually need multiple references to the
>>> buffer of the alpha plane?
>>
>> I’m not sure if I understand your question correctly.
>>
>> 1. Both the base layer and the alpha layer are decoded as yuv420p.
>> 2. The y plane of alpha layer is actually alpha.
>> 3. The decoder finally output yuva, not two yuv420p.
>>
>> So here make y plane of alpha frame reference the alpha plane of base frame.
>> When output, the base frame will contain YUV and alpha from two layers.
>>
> 
> The base layer AVFrame already contains a reference to the alpha plane;
> so why do we need another one? Does the base AVFrame get unreferenced
> before the alpha plane is finished decoding?

What he's doing is making the alpha layer frame contain a reference to 
the buffer that corresponds to the fourth component in the main (output) 
frame, and dropping the one that was allocated for it. The result is 
that, when decoding the alpha bitstream, the picture data will be stored 
in the output frame's fourth component buffer.
It's not 100% clean (We'll be writing data to a buffer with more than 
one reference), but it works.

> 
>>>
>>>> +
>>>> +    return AVERROR_BUG;
>>>> +}
>>>> +
>>>> static HEVCFrame *alloc_frame(HEVCContext *s, HEVCLayerContext *l)
>>>> {
>>>>      const HEVCVPS *vps = l->sps->vps;
>>>> @@ -103,7 +128,7 @@ static HEVCFrame *alloc_frame(HEVCContext *s, HEVCLayerContext *l)
>>>>          }
>>>>
>>>>          // add view ID side data if it's nontrivial
>>>> -        if (vps->nb_layers > 1 || view_id) {
>>>> +        if (!ff_hevc_is_alpha_video(s) && (vps->nb_layers > 1 || view_id)) {
>>>>              HEVCSEITDRDI *tdrdi = &s->sei.tdrdi;
>>>>              AVFrameSideData *sd = av_frame_side_data_new(&frame->f->side_data,
>>>>                                                           &frame->f->nb_side_data,
>>>> @@ -161,7 +186,15 @@ static HEVCFrame *alloc_frame(HEVCContext *s, HEVCLayerContext *l)
>>>>          if (ret < 0)
>>>>              goto fail;
>>>>
>>>> +
>>>>          frame->pps = av_refstruct_ref_c(s->pps);
>>>> +        if (l != &s->layers[0] && ff_hevc_is_alpha_video(s)) {
>>>> +            AVFrame *alpha = frame->f;
>>>> +            AVFrame *base = s->layers[0].cur_frame->f;
>>>> +            ret = replace_alpha_plane(alpha, base);
>>>> +            if (ret < 0)
>>>> +                goto fail;
>>>> +        }
>>>>
>>>>          return frame;
>>>> fail:
>>>
>>> _______________________________________________
>>> ffmpeg-devel mailing list
>>> ffmpeg-devel@ffmpeg.org
>>> https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
>>>
>>> To unsubscribe, visit link above, or email
>>> ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".
>>
>> _______________________________________________
>> ffmpeg-devel mailing list
>> ffmpeg-devel@ffmpeg.org
>> https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
>>
>> To unsubscribe, visit link above, or email
>> ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".
> 
> _______________________________________________
> ffmpeg-devel mailing list
> ffmpeg-devel@ffmpeg.org
> https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
> 
> To unsubscribe, visit link above, or email
> ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".


[-- Attachment #1.2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 495 bytes --]

[-- Attachment #2: Type: text/plain, Size: 251 bytes --]

_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel

To unsubscribe, visit link above, or email
ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [FFmpeg-devel] [PATCH v7 3/4] avcodec/hevc: Add alpha layer support
  2025-02-11 16:25         ` Andreas Rheinhardt
@ 2025-02-11 16:50           ` Zhao Zhili
  0 siblings, 0 replies; 11+ messages in thread
From: Zhao Zhili @ 2025-02-11 16:50 UTC (permalink / raw)
  To: FFmpeg development discussions and patches



> On Feb 12, 2025, at 00:25, Andreas Rheinhardt <andreas.rheinhardt@outlook.com> wrote:
> 
> Zhao Zhili:
>> 
>> 
>>> On Feb 12, 2025, at 00:10, Andreas Rheinhardt <andreas.rheinhardt@outlook.com> wrote:
>>> 
>>> Zhao Zhili:
>>>> 
>>>> 
>>>>> On Feb 11, 2025, at 23:37, Andreas Rheinhardt <andreas.rheinhardt@outlook.com> wrote:
>>>>> 
>>>>> Zhao Zhili:
>>>>>> From: Zhao Zhili <zhilizhao@tencent.com>
>>>>>> 
>>>>>> Signed-off-by: Zhao Zhili <zhilizhao@tencent.com>
>>>>>> ---
>>>>>> libavcodec/hevc/hevcdec.c | 73 ++++++++++++++++++++++++++++++++++++++-
>>>>>> libavcodec/hevc/hevcdec.h |  2 ++
>>>>>> libavcodec/hevc/refs.c    | 35 ++++++++++++++++++-
>>>>>> 3 files changed, 108 insertions(+), 2 deletions(-)
>>>>>> 
>>>>>> diff --git a/libavcodec/hevc/hevcdec.c b/libavcodec/hevc/hevcdec.c
>>>>>> index e9c045f7a1..f71edf213b 100644
>>>>>> --- a/libavcodec/hevc/hevcdec.c
>>>>>> +++ b/libavcodec/hevc/hevcdec.c
>>>>>> @@ -466,6 +466,25 @@ static int export_multilayer(HEVCContext *s, const HEVCVPS *vps)
>>>>>>   return 0;
>>>>>> }
>>>>>> 
>>>>>> +int ff_hevc_is_alpha_video(const HEVCContext *s)
>>>>>> +{
>>>>>> +    const HEVCVPS *vps = s->vps;
>>>>>> +    int ret = 0;
>>>>>> +
>>>>>> +    if (vps->nb_layers != 2 || !vps->layer_id_in_nuh[1])
>>>>>> +        return 0;
>>>>>> +
>>>>>> +    /* decode_vps_ext() guarantees that SCALABILITY_AUXILIARY with AuxId other
>>>>>> +     * than alpha cannot reach here.
>>>>>> +     */
>>>>>> +    ret = (s->vps->scalability_mask_flag & HEVC_SCALABILITY_AUXILIARY);
>>>>>> +
>>>>>> +    av_log(s->avctx, AV_LOG_DEBUG, "Multi layer video, %s alpha video\n",
>>>>>> +           ret ? "is" : "not");
>>>>>> +
>>>>>> +    return ret;
>>>>>> +}
>>>>>> +
>>>>>> static int setup_multilayer(HEVCContext *s, const HEVCVPS *vps)
>>>>>> {
>>>>>>   unsigned layers_active_output = 0, highest_layer;
>>>>>> @@ -473,6 +492,18 @@ static int setup_multilayer(HEVCContext *s, const HEVCVPS *vps)
>>>>>>   s->layers_active_output = 1;
>>>>>>   s->layers_active_decode = 1;
>>>>>> 
>>>>>> +    if (ff_hevc_is_alpha_video(s)) {
>>>>>> +        const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(s->avctx->pix_fmt);
>>>>>> +
>>>>>> +        if (!(desc->flags & AV_PIX_FMT_FLAG_ALPHA))
>>>>>> +            return 0;
>>>>>> +
>>>>>> +        s->layers_active_decode = (1 << vps->nb_layers) - 1;
>>>>>> +        s->layers_active_output = 1;
>>>>>> +
>>>>>> +        return 0;
>>>>>> +    }
>>>>>> +
>>>>>>   // nothing requested - decode base layer only
>>>>>>   if (!s->nb_view_ids)
>>>>>>       return 0;
>>>>>> @@ -530,6 +561,34 @@ static int setup_multilayer(HEVCContext *s, const HEVCVPS *vps)
>>>>>>   return 0;
>>>>>> }
>>>>>> 
>>>>>> +static enum AVPixelFormat map_to_alpha_format(HEVCContext *s,
>>>>>> +                                              enum AVPixelFormat pix_fmt)
>>>>>> +{
>>>>>> +    switch (pix_fmt) {
>>>>>> +    case AV_PIX_FMT_YUV420P:
>>>>>> +    case AV_PIX_FMT_YUVJ420P:
>>>>>> +        return AV_PIX_FMT_YUVA420P;
>>>>>> +    case AV_PIX_FMT_YUV420P10:
>>>>>> +        return AV_PIX_FMT_YUVA420P10;
>>>>>> +    case AV_PIX_FMT_YUV444P:
>>>>>> +        return AV_PIX_FMT_YUVA444P;
>>>>>> +    case AV_PIX_FMT_YUV422P:
>>>>>> +        return AV_PIX_FMT_YUVA422P;
>>>>>> +    case AV_PIX_FMT_YUV422P10LE:
>>>>>> +        return AV_PIX_FMT_YUVA422P10LE;
>>>>>> +    case AV_PIX_FMT_YUV444P10:
>>>>>> +        return AV_PIX_FMT_YUVA444P10;
>>>>>> +    case AV_PIX_FMT_YUV444P12:
>>>>>> +        return AV_PIX_FMT_YUVA444P12;
>>>>>> +    case AV_PIX_FMT_YUV422P12:
>>>>>> +        return AV_PIX_FMT_YUVA422P12;
>>>>>> +    default:
>>>>>> +        av_log(s->avctx, AV_LOG_WARNING, "No alpha pixel format map for %s\n",
>>>>>> +               av_get_pix_fmt_name(pix_fmt));
>>>>>> +        return AV_PIX_FMT_NONE;
>>>>>> +    }
>>>>>> +}
>>>>>> +
>>>>>> static enum AVPixelFormat get_format(HEVCContext *s, const HEVCSPS *sps)
>>>>>> {
>>>>>> #define HWACCEL_MAX (CONFIG_HEVC_DXVA2_HWACCEL + \
>>>>>> @@ -540,9 +599,13 @@ static enum AVPixelFormat get_format(HEVCContext *s, const HEVCSPS *sps)
>>>>>>                    CONFIG_HEVC_VIDEOTOOLBOX_HWACCEL + \
>>>>>>                    CONFIG_HEVC_VDPAU_HWACCEL + \
>>>>>>                    CONFIG_HEVC_VULKAN_HWACCEL)
>>>>>> -    enum AVPixelFormat pix_fmts[HWACCEL_MAX + 2], *fmt = pix_fmts;
>>>>>> +    enum AVPixelFormat pix_fmts[HWACCEL_MAX + 3], *fmt = pix_fmts;
>>>>>> +    enum AVPixelFormat alpha_fmt = AV_PIX_FMT_NONE;
>>>>>>   int ret;
>>>>>> 
>>>>>> +    if (ff_hevc_is_alpha_video(s))
>>>>>> +        alpha_fmt = map_to_alpha_format(s, sps->pix_fmt);
>>>>>> +
>>>>>>   switch (sps->pix_fmt) {
>>>>>>   case AV_PIX_FMT_YUV420P:
>>>>>>   case AV_PIX_FMT_YUVJ420P:
>>>>>> @@ -664,6 +727,8 @@ static enum AVPixelFormat get_format(HEVCContext *s, const HEVCSPS *sps)
>>>>>>       break;
>>>>>>   }
>>>>>> 
>>>>>> +    if (alpha_fmt != AV_PIX_FMT_NONE)
>>>>>> +        *fmt++ = alpha_fmt;
>>>>>>   *fmt++ = sps->pix_fmt;
>>>>>>   *fmt = AV_PIX_FMT_NONE;
>>>>>> 
>>>>>> @@ -3194,6 +3259,12 @@ static int hevc_frame_start(HEVCContext *s, HEVCLayerContext *l,
>>>>>>               !sps->vui.common.video_signal_type_present_flag)
>>>>>>               pix_fmt = sps_base->pix_fmt;
>>>>>> 
>>>>>> +            // Ignore range mismatch between base layer and alpha layer
>>>>>> +            if (ff_hevc_is_alpha_video(s) &&
>>>>>> +                sps_base->pix_fmt == AV_PIX_FMT_YUV420P &&
>>>>>> +                pix_fmt == AV_PIX_FMT_YUVJ420P)
>>>>>> +                pix_fmt = sps_base->pix_fmt;
>>>>>> +
>>>>>>           if (pix_fmt     != sps_base->pix_fmt ||
>>>>>>               sps->width  != sps_base->width   ||
>>>>>>               sps->height != sps_base->height) {
>>>>>> diff --git a/libavcodec/hevc/hevcdec.h b/libavcodec/hevc/hevcdec.h
>>>>>> index 4e95035688..b2b725b5cd 100644
>>>>>> --- a/libavcodec/hevc/hevcdec.h
>>>>>> +++ b/libavcodec/hevc/hevcdec.h
>>>>>> @@ -714,6 +714,8 @@ void ff_hevc_hls_residual_coding(HEVCLocalContext *lc, const HEVCPPS *pps,
>>>>>> 
>>>>>> void ff_hevc_hls_mvd_coding(HEVCLocalContext *lc, int x0, int y0, int log2_cb_size);
>>>>>> 
>>>>>> +int ff_hevc_is_alpha_video(const HEVCContext *s);
>>>>>> +
>>>>>> extern const uint8_t ff_hevc_qpel_extra_before[4];
>>>>>> extern const uint8_t ff_hevc_qpel_extra_after[4];
>>>>>> extern const uint8_t ff_hevc_qpel_extra[4];
>>>>>> diff --git a/libavcodec/hevc/refs.c b/libavcodec/hevc/refs.c
>>>>>> index dd7f7f95a8..6f10efd0ac 100644
>>>>>> --- a/libavcodec/hevc/refs.c
>>>>>> +++ b/libavcodec/hevc/refs.c
>>>>>> @@ -79,6 +79,31 @@ void ff_hevc_flush_dpb(HEVCContext *s)
>>>>>>   }
>>>>>> }
>>>>>> 
>>>>>> +static int replace_alpha_plane(AVFrame *alpha, AVFrame *base)
>>>>>> +{
>>>>>> +    AVBufferRef *base_a = av_frame_get_plane_buffer(base, 3);
>>>>>> +    uintptr_t data = (uintptr_t)alpha->data[0];
>>>>>> +    int ret;
>>>>>> +
>>>>>> +    for (int i = 0; i < FF_ARRAY_ELEMS(alpha->buf) && alpha->buf[i]; i++) {
>>>>>> +        AVBufferRef *buf = alpha->buf[i];
>>>>>> +        uintptr_t buf_begin = (uintptr_t)buf->data;
>>>>>> +
>>>>>> +        if (data >=  buf_begin && data < buf_begin + buf->size) {
>>>>>> +            ret = av_buffer_replace(&alpha->buf[i], base_a);
>>>>>> +            if (ret < 0)
>>>>>> +                return ret;
>>>>>> +
>>>>>> +            alpha->linesize[0] = base->linesize[3];
>>>>>> +            alpha->data[0] = base->data[3];
>>>>>> +
>>>>>> +            return 0;
>>>>>> +        }
>>>>>> +    }
>>>>> 
>>>>> Why does the decoding process actually need multiple references to the
>>>>> buffer of the alpha plane?
>>>> 
>>>> I’m not sure if I understand your question correctly.
>>>> 
>>>> 1. Both the base layer and the alpha layer are decoded as yuv420p.
>>>> 2. The y plane of alpha layer is actually alpha.
>>>> 3. The decoder finally output yuva, not two yuv420p.
>>>> 
>>>> So here make y plane of alpha frame reference the alpha plane of base frame.
>>>> When output, the base frame will contain YUV and alpha from two layers.
>>>> 
>>> 
>>> The base layer AVFrame already contains a reference to the alpha plane;
>>> so why do we need another one? Does the base AVFrame get unreferenced
>>> before the alpha plane is finished decoding?
>> 
>> In the decoding process, it’s almost the same as MV-HEVC:
>> 1. The base layer is decoded to the YUV of base frame, without touching the alpha plane.
>> 2. The alpha layer is decoded to YUV of alpha frame.
>> 
>> We can output the two frames like MV-HEVC, but it’s user friendly to output in YUVA format.
>> So I’m letting the alpha layer decoded to the alpha plane of the base layer. Or I can do the
>> reverse. It’s the same.
>> 
>> We can skip the alpha frame totally. Then the decoding process and DPB buffer management
>> will be different. Current method is simple but use more memory. I can work on that lately.
>> 
> It seems like you still don't get my question. Let me give it another
> try: What would happen if you simply did not set alpha->buf[0] (but
> still data[0] and linesize[0])? Would it crash? Or would it work because
> the actual alpha plane is always referenced by the base layer AVFrame?

It would work in normal case, base layer AVFrame should outlive alpha layer AVFrame. But it’s
safer to keep a reference. Another benefit is av_buffer_replace released the original alpha plane,
which can save memory.

> 
> - Andreas
> 
> _______________________________________________
> ffmpeg-devel mailing list
> ffmpeg-devel@ffmpeg.org
> https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
> 
> To unsubscribe, visit link above, or email
> ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".

_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel

To unsubscribe, visit link above, or email
ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".

^ permalink raw reply	[flat|nested] 11+ messages in thread

end of thread, other threads:[~2025-02-11 16:51 UTC | newest]

Thread overview: 11+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2025-02-11 13:21 [FFmpeg-devel] [PATCH v7 3/4] avcodec/hevc: Add alpha layer support Zhao Zhili
2025-02-11 15:37 ` Andreas Rheinhardt
2025-02-11 15:57   ` Zhao Zhili
2025-02-11 16:02     ` James Almer
2025-02-11 16:11       ` Zhao Zhili
2025-02-11 16:13         ` James Almer
2025-02-11 16:10     ` Andreas Rheinhardt
2025-02-11 16:21       ` Zhao Zhili
2025-02-11 16:25         ` Andreas Rheinhardt
2025-02-11 16:50           ` Zhao Zhili
2025-02-11 16:27       ` James Almer

Git Inbox Mirror of the ffmpeg-devel mailing list - see https://ffmpeg.org/mailman/listinfo/ffmpeg-devel

This inbox may be cloned and mirrored by anyone:

	git clone --mirror https://master.gitmailbox.com/ffmpegdev/0 ffmpegdev/git/0.git

	# If you have public-inbox 1.1+ installed, you may
	# initialize and index your mirror using the following commands:
	public-inbox-init -V2 ffmpegdev ffmpegdev/ https://master.gitmailbox.com/ffmpegdev \
		ffmpegdev@gitmailbox.com
	public-inbox-index ffmpegdev

Example config snippet for mirrors.


AGPL code for this site: git clone https://public-inbox.org/public-inbox.git