HEVC standard supports multi-layer streams (ITU-T H.265 02/2018 Annex F). Each NAL unit belongs to a particular layer defined by nuh_layer_id in the header. Currently, all NAL units that do not belong to a base layer are automatically removed in ff_h2645_packet_split(). Some data may therefore be lost when future filters/decoders are designed to support multi-layer streams. A better approach is to forward nuh_layer_id > 0 packets and let blocks down the chain decide how to process them. The condition to remove packets has been moved to hevcdec and cbs. Found-by: Andreas Rheinhardt <andreas.rheinhardt@gmail.com> Signed-off-by: Andriy Gelman <andriy.gelman@gmail.com> Signed-off-by: James Almer <jamrial@gmail.com>tags/n4.3
| @@ -565,6 +565,9 @@ static int cbs_h2645_fragment_add_nals(CodedBitstreamContext *ctx, | |||||
| AVBufferRef *ref; | AVBufferRef *ref; | ||||
| size_t size = nal->size; | size_t size = nal->size; | ||||
| if (nal->nuh_layer_id > 0) | |||||
| continue; | |||||
| // Remove trailing zeroes. | // Remove trailing zeroes. | ||||
| while (size > 0 && nal->data[size - 1] == 0) | while (size > 0 && nal->data[size - 1] == 0) | ||||
| --size; | --size; | ||||
| @@ -292,23 +292,22 @@ static int get_bit_length(H2645NAL *nal, int skip_trailing_zeros) | |||||
| static int hevc_parse_nal_header(H2645NAL *nal, void *logctx) | static int hevc_parse_nal_header(H2645NAL *nal, void *logctx) | ||||
| { | { | ||||
| GetBitContext *gb = &nal->gb; | GetBitContext *gb = &nal->gb; | ||||
| int nuh_layer_id; | |||||
| if (get_bits1(gb) != 0) | if (get_bits1(gb) != 0) | ||||
| return AVERROR_INVALIDDATA; | return AVERROR_INVALIDDATA; | ||||
| nal->type = get_bits(gb, 6); | nal->type = get_bits(gb, 6); | ||||
| nuh_layer_id = get_bits(gb, 6); | |||||
| nal->nuh_layer_id = get_bits(gb, 6); | |||||
| nal->temporal_id = get_bits(gb, 3) - 1; | nal->temporal_id = get_bits(gb, 3) - 1; | ||||
| if (nal->temporal_id < 0) | if (nal->temporal_id < 0) | ||||
| return AVERROR_INVALIDDATA; | return AVERROR_INVALIDDATA; | ||||
| av_log(logctx, AV_LOG_DEBUG, | av_log(logctx, AV_LOG_DEBUG, | ||||
| "nal_unit_type: %d(%s), nuh_layer_id: %d, temporal_id: %d\n", | "nal_unit_type: %d(%s), nuh_layer_id: %d, temporal_id: %d\n", | ||||
| nal->type, hevc_nal_unit_name(nal->type), nuh_layer_id, nal->temporal_id); | |||||
| nal->type, hevc_nal_unit_name(nal->type), nal->nuh_layer_id, nal->temporal_id); | |||||
| return nuh_layer_id == 0; | |||||
| return 1; | |||||
| } | } | ||||
| static int h264_parse_nal_header(H2645NAL *nal, void *logctx) | static int h264_parse_nal_header(H2645NAL *nal, void *logctx) | ||||
| @@ -56,6 +56,11 @@ typedef struct H2645NAL { | |||||
| */ | */ | ||||
| int temporal_id; | int temporal_id; | ||||
| /* | |||||
| * HEVC only, identifier of layer to which nal unit belongs | |||||
| */ | |||||
| int nuh_layer_id; | |||||
| int skipped_bytes; | int skipped_bytes; | ||||
| int skipped_bytes_pos_size; | int skipped_bytes_pos_size; | ||||
| int *skipped_bytes_pos; | int *skipped_bytes_pos; | ||||
| @@ -37,6 +37,8 @@ static int hevc_decode_nal_units(const uint8_t *buf, int buf_size, HEVCParamSets | |||||
| for (i = 0; i < pkt.nb_nals; i++) { | for (i = 0; i < pkt.nb_nals; i++) { | ||||
| H2645NAL *nal = &pkt.nals[i]; | H2645NAL *nal = &pkt.nals[i]; | ||||
| if (nal->nuh_layer_id > 0) | |||||
| continue; | |||||
| /* ignore everything except parameter sets and VCL NALUs */ | /* ignore everything except parameter sets and VCL NALUs */ | ||||
| switch (nal->type) { | switch (nal->type) { | ||||
| @@ -202,6 +202,9 @@ static int parse_nal_units(AVCodecParserContext *s, const uint8_t *buf, | |||||
| H2645NAL *nal = &ctx->pkt.nals[i]; | H2645NAL *nal = &ctx->pkt.nals[i]; | ||||
| GetBitContext *gb = &nal->gb; | GetBitContext *gb = &nal->gb; | ||||
| if (nal->nuh_layer_id > 0) | |||||
| continue; | |||||
| switch (nal->type) { | switch (nal->type) { | ||||
| case HEVC_NAL_VPS: | case HEVC_NAL_VPS: | ||||
| ff_hevc_decode_nal_vps(gb, avctx, ps); | ff_hevc_decode_nal_vps(gb, avctx, ps); | ||||
| @@ -3077,7 +3077,7 @@ static int decode_nal_units(HEVCContext *s, const uint8_t *buf, int length) | |||||
| if (s->avctx->skip_frame >= AVDISCARD_ALL || | if (s->avctx->skip_frame >= AVDISCARD_ALL || | ||||
| (s->avctx->skip_frame >= AVDISCARD_NONREF | (s->avctx->skip_frame >= AVDISCARD_NONREF | ||||
| && ff_hevc_nal_is_nonref(nal->type))) | |||||
| && ff_hevc_nal_is_nonref(nal->type)) || nal->nuh_layer_id > 0) | |||||
| continue; | continue; | ||||
| ret = decode_nal_unit(s, nal); | ret = decode_nal_unit(s, nal); | ||||