diff --git a/modules/rtp_rtcp/source/rtp_format.cc b/modules/rtp_rtcp/source/rtp_format.cc index 28f63f1109..f6f4a48f04 100644 --- a/modules/rtp_rtcp/source/rtp_format.cc +++ b/modules/rtp_rtcp/source/rtp_format.cc @@ -31,7 +31,7 @@ std::unique_ptr RtpPacketizer::Create( PayloadSizeLimits limits, // Codec-specific details. const RTPVideoHeader& rtp_video_header, - const RTPFragmentationHeader* fragmentation) { + const RTPFragmentationHeader* /*fragmentation*/) { if (!type) { // Use raw packetizer. return std::make_unique(payload, limits); @@ -39,11 +39,10 @@ std::unique_ptr RtpPacketizer::Create( switch (*type) { case kVideoCodecH264: { - RTC_CHECK(fragmentation); const auto& h264 = absl::get(rtp_video_header.video_type_header); - return std::make_unique( - payload, limits, h264.packetization_mode, *fragmentation); + return std::make_unique(payload, limits, + h264.packetization_mode); } case kVideoCodecVP8: { const auto& vp8 = diff --git a/modules/rtp_rtcp/source/rtp_format_h264.cc b/modules/rtp_rtcp/source/rtp_format_h264.cc index 6f19e38629..6c3966cb93 100644 --- a/modules/rtp_rtcp/source/rtp_format_h264.cc +++ b/modules/rtp_rtcp/source/rtp_format_h264.cc @@ -25,7 +25,6 @@ #include "common_video/h264/pps_parser.h" #include "common_video/h264/sps_parser.h" #include "common_video/h264/sps_vui_rewriter.h" -#include "modules/include/module_common_types.h" #include "modules/rtp_rtcp/source/byte_io.h" #include "modules/rtp_rtcp/source/rtp_packet_to_send.h" #include "rtc_base/checks.h" @@ -46,19 +45,18 @@ enum FuDefs : uint8_t { kSBit = 0x80, kEBit = 0x40, kRBit = 0x20 }; } // namespace -RtpPacketizerH264::RtpPacketizerH264( - rtc::ArrayView payload, - PayloadSizeLimits limits, - H264PacketizationMode packetization_mode, - const RTPFragmentationHeader& fragmentation) +RtpPacketizerH264::RtpPacketizerH264(rtc::ArrayView payload, + PayloadSizeLimits limits, + H264PacketizationMode packetization_mode) : limits_(limits), num_packets_left_(0) { // Guard against uninitialized memory in packetization_mode. RTC_CHECK(packetization_mode == H264PacketizationMode::NonInterleaved || packetization_mode == H264PacketizationMode::SingleNalUnit); - for (size_t i = 0; i < fragmentation.fragmentationVectorSize; ++i) { + for (const auto& nalu : + H264::FindNaluIndices(payload.data(), payload.size())) { input_fragments_.push_back( - payload.subview(fragmentation.Offset(i), fragmentation.Length(i))); + payload.subview(nalu.payload_start_offset, nalu.payload_size)); } if (!GeneratePackets(packetization_mode)) { diff --git a/modules/rtp_rtcp/source/rtp_format_h264.h b/modules/rtp_rtcp/source/rtp_format_h264.h index 4661dc2163..7c10dd5754 100644 --- a/modules/rtp_rtcp/source/rtp_format_h264.h +++ b/modules/rtp_rtcp/source/rtp_format_h264.h @@ -19,7 +19,6 @@ #include #include "api/array_view.h" -#include "modules/include/module_common_types.h" #include "modules/rtp_rtcp/source/rtp_format.h" #include "modules/rtp_rtcp/source/rtp_packet_to_send.h" #include "modules/video_coding/codecs/h264/include/h264_globals.h" @@ -34,8 +33,7 @@ class RtpPacketizerH264 : public RtpPacketizer { // The payload_data must be exactly one encoded H264 frame. RtpPacketizerH264(rtc::ArrayView payload, PayloadSizeLimits limits, - H264PacketizationMode packetization_mode, - const RTPFragmentationHeader& fragmentation); + H264PacketizationMode packetization_mode); ~RtpPacketizerH264() override; diff --git a/modules/rtp_rtcp/source/rtp_format_h264_unittest.cc b/modules/rtp_rtcp/source/rtp_format_h264_unittest.cc index bf9771ab9f..9f660b7a74 100644 --- a/modules/rtp_rtcp/source/rtp_format_h264_unittest.cc +++ b/modules/rtp_rtcp/source/rtp_format_h264_unittest.cc @@ -13,9 +13,9 @@ #include #include +#include "absl/algorithm/container.h" #include "api/array_view.h" #include "common_video/h264/h264_common.h" -#include "modules/include/module_common_types.h" #include "modules/rtp_rtcp/mocks/mock_rtp_rtcp.h" #include "modules/rtp_rtcp/source/byte_io.h" #include "modules/rtp_rtcp/source/rtp_packet_to_send.h" @@ -56,45 +56,61 @@ enum NalDefs { kFBit = 0x80, kNriMask = 0x60, kTypeMask = 0x1F }; // Bit masks for FU (A and B) headers. enum FuDefs { kSBit = 0x80, kEBit = 0x40, kRBit = 0x20 }; -RTPFragmentationHeader CreateFragmentation(rtc::ArrayView sizes) { - RTPFragmentationHeader fragmentation; - fragmentation.VerifyAndAllocateFragmentationHeader(sizes.size()); - size_t offset = 0; - for (size_t i = 0; i < sizes.size(); ++i) { - fragmentation.fragmentationOffset[i] = offset; - fragmentation.fragmentationLength[i] = sizes[i]; - offset += sizes[i]; - } - return fragmentation; -} - -// Create fragmentation with single fragment of same size as |frame| -RTPFragmentationHeader NoFragmentation(rtc::ArrayView frame) { - size_t frame_size[] = {frame.size()}; - return CreateFragmentation(frame_size); -} - -// Create frame of given size. -rtc::Buffer CreateFrame(size_t frame_size) { - rtc::Buffer frame(frame_size); +// Creates Buffer that looks like nal unit of given size. +rtc::Buffer GenerateNalUnit(size_t size) { + RTC_CHECK_GT(size, 0); + rtc::Buffer buffer(size); // Set some valid header. - frame[0] = 0x01; - // Generate payload to detect when shifted payload was put into a packet. - for (size_t i = 1; i < frame_size; ++i) - frame[i] = static_cast(i); + buffer[0] = kSlice; + for (size_t i = 1; i < size; ++i) { + buffer[i] = static_cast(i); + } + // Last byte shouldn't be 0, or it may be counted as part of next 4-byte start + // sequence. + buffer[size - 1] |= 0x10; + return buffer; +} + +// Create frame consisting of nalus of given size. +rtc::Buffer CreateFrame(std::initializer_list nalu_sizes) { + static constexpr int kStartCodeSize = 3; + rtc::Buffer frame(absl::c_accumulate(nalu_sizes, 0) + + kStartCodeSize * nalu_sizes.size()); + size_t offset = 0; + for (size_t nalu_size : nalu_sizes) { + EXPECT_GE(nalu_size, 1u); + // Insert nalu start code + frame[offset] = 0; + frame[offset + 1] = 0; + frame[offset + 2] = 1; + // Set some valid header. + frame[offset + 3] = 1; + // Fill payload avoiding accidental start codes + if (nalu_size > 1) { + memset(frame.data() + offset + 4, 0x3f, nalu_size - 1); + } + offset += (kStartCodeSize + nalu_size); + } return frame; } -// Create frame with size deduced from fragmentation. -rtc::Buffer CreateFrame(const RTPFragmentationHeader& fragmentation) { - size_t last_frame_index = fragmentation.fragmentationVectorSize - 1; - size_t frame_size = fragmentation.fragmentationOffset[last_frame_index] + - fragmentation.fragmentationLength[last_frame_index]; - rtc::Buffer frame = CreateFrame(frame_size); - // Set some headers. - // Tests can expect those are valid but shouln't rely on actual values. - for (size_t i = 0; i <= last_frame_index; ++i) { - frame[fragmentation.fragmentationOffset[i]] = i + 1; +// Create frame consisting of given nalus. +rtc::Buffer CreateFrame(rtc::ArrayView nalus) { + static constexpr int kStartCodeSize = 3; + int frame_size = 0; + for (const rtc::Buffer& nalu : nalus) { + frame_size += (kStartCodeSize + nalu.size()); + } + rtc::Buffer frame(frame_size); + size_t offset = 0; + for (const rtc::Buffer& nalu : nalus) { + // Insert nalu start code + frame[offset] = 0; + frame[offset + 1] = 0; + frame[offset + 2] = 1; + // Copy the nalu unit. + memcpy(frame.data() + offset + 3, nalu.data(), nalu.size()); + offset += (kStartCodeSize + nalu.size()); } return frame; } @@ -117,31 +133,28 @@ class RtpPacketizerH264ModeTest : public ::testing::TestWithParam {}; TEST_P(RtpPacketizerH264ModeTest, SingleNalu) { - const uint8_t frame[2] = {kIdr, 0xFF}; + const uint8_t frame[] = {0, 0, 1, kIdr, 0xFF}; - RtpPacketizerH264 packetizer(frame, kNoLimits, GetParam(), - NoFragmentation(frame)); + RtpPacketizerH264 packetizer(frame, kNoLimits, GetParam()); std::vector packets = FetchAllPackets(&packetizer); ASSERT_THAT(packets, SizeIs(1)); - EXPECT_THAT(packets[0].payload(), ElementsAreArray(frame)); + EXPECT_THAT(packets[0].payload(), ElementsAre(kIdr, 0xFF)); } TEST_P(RtpPacketizerH264ModeTest, SingleNaluTwoPackets) { RtpPacketizer::PayloadSizeLimits limits; limits.max_payload_len = kMaxPayloadSize; - const size_t fragment_sizes[] = {kMaxPayloadSize, 100}; - RTPFragmentationHeader fragmentation = CreateFragmentation(fragment_sizes); - rtc::Buffer frame = CreateFrame(fragmentation); + rtc::Buffer nalus[] = {GenerateNalUnit(kMaxPayloadSize), + GenerateNalUnit(100)}; + rtc::Buffer frame = CreateFrame(nalus); - RtpPacketizerH264 packetizer(frame, limits, GetParam(), fragmentation); + RtpPacketizerH264 packetizer(frame, limits, GetParam()); std::vector packets = FetchAllPackets(&packetizer); ASSERT_THAT(packets, SizeIs(2)); - EXPECT_THAT(packets[0].payload(), - ElementsAreArray(frame.data(), kMaxPayloadSize)); - EXPECT_THAT(packets[1].payload(), - ElementsAreArray(frame.data() + kMaxPayloadSize, 100)); + EXPECT_THAT(packets[0].payload(), ElementsAreArray(nalus[0])); + EXPECT_THAT(packets[1].payload(), ElementsAreArray(nalus[1])); } TEST_P(RtpPacketizerH264ModeTest, @@ -149,21 +162,18 @@ TEST_P(RtpPacketizerH264ModeTest, RtpPacketizer::PayloadSizeLimits limits; limits.max_payload_len = 200; limits.first_packet_reduction_len = 5; - const size_t fragments[] = {195, 200, 200}; + rtc::Buffer nalus[] = {GenerateNalUnit(/*size=*/195), + GenerateNalUnit(/*size=*/200), + GenerateNalUnit(/*size=*/200)}; + rtc::Buffer frame = CreateFrame(nalus); - RTPFragmentationHeader fragmentation = CreateFragmentation(fragments); - rtc::Buffer frame = CreateFrame(fragmentation); - - RtpPacketizerH264 packetizer(frame, limits, GetParam(), fragmentation); + RtpPacketizerH264 packetizer(frame, limits, GetParam()); std::vector packets = FetchAllPackets(&packetizer); ASSERT_THAT(packets, SizeIs(3)); - const uint8_t* next_fragment = frame.data(); - EXPECT_THAT(packets[0].payload(), ElementsAreArray(next_fragment, 195)); - next_fragment += 195; - EXPECT_THAT(packets[1].payload(), ElementsAreArray(next_fragment, 200)); - next_fragment += 200; - EXPECT_THAT(packets[2].payload(), ElementsAreArray(next_fragment, 200)); + EXPECT_THAT(packets[0].payload(), ElementsAreArray(nalus[0])); + EXPECT_THAT(packets[1].payload(), ElementsAreArray(nalus[1])); + EXPECT_THAT(packets[2].payload(), ElementsAreArray(nalus[2])); } TEST_P(RtpPacketizerH264ModeTest, @@ -171,21 +181,18 @@ TEST_P(RtpPacketizerH264ModeTest, RtpPacketizer::PayloadSizeLimits limits; limits.max_payload_len = 200; limits.last_packet_reduction_len = 5; - const size_t fragments[] = {200, 200, 195}; + rtc::Buffer nalus[] = {GenerateNalUnit(/*size=*/200), + GenerateNalUnit(/*size=*/200), + GenerateNalUnit(/*size=*/195)}; + rtc::Buffer frame = CreateFrame(nalus); - RTPFragmentationHeader fragmentation = CreateFragmentation(fragments); - rtc::Buffer frame = CreateFrame(fragmentation); - - RtpPacketizerH264 packetizer(frame, limits, GetParam(), fragmentation); + RtpPacketizerH264 packetizer(frame, limits, GetParam()); std::vector packets = FetchAllPackets(&packetizer); ASSERT_THAT(packets, SizeIs(3)); - const uint8_t* next_fragment = frame.data(); - EXPECT_THAT(packets[0].payload(), ElementsAreArray(next_fragment, 200)); - next_fragment += 200; - EXPECT_THAT(packets[1].payload(), ElementsAreArray(next_fragment, 200)); - next_fragment += 200; - EXPECT_THAT(packets[2].payload(), ElementsAreArray(next_fragment, 195)); + EXPECT_THAT(packets[0].payload(), ElementsAreArray(nalus[0])); + EXPECT_THAT(packets[1].payload(), ElementsAreArray(nalus[1])); + EXPECT_THAT(packets[2].payload(), ElementsAreArray(nalus[2])); } TEST_P(RtpPacketizerH264ModeTest, @@ -194,10 +201,9 @@ TEST_P(RtpPacketizerH264ModeTest, limits.max_payload_len = 200; limits.first_packet_reduction_len = 20; limits.last_packet_reduction_len = 30; - rtc::Buffer frame = CreateFrame(150); + rtc::Buffer frame = CreateFrame({150}); - RtpPacketizerH264 packetizer(frame, limits, GetParam(), - NoFragmentation(frame)); + RtpPacketizerH264 packetizer(frame, limits, GetParam()); std::vector packets = FetchAllPackets(&packetizer); EXPECT_THAT(packets, SizeIs(1)); @@ -211,19 +217,19 @@ INSTANTIATE_TEST_SUITE_P( // Aggregation tests. TEST(RtpPacketizerH264Test, StapA) { - size_t fragments[] = {2, 2, 0x123}; + rtc::Buffer nalus[] = {GenerateNalUnit(/*size=*/2), + GenerateNalUnit(/*size=*/2), + GenerateNalUnit(/*size=*/0x123)}; + rtc::Buffer frame = CreateFrame(nalus); - RTPFragmentationHeader fragmentation = CreateFragmentation(fragments); - rtc::Buffer frame = CreateFrame(fragmentation); - - RtpPacketizerH264 packetizer( - frame, kNoLimits, H264PacketizationMode::NonInterleaved, fragmentation); + RtpPacketizerH264 packetizer(frame, kNoLimits, + H264PacketizationMode::NonInterleaved); std::vector packets = FetchAllPackets(&packetizer); ASSERT_THAT(packets, SizeIs(1)); auto payload = packets[0].payload(); EXPECT_EQ(payload.size(), - kNalHeaderSize + 3 * kLengthFieldLength + frame.size()); + kNalHeaderSize + 3 * kLengthFieldLength + 2 + 2 + 0x123); EXPECT_EQ(payload[0], kStapA); payload = payload.subview(kNalHeaderSize); @@ -231,29 +237,26 @@ TEST(RtpPacketizerH264Test, StapA) { EXPECT_THAT(payload.subview(0, kLengthFieldLength), ElementsAre(0, 2)); // Size. EXPECT_THAT(payload.subview(kLengthFieldLength, 2), - ElementsAreArray(frame.data(), 2)); + ElementsAreArray(nalus[0])); payload = payload.subview(kLengthFieldLength + 2); // 2nd fragment. EXPECT_THAT(payload.subview(0, kLengthFieldLength), ElementsAre(0, 2)); // Size. EXPECT_THAT(payload.subview(kLengthFieldLength, 2), - ElementsAreArray(frame.data() + 2, 2)); + ElementsAreArray(nalus[1])); payload = payload.subview(kLengthFieldLength + 2); // 3rd fragment. EXPECT_THAT(payload.subview(0, kLengthFieldLength), ElementsAre(0x1, 0x23)); // Size. - EXPECT_THAT(payload.subview(kLengthFieldLength), - ElementsAreArray(frame.data() + 4, 0x123)); + EXPECT_THAT(payload.subview(kLengthFieldLength), ElementsAreArray(nalus[2])); } TEST(RtpPacketizerH264Test, SingleNalUnitModeHasNoStapA) { // This is the same setup as for the StapA test. - size_t fragments[] = {2, 2, 0x123}; - RTPFragmentationHeader fragmentation = CreateFragmentation(fragments); - rtc::Buffer frame = CreateFrame(fragmentation); + rtc::Buffer frame = CreateFrame({2, 2, 0x123}); - RtpPacketizerH264 packetizer( - frame, kNoLimits, H264PacketizationMode::SingleNalUnit, fragmentation); + RtpPacketizerH264 packetizer(frame, kNoLimits, + H264PacketizationMode::SingleNalUnit); std::vector packets = FetchAllPackets(&packetizer); // The three fragments should be returned as three packets. @@ -269,23 +272,23 @@ TEST(RtpPacketizerH264Test, StapARespectsFirstPacketReduction) { limits.first_packet_reduction_len = 100; const size_t kFirstFragmentSize = limits.max_payload_len - limits.first_packet_reduction_len; - size_t fragments[] = {kFirstFragmentSize, 2, 2}; - RTPFragmentationHeader fragmentation = CreateFragmentation(fragments); - rtc::Buffer frame = CreateFrame(fragmentation); + rtc::Buffer nalus[] = {GenerateNalUnit(/*size=*/kFirstFragmentSize), + GenerateNalUnit(/*size=*/2), + GenerateNalUnit(/*size=*/2)}; + rtc::Buffer frame = CreateFrame(nalus); - RtpPacketizerH264 packetizer( - frame, limits, H264PacketizationMode::NonInterleaved, fragmentation); + RtpPacketizerH264 packetizer(frame, limits, + H264PacketizationMode::NonInterleaved); std::vector packets = FetchAllPackets(&packetizer); ASSERT_THAT(packets, SizeIs(2)); // Expect 1st packet is single nalu. - EXPECT_THAT(packets[0].payload(), - ElementsAreArray(frame.data(), kFirstFragmentSize)); + EXPECT_THAT(packets[0].payload(), ElementsAreArray(nalus[0])); // Expect 2nd packet is aggregate of last two fragments. - const uint8_t* tail = frame.data() + kFirstFragmentSize; - EXPECT_THAT(packets[1].payload(), ElementsAre(kStapA, // - 0, 2, tail[0], tail[1], // - 0, 2, tail[2], tail[3])); + EXPECT_THAT(packets[1].payload(), + ElementsAre(kStapA, // + 0, 2, nalus[1][0], nalus[1][1], // + 0, 2, nalus[2][0], nalus[2][1])); } TEST(RtpPacketizerH264Test, StapARespectsLastPacketReduction) { @@ -294,22 +297,23 @@ TEST(RtpPacketizerH264Test, StapARespectsLastPacketReduction) { limits.last_packet_reduction_len = 100; const size_t kLastFragmentSize = limits.max_payload_len - limits.last_packet_reduction_len; - size_t fragments[] = {2, 2, kLastFragmentSize}; - RTPFragmentationHeader fragmentation = CreateFragmentation(fragments); - rtc::Buffer frame = CreateFrame(fragmentation); + rtc::Buffer nalus[] = {GenerateNalUnit(/*size=*/2), + GenerateNalUnit(/*size=*/2), + GenerateNalUnit(/*size=*/kLastFragmentSize)}; + rtc::Buffer frame = CreateFrame(nalus); - RtpPacketizerH264 packetizer( - frame, limits, H264PacketizationMode::NonInterleaved, fragmentation); + RtpPacketizerH264 packetizer(frame, limits, + H264PacketizationMode::NonInterleaved); std::vector packets = FetchAllPackets(&packetizer); ASSERT_THAT(packets, SizeIs(2)); // Expect 1st packet is aggregate of 1st two fragments. - EXPECT_THAT(packets[0].payload(), ElementsAre(kStapA, // - 0, 2, frame[0], frame[1], // - 0, 2, frame[2], frame[3])); + EXPECT_THAT(packets[0].payload(), + ElementsAre(kStapA, // + 0, 2, nalus[0][0], nalus[0][1], // + 0, 2, nalus[1][0], nalus[1][1])); // Expect 2nd packet is single nalu. - EXPECT_THAT(packets[1].payload(), - ElementsAreArray(frame.data() + 4, kLastFragmentSize)); + EXPECT_THAT(packets[1].payload(), ElementsAreArray(nalus[2])); } TEST(RtpPacketizerH264Test, TooSmallForStapAHeaders) { @@ -317,22 +321,23 @@ TEST(RtpPacketizerH264Test, TooSmallForStapAHeaders) { limits.max_payload_len = 1000; const size_t kLastFragmentSize = limits.max_payload_len - 3 * kLengthFieldLength - 4; - size_t fragments[] = {2, 2, kLastFragmentSize}; - RTPFragmentationHeader fragmentation = CreateFragmentation(fragments); - rtc::Buffer frame = CreateFrame(fragmentation); + rtc::Buffer nalus[] = {GenerateNalUnit(/*size=*/2), + GenerateNalUnit(/*size=*/2), + GenerateNalUnit(/*size=*/kLastFragmentSize)}; + rtc::Buffer frame = CreateFrame(nalus); - RtpPacketizerH264 packetizer( - frame, limits, H264PacketizationMode::NonInterleaved, fragmentation); + RtpPacketizerH264 packetizer(frame, limits, + H264PacketizationMode::NonInterleaved); std::vector packets = FetchAllPackets(&packetizer); ASSERT_THAT(packets, SizeIs(2)); // Expect 1st packet is aggregate of 1st two fragments. - EXPECT_THAT(packets[0].payload(), ElementsAre(kStapA, // - 0, 2, frame[0], frame[1], // - 0, 2, frame[2], frame[3])); + EXPECT_THAT(packets[0].payload(), + ElementsAre(kStapA, // + 0, 2, nalus[0][0], nalus[0][1], // + 0, 2, nalus[1][0], nalus[1][1])); // Expect 2nd packet is single nalu. - EXPECT_THAT(packets[1].payload(), - ElementsAreArray(frame.data() + 4, kLastFragmentSize)); + EXPECT_THAT(packets[1].payload(), ElementsAreArray(nalus[2])); } // Fragmentation + aggregation. @@ -342,28 +347,29 @@ TEST(RtpPacketizerH264Test, MixedStapAFUA) { const size_t kFuaPayloadSize = 70; const size_t kFuaNaluSize = kNalHeaderSize + 2 * kFuaPayloadSize; const size_t kStapANaluSize = 20; - size_t fragments[] = {kFuaNaluSize, kStapANaluSize, kStapANaluSize}; - RTPFragmentationHeader fragmentation = CreateFragmentation(fragments); - rtc::Buffer frame = CreateFrame(fragmentation); + rtc::Buffer nalus[] = {GenerateNalUnit(kFuaNaluSize), + GenerateNalUnit(kStapANaluSize), + GenerateNalUnit(kStapANaluSize)}; + rtc::Buffer frame = CreateFrame(nalus); - RtpPacketizerH264 packetizer( - frame, limits, H264PacketizationMode::NonInterleaved, fragmentation); + RtpPacketizerH264 packetizer(frame, limits, + H264PacketizationMode::NonInterleaved); std::vector packets = FetchAllPackets(&packetizer); ASSERT_THAT(packets, SizeIs(3)); - const uint8_t* next_fragment = frame.data() + kNalHeaderSize; // First expect two FU-A packets. EXPECT_THAT(packets[0].payload().subview(0, kFuAHeaderSize), - ElementsAre(kFuA, FuDefs::kSBit | frame[0])); - EXPECT_THAT(packets[0].payload().subview(kFuAHeaderSize), - ElementsAreArray(next_fragment, kFuaPayloadSize)); - next_fragment += kFuaPayloadSize; + ElementsAre(kFuA, FuDefs::kSBit | nalus[0][0])); + EXPECT_THAT( + packets[0].payload().subview(kFuAHeaderSize), + ElementsAreArray(nalus[0].data() + kNalHeaderSize, kFuaPayloadSize)); EXPECT_THAT(packets[1].payload().subview(0, kFuAHeaderSize), - ElementsAre(kFuA, FuDefs::kEBit | frame[0])); - EXPECT_THAT(packets[1].payload().subview(kFuAHeaderSize), - ElementsAreArray(next_fragment, kFuaPayloadSize)); - next_fragment += kFuaPayloadSize; + ElementsAre(kFuA, FuDefs::kEBit | nalus[0][0])); + EXPECT_THAT( + packets[1].payload().subview(kFuAHeaderSize), + ElementsAreArray(nalus[0].data() + kNalHeaderSize + kFuaPayloadSize, + kFuaPayloadSize)); // Then expect one STAP-A packet with two nal units. EXPECT_THAT(packets[2].payload()[0], kStapA); @@ -371,13 +377,11 @@ TEST(RtpPacketizerH264Test, MixedStapAFUA) { EXPECT_THAT(payload.subview(0, kLengthFieldLength), ElementsAre(0, kStapANaluSize)); EXPECT_THAT(payload.subview(kLengthFieldLength, kStapANaluSize), - ElementsAreArray(next_fragment, kStapANaluSize)); + ElementsAreArray(nalus[1])); payload = payload.subview(kLengthFieldLength + kStapANaluSize); - next_fragment += kStapANaluSize; EXPECT_THAT(payload.subview(0, kLengthFieldLength), ElementsAre(0, kStapANaluSize)); - EXPECT_THAT(payload.subview(kLengthFieldLength), - ElementsAreArray(next_fragment, kStapANaluSize)); + EXPECT_THAT(payload.subview(kLengthFieldLength), ElementsAreArray(nalus[2])); } TEST(RtpPacketizerH264Test, LastFragmentFitsInSingleButNotLastPacket) { @@ -387,12 +391,10 @@ TEST(RtpPacketizerH264Test, LastFragmentFitsInSingleButNotLastPacket) { limits.last_packet_reduction_len = 20; limits.single_packet_reduction_len = 20; // Actual sizes, which triggered this bug. - size_t fragments[] = {20, 8, 18, 1161}; - RTPFragmentationHeader fragmentation = CreateFragmentation(fragments); - rtc::Buffer frame = CreateFrame(fragmentation); + rtc::Buffer frame = CreateFrame({20, 8, 18, 1161}); - RtpPacketizerH264 packetizer( - frame, limits, H264PacketizationMode::NonInterleaved, fragmentation); + RtpPacketizerH264 packetizer(frame, limits, + H264PacketizationMode::NonInterleaved); std::vector packets = FetchAllPackets(&packetizer); // Last packet has to be of correct size. @@ -406,11 +408,11 @@ TEST(RtpPacketizerH264Test, LastFragmentFitsInSingleButNotLastPacket) { // Returns sizes of the payloads excluding fua headers. std::vector TestFua(size_t frame_payload_size, const RtpPacketizer::PayloadSizeLimits& limits) { - rtc::Buffer frame = CreateFrame(kNalHeaderSize + frame_payload_size); + rtc::Buffer nalu[] = {GenerateNalUnit(kNalHeaderSize + frame_payload_size)}; + rtc::Buffer frame = CreateFrame(nalu); RtpPacketizerH264 packetizer(frame, limits, - H264PacketizationMode::NonInterleaved, - NoFragmentation(frame)); + H264PacketizationMode::NonInterleaved); std::vector packets = FetchAllPackets(&packetizer); EXPECT_GE(packets.size(), 2u); // Single packet indicates it is not FuA. @@ -429,7 +431,7 @@ std::vector TestFua(size_t frame_payload_size, // Clear S and E bits before testing all are duplicating same original header. fua_header.front() &= ~FuDefs::kSBit; fua_header.back() &= ~FuDefs::kEBit; - EXPECT_THAT(fua_header, Each(Eq((kFuA << 8) | frame[0]))); + EXPECT_THAT(fua_header, Each(Eq((kFuA << 8) | nalu[0][0]))); return payload_sizes; } @@ -488,11 +490,10 @@ TEST(RtpPacketizerH264Test, FUABig) { TEST(RtpPacketizerH264Test, RejectsOverlongDataInPacketizationMode0) { RtpPacketizer::PayloadSizeLimits limits; - rtc::Buffer frame = CreateFrame(kMaxPayloadSize + 1); - RTPFragmentationHeader fragmentation = NoFragmentation(frame); + rtc::Buffer frame = CreateFrame({kMaxPayloadSize + 1}); - RtpPacketizerH264 packetizer( - frame, limits, H264PacketizationMode::SingleNalUnit, fragmentation); + RtpPacketizerH264 packetizer(frame, limits, + H264PacketizationMode::SingleNalUnit); std::vector packets = FetchAllPackets(&packetizer); EXPECT_THAT(packets, IsEmpty()); diff --git a/test/fake_encoder.cc b/test/fake_encoder.cc index 84a4afd0d2..219dafcf16 100644 --- a/test/fake_encoder.cc +++ b/test/fake_encoder.cc @@ -290,6 +290,7 @@ FakeH264Encoder::FakeH264Encoder(Clock* clock) std::unique_ptr FakeH264Encoder::EncodeHook( EncodedImage* encoded_image, CodecSpecificInfo* codec_specific) { + static constexpr std::array kStartCode = {0, 0, 1}; const size_t kSpsSize = 8; const size_t kPpsSize = 11; const int kIdrFrequency = 10; @@ -299,46 +300,46 @@ std::unique_ptr FakeH264Encoder::EncodeHook( current_idr_counter = idr_counter_; ++idr_counter_; } + for (size_t i = 0; i < encoded_image->size(); ++i) { + encoded_image->data()[i] = static_cast(i); + } + auto fragmentation = std::make_unique(); if (current_idr_counter % kIdrFrequency == 0 && - encoded_image->size() > kSpsSize + kPpsSize + 1) { + encoded_image->size() > kSpsSize + kPpsSize + 1 + 3 * kStartCode.size()) { const size_t kNumSlices = 3; fragmentation->VerifyAndAllocateFragmentationHeader(kNumSlices); - fragmentation->fragmentationOffset[0] = 0; + fragmentation->fragmentationOffset[0] = kStartCode.size(); fragmentation->fragmentationLength[0] = kSpsSize; - fragmentation->fragmentationOffset[1] = kSpsSize; + fragmentation->fragmentationOffset[1] = 2 * kStartCode.size() + kSpsSize; fragmentation->fragmentationLength[1] = kPpsSize; - fragmentation->fragmentationOffset[2] = kSpsSize + kPpsSize; + fragmentation->fragmentationOffset[2] = + 3 * kStartCode.size() + kSpsSize + kPpsSize; fragmentation->fragmentationLength[2] = - encoded_image->size() - (kSpsSize + kPpsSize); + encoded_image->size() - (3 * kStartCode.size() + kSpsSize + kPpsSize); const size_t kSpsNalHeader = 0x67; const size_t kPpsNalHeader = 0x68; const size_t kIdrNalHeader = 0x65; - encoded_image->data()[fragmentation->fragmentationOffset[0]] = - kSpsNalHeader; - encoded_image->data()[fragmentation->fragmentationOffset[1]] = - kPpsNalHeader; - encoded_image->data()[fragmentation->fragmentationOffset[2]] = - kIdrNalHeader; + memcpy(encoded_image->data(), kStartCode.data(), kStartCode.size()); + encoded_image->data()[fragmentation->Offset(0)] = kSpsNalHeader; + memcpy(encoded_image->data() + fragmentation->Offset(1) - kStartCode.size(), + kStartCode.data(), kStartCode.size()); + encoded_image->data()[fragmentation->Offset(1)] = kPpsNalHeader; + memcpy(encoded_image->data() + fragmentation->Offset(2) - kStartCode.size(), + kStartCode.data(), kStartCode.size()); + encoded_image->data()[fragmentation->Offset(2)] = kIdrNalHeader; } else { const size_t kNumSlices = 1; fragmentation->VerifyAndAllocateFragmentationHeader(kNumSlices); - fragmentation->fragmentationOffset[0] = 0; - fragmentation->fragmentationLength[0] = encoded_image->size(); + fragmentation->fragmentationOffset[0] = kStartCode.size(); + fragmentation->fragmentationLength[0] = + encoded_image->size() - kStartCode.size(); + memcpy(encoded_image->data(), kStartCode.data(), kStartCode.size()); const size_t kNalHeader = 0x41; encoded_image->data()[fragmentation->fragmentationOffset[0]] = kNalHeader; } - uint8_t value = 0; - int fragment_counter = 0; - for (size_t i = 0; i < encoded_image->size(); ++i) { - if (fragment_counter == fragmentation->fragmentationVectorSize || - i != fragmentation->fragmentationOffset[fragment_counter]) { - encoded_image->data()[i] = value++; - } else { - ++fragment_counter; - } - } + codec_specific->codecType = kVideoCodecH264; codec_specific->codecSpecific.H264.packetization_mode = H264PacketizationMode::NonInterleaved;