* [FFmpeg-devel] [PATCH v4 2/3] avcodec/hevc/ps: Add basic HEVC_SCALABILITY_AUXILIARY support
@ 2025-02-06 3:49 Zhao Zhili
2025-02-06 13:25 ` James Almer
0 siblings, 1 reply; 3+ messages in thread
From: Zhao Zhili @ 2025-02-06 3:49 UTC (permalink / raw)
To: ffmpeg-devel; +Cc: Zhao Zhili
From: Zhao Zhili <zhilizhao@tencent.com>
Only implementing what's needed for HEVC with alpha.
Signed-off-by: Zhao Zhili <zhilizhao@tencent.com>
---
libavcodec/hevc/hevc.h | 5 ++
libavcodec/hevc/ps.c | 126 +++++++++++++++++++++++++++++------------
libavcodec/hevc/ps.h | 4 ++
3 files changed, 98 insertions(+), 37 deletions(-)
diff --git a/libavcodec/hevc/hevc.h b/libavcodec/hevc/hevc.h
index b2229fda40..710786a89d 100644
--- a/libavcodec/hevc/hevc.h
+++ b/libavcodec/hevc/hevc.h
@@ -170,4 +170,9 @@ enum HEVCScalabilityMask {
HEVC_SCALABILITY_MASK_MAX = 0xFFFF,
};
+enum HEVCAuxId {
+ HEVC_AUX_ALPHA = 1,
+ HEVC_AUX_DEPTH = 2,
+};
+
#endif /* AVCODEC_HEVC_HEVC_H */
diff --git a/libavcodec/hevc/ps.c b/libavcodec/hevc/ps.c
index 861a6bb0a2..4f18cd72e4 100644
--- a/libavcodec/hevc/ps.c
+++ b/libavcodec/hevc/ps.c
@@ -460,14 +460,17 @@ static int decode_vps_ext(GetBitContext *gb, AVCodecContext *avctx, HEVCVPS *vps
uint64_t layer1_id_included)
{
PTL ptl_dummy;
- uint8_t max_sub_layers[HEVC_MAX_LAYERS];
+ uint8_t max_sub_layers[HEVC_MAX_LAYERS] = {1, 1};
+ uint8_t dimension_id_len[16] = {0};
+ uint8_t dimension_id[16] = {0};
+ unsigned n;
- int splitting_flag, dimension_id_len, view_id_len, num_add_olss, num_scalability_types,
+ int splitting_flag, view_id_len, num_add_olss, num_scalability_types,
default_output_layer_idc, direct_dep_type_len, direct_dep_type,
sub_layers_max_present, sub_layer_flag_info_present_flag, nb_ptl;
unsigned non_vui_extension_length;
- if (vps->vps_max_layers == 1 || vps->vps_num_layer_sets == 1) {
+ if (vps->vps_max_layers == 1) {
av_log(avctx, AV_LOG_VERBOSE, "Ignoring VPS extensions with a single layer\n");
return 0;
}
@@ -520,7 +523,8 @@ static int decode_vps_ext(GetBitContext *gb, AVCodecContext *avctx, HEVCVPS *vps
*/
vps->nb_layers = 2;
- if (parse_ptl(gb, avctx, 0, &ptl_dummy, vps->vps_max_sub_layers) < 0)
+ if (vps->vps_base_layer_internal_flag &&
+ parse_ptl(gb, avctx, 0, &ptl_dummy, vps->vps_max_sub_layers) < 0)
return AVERROR_INVALIDDATA;
splitting_flag = get_bits1(gb);
@@ -529,20 +533,25 @@ static int decode_vps_ext(GetBitContext *gb, AVCodecContext *avctx, HEVCVPS *vps
if (!num_scalability_types) {
av_log(avctx, AV_LOG_ERROR, "Missing scalability mask\n");
return AVERROR_INVALIDDATA;
- } else if (num_scalability_types > 1) {
- av_log(avctx, AV_LOG_ERROR, "Scalability number %d not supported\n",
- num_scalability_types);
- return AVERROR_PATCHWELCOME;
}
- if (!(vps->scalability_mask_flag & HEVC_SCALABILITY_MULTIVIEW)) {
+ if (!(vps->scalability_mask_flag &
+ (HEVC_SCALABILITY_MULTIVIEW | HEVC_SCALABILITY_AUXILIARY))) {
av_log(avctx, AV_LOG_ERROR, "Scalability type %d not supported\n",
15 - ff_ctz(vps->scalability_mask_flag));
return AVERROR_PATCHWELCOME;
}
+ // x265 specify MULTIVIEW when the stream really is alpha video only.
+ if (num_scalability_types > 1)
+ av_log(avctx, AV_LOG_WARNING, "Multiple scalability types presented\n");
- if (!splitting_flag)
- dimension_id_len = get_bits(gb, 3) + 1;
+ n = 0;
+ for (int i = 0; i < num_scalability_types - splitting_flag; i++) {
+ dimension_id_len[i] = get_bits(gb, 3) + 1;
+ n += dimension_id_len[i];
+ }
+ if (splitting_flag)
+ dimension_id_len[num_scalability_types - 1] = 5 - n;
if (get_bits1(gb)) { /* vps_nuh_layer_id_present_flag */
int layer_id_in_nuh = get_bits(gb, 6);
@@ -559,28 +568,57 @@ static int decode_vps_ext(GetBitContext *gb, AVCodecContext *avctx, HEVCVPS *vps
}
if (!splitting_flag) {
- int view_idx = get_bits(gb, dimension_id_len);
- if (view_idx != 1) {
- av_log(avctx, AV_LOG_ERROR, "Unexpected ViewOrderIdx: %d\n", view_idx);
+ int index = 0;
+
+ for (int i = 0; i < num_scalability_types; i++)
+ dimension_id[i] = get_bits(gb, dimension_id_len[i]);
+
+ if (vps->scalability_mask_flag & HEVC_SCALABILITY_MULTIVIEW)
+ index++;
+
+ /* AuxId 1 is alpha, 2 is depth. Only support alpha */
+ if (vps->scalability_mask_flag & HEVC_SCALABILITY_AUXILIARY &&
+ dimension_id[index] != HEVC_AUX_ALPHA) {
+ av_log(avctx, AV_LOG_WARNING,
+ "Unsupported dimension_id %d for HEVC_SCALABILITY_AUXILIARY\n",
+ dimension_id[index]);
return AVERROR_PATCHWELCOME;
}
}
view_id_len = get_bits(gb, 4);
- if (view_id_len)
- for (int i = 0; i < 2 /* NumViews */; i++)
+ if (view_id_len) {
+ n = (vps->scalability_mask_flag & HEVC_SCALABILITY_MULTIVIEW) ? 2 : 1;
+ for (int i = 0; i < n; i++)
vps->view_id[i] = get_bits(gb, view_id_len);
+ }
- if (!get_bits1(gb) /* direct_dependency_flag */) {
- av_log(avctx, AV_LOG_WARNING, "Independent output layers not supported\n");
- return AVERROR_PATCHWELCOME;
+ /* direct_dependency_flag */
+ vps->num_direct_ref_layers[1] = get_bits1(gb);
+ if (!vps->num_direct_ref_layers[1]) {
+ vps->num_add_layer_sets = get_ue_golomb(gb);
+ if (vps->num_add_layer_sets > 1) {
+ av_log(avctx, AV_LOG_WARNING,
+ "Unsupported num_add_layer_sets: %d\n", vps->num_add_layer_sets);
+ return AVERROR_PATCHWELCOME;
+ }
+
+ if (vps->num_add_layer_sets) {
+ /* highest_layer_idx_plus1 */
+ if (!get_bits1(gb))
+ return AVERROR_PATCHWELCOME;
+ }
}
- vps->num_direct_ref_layers[1] = 1;
+ vps->num_output_layer_sets = vps->vps_num_layer_sets + vps->num_add_layer_sets;
+ if (vps->num_output_layer_sets != 2)
+ return AVERROR_INVALIDDATA;
sub_layers_max_present = get_bits1(gb); // vps_sub_layers_max_minus1_present_flag
- for (int i = 0; i < vps->vps_max_layers; i++)
- max_sub_layers[i] = sub_layers_max_present ? get_bits(gb, 3) + 1 :
- vps->vps_max_sub_layers;
+ if (sub_layers_max_present) {
+ for (int i = 0; i < vps->vps_max_layers; i++)
+ max_sub_layers[i] = sub_layers_max_present ? get_bits(gb, 3) + 1 :
+ vps->vps_max_sub_layers;
+ }
if (get_bits1(gb) /* max_tid_ref_present_flag */)
skip_bits(gb, 3); // max_tid_il_ref_pics_plus1
@@ -613,18 +651,24 @@ static int decode_vps_ext(GetBitContext *gb, AVCodecContext *avctx, HEVCVPS *vps
}
/* Consequence of established layer dependencies */
- if (layer1_id_included != ((1 << vps->layer_id_in_nuh[0]) |
+ if (layer1_id_included &&
+ layer1_id_included != ((1 << vps->layer_id_in_nuh[0]) |
(1 << vps->layer_id_in_nuh[1]))) {
- av_log(avctx, AV_LOG_ERROR, "Dependent layer not included in layer ID?\n");
- return AVERROR_PATCHWELCOME;
+ av_log(avctx, AV_LOG_ERROR,
+ "Dependent layer not included in layer ID?\n");
+ return AVERROR_PATCHWELCOME;
}
+ if (!layer1_id_included)
+ vps->ols[1] = 2;
+ else
+ vps->ols[1] = 3;
- vps->num_output_layer_sets = 2;
- vps->ols[1] = 3;
+ if (vps->vps_num_layer_sets == 1 || default_output_layer_idc == 2)
+ skip_bits1(gb);
for (int j = 0; j < av_popcount64(vps->ols[1]); j++) {
int ptl_idx = get_bits(gb, av_ceil_log2(nb_ptl));
- if (ptl_idx < 1 || ptl_idx >= nb_ptl) {
+ if (ptl_idx >= nb_ptl) {
av_log(avctx, AV_LOG_ERROR, "Invalid PTL index: %d\n", ptl_idx);
return AVERROR_INVALIDDATA;
}
@@ -667,6 +711,8 @@ static int decode_vps_ext(GetBitContext *gb, AVCodecContext *avctx, HEVCVPS *vps
vps->max_one_active_ref_layer = get_bits1(gb);
vps->poc_lsb_aligned = get_bits1(gb);
+ if (!vps->num_direct_ref_layers[1])
+ vps->poc_lsb_not_present = get_bits1(gb) << 1;
sub_layer_flag_info_present_flag = get_bits1(gb);
for (int j = 0; j < FFMAX(max_sub_layers[0], max_sub_layers[1]); j++) {
@@ -688,12 +734,14 @@ static int decode_vps_ext(GetBitContext *gb, AVCodecContext *avctx, HEVCVPS *vps
return AVERROR_INVALIDDATA;
}
- skip_bits1(gb); /* direct_depenency_all_layers_flag */
- direct_dep_type = get_bits_long(gb, direct_dep_type_len);
- if (direct_dep_type > HEVC_DEP_TYPE_BOTH) {
- av_log(avctx, AV_LOG_WARNING, "Unsupported direct_dep_type: %d\n",
- direct_dep_type);
- return AVERROR_PATCHWELCOME;
+ /* direct_dependency_all_layers_flag */
+ if (get_bits1(gb) || vps->num_direct_ref_layers[1]) {
+ direct_dep_type = get_bits_long(gb, direct_dep_type_len);
+ if (direct_dep_type > HEVC_DEP_TYPE_BOTH) {
+ av_log(avctx, AV_LOG_WARNING, "Unsupported direct_dep_type: %d\n",
+ direct_dep_type);
+ return AVERROR_PATCHWELCOME;
+ }
}
non_vui_extension_length = get_ue_golomb(gb);
@@ -741,8 +789,12 @@ int ff_hevc_decode_nal_vps(GetBitContext *gb, AVCodecContext *avctx,
}
vps->vps_id = vps_id;
- if (get_bits(gb, 2) != 3) { // vps_reserved_three_2bits
- av_log(avctx, AV_LOG_ERROR, "vps_reserved_three_2bits is not three\n");
+ vps->vps_base_layer_internal_flag = get_bits1(gb);
+ vps->vps_base_layer_available_flag = get_bits1(gb);
+ if (!vps->vps_base_layer_internal_flag || !vps->vps_base_layer_available_flag) {
+ av_log(avctx, AV_LOG_ERROR,
+ "vps_base_layer_internal_flag or vps_base_layer_available_flag not set\n");
+ ret = AVERROR_PATCHWELCOME;
goto err;
}
diff --git a/libavcodec/hevc/ps.h b/libavcodec/hevc/ps.h
index d3465e3d27..f706b889e6 100644
--- a/libavcodec/hevc/ps.h
+++ b/libavcodec/hevc/ps.h
@@ -171,6 +171,9 @@ typedef struct RepFormat {
typedef struct HEVCVPS {
unsigned int vps_id;
+ uint8_t vps_base_layer_internal_flag;
+ uint8_t vps_base_layer_available_flag;
+
uint8_t vps_temporal_id_nesting_flag;
int vps_max_layers;
int vps_max_sub_layers; ///< vps_max_temporal_layers_minus1 + 1
@@ -237,6 +240,7 @@ typedef struct HEVCVPS {
// NumDirectRefLayers[layer_idx]
uint8_t num_direct_ref_layers[HEVC_VPS_MAX_LAYERS];
+ uint8_t num_add_layer_sets;
RepFormat rep_format;
--
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] 3+ messages in thread
* Re: [FFmpeg-devel] [PATCH v4 2/3] avcodec/hevc/ps: Add basic HEVC_SCALABILITY_AUXILIARY support
2025-02-06 3:49 [FFmpeg-devel] [PATCH v4 2/3] avcodec/hevc/ps: Add basic HEVC_SCALABILITY_AUXILIARY support Zhao Zhili
@ 2025-02-06 13:25 ` James Almer
2025-02-06 14:28 ` Zhao Zhili
0 siblings, 1 reply; 3+ messages in thread
From: James Almer @ 2025-02-06 13:25 UTC (permalink / raw)
To: ffmpeg-devel
[-- Attachment #1.1.1: Type: text/plain, Size: 11784 bytes --]
On 2/6/2025 12:49 AM, Zhao Zhili wrote:
> From: Zhao Zhili <zhilizhao@tencent.com>
>
> Only implementing what's needed for HEVC with alpha.
>
> Signed-off-by: Zhao Zhili <zhilizhao@tencent.com>
> ---
> libavcodec/hevc/hevc.h | 5 ++
> libavcodec/hevc/ps.c | 126 +++++++++++++++++++++++++++++------------
> libavcodec/hevc/ps.h | 4 ++
> 3 files changed, 98 insertions(+), 37 deletions(-)
>
> diff --git a/libavcodec/hevc/hevc.h b/libavcodec/hevc/hevc.h
> index b2229fda40..710786a89d 100644
> --- a/libavcodec/hevc/hevc.h
> +++ b/libavcodec/hevc/hevc.h
> @@ -170,4 +170,9 @@ enum HEVCScalabilityMask {
> HEVC_SCALABILITY_MASK_MAX = 0xFFFF,
> };
>
> +enum HEVCAuxId {
> + HEVC_AUX_ALPHA = 1,
> + HEVC_AUX_DEPTH = 2,
> +};
> +
> #endif /* AVCODEC_HEVC_HEVC_H */
> diff --git a/libavcodec/hevc/ps.c b/libavcodec/hevc/ps.c
> index 861a6bb0a2..4f18cd72e4 100644
> --- a/libavcodec/hevc/ps.c
> +++ b/libavcodec/hevc/ps.c
> @@ -460,14 +460,17 @@ static int decode_vps_ext(GetBitContext *gb, AVCodecContext *avctx, HEVCVPS *vps
> uint64_t layer1_id_included)
> {
> PTL ptl_dummy;
> - uint8_t max_sub_layers[HEVC_MAX_LAYERS];
> + uint8_t max_sub_layers[HEVC_MAX_LAYERS] = {1, 1};
> + uint8_t dimension_id_len[16] = {0};
> + uint8_t dimension_id[16] = {0};
> + unsigned n;
>
> - int splitting_flag, dimension_id_len, view_id_len, num_add_olss, num_scalability_types,
> + int splitting_flag, view_id_len, num_add_olss, num_scalability_types,
> default_output_layer_idc, direct_dep_type_len, direct_dep_type,
> sub_layers_max_present, sub_layer_flag_info_present_flag, nb_ptl;
> unsigned non_vui_extension_length;
>
> - if (vps->vps_max_layers == 1 || vps->vps_num_layer_sets == 1) {
> + if (vps->vps_max_layers == 1) {
> av_log(avctx, AV_LOG_VERBOSE, "Ignoring VPS extensions with a single layer\n");
> return 0;
> }
> @@ -520,7 +523,8 @@ static int decode_vps_ext(GetBitContext *gb, AVCodecContext *avctx, HEVCVPS *vps
> */
> vps->nb_layers = 2;
>
> - if (parse_ptl(gb, avctx, 0, &ptl_dummy, vps->vps_max_sub_layers) < 0)
> + if (vps->vps_base_layer_internal_flag &&
What's the point checking for this flag if this code will not be reached
if it's false?
> + parse_ptl(gb, avctx, 0, &ptl_dummy, vps->vps_max_sub_layers) < 0)
> return AVERROR_INVALIDDATA;
>
> splitting_flag = get_bits1(gb);
> @@ -529,20 +533,25 @@ static int decode_vps_ext(GetBitContext *gb, AVCodecContext *avctx, HEVCVPS *vps
> if (!num_scalability_types) {
> av_log(avctx, AV_LOG_ERROR, "Missing scalability mask\n");
> return AVERROR_INVALIDDATA;
> - } else if (num_scalability_types > 1) {
> - av_log(avctx, AV_LOG_ERROR, "Scalability number %d not supported\n",
> - num_scalability_types);
> - return AVERROR_PATCHWELCOME;
> }
>
> - if (!(vps->scalability_mask_flag & HEVC_SCALABILITY_MULTIVIEW)) {
> + if (!(vps->scalability_mask_flag &
> + (HEVC_SCALABILITY_MULTIVIEW | HEVC_SCALABILITY_AUXILIARY))) {
> av_log(avctx, AV_LOG_ERROR, "Scalability type %d not supported\n",
> 15 - ff_ctz(vps->scalability_mask_flag));
> return AVERROR_PATCHWELCOME;
> }
> + // x265 specify MULTIVIEW when the stream really is alpha video only.
> + if (num_scalability_types > 1)
> + av_log(avctx, AV_LOG_WARNING, "Multiple scalability types presented\n");
>
> - if (!splitting_flag)
> - dimension_id_len = get_bits(gb, 3) + 1;
> + n = 0;
> + for (int i = 0; i < num_scalability_types - splitting_flag; i++) {
> + dimension_id_len[i] = get_bits(gb, 3) + 1;
> + n += dimension_id_len[i];
> + }
> + if (splitting_flag)
> + dimension_id_len[num_scalability_types - 1] = 5 - n;
>
> if (get_bits1(gb)) { /* vps_nuh_layer_id_present_flag */
> int layer_id_in_nuh = get_bits(gb, 6);
> @@ -559,28 +568,57 @@ static int decode_vps_ext(GetBitContext *gb, AVCodecContext *avctx, HEVCVPS *vps
> }
>
> if (!splitting_flag) {
> - int view_idx = get_bits(gb, dimension_id_len);
> - if (view_idx != 1) {
> - av_log(avctx, AV_LOG_ERROR, "Unexpected ViewOrderIdx: %d\n", view_idx);
> + int index = 0;
> +
> + for (int i = 0; i < num_scalability_types; i++)
> + dimension_id[i] = get_bits(gb, dimension_id_len[i]);
> +
> + if (vps->scalability_mask_flag & HEVC_SCALABILITY_MULTIVIEW)
> + index++;
> +
> + /* AuxId 1 is alpha, 2 is depth. Only support alpha */
> + if (vps->scalability_mask_flag & HEVC_SCALABILITY_AUXILIARY &&
> + dimension_id[index] != HEVC_AUX_ALPHA) {
> + av_log(avctx, AV_LOG_WARNING,
> + "Unsupported dimension_id %d for HEVC_SCALABILITY_AUXILIARY\n",
> + dimension_id[index]);
> return AVERROR_PATCHWELCOME;
> }
> }
>
> view_id_len = get_bits(gb, 4);
> - if (view_id_len)
> - for (int i = 0; i < 2 /* NumViews */; i++)
> + if (view_id_len) {
> + n = (vps->scalability_mask_flag & HEVC_SCALABILITY_MULTIVIEW) ? 2 : 1;
> + for (int i = 0; i < n; i++)
> vps->view_id[i] = get_bits(gb, view_id_len);
> + }
>
> - if (!get_bits1(gb) /* direct_dependency_flag */) {
> - av_log(avctx, AV_LOG_WARNING, "Independent output layers not supported\n");
> - return AVERROR_PATCHWELCOME;
> + /* direct_dependency_flag */
> + vps->num_direct_ref_layers[1] = get_bits1(gb);
> + if (!vps->num_direct_ref_layers[1]) {
> + vps->num_add_layer_sets = get_ue_golomb(gb);
> + if (vps->num_add_layer_sets > 1) {
> + av_log(avctx, AV_LOG_WARNING,
> + "Unsupported num_add_layer_sets: %d\n", vps->num_add_layer_sets);
> + return AVERROR_PATCHWELCOME;
> + }
> +
> + if (vps->num_add_layer_sets) {
> + /* highest_layer_idx_plus1 */
> + if (!get_bits1(gb))
> + return AVERROR_PATCHWELCOME;
> + }
> }
> - vps->num_direct_ref_layers[1] = 1;
> + vps->num_output_layer_sets = vps->vps_num_layer_sets + vps->num_add_layer_sets;
> + if (vps->num_output_layer_sets != 2)
> + return AVERROR_INVALIDDATA;
>
> sub_layers_max_present = get_bits1(gb); // vps_sub_layers_max_minus1_present_flag
> - for (int i = 0; i < vps->vps_max_layers; i++)
> - max_sub_layers[i] = sub_layers_max_present ? get_bits(gb, 3) + 1 :
> - vps->vps_max_sub_layers;
> + if (sub_layers_max_present) {
> + for (int i = 0; i < vps->vps_max_layers; i++)
> + max_sub_layers[i] = sub_layers_max_present ? get_bits(gb, 3) + 1 :
> + vps->vps_max_sub_layers;
> + }
>
> if (get_bits1(gb) /* max_tid_ref_present_flag */)
> skip_bits(gb, 3); // max_tid_il_ref_pics_plus1
> @@ -613,18 +651,24 @@ static int decode_vps_ext(GetBitContext *gb, AVCodecContext *avctx, HEVCVPS *vps
> }
>
> /* Consequence of established layer dependencies */
> - if (layer1_id_included != ((1 << vps->layer_id_in_nuh[0]) |
> + if (layer1_id_included &&
> + layer1_id_included != ((1 << vps->layer_id_in_nuh[0]) |
> (1 << vps->layer_id_in_nuh[1]))) {
> - av_log(avctx, AV_LOG_ERROR, "Dependent layer not included in layer ID?\n");
> - return AVERROR_PATCHWELCOME;
> + av_log(avctx, AV_LOG_ERROR,
> + "Dependent layer not included in layer ID?\n");
> + return AVERROR_PATCHWELCOME;
> }
> + if (!layer1_id_included)
> + vps->ols[1] = 2;
> + else
> + vps->ols[1] = 3;
>
> - vps->num_output_layer_sets = 2;
> - vps->ols[1] = 3;
> + if (vps->vps_num_layer_sets == 1 || default_output_layer_idc == 2)
> + skip_bits1(gb);
>
> for (int j = 0; j < av_popcount64(vps->ols[1]); j++) {
> int ptl_idx = get_bits(gb, av_ceil_log2(nb_ptl));
> - if (ptl_idx < 1 || ptl_idx >= nb_ptl) {
> + if (ptl_idx >= nb_ptl) {
> av_log(avctx, AV_LOG_ERROR, "Invalid PTL index: %d\n", ptl_idx);
> return AVERROR_INVALIDDATA;
> }
> @@ -667,6 +711,8 @@ static int decode_vps_ext(GetBitContext *gb, AVCodecContext *avctx, HEVCVPS *vps
>
> vps->max_one_active_ref_layer = get_bits1(gb);
> vps->poc_lsb_aligned = get_bits1(gb);
> + if (!vps->num_direct_ref_layers[1])
> + vps->poc_lsb_not_present = get_bits1(gb) << 1;
Huh, so this was being checked in hls_slice_header() but never set
before now?
>
> sub_layer_flag_info_present_flag = get_bits1(gb);
> for (int j = 0; j < FFMAX(max_sub_layers[0], max_sub_layers[1]); j++) {
> @@ -688,12 +734,14 @@ static int decode_vps_ext(GetBitContext *gb, AVCodecContext *avctx, HEVCVPS *vps
> return AVERROR_INVALIDDATA;
> }
>
> - skip_bits1(gb); /* direct_depenency_all_layers_flag */
> - direct_dep_type = get_bits_long(gb, direct_dep_type_len);
> - if (direct_dep_type > HEVC_DEP_TYPE_BOTH) {
> - av_log(avctx, AV_LOG_WARNING, "Unsupported direct_dep_type: %d\n",
> - direct_dep_type);
> - return AVERROR_PATCHWELCOME;
> + /* direct_dependency_all_layers_flag */
> + if (get_bits1(gb) || vps->num_direct_ref_layers[1]) {
> + direct_dep_type = get_bits_long(gb, direct_dep_type_len);
> + if (direct_dep_type > HEVC_DEP_TYPE_BOTH) {
> + av_log(avctx, AV_LOG_WARNING, "Unsupported direct_dep_type: %d\n",
> + direct_dep_type);
> + return AVERROR_PATCHWELCOME;
> + }
> }
>
> non_vui_extension_length = get_ue_golomb(gb);
> @@ -741,8 +789,12 @@ int ff_hevc_decode_nal_vps(GetBitContext *gb, AVCodecContext *avctx,
> }
> vps->vps_id = vps_id;
>
> - if (get_bits(gb, 2) != 3) { // vps_reserved_three_2bits
> - av_log(avctx, AV_LOG_ERROR, "vps_reserved_three_2bits is not three\n");
> + vps->vps_base_layer_internal_flag = get_bits1(gb);
> + vps->vps_base_layer_available_flag = get_bits1(gb);
> + if (!vps->vps_base_layer_internal_flag || !vps->vps_base_layer_available_flag) {
> + av_log(avctx, AV_LOG_ERROR,
> + "vps_base_layer_internal_flag or vps_base_layer_available_flag not set\n");
> + ret = AVERROR_PATCHWELCOME;
> goto err;
> }
>
> diff --git a/libavcodec/hevc/ps.h b/libavcodec/hevc/ps.h
> index d3465e3d27..f706b889e6 100644
> --- a/libavcodec/hevc/ps.h
> +++ b/libavcodec/hevc/ps.h
> @@ -171,6 +171,9 @@ typedef struct RepFormat {
> typedef struct HEVCVPS {
> unsigned int vps_id;
>
> + uint8_t vps_base_layer_internal_flag;
> + uint8_t vps_base_layer_available_flag;
These two can be variables local to ff_hevc_decode_nal_vps() instead of
being in this struct.
> +
> uint8_t vps_temporal_id_nesting_flag;
> int vps_max_layers;
> int vps_max_sub_layers; ///< vps_max_temporal_layers_minus1 + 1
> @@ -237,6 +240,7 @@ typedef struct HEVCVPS {
>
> // NumDirectRefLayers[layer_idx]
> uint8_t num_direct_ref_layers[HEVC_VPS_MAX_LAYERS];
> + uint8_t num_add_layer_sets;
>
> RepFormat rep_format;
>
[-- 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] 3+ messages in thread
* Re: [FFmpeg-devel] [PATCH v4 2/3] avcodec/hevc/ps: Add basic HEVC_SCALABILITY_AUXILIARY support
2025-02-06 13:25 ` James Almer
@ 2025-02-06 14:28 ` Zhao Zhili
0 siblings, 0 replies; 3+ messages in thread
From: Zhao Zhili @ 2025-02-06 14:28 UTC (permalink / raw)
To: FFmpeg development discussions and patches
> On Feb 6, 2025, at 21:25, James Almer <jamrial@gmail.com> wrote:
>
> On 2/6/2025 12:49 AM, Zhao Zhili wrote:
>> From: Zhao Zhili <zhilizhao@tencent.com>
>> Only implementing what's needed for HEVC with alpha.
>> Signed-off-by: Zhao Zhili <zhilizhao@tencent.com>
>> ---
>> libavcodec/hevc/hevc.h | 5 ++
>> libavcodec/hevc/ps.c | 126 +++++++++++++++++++++++++++++------------
>> libavcodec/hevc/ps.h | 4 ++
>> 3 files changed, 98 insertions(+), 37 deletions(-)
>> diff --git a/libavcodec/hevc/hevc.h b/libavcodec/hevc/hevc.h
>> index b2229fda40..710786a89d 100644
>> --- a/libavcodec/hevc/hevc.h
>> +++ b/libavcodec/hevc/hevc.h
>> @@ -170,4 +170,9 @@ enum HEVCScalabilityMask {
>> HEVC_SCALABILITY_MASK_MAX = 0xFFFF,
>> };
>> +enum HEVCAuxId {
>> + HEVC_AUX_ALPHA = 1,
>> + HEVC_AUX_DEPTH = 2,
>> +};
>> +
>> #endif /* AVCODEC_HEVC_HEVC_H */
>> diff --git a/libavcodec/hevc/ps.c b/libavcodec/hevc/ps.c
>> index 861a6bb0a2..4f18cd72e4 100644
>> --- a/libavcodec/hevc/ps.c
>> +++ b/libavcodec/hevc/ps.c
>> @@ -460,14 +460,17 @@ static int decode_vps_ext(GetBitContext *gb, AVCodecContext *avctx, HEVCVPS *vps
>> uint64_t layer1_id_included)
>> {
>> PTL ptl_dummy;
>> - uint8_t max_sub_layers[HEVC_MAX_LAYERS];
>> + uint8_t max_sub_layers[HEVC_MAX_LAYERS] = {1, 1};
>> + uint8_t dimension_id_len[16] = {0};
>> + uint8_t dimension_id[16] = {0};
>> + unsigned n;
>> - int splitting_flag, dimension_id_len, view_id_len, num_add_olss, num_scalability_types,
>> + int splitting_flag, view_id_len, num_add_olss, num_scalability_types,
>> default_output_layer_idc, direct_dep_type_len, direct_dep_type,
>> sub_layers_max_present, sub_layer_flag_info_present_flag, nb_ptl;
>> unsigned non_vui_extension_length;
>> - if (vps->vps_max_layers == 1 || vps->vps_num_layer_sets == 1) {
>> + if (vps->vps_max_layers == 1) {
>> av_log(avctx, AV_LOG_VERBOSE, "Ignoring VPS extensions with a single layer\n");
>> return 0;
>> }
>> @@ -520,7 +523,8 @@ static int decode_vps_ext(GetBitContext *gb, AVCodecContext *avctx, HEVCVPS *vps
>> */
>> vps->nb_layers = 2;
>> - if (parse_ptl(gb, avctx, 0, &ptl_dummy, vps->vps_max_sub_layers) < 0)
>> + if (vps->vps_base_layer_internal_flag &&
>
> What's the point checking for this flag if this code will not be reached if it's false?
Here is only meant to follow the spec with little effort. When someone add support for
vps_base_layer_internal_flag = 0, it’s clear what does the flag can affect.
>
>> + parse_ptl(gb, avctx, 0, &ptl_dummy, vps->vps_max_sub_layers) < 0)
>> return AVERROR_INVALIDDATA;
>> splitting_flag = get_bits1(gb);
>> @@ -529,20 +533,25 @@ static int decode_vps_ext(GetBitContext *gb, AVCodecContext *avctx, HEVCVPS *vps
>> if (!num_scalability_types) {
>> av_log(avctx, AV_LOG_ERROR, "Missing scalability mask\n");
>> return AVERROR_INVALIDDATA;
>> - } else if (num_scalability_types > 1) {
>> - av_log(avctx, AV_LOG_ERROR, "Scalability number %d not supported\n",
>> - num_scalability_types);
>> - return AVERROR_PATCHWELCOME;
>> }
>> - if (!(vps->scalability_mask_flag & HEVC_SCALABILITY_MULTIVIEW)) {
>> + if (!(vps->scalability_mask_flag &
>> + (HEVC_SCALABILITY_MULTIVIEW | HEVC_SCALABILITY_AUXILIARY))) {
>> av_log(avctx, AV_LOG_ERROR, "Scalability type %d not supported\n",
>> 15 - ff_ctz(vps->scalability_mask_flag));
>> return AVERROR_PATCHWELCOME;
>> }
>> + // x265 specify MULTIVIEW when the stream really is alpha video only.
>> + if (num_scalability_types > 1)
>> + av_log(avctx, AV_LOG_WARNING, "Multiple scalability types presented\n");
>> - if (!splitting_flag)
>> - dimension_id_len = get_bits(gb, 3) + 1;
>> + n = 0;
>> + for (int i = 0; i < num_scalability_types - splitting_flag; i++) {
>> + dimension_id_len[i] = get_bits(gb, 3) + 1;
>> + n += dimension_id_len[i];
>> + }
>> + if (splitting_flag)
>> + dimension_id_len[num_scalability_types - 1] = 5 - n;
>> if (get_bits1(gb)) { /* vps_nuh_layer_id_present_flag */
>> int layer_id_in_nuh = get_bits(gb, 6);
>> @@ -559,28 +568,57 @@ static int decode_vps_ext(GetBitContext *gb, AVCodecContext *avctx, HEVCVPS *vps
>> }
>> if (!splitting_flag) {
>> - int view_idx = get_bits(gb, dimension_id_len);
>> - if (view_idx != 1) {
>> - av_log(avctx, AV_LOG_ERROR, "Unexpected ViewOrderIdx: %d\n", view_idx);
>> + int index = 0;
>> +
>> + for (int i = 0; i < num_scalability_types; i++)
>> + dimension_id[i] = get_bits(gb, dimension_id_len[i]);
>> +
>> + if (vps->scalability_mask_flag & HEVC_SCALABILITY_MULTIVIEW)
>> + index++;
>> +
>> + /* AuxId 1 is alpha, 2 is depth. Only support alpha */
>> + if (vps->scalability_mask_flag & HEVC_SCALABILITY_AUXILIARY &&
>> + dimension_id[index] != HEVC_AUX_ALPHA) {
>> + av_log(avctx, AV_LOG_WARNING,
>> + "Unsupported dimension_id %d for HEVC_SCALABILITY_AUXILIARY\n",
>> + dimension_id[index]);
>> return AVERROR_PATCHWELCOME;
>> }
>> }
>> view_id_len = get_bits(gb, 4);
>> - if (view_id_len)
>> - for (int i = 0; i < 2 /* NumViews */; i++)
>> + if (view_id_len) {
>> + n = (vps->scalability_mask_flag & HEVC_SCALABILITY_MULTIVIEW) ? 2 : 1;
>> + for (int i = 0; i < n; i++)
>> vps->view_id[i] = get_bits(gb, view_id_len);
>> + }
>> - if (!get_bits1(gb) /* direct_dependency_flag */) {
>> - av_log(avctx, AV_LOG_WARNING, "Independent output layers not supported\n");
>> - return AVERROR_PATCHWELCOME;
>> + /* direct_dependency_flag */
>> + vps->num_direct_ref_layers[1] = get_bits1(gb);
>> + if (!vps->num_direct_ref_layers[1]) {
>> + vps->num_add_layer_sets = get_ue_golomb(gb);
>> + if (vps->num_add_layer_sets > 1) {
>> + av_log(avctx, AV_LOG_WARNING,
>> + "Unsupported num_add_layer_sets: %d\n", vps->num_add_layer_sets);
>> + return AVERROR_PATCHWELCOME;
>> + }
>> +
>> + if (vps->num_add_layer_sets) {
>> + /* highest_layer_idx_plus1 */
>> + if (!get_bits1(gb))
>> + return AVERROR_PATCHWELCOME;
>> + }
>> }
>> - vps->num_direct_ref_layers[1] = 1;
>> + vps->num_output_layer_sets = vps->vps_num_layer_sets + vps->num_add_layer_sets;
>> + if (vps->num_output_layer_sets != 2)
>> + return AVERROR_INVALIDDATA;
>> sub_layers_max_present = get_bits1(gb); // vps_sub_layers_max_minus1_present_flag
>> - for (int i = 0; i < vps->vps_max_layers; i++)
>> - max_sub_layers[i] = sub_layers_max_present ? get_bits(gb, 3) + 1 :
>> - vps->vps_max_sub_layers;
>> + if (sub_layers_max_present) {
>> + for (int i = 0; i < vps->vps_max_layers; i++)
>> + max_sub_layers[i] = sub_layers_max_present ? get_bits(gb, 3) + 1 :
>> + vps->vps_max_sub_layers;
>> + }
>> if (get_bits1(gb) /* max_tid_ref_present_flag */)
>> skip_bits(gb, 3); // max_tid_il_ref_pics_plus1
>> @@ -613,18 +651,24 @@ static int decode_vps_ext(GetBitContext *gb, AVCodecContext *avctx, HEVCVPS *vps
>> }
>> /* Consequence of established layer dependencies */
>> - if (layer1_id_included != ((1 << vps->layer_id_in_nuh[0]) |
>> + if (layer1_id_included &&
>> + layer1_id_included != ((1 << vps->layer_id_in_nuh[0]) |
>> (1 << vps->layer_id_in_nuh[1]))) {
>> - av_log(avctx, AV_LOG_ERROR, "Dependent layer not included in layer ID?\n");
>> - return AVERROR_PATCHWELCOME;
>> + av_log(avctx, AV_LOG_ERROR,
>> + "Dependent layer not included in layer ID?\n");
>> + return AVERROR_PATCHWELCOME;
>> }
>> + if (!layer1_id_included)
>> + vps->ols[1] = 2;
>> + else
>> + vps->ols[1] = 3;
>> - vps->num_output_layer_sets = 2;
>> - vps->ols[1] = 3;
>> + if (vps->vps_num_layer_sets == 1 || default_output_layer_idc == 2)
>> + skip_bits1(gb);
>> for (int j = 0; j < av_popcount64(vps->ols[1]); j++) {
>> int ptl_idx = get_bits(gb, av_ceil_log2(nb_ptl));
>> - if (ptl_idx < 1 || ptl_idx >= nb_ptl) {
>> + if (ptl_idx >= nb_ptl) {
>> av_log(avctx, AV_LOG_ERROR, "Invalid PTL index: %d\n", ptl_idx);
>> return AVERROR_INVALIDDATA;
>> }
>> @@ -667,6 +711,8 @@ static int decode_vps_ext(GetBitContext *gb, AVCodecContext *avctx, HEVCVPS *vps
>> vps->max_one_active_ref_layer = get_bits1(gb);
>> vps->poc_lsb_aligned = get_bits1(gb);
>> + if (!vps->num_direct_ref_layers[1])
>> + vps->poc_lsb_not_present = get_bits1(gb) << 1;
>
> Huh, so this was being checked in hls_slice_header() but never set before now?
It’s inferred to be 0 and initialized by memset to 0.
>
>> sub_layer_flag_info_present_flag = get_bits1(gb);
>> for (int j = 0; j < FFMAX(max_sub_layers[0], max_sub_layers[1]); j++) {
>> @@ -688,12 +734,14 @@ static int decode_vps_ext(GetBitContext *gb, AVCodecContext *avctx, HEVCVPS *vps
>> return AVERROR_INVALIDDATA;
>> }
>> - skip_bits1(gb); /* direct_depenency_all_layers_flag */
>> - direct_dep_type = get_bits_long(gb, direct_dep_type_len);
>> - if (direct_dep_type > HEVC_DEP_TYPE_BOTH) {
>> - av_log(avctx, AV_LOG_WARNING, "Unsupported direct_dep_type: %d\n",
>> - direct_dep_type);
>> - return AVERROR_PATCHWELCOME;
>> + /* direct_dependency_all_layers_flag */
>> + if (get_bits1(gb) || vps->num_direct_ref_layers[1]) {
>> + direct_dep_type = get_bits_long(gb, direct_dep_type_len);
>> + if (direct_dep_type > HEVC_DEP_TYPE_BOTH) {
>> + av_log(avctx, AV_LOG_WARNING, "Unsupported direct_dep_type: %d\n",
>> + direct_dep_type);
>> + return AVERROR_PATCHWELCOME;
>> + }
>> }
>> non_vui_extension_length = get_ue_golomb(gb);
>> @@ -741,8 +789,12 @@ int ff_hevc_decode_nal_vps(GetBitContext *gb, AVCodecContext *avctx,
>> }
>> vps->vps_id = vps_id;
>> - if (get_bits(gb, 2) != 3) { // vps_reserved_three_2bits
>> - av_log(avctx, AV_LOG_ERROR, "vps_reserved_three_2bits is not three\n");
>> + vps->vps_base_layer_internal_flag = get_bits1(gb);
>> + vps->vps_base_layer_available_flag = get_bits1(gb);
>> + if (!vps->vps_base_layer_internal_flag || !vps->vps_base_layer_available_flag) {
>> + av_log(avctx, AV_LOG_ERROR,
>> + "vps_base_layer_internal_flag or vps_base_layer_available_flag not set\n");
>> + ret = AVERROR_PATCHWELCOME;
>> goto err;
>> }
>> diff --git a/libavcodec/hevc/ps.h b/libavcodec/hevc/ps.h
>> index d3465e3d27..f706b889e6 100644
>> --- a/libavcodec/hevc/ps.h
>> +++ b/libavcodec/hevc/ps.h
>> @@ -171,6 +171,9 @@ typedef struct RepFormat {
>> typedef struct HEVCVPS {
>> unsigned int vps_id;
>> + uint8_t vps_base_layer_internal_flag;
>> + uint8_t vps_base_layer_available_flag;
>
> These two can be variables local to ff_hevc_decode_nal_vps() instead of being in this struct.
It’s used by decode_vps_ext, and meant as a start point to add support for these flags been zero
in the future.
>
>> +
>> uint8_t vps_temporal_id_nesting_flag;
>> int vps_max_layers;
>> int vps_max_sub_layers; ///< vps_max_temporal_layers_minus1 + 1
>> @@ -237,6 +240,7 @@ typedef struct HEVCVPS {
>> // NumDirectRefLayers[layer_idx]
>> uint8_t num_direct_ref_layers[HEVC_VPS_MAX_LAYERS];
>> + uint8_t num_add_layer_sets;
>> RepFormat rep_format;
>>
>
> _______________________________________________
> 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] 3+ messages in thread
end of thread, other threads:[~2025-02-06 14:28 UTC | newest]
Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2025-02-06 3:49 [FFmpeg-devel] [PATCH v4 2/3] avcodec/hevc/ps: Add basic HEVC_SCALABILITY_AUXILIARY support Zhao Zhili
2025-02-06 13:25 ` James Almer
2025-02-06 14:28 ` Zhao Zhili
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