From d82e1adc2019135a2fc45372e0ed0b5ef107cdd0 Mon Sep 17 00:00:00 2001 From: Anton Khirnov Date: Thu, 9 Jul 2015 18:33:52 +0200 Subject: [PATCH] hevc: move splitting the packet into NALUs into a separate function This function is independent of the decoding context, so we'll be able to use it in the parser. --- libavcodec/hevc.c | 122 ++++++---------------------------------- libavcodec/hevc.h | 17 +++++- libavcodec/hevc_parse.c | 99 ++++++++++++++++++++++++++++++++ libavcodec/hevc_refs.c | 2 +- 4 files changed, 131 insertions(+), 109 deletions(-) diff --git a/libavcodec/hevc.c b/libavcodec/hevc.c index c46d44c51a..c9d43448e3 100644 --- a/libavcodec/hevc.c +++ b/libavcodec/hevc.c @@ -2341,32 +2341,6 @@ static int hls_slice_data(HEVCContext *s) return ctb_addr_ts; } -/** - * @return AVERROR_INVALIDDATA if the packet is not a valid NAL unit, - * 0 if the unit should be skipped, 1 otherwise - */ -static int hls_nal_unit(HEVCNAL *nal, AVCodecContext *avctx) -{ - GetBitContext *gb = &nal->gb; - int nuh_layer_id; - - if (get_bits1(gb) != 0) - return AVERROR_INVALIDDATA; - - nal->type = get_bits(gb, 6); - - nuh_layer_id = get_bits(gb, 6); - nal->temporal_id = get_bits(gb, 3) - 1; - if (nal->temporal_id < 0) - return AVERROR_INVALIDDATA; - - av_log(avctx, AV_LOG_DEBUG, - "nal_unit_type: %d, nuh_layer_id: %dtemporal_id: %d\n", - nal->type, nuh_layer_id, nal->temporal_id); - - return nuh_layer_id == 0; -} - static void restore_tqb_pixels(HEVCContext *s) { int min_pu_size = 1 << s->ps.sps->log2_min_pu_size; @@ -2638,92 +2612,30 @@ fail: static int decode_nal_units(HEVCContext *s, const uint8_t *buf, int length) { - int i, consumed, ret = 0; + int i, ret = 0; s->ref = NULL; s->eos = 0; /* split the input packet into NAL units, so we know the upper bound on the * number of slices in the frame */ - s->nb_nals = 0; - while (length >= 4) { - HEVCNAL *nal; - int extract_length = 0; + ret = ff_hevc_split_packet(&s->pkt, buf, length, s->avctx, s->is_nalff, + s->nal_length_size); + if (ret < 0) { + av_log(s->avctx, AV_LOG_ERROR, + "Error splitting the input into NAL units.\n"); + return ret; + } - if (s->is_nalff) { - int i; - for (i = 0; i < s->nal_length_size; i++) - extract_length = (extract_length << 8) | buf[i]; - buf += s->nal_length_size; - length -= s->nal_length_size; - - if (extract_length > length) { - av_log(s->avctx, AV_LOG_ERROR, "Invalid NAL unit size.\n"); - ret = AVERROR_INVALIDDATA; - goto fail; - } - } else { - if (buf[2] == 0) { - length--; - buf++; - continue; - } - if (buf[0] != 0 || buf[1] != 0 || buf[2] != 1) { - ret = AVERROR_INVALIDDATA; - goto fail; - } - - buf += 3; - length -= 3; - extract_length = length; - } - - if (s->nals_allocated < s->nb_nals + 1) { - int new_size = s->nals_allocated + 1; - HEVCNAL *tmp = av_realloc_array(s->nals, new_size, sizeof(*tmp)); - if (!tmp) { - ret = AVERROR(ENOMEM); - goto fail; - } - s->nals = tmp; - memset(s->nals + s->nals_allocated, 0, - (new_size - s->nals_allocated) * sizeof(*tmp)); - s->nals_allocated = new_size; - } - nal = &s->nals[s->nb_nals++]; - - consumed = ff_hevc_extract_rbsp(buf, extract_length, nal); - if (consumed < 0) { - ret = consumed; - goto fail; - } - - ret = init_get_bits8(&nal->gb, nal->data, nal->size); - if (ret < 0) - goto fail; - - ret = hls_nal_unit(nal, s->avctx); - if (ret <= 0) { - if (ret < 0) { - av_log(s->avctx, AV_LOG_ERROR, "Invalid NAL unit %d, skipping.\n", - nal->type); - } - s->nb_nals--; - goto skip_nal; - } - - if (nal->type == NAL_EOB_NUT || - nal->type == NAL_EOS_NUT) + for (i = 0; i < s->pkt.nb_nals; i++) { + if (s->pkt.nals[i].type == NAL_EOB_NUT || + s->pkt.nals[i].type == NAL_EOS_NUT) s->eos = 1; - -skip_nal: - buf += consumed; - length -= consumed; } /* parse the NAL units */ - for (i = 0; i < s->nb_nals; i++) { - ret = decode_nal_unit(s, &s->nals[i]); + for (i = 0; i < s->pkt.nb_nals; i++) { + ret = decode_nal_unit(s, &s->pkt.nals[i]); if (ret < 0) { av_log(s->avctx, AV_LOG_WARNING, "Error parsing NAL unit #%d.\n", i); @@ -2924,10 +2836,10 @@ static av_cold int hevc_decode_free(AVCodecContext *avctx) for (i = 0; i < FF_ARRAY_ELEMS(s->ps.pps_list); i++) av_buffer_unref(&s->ps.pps_list[i]); - for (i = 0; i < s->nals_allocated; i++) - av_freep(&s->nals[i].rbsp_buffer); - av_freep(&s->nals); - s->nals_allocated = 0; + for (i = 0; i < s->pkt.nals_allocated; i++) + av_freep(&s->pkt.nals[i].rbsp_buffer); + av_freep(&s->pkt.nals); + s->pkt.nals_allocated = 0; return 0; } diff --git a/libavcodec/hevc.h b/libavcodec/hevc.h index 41b88dbfa8..c6e05bc0bb 100644 --- a/libavcodec/hevc.h +++ b/libavcodec/hevc.h @@ -718,6 +718,13 @@ typedef struct HEVCNAL { int temporal_id; } HEVCNAL; +/* an input packet split into unescaped NAL units */ +typedef struct HEVCPacket { + HEVCNAL *nals; + int nb_nals; + int nals_allocated; +} HEVCPacket; + struct HEVCContext; typedef struct HEVCPredContext { @@ -843,9 +850,7 @@ typedef struct HEVCContext { uint16_t seq_decode; uint16_t seq_output; - HEVCNAL *nals; - int nb_nals; - int nals_allocated; + HEVCPacket pkt; // type of the first VCL NAL of the current frame enum NALUnitType first_nal_type; @@ -1022,6 +1027,12 @@ void ff_hevc_pred_init(HEVCPredContext *hpc, int bit_depth); int ff_hevc_extract_rbsp(const uint8_t *src, int length, HEVCNAL *nal); +/** + * Split an input packet into NAL units. + */ +int ff_hevc_split_packet(HEVCPacket *pkt, const uint8_t *buf, int length, + AVCodecContext *avctx, int is_nalff, int nal_length_size); + int ff_hevc_encode_nal_vps(HEVCVPS *vps, unsigned int id, uint8_t *buf, int buf_size); diff --git a/libavcodec/hevc_parse.c b/libavcodec/hevc_parse.c index 32a440bf92..93c8175702 100644 --- a/libavcodec/hevc_parse.c +++ b/libavcodec/hevc_parse.c @@ -127,3 +127,102 @@ nsc: nal->raw_size = si; return si; } + +/** + * @return AVERROR_INVALIDDATA if the packet is not a valid NAL unit, + * 0 if the unit should be skipped, 1 otherwise + */ +static int hls_nal_unit(HEVCNAL *nal, AVCodecContext *avctx) +{ + GetBitContext *gb = &nal->gb; + int nuh_layer_id; + + if (get_bits1(gb) != 0) + return AVERROR_INVALIDDATA; + + nal->type = get_bits(gb, 6); + + nuh_layer_id = get_bits(gb, 6); + nal->temporal_id = get_bits(gb, 3) - 1; + if (nal->temporal_id < 0) + return AVERROR_INVALIDDATA; + + av_log(avctx, AV_LOG_DEBUG, + "nal_unit_type: %d, nuh_layer_id: %dtemporal_id: %d\n", + nal->type, nuh_layer_id, nal->temporal_id); + + return nuh_layer_id == 0; +} + + +int ff_hevc_split_packet(HEVCPacket *pkt, const uint8_t *buf, int length, + AVCodecContext *avctx, int is_nalff, int nal_length_size) +{ + int consumed, ret = 0; + + pkt->nb_nals = 0; + while (length >= 4) { + HEVCNAL *nal; + int extract_length = 0; + + if (is_nalff) { + int i; + for (i = 0; i < nal_length_size; i++) + extract_length = (extract_length << 8) | buf[i]; + buf += nal_length_size; + length -= nal_length_size; + + if (extract_length > length) { + av_log(avctx, AV_LOG_ERROR, "Invalid NAL unit size.\n"); + return AVERROR_INVALIDDATA; + } + } else { + if (buf[2] == 0) { + length--; + buf++; + continue; + } + if (buf[0] != 0 || buf[1] != 0 || buf[2] != 1) + return AVERROR_INVALIDDATA; + + buf += 3; + length -= 3; + extract_length = length; + } + + if (pkt->nals_allocated < pkt->nb_nals + 1) { + int new_size = pkt->nals_allocated + 1; + HEVCNAL *tmp = av_realloc_array(pkt->nals, new_size, sizeof(*tmp)); + if (!tmp) + return AVERROR(ENOMEM); + + pkt->nals = tmp; + memset(pkt->nals + pkt->nals_allocated, 0, + (new_size - pkt->nals_allocated) * sizeof(*tmp)); + pkt->nals_allocated = new_size; + } + nal = &pkt->nals[pkt->nb_nals++]; + + consumed = ff_hevc_extract_rbsp(buf, extract_length, nal); + if (consumed < 0) + return consumed; + + ret = init_get_bits8(&nal->gb, nal->data, nal->size); + if (ret < 0) + return ret; + + ret = hls_nal_unit(nal, avctx); + if (ret <= 0) { + if (ret < 0) { + av_log(avctx, AV_LOG_ERROR, "Invalid NAL unit %d, skipping.\n", + nal->type); + } + pkt->nb_nals--; + } + + buf += consumed; + length -= consumed; + } + + return 0; +} diff --git a/libavcodec/hevc_refs.c b/libavcodec/hevc_refs.c index a4889a19c1..7901b9eafb 100644 --- a/libavcodec/hevc_refs.c +++ b/libavcodec/hevc_refs.c @@ -92,7 +92,7 @@ static HEVCFrame *alloc_frame(HEVCContext *s) if (ret < 0) return NULL; - frame->rpl_buf = av_buffer_allocz(s->nb_nals * sizeof(RefPicListTab)); + frame->rpl_buf = av_buffer_allocz(s->pkt.nb_nals * sizeof(RefPicListTab)); if (!frame->rpl_buf) goto fail;