]> git.sesse.net Git - ffmpeg/blobdiff - libavcodec/h2645_parse.c
avcodec/sheervideo: add interlaced YCbCr(A) 4:2:2:4 8-bit support
[ffmpeg] / libavcodec / h2645_parse.c
index 6e24ea39c50cf089ff11744ac429a9cc2f38fbc2..9979b63c3be6f42bb4e475248c601ab2d2708873 100644 (file)
 
 #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)
 {
@@ -39,7 +38,7 @@ int ff_h2645_extract_rbsp(const uint8_t *src, int length,
     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;                                             \
             }                                                           \
@@ -104,7 +103,7 @@ int ff_h2645_extract_rbsp(const uint8_t *src, int length,
         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;
@@ -178,6 +177,31 @@ static const char *nal_unit_name(int nal_type)
     }
 }
 
+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
@@ -226,13 +250,15 @@ int ff_h2645_packet_split(H2645Packet *pkt, const uint8_t *buf, int length,
                           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];
@@ -243,6 +269,7 @@ int ff_h2645_packet_split(H2645Packet *pkt, const uint8_t *buf, int length,
                 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) {
@@ -257,12 +284,21 @@ int ff_h2645_packet_split(H2645Packet *pkt, const uint8_t *buf, int length,
                         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) {
@@ -290,9 +326,22 @@ int ff_h2645_packet_split(H2645Packet *pkt, const uint8_t *buf, int length,
         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;
 
@@ -300,7 +349,7 @@ int ff_h2645_packet_split(H2645Packet *pkt, const uint8_t *buf, int length,
             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);