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:
parent
94fa6bf9f4
commit
469e69800f
@ -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;
|
||||
}
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
|
||||
@ -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 = [
|
||||
|
||||
@ -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));
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -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());
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@ -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()));
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -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 {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user