Add support for 3-byte headers in VideoToolbox NALU parser.

BUG=webrtc:6278
R=tkchin@webrtc.org, tommi@webrtc.org

Review URL: https://codereview.webrtc.org/2356793002 .

Cr-Original-Commit-Position: refs/heads/master@{#14889}
Cr-Mirrored-From: https://chromium.googlesource.com/external/webrtc
Cr-Mirrored-Commit: cb18ee61270694e743970100bf2871bd67a44906
diff --git a/common_video/h264/h264_common.cc b/common_video/h264/h264_common.cc
index c17b118..fe55b02 100644
--- a/common_video/h264/h264_common.cc
+++ b/common_video/h264/h264_common.cc
@@ -21,8 +21,9 @@
   // given a 3-byte sequence we're looking at, if the 3rd byte isn't 1 or 0,
   // skip ahead to the next 3-byte sequence. 0s and 1s are relatively rare, so
   // this will skip the majority of reads/checks.
-  RTC_CHECK_GE(buffer_size, kNaluShortStartSequenceSize);
   std::vector<NaluIndex> sequences;
+  if (buffer_size < kNaluShortStartSequenceSize)
+    return sequences;
   const size_t end = buffer_size - kNaluShortStartSequenceSize;
   for (size_t i = 0; i < end;) {
     if (buffer[i + 2] > 1) {
diff --git a/modules/video_coding/codecs/h264/h264_video_toolbox_nalu.cc b/modules/video_coding/codecs/h264/h264_video_toolbox_nalu.cc
index c6c0406..357b4d4 100644
--- a/modules/video_coding/codecs/h264/h264_video_toolbox_nalu.cc
+++ b/modules/video_coding/codecs/h264/h264_video_toolbox_nalu.cc
@@ -19,13 +19,13 @@
 
 #include "webrtc/base/checks.h"
 #include "webrtc/base/logging.h"
-#include "webrtc/common_video/h264/h264_common.h"
 
 namespace webrtc {
 
-using H264::NaluType;
 using H264::kAud;
 using H264::kSps;
+using H264::NaluIndex;
+using H264::NaluType;
 using H264::ParseNaluType;
 
 const char kAnnexBHeaderBytes[4] = {0, 0, 0, 1};
@@ -57,8 +57,7 @@
     LOG(LS_ERROR) << "Failed to get parameter set.";
     return false;
   }
-  // TODO(tkchin): handle other potential sizes.
-  RTC_DCHECK_EQ(nalu_header_size, 4);
+  RTC_CHECK_EQ(nalu_header_size, kAvccHeaderByteSize);
   RTC_DCHECK_EQ(param_set_count, 2u);
 
   // Truncate any previous data in the buffer without changing its capacity.
@@ -140,7 +139,7 @@
     frag_lengths.push_back(packet_size);
     nalu_offset += sizeof(kAnnexBHeaderBytes) + packet_size;
 
-    size_t bytes_written = packet_size + nalu_header_size;
+    size_t bytes_written = packet_size + sizeof(kAnnexBHeaderBytes);
     bytes_remaining -= bytes_written;
     data_ptr += bytes_written;
   }
@@ -312,11 +311,10 @@
 
 AnnexBBufferReader::AnnexBBufferReader(const uint8_t* annexb_buffer,
                                        size_t length)
-    : start_(annexb_buffer), offset_(0), next_offset_(0), length_(length) {
+    : start_(annexb_buffer), length_(length) {
   RTC_DCHECK(annexb_buffer);
-  offset_ = FindNextNaluHeader(start_, length_, 0);
-  next_offset_ =
-      FindNextNaluHeader(start_, length_, offset_ + sizeof(kAnnexBHeaderBytes));
+  offsets_ = H264::FindNaluIndices(annexb_buffer, length);
+  offset_ = offsets_.begin();
 }
 
 bool AnnexBBufferReader::ReadNalu(const uint8_t** out_nalu,
@@ -326,46 +324,20 @@
   *out_nalu = nullptr;
   *out_length = 0;
 
-  size_t data_offset = offset_ + sizeof(kAnnexBHeaderBytes);
-  if (data_offset > length_) {
+  if (offset_ == offsets_.end()) {
     return false;
   }
-  *out_nalu = start_ + data_offset;
-  *out_length = next_offset_ - data_offset;
-  offset_ = next_offset_;
-  next_offset_ =
-      FindNextNaluHeader(start_, length_, offset_ + sizeof(kAnnexBHeaderBytes));
+  *out_nalu = start_ + offset_->payload_start_offset;
+  *out_length = offset_->payload_size;
+  ++offset_;
   return true;
 }
 
 size_t AnnexBBufferReader::BytesRemaining() const {
-  return length_ - offset_;
-}
-
-size_t AnnexBBufferReader::FindNextNaluHeader(const uint8_t* start,
-                                              size_t length,
-                                              size_t offset) const {
-  RTC_DCHECK(start);
-  if (offset + sizeof(kAnnexBHeaderBytes) > length) {
-    return length;
+  if (offset_ == offsets_.end()) {
+    return 0;
   }
-  // NALUs are separated by an 00 00 00 01 header. Scan the byte stream
-  // starting from the offset for the next such sequence.
-  const uint8_t* current = start + offset;
-  // The loop reads sizeof(kAnnexBHeaderBytes) at a time, so stop when there
-  // aren't enough bytes remaining.
-  const uint8_t* const end = start + length - sizeof(kAnnexBHeaderBytes);
-  while (current < end) {
-    if (current[3] > 1) {
-      current += 4;
-    } else if (current[3] == 1 && current[2] == 0 && current[1] == 0 &&
-               current[0] == 0) {
-      return current - start;
-    } else {
-      ++current;
-    }
-  }
-  return length;
+  return length_ - offset_->start_offset;
 }
 
 AvccBufferWriter::AvccBufferWriter(uint8_t* const avcc_buffer, size_t length)
diff --git a/modules/video_coding/codecs/h264/h264_video_toolbox_nalu.h b/modules/video_coding/codecs/h264/h264_video_toolbox_nalu.h
index 5094253..7862c3b 100644
--- a/modules/video_coding/codecs/h264/h264_video_toolbox_nalu.h
+++ b/modules/video_coding/codecs/h264/h264_video_toolbox_nalu.h
@@ -17,10 +17,14 @@
 #if defined(WEBRTC_VIDEO_TOOLBOX_SUPPORTED)
 
 #include <CoreMedia/CoreMedia.h>
+#include <vector>
 
 #include "webrtc/base/buffer.h"
+#include "webrtc/common_video/h264/h264_common.h"
 #include "webrtc/modules/include/module_common_types.h"
 
+using webrtc::H264::NaluIndex;
+
 namespace webrtc {
 
 // Converts a sample buffer emitted from the VideoToolbox encoder into a buffer
@@ -79,8 +83,8 @@
                             size_t offset) const;
 
   const uint8_t* const start_;
-  size_t offset_;
-  size_t next_offset_;
+  std::vector<NaluIndex> offsets_;
+  std::vector<NaluIndex>::iterator offset_;
   const size_t length_;
 };
 
diff --git a/modules/video_coding/codecs/h264/h264_video_toolbox_nalu_unittest.cc b/modules/video_coding/codecs/h264/h264_video_toolbox_nalu_unittest.cc
index b5e3195..df71f54 100644
--- a/modules/video_coding/codecs/h264/h264_video_toolbox_nalu_unittest.cc
+++ b/modules/video_coding/codecs/h264/h264_video_toolbox_nalu_unittest.cc
@@ -87,11 +87,25 @@
   EXPECT_EQ(0u, nalu_length);
 }
 
+TEST(AnnexBBufferReaderTest, TestReadSingleNalu3ByteHeader) {
+  const uint8_t annex_b_test_data[] = {0x00, 0x00, 0x01, 0xAA};
+  AnnexBBufferReader reader(annex_b_test_data, arraysize(annex_b_test_data));
+  const uint8_t* nalu = nullptr;
+  size_t nalu_length = 0;
+  EXPECT_EQ(arraysize(annex_b_test_data), reader.BytesRemaining());
+  EXPECT_TRUE(reader.ReadNalu(&nalu, &nalu_length));
+  EXPECT_EQ(annex_b_test_data + 3, nalu);
+  EXPECT_EQ(1u, nalu_length);
+  EXPECT_EQ(0u, reader.BytesRemaining());
+  EXPECT_FALSE(reader.ReadNalu(&nalu, &nalu_length));
+  EXPECT_EQ(nullptr, nalu);
+  EXPECT_EQ(0u, nalu_length);
+}
+
 TEST(AnnexBBufferReaderTest, TestReadMissingNalu) {
   // clang-format off
   const uint8_t annex_b_test_data[] = {0x01,
                                        0x00, 0x01,
-                                       0x00, 0x00, 0x01,
                                        0x00, 0x00, 0x00, 0xFF};
   // clang-format on
   AnnexBBufferReader reader(annex_b_test_data, arraysize(annex_b_test_data));
@@ -108,9 +122,8 @@
   const uint8_t annex_b_test_data[] = {0x00, 0x00, 0x00, 0x01, 0xFF,
                                        0x01,
                                        0x00, 0x01,
-                                       0x00, 0x00, 0x01,
                                        0x00, 0x00, 0x00, 0xFF,
-                                       0x00, 0x00, 0x00, 0x01, 0xAA, 0xBB};
+                                       0x00, 0x00, 0x01, 0xAA, 0xBB};
   // clang-format on
   AnnexBBufferReader reader(annex_b_test_data, arraysize(annex_b_test_data));
   const uint8_t* nalu = nullptr;
@@ -118,10 +131,10 @@
   EXPECT_EQ(arraysize(annex_b_test_data), reader.BytesRemaining());
   EXPECT_TRUE(reader.ReadNalu(&nalu, &nalu_length));
   EXPECT_EQ(annex_b_test_data + 4, nalu);
-  EXPECT_EQ(11u, nalu_length);
+  EXPECT_EQ(8u, nalu_length);
   EXPECT_EQ(6u, reader.BytesRemaining());
   EXPECT_TRUE(reader.ReadNalu(&nalu, &nalu_length));
-  EXPECT_EQ(annex_b_test_data + 19, nalu);
+  EXPECT_EQ(annex_b_test_data + 16, nalu);
   EXPECT_EQ(2u, nalu_length);
   EXPECT_EQ(0u, reader.BytesRemaining());
   EXPECT_FALSE(reader.ReadNalu(&nalu, &nalu_length));