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));