Use ArrayView on H264 bitstream parsing

No-Try: true
Bug: webrtc:42225170
Change-Id: I4682f400054fee5c86ea24bebf6d703fb90074da
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/354722
Reviewed-by: Harald Alvestrand <hta@webrtc.org>
Commit-Queue: Ilya Nikolaevskiy <ilnik@webrtc.org>
Reviewed-by: Danil Chapovalov <danilchap@webrtc.org>
Reviewed-by: Sergey Silkin <ssilkin@webrtc.org>
Reviewed-by: Ilya Nikolaevskiy <ilnik@webrtc.org>
Reviewed-by: Erik Språng <sprang@webrtc.org>
Cr-Commit-Position: refs/heads/main@{#42650}
This commit is contained in:
Sergio Garcia Murillo 2024-07-17 19:33:37 +02:00 committed by WebRTC LUCI CQ
parent b27ac6bc83
commit 45e5e385f3
36 changed files with 251 additions and 233 deletions

View File

@ -31,15 +31,13 @@ H264BitstreamParser::H264BitstreamParser() = default;
H264BitstreamParser::~H264BitstreamParser() = default; H264BitstreamParser::~H264BitstreamParser() = default;
H264BitstreamParser::Result H264BitstreamParser::ParseNonParameterSetNalu( H264BitstreamParser::Result H264BitstreamParser::ParseNonParameterSetNalu(
const uint8_t* source, rtc::ArrayView<const uint8_t> source,
size_t source_length,
uint8_t nalu_type) { uint8_t nalu_type) {
if (!sps_ || !pps_) if (!sps_ || !pps_)
return kInvalidStream; return kInvalidStream;
last_slice_qp_delta_ = absl::nullopt; last_slice_qp_delta_ = absl::nullopt;
const std::vector<uint8_t> slice_rbsp = const std::vector<uint8_t> slice_rbsp = H264::ParseRbsp(source);
H264::ParseRbsp(source, source_length);
if (slice_rbsp.size() < H264::kNaluTypeSize) if (slice_rbsp.size() < H264::kNaluTypeSize)
return kInvalidStream; return kInvalidStream;
@ -308,19 +306,17 @@ H264BitstreamParser::Result H264BitstreamParser::ParseNonParameterSetNalu(
return kOk; return kOk;
} }
void H264BitstreamParser::ParseSlice(const uint8_t* slice, size_t length) { void H264BitstreamParser::ParseSlice(rtc::ArrayView<const uint8_t> slice) {
H264::NaluType nalu_type = H264::ParseNaluType(slice[0]); H264::NaluType nalu_type = H264::ParseNaluType(slice[0]);
switch (nalu_type) { switch (nalu_type) {
case H264::NaluType::kSps: { case H264::NaluType::kSps: {
sps_ = SpsParser::ParseSps(slice + H264::kNaluTypeSize, sps_ = SpsParser::ParseSps(slice.subview(H264::kNaluTypeSize));
length - H264::kNaluTypeSize);
if (!sps_) if (!sps_)
RTC_DLOG(LS_WARNING) << "Unable to parse SPS from H264 bitstream."; RTC_DLOG(LS_WARNING) << "Unable to parse SPS from H264 bitstream.";
break; break;
} }
case H264::NaluType::kPps: { case H264::NaluType::kPps: {
pps_ = PpsParser::ParsePps(slice + H264::kNaluTypeSize, pps_ = PpsParser::ParsePps(slice.subview(H264::kNaluTypeSize));
length - H264::kNaluTypeSize);
if (!pps_) if (!pps_)
RTC_DLOG(LS_WARNING) << "Unable to parse PPS from H264 bitstream."; RTC_DLOG(LS_WARNING) << "Unable to parse PPS from H264 bitstream.";
break; break;
@ -330,7 +326,7 @@ void H264BitstreamParser::ParseSlice(const uint8_t* slice, size_t length) {
case H264::NaluType::kPrefix: case H264::NaluType::kPrefix:
break; // Ignore these nalus, as we don't care about their contents. break; // Ignore these nalus, as we don't care about their contents.
default: default:
Result res = ParseNonParameterSetNalu(slice, length, nalu_type); Result res = ParseNonParameterSetNalu(slice, nalu_type);
if (res != kOk) if (res != kOk)
RTC_DLOG(LS_INFO) << "Failed to parse bitstream. Error: " << res; RTC_DLOG(LS_INFO) << "Failed to parse bitstream. Error: " << res;
break; break;
@ -339,11 +335,10 @@ void H264BitstreamParser::ParseSlice(const uint8_t* slice, size_t length) {
void H264BitstreamParser::ParseBitstream( void H264BitstreamParser::ParseBitstream(
rtc::ArrayView<const uint8_t> bitstream) { rtc::ArrayView<const uint8_t> bitstream) {
std::vector<H264::NaluIndex> nalu_indices = std::vector<H264::NaluIndex> nalu_indices = H264::FindNaluIndices(bitstream);
H264::FindNaluIndices(bitstream.data(), bitstream.size());
for (const H264::NaluIndex& index : nalu_indices) for (const H264::NaluIndex& index : nalu_indices)
ParseSlice(bitstream.data() + index.payload_start_offset, ParseSlice(
index.payload_size); bitstream.subview(index.payload_start_offset, index.payload_size));
} }
absl::optional<int> H264BitstreamParser::GetLastSliceQp() const { absl::optional<int> H264BitstreamParser::GetLastSliceQp() const {

View File

@ -40,9 +40,8 @@ class H264BitstreamParser : public BitstreamParser {
kInvalidStream, kInvalidStream,
kUnsupportedStream, kUnsupportedStream,
}; };
void ParseSlice(const uint8_t* slice, size_t length); void ParseSlice(rtc::ArrayView<const uint8_t> slice);
Result ParseNonParameterSetNalu(const uint8_t* source, Result ParseNonParameterSetNalu(rtc::ArrayView<const uint8_t> source,
size_t source_length,
uint8_t nalu_type); uint8_t nalu_type);
// SPS/PPS state, updated when parsing new SPS/PPS, used to parse slices. // SPS/PPS state, updated when parsing new SPS/PPS, used to parse slices.

View File

@ -17,19 +17,18 @@ namespace H264 {
const uint8_t kNaluTypeMask = 0x1F; const uint8_t kNaluTypeMask = 0x1F;
std::vector<NaluIndex> FindNaluIndices(const uint8_t* buffer, std::vector<NaluIndex> FindNaluIndices(rtc::ArrayView<const uint8_t> buffer) {
size_t buffer_size) {
// This is sorta like Boyer-Moore, but with only the first optimization step: // This is sorta like Boyer-Moore, but with only the first optimization step:
// given a 3-byte sequence we're looking at, if the 3rd byte isn't 1 or 0, // 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 // skip ahead to the next 3-byte sequence. 0s and 1s are relatively rare, so
// this will skip the majority of reads/checks. // this will skip the majority of reads/checks.
std::vector<NaluIndex> sequences; std::vector<NaluIndex> sequences;
if (buffer_size < kNaluShortStartSequenceSize) if (buffer.size() < kNaluShortStartSequenceSize)
return sequences; return sequences;
static_assert(kNaluShortStartSequenceSize >= 2, static_assert(kNaluShortStartSequenceSize >= 2,
"kNaluShortStartSequenceSize must be larger or equals to 2"); "kNaluShortStartSequenceSize must be larger or equals to 2");
const size_t end = buffer_size - kNaluShortStartSequenceSize; const size_t end = buffer.size() - kNaluShortStartSequenceSize;
for (size_t i = 0; i < end;) { for (size_t i = 0; i < end;) {
if (buffer[i + 2] > 1) { if (buffer[i + 2] > 1) {
i += 3; i += 3;
@ -57,7 +56,7 @@ std::vector<NaluIndex> FindNaluIndices(const uint8_t* buffer,
// Update length of last entry, if any. // Update length of last entry, if any.
auto it = sequences.rbegin(); auto it = sequences.rbegin();
if (it != sequences.rend()) if (it != sequences.rend())
it->payload_size = buffer_size - it->payload_start_offset; it->payload_size = buffer.size() - it->payload_start_offset;
return sequences; return sequences;
} }
@ -66,16 +65,16 @@ NaluType ParseNaluType(uint8_t data) {
return static_cast<NaluType>(data & kNaluTypeMask); return static_cast<NaluType>(data & kNaluTypeMask);
} }
std::vector<uint8_t> ParseRbsp(const uint8_t* data, size_t length) { std::vector<uint8_t> ParseRbsp(rtc::ArrayView<const uint8_t> data) {
std::vector<uint8_t> out; std::vector<uint8_t> out;
out.reserve(length); out.reserve(data.size());
for (size_t i = 0; i < length;) { for (size_t i = 0; i < data.size();) {
// Be careful about over/underflow here. byte_length_ - 3 can underflow, and // Be careful about over/underflow here. byte_length_ - 3 can underflow, and
// i + 3 can overflow, but byte_length_ - i can't, because i < byte_length_ // i + 3 can overflow, but byte_length_ - i can't, because i < byte_length_
// above, and that expression will produce the number of bytes left in // above, and that expression will produce the number of bytes left in
// the stream including the byte at i. // the stream including the byte at i.
if (length - i >= 3 && !data[i] && !data[i + 1] && data[i + 2] == 3) { if (data.size() - i >= 3 && !data[i] && !data[i + 1] && data[i + 2] == 3) {
// Two rbsp bytes. // Two rbsp bytes.
out.push_back(data[i++]); out.push_back(data[i++]);
out.push_back(data[i++]); out.push_back(data[i++]);
@ -89,14 +88,13 @@ std::vector<uint8_t> ParseRbsp(const uint8_t* data, size_t length) {
return out; return out;
} }
void WriteRbsp(const uint8_t* bytes, size_t length, rtc::Buffer* destination) { void WriteRbsp(rtc::ArrayView<const uint8_t> bytes, rtc::Buffer* destination) {
static const uint8_t kZerosInStartSequence = 2; static const uint8_t kZerosInStartSequence = 2;
static const uint8_t kEmulationByte = 0x03u; static const uint8_t kEmulationByte = 0x03u;
size_t num_consecutive_zeros = 0; size_t num_consecutive_zeros = 0;
destination->EnsureCapacity(destination->size() + length); destination->EnsureCapacity(destination->size() + bytes.size());
for (size_t i = 0; i < length; ++i) { for (uint8_t byte : bytes) {
uint8_t byte = bytes[i];
if (byte <= kEmulationByte && if (byte <= kEmulationByte &&
num_consecutive_zeros >= kZerosInStartSequence) { num_consecutive_zeros >= kZerosInStartSequence) {
// Need to escape. // Need to escape.

View File

@ -63,8 +63,14 @@ struct NaluIndex {
}; };
// Returns a vector of the NALU indices in the given buffer. // Returns a vector of the NALU indices in the given buffer.
RTC_EXPORT std::vector<NaluIndex> FindNaluIndices(const uint8_t* buffer, RTC_EXPORT std::vector<NaluIndex> FindNaluIndices(
size_t buffer_size); rtc::ArrayView<const uint8_t> buffer);
// TODO: bugs.webrtc.org/42225170 - Deprecate.
inline std::vector<NaluIndex> FindNaluIndices(const uint8_t* buffer,
size_t buffer_size) {
return FindNaluIndices(rtc::MakeArrayView(buffer, buffer_size));
}
// Get the NAL type from the header byte immediately following start sequence. // Get the NAL type from the header byte immediately following start sequence.
RTC_EXPORT NaluType ParseNaluType(uint8_t data); RTC_EXPORT NaluType ParseNaluType(uint8_t data);
@ -83,12 +89,24 @@ RTC_EXPORT NaluType ParseNaluType(uint8_t data);
// the 03 emulation byte. // the 03 emulation byte.
// Parse the given data and remove any emulation byte escaping. // Parse the given data and remove any emulation byte escaping.
std::vector<uint8_t> ParseRbsp(const uint8_t* data, size_t length); std::vector<uint8_t> ParseRbsp(rtc::ArrayView<const uint8_t> data);
// TODO: bugs.webrtc.org/42225170 - Deprecate.
inline std::vector<uint8_t> ParseRbsp(const uint8_t* data, size_t length) {
return ParseRbsp(rtc::MakeArrayView(data, length));
}
// Write the given data to the destination buffer, inserting and emulation // Write the given data to the destination buffer, inserting and emulation
// bytes in order to escape any data the could be interpreted as a start // bytes in order to escape any data the could be interpreted as a start
// sequence. // sequence.
void WriteRbsp(const uint8_t* bytes, size_t length, rtc::Buffer* destination); void WriteRbsp(rtc::ArrayView<const uint8_t> bytes, rtc::Buffer* destination);
// TODO: bugs.webrtc.org/42225170 - Deprecate.
inline void WriteRbsp(const uint8_t* bytes,
size_t length,
rtc::Buffer* destination) {
WriteRbsp(rtc::MakeArrayView(bytes, length), destination);
}
} // namespace H264 } // namespace H264
} // namespace webrtc } // namespace webrtc

View File

@ -29,16 +29,15 @@ constexpr int kMinPicInitQpDeltaValue = -26;
// You can find it on this page: // You can find it on this page:
// http://www.itu.int/rec/T-REC-H.264 // http://www.itu.int/rec/T-REC-H.264
absl::optional<PpsParser::PpsState> PpsParser::ParsePps(const uint8_t* data, absl::optional<PpsParser::PpsState> PpsParser::ParsePps(
size_t length) { rtc::ArrayView<const uint8_t> data) {
// First, parse out rbsp, which is basically the source buffer minus emulation // First, parse out rbsp, which is basically the source buffer minus emulation
// bytes (the last byte of a 0x00 0x00 0x03 sequence). RBSP is defined in // bytes (the last byte of a 0x00 0x00 0x03 sequence). RBSP is defined in
// section 7.3.1 of the H.264 standard. // section 7.3.1 of the H.264 standard.
return ParseInternal(H264::ParseRbsp(data, length)); return ParseInternal(H264::ParseRbsp(data));
} }
bool PpsParser::ParsePpsIds(const uint8_t* data, bool PpsParser::ParsePpsIds(rtc::ArrayView<const uint8_t> data,
size_t length,
uint32_t* pps_id, uint32_t* pps_id,
uint32_t* sps_id) { uint32_t* sps_id) {
RTC_DCHECK(pps_id); RTC_DCHECK(pps_id);
@ -46,7 +45,7 @@ bool PpsParser::ParsePpsIds(const uint8_t* data,
// First, parse out rbsp, which is basically the source buffer minus emulation // First, parse out rbsp, which is basically the source buffer minus emulation
// bytes (the last byte of a 0x00 0x00 0x03 sequence). RBSP is defined in // bytes (the last byte of a 0x00 0x00 0x03 sequence). RBSP is defined in
// section 7.3.1 of the H.264 standard. // section 7.3.1 of the H.264 standard.
std::vector<uint8_t> unpacked_buffer = H264::ParseRbsp(data, length); std::vector<uint8_t> unpacked_buffer = H264::ParseRbsp(data);
BitstreamReader reader(unpacked_buffer); BitstreamReader reader(unpacked_buffer);
*pps_id = reader.ReadExponentialGolomb(); *pps_id = reader.ReadExponentialGolomb();
*sps_id = reader.ReadExponentialGolomb(); *sps_id = reader.ReadExponentialGolomb();
@ -54,9 +53,8 @@ bool PpsParser::ParsePpsIds(const uint8_t* data,
} }
absl::optional<PpsParser::SliceHeader> PpsParser::ParseSliceHeader( absl::optional<PpsParser::SliceHeader> PpsParser::ParseSliceHeader(
const uint8_t* data, rtc::ArrayView<const uint8_t> data) {
size_t length) { std::vector<uint8_t> unpacked_buffer = H264::ParseRbsp(data);
std::vector<uint8_t> unpacked_buffer = H264::ParseRbsp(data, length);
BitstreamReader slice_reader(unpacked_buffer); BitstreamReader slice_reader(unpacked_buffer);
PpsParser::SliceHeader slice_header; PpsParser::SliceHeader slice_header;

View File

@ -47,15 +47,19 @@ class PpsParser {
}; };
// Unpack RBSP and parse PPS state from the supplied buffer. // Unpack RBSP and parse PPS state from the supplied buffer.
static absl::optional<PpsState> ParsePps(const uint8_t* data, size_t length); static absl::optional<PpsState> ParsePps(rtc::ArrayView<const uint8_t> data);
// TODO: bugs.webrtc.org/42225170 - Deprecate.
static inline absl::optional<PpsState> ParsePps(const uint8_t* data,
size_t length) {
return ParsePps(rtc::MakeArrayView(data, length));
}
static bool ParsePpsIds(const uint8_t* data, static bool ParsePpsIds(rtc::ArrayView<const uint8_t> data,
size_t length,
uint32_t* pps_id, uint32_t* pps_id,
uint32_t* sps_id); uint32_t* sps_id);
static absl::optional<SliceHeader> ParseSliceHeader(const uint8_t* data, static absl::optional<SliceHeader> ParseSliceHeader(
size_t length); rtc::ArrayView<const uint8_t> data);
protected: protected:
// Parse the PPS state, for a buffer where RBSP decoding has already been // Parse the PPS state, for a buffer where RBSP decoding has already been

View File

@ -134,7 +134,7 @@ void WritePps(const PpsParser::PpsState& pps,
bit_buffer.GetCurrentOffset(&byte_offset, &bit_offset); bit_buffer.GetCurrentOffset(&byte_offset, &bit_offset);
} }
H264::WriteRbsp(data, byte_offset, out_buffer); H264::WriteRbsp(rtc::MakeArrayView(data, byte_offset), out_buffer);
} }
class PpsParserTest : public ::testing::Test { class PpsParserTest : public ::testing::Test {
@ -175,7 +175,7 @@ class PpsParserTest : public ::testing::Test {
buffer_.Clear(); buffer_.Clear();
WritePps(pps, slice_group_map_type, num_slice_groups, pic_size_in_map_units, WritePps(pps, slice_group_map_type, num_slice_groups, pic_size_in_map_units,
&buffer_); &buffer_);
parsed_pps_ = PpsParser::ParsePps(buffer_.data(), buffer_.size()); parsed_pps_ = PpsParser::ParsePps(buffer_);
ASSERT_TRUE(parsed_pps_); ASSERT_TRUE(parsed_pps_);
EXPECT_EQ(pps.bottom_field_pic_order_in_frame_present_flag, EXPECT_EQ(pps.bottom_field_pic_order_in_frame_present_flag,
parsed_pps_->bottom_field_pic_order_in_frame_present_flag); parsed_pps_->bottom_field_pic_order_in_frame_present_flag);
@ -219,18 +219,17 @@ TEST_F(PpsParserTest, MaxPps) {
} }
TEST_F(PpsParserTest, ParseSliceHeader) { TEST_F(PpsParserTest, ParseSliceHeader) {
std::vector<H264::NaluIndex> nalu_indices = rtc::ArrayView<const uint8_t> chunk(kH264BitstreamChunk);
H264::FindNaluIndices(kH264BitstreamChunk, sizeof(kH264BitstreamChunk)); std::vector<H264::NaluIndex> nalu_indices = H264::FindNaluIndices(chunk);
EXPECT_EQ(nalu_indices.size(), 3ull); EXPECT_EQ(nalu_indices.size(), 3ull);
for (const auto& index : nalu_indices) { for (const auto& index : nalu_indices) {
H264::NaluType nalu_type = H264::NaluType nalu_type =
H264::ParseNaluType(kH264BitstreamChunk[index.payload_start_offset]); H264::ParseNaluType(chunk[index.payload_start_offset]);
if (nalu_type == H264::NaluType::kIdr) { if (nalu_type == H264::NaluType::kIdr) {
// Skip NAL type header and parse slice header. // Skip NAL type header and parse slice header.
absl::optional<PpsParser::SliceHeader> slice_header = absl::optional<PpsParser::SliceHeader> slice_header =
PpsParser::ParseSliceHeader( PpsParser::ParseSliceHeader(chunk.subview(
kH264BitstreamChunk + index.payload_start_offset + 1, index.payload_start_offset + 1, index.payload_size - 1));
index.payload_size - 1);
ASSERT_TRUE(slice_header.has_value()); ASSERT_TRUE(slice_header.has_value());
EXPECT_EQ(slice_header->first_mb_in_slice, 0u); EXPECT_EQ(slice_header->first_mb_in_slice, 0u);
EXPECT_EQ(slice_header->pic_parameter_set_id, 0u); EXPECT_EQ(slice_header->pic_parameter_set_id, 0u);

View File

@ -32,9 +32,9 @@ SpsParser::SpsState::~SpsState() = default;
// http://www.itu.int/rec/T-REC-H.264 // http://www.itu.int/rec/T-REC-H.264
// Unpack RBSP and parse SPS state from the supplied buffer. // Unpack RBSP and parse SPS state from the supplied buffer.
absl::optional<SpsParser::SpsState> SpsParser::ParseSps(const uint8_t* data, absl::optional<SpsParser::SpsState> SpsParser::ParseSps(
size_t length) { rtc::ArrayView<const uint8_t> data) {
std::vector<uint8_t> unpacked_buffer = H264::ParseRbsp(data, length); std::vector<uint8_t> unpacked_buffer = H264::ParseRbsp(data);
BitstreamReader reader(unpacked_buffer); BitstreamReader reader(unpacked_buffer);
return ParseSpsUpToVui(reader); return ParseSpsUpToVui(reader);
} }

View File

@ -42,7 +42,12 @@ class RTC_EXPORT SpsParser {
}; };
// Unpack RBSP and parse SPS state from the supplied buffer. // Unpack RBSP and parse SPS state from the supplied buffer.
static absl::optional<SpsState> ParseSps(const uint8_t* data, size_t length); static absl::optional<SpsState> ParseSps(rtc::ArrayView<const uint8_t> data);
// TODO: bugs.webrtc.org/42225170 - Deprecate.
static inline absl::optional<SpsState> ParseSps(const uint8_t* data,
size_t length) {
return ParseSps(rtc::MakeArrayView(data, length));
}
protected: protected:
// Parse the SPS state, up till the VUI part, for a buffer where RBSP // Parse the SPS state, up till the VUI part, for a buffer where RBSP

View File

@ -107,7 +107,7 @@ void GenerateFakeSps(uint16_t width,
} }
out_buffer->Clear(); out_buffer->Clear();
H264::WriteRbsp(rbsp, byte_count, out_buffer); H264::WriteRbsp(rtc::MakeArrayView(rbsp, byte_count), out_buffer);
} }
TEST(H264SpsParserTest, TestSampleSPSHdLandscape) { TEST(H264SpsParserTest, TestSampleSPSHdLandscape) {
@ -116,8 +116,7 @@ TEST(H264SpsParserTest, TestSampleSPSHdLandscape) {
const uint8_t buffer[] = {0x7A, 0x00, 0x1F, 0xBC, 0xD9, 0x40, 0x50, 0x05, const uint8_t buffer[] = {0x7A, 0x00, 0x1F, 0xBC, 0xD9, 0x40, 0x50, 0x05,
0xBA, 0x10, 0x00, 0x00, 0x03, 0x00, 0xC0, 0x00, 0xBA, 0x10, 0x00, 0x00, 0x03, 0x00, 0xC0, 0x00,
0x00, 0x2A, 0xE0, 0xF1, 0x83, 0x19, 0x60}; 0x00, 0x2A, 0xE0, 0xF1, 0x83, 0x19, 0x60};
absl::optional<SpsParser::SpsState> sps = absl::optional<SpsParser::SpsState> sps = SpsParser::ParseSps(buffer);
SpsParser::ParseSps(buffer, arraysize(buffer));
ASSERT_TRUE(sps.has_value()); ASSERT_TRUE(sps.has_value());
EXPECT_EQ(1280u, sps->width); EXPECT_EQ(1280u, sps->width);
EXPECT_EQ(720u, sps->height); EXPECT_EQ(720u, sps->height);
@ -129,8 +128,7 @@ TEST(H264SpsParserTest, TestSampleSPSVgaLandscape) {
const uint8_t buffer[] = {0x7A, 0x00, 0x1E, 0xBC, 0xD9, 0x40, 0xA0, 0x2F, const uint8_t buffer[] = {0x7A, 0x00, 0x1E, 0xBC, 0xD9, 0x40, 0xA0, 0x2F,
0xF8, 0x98, 0x40, 0x00, 0x00, 0x03, 0x01, 0x80, 0xF8, 0x98, 0x40, 0x00, 0x00, 0x03, 0x01, 0x80,
0x00, 0x00, 0x56, 0x83, 0xC5, 0x8B, 0x65, 0x80}; 0x00, 0x00, 0x56, 0x83, 0xC5, 0x8B, 0x65, 0x80};
absl::optional<SpsParser::SpsState> sps = absl::optional<SpsParser::SpsState> sps = SpsParser::ParseSps(buffer);
SpsParser::ParseSps(buffer, arraysize(buffer));
ASSERT_TRUE(sps.has_value()); ASSERT_TRUE(sps.has_value());
EXPECT_EQ(640u, sps->width); EXPECT_EQ(640u, sps->width);
EXPECT_EQ(360u, sps->height); EXPECT_EQ(360u, sps->height);
@ -142,8 +140,7 @@ TEST(H264SpsParserTest, TestSampleSPSWeirdResolution) {
const uint8_t buffer[] = {0x7A, 0x00, 0x0D, 0xBC, 0xD9, 0x43, 0x43, 0x3E, const uint8_t buffer[] = {0x7A, 0x00, 0x0D, 0xBC, 0xD9, 0x43, 0x43, 0x3E,
0x5E, 0x10, 0x00, 0x00, 0x03, 0x00, 0x60, 0x00, 0x5E, 0x10, 0x00, 0x00, 0x03, 0x00, 0x60, 0x00,
0x00, 0x15, 0xA0, 0xF1, 0x42, 0x99, 0x60}; 0x00, 0x15, 0xA0, 0xF1, 0x42, 0x99, 0x60};
absl::optional<SpsParser::SpsState> sps = absl::optional<SpsParser::SpsState> sps = SpsParser::ParseSps(buffer);
SpsParser::ParseSps(buffer, arraysize(buffer));
ASSERT_TRUE(sps.has_value()); ASSERT_TRUE(sps.has_value());
EXPECT_EQ(200u, sps->width); EXPECT_EQ(200u, sps->width);
EXPECT_EQ(400u, sps->height); EXPECT_EQ(400u, sps->height);
@ -152,8 +149,7 @@ TEST(H264SpsParserTest, TestSampleSPSWeirdResolution) {
TEST(H264SpsParserTest, TestSyntheticSPSQvgaLandscape) { TEST(H264SpsParserTest, TestSyntheticSPSQvgaLandscape) {
rtc::Buffer buffer; rtc::Buffer buffer;
GenerateFakeSps(320u, 180u, 1, 0, 0, &buffer); GenerateFakeSps(320u, 180u, 1, 0, 0, &buffer);
absl::optional<SpsParser::SpsState> sps = absl::optional<SpsParser::SpsState> sps = SpsParser::ParseSps(buffer);
SpsParser::ParseSps(buffer.data(), buffer.size());
ASSERT_TRUE(sps.has_value()); ASSERT_TRUE(sps.has_value());
EXPECT_EQ(320u, sps->width); EXPECT_EQ(320u, sps->width);
EXPECT_EQ(180u, sps->height); EXPECT_EQ(180u, sps->height);
@ -163,8 +159,7 @@ TEST(H264SpsParserTest, TestSyntheticSPSQvgaLandscape) {
TEST(H264SpsParserTest, TestSyntheticSPSWeirdResolution) { TEST(H264SpsParserTest, TestSyntheticSPSWeirdResolution) {
rtc::Buffer buffer; rtc::Buffer buffer;
GenerateFakeSps(156u, 122u, 2, 0, 0, &buffer); GenerateFakeSps(156u, 122u, 2, 0, 0, &buffer);
absl::optional<SpsParser::SpsState> sps = absl::optional<SpsParser::SpsState> sps = SpsParser::ParseSps(buffer);
SpsParser::ParseSps(buffer.data(), buffer.size());
ASSERT_TRUE(sps.has_value()); ASSERT_TRUE(sps.has_value());
EXPECT_EQ(156u, sps->width); EXPECT_EQ(156u, sps->width);
EXPECT_EQ(122u, sps->height); EXPECT_EQ(122u, sps->height);
@ -178,8 +173,7 @@ TEST(H264SpsParserTest, TestSampleSPSWithScalingLists) {
0x10, 0xc2, 0x00, 0x84, 0x3b, 0x50, 0x3c, 0x01, 0x10, 0xc2, 0x00, 0x84, 0x3b, 0x50, 0x3c, 0x01,
0x13, 0xf2, 0xcd, 0xc0, 0x40, 0x40, 0x50, 0x00, 0x13, 0xf2, 0xcd, 0xc0, 0x40, 0x40, 0x50, 0x00,
0x00, 0x00, 0x10, 0x00, 0x00, 0x01, 0xe8, 0x40}; 0x00, 0x00, 0x10, 0x00, 0x00, 0x01, 0xe8, 0x40};
absl::optional<SpsParser::SpsState> sps = absl::optional<SpsParser::SpsState> sps = SpsParser::ParseSps(buffer);
SpsParser::ParseSps(buffer, arraysize(buffer));
ASSERT_TRUE(sps.has_value()); ASSERT_TRUE(sps.has_value());
EXPECT_EQ(1920u, sps->width); EXPECT_EQ(1920u, sps->width);
EXPECT_EQ(1080u, sps->height); EXPECT_EQ(1080u, sps->height);
@ -188,8 +182,7 @@ TEST(H264SpsParserTest, TestSampleSPSWithScalingLists) {
TEST(H264SpsParserTest, TestLog2MaxFrameNumMinus4) { TEST(H264SpsParserTest, TestLog2MaxFrameNumMinus4) {
rtc::Buffer buffer; rtc::Buffer buffer;
GenerateFakeSps(320u, 180u, 1, 0, 0, &buffer); GenerateFakeSps(320u, 180u, 1, 0, 0, &buffer);
absl::optional<SpsParser::SpsState> sps = absl::optional<SpsParser::SpsState> sps = SpsParser::ParseSps(buffer);
SpsParser::ParseSps(buffer.data(), buffer.size());
ASSERT_TRUE(sps.has_value()); ASSERT_TRUE(sps.has_value());
EXPECT_EQ(320u, sps->width); EXPECT_EQ(320u, sps->width);
EXPECT_EQ(180u, sps->height); EXPECT_EQ(180u, sps->height);
@ -197,7 +190,7 @@ TEST(H264SpsParserTest, TestLog2MaxFrameNumMinus4) {
EXPECT_EQ(4u, sps->log2_max_frame_num); EXPECT_EQ(4u, sps->log2_max_frame_num);
GenerateFakeSps(320u, 180u, 1, 12, 0, &buffer); GenerateFakeSps(320u, 180u, 1, 12, 0, &buffer);
sps = SpsParser::ParseSps(buffer.data(), buffer.size()); sps = SpsParser::ParseSps(buffer);
ASSERT_TRUE(sps.has_value()); ASSERT_TRUE(sps.has_value());
EXPECT_EQ(320u, sps->width); EXPECT_EQ(320u, sps->width);
EXPECT_EQ(180u, sps->height); EXPECT_EQ(180u, sps->height);
@ -205,14 +198,13 @@ TEST(H264SpsParserTest, TestLog2MaxFrameNumMinus4) {
EXPECT_EQ(16u, sps->log2_max_frame_num); EXPECT_EQ(16u, sps->log2_max_frame_num);
GenerateFakeSps(320u, 180u, 1, 13, 0, &buffer); GenerateFakeSps(320u, 180u, 1, 13, 0, &buffer);
EXPECT_FALSE(SpsParser::ParseSps(buffer.data(), buffer.size())); EXPECT_FALSE(SpsParser::ParseSps(buffer));
} }
TEST(H264SpsParserTest, TestLog2MaxPicOrderCntMinus4) { TEST(H264SpsParserTest, TestLog2MaxPicOrderCntMinus4) {
rtc::Buffer buffer; rtc::Buffer buffer;
GenerateFakeSps(320u, 180u, 1, 0, 0, &buffer); GenerateFakeSps(320u, 180u, 1, 0, 0, &buffer);
absl::optional<SpsParser::SpsState> sps = absl::optional<SpsParser::SpsState> sps = SpsParser::ParseSps(buffer);
SpsParser::ParseSps(buffer.data(), buffer.size());
ASSERT_TRUE(sps.has_value()); ASSERT_TRUE(sps.has_value());
EXPECT_EQ(320u, sps->width); EXPECT_EQ(320u, sps->width);
EXPECT_EQ(180u, sps->height); EXPECT_EQ(180u, sps->height);
@ -220,15 +212,14 @@ TEST(H264SpsParserTest, TestLog2MaxPicOrderCntMinus4) {
EXPECT_EQ(4u, sps->log2_max_pic_order_cnt_lsb); EXPECT_EQ(4u, sps->log2_max_pic_order_cnt_lsb);
GenerateFakeSps(320u, 180u, 1, 0, 12, &buffer); GenerateFakeSps(320u, 180u, 1, 0, 12, &buffer);
EXPECT_TRUE(static_cast<bool>( EXPECT_TRUE(static_cast<bool>(sps = SpsParser::ParseSps(buffer)));
sps = SpsParser::ParseSps(buffer.data(), buffer.size())));
EXPECT_EQ(320u, sps->width); EXPECT_EQ(320u, sps->width);
EXPECT_EQ(180u, sps->height); EXPECT_EQ(180u, sps->height);
EXPECT_EQ(1u, sps->id); EXPECT_EQ(1u, sps->id);
EXPECT_EQ(16u, sps->log2_max_pic_order_cnt_lsb); EXPECT_EQ(16u, sps->log2_max_pic_order_cnt_lsb);
GenerateFakeSps(320u, 180u, 1, 0, 13, &buffer); GenerateFakeSps(320u, 180u, 1, 0, 13, &buffer);
EXPECT_FALSE(SpsParser::ParseSps(buffer.data(), buffer.size())); EXPECT_FALSE(SpsParser::ParseSps(buffer));
} }
} // namespace webrtc } // namespace webrtc

View File

@ -135,14 +135,13 @@ void SpsVuiRewriter::UpdateStats(ParseResult result, Direction direction) {
} }
SpsVuiRewriter::ParseResult SpsVuiRewriter::ParseAndRewriteSps( SpsVuiRewriter::ParseResult SpsVuiRewriter::ParseAndRewriteSps(
const uint8_t* buffer, rtc::ArrayView<const uint8_t> buffer,
size_t length,
absl::optional<SpsParser::SpsState>* sps, absl::optional<SpsParser::SpsState>* sps,
const webrtc::ColorSpace* color_space, const webrtc::ColorSpace* color_space,
rtc::Buffer* destination) { rtc::Buffer* destination) {
// Create temporary RBSP decoded buffer of the payload (exlcuding the // Create temporary RBSP decoded buffer of the payload (exlcuding the
// leading nalu type header byte (the SpsParser uses only the payload). // leading nalu type header byte (the SpsParser uses only the payload).
std::vector<uint8_t> rbsp_buffer = H264::ParseRbsp(buffer, length); std::vector<uint8_t> rbsp_buffer = H264::ParseRbsp(buffer);
BitstreamReader source_buffer(rbsp_buffer); BitstreamReader source_buffer(rbsp_buffer);
absl::optional<SpsParser::SpsState> sps_state = absl::optional<SpsParser::SpsState> sps_state =
SpsParser::ParseSpsUpToVui(source_buffer); SpsParser::ParseSpsUpToVui(source_buffer);
@ -153,7 +152,7 @@ SpsVuiRewriter::ParseResult SpsVuiRewriter::ParseAndRewriteSps(
// We're going to completely muck up alignment, so we need a BitBufferWriter // We're going to completely muck up alignment, so we need a BitBufferWriter
// to write with. // to write with.
rtc::Buffer out_buffer(length + kMaxVuiSpsIncrease); rtc::Buffer out_buffer(buffer.size() + kMaxVuiSpsIncrease);
rtc::BitBufferWriter sps_writer(out_buffer.data(), out_buffer.size()); rtc::BitBufferWriter sps_writer(out_buffer.data(), out_buffer.size());
// Check how far the SpsParser has read, and copy that data in bulk. // Check how far the SpsParser has read, and copy that data in bulk.
@ -200,26 +199,25 @@ SpsVuiRewriter::ParseResult SpsVuiRewriter::ParseAndRewriteSps(
bit_offset = 0; bit_offset = 0;
} }
RTC_DCHECK(byte_offset <= length + kMaxVuiSpsIncrease); RTC_DCHECK(byte_offset <= buffer.size() + kMaxVuiSpsIncrease);
RTC_CHECK(destination != nullptr); RTC_CHECK(destination != nullptr);
out_buffer.SetSize(byte_offset); out_buffer.SetSize(byte_offset);
// Write updates SPS to destination with added RBSP // Write updates SPS to destination with added RBSP
H264::WriteRbsp(out_buffer.data(), out_buffer.size(), destination); H264::WriteRbsp(out_buffer, destination);
return ParseResult::kVuiRewritten; return ParseResult::kVuiRewritten;
} }
SpsVuiRewriter::ParseResult SpsVuiRewriter::ParseAndRewriteSps( SpsVuiRewriter::ParseResult SpsVuiRewriter::ParseAndRewriteSps(
const uint8_t* buffer, rtc::ArrayView<const uint8_t> buffer,
size_t length,
absl::optional<SpsParser::SpsState>* sps, absl::optional<SpsParser::SpsState>* sps,
const webrtc::ColorSpace* color_space, const webrtc::ColorSpace* color_space,
rtc::Buffer* destination, rtc::Buffer* destination,
Direction direction) { Direction direction) {
ParseResult result = ParseResult result =
ParseAndRewriteSps(buffer, length, sps, color_space, destination); ParseAndRewriteSps(buffer, sps, color_space, destination);
UpdateStats(result, direction); UpdateStats(result, direction);
return result; return result;
} }
@ -227,22 +225,21 @@ SpsVuiRewriter::ParseResult SpsVuiRewriter::ParseAndRewriteSps(
rtc::Buffer SpsVuiRewriter::ParseOutgoingBitstreamAndRewrite( rtc::Buffer SpsVuiRewriter::ParseOutgoingBitstreamAndRewrite(
rtc::ArrayView<const uint8_t> buffer, rtc::ArrayView<const uint8_t> buffer,
const webrtc::ColorSpace* color_space) { const webrtc::ColorSpace* color_space) {
std::vector<H264::NaluIndex> nalus = std::vector<H264::NaluIndex> nalus = H264::FindNaluIndices(buffer);
H264::FindNaluIndices(buffer.data(), buffer.size());
// Allocate some extra space for potentially adding a missing VUI. // Allocate some extra space for potentially adding a missing VUI.
rtc::Buffer output_buffer(/*size=*/0, /*capacity=*/buffer.size() + rtc::Buffer output_buffer(/*size=*/0, /*capacity=*/buffer.size() +
nalus.size() * kMaxVuiSpsIncrease); nalus.size() * kMaxVuiSpsIncrease);
for (const H264::NaluIndex& nalu : nalus) { for (const H264::NaluIndex& nalu_index : nalus) {
// Copy NAL unit start code. // Copy NAL unit start code.
const uint8_t* start_code_ptr = buffer.data() + nalu.start_offset; rtc::ArrayView<const uint8_t> start_code = buffer.subview(
const size_t start_code_length = nalu_index.start_offset,
nalu.payload_start_offset - nalu.start_offset; nalu_index.payload_start_offset - nalu_index.start_offset);
const uint8_t* nalu_ptr = buffer.data() + nalu.payload_start_offset; rtc::ArrayView<const uint8_t> nalu = buffer.subview(
const size_t nalu_length = nalu.payload_size; nalu_index.payload_start_offset, nalu_index.payload_size);
if (H264::ParseNaluType(nalu_ptr[0]) == H264::NaluType::kSps) { if (H264::ParseNaluType(nalu[0]) == H264::NaluType::kSps) {
// Check if stream uses picture order count type 0, and if so rewrite it // Check if stream uses picture order count type 0, and if so rewrite it
// to enable faster decoding. Streams in that format incur additional // to enable faster decoding. Streams in that format incur additional
// delay because it allows decode order to differ from render order. // delay because it allows decode order to differ from render order.
@ -259,24 +256,24 @@ rtc::Buffer SpsVuiRewriter::ParseOutgoingBitstreamAndRewrite(
// Add the type header to the output buffer first, so that the rewriter // Add the type header to the output buffer first, so that the rewriter
// can append modified payload on top of that. // can append modified payload on top of that.
output_nalu.AppendData(nalu_ptr[0]); output_nalu.AppendData(nalu[0]);
ParseResult result = ParseAndRewriteSps( ParseResult result =
nalu_ptr + H264::kNaluTypeSize, nalu_length - H264::kNaluTypeSize, ParseAndRewriteSps(nalu.subview(H264::kNaluTypeSize), &sps,
&sps, color_space, &output_nalu, Direction::kOutgoing); color_space, &output_nalu, Direction::kOutgoing);
if (result == ParseResult::kVuiRewritten) { if (result == ParseResult::kVuiRewritten) {
output_buffer.AppendData(start_code_ptr, start_code_length); output_buffer.AppendData(start_code);
output_buffer.AppendData(output_nalu.data(), output_nalu.size()); output_buffer.AppendData(output_nalu.data(), output_nalu.size());
continue; continue;
} }
} else if (H264::ParseNaluType(nalu_ptr[0]) == H264::NaluType::kAud) { } else if (H264::ParseNaluType(nalu[0]) == H264::NaluType::kAud) {
// Skip the access unit delimiter copy. // Skip the access unit delimiter copy.
continue; continue;
} }
// vui wasn't rewritten and it is not aud, copy the nal unit as is. // vui wasn't rewritten and it is not aud, copy the nal unit as is.
output_buffer.AppendData(start_code_ptr, start_code_length); output_buffer.AppendData(start_code);
output_buffer.AppendData(nalu_ptr, nalu_length); output_buffer.AppendData(nalu);
} }
return output_buffer; return output_buffer;
} }

View File

@ -43,8 +43,7 @@ class SpsVuiRewriter : private SpsParser {
// (NALU start, type, Stap-A, etc) have already been parsed and that RBSP // (NALU start, type, Stap-A, etc) have already been parsed and that RBSP
// decoding has been performed. // decoding has been performed.
static ParseResult ParseAndRewriteSps( static ParseResult ParseAndRewriteSps(
const uint8_t* buffer, rtc::ArrayView<const uint8_t> buffer,
size_t length,
absl::optional<SpsParser::SpsState>* sps, absl::optional<SpsParser::SpsState>* sps,
const ColorSpace* color_space, const ColorSpace* color_space,
rtc::Buffer* destination, rtc::Buffer* destination,
@ -58,8 +57,7 @@ class SpsVuiRewriter : private SpsParser {
private: private:
static ParseResult ParseAndRewriteSps( static ParseResult ParseAndRewriteSps(
const uint8_t* buffer, rtc::ArrayView<const uint8_t> buffer,
size_t length,
absl::optional<SpsParser::SpsState>* sps, absl::optional<SpsParser::SpsState>* sps,
const ColorSpace* color_space, const ColorSpace* color_space,
rtc::Buffer* destination); rtc::Buffer* destination);

View File

@ -297,7 +297,7 @@ void GenerateFakeSps(const VuiHeader& vui, rtc::Buffer* out_buffer) {
byte_count++; byte_count++;
} }
H264::WriteRbsp(rbsp, byte_count, out_buffer); H264::WriteRbsp(rtc::MakeArrayView(rbsp, byte_count), out_buffer);
} }
void TestSps(const VuiHeader& vui, void TestSps(const VuiHeader& vui,
@ -310,8 +310,8 @@ void TestSps(const VuiHeader& vui,
absl::optional<SpsParser::SpsState> sps; absl::optional<SpsParser::SpsState> sps;
rtc::Buffer rewritten_sps; rtc::Buffer rewritten_sps;
SpsVuiRewriter::ParseResult result = SpsVuiRewriter::ParseAndRewriteSps( SpsVuiRewriter::ParseResult result = SpsVuiRewriter::ParseAndRewriteSps(
original_sps.data(), original_sps.size(), &sps, color_space, original_sps, &sps, color_space, &rewritten_sps,
&rewritten_sps, SpsVuiRewriter::Direction::kIncoming); SpsVuiRewriter::Direction::kIncoming);
EXPECT_EQ(expected_parse_result, result); EXPECT_EQ(expected_parse_result, result);
ASSERT_TRUE(sps); ASSERT_TRUE(sps);
EXPECT_EQ(sps->width, kWidth); EXPECT_EQ(sps->width, kWidth);
@ -324,7 +324,7 @@ void TestSps(const VuiHeader& vui,
// Ensure that added/rewritten SPS is parsable. // Ensure that added/rewritten SPS is parsable.
rtc::Buffer tmp; rtc::Buffer tmp;
result = SpsVuiRewriter::ParseAndRewriteSps( result = SpsVuiRewriter::ParseAndRewriteSps(
rewritten_sps.data(), rewritten_sps.size(), &sps, nullptr, &tmp, rewritten_sps, &sps, nullptr, &tmp,
SpsVuiRewriter::Direction::kIncoming); SpsVuiRewriter::Direction::kIncoming);
EXPECT_EQ(SpsVuiRewriter::ParseResult::kVuiOk, result); EXPECT_EQ(SpsVuiRewriter::ParseResult::kVuiOk, result);
ASSERT_TRUE(sps); ASSERT_TRUE(sps);

View File

@ -80,13 +80,11 @@ H265BitstreamParser::~H265BitstreamParser() = default;
// section 7.3.6.1. You can find it on this page: // section 7.3.6.1. You can find it on this page:
// http://www.itu.int/rec/T-REC-H.265 // http://www.itu.int/rec/T-REC-H.265
H265BitstreamParser::Result H265BitstreamParser::ParseNonParameterSetNalu( H265BitstreamParser::Result H265BitstreamParser::ParseNonParameterSetNalu(
const uint8_t* source, rtc::ArrayView<const uint8_t> source,
size_t source_length,
uint8_t nalu_type) { uint8_t nalu_type) {
last_slice_qp_delta_ = absl::nullopt; last_slice_qp_delta_ = absl::nullopt;
last_slice_pps_id_ = absl::nullopt; last_slice_pps_id_ = absl::nullopt;
const std::vector<uint8_t> slice_rbsp = const std::vector<uint8_t> slice_rbsp = H265::ParseRbsp(source);
H265::ParseRbsp(source, source_length);
if (slice_rbsp.size() < H265::kNaluHeaderSize) if (slice_rbsp.size() < H265::kNaluHeaderSize)
return kInvalidStream; return kInvalidStream;
@ -420,14 +418,14 @@ const H265SpsParser::SpsState* H265BitstreamParser::GetSPS(uint32_t id) const {
return &it->second; return &it->second;
} }
void H265BitstreamParser::ParseSlice(const uint8_t* slice, size_t length) { void H265BitstreamParser::ParseSlice(rtc::ArrayView<const uint8_t> slice) {
H265::NaluType nalu_type = H265::ParseNaluType(slice[0]); H265::NaluType nalu_type = H265::ParseNaluType(slice[0]);
switch (nalu_type) { switch (nalu_type) {
case H265::NaluType::kVps: { case H265::NaluType::kVps: {
absl::optional<H265VpsParser::VpsState> vps_state; absl::optional<H265VpsParser::VpsState> vps_state;
if (length >= H265::kNaluHeaderSize) { if (slice.size() >= H265::kNaluHeaderSize) {
vps_state = H265VpsParser::ParseVps(slice + H265::kNaluHeaderSize, vps_state =
length - H265::kNaluHeaderSize); H265VpsParser::ParseVps(slice.subview(H265::kNaluHeaderSize));
} }
if (!vps_state) { if (!vps_state) {
@ -439,9 +437,9 @@ void H265BitstreamParser::ParseSlice(const uint8_t* slice, size_t length) {
} }
case H265::NaluType::kSps: { case H265::NaluType::kSps: {
absl::optional<H265SpsParser::SpsState> sps_state; absl::optional<H265SpsParser::SpsState> sps_state;
if (length >= H265::kNaluHeaderSize) { if (slice.size() >= H265::kNaluHeaderSize) {
sps_state = H265SpsParser::ParseSps(slice + H265::kNaluHeaderSize, sps_state =
length - H265::kNaluHeaderSize); H265SpsParser::ParseSps(slice.subview(H265::kNaluHeaderSize));
} }
if (!sps_state) { if (!sps_state) {
RTC_LOG(LS_WARNING) << "Unable to parse SPS from H265 bitstream."; RTC_LOG(LS_WARNING) << "Unable to parse SPS from H265 bitstream.";
@ -452,9 +450,9 @@ void H265BitstreamParser::ParseSlice(const uint8_t* slice, size_t length) {
} }
case H265::NaluType::kPps: { case H265::NaluType::kPps: {
absl::optional<H265PpsParser::PpsState> pps_state; absl::optional<H265PpsParser::PpsState> pps_state;
if (length >= H265::kNaluHeaderSize) { if (slice.size() >= H265::kNaluHeaderSize) {
std::vector<uint8_t> unpacked_buffer = H265::ParseRbsp( std::vector<uint8_t> unpacked_buffer =
slice + H265::kNaluHeaderSize, length - H265::kNaluHeaderSize); H265::ParseRbsp(slice.subview(H265::kNaluHeaderSize));
BitstreamReader slice_reader(unpacked_buffer); BitstreamReader slice_reader(unpacked_buffer);
// pic_parameter_set_id: ue(v) // pic_parameter_set_id: ue(v)
uint32_t pps_id = slice_reader.ReadExponentialGolomb(); uint32_t pps_id = slice_reader.ReadExponentialGolomb();
@ -463,8 +461,8 @@ void H265BitstreamParser::ParseSlice(const uint8_t* slice, size_t length) {
uint32_t sps_id = slice_reader.ReadExponentialGolomb(); uint32_t sps_id = slice_reader.ReadExponentialGolomb();
IN_RANGE_OR_RETURN_VOID(sps_id, 0, 15); IN_RANGE_OR_RETURN_VOID(sps_id, 0, 15);
const H265SpsParser::SpsState* sps = GetSPS(sps_id); const H265SpsParser::SpsState* sps = GetSPS(sps_id);
pps_state = H265PpsParser::ParsePps( pps_state =
slice + H265::kNaluHeaderSize, length - H265::kNaluHeaderSize, sps); H265PpsParser::ParsePps(slice.subview(H265::kNaluHeaderSize), sps);
} }
if (!pps_state) { if (!pps_state) {
RTC_LOG(LS_WARNING) << "Unable to parse PPS from H265 bitstream."; RTC_LOG(LS_WARNING) << "Unable to parse PPS from H265 bitstream.";
@ -480,7 +478,7 @@ void H265BitstreamParser::ParseSlice(const uint8_t* slice, size_t length) {
case H265::NaluType::kFu: case H265::NaluType::kFu:
break; break;
default: default:
Result res = ParseNonParameterSetNalu(slice, length, nalu_type); Result res = ParseNonParameterSetNalu(slice, nalu_type);
if (res != kOk) { if (res != kOk) {
RTC_LOG(LS_INFO) << "Failed to parse bitstream. Error: " << res; RTC_LOG(LS_INFO) << "Failed to parse bitstream. Error: " << res;
} }
@ -489,10 +487,10 @@ void H265BitstreamParser::ParseSlice(const uint8_t* slice, size_t length) {
} }
absl::optional<uint32_t> absl::optional<uint32_t>
H265BitstreamParser::ParsePpsIdFromSliceSegmentLayerRbsp(const uint8_t* data, H265BitstreamParser::ParsePpsIdFromSliceSegmentLayerRbsp(
size_t length, rtc::ArrayView<const uint8_t> data,
uint8_t nalu_type) { uint8_t nalu_type) {
std::vector<uint8_t> unpacked_buffer = H265::ParseRbsp(data, length); std::vector<uint8_t> unpacked_buffer = H265::ParseRbsp(data);
BitstreamReader slice_reader(unpacked_buffer); BitstreamReader slice_reader(unpacked_buffer);
// first_slice_segment_in_pic_flag: u(1) // first_slice_segment_in_pic_flag: u(1)
@ -519,10 +517,10 @@ H265BitstreamParser::ParsePpsIdFromSliceSegmentLayerRbsp(const uint8_t* data,
void H265BitstreamParser::ParseBitstream( void H265BitstreamParser::ParseBitstream(
rtc::ArrayView<const uint8_t> bitstream) { rtc::ArrayView<const uint8_t> bitstream) {
std::vector<H265::NaluIndex> nalu_indices = std::vector<H265::NaluIndex> nalu_indices = H265::FindNaluIndices(bitstream);
H265::FindNaluIndices(bitstream.data(), bitstream.size());
for (const H265::NaluIndex& index : nalu_indices) for (const H265::NaluIndex& index : nalu_indices)
ParseSlice(&bitstream[index.payload_start_offset], index.payload_size); ParseSlice(
bitstream.subview(index.payload_start_offset, index.payload_size));
} }
absl::optional<int> H265BitstreamParser::GetLastSliceQp() const { absl::optional<int> H265BitstreamParser::GetLastSliceQp() const {

View File

@ -40,8 +40,7 @@ class RTC_EXPORT H265BitstreamParser : public BitstreamParser {
absl::optional<uint32_t> GetLastSlicePpsId() const; absl::optional<uint32_t> GetLastSlicePpsId() const;
static absl::optional<uint32_t> ParsePpsIdFromSliceSegmentLayerRbsp( static absl::optional<uint32_t> ParsePpsIdFromSliceSegmentLayerRbsp(
const uint8_t* data, rtc::ArrayView<const uint8_t> data,
size_t length,
uint8_t nalu_type); uint8_t nalu_type);
protected: protected:
@ -50,9 +49,8 @@ class RTC_EXPORT H265BitstreamParser : public BitstreamParser {
kInvalidStream, kInvalidStream,
kUnsupportedStream, kUnsupportedStream,
}; };
void ParseSlice(const uint8_t* slice, size_t length); void ParseSlice(rtc::ArrayView<const uint8_t> slice);
Result ParseNonParameterSetNalu(const uint8_t* source, Result ParseNonParameterSetNalu(rtc::ArrayView<const uint8_t> source,
size_t source_length,
uint8_t nalu_type); uint8_t nalu_type);
const H265PpsParser::PpsState* GetPPS(uint32_t id) const; const H265PpsParser::PpsState* GetPPS(uint32_t id) const;

View File

@ -127,8 +127,8 @@ TEST(H265BitstreamParserTest, ReportsLastSliceQpFromShortTermReferenceSlices) {
TEST(H265BitstreamParserTest, PpsIdFromSlice) { TEST(H265BitstreamParserTest, PpsIdFromSlice) {
H265BitstreamParser h265_parser; H265BitstreamParser h265_parser;
absl::optional<uint32_t> pps_id = absl::optional<uint32_t> pps_id =
h265_parser.ParsePpsIdFromSliceSegmentLayerRbsp( h265_parser.ParsePpsIdFromSliceSegmentLayerRbsp(kH265SliceChunk,
kH265SliceChunk, sizeof(kH265SliceChunk), H265::NaluType::kTrailR); H265::NaluType::kTrailR);
ASSERT_TRUE(pps_id); ASSERT_TRUE(pps_id);
EXPECT_EQ(1u, *pps_id); EXPECT_EQ(1u, *pps_id);
} }

View File

@ -17,10 +17,8 @@ namespace H265 {
constexpr uint8_t kNaluTypeMask = 0x7E; constexpr uint8_t kNaluTypeMask = 0x7E;
std::vector<NaluIndex> FindNaluIndices(const uint8_t* buffer, std::vector<NaluIndex> FindNaluIndices(rtc::ArrayView<const uint8_t> buffer) {
size_t buffer_size) { std::vector<H264::NaluIndex> indices = H264::FindNaluIndices(buffer);
std::vector<H264::NaluIndex> indices =
H264::FindNaluIndices(buffer, buffer_size);
std::vector<NaluIndex> results; std::vector<NaluIndex> results;
for (auto& index : indices) { for (auto& index : indices) {
results.push_back( results.push_back(
@ -33,12 +31,12 @@ NaluType ParseNaluType(uint8_t data) {
return static_cast<NaluType>((data & kNaluTypeMask) >> 1); return static_cast<NaluType>((data & kNaluTypeMask) >> 1);
} }
std::vector<uint8_t> ParseRbsp(const uint8_t* data, size_t length) { std::vector<uint8_t> ParseRbsp(rtc::ArrayView<const uint8_t> data) {
return H264::ParseRbsp(data, length); return H264::ParseRbsp(data);
} }
void WriteRbsp(const uint8_t* bytes, size_t length, rtc::Buffer* destination) { void WriteRbsp(rtc::ArrayView<const uint8_t> bytes, rtc::Buffer* destination) {
H264::WriteRbsp(bytes, length, destination); H264::WriteRbsp(bytes, destination);
} }
uint32_t Log2Ceiling(uint32_t value) { uint32_t Log2Ceiling(uint32_t value) {

View File

@ -77,8 +77,14 @@ struct NaluIndex {
}; };
// Returns a vector of the NALU indices in the given buffer. // Returns a vector of the NALU indices in the given buffer.
RTC_EXPORT std::vector<NaluIndex> FindNaluIndices(const uint8_t* buffer, RTC_EXPORT std::vector<NaluIndex> FindNaluIndices(
size_t buffer_size); rtc::ArrayView<const uint8_t> buffer);
// TODO: bugs.webrtc.org/42225170 - Deprecate.
inline std::vector<NaluIndex> FindNaluIndices(const uint8_t* buffer,
size_t buffer_size) {
return FindNaluIndices(rtc::MakeArrayView(buffer, buffer_size));
}
// Get the NAL type from the header byte immediately following start sequence. // Get the NAL type from the header byte immediately following start sequence.
RTC_EXPORT NaluType ParseNaluType(uint8_t data); RTC_EXPORT NaluType ParseNaluType(uint8_t data);
@ -97,12 +103,24 @@ RTC_EXPORT NaluType ParseNaluType(uint8_t data);
// the 03 emulation byte. // the 03 emulation byte.
// Parse the given data and remove any emulation byte escaping. // Parse the given data and remove any emulation byte escaping.
std::vector<uint8_t> ParseRbsp(const uint8_t* data, size_t length); std::vector<uint8_t> ParseRbsp(rtc::ArrayView<const uint8_t> data);
// TODO: bugs.webrtc.org/42225170 - Deprecate.
inline std::vector<uint8_t> ParseRbsp(const uint8_t* data, size_t length) {
return ParseRbsp(rtc::MakeArrayView(data, length));
}
// Write the given data to the destination buffer, inserting and emulation // Write the given data to the destination buffer, inserting and emulation
// bytes in order to escape any data the could be interpreted as a start // bytes in order to escape any data the could be interpreted as a start
// sequence. // sequence.
void WriteRbsp(const uint8_t* bytes, size_t length, rtc::Buffer* destination); void WriteRbsp(rtc::ArrayView<const uint8_t> bytes, rtc::Buffer* destination);
// TODO: bugs.webrtc.org/42225170 - Deprecate.
inline void WriteRbsp(const uint8_t* bytes,
size_t length,
rtc::Buffer* destination) {
WriteRbsp(rtc::MakeArrayView(bytes, length), destination);
}
uint32_t Log2Ceiling(uint32_t value); uint32_t Log2Ceiling(uint32_t value);

View File

@ -63,17 +63,15 @@ namespace webrtc {
// http://www.itu.int/rec/T-REC-H.265 // http://www.itu.int/rec/T-REC-H.265
absl::optional<H265PpsParser::PpsState> H265PpsParser::ParsePps( absl::optional<H265PpsParser::PpsState> H265PpsParser::ParsePps(
const uint8_t* data, rtc::ArrayView<const uint8_t> data,
size_t length,
const H265SpsParser::SpsState* sps) { const H265SpsParser::SpsState* sps) {
// First, parse out rbsp, which is basically the source buffer minus emulation // First, parse out rbsp, which is basically the source buffer minus emulation
// bytes (the last byte of a 0x00 0x00 0x03 sequence). RBSP is defined in // bytes (the last byte of a 0x00 0x00 0x03 sequence). RBSP is defined in
// section 7.3.1.1 of the H.265 standard. // section 7.3.1.1 of the H.265 standard.
return ParseInternal(H265::ParseRbsp(data, length), sps); return ParseInternal(H265::ParseRbsp(data), sps);
} }
bool H265PpsParser::ParsePpsIds(const uint8_t* data, bool H265PpsParser::ParsePpsIds(rtc::ArrayView<const uint8_t> data,
size_t length,
uint32_t* pps_id, uint32_t* pps_id,
uint32_t* sps_id) { uint32_t* sps_id) {
RTC_DCHECK(pps_id); RTC_DCHECK(pps_id);
@ -81,7 +79,7 @@ bool H265PpsParser::ParsePpsIds(const uint8_t* data,
// First, parse out rbsp, which is basically the source buffer minus emulation // First, parse out rbsp, which is basically the source buffer minus emulation
// bytes (the last byte of a 0x00 0x00 0x03 sequence). RBSP is defined in // bytes (the last byte of a 0x00 0x00 0x03 sequence). RBSP is defined in
// section 7.3.1.1 of the H.265 standard. // section 7.3.1.1 of the H.265 standard.
std::vector<uint8_t> unpacked_buffer = H265::ParseRbsp(data, length); std::vector<uint8_t> unpacked_buffer = H265::ParseRbsp(data);
BitstreamReader reader(unpacked_buffer); BitstreamReader reader(unpacked_buffer);
*pps_id = reader.ReadExponentialGolomb(); *pps_id = reader.ReadExponentialGolomb();
IN_RANGE_OR_RETURN_FALSE(*pps_id, 0, 63); IN_RANGE_OR_RETURN_FALSE(*pps_id, 0, 63);

View File

@ -43,14 +43,26 @@ class RTC_EXPORT H265PpsParser {
}; };
// Unpack RBSP and parse PPS state from the supplied buffer. // Unpack RBSP and parse PPS state from the supplied buffer.
static absl::optional<PpsState> ParsePps(const uint8_t* data, static absl::optional<PpsState> ParsePps(rtc::ArrayView<const uint8_t> data,
size_t length,
const H265SpsParser::SpsState* sps); const H265SpsParser::SpsState* sps);
// TODO: bugs.webrtc.org/42225170 - Deprecate.
static bool ParsePpsIds(const uint8_t* data, static inline absl::optional<PpsState> ParsePps(
const uint8_t* data,
size_t length, size_t length,
const H265SpsParser::SpsState* sps) {
return ParsePps(rtc::MakeArrayView(data, length), sps);
}
static bool ParsePpsIds(rtc::ArrayView<const uint8_t> data,
uint32_t* pps_id, uint32_t* pps_id,
uint32_t* sps_id); uint32_t* sps_id);
// TODO: bugs.webrtc.org/42225170 - Deprecate.
static inline bool ParsePpsIds(const uint8_t* data,
size_t length,
uint32_t* pps_id,
uint32_t* sps_id) {
return ParsePpsIds(rtc::MakeArrayView(data, length), pps_id, sps_id);
}
protected: protected:
// Parse the PPS state, for a bit buffer where RBSP decoding has already been // Parse the PPS state, for a bit buffer where RBSP decoding has already been

View File

@ -161,7 +161,7 @@ void WritePps(const H265PpsParser::PpsState& pps,
bit_buffer.GetCurrentOffset(&byte_offset, &bit_offset); bit_buffer.GetCurrentOffset(&byte_offset, &bit_offset);
} }
H265::WriteRbsp(data, byte_offset, out_buffer); H265::WriteRbsp(rtc::MakeArrayView(data, byte_offset), out_buffer);
} }
class H265PpsParserTest : public ::testing::Test { class H265PpsParserTest : public ::testing::Test {
@ -196,9 +196,8 @@ class H265PpsParserTest : public ::testing::Test {
0x16, 0x59, 0x59, 0xa4, 0x93, 0x2b, 0x80, 0x40, 0x00, 0x00, 0x16, 0x59, 0x59, 0xa4, 0x93, 0x2b, 0x80, 0x40, 0x00, 0x00,
0x03, 0x00, 0x40, 0x00, 0x00, 0x07, 0x82}; 0x03, 0x00, 0x40, 0x00, 0x00, 0x07, 0x82};
H265SpsParser::SpsState parsed_sps = H265SpsParser::SpsState parsed_sps =
H265SpsParser::ParseSps(sps_buffer, arraysize(sps_buffer)).value(); H265SpsParser::ParseSps(sps_buffer).value();
parsed_pps_ = parsed_pps_ = H265PpsParser::ParsePps(buffer_, &parsed_sps);
H265PpsParser::ParsePps(buffer_.data(), buffer_.size(), &parsed_sps);
ASSERT_TRUE(parsed_pps_); ASSERT_TRUE(parsed_pps_);
EXPECT_EQ(pps.dependent_slice_segments_enabled_flag, EXPECT_EQ(pps.dependent_slice_segments_enabled_flag,
parsed_pps_->dependent_slice_segments_enabled_flag); parsed_pps_->dependent_slice_segments_enabled_flag);

View File

@ -104,10 +104,8 @@ size_t H265SpsParser::GetDpbMaxPicBuf(int general_profile_idc) {
// Unpack RBSP and parse SPS state from the supplied buffer. // Unpack RBSP and parse SPS state from the supplied buffer.
absl::optional<H265SpsParser::SpsState> H265SpsParser::ParseSps( absl::optional<H265SpsParser::SpsState> H265SpsParser::ParseSps(
const uint8_t* data, rtc::ArrayView<const uint8_t> data) {
size_t length) { return ParseSpsInternal(H265::ParseRbsp(data));
RTC_DCHECK(data);
return ParseSpsInternal(H265::ParseRbsp(data, length));
} }
bool H265SpsParser::ParseScalingListData(BitstreamReader& reader) { bool H265SpsParser::ParseScalingListData(BitstreamReader& reader) {

View File

@ -104,7 +104,12 @@ class RTC_EXPORT H265SpsParser {
}; };
// Unpack RBSP and parse SPS state from the supplied buffer. // Unpack RBSP and parse SPS state from the supplied buffer.
static absl::optional<SpsState> ParseSps(const uint8_t* data, size_t length); static absl::optional<SpsState> ParseSps(rtc::ArrayView<const uint8_t> data);
// TODO: bugs.webrtc.org/42225170 - Deprecate.
static inline absl::optional<SpsState> ParseSps(const uint8_t* data,
size_t length) {
return ParseSps(rtc::MakeArrayView(data, length));
}
static bool ParseScalingListData(BitstreamReader& reader); static bool ParseScalingListData(BitstreamReader& reader);

View File

@ -365,7 +365,7 @@ void WriteSps(uint16_t width,
} }
out_buffer->Clear(); out_buffer->Clear();
H265::WriteRbsp(rbsp, byte_count, out_buffer); H265::WriteRbsp(rtc::MakeArrayView(rbsp, byte_count), out_buffer);
} }
class H265SpsParserTest : public ::testing::Test { class H265SpsParserTest : public ::testing::Test {
@ -389,8 +389,7 @@ TEST_F(H265SpsParserTest, TestSampleSPSHdLandscape) {
0x02, 0x80, 0x80, 0x2d, 0x16, 0x59, 0x59, 0xa4, 0x02, 0x80, 0x80, 0x2d, 0x16, 0x59, 0x59, 0xa4,
0x93, 0x2b, 0x80, 0x40, 0x00, 0x00, 0x03, 0x00, 0x93, 0x2b, 0x80, 0x40, 0x00, 0x00, 0x03, 0x00,
0x40, 0x00, 0x00, 0x07, 0x82}; 0x40, 0x00, 0x00, 0x07, 0x82};
absl::optional<H265SpsParser::SpsState> sps = absl::optional<H265SpsParser::SpsState> sps = H265SpsParser::ParseSps(buffer);
H265SpsParser::ParseSps(buffer, arraysize(buffer));
ASSERT_TRUE(sps.has_value()); ASSERT_TRUE(sps.has_value());
EXPECT_EQ(1280u, sps->width); EXPECT_EQ(1280u, sps->width);
EXPECT_EQ(720u, sps->height); EXPECT_EQ(720u, sps->height);
@ -418,8 +417,7 @@ TEST_F(H265SpsParserTest, TestSampleSPSVerticalCropLandscape) {
0x05, 0x02, 0x01, 0x09, 0xf2, 0xe5, 0x95, 0x9a, 0x05, 0x02, 0x01, 0x09, 0xf2, 0xe5, 0x95, 0x9a,
0x49, 0x32, 0xb8, 0x04, 0x00, 0x00, 0x03, 0x00, 0x49, 0x32, 0xb8, 0x04, 0x00, 0x00, 0x03, 0x00,
0x04, 0x00, 0x00, 0x03, 0x00, 0x78, 0x20}; 0x04, 0x00, 0x00, 0x03, 0x00, 0x78, 0x20};
absl::optional<H265SpsParser::SpsState> sps = absl::optional<H265SpsParser::SpsState> sps = H265SpsParser::ParseSps(buffer);
H265SpsParser::ParseSps(buffer, arraysize(buffer));
ASSERT_TRUE(sps.has_value()); ASSERT_TRUE(sps.has_value());
EXPECT_EQ(640u, sps->width); EXPECT_EQ(640u, sps->width);
EXPECT_EQ(260u, sps->height); EXPECT_EQ(260u, sps->height);
@ -446,8 +444,7 @@ TEST_F(H265SpsParserTest, TestSampleSPSHorizontalAndVerticalCrop) {
0x08, 0x48, 0x04, 0x27, 0x72, 0xe5, 0x95, 0x9a, 0x08, 0x48, 0x04, 0x27, 0x72, 0xe5, 0x95, 0x9a,
0x49, 0x32, 0xb8, 0x04, 0x00, 0x00, 0x03, 0x00, 0x49, 0x32, 0xb8, 0x04, 0x00, 0x00, 0x03, 0x00,
0x04, 0x00, 0x00, 0x03, 0x00, 0x78, 0x20}; 0x04, 0x00, 0x00, 0x03, 0x00, 0x78, 0x20};
absl::optional<H265SpsParser::SpsState> sps = absl::optional<H265SpsParser::SpsState> sps = H265SpsParser::ParseSps(buffer);
H265SpsParser::ParseSps(buffer, arraysize(buffer));
ASSERT_TRUE(sps.has_value()); ASSERT_TRUE(sps.has_value());
EXPECT_EQ(260u, sps->width); EXPECT_EQ(260u, sps->width);
EXPECT_EQ(260u, sps->height); EXPECT_EQ(260u, sps->height);
@ -456,8 +453,7 @@ TEST_F(H265SpsParserTest, TestSampleSPSHorizontalAndVerticalCrop) {
TEST_F(H265SpsParserTest, TestSyntheticSPSQvgaLandscape) { TEST_F(H265SpsParserTest, TestSyntheticSPSQvgaLandscape) {
rtc::Buffer buffer; rtc::Buffer buffer;
WriteSps(320u, 180u, 1, 0, 1, 0, &buffer); WriteSps(320u, 180u, 1, 0, 1, 0, &buffer);
absl::optional<H265SpsParser::SpsState> sps = absl::optional<H265SpsParser::SpsState> sps = H265SpsParser::ParseSps(buffer);
H265SpsParser::ParseSps(buffer.data(), buffer.size());
ASSERT_TRUE(sps.has_value()); ASSERT_TRUE(sps.has_value());
EXPECT_EQ(320u, sps->width); EXPECT_EQ(320u, sps->width);
EXPECT_EQ(180u, sps->height); EXPECT_EQ(180u, sps->height);
@ -467,8 +463,7 @@ TEST_F(H265SpsParserTest, TestSyntheticSPSQvgaLandscape) {
TEST_F(H265SpsParserTest, TestSyntheticSPSWeirdResolution) { TEST_F(H265SpsParserTest, TestSyntheticSPSWeirdResolution) {
rtc::Buffer buffer; rtc::Buffer buffer;
WriteSps(156u, 122u, 2, 0, 1, 0, &buffer); WriteSps(156u, 122u, 2, 0, 1, 0, &buffer);
absl::optional<H265SpsParser::SpsState> sps = absl::optional<H265SpsParser::SpsState> sps = H265SpsParser::ParseSps(buffer);
H265SpsParser::ParseSps(buffer.data(), buffer.size());
ASSERT_TRUE(sps.has_value()); ASSERT_TRUE(sps.has_value());
EXPECT_EQ(156u, sps->width); EXPECT_EQ(156u, sps->width);
EXPECT_EQ(122u, sps->height); EXPECT_EQ(122u, sps->height);
@ -478,8 +473,7 @@ TEST_F(H265SpsParserTest, TestSyntheticSPSWeirdResolution) {
TEST_F(H265SpsParserTest, TestLog2MaxSubLayersMinus1) { TEST_F(H265SpsParserTest, TestLog2MaxSubLayersMinus1) {
rtc::Buffer buffer; rtc::Buffer buffer;
WriteSps(320u, 180u, 1, 0, 1, 0, &buffer); WriteSps(320u, 180u, 1, 0, 1, 0, &buffer);
absl::optional<H265SpsParser::SpsState> sps = absl::optional<H265SpsParser::SpsState> sps = H265SpsParser::ParseSps(buffer);
H265SpsParser::ParseSps(buffer.data(), buffer.size());
ASSERT_TRUE(sps.has_value()); ASSERT_TRUE(sps.has_value());
EXPECT_EQ(320u, sps->width); EXPECT_EQ(320u, sps->width);
EXPECT_EQ(180u, sps->height); EXPECT_EQ(180u, sps->height);
@ -488,7 +482,7 @@ TEST_F(H265SpsParserTest, TestLog2MaxSubLayersMinus1) {
WriteSps(320u, 180u, 1, 6, 1, 0, &buffer); WriteSps(320u, 180u, 1, 6, 1, 0, &buffer);
absl::optional<H265SpsParser::SpsState> sps1 = absl::optional<H265SpsParser::SpsState> sps1 =
H265SpsParser::ParseSps(buffer.data(), buffer.size()); H265SpsParser::ParseSps(buffer);
ASSERT_TRUE(sps1.has_value()); ASSERT_TRUE(sps1.has_value());
EXPECT_EQ(320u, sps1->width); EXPECT_EQ(320u, sps1->width);
EXPECT_EQ(180u, sps1->height); EXPECT_EQ(180u, sps1->height);
@ -497,15 +491,14 @@ TEST_F(H265SpsParserTest, TestLog2MaxSubLayersMinus1) {
WriteSps(320u, 180u, 1, 7, 1, 0, &buffer); WriteSps(320u, 180u, 1, 7, 1, 0, &buffer);
absl::optional<H265SpsParser::SpsState> result = absl::optional<H265SpsParser::SpsState> result =
H265SpsParser::ParseSps(buffer.data(), buffer.size()); H265SpsParser::ParseSps(buffer);
EXPECT_FALSE(result.has_value()); EXPECT_FALSE(result.has_value());
} }
TEST_F(H265SpsParserTest, TestSubLayerOrderingInfoPresentFlag) { TEST_F(H265SpsParserTest, TestSubLayerOrderingInfoPresentFlag) {
rtc::Buffer buffer; rtc::Buffer buffer;
WriteSps(320u, 180u, 1, 6, 1, 0, &buffer); WriteSps(320u, 180u, 1, 6, 1, 0, &buffer);
absl::optional<H265SpsParser::SpsState> sps = absl::optional<H265SpsParser::SpsState> sps = H265SpsParser::ParseSps(buffer);
H265SpsParser::ParseSps(buffer.data(), buffer.size());
ASSERT_TRUE(sps.has_value()); ASSERT_TRUE(sps.has_value());
EXPECT_EQ(320u, sps->width); EXPECT_EQ(320u, sps->width);
EXPECT_EQ(180u, sps->height); EXPECT_EQ(180u, sps->height);
@ -514,7 +507,7 @@ TEST_F(H265SpsParserTest, TestSubLayerOrderingInfoPresentFlag) {
WriteSps(320u, 180u, 1, 6, 1, 0, &buffer); WriteSps(320u, 180u, 1, 6, 1, 0, &buffer);
absl::optional<H265SpsParser::SpsState> sps1 = absl::optional<H265SpsParser::SpsState> sps1 =
H265SpsParser::ParseSps(buffer.data(), buffer.size()); H265SpsParser::ParseSps(buffer);
ASSERT_TRUE(sps1.has_value()); ASSERT_TRUE(sps1.has_value());
EXPECT_EQ(320u, sps1->width); EXPECT_EQ(320u, sps1->width);
EXPECT_EQ(180u, sps1->height); EXPECT_EQ(180u, sps1->height);
@ -525,8 +518,7 @@ TEST_F(H265SpsParserTest, TestSubLayerOrderingInfoPresentFlag) {
TEST_F(H265SpsParserTest, TestLongTermRefPicsPresentFlag) { TEST_F(H265SpsParserTest, TestLongTermRefPicsPresentFlag) {
rtc::Buffer buffer; rtc::Buffer buffer;
WriteSps(320u, 180u, 1, 0, 1, 0, &buffer); WriteSps(320u, 180u, 1, 0, 1, 0, &buffer);
absl::optional<H265SpsParser::SpsState> sps = absl::optional<H265SpsParser::SpsState> sps = H265SpsParser::ParseSps(buffer);
H265SpsParser::ParseSps(buffer.data(), buffer.size());
ASSERT_TRUE(sps.has_value()); ASSERT_TRUE(sps.has_value());
EXPECT_EQ(320u, sps->width); EXPECT_EQ(320u, sps->width);
EXPECT_EQ(180u, sps->height); EXPECT_EQ(180u, sps->height);
@ -535,7 +527,7 @@ TEST_F(H265SpsParserTest, TestLongTermRefPicsPresentFlag) {
WriteSps(320u, 180u, 1, 6, 1, 1, &buffer); WriteSps(320u, 180u, 1, 6, 1, 1, &buffer);
absl::optional<H265SpsParser::SpsState> sps1 = absl::optional<H265SpsParser::SpsState> sps1 =
H265SpsParser::ParseSps(buffer.data(), buffer.size()); H265SpsParser::ParseSps(buffer);
ASSERT_TRUE(sps1.has_value()); ASSERT_TRUE(sps1.has_value());
EXPECT_EQ(320u, sps1->width); EXPECT_EQ(320u, sps1->width);
EXPECT_EQ(180u, sps1->height); EXPECT_EQ(180u, sps1->height);

View File

@ -25,10 +25,8 @@ H265VpsParser::VpsState::VpsState() = default;
// Unpack RBSP and parse VPS state from the supplied buffer. // Unpack RBSP and parse VPS state from the supplied buffer.
absl::optional<H265VpsParser::VpsState> H265VpsParser::ParseVps( absl::optional<H265VpsParser::VpsState> H265VpsParser::ParseVps(
const uint8_t* data, rtc::ArrayView<const uint8_t> data) {
size_t length) { return ParseInternal(H265::ParseRbsp(data));
RTC_DCHECK(data);
return ParseInternal(H265::ParseRbsp(data, length));
} }
absl::optional<H265VpsParser::VpsState> H265VpsParser::ParseInternal( absl::optional<H265VpsParser::VpsState> H265VpsParser::ParseInternal(

View File

@ -29,7 +29,12 @@ class RTC_EXPORT H265VpsParser {
}; };
// Unpack RBSP and parse VPS state from the supplied buffer. // Unpack RBSP and parse VPS state from the supplied buffer.
static absl::optional<VpsState> ParseVps(const uint8_t* data, size_t length); static absl::optional<VpsState> ParseVps(rtc::ArrayView<const uint8_t> data);
// TODO: bugs.webrtc.org/42225170 - Deprecate.
static inline absl::optional<VpsState> ParseVps(const uint8_t* data,
size_t length) {
return ParseVps(rtc::MakeArrayView(data, length));
}
protected: protected:
// Parse the VPS state, for a bit buffer where RBSP decoding has already been // Parse the VPS state, for a bit buffer where RBSP decoding has already been

View File

@ -41,8 +41,7 @@ TEST_F(H265VpsParserTest, TestSampleVPSId) {
0x1c, 0x01, 0xff, 0xff, 0x04, 0x08, 0x00, 0x00, 0x03, 0x00, 0x9d, 0x1c, 0x01, 0xff, 0xff, 0x04, 0x08, 0x00, 0x00, 0x03, 0x00, 0x9d,
0x08, 0x00, 0x00, 0x03, 0x00, 0x00, 0x78, 0x95, 0x98, 0x09, 0x08, 0x00, 0x00, 0x03, 0x00, 0x00, 0x78, 0x95, 0x98, 0x09,
}; };
EXPECT_TRUE(static_cast<bool>( EXPECT_TRUE(static_cast<bool>(vps_ = H265VpsParser::ParseVps(buffer)));
vps_ = H265VpsParser::ParseVps(buffer, arraysize(buffer))));
EXPECT_EQ(1u, vps_->id); EXPECT_EQ(1u, vps_->id);
} }

View File

@ -48,8 +48,7 @@ RtpPacketizerH264::RtpPacketizerH264(rtc::ArrayView<const uint8_t> payload,
RTC_CHECK(packetization_mode == H264PacketizationMode::NonInterleaved || RTC_CHECK(packetization_mode == H264PacketizationMode::NonInterleaved ||
packetization_mode == H264PacketizationMode::SingleNalUnit); packetization_mode == H264PacketizationMode::SingleNalUnit);
for (const auto& nalu : for (const auto& nalu : H264::FindNaluIndices(payload)) {
H264::FindNaluIndices(payload.data(), payload.size())) {
input_fragments_.push_back( input_fragments_.push_back(
payload.subview(nalu.payload_start_offset, nalu.payload_size)); payload.subview(nalu.payload_start_offset, nalu.payload_size));
} }

View File

@ -24,8 +24,7 @@ namespace webrtc {
RtpPacketizerH265::RtpPacketizerH265(rtc::ArrayView<const uint8_t> payload, RtpPacketizerH265::RtpPacketizerH265(rtc::ArrayView<const uint8_t> payload,
PayloadSizeLimits limits) PayloadSizeLimits limits)
: limits_(limits), num_packets_left_(0) { : limits_(limits), num_packets_left_(0) {
for (const auto& nalu : for (const auto& nalu : H264::FindNaluIndices(payload)) {
H264::FindNaluIndices(payload.data(), payload.size())) {
if (!nalu.payload_size) { if (!nalu.payload_size) {
input_fragments_.clear(); input_fragments_.clear();
return; return;

View File

@ -116,7 +116,8 @@ absl::optional<VideoRtpDepacketizer::ParsedRtpPayload> ProcessStapAOrSingleNalu(
nalu.sps_id = -1; nalu.sps_id = -1;
nalu.pps_id = -1; nalu.pps_id = -1;
start_offset += H264::kNaluTypeSize; start_offset += H264::kNaluTypeSize;
rtc::ArrayView<const uint8_t> nalu_data(&payload_data[start_offset],
end_offset - start_offset);
switch (nalu.type) { switch (nalu.type) {
case H264::NaluType::kSps: { case H264::NaluType::kSps: {
// Check if VUI is present in SPS and if it needs to be modified to // Check if VUI is present in SPS and if it needs to be modified to
@ -131,8 +132,8 @@ absl::optional<VideoRtpDepacketizer::ParsedRtpPayload> ProcessStapAOrSingleNalu(
absl::optional<SpsParser::SpsState> sps; absl::optional<SpsParser::SpsState> sps;
SpsVuiRewriter::ParseResult result = SpsVuiRewriter::ParseAndRewriteSps( SpsVuiRewriter::ParseResult result = SpsVuiRewriter::ParseAndRewriteSps(
&payload_data[start_offset], end_offset - start_offset, &sps, nalu_data, &sps, nullptr, &output_buffer,
nullptr, &output_buffer, SpsVuiRewriter::Direction::kIncoming); SpsVuiRewriter::Direction::kIncoming);
switch (result) { switch (result) {
case SpsVuiRewriter::ParseResult::kFailure: case SpsVuiRewriter::ParseResult::kFailure:
RTC_LOG(LS_WARNING) << "Failed to parse SPS NAL unit."; RTC_LOG(LS_WARNING) << "Failed to parse SPS NAL unit.";
@ -179,9 +180,7 @@ absl::optional<VideoRtpDepacketizer::ParsedRtpPayload> ProcessStapAOrSingleNalu(
case H264::NaluType::kPps: { case H264::NaluType::kPps: {
uint32_t pps_id; uint32_t pps_id;
uint32_t sps_id; uint32_t sps_id;
if (PpsParser::ParsePpsIds(&payload_data[start_offset], if (PpsParser::ParsePpsIds(nalu_data, &pps_id, &sps_id)) {
end_offset - start_offset, &pps_id,
&sps_id)) {
nalu.pps_id = pps_id; nalu.pps_id = pps_id;
nalu.sps_id = sps_id; nalu.sps_id = sps_id;
} else { } else {
@ -197,8 +196,7 @@ absl::optional<VideoRtpDepacketizer::ParsedRtpPayload> ProcessStapAOrSingleNalu(
[[fallthrough]]; [[fallthrough]];
case H264::NaluType::kSlice: { case H264::NaluType::kSlice: {
absl::optional<PpsParser::SliceHeader> slice_header = absl::optional<PpsParser::SliceHeader> slice_header =
PpsParser::ParseSliceHeader(&payload_data[start_offset], PpsParser::ParseSliceHeader(nalu_data);
end_offset - start_offset);
if (slice_header) { if (slice_header) {
nalu.pps_id = slice_header->pic_parameter_set_id; nalu.pps_id = slice_header->pic_parameter_set_id;
parsed_payload->video_header.is_first_packet_in_frame &= parsed_payload->video_header.is_first_packet_in_frame &=
@ -249,8 +247,8 @@ absl::optional<VideoRtpDepacketizer::ParsedRtpPayload> ParseFuaNalu(
if (original_nal_type == H264::NaluType::kIdr || if (original_nal_type == H264::NaluType::kIdr ||
original_nal_type == H264::NaluType::kSlice) { original_nal_type == H264::NaluType::kSlice) {
absl::optional<PpsParser::SliceHeader> slice_header = absl::optional<PpsParser::SliceHeader> slice_header =
PpsParser::ParseSliceHeader(rtp_payload.cdata() + 2 * kNalHeaderSize, PpsParser::ParseSliceHeader(rtc::ArrayView<const uint8_t>(rtp_payload)
rtp_payload.size() - 2 * kNalHeaderSize); .subview(2 * kNalHeaderSize));
if (slice_header) { if (slice_header) {
nalu.pps_id = slice_header->pic_parameter_set_id; nalu.pps_id = slice_header->pic_parameter_set_id;
is_first_packet_in_frame = slice_header->first_mb_in_slice == 0; is_first_packet_in_frame = slice_header->first_mb_in_slice == 0;

View File

@ -120,6 +120,8 @@ absl::optional<VideoRtpDepacketizer::ParsedRtpPayload> ProcessApOrSingleNalu(
uint8_t nalu_type = (payload_data[start_offset] & kH265TypeMask) >> 1; uint8_t nalu_type = (payload_data[start_offset] & kH265TypeMask) >> 1;
start_offset += kH265NalHeaderSizeBytes; start_offset += kH265NalHeaderSizeBytes;
rtc::ArrayView<const uint8_t> nalu_data(&payload_data[start_offset],
end_offset - start_offset);
switch (nalu_type) { switch (nalu_type) {
case H265::NaluType::kBlaWLp: case H265::NaluType::kBlaWLp:
case H265::NaluType::kBlaWRadl: case H265::NaluType::kBlaWRadl:
@ -141,8 +143,8 @@ absl::optional<VideoRtpDepacketizer::ParsedRtpPayload> ProcessApOrSingleNalu(
if (start_offset) if (start_offset)
output_buffer->AppendData(payload_data, start_offset); output_buffer->AppendData(payload_data, start_offset);
absl::optional<H265SpsParser::SpsState> sps = H265SpsParser::ParseSps( absl::optional<H265SpsParser::SpsState> sps =
&payload_data[start_offset], end_offset - start_offset); H265SpsParser::ParseSps(nalu_data);
if (sps) { if (sps) {
// TODO(bugs.webrtc.org/13485): Implement the size calculation taking // TODO(bugs.webrtc.org/13485): Implement the size calculation taking

View File

@ -381,7 +381,7 @@ void VideoCodecTestFixtureImpl::H264KeyframeChecker::CheckEncodedFrame(
bool contains_pps = false; bool contains_pps = false;
bool contains_idr = false; bool contains_idr = false;
const std::vector<webrtc::H264::NaluIndex> nalu_indices = const std::vector<webrtc::H264::NaluIndex> nalu_indices =
webrtc::H264::FindNaluIndices(encoded_frame.data(), encoded_frame.size()); webrtc::H264::FindNaluIndices(encoded_frame);
for (const webrtc::H264::NaluIndex& index : nalu_indices) { for (const webrtc::H264::NaluIndex& index : nalu_indices) {
webrtc::H264::NaluType nalu_type = webrtc::H264::ParseNaluType( webrtc::H264::NaluType nalu_type = webrtc::H264::ParseNaluType(
encoded_frame.data()[index.payload_start_offset]); encoded_frame.data()[index.payload_start_offset]);

View File

@ -52,7 +52,7 @@ size_t GetMaxNaluSizeBytes(const EncodedImage& encoded_frame,
return 0; return 0;
std::vector<webrtc::H264::NaluIndex> nalu_indices = std::vector<webrtc::H264::NaluIndex> nalu_indices =
webrtc::H264::FindNaluIndices(encoded_frame.data(), encoded_frame.size()); webrtc::H264::FindNaluIndices(encoded_frame);
RTC_CHECK(!nalu_indices.empty()); RTC_CHECK(!nalu_indices.empty());

View File

@ -217,9 +217,9 @@ void H264SpsPpsTracker::InsertSpsPpsNalus(const std::vector<uint8_t>& sps,
return; return;
} }
absl::optional<SpsParser::SpsState> parsed_sps = SpsParser::ParseSps( absl::optional<SpsParser::SpsState> parsed_sps = SpsParser::ParseSps(
sps.data() + kNaluHeaderOffset, sps.size() - kNaluHeaderOffset); rtc::ArrayView<const uint8_t>(sps).subview(kNaluHeaderOffset));
absl::optional<PpsParser::PpsState> parsed_pps = PpsParser::ParsePps( absl::optional<PpsParser::PpsState> parsed_pps = PpsParser::ParsePps(
pps.data() + kNaluHeaderOffset, pps.size() - kNaluHeaderOffset); rtc::ArrayView<const uint8_t>(pps).subview(kNaluHeaderOffset));
if (!parsed_sps) { if (!parsed_sps) {
RTC_LOG(LS_WARNING) << "Failed to parse SPS."; RTC_LOG(LS_WARNING) << "Failed to parse SPS.";

View File

@ -85,8 +85,8 @@ int64_t* GetContinuousSequence(rtc::ArrayView<int64_t> last_continuous,
#ifdef RTC_ENABLE_H265 #ifdef RTC_ENABLE_H265
bool HasVps(const H26xPacketBuffer::Packet& packet) { bool HasVps(const H26xPacketBuffer::Packet& packet) {
std::vector<H265::NaluIndex> nalu_indices = H265::FindNaluIndices( std::vector<H265::NaluIndex> nalu_indices =
packet.video_payload.cdata(), packet.video_payload.size()); H265::FindNaluIndices(packet.video_payload);
return absl::c_any_of((nalu_indices), [&packet]( return absl::c_any_of((nalu_indices), [&packet](
const H265::NaluIndex& nalu_index) { const H265::NaluIndex& nalu_index) {
return H265::ParseNaluType( return H265::ParseNaluType(
@ -242,8 +242,8 @@ bool H26xPacketBuffer::MaybeAssembleFrame(int64_t start_seq_num_unwrapped,
} }
#ifdef RTC_ENABLE_H265 #ifdef RTC_ENABLE_H265
} else if (packet->codec() == kVideoCodecH265) { } else if (packet->codec() == kVideoCodecH265) {
std::vector<H265::NaluIndex> nalu_indices = H265::FindNaluIndices( std::vector<H265::NaluIndex> nalu_indices =
packet->video_payload.cdata(), packet->video_payload.size()); H265::FindNaluIndices(packet->video_payload);
for (const auto& nalu_index : nalu_indices) { for (const auto& nalu_index : nalu_indices) {
uint8_t nalu_type = H265::ParseNaluType( uint8_t nalu_type = H265::ParseNaluType(
packet->video_payload.cdata()[nalu_index.payload_start_offset]); packet->video_payload.cdata()[nalu_index.payload_start_offset]);
@ -339,9 +339,9 @@ void H26xPacketBuffer::InsertSpsPpsNalus(const std::vector<uint8_t>& sps,
return; return;
} }
absl::optional<SpsParser::SpsState> parsed_sps = SpsParser::ParseSps( absl::optional<SpsParser::SpsState> parsed_sps = SpsParser::ParseSps(
sps.data() + kNaluHeaderOffset, sps.size() - kNaluHeaderOffset); rtc::ArrayView<const uint8_t>(sps).subview(kNaluHeaderOffset));
absl::optional<PpsParser::PpsState> parsed_pps = PpsParser::ParsePps( absl::optional<PpsParser::PpsState> parsed_pps = PpsParser::ParsePps(
pps.data() + kNaluHeaderOffset, pps.size() - kNaluHeaderOffset); rtc::ArrayView<const uint8_t>(pps).subview(kNaluHeaderOffset));
if (!parsed_sps) { if (!parsed_sps) {
RTC_LOG(LS_WARNING) << "Failed to parse SPS."; RTC_LOG(LS_WARNING) << "Failed to parse SPS.";

View File

@ -259,7 +259,7 @@ AnnexBBufferReader::AnnexBBufferReader(const uint8_t* annexb_buffer,
size_t length) size_t length)
: start_(annexb_buffer), length_(length) { : start_(annexb_buffer), length_(length) {
RTC_DCHECK(annexb_buffer); RTC_DCHECK(annexb_buffer);
offsets_ = H264::FindNaluIndices(annexb_buffer, length); offsets_ = H264::FindNaluIndices(rtc::MakeArrayView(annexb_buffer, length));
offset_ = offsets_.begin(); offset_ = offsets_.begin();
} }