> On Feb 6, 2025, at 21:25, James Almer <jamr...@gmail.com> wrote: > > On 2/6/2025 12:49 AM, Zhao Zhili wrote: >> From: Zhao Zhili <zhiliz...@tencent.com> >> Only implementing what's needed for HEVC with alpha. >> Signed-off-by: Zhao Zhili <zhiliz...@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-requ...@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-requ...@ffmpeg.org with subject "unsubscribe".