Remove kMaxNalusPerPacket hard limit for H264 frames

Bug: webrtc:346608838
Change-Id: I067401250994bc57897edff8e8a18c3088d96b08
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/354622
Reviewed-by: Philip Eliasson <philipel@webrtc.org>
Commit-Queue: Danil Chapovalov <danilchap@webrtc.org>
Reviewed-by: Danil Chapovalov <danilchap@webrtc.org>
Cr-Commit-Position: refs/heads/main@{#42487}
This commit is contained in:
Sergio Garcia Murillo 2024-06-14 14:10:50 +02:00 committed by WebRTC LUCI CQ
parent 94fa6bf9f4
commit 469e69800f
17 changed files with 102 additions and 197 deletions

View File

@ -28,8 +28,7 @@ RTPVideoHeaderH264 ExampleHeaderH264() {
RTPVideoHeaderH264 header;
header.nalu_type = 4;
header.packetization_type = H264PacketizationTypes::kH264StapA;
header.nalus[0] = nalu_info;
header.nalus_length = 1;
header.nalus = {nalu_info};
header.packetization_mode = H264PacketizationMode::SingleNalUnit;
return header;
}

View File

@ -220,13 +220,7 @@ absl::optional<VideoRtpDepacketizer::ParsedRtpPayload> ProcessStapAOrSingleNalu(
return absl::nullopt;
}
if (h264_header.nalus_length == kMaxNalusPerPacket) {
RTC_LOG(LS_WARNING)
<< "Received packet containing more than " << kMaxNalusPerPacket
<< " NAL units. Will not keep track sps and pps ids for all of them.";
} else {
h264_header.nalus[h264_header.nalus_length++] = nalu;
}
h264_header.nalus.push_back(nalu);
}
return parsed_payload;
@ -284,8 +278,7 @@ absl::optional<VideoRtpDepacketizer::ParsedRtpPayload> ParseFuaNalu(
h264_header.packetization_type = kH264FuA;
h264_header.nalu_type = original_nal_type;
if (first_fragment) {
h264_header.nalus[h264_header.nalus_length] = nalu;
h264_header.nalus_length = 1;
h264_header.nalus = {nalu};
}
return parsed_payload;
}

View File

