X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=libavcodec%2Fhevc_parse.c;h=cf04bc2ffff4960f266fea998ef84cb33b154d14;hb=e3842e87f2f03f8e2053cd4f5b7354e0274c2110;hp=d557cc7f04c5ae573e354729d3d1b62c53856eab;hpb=8f540b86125a25ee48ea6da69139356063726b8e;p=ffmpeg diff --git a/libavcodec/hevc_parse.c b/libavcodec/hevc_parse.c index d557cc7f04c..cf04bc2ffff 100644 --- a/libavcodec/hevc_parse.c +++ b/libavcodec/hevc_parse.c @@ -1,6 +1,4 @@ /* - * HEVC common code - * * This file is part of FFmpeg. * * FFmpeg is free software; you can redistribute it and/or @@ -18,280 +16,119 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -#include - -#include "config.h" - -#include "libavutil/intreadwrite.h" -#include "libavutil/mem.h" - +#include "bytestream.h" +#include "h2645_parse.h" #include "hevc.h" +#include "hevc_parse.h" -/* FIXME: This is adapted from ff_h264_decode_nal, avoiding duplication - * between these functions would be nice. */ -int ff_hevc_extract_rbsp(HEVCContext *s, const uint8_t *src, int length, - HEVCNAL *nal) +static int hevc_decode_nal_units(const uint8_t *buf, int buf_size, HEVCParamSets *ps, + int is_nalff, int nal_length_size, void *logctx) { - int i, si, di; - uint8_t *dst; - - if (s) - nal->skipped_bytes = 0; -#define STARTCODE_TEST \ - if (i + 2 < length && src[i + 1] == 0 && src[i + 2] <= 3) { \ - if (src[i + 2] != 3) { \ - /* startcode, so we must be past the end */ \ - length = i; \ - } \ - break; \ - } -#if HAVE_FAST_UNALIGNED -#define FIND_FIRST_ZERO \ - if (i > 0 && !src[i]) \ - i--; \ - while (src[i]) \ - i++ -#if HAVE_FAST_64BIT - for (i = 0; i + 1 < length; i += 9) { - if (!((~AV_RN64A(src + i) & - (AV_RN64A(src + i) - 0x0100010001000101ULL)) & - 0x8000800080008080ULL)) - continue; - FIND_FIRST_ZERO; - STARTCODE_TEST; - i -= 7; - } -#else - for (i = 0; i + 1 < length; i += 5) { - if (!((~AV_RN32A(src + i) & - (AV_RN32A(src + i) - 0x01000101U)) & - 0x80008080U)) - continue; - FIND_FIRST_ZERO; - STARTCODE_TEST; - i -= 3; - } -#endif /* HAVE_FAST_64BIT */ -#else - for (i = 0; i + 1 < length; i += 2) { - if (src[i]) - continue; - if (i > 0 && src[i - 1] == 0) - i--; - STARTCODE_TEST; - } -#endif /* HAVE_FAST_UNALIGNED */ + int i; + int ret = 0; + H2645Packet pkt = { 0 }; - if (i >= length - 1) { // no escaped 0 - nal->data = - nal->raw_data = src; - nal->size = - nal->raw_size = length; - return length; + ret = ff_h2645_packet_split(&pkt, buf, buf_size, logctx, is_nalff, nal_length_size, AV_CODEC_ID_HEVC, 1); + if (ret < 0) { + goto done; } - av_fast_malloc(&nal->rbsp_buffer, &nal->rbsp_buffer_size, - length + AV_INPUT_BUFFER_PADDING_SIZE); - if (!nal->rbsp_buffer) - return AVERROR(ENOMEM); - - dst = nal->rbsp_buffer; - - memcpy(dst, src, i); - si = di = i; - while (si + 2 < length) { - // remove escapes (very rare 1:2^22) - if (src[si + 2] > 3) { - dst[di++] = src[si++]; - dst[di++] = src[si++]; - } else if (src[si] == 0 && src[si + 1] == 0) { - if (src[si + 2] == 3) { // escape - dst[di++] = 0; - dst[di++] = 0; - si += 3; - - if (s && nal->skipped_bytes_pos) { - nal->skipped_bytes++; - if (nal->skipped_bytes_pos_size < nal->skipped_bytes) { - nal->skipped_bytes_pos_size *= 2; - av_assert0(nal->skipped_bytes_pos_size >= nal->skipped_bytes); - av_reallocp_array(&nal->skipped_bytes_pos, - nal->skipped_bytes_pos_size, - sizeof(*nal->skipped_bytes_pos)); - if (!nal->skipped_bytes_pos) { - nal->skipped_bytes_pos_size = 0; - return AVERROR(ENOMEM); - } - } - if (nal->skipped_bytes_pos) - nal->skipped_bytes_pos[nal->skipped_bytes-1] = di - 1; - } - continue; - } else // next start code - goto nsc; + for (i = 0; i < pkt.nb_nals; i++) { + H2645NAL *nal = &pkt.nals[i]; + + /* ignore everything except parameter sets and VCL NALUs */ + switch (nal->type) { + case NAL_VPS: ff_hevc_decode_nal_vps(&nal->gb, logctx, ps); break; + case NAL_SPS: ff_hevc_decode_nal_sps(&nal->gb, logctx, ps, 1); break; + case NAL_PPS: ff_hevc_decode_nal_pps(&nal->gb, logctx, ps); break; + case NAL_TRAIL_R: + case NAL_TRAIL_N: + case NAL_TSA_N: + case NAL_TSA_R: + case NAL_STSA_N: + case NAL_STSA_R: + case NAL_BLA_W_LP: + case NAL_BLA_W_RADL: + case NAL_BLA_N_LP: + case NAL_IDR_W_RADL: + case NAL_IDR_N_LP: + case NAL_CRA_NUT: + case NAL_RADL_N: + case NAL_RADL_R: + case NAL_RASL_N: + case NAL_RASL_R: + av_log(logctx, AV_LOG_ERROR, "Invalid NAL unit: %d\n", nal->type); + ret = AVERROR_INVALIDDATA; + goto done; + break; } - - dst[di++] = src[si++]; } - while (si < length) - dst[di++] = src[si++]; - -nsc: - memset(dst + di, 0, AV_INPUT_BUFFER_PADDING_SIZE); - nal->data = dst; - nal->size = di; - nal->raw_data = src; - nal->raw_size = si; - return si; -} - -static const char *nal_unit_name(int nal_type) -{ - switch(nal_type) { - case NAL_TRAIL_N : return "TRAIL_N"; - case NAL_TRAIL_R : return "TRAIL_R"; - case NAL_TSA_N : return "TSA_N"; - case NAL_TSA_R : return "TSA_R"; - case NAL_STSA_N : return "STSA_N"; - case NAL_STSA_R : return "STSA_R"; - case NAL_RADL_N : return "RADL_N"; - case NAL_RADL_R : return "RADL_R"; - case NAL_RASL_N : return "RASL_N"; - case NAL_RASL_R : return "RASL_R"; - case NAL_BLA_W_LP : return "BLA_W_LP"; - case NAL_BLA_W_RADL : return "BLA_W_RADL"; - case NAL_BLA_N_LP : return "BLA_N_LP"; - case NAL_IDR_W_RADL : return "IDR_W_RADL"; - case NAL_IDR_N_LP : return "IDR_N_LP"; - case NAL_CRA_NUT : return "CRA_NUT"; - case NAL_VPS : return "VPS"; - case NAL_SPS : return "SPS"; - case NAL_PPS : return "PPS"; - case NAL_AUD : return "AUD"; - case NAL_EOS_NUT : return "EOS_NUT"; - case NAL_EOB_NUT : return "EOB_NUT"; - case NAL_FD_NUT : return "FD_NUT"; - case NAL_SEI_PREFIX : return "SEI_PREFIX"; - case NAL_SEI_SUFFIX : return "SEI_SUFFIX"; - default : return "?"; - } +done: + ff_h2645_packet_uninit(&pkt); + return ret; } -/** - * @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) +int ff_hevc_decode_extradata(const uint8_t *data, int size, HEVCParamSets *ps, + int *is_nalff, int *nal_length_size, + int err_recognition, void *logctx) { - 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(%s), nuh_layer_id: %d, temporal_id: %d\n", - nal->type, nal_unit_name(nal->type), nuh_layer_id, nal->temporal_id); - - return nuh_layer_id == 0; -} - - -int ff_hevc_split_packet(HEVCContext *s, 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; + int ret = 0; + GetByteContext gb; + + bytestream2_init(&gb, data, size); + + if (size > 3 && (data[0] || data[1] || data[2] > 1)) { + /* It seems the extradata is encoded as hvcC format. + * Temporarily, we support configurationVersion==0 until 14496-15 3rd + * is finalized. When finalized, configurationVersion will be 1 and we + * can recognize hvcC by checking if avctx->extradata[0]==1 or not. */ + int i, j, num_arrays, nal_len_size; + + *is_nalff = 1; + + bytestream2_skip(&gb, 21); + nal_len_size = (bytestream2_get_byte(&gb) & 3) + 1; + num_arrays = bytestream2_get_byte(&gb); + + /* nal units in the hvcC always have length coded with 2 bytes, + * so put a fake nal_length_size = 2 while parsing them */ + *nal_length_size = 2; + + /* Decode nal units from hvcC. */ + for (i = 0; i < num_arrays; i++) { + int type = bytestream2_get_byte(&gb) & 0x3f; + int cnt = bytestream2_get_be16(&gb); + + for (j = 0; j < cnt; j++) { + // +2 for the nal size field + int nalsize = bytestream2_peek_be16(&gb) + 2; + if (bytestream2_get_bytes_left(&gb) < nalsize) { + av_log(logctx, AV_LOG_ERROR, + "Invalid NAL unit size in extradata.\n"); + return AVERROR_INVALIDDATA; + } - if (extract_length > length) { - av_log(avctx, AV_LOG_ERROR, "Invalid NAL unit size.\n"); - return AVERROR_INVALIDDATA; - } - } else { - /* search start code */ - while (buf[0] != 0 || buf[1] != 0 || buf[2] != 1) { - ++buf; - --length; - if (length < 4) { - if (pkt->nb_nals > 0) { - // No more start codes: we discarded some irrelevant - // bytes at the end of the packet. - return 0; - } else { - av_log(avctx, AV_LOG_ERROR, "No start code is found.\n"); - return AVERROR_INVALIDDATA; - } + ret = hevc_decode_nal_units(gb.buffer, nalsize, ps, *is_nalff, *nal_length_size, logctx); + if (ret < 0) { + av_log(logctx, AV_LOG_ERROR, + "Decoding nal unit %d %d from hvcC failed\n", + type, i); + return ret; } + bytestream2_skip(&gb, nalsize); } - - buf += 3; - length -= 3; - extract_length = length; } - if (pkt->nals_allocated < pkt->nb_nals + 1) { - int new_size = pkt->nals_allocated + 1; - void *tmp = av_realloc_array(pkt->nals, new_size, sizeof(*pkt->nals)); - - if (!tmp) - return AVERROR(ENOMEM); - - pkt->nals = tmp; - memset(pkt->nals + pkt->nals_allocated, 0, - (new_size - pkt->nals_allocated) * sizeof(*pkt->nals)); - - nal = &pkt->nals[pkt->nb_nals]; - nal->skipped_bytes_pos_size = 1024; // initial buffer size - nal->skipped_bytes_pos = av_malloc_array(nal->skipped_bytes_pos_size, sizeof(*nal->skipped_bytes_pos)); - if (!nal->skipped_bytes_pos) - return AVERROR(ENOMEM); - - pkt->nals_allocated = new_size; - } - nal = &pkt->nals[pkt->nb_nals]; - - consumed = ff_hevc_extract_rbsp(s, buf, extract_length, nal); - if (consumed < 0) - return consumed; - - pkt->nb_nals++; - - ret = init_get_bits8(&nal->gb, nal->data, nal->size); + /* Now store right nal length size, that will be used to parse + * all other nals */ + *nal_length_size = nal_len_size; + } else { + *is_nalff = 0; + ret = hevc_decode_nal_units(data, size, ps, *is_nalff, *nal_length_size, logctx); 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; + return ret; } -