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:
parent
b27ac6bc83
commit
45e5e385f3
@ -31,15 +31,13 @@ H264BitstreamParser::H264BitstreamParser() = default;
|
||||
H264BitstreamParser::~H264BitstreamParser() = default;
|
||||
|
||||
H264BitstreamParser::Result H264BitstreamParser::ParseNonParameterSetNalu(
|
||||
const uint8_t* source,
|
||||
size_t source_length,
|
||||
rtc::ArrayView<const uint8_t> source,
|
||||
uint8_t nalu_type) {
|
||||
if (!sps_ || !pps_)
|
||||
return kInvalidStream;
|
||||
|
||||
last_slice_qp_delta_ = absl::nullopt;
|
||||
const std::vector<uint8_t> slice_rbsp =
|
||||
H264::ParseRbsp(source, source_length);
|
||||
const std::vector<uint8_t> slice_rbsp = H264::ParseRbsp(source);
|
||||
if (slice_rbsp.size() < H264::kNaluTypeSize)
|
||||
return kInvalidStream;
|
||||
|
||||
@ -308,19 +306,17 @@ H264BitstreamParser::Result H264BitstreamParser::ParseNonParameterSetNalu(
|
||||
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]);
|
||||
switch (nalu_type) {
|
||||
case H264::NaluType::kSps: {
|
||||
sps_ = SpsParser::ParseSps(slice + H264::kNaluTypeSize,
|
||||
length - H264::kNaluTypeSize);
|
||||
sps_ = SpsParser::ParseSps(slice.subview(H264::kNaluTypeSize));
|
||||
if (!sps_)
|
||||
RTC_DLOG(LS_WARNING) << "Unable to parse SPS from H264 bitstream.";
|
||||
break;
|
||||
}
|
||||
case H264::NaluType::kPps: {
|
||||
pps_ = PpsParser::ParsePps(slice + H264::kNaluTypeSize,
|
||||
length - H264::kNaluTypeSize);
|
||||
pps_ = PpsParser::ParsePps(slice.subview(H264::kNaluTypeSize));
|
||||
if (!pps_)
|
||||
RTC_DLOG(LS_WARNING) << "Unable to parse PPS from H264 bitstream.";
|
||||
break;
|
||||
@ -330,7 +326,7 @@ void H264BitstreamParser::ParseSlice(const uint8_t* slice, size_t length) {
|
||||
case H264::NaluType::kPrefix:
|
||||
break; // Ignore these nalus, as we don't care about their contents.
|
||||
default:
|
||||
Result res = ParseNonParameterSetNalu(slice, length, nalu_type);
|
||||
Result res = ParseNonParameterSetNalu(slice, nalu_type);
|
||||
if (res != kOk)
|
||||
RTC_DLOG(LS_INFO) << "Failed to parse bitstream. Error: " << res;
|
||||
break;
|
||||
@ -339,11 +335,10 @@ void H264BitstreamParser::ParseSlice(const uint8_t* slice, size_t length) {
|
||||
|
||||
void H264BitstreamParser::ParseBitstream(
|
||||
rtc::ArrayView<const uint8_t> bitstream) {
|
||||
std::vector<H264::NaluIndex> nalu_indices =
|
||||
H264::FindNaluIndices(bitstream.data(), bitstream.size());
|
||||
std::vector<H264::NaluIndex> nalu_indices = H264::FindNaluIndices(bitstream);
|
||||
for (const H264::NaluIndex& index : nalu_indices)
|
||||
ParseSlice(bitstream.data() + index.payload_start_offset,
|
||||
index.payload_size);
|
||||
ParseSlice(
|
||||
bitstream.subview(index.payload_start_offset, index.payload_size));
|
||||
}
|
||||
|
||||
absl::optional<int> H264BitstreamParser::GetLastSliceQp() const {
|
||||
|
||||
@ -40,9 +40,8 @@ class H264BitstreamParser : public BitstreamParser {
|
||||
kInvalidStream,
|
||||
kUnsupportedStream,
|
||||
};
|
||||
void ParseSlice(const uint8_t* slice, size_t length);
|
||||
Result ParseNonParameterSetNalu(const uint8_t* source,
|
||||
size_t source_length,
|
||||
void ParseSlice(rtc::ArrayView<const uint8_t> slice);
|
||||
Result ParseNonParameterSetNalu(rtc::ArrayView<const uint8_t> source,
|
||||
uint8_t nalu_type);
|
||||
|
||||
// SPS/PPS state, updated when parsing new SPS/PPS, used to parse slices.
|
||||
|
||||
@ -17,19 +17,18 @@ namespace H264 {
|
||||
|
||||
const uint8_t kNaluTypeMask = 0x1F;
|
||||
|
||||
std::vector<NaluIndex> FindNaluIndices(const uint8_t* buffer,
|
||||
size_t buffer_size) {
|
||||
std::vector<NaluIndex> FindNaluIndices(rtc::ArrayView<const uint8_t> buffer) {
|
||||
// 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,
|
||||
// skip ahead to the next 3-byte sequence. 0s and 1s are relatively rare, so
|
||||
// this will skip the majority of reads/checks.
|
||||
std::vector<NaluIndex> sequences;
|
||||
if (buffer_size < kNaluShortStartSequenceSize)
|
||||
if (buffer.size() < kNaluShortStartSequenceSize)
|
||||
return sequences;
|
||||
|
||||
static_assert(kNaluShortStartSequenceSize >= 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;) {
|
||||
if (buffer[i + 2] > 1) {
|
||||
i += 3;
|
||||
@ -57,7 +56,7 @@ std::vector<NaluIndex> FindNaluIndices(const uint8_t* buffer,
|
||||
// Update length of last entry, if any.
|
||||
auto it = sequences.rbegin();
|
||||
if (it != sequences.rend())
|
||||
it->payload_size = buffer_size - it->payload_start_offset;
|
||||
it->payload_size = buffer.size() - it->payload_start_offset;
|
||||
|
||||
return sequences;
|
||||
}
|
||||
@ -66,16 +65,16 @@ NaluType ParseNaluType(uint8_t data) {
|
||||
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;
|
||||
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
|
||||
// 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
|
||||
// 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.
|
||||
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;
|
||||
}
|
||||
|
||||
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 kEmulationByte = 0x03u;
|
||||
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) {
|
||||
uint8_t byte = bytes[i];
|
||||
for (uint8_t byte : bytes) {
|
||||
if (byte <= kEmulationByte &&
|
||||
num_consecutive_zeros >= kZerosInStartSequence) {
|
||||
// Need to escape.
|
||||
|
||||
@ -63,8 +63,14 @@ struct NaluIndex {
|
||||
};
|
||||
|
||||
// Returns a vector of the NALU indices in the given buffer.
|
||||
RTC_EXPORT std::vector<NaluIndex> FindNaluIndices(const uint8_t* buffer,
|
||||
size_t buffer_size);
|
||||
RTC_EXPORT std::vector<NaluIndex> FindNaluIndices(
|
||||
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.
|
||||
RTC_EXPORT NaluType ParseNaluType(uint8_t data);
|
||||
@ -83,12 +89,24 @@ RTC_EXPORT NaluType ParseNaluType(uint8_t data);
|
||||
// the 03 emulation byte.
|
||||
|
||||
// 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
|
||||
// bytes in order to escape any data the could be interpreted as a start
|
||||
// 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 webrtc
|
||||
|
||||
|
||||
@ -29,16 +29,15 @@ constexpr int kMinPicInitQpDeltaValue = -26;
|
||||
// You can find it on this page:
|
||||
// http://www.itu.int/rec/T-REC-H.264
|
||||
|
||||
absl::optional<PpsParser::PpsState> PpsParser::ParsePps(const uint8_t* data,
|
||||
size_t length) {
|
||||
absl::optional<PpsParser::PpsState> PpsParser::ParsePps(
|
||||
rtc::ArrayView<const uint8_t> data) {
|
||||
// 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
|
||||
// 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,
|
||||
size_t length,
|
||||
bool PpsParser::ParsePpsIds(rtc::ArrayView<const uint8_t> data,
|
||||
uint32_t* pps_id,
|
||||
uint32_t* sps_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
|
||||
// bytes (the last byte of a 0x00 0x00 0x03 sequence). RBSP is defined in
|
||||
// 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);
|
||||
*pps_id = reader.ReadExponentialGolomb();
|
||||
*sps_id = reader.ReadExponentialGolomb();
|
||||
@ -54,9 +53,8 @@ bool PpsParser::ParsePpsIds(const uint8_t* data,
|
||||
}
|
||||
|
||||
absl::optional<PpsParser::SliceHeader> PpsParser::ParseSliceHeader(
|
||||
const uint8_t* data,
|
||||
size_t length) {
|
||||
std::vector<uint8_t> unpacked_buffer = H264::ParseRbsp(data, length);
|
||||
rtc::ArrayView<const uint8_t> data) {
|
||||
std::vector<uint8_t> unpacked_buffer = H264::ParseRbsp(data);
|
||||
BitstreamReader slice_reader(unpacked_buffer);
|
||||
PpsParser::SliceHeader slice_header;
|
||||
|
||||
|
||||
@ -47,15 +47,19 @@ class PpsParser {
|
||||
};
|
||||
|
||||
// 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,
|
||||
size_t length,
|
||||
static bool ParsePpsIds(rtc::ArrayView<const uint8_t> data,
|
||||
uint32_t* pps_id,
|
||||
uint32_t* sps_id);
|
||||
|
||||
static absl::optional<SliceHeader> ParseSliceHeader(const uint8_t* data,
|
||||
size_t length);
|
||||
static absl::optional<SliceHeader> ParseSliceHeader(
|
||||
rtc::ArrayView<const uint8_t> data);
|
||||
|
||||
protected:
|
||||
// Parse the PPS state, for a buffer where RBSP decoding has already been
|
||||
|
||||
@ -134,7 +134,7 @@ void WritePps(const PpsParser::PpsState& pps,
|
||||
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 {
|
||||
@ -175,7 +175,7 @@ class PpsParserTest : public ::testing::Test {
|
||||
buffer_.Clear();
|
||||
WritePps(pps, slice_group_map_type, num_slice_groups, pic_size_in_map_units,
|
||||
&buffer_);
|
||||
parsed_pps_ = PpsParser::ParsePps(buffer_.data(), buffer_.size());
|
||||
parsed_pps_ = PpsParser::ParsePps(buffer_);
|
||||
ASSERT_TRUE(parsed_pps_);
|
||||
EXPECT_EQ(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) {
|
||||
std::vector<H264::NaluIndex> nalu_indices =
|
||||
H264::FindNaluIndices(kH264BitstreamChunk, sizeof(kH264BitstreamChunk));
|
||||
rtc::ArrayView<const uint8_t> chunk(kH264BitstreamChunk);
|
||||
std::vector<H264::NaluIndex> nalu_indices = H264::FindNaluIndices(chunk);
|
||||
EXPECT_EQ(nalu_indices.size(), 3ull);
|
||||
for (const auto& index : nalu_indices) {
|
||||
H264::NaluType nalu_type =
|
||||
H264::ParseNaluType(kH264BitstreamChunk[index.payload_start_offset]);
|
||||
H264::ParseNaluType(chunk[index.payload_start_offset]);
|
||||
if (nalu_type == H264::NaluType::kIdr) {
|
||||
// Skip NAL type header and parse slice header.
|
||||
absl::optional<PpsParser::SliceHeader> slice_header =
|
||||
PpsParser::ParseSliceHeader(
|
||||
kH264BitstreamChunk + index.payload_start_offset + 1,
|
||||
index.payload_size - 1);
|
||||
PpsParser::ParseSliceHeader(chunk.subview(
|
||||
index.payload_start_offset + 1, index.payload_size - 1));
|
||||
ASSERT_TRUE(slice_header.has_value());
|
||||
EXPECT_EQ(slice_header->first_mb_in_slice, 0u);
|
||||
EXPECT_EQ(slice_header->pic_parameter_set_id, 0u);
|
||||
|
||||
@ -32,9 +32,9 @@ SpsParser::SpsState::~SpsState() = default;
|
||||
// http://www.itu.int/rec/T-REC-H.264
|
||||
|
||||
// Unpack RBSP and parse SPS state from the supplied buffer.
|
||||
absl::optional<SpsParser::SpsState> SpsParser::ParseSps(const uint8_t* data,
|
||||
size_t length) {
|
||||
std::vector<uint8_t> unpacked_buffer = H264::ParseRbsp(data, length);
|
||||
absl::optional<SpsParser::SpsState> SpsParser::ParseSps(
|
||||
rtc::ArrayView<const uint8_t> data) {
|
||||
std::vector<uint8_t> unpacked_buffer = H264::ParseRbsp(data);
|
||||
BitstreamReader reader(unpacked_buffer);
|
||||
return ParseSpsUpToVui(reader);
|
||||
}
|
||||
|
||||
@ -42,7 +42,12 @@ class RTC_EXPORT SpsParser {
|
||||
};
|
||||
|
||||
// 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:
|
||||
// Parse the SPS state, up till the VUI part, for a buffer where RBSP
|
||||
|
||||
@ -107,7 +107,7 @@ void GenerateFakeSps(uint16_t width,
|
||||
}
|
||||
|
||||
out_buffer->Clear();
|
||||
H264::WriteRbsp(rbsp, byte_count, out_buffer);
|
||||
H264::WriteRbsp(rtc::MakeArrayView(rbsp, byte_count), out_buffer);
|
||||
}
|
||||
|
||||
TEST(H264SpsParserTest, TestSampleSPSHdLandscape) {
|
||||
@ -116,8 +116,7 @@ TEST(H264SpsParserTest, TestSampleSPSHdLandscape) {
|
||||
const uint8_t buffer[] = {0x7A, 0x00, 0x1F, 0xBC, 0xD9, 0x40, 0x50, 0x05,
|
||||
0xBA, 0x10, 0x00, 0x00, 0x03, 0x00, 0xC0, 0x00,
|
||||
0x00, 0x2A, 0xE0, 0xF1, 0x83, 0x19, 0x60};
|
||||
absl::optional<SpsParser::SpsState> sps =
|
||||
SpsParser::ParseSps(buffer, arraysize(buffer));
|
||||
absl::optional<SpsParser::SpsState> sps = SpsParser::ParseSps(buffer);
|
||||
ASSERT_TRUE(sps.has_value());
|
||||
EXPECT_EQ(1280u, sps->width);
|
||||
EXPECT_EQ(720u, sps->height);
|
||||
@ -129,8 +128,7 @@ TEST(H264SpsParserTest, TestSampleSPSVgaLandscape) {
|
||||
const uint8_t buffer[] = {0x7A, 0x00, 0x1E, 0xBC, 0xD9, 0x40, 0xA0, 0x2F,
|
||||
0xF8, 0x98, 0x40, 0x00, 0x00, 0x03, 0x01, 0x80,
|
||||
0x00, 0x00, 0x56, 0x83, 0xC5, 0x8B, 0x65, 0x80};
|
||||
absl::optional<SpsParser::SpsState> sps =
|
||||
SpsParser::ParseSps(buffer, arraysize(buffer));
|
||||
absl::optional<SpsParser::SpsState> sps = SpsParser::ParseSps(buffer);
|
||||
ASSERT_TRUE(sps.has_value());
|
||||
EXPECT_EQ(640u, sps->width);
|
||||
EXPECT_EQ(360u, sps->height);
|
||||
@ -142,8 +140,7 @@ TEST(H264SpsParserTest, TestSampleSPSWeirdResolution) {
|
||||
const uint8_t buffer[] = {0x7A, 0x00, 0x0D, 0xBC, 0xD9, 0x43, 0x43, 0x3E,
|
||||
0x5E, 0x10, 0x00, 0x00, 0x03, 0x00, 0x60, 0x00,
|
||||
0x00, 0x15, 0xA0, 0xF1, 0x42, 0x99, 0x60};
|
||||
absl::optional<SpsParser::SpsState> sps =
|
||||
SpsParser::ParseSps(buffer, arraysize(buffer));
|
||||
absl::optional<SpsParser::SpsState> sps = SpsParser::ParseSps(buffer);
|
||||
ASSERT_TRUE(sps.has_value());
|
||||
EXPECT_EQ(200u, sps->width);
|
||||
EXPECT_EQ(400u, sps->height);
|
||||
@ -152,8 +149,7 @@ TEST(H264SpsParserTest, TestSampleSPSWeirdResolution) {
|
||||
TEST(H264SpsParserTest, TestSyntheticSPSQvgaLandscape) {
|
||||
rtc::Buffer buffer;
|
||||
GenerateFakeSps(320u, 180u, 1, 0, 0, &buffer);
|
||||
absl::optional<SpsParser::SpsState> sps =
|
||||
SpsParser::ParseSps(buffer.data(), buffer.size());
|
||||
absl::optional<SpsParser::SpsState> sps = SpsParser::ParseSps(buffer);
|
||||
ASSERT_TRUE(sps.has_value());
|
||||
EXPECT_EQ(320u, sps->width);
|
||||
EXPECT_EQ(180u, sps->height);
|
||||
@ -163,8 +159,7 @@ TEST(H264SpsParserTest, TestSyntheticSPSQvgaLandscape) {
|
||||
TEST(H264SpsParserTest, TestSyntheticSPSWeirdResolution) {
|
||||
rtc::Buffer buffer;
|
||||
GenerateFakeSps(156u, 122u, 2, 0, 0, &buffer);
|
||||
absl::optional<SpsParser::SpsState> sps =
|
||||
SpsParser::ParseSps(buffer.data(), buffer.size());
|
||||
absl::optional<SpsParser::SpsState> sps = SpsParser::ParseSps(buffer);
|
||||
ASSERT_TRUE(sps.has_value());
|
||||
EXPECT_EQ(156u, sps->width);
|
||||
EXPECT_EQ(122u, sps->height);
|
||||
@ -178,8 +173,7 @@ TEST(H264SpsParserTest, TestSampleSPSWithScalingLists) {
|
||||
0x10, 0xc2, 0x00, 0x84, 0x3b, 0x50, 0x3c, 0x01,
|
||||
0x13, 0xf2, 0xcd, 0xc0, 0x40, 0x40, 0x50, 0x00,
|
||||
0x00, 0x00, 0x10, 0x00, 0x00, 0x01, 0xe8, 0x40};
|
||||
absl::optional<SpsParser::SpsState> sps =
|
||||
SpsParser::ParseSps(buffer, arraysize(buffer));
|
||||
absl::optional<SpsParser::SpsState> sps = SpsParser::ParseSps(buffer);
|
||||
ASSERT_TRUE(sps.has_value());
|
||||
EXPECT_EQ(1920u, sps->width);
|
||||
EXPECT_EQ(1080u, sps->height);
|
||||
@ -188,8 +182,7 @@ TEST(H264SpsParserTest, TestSampleSPSWithScalingLists) {
|
||||
TEST(H264SpsParserTest, TestLog2MaxFrameNumMinus4) {
|
||||
rtc::Buffer buffer;
|
||||
GenerateFakeSps(320u, 180u, 1, 0, 0, &buffer);
|
||||
absl::optional<SpsParser::SpsState> sps =
|
||||
SpsParser::ParseSps(buffer.data(), buffer.size());
|
||||
absl::optional<SpsParser::SpsState> sps = SpsParser::ParseSps(buffer);
|
||||
ASSERT_TRUE(sps.has_value());
|
||||
EXPECT_EQ(320u, sps->width);
|
||||
EXPECT_EQ(180u, sps->height);
|
||||
@ -197,7 +190,7 @@ TEST(H264SpsParserTest, TestLog2MaxFrameNumMinus4) {
|
||||
EXPECT_EQ(4u, sps->log2_max_frame_num);
|
||||
|
||||
GenerateFakeSps(320u, 180u, 1, 12, 0, &buffer);
|
||||
sps = SpsParser::ParseSps(buffer.data(), buffer.size());
|
||||
sps = SpsParser::ParseSps(buffer);
|
||||
ASSERT_TRUE(sps.has_value());
|
||||
EXPECT_EQ(320u, sps->width);
|
||||
EXPECT_EQ(180u, sps->height);
|
||||
@ -205,14 +198,13 @@ TEST(H264SpsParserTest, TestLog2MaxFrameNumMinus4) {
|
||||
EXPECT_EQ(16u, sps->log2_max_frame_num);
|
||||
|
||||
GenerateFakeSps(320u, 180u, 1, 13, 0, &buffer);
|
||||
EXPECT_FALSE(SpsParser::ParseSps(buffer.data(), buffer.size()));
|
||||
EXPECT_FALSE(SpsParser::ParseSps(buffer));
|
||||
}
|
||||
|
||||
TEST(H264SpsParserTest, TestLog2MaxPicOrderCntMinus4) {
|
||||
rtc::Buffer buffer;
|
||||
GenerateFakeSps(320u, 180u, 1, 0, 0, &buffer);
|
||||
absl::optional<SpsParser::SpsState> sps =
|
||||
SpsParser::ParseSps(buffer.data(), buffer.size());
|
||||
absl::optional<SpsParser::SpsState> sps = SpsParser::ParseSps(buffer);
|
||||
ASSERT_TRUE(sps.has_value());
|
||||
EXPECT_EQ(320u, sps->width);
|
||||
EXPECT_EQ(180u, sps->height);
|
||||
@ -220,15 +212,14 @@ TEST(H264SpsParserTest, TestLog2MaxPicOrderCntMinus4) {
|
||||
EXPECT_EQ(4u, sps->log2_max_pic_order_cnt_lsb);
|
||||
|
||||
GenerateFakeSps(320u, 180u, 1, 0, 12, &buffer);
|
||||
EXPECT_TRUE(static_cast<bool>(
|
||||
sps = SpsParser::ParseSps(buffer.data(), buffer.size())));
|
||||
EXPECT_TRUE(static_cast<bool>(sps = SpsParser::ParseSps(buffer)));
|
||||
EXPECT_EQ(320u, sps->width);
|
||||
EXPECT_EQ(180u, sps->height);
|
||||
EXPECT_EQ(1u, sps->id);
|
||||
EXPECT_EQ(16u, sps->log2_max_pic_order_cnt_lsb);
|
||||
|
||||
GenerateFakeSps(320u, 180u, 1, 0, 13, &buffer);
|
||||
EXPECT_FALSE(SpsParser::ParseSps(buffer.data(), buffer.size()));
|
||||
EXPECT_FALSE(SpsParser::ParseSps(buffer));
|
||||
}
|
||||
|
||||
} // namespace webrtc
|
||||
|
||||
@ -135,14 +135,13 @@ void SpsVuiRewriter::UpdateStats(ParseResult result, Direction direction) {
|
||||
}
|
||||
|
||||
SpsVuiRewriter::ParseResult SpsVuiRewriter::ParseAndRewriteSps(
|
||||
const uint8_t* buffer,
|
||||
size_t length,
|
||||
rtc::ArrayView<const uint8_t> buffer,
|
||||
absl::optional<SpsParser::SpsState>* sps,
|
||||
const webrtc::ColorSpace* color_space,
|
||||
rtc::Buffer* destination) {
|
||||
// Create temporary RBSP decoded buffer of the payload (exlcuding the
|
||||
// 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);
|
||||
absl::optional<SpsParser::SpsState> sps_state =
|
||||
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
|
||||
// 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());
|
||||
|
||||
// Check how far the SpsParser has read, and copy that data in bulk.
|
||||
@ -200,26 +199,25 @@ SpsVuiRewriter::ParseResult SpsVuiRewriter::ParseAndRewriteSps(
|
||||
bit_offset = 0;
|
||||
}
|
||||
|
||||
RTC_DCHECK(byte_offset <= length + kMaxVuiSpsIncrease);
|
||||
RTC_DCHECK(byte_offset <= buffer.size() + kMaxVuiSpsIncrease);
|
||||
RTC_CHECK(destination != nullptr);
|
||||
|
||||
out_buffer.SetSize(byte_offset);
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
SpsVuiRewriter::ParseResult SpsVuiRewriter::ParseAndRewriteSps(
|
||||
const uint8_t* buffer,
|
||||
size_t length,
|
||||
rtc::ArrayView<const uint8_t> buffer,
|
||||
absl::optional<SpsParser::SpsState>* sps,
|
||||
const webrtc::ColorSpace* color_space,
|
||||
rtc::Buffer* destination,
|
||||
Direction direction) {
|
||||
ParseResult result =
|
||||
ParseAndRewriteSps(buffer, length, sps, color_space, destination);
|
||||
ParseAndRewriteSps(buffer, sps, color_space, destination);
|
||||
UpdateStats(result, direction);
|
||||
return result;
|
||||
}
|
||||
@ -227,22 +225,21 @@ SpsVuiRewriter::ParseResult SpsVuiRewriter::ParseAndRewriteSps(
|
||||
rtc::Buffer SpsVuiRewriter::ParseOutgoingBitstreamAndRewrite(
|
||||
rtc::ArrayView<const uint8_t> buffer,
|
||||
const webrtc::ColorSpace* color_space) {
|
||||
std::vector<H264::NaluIndex> nalus =
|
||||
H264::FindNaluIndices(buffer.data(), buffer.size());
|
||||
std::vector<H264::NaluIndex> nalus = H264::FindNaluIndices(buffer);
|
||||
|
||||
// Allocate some extra space for potentially adding a missing VUI.
|
||||
rtc::Buffer output_buffer(/*size=*/0, /*capacity=*/buffer.size() +
|
||||
nalus.size() * kMaxVuiSpsIncrease);
|
||||
|
||||
for (const H264::NaluIndex& nalu : nalus) {
|
||||
for (const H264::NaluIndex& nalu_index : nalus) {
|
||||
// Copy NAL unit start code.
|
||||
const uint8_t* start_code_ptr = buffer.data() + nalu.start_offset;
|
||||
const size_t start_code_length =
|
||||
nalu.payload_start_offset - nalu.start_offset;
|
||||
const uint8_t* nalu_ptr = buffer.data() + nalu.payload_start_offset;
|
||||
const size_t nalu_length = nalu.payload_size;
|
||||
rtc::ArrayView<const uint8_t> start_code = buffer.subview(
|
||||
nalu_index.start_offset,
|
||||
nalu_index.payload_start_offset - nalu_index.start_offset);
|
||||
rtc::ArrayView<const uint8_t> nalu = buffer.subview(
|
||||
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
|
||||
// to enable faster decoding. Streams in that format incur additional
|
||||
// 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
|
||||
// can append modified payload on top of that.
|
||||
output_nalu.AppendData(nalu_ptr[0]);
|
||||
output_nalu.AppendData(nalu[0]);
|
||||
|
||||
ParseResult result = ParseAndRewriteSps(
|
||||
nalu_ptr + H264::kNaluTypeSize, nalu_length - H264::kNaluTypeSize,
|
||||
&sps, color_space, &output_nalu, Direction::kOutgoing);
|
||||
ParseResult result =
|
||||
ParseAndRewriteSps(nalu.subview(H264::kNaluTypeSize), &sps,
|
||||
color_space, &output_nalu, Direction::kOutgoing);
|
||||
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());
|
||||
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.
|
||||
continue;
|
||||
}
|
||||
|
||||
// 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(nalu_ptr, nalu_length);
|
||||
output_buffer.AppendData(start_code);
|
||||
output_buffer.AppendData(nalu);
|
||||
}
|
||||
return output_buffer;
|
||||
}
|
||||
|
||||
@ -43,8 +43,7 @@ class SpsVuiRewriter : private SpsParser {
|
||||
// (NALU start, type, Stap-A, etc) have already been parsed and that RBSP
|
||||
// decoding has been performed.
|
||||
static ParseResult ParseAndRewriteSps(
|
||||
const uint8_t* buffer,
|
||||
size_t length,
|
||||
rtc::ArrayView<const uint8_t> buffer,
|
||||
absl::optional<SpsParser::SpsState>* sps,
|
||||
const ColorSpace* color_space,
|
||||
rtc::Buffer* destination,
|
||||
@ -58,8 +57,7 @@ class SpsVuiRewriter : private SpsParser {
|
||||
|
||||
private:
|
||||
static ParseResult ParseAndRewriteSps(
|
||||
const uint8_t* buffer,
|
||||
size_t length,
|
||||
rtc::ArrayView<const uint8_t> buffer,
|
||||
absl::optional<SpsParser::SpsState>* sps,
|
||||
const ColorSpace* color_space,
|
||||
rtc::Buffer* destination);
|
||||
|
||||
@ -297,7 +297,7 @@ void GenerateFakeSps(const VuiHeader& vui, rtc::Buffer* out_buffer) {
|
||||
byte_count++;
|
||||
}
|
||||
|
||||
H264::WriteRbsp(rbsp, byte_count, out_buffer);
|
||||
H264::WriteRbsp(rtc::MakeArrayView(rbsp, byte_count), out_buffer);
|
||||
}
|
||||
|
||||
void TestSps(const VuiHeader& vui,
|
||||
@ -310,8 +310,8 @@ void TestSps(const VuiHeader& vui,
|
||||
absl::optional<SpsParser::SpsState> sps;
|
||||
rtc::Buffer rewritten_sps;
|
||||
SpsVuiRewriter::ParseResult result = SpsVuiRewriter::ParseAndRewriteSps(
|
||||
original_sps.data(), original_sps.size(), &sps, color_space,
|
||||
&rewritten_sps, SpsVuiRewriter::Direction::kIncoming);
|
||||
original_sps, &sps, color_space, &rewritten_sps,
|
||||
SpsVuiRewriter::Direction::kIncoming);
|
||||
EXPECT_EQ(expected_parse_result, result);
|
||||
ASSERT_TRUE(sps);
|
||||
EXPECT_EQ(sps->width, kWidth);
|
||||
@ -324,7 +324,7 @@ void TestSps(const VuiHeader& vui,
|
||||
// Ensure that added/rewritten SPS is parsable.
|
||||
rtc::Buffer tmp;
|
||||
result = SpsVuiRewriter::ParseAndRewriteSps(
|
||||
rewritten_sps.data(), rewritten_sps.size(), &sps, nullptr, &tmp,
|
||||
rewritten_sps, &sps, nullptr, &tmp,
|
||||
SpsVuiRewriter::Direction::kIncoming);
|
||||
EXPECT_EQ(SpsVuiRewriter::ParseResult::kVuiOk, result);
|
||||
ASSERT_TRUE(sps);
|
||||
|
||||
@ -80,13 +80,11 @@ H265BitstreamParser::~H265BitstreamParser() = default;
|
||||
// section 7.3.6.1. You can find it on this page:
|
||||
// http://www.itu.int/rec/T-REC-H.265
|
||||
H265BitstreamParser::Result H265BitstreamParser::ParseNonParameterSetNalu(
|
||||
const uint8_t* source,
|
||||
size_t source_length,
|
||||
rtc::ArrayView<const uint8_t> source,
|
||||
uint8_t nalu_type) {
|
||||
last_slice_qp_delta_ = absl::nullopt;
|
||||
last_slice_pps_id_ = absl::nullopt;
|
||||
const std::vector<uint8_t> slice_rbsp =
|
||||
H265::ParseRbsp(source, source_length);
|
||||
const std::vector<uint8_t> slice_rbsp = H265::ParseRbsp(source);
|
||||
if (slice_rbsp.size() < H265::kNaluHeaderSize)
|
||||
return kInvalidStream;
|
||||
|
||||
@ -420,14 +418,14 @@ const H265SpsParser::SpsState* H265BitstreamParser::GetSPS(uint32_t id) const {
|
||||
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]);
|
||||
switch (nalu_type) {
|
||||
case H265::NaluType::kVps: {
|
||||
absl::optional<H265VpsParser::VpsState> vps_state;
|
||||
if (length >= H265::kNaluHeaderSize) {
|
||||
vps_state = H265VpsParser::ParseVps(slice + H265::kNaluHeaderSize,
|
||||
length - H265::kNaluHeaderSize);
|
||||
if (slice.size() >= H265::kNaluHeaderSize) {
|
||||
vps_state =
|
||||
H265VpsParser::ParseVps(slice.subview(H265::kNaluHeaderSize));
|
||||
}
|
||||
|
||||
if (!vps_state) {
|
||||
@ -439,9 +437,9 @@ void H265BitstreamParser::ParseSlice(const uint8_t* slice, size_t length) {
|
||||
}
|
||||
case H265::NaluType::kSps: {
|
||||
absl::optional<H265SpsParser::SpsState> sps_state;
|
||||
if (length >= H265::kNaluHeaderSize) {
|
||||
sps_state = H265SpsParser::ParseSps(slice + H265::kNaluHeaderSize,
|
||||
length - H265::kNaluHeaderSize);
|
||||
if (slice.size() >= H265::kNaluHeaderSize) {
|
||||
sps_state =
|
||||
H265SpsParser::ParseSps(slice.subview(H265::kNaluHeaderSize));
|
||||
}
|
||||
if (!sps_state) {
|
||||
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: {
|
||||
absl::optional<H265PpsParser::PpsState> pps_state;
|
||||
if (length >= H265::kNaluHeaderSize) {
|
||||
std::vector<uint8_t> unpacked_buffer = H265::ParseRbsp(
|
||||
slice + H265::kNaluHeaderSize, length - H265::kNaluHeaderSize);
|
||||
if (slice.size() >= H265::kNaluHeaderSize) {
|
||||
std::vector<uint8_t> unpacked_buffer =
|
||||
H265::ParseRbsp(slice.subview(H265::kNaluHeaderSize));
|
||||
BitstreamReader slice_reader(unpacked_buffer);
|
||||
// pic_parameter_set_id: ue(v)
|
||||
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();
|
||||
IN_RANGE_OR_RETURN_VOID(sps_id, 0, 15);
|
||||
const H265SpsParser::SpsState* sps = GetSPS(sps_id);
|
||||
pps_state = H265PpsParser::ParsePps(
|
||||
slice + H265::kNaluHeaderSize, length - H265::kNaluHeaderSize, sps);
|
||||
pps_state =
|
||||
H265PpsParser::ParsePps(slice.subview(H265::kNaluHeaderSize), sps);
|
||||
}
|
||||
if (!pps_state) {
|
||||
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:
|
||||
break;
|
||||
default:
|
||||
Result res = ParseNonParameterSetNalu(slice, length, nalu_type);
|
||||
Result res = ParseNonParameterSetNalu(slice, nalu_type);
|
||||
if (res != kOk) {
|
||||
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>
|
||||
H265BitstreamParser::ParsePpsIdFromSliceSegmentLayerRbsp(const uint8_t* data,
|
||||
size_t length,
|
||||
uint8_t nalu_type) {
|
||||
std::vector<uint8_t> unpacked_buffer = H265::ParseRbsp(data, length);
|
||||
H265BitstreamParser::ParsePpsIdFromSliceSegmentLayerRbsp(
|
||||
rtc::ArrayView<const uint8_t> data,
|
||||
uint8_t nalu_type) {
|
||||
std::vector<uint8_t> unpacked_buffer = H265::ParseRbsp(data);
|
||||
BitstreamReader slice_reader(unpacked_buffer);
|
||||
|
||||
// first_slice_segment_in_pic_flag: u(1)
|
||||
@ -519,10 +517,10 @@ H265BitstreamParser::ParsePpsIdFromSliceSegmentLayerRbsp(const uint8_t* data,
|
||||
|
||||
void H265BitstreamParser::ParseBitstream(
|
||||
rtc::ArrayView<const uint8_t> bitstream) {
|
||||
std::vector<H265::NaluIndex> nalu_indices =
|
||||
H265::FindNaluIndices(bitstream.data(), bitstream.size());
|
||||
std::vector<H265::NaluIndex> nalu_indices = H265::FindNaluIndices(bitstream);
|
||||
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 {
|
||||
|
||||
@ -40,8 +40,7 @@ class RTC_EXPORT H265BitstreamParser : public BitstreamParser {
|
||||
absl::optional<uint32_t> GetLastSlicePpsId() const;
|
||||
|
||||
static absl::optional<uint32_t> ParsePpsIdFromSliceSegmentLayerRbsp(
|
||||
const uint8_t* data,
|
||||
size_t length,
|
||||
rtc::ArrayView<const uint8_t> data,
|
||||
uint8_t nalu_type);
|
||||
|
||||
protected:
|
||||
@ -50,9 +49,8 @@ class RTC_EXPORT H265BitstreamParser : public BitstreamParser {
|
||||
kInvalidStream,
|
||||
kUnsupportedStream,
|
||||
};
|
||||
void ParseSlice(const uint8_t* slice, size_t length);
|
||||
Result ParseNonParameterSetNalu(const uint8_t* source,
|
||||
size_t source_length,
|
||||
void ParseSlice(rtc::ArrayView<const uint8_t> slice);
|
||||
Result ParseNonParameterSetNalu(rtc::ArrayView<const uint8_t> source,
|
||||
uint8_t nalu_type);
|
||||
|
||||
const H265PpsParser::PpsState* GetPPS(uint32_t id) const;
|
||||
|
||||
@ -127,8 +127,8 @@ TEST(H265BitstreamParserTest, ReportsLastSliceQpFromShortTermReferenceSlices) {
|
||||
TEST(H265BitstreamParserTest, PpsIdFromSlice) {
|
||||
H265BitstreamParser h265_parser;
|
||||
absl::optional<uint32_t> pps_id =
|
||||
h265_parser.ParsePpsIdFromSliceSegmentLayerRbsp(
|
||||
kH265SliceChunk, sizeof(kH265SliceChunk), H265::NaluType::kTrailR);
|
||||
h265_parser.ParsePpsIdFromSliceSegmentLayerRbsp(kH265SliceChunk,
|
||||
H265::NaluType::kTrailR);
|
||||
ASSERT_TRUE(pps_id);
|
||||
EXPECT_EQ(1u, *pps_id);
|
||||
}
|
||||
|
||||
@ -17,10 +17,8 @@ namespace H265 {
|
||||
|
||||
constexpr uint8_t kNaluTypeMask = 0x7E;
|
||||
|
||||
std::vector<NaluIndex> FindNaluIndices(const uint8_t* buffer,
|
||||
size_t buffer_size) {
|
||||
std::vector<H264::NaluIndex> indices =
|
||||
H264::FindNaluIndices(buffer, buffer_size);
|
||||
std::vector<NaluIndex> FindNaluIndices(rtc::ArrayView<const uint8_t> buffer) {
|
||||
std::vector<H264::NaluIndex> indices = H264::FindNaluIndices(buffer);
|
||||
std::vector<NaluIndex> results;
|
||||
for (auto& index : indices) {
|
||||
results.push_back(
|
||||
@ -33,12 +31,12 @@ NaluType ParseNaluType(uint8_t data) {
|
||||
return static_cast<NaluType>((data & kNaluTypeMask) >> 1);
|
||||
}
|
||||
|
||||
std::vector<uint8_t> ParseRbsp(const uint8_t* data, size_t length) {
|
||||
return H264::ParseRbsp(data, length);
|
||||
std::vector<uint8_t> ParseRbsp(rtc::ArrayView<const uint8_t> data) {
|
||||
return H264::ParseRbsp(data);
|
||||
}
|
||||
|
||||
void WriteRbsp(const uint8_t* bytes, size_t length, rtc::Buffer* destination) {
|
||||
H264::WriteRbsp(bytes, length, destination);
|
||||
void WriteRbsp(rtc::ArrayView<const uint8_t> bytes, rtc::Buffer* destination) {
|
||||
H264::WriteRbsp(bytes, destination);
|
||||
}
|
||||
|
||||
uint32_t Log2Ceiling(uint32_t value) {
|
||||
|
||||
@ -77,8 +77,14 @@ struct NaluIndex {
|
||||
};
|
||||
|
||||
// Returns a vector of the NALU indices in the given buffer.
|
||||
RTC_EXPORT std::vector<NaluIndex> FindNaluIndices(const uint8_t* buffer,
|
||||
size_t buffer_size);
|
||||
RTC_EXPORT std::vector<NaluIndex> FindNaluIndices(
|
||||
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.
|
||||
RTC_EXPORT NaluType ParseNaluType(uint8_t data);
|
||||
@ -97,12 +103,24 @@ RTC_EXPORT NaluType ParseNaluType(uint8_t data);
|
||||
// the 03 emulation byte.
|
||||
|
||||
// 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
|
||||
// bytes in order to escape any data the could be interpreted as a start
|
||||
// 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);
|
||||
|
||||
|
||||
@ -63,17 +63,15 @@ namespace webrtc {
|
||||
// http://www.itu.int/rec/T-REC-H.265
|
||||
|
||||
absl::optional<H265PpsParser::PpsState> H265PpsParser::ParsePps(
|
||||
const uint8_t* data,
|
||||
size_t length,
|
||||
rtc::ArrayView<const uint8_t> data,
|
||||
const H265SpsParser::SpsState* sps) {
|
||||
// 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
|
||||
// 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,
|
||||
size_t length,
|
||||
bool H265PpsParser::ParsePpsIds(rtc::ArrayView<const uint8_t> data,
|
||||
uint32_t* pps_id,
|
||||
uint32_t* sps_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
|
||||
// bytes (the last byte of a 0x00 0x00 0x03 sequence). RBSP is defined in
|
||||
// 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);
|
||||
*pps_id = reader.ReadExponentialGolomb();
|
||||
IN_RANGE_OR_RETURN_FALSE(*pps_id, 0, 63);
|
||||
|
||||
@ -43,14 +43,26 @@ class RTC_EXPORT H265PpsParser {
|
||||
};
|
||||
|
||||
// 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,
|
||||
const H265SpsParser::SpsState* sps);
|
||||
// TODO: bugs.webrtc.org/42225170 - Deprecate.
|
||||
static inline absl::optional<PpsState> ParsePps(
|
||||
const uint8_t* data,
|
||||
size_t length,
|
||||
const H265SpsParser::SpsState* sps) {
|
||||
return ParsePps(rtc::MakeArrayView(data, length), sps);
|
||||
}
|
||||
|
||||
static bool ParsePpsIds(const uint8_t* data,
|
||||
size_t length,
|
||||
static bool ParsePpsIds(rtc::ArrayView<const uint8_t> data,
|
||||
uint32_t* pps_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:
|
||||
// Parse the PPS state, for a bit buffer where RBSP decoding has already been
|
||||
|
||||
@ -161,7 +161,7 @@ void WritePps(const H265PpsParser::PpsState& pps,
|
||||
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 {
|
||||
@ -196,9 +196,8 @@ class H265PpsParserTest : public ::testing::Test {
|
||||
0x16, 0x59, 0x59, 0xa4, 0x93, 0x2b, 0x80, 0x40, 0x00, 0x00,
|
||||
0x03, 0x00, 0x40, 0x00, 0x00, 0x07, 0x82};
|
||||
H265SpsParser::SpsState parsed_sps =
|
||||
H265SpsParser::ParseSps(sps_buffer, arraysize(sps_buffer)).value();
|
||||
parsed_pps_ =
|
||||
H265PpsParser::ParsePps(buffer_.data(), buffer_.size(), &parsed_sps);
|
||||
H265SpsParser::ParseSps(sps_buffer).value();
|
||||
parsed_pps_ = H265PpsParser::ParsePps(buffer_, &parsed_sps);
|
||||
ASSERT_TRUE(parsed_pps_);
|
||||
EXPECT_EQ(pps.dependent_slice_segments_enabled_flag,
|
||||
parsed_pps_->dependent_slice_segments_enabled_flag);
|
||||
|
||||
@ -104,10 +104,8 @@ size_t H265SpsParser::GetDpbMaxPicBuf(int general_profile_idc) {
|
||||
|
||||
// Unpack RBSP and parse SPS state from the supplied buffer.
|
||||
absl::optional<H265SpsParser::SpsState> H265SpsParser::ParseSps(
|
||||
const uint8_t* data,
|
||||
size_t length) {
|
||||
RTC_DCHECK(data);
|
||||
return ParseSpsInternal(H265::ParseRbsp(data, length));
|
||||
rtc::ArrayView<const uint8_t> data) {
|
||||
return ParseSpsInternal(H265::ParseRbsp(data));
|
||||
}
|
||||
|
||||
bool H265SpsParser::ParseScalingListData(BitstreamReader& reader) {
|
||||
|
||||
@ -104,7 +104,12 @@ class RTC_EXPORT H265SpsParser {
|
||||
};
|
||||
|
||||
// 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);
|
||||
|
||||
|
||||
@ -365,7 +365,7 @@ void WriteSps(uint16_t width,
|
||||
}
|
||||
|
||||
out_buffer->Clear();
|
||||
H265::WriteRbsp(rbsp, byte_count, out_buffer);
|
||||
H265::WriteRbsp(rtc::MakeArrayView(rbsp, byte_count), out_buffer);
|
||||
}
|
||||
|
||||
class H265SpsParserTest : public ::testing::Test {
|
||||
@ -389,8 +389,7 @@ TEST_F(H265SpsParserTest, TestSampleSPSHdLandscape) {
|
||||
0x02, 0x80, 0x80, 0x2d, 0x16, 0x59, 0x59, 0xa4,
|
||||
0x93, 0x2b, 0x80, 0x40, 0x00, 0x00, 0x03, 0x00,
|
||||
0x40, 0x00, 0x00, 0x07, 0x82};
|
||||
absl::optional<H265SpsParser::SpsState> sps =
|
||||
H265SpsParser::ParseSps(buffer, arraysize(buffer));
|
||||
absl::optional<H265SpsParser::SpsState> sps = H265SpsParser::ParseSps(buffer);
|
||||
ASSERT_TRUE(sps.has_value());
|
||||
EXPECT_EQ(1280u, sps->width);
|
||||
EXPECT_EQ(720u, sps->height);
|
||||
@ -418,8 +417,7 @@ TEST_F(H265SpsParserTest, TestSampleSPSVerticalCropLandscape) {
|
||||
0x05, 0x02, 0x01, 0x09, 0xf2, 0xe5, 0x95, 0x9a,
|
||||
0x49, 0x32, 0xb8, 0x04, 0x00, 0x00, 0x03, 0x00,
|
||||
0x04, 0x00, 0x00, 0x03, 0x00, 0x78, 0x20};
|
||||
absl::optional<H265SpsParser::SpsState> sps =
|
||||
H265SpsParser::ParseSps(buffer, arraysize(buffer));
|
||||
absl::optional<H265SpsParser::SpsState> sps = H265SpsParser::ParseSps(buffer);
|
||||
ASSERT_TRUE(sps.has_value());
|
||||
EXPECT_EQ(640u, sps->width);
|
||||
EXPECT_EQ(260u, sps->height);
|
||||
@ -446,8 +444,7 @@ TEST_F(H265SpsParserTest, TestSampleSPSHorizontalAndVerticalCrop) {
|
||||
0x08, 0x48, 0x04, 0x27, 0x72, 0xe5, 0x95, 0x9a,
|
||||
0x49, 0x32, 0xb8, 0x04, 0x00, 0x00, 0x03, 0x00,
|
||||
0x04, 0x00, 0x00, 0x03, 0x00, 0x78, 0x20};
|
||||
absl::optional<H265SpsParser::SpsState> sps =
|
||||
H265SpsParser::ParseSps(buffer, arraysize(buffer));
|
||||
absl::optional<H265SpsParser::SpsState> sps = H265SpsParser::ParseSps(buffer);
|
||||
ASSERT_TRUE(sps.has_value());
|
||||
EXPECT_EQ(260u, sps->width);
|
||||
EXPECT_EQ(260u, sps->height);
|
||||
@ -456,8 +453,7 @@ TEST_F(H265SpsParserTest, TestSampleSPSHorizontalAndVerticalCrop) {
|
||||
TEST_F(H265SpsParserTest, TestSyntheticSPSQvgaLandscape) {
|
||||
rtc::Buffer buffer;
|
||||
WriteSps(320u, 180u, 1, 0, 1, 0, &buffer);
|
||||
absl::optional<H265SpsParser::SpsState> sps =
|
||||
H265SpsParser::ParseSps(buffer.data(), buffer.size());
|
||||
absl::optional<H265SpsParser::SpsState> sps = H265SpsParser::ParseSps(buffer);
|
||||
ASSERT_TRUE(sps.has_value());
|
||||
EXPECT_EQ(320u, sps->width);
|
||||
EXPECT_EQ(180u, sps->height);
|
||||
@ -467,8 +463,7 @@ TEST_F(H265SpsParserTest, TestSyntheticSPSQvgaLandscape) {
|
||||
TEST_F(H265SpsParserTest, TestSyntheticSPSWeirdResolution) {
|
||||
rtc::Buffer buffer;
|
||||
WriteSps(156u, 122u, 2, 0, 1, 0, &buffer);
|
||||
absl::optional<H265SpsParser::SpsState> sps =
|
||||
H265SpsParser::ParseSps(buffer.data(), buffer.size());
|
||||
absl::optional<H265SpsParser::SpsState> sps = H265SpsParser::ParseSps(buffer);
|
||||
ASSERT_TRUE(sps.has_value());
|
||||
EXPECT_EQ(156u, sps->width);
|
||||
EXPECT_EQ(122u, sps->height);
|
||||
@ -478,8 +473,7 @@ TEST_F(H265SpsParserTest, TestSyntheticSPSWeirdResolution) {
|
||||
TEST_F(H265SpsParserTest, TestLog2MaxSubLayersMinus1) {
|
||||
rtc::Buffer buffer;
|
||||
WriteSps(320u, 180u, 1, 0, 1, 0, &buffer);
|
||||
absl::optional<H265SpsParser::SpsState> sps =
|
||||
H265SpsParser::ParseSps(buffer.data(), buffer.size());
|
||||
absl::optional<H265SpsParser::SpsState> sps = H265SpsParser::ParseSps(buffer);
|
||||
ASSERT_TRUE(sps.has_value());
|
||||
EXPECT_EQ(320u, sps->width);
|
||||
EXPECT_EQ(180u, sps->height);
|
||||
@ -488,7 +482,7 @@ TEST_F(H265SpsParserTest, TestLog2MaxSubLayersMinus1) {
|
||||
|
||||
WriteSps(320u, 180u, 1, 6, 1, 0, &buffer);
|
||||
absl::optional<H265SpsParser::SpsState> sps1 =
|
||||
H265SpsParser::ParseSps(buffer.data(), buffer.size());
|
||||
H265SpsParser::ParseSps(buffer);
|
||||
ASSERT_TRUE(sps1.has_value());
|
||||
EXPECT_EQ(320u, sps1->width);
|
||||
EXPECT_EQ(180u, sps1->height);
|
||||
@ -497,15 +491,14 @@ TEST_F(H265SpsParserTest, TestLog2MaxSubLayersMinus1) {
|
||||
|
||||
WriteSps(320u, 180u, 1, 7, 1, 0, &buffer);
|
||||
absl::optional<H265SpsParser::SpsState> result =
|
||||
H265SpsParser::ParseSps(buffer.data(), buffer.size());
|
||||
H265SpsParser::ParseSps(buffer);
|
||||
EXPECT_FALSE(result.has_value());
|
||||
}
|
||||
|
||||
TEST_F(H265SpsParserTest, TestSubLayerOrderingInfoPresentFlag) {
|
||||
rtc::Buffer buffer;
|
||||
WriteSps(320u, 180u, 1, 6, 1, 0, &buffer);
|
||||
absl::optional<H265SpsParser::SpsState> sps =
|
||||
H265SpsParser::ParseSps(buffer.data(), buffer.size());
|
||||
absl::optional<H265SpsParser::SpsState> sps = H265SpsParser::ParseSps(buffer);
|
||||
ASSERT_TRUE(sps.has_value());
|
||||
EXPECT_EQ(320u, sps->width);
|
||||
EXPECT_EQ(180u, sps->height);
|
||||
@ -514,7 +507,7 @@ TEST_F(H265SpsParserTest, TestSubLayerOrderingInfoPresentFlag) {
|
||||
|
||||
WriteSps(320u, 180u, 1, 6, 1, 0, &buffer);
|
||||
absl::optional<H265SpsParser::SpsState> sps1 =
|
||||
H265SpsParser::ParseSps(buffer.data(), buffer.size());
|
||||
H265SpsParser::ParseSps(buffer);
|
||||
ASSERT_TRUE(sps1.has_value());
|
||||
EXPECT_EQ(320u, sps1->width);
|
||||
EXPECT_EQ(180u, sps1->height);
|
||||
@ -525,8 +518,7 @@ TEST_F(H265SpsParserTest, TestSubLayerOrderingInfoPresentFlag) {
|
||||
TEST_F(H265SpsParserTest, TestLongTermRefPicsPresentFlag) {
|
||||
rtc::Buffer buffer;
|
||||
WriteSps(320u, 180u, 1, 0, 1, 0, &buffer);
|
||||
absl::optional<H265SpsParser::SpsState> sps =
|
||||
H265SpsParser::ParseSps(buffer.data(), buffer.size());
|
||||
absl::optional<H265SpsParser::SpsState> sps = H265SpsParser::ParseSps(buffer);
|
||||
ASSERT_TRUE(sps.has_value());
|
||||
EXPECT_EQ(320u, sps->width);
|
||||
EXPECT_EQ(180u, sps->height);
|
||||
@ -535,7 +527,7 @@ TEST_F(H265SpsParserTest, TestLongTermRefPicsPresentFlag) {
|
||||
|
||||
WriteSps(320u, 180u, 1, 6, 1, 1, &buffer);
|
||||
absl::optional<H265SpsParser::SpsState> sps1 =
|
||||
H265SpsParser::ParseSps(buffer.data(), buffer.size());
|
||||
H265SpsParser::ParseSps(buffer);
|
||||
ASSERT_TRUE(sps1.has_value());
|
||||
EXPECT_EQ(320u, sps1->width);
|
||||
EXPECT_EQ(180u, sps1->height);
|
||||
|
||||
@ -25,10 +25,8 @@ H265VpsParser::VpsState::VpsState() = default;
|
||||
|
||||
// Unpack RBSP and parse VPS state from the supplied buffer.
|
||||
absl::optional<H265VpsParser::VpsState> H265VpsParser::ParseVps(
|
||||
const uint8_t* data,
|
||||
size_t length) {
|
||||
RTC_DCHECK(data);
|
||||
return ParseInternal(H265::ParseRbsp(data, length));
|
||||
rtc::ArrayView<const uint8_t> data) {
|
||||
return ParseInternal(H265::ParseRbsp(data));
|
||||
}
|
||||
|
||||
absl::optional<H265VpsParser::VpsState> H265VpsParser::ParseInternal(
|
||||
|
||||
@ -29,7 +29,12 @@ class RTC_EXPORT H265VpsParser {
|
||||
};
|
||||
|
||||
// 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:
|
||||
// Parse the VPS state, for a bit buffer where RBSP decoding has already been
|
||||
|
||||
@ -41,8 +41,7 @@ TEST_F(H265VpsParserTest, TestSampleVPSId) {
|
||||
0x1c, 0x01, 0xff, 0xff, 0x04, 0x08, 0x00, 0x00, 0x03, 0x00, 0x9d,
|
||||
0x08, 0x00, 0x00, 0x03, 0x00, 0x00, 0x78, 0x95, 0x98, 0x09,
|
||||
};
|
||||
EXPECT_TRUE(static_cast<bool>(
|
||||
vps_ = H265VpsParser::ParseVps(buffer, arraysize(buffer))));
|
||||
EXPECT_TRUE(static_cast<bool>(vps_ = H265VpsParser::ParseVps(buffer)));
|
||||
EXPECT_EQ(1u, vps_->id);
|
||||
}
|
||||
|
||||
|
||||
@ -48,8 +48,7 @@ RtpPacketizerH264::RtpPacketizerH264(rtc::ArrayView<const uint8_t> payload,
|
||||
RTC_CHECK(packetization_mode == H264PacketizationMode::NonInterleaved ||
|
||||
packetization_mode == H264PacketizationMode::SingleNalUnit);
|
||||
|
||||
for (const auto& nalu :
|
||||
H264::FindNaluIndices(payload.data(), payload.size())) {
|
||||
for (const auto& nalu : H264::FindNaluIndices(payload)) {
|
||||
input_fragments_.push_back(
|
||||
payload.subview(nalu.payload_start_offset, nalu.payload_size));
|
||||
}
|
||||
|
||||
@ -24,8 +24,7 @@ namespace webrtc {
|
||||
RtpPacketizerH265::RtpPacketizerH265(rtc::ArrayView<const uint8_t> payload,
|
||||
PayloadSizeLimits limits)
|
||||
: limits_(limits), num_packets_left_(0) {
|
||||
for (const auto& nalu :
|
||||
H264::FindNaluIndices(payload.data(), payload.size())) {
|
||||
for (const auto& nalu : H264::FindNaluIndices(payload)) {
|
||||
if (!nalu.payload_size) {
|
||||
input_fragments_.clear();
|
||||
return;
|
||||
|
||||
@ -116,7 +116,8 @@ absl::optional<VideoRtpDepacketizer::ParsedRtpPayload> ProcessStapAOrSingleNalu(
|
||||
nalu.sps_id = -1;
|
||||
nalu.pps_id = -1;
|
||||
start_offset += H264::kNaluTypeSize;
|
||||
|
||||
rtc::ArrayView<const uint8_t> nalu_data(&payload_data[start_offset],
|
||||
end_offset - start_offset);
|
||||
switch (nalu.type) {
|
||||
case H264::NaluType::kSps: {
|
||||
// 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;
|
||||
|
||||
SpsVuiRewriter::ParseResult result = SpsVuiRewriter::ParseAndRewriteSps(
|
||||
&payload_data[start_offset], end_offset - start_offset, &sps,
|
||||
nullptr, &output_buffer, SpsVuiRewriter::Direction::kIncoming);
|
||||
nalu_data, &sps, nullptr, &output_buffer,
|
||||
SpsVuiRewriter::Direction::kIncoming);
|
||||
switch (result) {
|
||||
case SpsVuiRewriter::ParseResult::kFailure:
|
||||
RTC_LOG(LS_WARNING) << "Failed to parse SPS NAL unit.";
|
||||
@ -179,9 +180,7 @@ absl::optional<VideoRtpDepacketizer::ParsedRtpPayload> ProcessStapAOrSingleNalu(
|
||||
case H264::NaluType::kPps: {
|
||||
uint32_t pps_id;
|
||||
uint32_t sps_id;
|
||||
if (PpsParser::ParsePpsIds(&payload_data[start_offset],
|
||||
end_offset - start_offset, &pps_id,
|
||||
&sps_id)) {
|
||||
if (PpsParser::ParsePpsIds(nalu_data, &pps_id, &sps_id)) {
|
||||
nalu.pps_id = pps_id;
|
||||
nalu.sps_id = sps_id;
|
||||
} else {
|
||||
@ -197,8 +196,7 @@ absl::optional<VideoRtpDepacketizer::ParsedRtpPayload> ProcessStapAOrSingleNalu(
|
||||
[[fallthrough]];
|
||||
case H264::NaluType::kSlice: {
|
||||
absl::optional<PpsParser::SliceHeader> slice_header =
|
||||
PpsParser::ParseSliceHeader(&payload_data[start_offset],
|
||||
end_offset - start_offset);
|
||||
PpsParser::ParseSliceHeader(nalu_data);
|
||||
if (slice_header) {
|
||||
nalu.pps_id = slice_header->pic_parameter_set_id;
|
||||
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 ||
|
||||
original_nal_type == H264::NaluType::kSlice) {
|
||||
absl::optional<PpsParser::SliceHeader> slice_header =
|
||||
PpsParser::ParseSliceHeader(rtp_payload.cdata() + 2 * kNalHeaderSize,
|
||||
rtp_payload.size() - 2 * kNalHeaderSize);
|
||||
PpsParser::ParseSliceHeader(rtc::ArrayView<const uint8_t>(rtp_payload)
|
||||
.subview(2 * kNalHeaderSize));
|
||||
if (slice_header) {
|
||||
nalu.pps_id = slice_header->pic_parameter_set_id;
|
||||
is_first_packet_in_frame = slice_header->first_mb_in_slice == 0;
|
||||
|
||||
@ -120,6 +120,8 @@ absl::optional<VideoRtpDepacketizer::ParsedRtpPayload> ProcessApOrSingleNalu(
|
||||
|
||||
uint8_t nalu_type = (payload_data[start_offset] & kH265TypeMask) >> 1;
|
||||
start_offset += kH265NalHeaderSizeBytes;
|
||||
rtc::ArrayView<const uint8_t> nalu_data(&payload_data[start_offset],
|
||||
end_offset - start_offset);
|
||||
switch (nalu_type) {
|
||||
case H265::NaluType::kBlaWLp:
|
||||
case H265::NaluType::kBlaWRadl:
|
||||
@ -141,8 +143,8 @@ absl::optional<VideoRtpDepacketizer::ParsedRtpPayload> ProcessApOrSingleNalu(
|
||||
if (start_offset)
|
||||
output_buffer->AppendData(payload_data, start_offset);
|
||||
|
||||
absl::optional<H265SpsParser::SpsState> sps = H265SpsParser::ParseSps(
|
||||
&payload_data[start_offset], end_offset - start_offset);
|
||||
absl::optional<H265SpsParser::SpsState> sps =
|
||||
H265SpsParser::ParseSps(nalu_data);
|
||||
|
||||
if (sps) {
|
||||
// TODO(bugs.webrtc.org/13485): Implement the size calculation taking
|
||||
|
||||
@ -381,7 +381,7 @@ void VideoCodecTestFixtureImpl::H264KeyframeChecker::CheckEncodedFrame(
|
||||
bool contains_pps = false;
|
||||
bool contains_idr = false;
|
||||
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) {
|
||||
webrtc::H264::NaluType nalu_type = webrtc::H264::ParseNaluType(
|
||||
encoded_frame.data()[index.payload_start_offset]);
|
||||
|
||||
@ -52,7 +52,7 @@ size_t GetMaxNaluSizeBytes(const EncodedImage& encoded_frame,
|
||||
return 0;
|
||||
|
||||
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());
|
||||
|
||||
|
||||
@ -217,9 +217,9 @@ void H264SpsPpsTracker::InsertSpsPpsNalus(const std::vector<uint8_t>& sps,
|
||||
return;
|
||||
}
|
||||
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(
|
||||
pps.data() + kNaluHeaderOffset, pps.size() - kNaluHeaderOffset);
|
||||
rtc::ArrayView<const uint8_t>(pps).subview(kNaluHeaderOffset));
|
||||
|
||||
if (!parsed_sps) {
|
||||
RTC_LOG(LS_WARNING) << "Failed to parse SPS.";
|
||||
|
||||
@ -85,8 +85,8 @@ int64_t* GetContinuousSequence(rtc::ArrayView<int64_t> last_continuous,
|
||||
|
||||
#ifdef RTC_ENABLE_H265
|
||||
bool HasVps(const H26xPacketBuffer::Packet& packet) {
|
||||
std::vector<H265::NaluIndex> nalu_indices = H265::FindNaluIndices(
|
||||
packet.video_payload.cdata(), packet.video_payload.size());
|
||||
std::vector<H265::NaluIndex> nalu_indices =
|
||||
H265::FindNaluIndices(packet.video_payload);
|
||||
return absl::c_any_of((nalu_indices), [&packet](
|
||||
const H265::NaluIndex& nalu_index) {
|
||||
return H265::ParseNaluType(
|
||||
@ -242,8 +242,8 @@ bool H26xPacketBuffer::MaybeAssembleFrame(int64_t start_seq_num_unwrapped,
|
||||
}
|
||||
#ifdef RTC_ENABLE_H265
|
||||
} else if (packet->codec() == kVideoCodecH265) {
|
||||
std::vector<H265::NaluIndex> nalu_indices = H265::FindNaluIndices(
|
||||
packet->video_payload.cdata(), packet->video_payload.size());
|
||||
std::vector<H265::NaluIndex> nalu_indices =
|
||||
H265::FindNaluIndices(packet->video_payload);
|
||||
for (const auto& nalu_index : nalu_indices) {
|
||||
uint8_t nalu_type = H265::ParseNaluType(
|
||||
packet->video_payload.cdata()[nalu_index.payload_start_offset]);
|
||||
@ -339,9 +339,9 @@ void H26xPacketBuffer::InsertSpsPpsNalus(const std::vector<uint8_t>& sps,
|
||||
return;
|
||||
}
|
||||
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(
|
||||
pps.data() + kNaluHeaderOffset, pps.size() - kNaluHeaderOffset);
|
||||
rtc::ArrayView<const uint8_t>(pps).subview(kNaluHeaderOffset));
|
||||
|
||||
if (!parsed_sps) {
|
||||
RTC_LOG(LS_WARNING) << "Failed to parse SPS.";
|
||||
|
||||
@ -259,7 +259,7 @@ AnnexBBufferReader::AnnexBBufferReader(const uint8_t* annexb_buffer,
|
||||
size_t length)
|
||||
: start_(annexb_buffer), length_(length) {
|
||||
RTC_DCHECK(annexb_buffer);
|
||||
offsets_ = H264::FindNaluIndices(annexb_buffer, length);
|
||||
offsets_ = H264::FindNaluIndices(rtc::MakeArrayView(annexb_buffer, length));
|
||||
offset_ = offsets_.begin();
|
||||
}
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user