@ -125,15 +125,7 @@ TEST(VideoRtpDepacketizerH264Test, StapAKey) {
EXPECT_EQ(h264.packetization_type, kH264StapA);
// NALU type for aggregated packets is the type of the first packet only.
EXPECT_EQ(h264.nalu_type, kSps);
ASSERT_EQ(h264.nalus_length, 3u);
for (size_t i = 0; i < h264.nalus_length; ++i) {
EXPECT_EQ(h264.nalus[i].type, kExpectedNalus[i].type)
<< "Failed parsing nalu " << i;
EXPECT_EQ(h264.nalus[i].sps_id, kExpectedNalus[i].sps_id)
<< "Failed parsing nalu " << i;
EXPECT_EQ(h264.nalus[i].pps_id, kExpectedNalus[i].pps_id)
<< "Failed parsing nalu " << i;
}
EXPECT_THAT(h264.nalus, ElementsAreArray(kExpectedNalus));
}
TEST(VideoRtpDepacketizerH264Test, StapANaluSpsWithResolution) {
@ -327,7 +319,7 @@ TEST(VideoRtpDepacketizerH264Test, FuA) {
absl::get<RTPVideoHeaderH264>(parsed1->video_header.video_type_header);
EXPECT_EQ(h264.packetization_type, kH264FuA);
EXPECT_EQ(h264.nalu_type, kIdr);
ASSERT_EQ(h264.nalus_length, 1u);
ASSERT_THAT(h264.nalus, SizeIs(1));
EXPECT_EQ(h264.nalus[0].type, static_cast<H264::NaluType>(kIdr));
EXPECT_EQ(h264.nalus[0].sps_id, -1);
EXPECT_EQ(h264.nalus[0].pps_id, 0);
@ -347,7 +339,7 @@ TEST(VideoRtpDepacketizerH264Test, FuA) {
EXPECT_EQ(h264.packetization_type, kH264FuA);
EXPECT_EQ(h264.nalu_type, kIdr);
// NALU info is only expected for the first FU-A packet.
EXPECT_EQ(h264.nalus_length, 0u);
EXPECT_THAT(h264.nalus, IsEmpty());
}
auto parsed3 = depacketizer.Parse(rtc::CopyOnWriteBuffer(packet3));
@ -362,7 +354,7 @@ TEST(VideoRtpDepacketizerH264Test, FuA) {
EXPECT_EQ(h264.packetization_type, kH264FuA);
EXPECT_EQ(h264.nalu_type, kIdr);
// NALU info is only expected for the first FU-A packet.
ASSERT_EQ(h264.nalus_length, 0u);
EXPECT_THAT(h264.nalus, IsEmpty());
}
}
@ -409,7 +401,7 @@ TEST(VideoRtpDepacketizerH264Test, SeiPacket) {
EXPECT_EQ(parsed->video_header.frame_type, VideoFrameType::kVideoFrameDelta);
EXPECT_EQ(h264.packetization_type, kH264SingleNalu);
EXPECT_EQ(h264.nalu_type, kSei);
ASSERT_EQ(h264.nalus_length, 1u);
ASSERT_THAT(h264.nalus, SizeIs(1));
EXPECT_EQ(h264.nalus[0].type, static_cast<H264::NaluType>(kSei));
EXPECT_EQ(h264.nalus[0].sps_id, -1);
EXPECT_EQ(h264.nalus[0].pps_id, -1);

View File

@ -16,6 +16,7 @@
#include <algorithm>
#include <string>
#include <vector>
#include "modules/video_coding/codecs/interface/common_constants.h"
#include "rtc_base/checks.h"
@ -72,8 +73,6 @@ struct NaluInfo {
}
};
const size_t kMaxNalusPerPacket = 10;
struct RTPVideoHeaderH264 {
// The NAL unit type. If this is a header for a
// fragmented packet, it's the NAL unit type of
@ -83,8 +82,7 @@ struct RTPVideoHeaderH264 {
uint8_t nalu_type;
// The packetization type of this buffer - single, aggregated or fragmented.
H264PacketizationTypes packetization_type;
NaluInfo nalus[kMaxNalusPerPacket];
size_t nalus_length;
std::vector<NaluInfo> nalus;
// The packetization mode of this transport. Packetization mode
// determines which packetization types are allowed when packetizing.
H264PacketizationMode packetization_mode;
@ -93,8 +91,7 @@ struct RTPVideoHeaderH264 {
const RTPVideoHeaderH264& rhs) {
return lhs.nalu_type == rhs.nalu_type &&
lhs.packetization_type == rhs.packetization_type &&
std::equal(lhs.nalus, lhs.nalus + lhs.nalus_length, rhs.nalus,
rhs.nalus + rhs.nalus_length) &&
lhs.nalus == rhs.nalus &&
lhs.packetization_mode == rhs.packetization_mode;
}

View File

@ -134,6 +134,7 @@ rtc_library("deprecated_session_info") {
"../../../modules:module_api_public",
"../../../modules/video_coding:codec_globals_headers",
"../../../rtc_base:logging",
"//third_party/abseil-cpp/absl/algorithm:container",
"//third_party/abseil-cpp/absl/types:variant",
]
sources = [

View File

@ -903,10 +903,8 @@ TEST_F(TestBasicJitterBuffer, SpsAndPpsHandling) {
packet_->markerBit = true;
packet_->video_header.codec = kVideoCodecH264;
h264_header.nalu_type = H264::NaluType::kIdr;
h264_header.nalus[0].type = H264::NaluType::kIdr;
h264_header.nalus[0].sps_id = -1;
h264_header.nalus[0].pps_id = 0;
h264_header.nalus_length = 1;
h264_header.nalus = {
{.type = H264::NaluType::kIdr, .sps_id = -1, .pps_id = 0}};
bool retransmitted = false;
EXPECT_EQ(kCompleteSession,
jitter_buffer_->InsertPacket(*packet_, &retransmitted));
@ -922,13 +920,9 @@ TEST_F(TestBasicJitterBuffer, SpsAndPpsHandling) {
packet_->markerBit = false;
packet_->video_header.codec = kVideoCodecH264;
h264_header.nalu_type = H264::NaluType::kStapA;
h264_header.nalus[0].type = H264::NaluType::kSps;
h264_header.nalus[0].sps_id = 0;
h264_header.nalus[0].pps_id = -1;
h264_header.nalus[1].type = H264::NaluType::kPps;
h264_header.nalus[1].sps_id = 0;
h264_header.nalus[1].pps_id = 0;
h264_header.nalus_length = 2;
h264_header.nalus = {
{.type = H264::NaluType::kSps, .sps_id = 0, .pps_id = -1},
{.type = H264::NaluType::kPps, .sps_id = 0, .pps_id = 0}};
// Not complete since the marker bit hasn't been received.
EXPECT_EQ(kIncomplete,
jitter_buffer_->InsertPacket(*packet_, &retransmitted));
@ -940,10 +934,8 @@ TEST_F(TestBasicJitterBuffer, SpsAndPpsHandling) {
packet_->markerBit = true;
packet_->video_header.codec = kVideoCodecH264;
h264_header.nalu_type = H264::NaluType::kIdr;
h264_header.nalus[0].type = H264::NaluType::kIdr;
h264_header.nalus[0].sps_id = -1;
h264_header.nalus[0].pps_id = 0;
h264_header.nalus_length = 1;
h264_header.nalus = {
{.type = H264::NaluType::kIdr, .sps_id = -1, .pps_id = 0}};
// Complete and decodable since the pps and sps are received in the first
// packet of this frame.
EXPECT_EQ(kCompleteSession,
@ -961,10 +953,9 @@ TEST_F(TestBasicJitterBuffer, SpsAndPpsHandling) {
packet_->markerBit = true;
packet_->video_header.codec = kVideoCodecH264;
h264_header.nalu_type = H264::NaluType::kSlice;
h264_header.nalus[0].type = H264::NaluType::kSlice;
h264_header.nalus[0].sps_id = -1;
h264_header.nalus[0].pps_id = 0;
h264_header.nalus_length = 1;
h264_header.nalus = {
{.type = H264::NaluType::kIdr, .sps_id = -1, .pps_id = 0}};
// Complete and decodable since sps, pps and key frame has been received.
EXPECT_EQ(kCompleteSession,
jitter_buffer_->InsertPacket(*packet_, &retransmitted));

View File

@ -14,6 +14,7 @@
#include <vector>
#include "absl/algorithm/container.h"
#include "absl/types/variant.h"
#include "modules/include/module_common_types.h"
#include "modules/include/module_common_types_public.h"
@ -139,9 +140,7 @@ std::vector<NaluInfo> VCMSessionInfo::GetNaluInfos() const {
for (const VCMPacket& packet : packets_) {
const auto& h264 =
absl::get<RTPVideoHeaderH264>(packet.video_header.video_type_header);
for (size_t i = 0; i < h264.nalus_length; ++i) {
nalu_infos.push_back(h264.nalus[i]);
}
absl::c_copy(h264.nalus, std::back_inserter(nalu_infos));
}
return nalu_infos;
}

View File

@ -58,8 +58,7 @@ H264SpsPpsTracker::FixedBitstream H264SpsPpsTracker::CopyAndFixBitstream(
auto sps = sps_data_.end();
auto pps = pps_data_.end();
for (size_t i = 0; i < h264_header.nalus_length; ++i) {
const NaluInfo& nalu = h264_header.nalus[i];
for (const NaluInfo& nalu : h264_header.nalus) {
switch (nalu.type) {
case H264::NaluType::kSps: {
SpsInfo& sps_info = sps_data_[nalu.sps_id];
@ -140,7 +139,7 @@ H264SpsPpsTracker::FixedBitstream H264SpsPpsTracker::CopyAndFixBitstream(
nalu_ptr += segment_length;
}
} else {
if (h264_header.nalus_length > 0) {
if (!h264_header.nalus.empty()) {
required_size += sizeof(start_code_h264);
}
required_size += bitstream.size();
@ -160,21 +159,11 @@ H264SpsPpsTracker::FixedBitstream H264SpsPpsTracker::CopyAndFixBitstream(
fixed.bitstream.AppendData(pps->second.data.get(), pps->second.size);
// Update codec header to reflect the newly added SPS and PPS.
NaluInfo sps_info;
sps_info.type = H264::NaluType::kSps;
sps_info.sps_id = sps->first;
sps_info.pps_id = -1;
NaluInfo pps_info;
pps_info.type = H264::NaluType::kPps;
pps_info.sps_id = sps->first;
pps_info.pps_id = pps->first;
if (h264_header.nalus_length + 2 <= kMaxNalusPerPacket) {
h264_header.nalus[h264_header.nalus_length++] = sps_info;
h264_header.nalus[h264_header.nalus_length++] = pps_info;
} else {
RTC_LOG(LS_WARNING) << "Not enough space in H.264 codec header to insert "
"SPS/PPS provided out-of-band.";
}
h264_header.nalus.push_back(
{.type = H264::NaluType::kSps, .sps_id = sps->first, .pps_id = -1});
h264_header.nalus.push_back({.type = H264::NaluType::kPps,
.sps_id = sps->first,
.pps_id = pps->first});
}
// Copy the rest of the bitstream and insert start codes.
@ -196,7 +185,7 @@ H264SpsPpsTracker::FixedBitstream H264SpsPpsTracker::CopyAndFixBitstream(
nalu_ptr += segment_length;
}
} else {
if (h264_header.nalus_length > 0) {
if (!h264_header.nalus.empty()) {
fixed.bitstream.AppendData(start_code_h264);
}
fixed.bitstream.AppendData(bitstream.data(), bitstream.size());

View File

@ -66,8 +66,8 @@ class H264SpsPpsTracker {
std::unique_ptr<uint8_t[]> data;
};
std::map<uint32_t, PpsInfo> pps_data_;
std::map<uint32_t, SpsInfo> sps_data_;
std::map<int, PpsInfo> pps_data_;
std::map<int, SpsInfo> sps_data_;
};
} // namespace video_coding

View File

@ -26,6 +26,7 @@ namespace video_coding {
namespace {
using ::testing::ElementsAreArray;
using ::testing::SizeIs;
const uint8_t start_code[] = {0, 0, 0, 1};
@ -64,7 +65,6 @@ class H264VideoHeader : public RTPVideoHeader {
codec = kVideoCodecH264;
is_first_packet_in_frame = false;
auto& h264_header = video_type_header.emplace<RTPVideoHeaderH264>();
h264_header.nalus_length = 0;
h264_header.packetization_type = kH264SingleNalu;
}
@ -87,7 +87,7 @@ class TestH264SpsPpsTracker : public ::testing::Test {
data->push_back(H264::NaluType::kSps);
data->push_back(sps_id); // The sps data, just a single byte.
header->h264().nalus[header->h264().nalus_length++] = info;
header->h264().nalus.push_back(info);
}
void AddPps(H264VideoHeader* header,
@ -101,7 +101,7 @@ class TestH264SpsPpsTracker : public ::testing::Test {
data->push_back(H264::NaluType::kPps);
data->push_back(pps_id); // The pps data, just a single byte.
header->h264().nalus[header->h264().nalus_length++] = info;
header->h264().nalus.push_back(info);
}
void AddIdr(H264VideoHeader* header, int pps_id) {
@ -110,7 +110,7 @@ class TestH264SpsPpsTracker : public ::testing::Test {
info.sps_id = -1;
info.pps_id = pps_id;
header->h264().nalus[header->h264().nalus_length++] = info;
header->h264().nalus.push_back(info);
}
protected:
@ -133,7 +133,7 @@ TEST_F(TestH264SpsPpsTracker, FuAFirstPacket) {
uint8_t data[] = {1, 2, 3};
H264VideoHeader header;
header.h264().packetization_type = kH264FuA;
header.h264().nalus_length = 1;
header.h264().nalus.resize(1);
header.is_first_packet_in_frame = true;
H264SpsPpsTracker::FixedBitstream fixed =
@ -201,7 +201,7 @@ TEST_F(TestH264SpsPpsTracker, ConsecutiveStapA) {
TEST_F(TestH264SpsPpsTracker, SingleNaluInsertStartCode) {
uint8_t data[] = {1, 2, 3};
H264VideoHeader header;
header.h264().nalus_length = 1;
header.h264().nalus.resize(1);
H264SpsPpsTracker::FixedBitstream fixed =
tracker_.CopyAndFixBitstream(data, &header);
@ -217,8 +217,8 @@ TEST_F(TestH264SpsPpsTracker, NoStartCodeInsertedForSubsequentFuAPacket) {
std::vector<uint8_t> data = {1, 2, 3};
H264VideoHeader header;
header.h264().packetization_type = kH264FuA;
// Since no NALU begin in this packet the nalus_length is zero.
header.h264().nalus_length = 0;
// Since no NALU begin in this packet the nalus are empty.
header.h264().nalus.clear();
H264SpsPpsTracker::FixedBitstream fixed =
tracker_.CopyAndFixBitstream(data, &header);
@ -330,12 +330,12 @@ TEST_F(TestH264SpsPpsTracker, SpsPpsOutOfBand) {
H264VideoHeader idr_header;
idr_header.is_first_packet_in_frame = true;
AddIdr(&idr_header, 0);
EXPECT_EQ(idr_header.h264().nalus_length, 1u);
EXPECT_THAT(idr_header.h264().nalus, SizeIs(1));
H264SpsPpsTracker::FixedBitstream fixed =
tracker_.CopyAndFixBitstream(kData, &idr_header);
EXPECT_EQ(idr_header.h264().nalus_length, 3u);
EXPECT_THAT(idr_header.h264().nalus, SizeIs(3));
EXPECT_EQ(idr_header.width, 320u);
EXPECT_EQ(idr_header.height, 240u);
ExpectSpsPpsIdr(idr_header.h264(), 0, 0);

View File

@ -42,24 +42,15 @@ int64_t EuclideanMod(int64_t n, int64_t div) {
return (n %= div) < 0 ? n + div : n;
}
rtc::ArrayView<const NaluInfo> GetNaluInfos(
const RTPVideoHeaderH264& h264_header) {
if (h264_header.nalus_length > kMaxNalusPerPacket) {
return {};
}
return rtc::MakeArrayView(h264_header.nalus, h264_header.nalus_length);
}
bool IsFirstPacketOfFragment(const RTPVideoHeaderH264& h264_header) {
return h264_header.nalus_length > 0;
return !h264_header.nalus.empty();
}
bool BeginningOfIdr(const H26xPacketBuffer::Packet& packet) {
const auto& h264_header =
absl::get<RTPVideoHeaderH264>(packet.video_header.video_type_header);
const bool contains_idr_nalu =
absl::c_any_of(GetNaluInfos(h264_header), [](const auto& nalu_info) {
absl::c_any_of(h264_header.nalus, [](const auto& nalu_info) {
return nalu_info.type == H264::NaluType::kIdr;
});
switch (h264_header.packetization_type) {
@ -76,7 +67,7 @@ bool BeginningOfIdr(const H26xPacketBuffer::Packet& packet) {
bool HasSps(const H26xPacketBuffer::Packet& packet) {
auto& h264_header =
absl::get<RTPVideoHeaderH264>(packet.video_header.video_type_header);
return absl::c_any_of(GetNaluInfos(h264_header), [](const auto& nalu_info) {
return absl::c_any_of(h264_header.nalus, [](const auto& nalu_info) {
return nalu_info.type == H264::NaluType::kSps;
});
}
@ -219,7 +210,7 @@ bool H26xPacketBuffer::MaybeAssembleFrame(int64_t start_seq_num_unwrapped,
if (packet->codec() == kVideoCodecH264) {
const auto& h264_header =
absl::get<RTPVideoHeaderH264>(packet->video_header.video_type_header);
for (const auto& nalu : GetNaluInfos(h264_header)) {
for (const auto& nalu : h264_header.nalus) {
has_idr |= nalu.type == H264::NaluType::kIdr;
has_sps |= nalu.type == H264::NaluType::kSps;
has_pps |= nalu.type == H264::NaluType::kPps;
@ -383,8 +374,7 @@ bool H26xPacketBuffer::FixH264Packet(Packet& packet) {
auto sps = sps_data_.end();
auto pps = pps_data_.end();
for (size_t i = 0; i < h264_header.nalus_length; ++i) {
const NaluInfo& nalu = h264_header.nalus[i];
for (const NaluInfo& nalu : h264_header.nalus) {
switch (nalu.type) {
case H264::NaluType::kSps: {
SpsInfo& sps_info = sps_data_[nalu.sps_id];
@ -456,22 +446,11 @@ bool H26xPacketBuffer::FixH264Packet(Packet& packet) {
result.AppendData(pps->second.payload.get(), pps->second.size);
// Update codec header to reflect the newly added SPS and PPS.
NaluInfo sps_info;
sps_info.type = H264::NaluType::kSps;
sps_info.sps_id = sps->first;
sps_info.pps_id = -1;
NaluInfo pps_info;
pps_info.type = H264::NaluType::kPps;
pps_info.sps_id = sps->first;
pps_info.pps_id = pps->first;
if (h264_header.nalus_length + 2 <= kMaxNalusPerPacket) {
h264_header.nalus[h264_header.nalus_length++] = sps_info;
h264_header.nalus[h264_header.nalus_length++] = pps_info;
} else {
RTC_LOG(LS_WARNING)
<< "Not enough space in H.264 codec header to insert "
"SPS/PPS provided out-of-band.";
}
h264_header.nalus.push_back(
{.type = H264::NaluType::kSps, .sps_id = sps->first, .pps_id = -1});
h264_header.nalus.push_back({.type = H264::NaluType::kPps,
.sps_id = sps->first,
.pps_id = pps->first});
}
}

View File

@ -96,10 +96,10 @@ class H26xPacketBuffer {
// Map from pps_pic_parameter_set_id to the PPS payload associated with this
// ID.
std::map<uint32_t, PpsInfo> pps_data_;
std::map<int, PpsInfo> pps_data_;
// Map from sps_video_parameter_set_id to the SPS payload associated with this
// ID.
std::map<uint32_t, SpsInfo> sps_data_;
std::map<int, SpsInfo> sps_data_;
};
} // namespace webrtc

View File

@ -109,14 +109,14 @@ H264Packet& H264Packet::Idr(std::vector<uint8_t> payload, int pps_id) {
auto& h264_header = H264Header();
auto nalu_info = MakeNaluInfo(kIdr);
nalu_info.pps_id = pps_id;
h264_header.nalus[h264_header.nalus_length++] = nalu_info;
h264_header.nalus.push_back(nalu_info);
nalu_payloads_.push_back(std::move(payload));
return *this;
}
H264Packet& H264Packet::Slice(std::vector<uint8_t> payload) {
auto& h264_header = H264Header();
h264_header.nalus[h264_header.nalus_length++] = MakeNaluInfo(kSlice);
h264_header.nalus.push_back(MakeNaluInfo(kSlice));
nalu_payloads_.push_back(std::move(payload));
return *this;
}
@ -125,7 +125,7 @@ H264Packet& H264Packet::Sps(std::vector<uint8_t> payload, int sps_id) {
auto& h264_header = H264Header();
auto nalu_info = MakeNaluInfo(kSps);
nalu_info.pps_id = sps_id;
h264_header.nalus[h264_header.nalus_length++] = nalu_info;
h264_header.nalus.push_back(nalu_info);
nalu_payloads_.push_back(std::move(payload));
return *this;
}
@ -133,7 +133,7 @@ H264Packet& H264Packet::Sps(std::vector<uint8_t> payload, int sps_id) {
H264Packet& H264Packet::SpsWithResolution(RenderResolution resolution,
std::vector<uint8_t> payload) {
auto& h264_header = H264Header();
h264_header.nalus[h264_header.nalus_length++] = MakeNaluInfo(kSps);
h264_header.nalus.push_back(MakeNaluInfo(kSps));
video_header_.width = resolution.Width();
video_header_.height = resolution.Height();
nalu_payloads_.push_back(std::move(payload));
@ -147,14 +147,14 @@ H264Packet& H264Packet::Pps(std::vector<uint8_t> payload,
auto nalu_info = MakeNaluInfo(kPps);
nalu_info.pps_id = pps_id;
nalu_info.sps_id = sps_id;
h264_header.nalus[h264_header.nalus_length++] = nalu_info;
h264_header.nalus.push_back(nalu_info);
nalu_payloads_.push_back(std::move(payload));
return *this;
}
H264Packet& H264Packet::Aud() {
auto& h264_header = H264Header();
h264_header.nalus[h264_header.nalus_length++] = MakeNaluInfo(kAud);
h264_header.nalus.push_back(MakeNaluInfo(kAud));
nalu_payloads_.push_back({});
return *this;
}
@ -185,25 +185,24 @@ std::unique_ptr<H26xPacketBuffer::Packet> H264Packet::Build() {
auto& h264_header = H264Header();
switch (type_) {
case kH264FuA: {
RTC_CHECK_EQ(h264_header.nalus_length, 1);
RTC_CHECK_EQ(h264_header.nalus.size(), 1);
res->video_payload = BuildFuaPayload();
break;
}
case kH264SingleNalu: {
RTC_CHECK_EQ(h264_header.nalus_length, 1);
RTC_CHECK_EQ(h264_header.nalus.size(), 1);
res->video_payload = BuildSingleNaluPayload();
break;
}
case kH264StapA: {
RTC_CHECK_GT(h264_header.nalus_length, 1);
RTC_CHECK_LE(h264_header.nalus_length, kMaxNalusPerPacket);
RTC_CHECK_GT(h264_header.nalus.size(), 1);
res->video_payload = BuildStapAPayload();
break;
}
}
if (type_ == kH264FuA && !first_fragment_) {
h264_header.nalus_length = 0;
h264_header.nalus.clear();
}
h264_header.packetization_type = type_;
@ -235,7 +234,7 @@ rtc::CopyOnWriteBuffer H264Packet::BuildStapAPayload() const {
res.AppendData(&indicator, 1);
auto& h264_header = H264Header();
for (size_t i = 0; i < h264_header.nalus_length; ++i) {
for (size_t i = 0; i < h264_header.nalus.size(); ++i) {
// The two first bytes indicates the nalu segment size.
uint8_t length_as_array[2] = {
0, static_cast<uint8_t>(nalu_payloads_[i].size() + 1)};
@ -1044,24 +1043,6 @@ TEST(H26xPacketBufferTest, FullPacketBufferDoesNotBlockKeyframe) {
SizeIs(1));
}
TEST(H26xPacketBufferTest, TooManyNalusInPacket) {
H26xPacketBuffer packet_buffer(/*h264_allow_idr_only_keyframes=*/false);
std::unique_ptr<H26xPacketBuffer::Packet> packet(H264Packet(kH264StapA)
.Sps()
.Pps()
.Idr()
.SeqNum(1)
.Time(1)
.Marker()
.Build());
auto& h264_header =
absl::get<RTPVideoHeaderH264>(packet->video_header.video_type_header);
h264_header.nalus_length = kMaxNalusPerPacket + 1;
EXPECT_THAT(packet_buffer.InsertPacket(std::move(packet)).packets, IsEmpty());
}
#ifdef RTC_ENABLE_H265
TEST(H26xPacketBufferTest, H265VpsSpsPpsIdrIsKeyframe) {
H26xPacketBuffer packet_buffer(/*allow_idr_only_keyframes=*/false);

View File

@ -287,15 +287,15 @@ std::vector<std::unique_ptr<PacketBuffer::Packet>> PacketBuffer::FindFrames(
if (is_h264_descriptor) {
const auto* h264_header = absl::get_if<RTPVideoHeaderH264>(
&buffer_[start_index]->video_header.video_type_header);
if (!h264_header || h264_header->nalus_length >= kMaxNalusPerPacket)
if (!h264_header)
return found_frames;
for (size_t j = 0; j < h264_header->nalus_length; ++j) {
if (h264_header->nalus[j].type == H264::NaluType::kSps) {
for (const NaluInfo& nalu : h264_header->nalus) {
if (nalu.type == H264::NaluType::kSps) {
has_h264_sps = true;
} else if (h264_header->nalus[j].type == H264::NaluType::kPps) {
} else if (nalu.type == H264::NaluType::kPps) {
has_h264_pps = true;
} else if (h264_header->nalus[j].type == H264::NaluType::kIdr) {
} else if (nalu.type == H264::NaluType::kIdr) {
has_h264_idr = true;
}
}

View File

@ -416,13 +416,11 @@ class PacketBufferH264Test : public PacketBufferTest {
packet->timestamp = timestamp;
if (keyframe == kKeyFrame) {
if (sps_pps_idr_is_keyframe_) {
h264_header.nalus[0].type = H264::NaluType::kSps;
h264_header.nalus[1].type = H264::NaluType::kPps;
h264_header.nalus[2].type = H264::NaluType::kIdr;
h264_header.nalus_length = 3;
h264_header.nalus = {{H264::NaluType::kSps},
{H264::NaluType::kPps},
{H264::NaluType::kIdr}};
} else {
h264_header.nalus[0].type = H264::NaluType::kIdr;
h264_header.nalus_length = 1;
h264_header.nalus = {{H264::NaluType::kIdr}};
}
}
packet->video_header.width = width;
@ -458,8 +456,7 @@ class PacketBufferH264Test : public PacketBufferTest {
RTC_CHECK(first == kFirst);
// Insert a AUD NALU / packet without width/height.
h264_header.nalus[0].type = H264::NaluType::kAud;
h264_header.nalus_length = 1;
h264_header.nalus = {{H264::NaluType::kAud}};
packet->video_header.is_first_packet_in_frame = true;
packet->video_header.is_last_packet_in_frame = false;
IgnoreResult(packet_buffer_.InsertPacket(std::move(packet)));
@ -524,8 +521,7 @@ TEST_P(PacketBufferH264ParameterizedTest, GetBitstreamBufferPadding) {
auto packet = std::make_unique<PacketBuffer::Packet>();
auto& h264_header =
packet->video_header.video_type_header.emplace<RTPVideoHeaderH264>();
h264_header.nalus_length = 1;
h264_header.nalus[0].type = H264::NaluType::kIdr;
h264_header.nalus = {{H264::NaluType::kIdr}};
h264_header.packetization_type = kH264SingleNalu;
packet->seq_num = seq_num;
packet->video_header.codec = kVideoCodecH264;
@ -641,7 +637,7 @@ TEST_F(PacketBufferTest, IncomingCodecChange) {
packet->video_header.codec = kVideoCodecH264;
auto& h264_header =
packet->video_header.video_type_header.emplace<RTPVideoHeaderH264>();
h264_header.nalus_length = 1;
h264_header.nalus.resize(1);
packet->timestamp = 3;
packet->seq_num = 3;
packet->video_header.frame_type = VideoFrameType::kVideoFrameKey;
@ -660,21 +656,6 @@ TEST_F(PacketBufferTest, IncomingCodecChange) {
SizeIs(2));
}
TEST_F(PacketBufferTest, TooManyNalusInPacket) {
auto packet = std::make_unique<PacketBuffer::Packet>();
packet->video_header.codec = kVideoCodecH264;
packet->timestamp = 1;
packet->seq_num = 1;
packet->video_header.frame_type = VideoFrameType::kVideoFrameKey;
packet->video_header.is_first_packet_in_frame = true;
packet->video_header.is_last_packet_in_frame = true;
auto& h264_header =
packet->video_header.video_type_header.emplace<RTPVideoHeaderH264>();
h264_header.nalus_length = kMaxNalusPerPacket;
EXPECT_THAT(packet_buffer_.InsertPacket(std::move(packet)).packets,
IsEmpty());
}
TEST_P(PacketBufferH264ParameterizedTest, OneFrameFillBuffer) {
InsertH264(0, kKeyFrame, kFirst, kNotLast, 1000);
for (int i = 1; i < kStartSize - 1; ++i)
@ -771,8 +752,7 @@ TEST_F(PacketBufferH264IdrIsKeyframeTest, IdrIsKeyframe) {
auto packet = CreatePacket();
auto& h264_header =
packet->video_header.video_type_header.emplace<RTPVideoHeaderH264>();
h264_header.nalus[0].type = H264::NaluType::kIdr;
h264_header.nalus_length = 1;
h264_header.nalus = {{H264::NaluType::kIdr}};
EXPECT_THAT(packet_buffer_.InsertPacket(std::move(packet)).packets,
ElementsAre(KeyFrame()));
}
@ -781,10 +761,8 @@ TEST_F(PacketBufferH264IdrIsKeyframeTest, SpsPpsIdrIsKeyframe) {
auto packet = CreatePacket();
auto& h264_header =
packet->video_header.video_type_header.emplace<RTPVideoHeaderH264>();
h264_header.nalus[0].type = H264::NaluType::kSps;
h264_header.nalus[1].type = H264::NaluType::kPps;
h264_header.nalus[2].type = H264::NaluType::kIdr;
h264_header.nalus_length = 3;
h264_header.nalus = {
{H264::NaluType::kSps}, {H264::NaluType::kPps}, {H264::NaluType::kIdr}};
EXPECT_THAT(packet_buffer_.InsertPacket(std::move(packet)).packets,
ElementsAre(KeyFrame()));
@ -801,8 +779,7 @@ TEST_F(PacketBufferH264SpsPpsIdrIsKeyframeTest, IdrIsNotKeyframe) {
auto packet = CreatePacket();
auto& h264_header =
packet->video_header.video_type_header.emplace<RTPVideoHeaderH264>();
h264_header.nalus[0].type = H264::NaluType::kIdr;
h264_header.nalus_length = 1;
h264_header.nalus = {{H264::NaluType::kIdr}};
EXPECT_THAT(packet_buffer_.InsertPacket(std::move(packet)).packets,
ElementsAre(DeltaFrame()));
@ -812,9 +789,7 @@ TEST_F(PacketBufferH264SpsPpsIdrIsKeyframeTest, SpsPpsIsNotKeyframe) {
auto packet = CreatePacket();
auto& h264_header =
packet->video_header.video_type_header.emplace<RTPVideoHeaderH264>();
h264_header.nalus[0].type = H264::NaluType::kSps;
h264_header.nalus[1].type = H264::NaluType::kPps;
h264_header.nalus_length = 2;
h264_header.nalus = {{H264::NaluType::kSps}, {H264::NaluType::kPps}};
EXPECT_THAT(packet_buffer_.InsertPacket(std::move(packet)).packets,
ElementsAre(DeltaFrame()));
@ -824,10 +799,8 @@ TEST_F(PacketBufferH264SpsPpsIdrIsKeyframeTest, SpsPpsIdrIsKeyframe) {
auto packet = CreatePacket();
auto& h264_header =
packet->video_header.video_type_header.emplace<RTPVideoHeaderH264>();
h264_header.nalus[0].type = H264::NaluType::kSps;
h264_header.nalus[1].type = H264::NaluType::kPps;
h264_header.nalus[2].type = H264::NaluType::kIdr;
h264_header.nalus_length = 3;
h264_header.nalus = {
{H264::NaluType::kSps}, {H264::NaluType::kPps}, {H264::NaluType::kIdr}};
EXPECT_THAT(packet_buffer_.InsertPacket(std::move(packet)).packets,
ElementsAre(KeyFrame()));

View File

@ -56,6 +56,18 @@ class DataReader {
size_t offset_ = 0;
};
RTPVideoHeaderH264 GenerateRTPVideoHeaderH264(DataReader* reader) {
RTPVideoHeaderH264 result;
result.nalu_type = reader->GetNum<uint8_t>();
result.packetization_type = reader->GetNum<H264PacketizationTypes>();
int nalus_length = reader->GetNum<uint8_t>();
for (int i = 0; i < nalus_length; ++i) {
reader->CopyTo(&result.nalus.emplace_back());
}
result.packetization_mode = reader->GetNum<H264PacketizationMode>();
return result;
}
absl::optional<RTPVideoHeader::GenericDescriptorInfo>
GenerateGenericFrameDependencies(DataReader* reader) {
absl::optional<RTPVideoHeader::GenericDescriptorInfo> result;
@ -117,8 +129,7 @@ void FuzzOneInput(const uint8_t* data, size_t size) {
&video_header.video_type_header.emplace<RTPVideoHeaderVP9>());
break;
case kVideoCodecH264:
reader.CopyTo(
&video_header.video_type_header.emplace<RTPVideoHeaderH264>());
video_header.video_type_header = GenerateRTPVideoHeaderH264(&reader);
break;
case kVideoCodecH265:
// TODO(bugs.webrtc.org/13485)

View File

@ -188,7 +188,7 @@ class RtpVideoStreamReceiver2Test : public ::testing::Test,
info.pps_id = -1;
data->AppendData<uint8_t, 2>({H264::NaluType::kSps, sps_id});
auto& h264 = absl::get<RTPVideoHeaderH264>(video_header->video_type_header);
h264.nalus[h264.nalus_length++] = info;
h264.nalus.push_back(info);
}
void AddPps(RTPVideoHeader* video_header,
@ -201,7 +201,7 @@ class RtpVideoStreamReceiver2Test : public ::testing::Test,
info.pps_id = pps_id;
data->AppendData<uint8_t, 2>({H264::NaluType::kPps, pps_id});
auto& h264 = absl::get<RTPVideoHeaderH264>(video_header->video_type_header);
h264.nalus[h264.nalus_length++] = info;
h264.nalus.push_back(info);
}
void AddIdr(RTPVideoHeader* video_header, int pps_id) {
@ -210,7 +210,7 @@ class RtpVideoStreamReceiver2Test : public ::testing::Test,
info.sps_id = -1;
info.pps_id = pps_id;
auto& h264 = absl::get<RTPVideoHeaderH264>(video_header->video_type_header);
h264.nalus[h264.nalus_length++] = info;
h264.nalus.push_back(info);
}
void OnRtpPacket(const RtpPacketReceived& packet) override {