#include "config.h"
+#include "libavutil/intmath.h"
#include "libavutil/intreadwrite.h"
#include "libavutil/mem.h"
#include "hevc.h"
#include "h2645_parse.h"
-/* FIXME: This is adapted from ff_h264_decode_nal, avoiding duplication
- * between these functions would be nice. */
int ff_h2645_extract_rbsp(const uint8_t *src, int length,
H2645NAL *nal)
{
nal->skipped_bytes = 0;
#define STARTCODE_TEST \
if (i + 2 < length && src[i + 1] == 0 && src[i + 2] <= 3) { \
- if (src[i + 2] != 3) { \
+ if (src[i + 2] != 3 && src[i + 2] != 0) { \
/* startcode, so we must be past the end */ \
length = i; \
} \
if (src[si + 2] > 3) {
dst[di++] = src[si++];
dst[di++] = src[si++];
- } else if (src[si] == 0 && src[si + 1] == 0) {
+ } else if (src[si] == 0 && src[si + 1] == 0 && src[si + 2] != 0) {
if (src[si + 2] == 3) { // escape
dst[di++] = 0;
dst[di++] = 0;
}
}
+static int get_bit_length(H2645NAL *nal, int skip_trailing_zeros)
+{
+ int size = nal->size;
+ int v;
+
+ while (skip_trailing_zeros && size > 0 && nal->data[size - 1] == 0)
+ size--;
+
+ if (!size)
+ return 0;
+
+ v = nal->data[size - 1];
+
+ if (size > INT_MAX / 8)
+ return AVERROR(ERANGE);
+ size *= 8;
+
+ /* remove the stop bit and following trailing zeros,
+ * or nothing for damaged bitstreams */
+ if (v)
+ size -= ff_ctz(v) + 1;
+
+ return size;
+}
+
/**
* @return AVERROR_INVALIDDATA if the packet is not a valid NAL unit,
* 0 if the unit should be skipped, 1 otherwise
enum AVCodecID codec_id)
{
int consumed, ret = 0;
+ const uint8_t *next_avc = is_nalff ? buf : buf + length;
pkt->nb_nals = 0;
while (length >= 4) {
H2645NAL *nal;
int extract_length = 0;
+ int skip_trailing_zeros = 1;
- if (is_nalff) {
+ if (buf >= next_avc) {
int i;
for (i = 0; i < nal_length_size; i++)
extract_length = (extract_length << 8) | buf[i];
av_log(logctx, AV_LOG_ERROR, "Invalid NAL unit size.\n");
return AVERROR_INVALIDDATA;
}
+ next_avc = buf + extract_length;
} else {
/* search start code */
while (buf[0] != 0 || buf[1] != 0 || buf[2] != 1) {
av_log(logctx, AV_LOG_ERROR, "No start code is found.\n");
return AVERROR_INVALIDDATA;
}
- }
+ } else if (buf >= (next_avc - 3))
+ break;
}
buf += 3;
length -= 3;
extract_length = length;
+
+ if (buf >= next_avc) {
+ /* skip to the start of the next NAL */
+ int offset = next_avc - buf;
+ buf += offset;
+ length -= offset;
+ continue;
+ }
}
if (pkt->nals_allocated < pkt->nb_nals + 1) {
if (consumed < 0)
return consumed;
+ if (is_nalff && (extract_length != consumed) && extract_length)
+ av_log(logctx, AV_LOG_DEBUG,
+ "NALFF: Consumed only %d bytes instead of %d\n",
+ consumed, extract_length);
+
pkt->nb_nals++;
- ret = init_get_bits8(&nal->gb, nal->data, nal->size);
+ /* see commit 3566042a0 */
+ if (consumed < length - 3 &&
+ buf[consumed] == 0x00 && buf[consumed + 1] == 0x00 &&
+ buf[consumed + 2] == 0x01 && buf[consumed + 3] == 0xE0)
+ skip_trailing_zeros = 0;
+
+ nal->size_bits = get_bit_length(nal, skip_trailing_zeros);
+
+ ret = init_get_bits(&nal->gb, nal->data, nal->size_bits);
if (ret < 0)
return ret;
ret = hevc_parse_nal_header(nal, logctx);
else
ret = h264_parse_nal_header(nal, logctx);
- if (ret <= 0) {
+ if (ret <= 0 || nal->size <= 0) {
if (ret < 0) {
av_log(logctx, AV_LOG_ERROR, "Invalid NAL unit %d, skipping.\n",
nal->type);