diff --git a/webrtc/modules/rtp_rtcp/source/rtp_format.h b/webrtc/modules/rtp_rtcp/source/rtp_format.h index 8cad6a916d..3b6004b9a1 100644 --- a/webrtc/modules/rtp_rtcp/source/rtp_format.h +++ b/webrtc/modules/rtp_rtcp/source/rtp_format.h @@ -18,6 +18,7 @@ #include "webrtc/modules/rtp_rtcp/include/rtp_rtcp_defines.h" namespace webrtc { +class RtpPacketToSend; class RtpPacketizer { public: @@ -33,15 +34,11 @@ class RtpPacketizer { const RTPFragmentationHeader* fragmentation) = 0; // Get the next payload with payload header. - // buffer is a pointer to where the output will be written. - // bytes_to_send is an output variable that will contain number of bytes - // written to buffer. The parameter last_packet is true for the last packet of - // the frame, false otherwise (i.e., call the function again to get the - // next packet). - // Returns true on success or false if there was no payload to packetize. - virtual bool NextPacket(uint8_t* buffer, - size_t* bytes_to_send, - bool* last_packet) = 0; + // Write payload and set marker bit of the |packet|. + // The parameter |last_packet| is true for the last packet of the frame, false + // otherwise (i.e., call the function again to get the next packet). + // Returns true on success, false otherwise. + virtual bool NextPacket(RtpPacketToSend* packet, bool* last_packet) = 0; virtual ProtectionType GetProtectionType() = 0; diff --git a/webrtc/modules/rtp_rtcp/source/rtp_format_h264.cc b/webrtc/modules/rtp_rtcp/source/rtp_format_h264.cc index 2344b2820c..b82b66f5fe 100644 --- a/webrtc/modules/rtp_rtcp/source/rtp_format_h264.cc +++ b/webrtc/modules/rtp_rtcp/source/rtp_format_h264.cc @@ -19,6 +19,7 @@ #include "webrtc/base/logging.h" #include "webrtc/modules/include/module_common_types.h" #include "webrtc/modules/rtp_rtcp/source/byte_io.h" +#include "webrtc/modules/rtp_rtcp/source/rtp_packet_to_send.h" #include "webrtc/common_video/h264/sps_vui_rewriter.h" #include "webrtc/common_video/h264/h264_common.h" #include "webrtc/common_video/h264/pps_parser.h" @@ -229,54 +230,50 @@ size_t RtpPacketizerH264::PacketizeStapA(size_t fragment_index) { return fragment_index; } -bool RtpPacketizerH264::NextPacket(uint8_t* buffer, - size_t* bytes_to_send, +bool RtpPacketizerH264::NextPacket(RtpPacketToSend* rtp_packet, bool* last_packet) { - *bytes_to_send = 0; + RTC_DCHECK(rtp_packet); + RTC_DCHECK(last_packet); if (packets_.empty()) { - *bytes_to_send = 0; *last_packet = true; return false; } PacketUnit packet = packets_.front(); - if (packet.first_fragment && packet.last_fragment) { // Single NAL unit packet. - *bytes_to_send = packet.source_fragment.length; - memcpy(buffer, packet.source_fragment.buffer, *bytes_to_send); + size_t bytes_to_send = packet.source_fragment.length; + uint8_t* buffer = rtp_packet->AllocatePayload(bytes_to_send); + memcpy(buffer, packet.source_fragment.buffer, bytes_to_send); packets_.pop(); input_fragments_.pop_front(); - RTC_CHECK_LE(*bytes_to_send, max_payload_len_); } else if (packet.aggregated) { - NextAggregatePacket(buffer, bytes_to_send); - RTC_CHECK_LE(*bytes_to_send, max_payload_len_); + NextAggregatePacket(rtp_packet); } else { - NextFragmentPacket(buffer, bytes_to_send); - RTC_CHECK_LE(*bytes_to_send, max_payload_len_); + NextFragmentPacket(rtp_packet); } + RTC_DCHECK_LE(rtp_packet->payload_size(), max_payload_len_); *last_packet = packets_.empty(); + rtp_packet->SetMarker(*last_packet); return true; } -void RtpPacketizerH264::NextAggregatePacket(uint8_t* buffer, - size_t* bytes_to_send) { +void RtpPacketizerH264::NextAggregatePacket(RtpPacketToSend* rtp_packet) { + uint8_t* buffer = rtp_packet->AllocatePayload(max_payload_len_); + RTC_DCHECK(buffer); PacketUnit* packet = &packets_.front(); RTC_CHECK(packet->first_fragment); // STAP-A NALU header. buffer[0] = (packet->header & (kFBit | kNriMask)) | H264::NaluType::kStapA; - int index = kNalHeaderSize; - *bytes_to_send += kNalHeaderSize; + size_t index = kNalHeaderSize; while (packet->aggregated) { const Fragment& fragment = packet->source_fragment; // Add NAL unit length field. ByteWriter::WriteBigEndian(&buffer[index], fragment.length); index += kLengthFieldSize; - *bytes_to_send += kLengthFieldSize; // Add NAL unit. memcpy(&buffer[index], fragment.buffer, fragment.length); index += fragment.length; - *bytes_to_send += fragment.length; packets_.pop(); input_fragments_.pop_front(); if (packet->last_fragment) @@ -284,10 +281,10 @@ void RtpPacketizerH264::NextAggregatePacket(uint8_t* buffer, packet = &packets_.front(); } RTC_CHECK(packet->last_fragment); + rtp_packet->SetPayloadSize(index); } -void RtpPacketizerH264::NextFragmentPacket(uint8_t* buffer, - size_t* bytes_to_send) { +void RtpPacketizerH264::NextFragmentPacket(RtpPacketToSend* rtp_packet) { PacketUnit* packet = &packets_.front(); // NAL unit fragmented over multiple packets (FU-A). // We do not send original NALU header, so it will be replaced by the @@ -301,11 +298,11 @@ void RtpPacketizerH264::NextFragmentPacket(uint8_t* buffer, fu_header |= (packet->last_fragment ? kEBit : 0); uint8_t type = packet->header & kTypeMask; fu_header |= type; + const Fragment& fragment = packet->source_fragment; + uint8_t* buffer = + rtp_packet->AllocatePayload(kFuAHeaderSize + fragment.length); buffer[0] = fu_indicator; buffer[1] = fu_header; - - const Fragment& fragment = packet->source_fragment; - *bytes_to_send = fragment.length + kFuAHeaderSize; memcpy(buffer + kFuAHeaderSize, fragment.buffer, fragment.length); if (packet->last_fragment) input_fragments_.pop_front(); diff --git a/webrtc/modules/rtp_rtcp/source/rtp_format_h264.h b/webrtc/modules/rtp_rtcp/source/rtp_format_h264.h index 9cf3150dfa..bc3240106d 100644 --- a/webrtc/modules/rtp_rtcp/source/rtp_format_h264.h +++ b/webrtc/modules/rtp_rtcp/source/rtp_format_h264.h @@ -12,6 +12,7 @@ #define WEBRTC_MODULES_RTP_RTCP_SOURCE_RTP_FORMAT_H264_H_ #include +#include #include #include @@ -34,15 +35,11 @@ class RtpPacketizerH264 : public RtpPacketizer { const RTPFragmentationHeader* fragmentation) override; // Get the next payload with H264 payload header. - // buffer is a pointer to where the output will be written. - // bytes_to_send is an output variable that will contain number of bytes - // written to buffer. The parameter last_packet is true for the last packet of - // the frame, false otherwise (i.e., call the function again to get the - // next packet). - // Returns true on success or false if there was no payload to packetize. - bool NextPacket(uint8_t* buffer, - size_t* bytes_to_send, - bool* last_packet) override; + // Write payload and set marker bit of the |packet|. + // The parameter |last_packet| is true for the last packet of the frame, false + // otherwise (i.e., call the function again to get the next packet). + // Returns true on success, false otherwise. + bool NextPacket(RtpPacketToSend* rtp_packet, bool* last_packet) override; ProtectionType GetProtectionType() override; @@ -89,8 +86,8 @@ class RtpPacketizerH264 : public RtpPacketizer { void GeneratePackets(); void PacketizeFuA(size_t fragment_index); size_t PacketizeStapA(size_t fragment_index); - void NextAggregatePacket(uint8_t* buffer, size_t* bytes_to_send); - void NextFragmentPacket(uint8_t* buffer, size_t* bytes_to_send); + void NextAggregatePacket(RtpPacketToSend* rtp_packet); + void NextFragmentPacket(RtpPacketToSend* rtp_packet); const size_t max_payload_len_; std::deque input_fragments_; diff --git a/webrtc/modules/rtp_rtcp/source/rtp_format_h264_unittest.cc b/webrtc/modules/rtp_rtcp/source/rtp_format_h264_unittest.cc index 894415da8a..03082a420d 100644 --- a/webrtc/modules/rtp_rtcp/source/rtp_format_h264_unittest.cc +++ b/webrtc/modules/rtp_rtcp/source/rtp_format_h264_unittest.cc @@ -11,16 +11,22 @@ #include #include +#include "webrtc/base/array_view.h" #include "webrtc/common_video/h264/h264_common.h" #include "webrtc/modules/include/module_common_types.h" #include "webrtc/modules/rtp_rtcp/mocks/mock_rtp_rtcp.h" #include "webrtc/modules/rtp_rtcp/source/byte_io.h" #include "webrtc/modules/rtp_rtcp/source/rtp_format.h" +#include "webrtc/modules/rtp_rtcp/source/rtp_packet_to_send.h" #include "webrtc/test/gmock.h" #include "webrtc/test/gtest.h" namespace webrtc { namespace { + +using ::testing::ElementsAreArray; + +constexpr RtpPacketToSend::ExtensionManager* kNoExtensions = nullptr; const size_t kMaxPayloadSize = 1200; const size_t kLengthFieldLength = 2; @@ -46,10 +52,9 @@ enum FuDefs { kSBit = 0x80, kEBit = 0x40, kRBit = 0x20 }; void VerifyFua(size_t fua_index, const uint8_t* expected_payload, int offset, - const uint8_t* packet, - size_t length, + rtc::ArrayView packet, const std::vector& expected_sizes) { - ASSERT_EQ(expected_sizes[fua_index] + kFuAHeaderSize, length) + ASSERT_EQ(expected_sizes[fua_index] + kFuAHeaderSize, packet.size()) << "FUA index: " << fua_index; const uint8_t kFuIndicator = 0x1C; // F=0, NRI=0, Type=28. EXPECT_EQ(kFuIndicator, packet[0]) << "FUA index: " << fua_index; @@ -65,9 +70,8 @@ void VerifyFua(size_t fua_index, std::vector expected_packet_payload( &expected_payload[offset], &expected_payload[offset + expected_sizes[fua_index]]); - EXPECT_THAT( - expected_packet_payload, - ::testing::ElementsAreArray(&packet[2], expected_sizes[fua_index])) + EXPECT_THAT(expected_packet_payload, + ElementsAreArray(&packet[2], expected_sizes[fua_index])) << "FUA index: " << fua_index; } @@ -88,18 +92,18 @@ void TestFua(size_t frame_size, kRtpVideoH264, max_payload_size, NULL, kEmptyFrame)); packetizer->SetPayloadData(frame.get(), frame_size, &fragmentation); - std::unique_ptr packet(new uint8_t[max_payload_size]); - size_t length = 0; + RtpPacketToSend packet(kNoExtensions); + ASSERT_LE(max_payload_size, packet.FreeCapacity()); bool last = false; size_t offset = kNalHeaderSize; for (size_t i = 0; i < expected_sizes.size(); ++i) { - ASSERT_TRUE(packetizer->NextPacket(packet.get(), &length, &last)); - VerifyFua(i, frame.get(), offset, packet.get(), length, expected_sizes); + ASSERT_TRUE(packetizer->NextPacket(&packet, &last)); + VerifyFua(i, frame.get(), offset, packet.payload(), expected_sizes); EXPECT_EQ(i == expected_sizes.size() - 1, last) << "FUA index: " << i; offset += expected_sizes[i]; } - EXPECT_FALSE(packetizer->NextPacket(packet.get(), &length, &last)); + EXPECT_FALSE(packetizer->NextPacket(&packet, &last)); } size_t GetExpectedNaluOffset(const RTPFragmentationHeader& fragmentation, @@ -117,10 +121,8 @@ size_t GetExpectedNaluOffset(const RTPFragmentationHeader& fragmentation, void VerifyStapAPayload(const RTPFragmentationHeader& fragmentation, size_t first_stapa_index, size_t nalu_index, - const uint8_t* frame, - size_t frame_length, - const uint8_t* packet, - size_t packet_length) { + rtc::ArrayView frame, + rtc::ArrayView packet) { size_t expected_payload_offset = GetExpectedNaluOffset(fragmentation, first_stapa_index, nalu_index) + kLengthFieldLength; @@ -128,27 +130,22 @@ void VerifyStapAPayload(const RTPFragmentationHeader& fragmentation, const uint8_t* expected_payload = &frame[offset]; size_t expected_payload_length = fragmentation.fragmentationLength[nalu_index]; - ASSERT_LE(offset + expected_payload_length, frame_length); - ASSERT_LE(expected_payload_offset + expected_payload_length, packet_length); + ASSERT_LE(offset + expected_payload_length, frame.size()); + ASSERT_LE(expected_payload_offset + expected_payload_length, packet.size()); std::vector expected_payload_vector( expected_payload, &expected_payload[expected_payload_length]); EXPECT_THAT(expected_payload_vector, - ::testing::ElementsAreArray(&packet[expected_payload_offset], - expected_payload_length)); + ElementsAreArray(&packet[expected_payload_offset], + expected_payload_length)); } void VerifySingleNaluPayload(const RTPFragmentationHeader& fragmentation, size_t nalu_index, - const uint8_t* frame, - size_t frame_length, - const uint8_t* packet, - size_t packet_length) { - std::vector expected_payload_vector( - &frame[fragmentation.fragmentationOffset[nalu_index]], - &frame[fragmentation.fragmentationOffset[nalu_index] + - fragmentation.fragmentationLength[nalu_index]]); - EXPECT_THAT(expected_payload_vector, - ::testing::ElementsAreArray(packet, packet_length)); + rtc::ArrayView frame, + rtc::ArrayView packet) { + auto fragment = frame.subview(fragmentation.fragmentationOffset[nalu_index], + fragmentation.fragmentationLength[nalu_index]); + EXPECT_THAT(packet, ElementsAreArray(fragment.begin(), fragment.end())); } } // namespace @@ -161,15 +158,14 @@ TEST(RtpPacketizerH264Test, TestSingleNalu) { std::unique_ptr packetizer( RtpPacketizer::Create(kRtpVideoH264, kMaxPayloadSize, NULL, kEmptyFrame)); packetizer->SetPayloadData(frame, sizeof(frame), &fragmentation); - uint8_t packet[kMaxPayloadSize] = {0}; - size_t length = 0; + RtpPacketToSend packet(kNoExtensions); + ASSERT_LE(kMaxPayloadSize, packet.FreeCapacity()); bool last = false; - ASSERT_TRUE(packetizer->NextPacket(packet, &length, &last)); - EXPECT_EQ(2u, length); + ASSERT_TRUE(packetizer->NextPacket(&packet, &last)); + EXPECT_EQ(2u, packet.payload_size()); EXPECT_TRUE(last); - VerifySingleNaluPayload( - fragmentation, 0, frame, sizeof(frame), packet, length); - EXPECT_FALSE(packetizer->NextPacket(packet, &length, &last)); + VerifySingleNaluPayload(fragmentation, 0, frame, packet.payload()); + EXPECT_FALSE(packetizer->NextPacket(&packet, &last)); } TEST(RtpPacketizerH264Test, TestSingleNaluTwoPackets) { @@ -191,19 +187,18 @@ TEST(RtpPacketizerH264Test, TestSingleNaluTwoPackets) { RtpPacketizer::Create(kRtpVideoH264, kMaxPayloadSize, NULL, kEmptyFrame)); packetizer->SetPayloadData(frame, kFrameSize, &fragmentation); - uint8_t packet[kMaxPayloadSize] = {0}; - size_t length = 0; + RtpPacketToSend packet(kNoExtensions); bool last = false; - ASSERT_TRUE(packetizer->NextPacket(packet, &length, &last)); - ASSERT_EQ(fragmentation.fragmentationOffset[1], length); - VerifySingleNaluPayload(fragmentation, 0, frame, kFrameSize, packet, length); + ASSERT_TRUE(packetizer->NextPacket(&packet, &last)); + ASSERT_EQ(fragmentation.fragmentationOffset[1], packet.payload_size()); + VerifySingleNaluPayload(fragmentation, 0, frame, packet.payload()); - ASSERT_TRUE(packetizer->NextPacket(packet, &length, &last)); - ASSERT_EQ(fragmentation.fragmentationLength[1], length); - VerifySingleNaluPayload(fragmentation, 1, frame, kFrameSize, packet, length); + ASSERT_TRUE(packetizer->NextPacket(&packet, &last)); + ASSERT_EQ(fragmentation.fragmentationLength[1], packet.payload_size()); + VerifySingleNaluPayload(fragmentation, 1, frame, packet.payload()); EXPECT_TRUE(last); - EXPECT_FALSE(packetizer->NextPacket(packet, &length, &last)); + EXPECT_FALSE(packetizer->NextPacket(&packet, &last)); } TEST(RtpPacketizerH264Test, TestStapA) { @@ -228,18 +223,18 @@ TEST(RtpPacketizerH264Test, TestStapA) { RtpPacketizer::Create(kRtpVideoH264, kMaxPayloadSize, NULL, kEmptyFrame)); packetizer->SetPayloadData(frame, kFrameSize, &fragmentation); - uint8_t packet[kMaxPayloadSize] = {0}; - size_t length = 0; + RtpPacketToSend packet(kNoExtensions); + ASSERT_LE(kMaxPayloadSize, packet.FreeCapacity()); bool last = false; - ASSERT_TRUE(packetizer->NextPacket(packet, &length, &last)); + ASSERT_TRUE(packetizer->NextPacket(&packet, &last)); size_t expected_packet_size = kNalHeaderSize + 3 * kLengthFieldLength + kFrameSize; - ASSERT_EQ(expected_packet_size, length); + ASSERT_EQ(expected_packet_size, packet.payload_size()); EXPECT_TRUE(last); for (size_t i = 0; i < fragmentation.fragmentationVectorSize; ++i) - VerifyStapAPayload(fragmentation, 0, i, frame, kFrameSize, packet, length); + VerifyStapAPayload(fragmentation, 0, i, frame, packet.payload()); - EXPECT_FALSE(packetizer->NextPacket(packet, &length, &last)); + EXPECT_FALSE(packetizer->NextPacket(&packet, &last)); } TEST(RtpPacketizerH264Test, TestTooSmallForStapAHeaders) { @@ -263,27 +258,27 @@ TEST(RtpPacketizerH264Test, TestTooSmallForStapAHeaders) { RtpPacketizer::Create(kRtpVideoH264, kMaxPayloadSize, NULL, kEmptyFrame)); packetizer->SetPayloadData(frame, kFrameSize, &fragmentation); - uint8_t packet[kMaxPayloadSize] = {0}; - size_t length = 0; + RtpPacketToSend packet(kNoExtensions); + ASSERT_LE(kMaxPayloadSize, packet.FreeCapacity()); bool last = false; - ASSERT_TRUE(packetizer->NextPacket(packet, &length, &last)); + ASSERT_TRUE(packetizer->NextPacket(&packet, &last)); size_t expected_packet_size = kNalHeaderSize; for (size_t i = 0; i < 2; ++i) { expected_packet_size += kLengthFieldLength + fragmentation.fragmentationLength[i]; } - ASSERT_EQ(expected_packet_size, length); + ASSERT_EQ(expected_packet_size, packet.payload_size()); EXPECT_FALSE(last); for (size_t i = 0; i < 2; ++i) - VerifyStapAPayload(fragmentation, 0, i, frame, kFrameSize, packet, length); + VerifyStapAPayload(fragmentation, 0, i, frame, packet.payload()); - ASSERT_TRUE(packetizer->NextPacket(packet, &length, &last)); + ASSERT_TRUE(packetizer->NextPacket(&packet, &last)); expected_packet_size = fragmentation.fragmentationLength[2]; - ASSERT_EQ(expected_packet_size, length); + ASSERT_EQ(expected_packet_size, packet.payload_size()); EXPECT_TRUE(last); - VerifySingleNaluPayload(fragmentation, 2, frame, kFrameSize, packet, length); + VerifySingleNaluPayload(fragmentation, 2, frame, packet.payload()); - EXPECT_FALSE(packetizer->NextPacket(packet, &length, &last)); + EXPECT_FALSE(packetizer->NextPacket(&packet, &last)); } TEST(RtpPacketizerH264Test, TestMixedStapA_FUA) { @@ -315,26 +310,26 @@ TEST(RtpPacketizerH264Test, TestMixedStapA_FUA) { std::vector fua_sizes; fua_sizes.push_back(1100); fua_sizes.push_back(1099); - uint8_t packet[kMaxPayloadSize] = {0}; - size_t length = 0; + RtpPacketToSend packet(kNoExtensions); + ASSERT_LE(kMaxPayloadSize, packet.FreeCapacity()); bool last = false; int fua_offset = kNalHeaderSize; for (size_t i = 0; i < 2; ++i) { - ASSERT_TRUE(packetizer->NextPacket(packet, &length, &last)); - VerifyFua(i, frame, fua_offset, packet, length, fua_sizes); + ASSERT_TRUE(packetizer->NextPacket(&packet, &last)); + VerifyFua(i, frame, fua_offset, packet.payload(), fua_sizes); EXPECT_FALSE(last); fua_offset += fua_sizes[i]; } // Then expecting one STAP-A packet with two nal units. - ASSERT_TRUE(packetizer->NextPacket(packet, &length, &last)); + ASSERT_TRUE(packetizer->NextPacket(&packet, &last)); size_t expected_packet_size = kNalHeaderSize + 2 * kLengthFieldLength + 2 * kStapANaluSize; - ASSERT_EQ(expected_packet_size, length); + ASSERT_EQ(expected_packet_size, packet.payload_size()); EXPECT_TRUE(last); for (size_t i = 1; i < fragmentation.fragmentationVectorSize; ++i) - VerifyStapAPayload(fragmentation, 1, i, frame, kFrameSize, packet, length); + VerifyStapAPayload(fragmentation, 1, i, frame, packet.payload()); - EXPECT_FALSE(packetizer->NextPacket(packet, &length, &last)); + EXPECT_FALSE(packetizer->NextPacket(&packet, &last)); } TEST(RtpPacketizerH264Test, TestFUAOddSize) { @@ -429,24 +424,20 @@ TEST_F(RtpPacketizerH264TestSpsRewriting, FuASps) { &fragmentation_header_); bool last_packet = true; - uint8_t buffer[sizeof(kOriginalSps) + kHeaderOverhead] = {}; - size_t num_bytes = 0; + RtpPacketToSend packet(kNoExtensions); + ASSERT_LE(sizeof(kOriginalSps) + kHeaderOverhead, packet.FreeCapacity()); - EXPECT_TRUE(packetizer_->NextPacket(buffer, &num_bytes, &last_packet)); + EXPECT_TRUE(packetizer_->NextPacket(&packet, &last_packet)); size_t offset = H264::kNaluTypeSize; - size_t length = num_bytes - kFuAHeaderSize; - std::vector expected_payload(&kRewrittenSps[offset], - &kRewrittenSps[offset + length]); - EXPECT_THAT(expected_payload, - ::testing::ElementsAreArray(&buffer[kFuAHeaderSize], length)); + size_t length = packet.payload_size() - kFuAHeaderSize; + EXPECT_THAT(packet.payload().subview(kFuAHeaderSize), + ElementsAreArray(&kRewrittenSps[offset], length)); offset += length; - EXPECT_TRUE(packetizer_->NextPacket(buffer, &num_bytes, &last_packet)); - length = num_bytes - kFuAHeaderSize; - expected_payload = std::vector(&kRewrittenSps[offset], - &kRewrittenSps[offset + length]); - EXPECT_THAT(expected_payload, - ::testing::ElementsAreArray(&buffer[kFuAHeaderSize], length)); + EXPECT_TRUE(packetizer_->NextPacket(&packet, &last_packet)); + length = packet.payload_size() - kFuAHeaderSize; + EXPECT_THAT(packet.payload().subview(kFuAHeaderSize), + ElementsAreArray(&kRewrittenSps[offset], length)); offset += length; EXPECT_EQ(offset, sizeof(kRewrittenSps)); @@ -467,18 +458,14 @@ TEST_F(RtpPacketizerH264TestSpsRewriting, StapASps) { &fragmentation_header_); bool last_packet = true; - uint8_t buffer[kExpectedTotalSize + kHeaderOverhead] = {}; - size_t num_bytes = 0; + RtpPacketToSend packet(kNoExtensions); + ASSERT_LE(kExpectedTotalSize + kHeaderOverhead, packet.FreeCapacity()); - EXPECT_TRUE(packetizer_->NextPacket(buffer, &num_bytes, &last_packet)); - EXPECT_EQ(kExpectedTotalSize, num_bytes); - - std::vector expected_payload(kRewrittenSps, - &kRewrittenSps[sizeof(kRewrittenSps)]); - EXPECT_THAT(expected_payload, - ::testing::ElementsAreArray( - &buffer[H264::kNaluTypeSize + kLengthFieldLength], - sizeof(kRewrittenSps))); + EXPECT_TRUE(packetizer_->NextPacket(&packet, &last_packet)); + EXPECT_EQ(kExpectedTotalSize, packet.payload_size()); + EXPECT_THAT(packet.payload().subview(H264::kNaluTypeSize + kLengthFieldLength, + sizeof(kRewrittenSps)), + ElementsAreArray(kRewrittenSps)); } class RtpDepacketizerH264Test : public ::testing::Test { diff --git a/webrtc/modules/rtp_rtcp/source/rtp_format_video_generic.cc b/webrtc/modules/rtp_rtcp/source/rtp_format_video_generic.cc index b47e9b9359..a2ce664680 100644 --- a/webrtc/modules/rtp_rtcp/source/rtp_format_video_generic.cc +++ b/webrtc/modules/rtp_rtcp/source/rtp_format_video_generic.cc @@ -13,6 +13,7 @@ #include "webrtc/base/logging.h" #include "webrtc/modules/include/module_common_types.h" #include "webrtc/modules/rtp_rtcp/source/rtp_format_video_generic.h" +#include "webrtc/modules/rtp_rtcp/source/rtp_packet_to_send.h" namespace webrtc { @@ -45,32 +46,33 @@ void RtpPacketizerGeneric::SetPayloadData( generic_header_ = RtpFormatVideoGeneric::kFirstPacketBit; } -bool RtpPacketizerGeneric::NextPacket(uint8_t* buffer, - size_t* bytes_to_send, +bool RtpPacketizerGeneric::NextPacket(RtpPacketToSend* packet, bool* last_packet) { + RTC_DCHECK(packet); + RTC_DCHECK(last_packet); if (payload_size_ < payload_length_) { payload_length_ = payload_size_; } payload_size_ -= payload_length_; - *bytes_to_send = payload_length_ + kGenericHeaderLength; - assert(payload_length_ <= max_payload_len_); + RTC_DCHECK_LE(payload_length_, max_payload_len_); - uint8_t* out_ptr = buffer; + uint8_t* out_ptr = + packet->AllocatePayload(kGenericHeaderLength + payload_length_); // Put generic header in packet if (frame_type_ == kVideoFrameKey) { generic_header_ |= RtpFormatVideoGeneric::kKeyFrameBit; } - *out_ptr++ = generic_header_; + out_ptr[0] = generic_header_; // Remove first-packet bit, following packets are intermediate generic_header_ &= ~RtpFormatVideoGeneric::kFirstPacketBit; // Put payload in packet - memcpy(out_ptr, payload_data_, payload_length_); + memcpy(out_ptr + kGenericHeaderLength, payload_data_, payload_length_); payload_data_ += payload_length_; *last_packet = payload_size_ <= 0; - + packet->SetMarker(*last_packet); return true; } diff --git a/webrtc/modules/rtp_rtcp/source/rtp_format_video_generic.h b/webrtc/modules/rtp_rtcp/source/rtp_format_video_generic.h index e72fe310cf..118166fbf3 100644 --- a/webrtc/modules/rtp_rtcp/source/rtp_format_video_generic.h +++ b/webrtc/modules/rtp_rtcp/source/rtp_format_video_generic.h @@ -36,15 +36,11 @@ class RtpPacketizerGeneric : public RtpPacketizer { const RTPFragmentationHeader* fragmentation) override; // Get the next payload with generic payload header. - // buffer is a pointer to where the output will be written. - // bytes_to_send is an output variable that will contain number of bytes - // written to buffer. The parameter last_packet is true for the last packet of - // the frame, false otherwise (i.e., call the function again to get the - // next packet). - // Returns true on success or false if there was no payload to packetize. - bool NextPacket(uint8_t* buffer, - size_t* bytes_to_send, - bool* last_packet) override; + // Write payload and set marker bit of the |packet|. + // The parameter |last_packet| is true for the last packet of the frame, false + // otherwise (i.e., call the function again to get the next packet). + // Returns true on success, false otherwise. + bool NextPacket(RtpPacketToSend* packet, bool* last_packet) override; ProtectionType GetProtectionType() override; diff --git a/webrtc/modules/rtp_rtcp/source/rtp_format_vp8.cc b/webrtc/modules/rtp_rtcp/source/rtp_format_vp8.cc index 7beeb181e2..e8e7f2997a 100644 --- a/webrtc/modules/rtp_rtcp/source/rtp_format_vp8.cc +++ b/webrtc/modules/rtp_rtcp/source/rtp_format_vp8.cc @@ -17,6 +17,7 @@ #include "webrtc/base/logging.h" #include "webrtc/modules/rtp_rtcp/source/vp8_partition_aggregator.h" +#include "webrtc/modules/rtp_rtcp/source/rtp_packet_to_send.h" namespace webrtc { namespace { @@ -197,9 +198,9 @@ void RtpPacketizerVp8::SetPayloadData( } } -bool RtpPacketizerVp8::NextPacket(uint8_t* buffer, - size_t* bytes_to_send, - bool* last_packet) { +bool RtpPacketizerVp8::NextPacket(RtpPacketToSend* packet, bool* last_packet) { + RTC_DCHECK(packet); + RTC_DCHECK(last_packet); if (!packets_calculated_) { int ret = 0; if (aggr_mode_ == kAggrPartitions && balance_) { @@ -217,13 +218,14 @@ bool RtpPacketizerVp8::NextPacket(uint8_t* buffer, InfoStruct packet_info = packets_.front(); packets_.pop(); + uint8_t* buffer = packet->AllocatePayload(max_payload_len_); int bytes = WriteHeaderAndPayload(packet_info, buffer, max_payload_len_); if (bytes < 0) { return false; } - *bytes_to_send = static_cast(bytes); - + packet->SetPayloadSize(bytes); *last_packet = packets_.empty(); + packet->SetMarker(*last_packet); return true; } diff --git a/webrtc/modules/rtp_rtcp/source/rtp_format_vp8.h b/webrtc/modules/rtp_rtcp/source/rtp_format_vp8.h index d62ecba85f..cddf51f04e 100644 --- a/webrtc/modules/rtp_rtcp/source/rtp_format_vp8.h +++ b/webrtc/modules/rtp_rtcp/source/rtp_format_vp8.h @@ -65,19 +65,11 @@ class RtpPacketizerVp8 : public RtpPacketizer { const RTPFragmentationHeader* fragmentation) override; // Get the next payload with VP8 payload header. - // max_payload_len limits the sum length of payload and VP8 payload header. - // buffer is a pointer to where the output will be written. - // bytes_to_send is an output variable that will contain number of bytes - // written to buffer. Parameter last_packet is true for the last packet of - // the frame, false otherwise (i.e., call the function again to get the - // next packet). - // For the kStrict and kAggregate mode: returns the partition index from which - // the first payload byte in the packet is taken, with the first partition - // having index 0; returns negative on error. - // For the kEqualSize mode: returns 0 on success, return negative on error. - bool NextPacket(uint8_t* buffer, - size_t* bytes_to_send, - bool* last_packet) override; + // Write payload and set marker bit of the |packet|. + // The parameter |last_packet| is true for the last packet of the frame, false + // otherwise (i.e., call the function again to get the next packet). + // Returns true on success, false otherwise. + bool NextPacket(RtpPacketToSend* packet, bool* last_packet) override; ProtectionType GetProtectionType() override; diff --git a/webrtc/modules/rtp_rtcp/source/rtp_format_vp8_test_helper.cc b/webrtc/modules/rtp_rtcp/source/rtp_format_vp8_test_helper.cc index 5105659292..8b20aebb90 100644 --- a/webrtc/modules/rtp_rtcp/source/rtp_format_vp8_test_helper.cc +++ b/webrtc/modules/rtp_rtcp/source/rtp_format_vp8_test_helper.cc @@ -17,22 +17,22 @@ namespace webrtc { namespace test { +constexpr RtpPacketToSend::ExtensionManager* kNoExtensions = nullptr; + RtpFormatVp8TestHelper::RtpFormatVp8TestHelper(const RTPVideoHeaderVP8* hdr) - : payload_data_(NULL), - buffer_(NULL), + : packet_(kNoExtensions), + payload_data_(NULL), data_ptr_(NULL), fragmentation_(NULL), hdr_info_(hdr), payload_start_(0), payload_size_(0), - buffer_size_(0), sloppy_partitioning_(false), inited_(false) {} RtpFormatVp8TestHelper::~RtpFormatVp8TestHelper() { delete fragmentation_; delete [] payload_data_; - delete [] buffer_; } bool RtpFormatVp8TestHelper::Init(const size_t* partition_sizes, @@ -45,9 +45,7 @@ bool RtpFormatVp8TestHelper::Init(const size_t* partition_sizes, for (size_t p = 0; p < num_partitions; ++p) { payload_size_ += partition_sizes[p]; } - buffer_size_ = payload_size_ + 6; // Add space for payload descriptor. payload_data_ = new uint8_t[payload_size_]; - buffer_ = new uint8_t[buffer_size_]; size_t j = 0; // Loop through the partitions again. for (size_t p = 0; p < num_partitions; ++p) { @@ -70,15 +68,13 @@ void RtpFormatVp8TestHelper::GetAllPacketsAndCheck( const bool* expected_frag_start, size_t expected_num_packets) { ASSERT_TRUE(inited_); - size_t send_bytes = 0; bool last = false; for (size_t i = 0; i < expected_num_packets; ++i) { std::ostringstream ss; ss << "Checking packet " << i; SCOPED_TRACE(ss.str()); - EXPECT_TRUE(packetizer->NextPacket(buffer_, &send_bytes, &last)); - CheckPacket(send_bytes, expected_sizes[i], last, - expected_frag_start[i]); + EXPECT_TRUE(packetizer->NextPacket(&packet_, &last)); + CheckPacket(expected_sizes[i], last, expected_frag_start[i]); } EXPECT_TRUE(last); } @@ -127,67 +123,68 @@ void RtpFormatVp8TestHelper::GetAllPacketsAndCheck( void RtpFormatVp8TestHelper::CheckHeader(bool frag_start) { payload_start_ = 1; - EXPECT_BIT_EQ(buffer_[0], 6, 0); // Check reserved bit. + rtc::ArrayView buffer = packet_.payload(); + EXPECT_BIT_EQ(buffer[0], 6, 0); // Check reserved bit. if (hdr_info_->pictureId != kNoPictureId || hdr_info_->temporalIdx != kNoTemporalIdx || hdr_info_->tl0PicIdx != kNoTl0PicIdx || hdr_info_->keyIdx != kNoKeyIdx) { - EXPECT_BIT_X_EQ(buffer_[0], 1); + EXPECT_BIT_X_EQ(buffer[0], 1); ++payload_start_; CheckPictureID(); CheckTl0PicIdx(); CheckTIDAndKeyIdx(); } else { - EXPECT_BIT_X_EQ(buffer_[0], 0); + EXPECT_BIT_X_EQ(buffer[0], 0); } - EXPECT_BIT_N_EQ(buffer_[0], hdr_info_->nonReference ? 1 : 0); - EXPECT_BIT_S_EQ(buffer_[0], frag_start ? 1 : 0); + EXPECT_BIT_N_EQ(buffer[0], hdr_info_->nonReference ? 1 : 0); + EXPECT_BIT_S_EQ(buffer[0], frag_start ? 1 : 0); // Check partition index. if (!sloppy_partitioning_) { // The test payload data is constructed such that the payload value is the // same as the partition index. - EXPECT_EQ(buffer_[0] & 0x0F, buffer_[payload_start_]); + EXPECT_EQ(buffer[0] & 0x0F, buffer[payload_start_]); } else { // Partition should be set to 0. - EXPECT_EQ(buffer_[0] & 0x0F, 0); + EXPECT_EQ(buffer[0] & 0x0F, 0); } } // Verify that the I bit and the PictureID field are both set in accordance // with the information in hdr_info_->pictureId. void RtpFormatVp8TestHelper::CheckPictureID() { + auto buffer = packet_.payload(); if (hdr_info_->pictureId != kNoPictureId) { - EXPECT_BIT_I_EQ(buffer_[1], 1); + EXPECT_BIT_I_EQ(buffer[1], 1); if (hdr_info_->pictureId > 0x7F) { - EXPECT_BIT_EQ(buffer_[payload_start_], 7, 1); - EXPECT_EQ(buffer_[payload_start_] & 0x7F, + EXPECT_BIT_EQ(buffer[payload_start_], 7, 1); + EXPECT_EQ(buffer[payload_start_] & 0x7F, (hdr_info_->pictureId >> 8) & 0x7F); - EXPECT_EQ(buffer_[payload_start_ + 1], - hdr_info_->pictureId & 0xFF); + EXPECT_EQ(buffer[payload_start_ + 1], hdr_info_->pictureId & 0xFF); payload_start_ += 2; } else { - EXPECT_BIT_EQ(buffer_[payload_start_], 7, 0); - EXPECT_EQ(buffer_[payload_start_] & 0x7F, - (hdr_info_->pictureId) & 0x7F); + EXPECT_BIT_EQ(buffer[payload_start_], 7, 0); + EXPECT_EQ(buffer[payload_start_] & 0x7F, (hdr_info_->pictureId) & 0x7F); payload_start_ += 1; } } else { - EXPECT_BIT_I_EQ(buffer_[1], 0); + EXPECT_BIT_I_EQ(buffer[1], 0); } } // Verify that the L bit and the TL0PICIDX field are both set in accordance // with the information in hdr_info_->tl0PicIdx. void RtpFormatVp8TestHelper::CheckTl0PicIdx() { + auto buffer = packet_.payload(); if (hdr_info_->tl0PicIdx != kNoTl0PicIdx) { - EXPECT_BIT_L_EQ(buffer_[1], 1); - EXPECT_EQ(buffer_[payload_start_], hdr_info_->tl0PicIdx); + EXPECT_BIT_L_EQ(buffer[1], 1); + EXPECT_EQ(buffer[payload_start_], hdr_info_->tl0PicIdx); ++payload_start_; } else { - EXPECT_BIT_L_EQ(buffer_[1], 0); + EXPECT_BIT_L_EQ(buffer[1], 0); } } @@ -195,36 +192,39 @@ void RtpFormatVp8TestHelper::CheckTl0PicIdx() { // field are all set in accordance with the information in // hdr_info_->temporalIdx and hdr_info_->keyIdx, respectively. void RtpFormatVp8TestHelper::CheckTIDAndKeyIdx() { + auto buffer = packet_.payload(); if (hdr_info_->temporalIdx == kNoTemporalIdx && hdr_info_->keyIdx == kNoKeyIdx) { - EXPECT_BIT_T_EQ(buffer_[1], 0); - EXPECT_BIT_K_EQ(buffer_[1], 0); + EXPECT_BIT_T_EQ(buffer[1], 0); + EXPECT_BIT_K_EQ(buffer[1], 0); return; } if (hdr_info_->temporalIdx != kNoTemporalIdx) { - EXPECT_BIT_T_EQ(buffer_[1], 1); - EXPECT_TID_EQ(buffer_[payload_start_], hdr_info_->temporalIdx); - EXPECT_BIT_Y_EQ(buffer_[payload_start_], hdr_info_->layerSync ? 1 : 0); + EXPECT_BIT_T_EQ(buffer[1], 1); + EXPECT_TID_EQ(buffer[payload_start_], hdr_info_->temporalIdx); + EXPECT_BIT_Y_EQ(buffer[payload_start_], hdr_info_->layerSync ? 1 : 0); } else { - EXPECT_BIT_T_EQ(buffer_[1], 0); - EXPECT_TID_EQ(buffer_[payload_start_], 0); - EXPECT_BIT_Y_EQ(buffer_[payload_start_], 0); + EXPECT_BIT_T_EQ(buffer[1], 0); + EXPECT_TID_EQ(buffer[payload_start_], 0); + EXPECT_BIT_Y_EQ(buffer[payload_start_], 0); } if (hdr_info_->keyIdx != kNoKeyIdx) { - EXPECT_BIT_K_EQ(buffer_[1], 1); - EXPECT_KEYIDX_EQ(buffer_[payload_start_], hdr_info_->keyIdx); + EXPECT_BIT_K_EQ(buffer[1], 1); + EXPECT_KEYIDX_EQ(buffer[payload_start_], hdr_info_->keyIdx); } else { - EXPECT_BIT_K_EQ(buffer_[1], 0); - EXPECT_KEYIDX_EQ(buffer_[payload_start_], 0); + EXPECT_BIT_K_EQ(buffer[1], 0); + EXPECT_KEYIDX_EQ(buffer[payload_start_], 0); } ++payload_start_; } // Verify that the payload (i.e., after the headers) of the packet stored in // buffer_ is identical to the expected (as found in data_ptr_). -void RtpFormatVp8TestHelper::CheckPayload(size_t payload_end) { +void RtpFormatVp8TestHelper::CheckPayload() { + auto buffer = packet_.payload(); + size_t payload_end = buffer.size(); for (size_t i = payload_start_; i < payload_end; ++i, ++data_ptr_) - EXPECT_EQ(buffer_[i], *data_ptr_); + EXPECT_EQ(buffer[i], *data_ptr_); } // Verify that the input variable "last" agrees with the position of data_ptr_. @@ -236,13 +236,12 @@ void RtpFormatVp8TestHelper::CheckLast(bool last) const { // Verify the contents of a packet. Check the length versus expected_bytes, // the header, payload, and "last" flag. -void RtpFormatVp8TestHelper::CheckPacket(size_t send_bytes, - size_t expect_bytes, +void RtpFormatVp8TestHelper::CheckPacket(size_t expect_bytes, bool last, bool frag_start) { - EXPECT_EQ(expect_bytes, send_bytes); + EXPECT_EQ(expect_bytes, packet_.payload_size()); CheckHeader(frag_start); - CheckPayload(send_bytes); + CheckPayload(); CheckLast(last); } diff --git a/webrtc/modules/rtp_rtcp/source/rtp_format_vp8_test_helper.h b/webrtc/modules/rtp_rtcp/source/rtp_format_vp8_test_helper.h index 668476833d..c71ba71af3 100644 --- a/webrtc/modules/rtp_rtcp/source/rtp_format_vp8_test_helper.h +++ b/webrtc/modules/rtp_rtcp/source/rtp_format_vp8_test_helper.h @@ -21,6 +21,7 @@ #include "webrtc/base/constructormagic.h" #include "webrtc/modules/include/module_common_types.h" #include "webrtc/modules/rtp_rtcp/source/rtp_format_vp8.h" +#include "webrtc/modules/rtp_rtcp/source/rtp_packet_to_send.h" #include "webrtc/typedefs.h" namespace webrtc { @@ -41,7 +42,10 @@ class RtpFormatVp8TestHelper { uint8_t* payload_data() const { return payload_data_; } size_t payload_size() const { return payload_size_; } RTPFragmentationHeader* fragmentation() const { return fragmentation_; } - size_t buffer_size() const { return buffer_size_; } + size_t buffer_size() const { + static constexpr size_t kVp8PayloadDescriptorMaxSize = 6; + return payload_size_ + kVp8PayloadDescriptorMaxSize; + } void set_sloppy_partitioning(bool value) { sloppy_partitioning_ = value; } private: @@ -49,19 +53,17 @@ class RtpFormatVp8TestHelper { void CheckPictureID(); void CheckTl0PicIdx(); void CheckTIDAndKeyIdx(); - void CheckPayload(size_t payload_end); + void CheckPayload(); void CheckLast(bool last) const; - void CheckPacket(size_t send_bytes, size_t expect_bytes, bool last, - bool frag_start); + void CheckPacket(size_t expect_bytes, bool last, bool frag_start); + RtpPacketToSend packet_; uint8_t* payload_data_; - uint8_t* buffer_; uint8_t* data_ptr_; RTPFragmentationHeader* fragmentation_; const RTPVideoHeaderVP8* hdr_info_; int payload_start_; size_t payload_size_; - size_t buffer_size_; bool sloppy_partitioning_; bool inited_; diff --git a/webrtc/modules/rtp_rtcp/source/rtp_format_vp8_unittest.cc b/webrtc/modules/rtp_rtcp/source/rtp_format_vp8_unittest.cc index ce39095350..0e1a474e35 100644 --- a/webrtc/modules/rtp_rtcp/source/rtp_format_vp8_unittest.cc +++ b/webrtc/modules/rtp_rtcp/source/rtp_format_vp8_unittest.cc @@ -12,6 +12,7 @@ #include "webrtc/modules/rtp_rtcp/source/rtp_format_vp8.h" #include "webrtc/modules/rtp_rtcp/source/rtp_format_vp8_test_helper.h" +#include "webrtc/modules/rtp_rtcp/source/rtp_packet_to_send.h" #include "webrtc/test/gmock.h" #include "webrtc/test/gtest.h" #include "webrtc/typedefs.h" @@ -22,6 +23,11 @@ namespace webrtc { namespace { + +using ::testing::ElementsAreArray; +using ::testing::make_tuple; + +constexpr RtpPacketToSend::ExtensionManager* kNoExtensions = nullptr; // Payload descriptor // 0 1 2 3 4 5 6 7 // +-+-+-+-+-+-+-+-+ @@ -100,8 +106,8 @@ TEST_F(RtpPacketizerVp8Test, TestStrictMode) { ASSERT_TRUE(Init(kSizeVector, kNumPartitions)); hdr_info_.pictureId = 200; // > 0x7F should produce 2-byte PictureID. - const size_t kMaxSize = 13; - RtpPacketizerVp8 packetizer(hdr_info_, kMaxSize, kStrict); + const size_t kMaxPayloadSize = 13; + RtpPacketizerVp8 packetizer(hdr_info_, kMaxPayloadSize, kStrict); packetizer.SetPayloadData(helper_->payload_data(), helper_->payload_size(), helper_->fragmentation()); @@ -131,8 +137,8 @@ TEST_F(RtpPacketizerVp8Test, DISABLED_TestStrictEqualTightPartitions) { ASSERT_TRUE(Init(kSizeVector, kNumPartitions)); hdr_info_.pictureId = 200; // > 0x7F should produce 2-byte PictureID. - const int kMaxSize = 14; - RtpPacketizerVp8 packetizer(hdr_info_, kMaxSize, kStrict); + const int kMaxPayloadSize = 14; + RtpPacketizerVp8 packetizer(hdr_info_, kMaxPayloadSize, kStrict); packetizer.SetPayloadData(helper_->payload_data(), helper_->payload_size(), helper_->fragmentation()); @@ -154,8 +160,8 @@ TEST_F(RtpPacketizerVp8Test, TestAggregateMode) { ASSERT_TRUE(Init(kSizeVector, kNumPartitions)); hdr_info_.pictureId = 20; // <= 0x7F should produce 1-byte PictureID. - const size_t kMaxSize = 25; - RtpPacketizerVp8 packetizer(hdr_info_, kMaxSize, kAggregate); + const size_t kMaxPayloadSize = 25; + RtpPacketizerVp8 packetizer(hdr_info_, kMaxPayloadSize, kAggregate); packetizer.SetPayloadData(helper_->payload_data(), helper_->payload_size(), helper_->fragmentation()); @@ -181,8 +187,8 @@ TEST_F(RtpPacketizerVp8Test, TestAggregateModeManyPartitions1) { ASSERT_TRUE(Init(kSizeVector, kNumPartitions)); hdr_info_.pictureId = 20; // <= 0x7F should produce 1-byte PictureID. - const size_t kMaxSize = 1500; - RtpPacketizerVp8 packetizer(hdr_info_, kMaxSize, kAggregate); + const size_t kMaxPayloadSize = 1000; + RtpPacketizerVp8 packetizer(hdr_info_, kMaxPayloadSize, kAggregate); packetizer.SetPayloadData(helper_->payload_data(), helper_->payload_size(), helper_->fragmentation()); @@ -208,8 +214,8 @@ TEST_F(RtpPacketizerVp8Test, TestAggregateModeManyPartitions2) { ASSERT_TRUE(Init(kSizeVector, kNumPartitions)); hdr_info_.pictureId = 20; // <= 0x7F should produce 1-byte PictureID. - const size_t kMaxSize = 1500; - RtpPacketizerVp8 packetizer(hdr_info_, kMaxSize, kAggregate); + const size_t kMaxPayloadSize = 1000; + RtpPacketizerVp8 packetizer(hdr_info_, kMaxPayloadSize, kAggregate); packetizer.SetPayloadData(helper_->payload_data(), helper_->payload_size(), helper_->fragmentation()); @@ -235,8 +241,8 @@ TEST_F(RtpPacketizerVp8Test, TestAggregateModeTwoLargePartitions) { ASSERT_TRUE(Init(kSizeVector, kNumPartitions)); hdr_info_.pictureId = 20; // <= 0x7F should produce 1-byte PictureID. - const size_t kMaxSize = 1460; - RtpPacketizerVp8 packetizer(hdr_info_, kMaxSize, kAggregate); + const size_t kMaxPayloadSize = 1460; + RtpPacketizerVp8 packetizer(hdr_info_, kMaxPayloadSize, kAggregate); packetizer.SetPayloadData(helper_->payload_data(), helper_->payload_size(), helper_->fragmentation()); @@ -262,9 +268,9 @@ TEST_F(RtpPacketizerVp8Test, TestEqualSizeModeFallback) { const size_t kNumPartitions = GTEST_ARRAY_SIZE_(kSizeVector); ASSERT_TRUE(Init(kSizeVector, kNumPartitions)); - hdr_info_.pictureId = 200; // > 0x7F should produce 2-byte PictureID - const size_t kMaxSize = 12; // Small enough to produce 4 packets. - RtpPacketizerVp8 packetizer(hdr_info_, kMaxSize); + hdr_info_.pictureId = 200; // > 0x7F should produce 2-byte PictureID + const size_t kMaxPayloadSize = 12; // Small enough to produce 4 packets. + RtpPacketizerVp8 packetizer(hdr_info_, kMaxPayloadSize); packetizer.SetPayloadData( helper_->payload_data(), helper_->payload_size(), NULL); @@ -292,8 +298,8 @@ TEST_F(RtpPacketizerVp8Test, TestNonReferenceBit) { ASSERT_TRUE(Init(kSizeVector, kNumPartitions)); hdr_info_.nonReference = true; - const size_t kMaxSize = 25; // Small enough to produce two packets. - RtpPacketizerVp8 packetizer(hdr_info_, kMaxSize); + const size_t kMaxPayloadSize = 25; // Small enough to produce two packets. + RtpPacketizerVp8 packetizer(hdr_info_, kMaxPayloadSize); packetizer.SetPayloadData( helper_->payload_data(), helper_->payload_size(), NULL); @@ -323,9 +329,9 @@ TEST_F(RtpPacketizerVp8Test, TestTl0PicIdxAndTID) { hdr_info_.tl0PicIdx = 117; hdr_info_.temporalIdx = 2; hdr_info_.layerSync = true; - // kMaxSize is only limited by allocated buffer size. - const size_t kMaxSize = helper_->buffer_size(); - RtpPacketizerVp8 packetizer(hdr_info_, kMaxSize, kAggregate); + // kMaxPayloadSize is only limited by allocated buffer size. + const size_t kMaxPayloadSize = helper_->buffer_size(); + RtpPacketizerVp8 packetizer(hdr_info_, kMaxPayloadSize, kAggregate); packetizer.SetPayloadData(helper_->payload_data(), helper_->payload_size(), helper_->fragmentation()); @@ -352,9 +358,9 @@ TEST_F(RtpPacketizerVp8Test, TestKeyIdx) { ASSERT_TRUE(Init(kSizeVector, kNumPartitions)); hdr_info_.keyIdx = 17; - // kMaxSize is only limited by allocated buffer size. - const size_t kMaxSize = helper_->buffer_size(); - RtpPacketizerVp8 packetizer(hdr_info_, kMaxSize, kAggregate); + // kMaxPayloadSize is only limited by allocated buffer size. + const size_t kMaxPayloadSize = helper_->buffer_size(); + RtpPacketizerVp8 packetizer(hdr_info_, kMaxPayloadSize, kAggregate); packetizer.SetPayloadData(helper_->payload_data(), helper_->payload_size(), helper_->fragmentation()); @@ -382,9 +388,9 @@ TEST_F(RtpPacketizerVp8Test, TestTIDAndKeyIdx) { hdr_info_.temporalIdx = 1; hdr_info_.keyIdx = 5; - // kMaxSize is only limited by allocated buffer size. - const size_t kMaxSize = helper_->buffer_size(); - RtpPacketizerVp8 packetizer(hdr_info_, kMaxSize, kAggregate); + // kMaxPayloadSize is only limited by allocated buffer size. + const size_t kMaxPayloadSize = helper_->buffer_size(); + RtpPacketizerVp8 packetizer(hdr_info_, kMaxPayloadSize, kAggregate); packetizer.SetPayloadData(helper_->payload_data(), helper_->payload_size(), helper_->fragmentation()); @@ -432,6 +438,7 @@ TEST_F(RtpDepacketizerVp8Test, BasicHeader) { ASSERT_TRUE(depacketizer_->Parse(&payload, packet, sizeof(packet))); ExpectPacket( &payload, packet + kHeaderLength, sizeof(packet) - kHeaderLength); + EXPECT_EQ(kVideoFrameDelta, payload.frame_type); EXPECT_EQ(kRtpVideoVp8, payload.type.Video.codec); VerifyBasicHeader(&payload.type, 0, 1, 4); @@ -564,7 +571,7 @@ TEST_F(RtpDepacketizerVp8Test, TooShortHeader) { TEST_F(RtpDepacketizerVp8Test, TestWithPacketizer) { const uint8_t kHeaderLength = 5; uint8_t data[10] = {0}; - uint8_t packet[20] = {0}; + RtpPacketToSend packet(kNoExtensions); RTPVideoHeaderVP8 input_header; input_header.nonReference = true; input_header.pictureId = 300; @@ -575,14 +582,16 @@ TEST_F(RtpDepacketizerVp8Test, TestWithPacketizer) { RtpPacketizerVp8 packetizer(input_header, 20); packetizer.SetPayloadData(data, 10, NULL); bool last; - size_t send_bytes; - ASSERT_TRUE(packetizer.NextPacket(packet, &send_bytes, &last)); - ASSERT_TRUE(last); - RtpDepacketizer::ParsedPayload payload; + ASSERT_TRUE(packetizer.NextPacket(&packet, &last)); + EXPECT_TRUE(last); + EXPECT_TRUE(packet.Marker()); - ASSERT_TRUE(depacketizer_->Parse(&payload, packet, sizeof(packet))); - ExpectPacket( - &payload, packet + kHeaderLength, sizeof(packet) - kHeaderLength); + auto rtp_payload = packet.payload(); + RtpDepacketizer::ParsedPayload payload; + ASSERT_TRUE( + depacketizer_->Parse(&payload, rtp_payload.data(), rtp_payload.size())); + auto vp8_payload = rtp_payload.subview(kHeaderLength); + ExpectPacket(&payload, vp8_payload.data(), vp8_payload.size()); EXPECT_EQ(kVideoFrameKey, payload.frame_type); EXPECT_EQ(kRtpVideoVp8, payload.type.Video.codec); VerifyBasicHeader(&payload.type, 1, 1, 0); diff --git a/webrtc/modules/rtp_rtcp/source/rtp_format_vp9.cc b/webrtc/modules/rtp_rtcp/source/rtp_format_vp9.cc index d2f22d5044..b77d6a3b72 100644 --- a/webrtc/modules/rtp_rtcp/source/rtp_format_vp9.cc +++ b/webrtc/modules/rtp_rtcp/source/rtp_format_vp9.cc @@ -18,6 +18,7 @@ #include "webrtc/base/bitbuffer.h" #include "webrtc/base/checks.h" #include "webrtc/base/logging.h" +#include "webrtc/modules/rtp_rtcp/source/rtp_packet_to_send.h" #define RETURN_FALSE_ON_ERROR(x) \ if (!(x)) { \ @@ -545,21 +546,22 @@ void RtpPacketizerVp9::GeneratePackets() { assert(bytes_processed == payload_size_); } -bool RtpPacketizerVp9::NextPacket(uint8_t* buffer, - size_t* bytes_to_send, - bool* last_packet) { +bool RtpPacketizerVp9::NextPacket(RtpPacketToSend* packet, bool* last_packet) { + RTC_DCHECK(packet); + RTC_DCHECK(last_packet); if (packets_.empty()) { return false; } PacketInfo packet_info = packets_.front(); packets_.pop(); - if (!WriteHeaderAndPayload(packet_info, buffer, bytes_to_send)) { + if (!WriteHeaderAndPayload(packet_info, packet)) { return false; } - *last_packet = - packets_.empty() && (hdr_.spatial_idx == kNoSpatialIdx || - hdr_.spatial_idx == hdr_.num_spatial_layers - 1); + *last_packet = packets_.empty(); + packet->SetMarker(packets_.empty() && + (hdr_.spatial_idx == kNoSpatialIdx || + hdr_.spatial_idx == hdr_.num_spatial_layers - 1)); return true; } @@ -600,8 +602,9 @@ bool RtpPacketizerVp9::NextPacket(uint8_t* buffer, // +-+-+-+-+-+-+-+-+ bool RtpPacketizerVp9::WriteHeaderAndPayload(const PacketInfo& packet_info, - uint8_t* buffer, - size_t* bytes_to_send) const { + RtpPacketToSend* packet) const { + uint8_t* buffer = packet->AllocatePayload(max_payload_length_); + RTC_DCHECK(buffer); size_t header_length; if (!WriteHeader(packet_info, buffer, &header_length)) return false; @@ -610,7 +613,7 @@ bool RtpPacketizerVp9::WriteHeaderAndPayload(const PacketInfo& packet_info, memcpy(&buffer[header_length], &payload_[packet_info.payload_start_pos], packet_info.size); - *bytes_to_send = header_length + packet_info.size; + packet->SetPayloadSize(header_length + packet_info.size); return true; } diff --git a/webrtc/modules/rtp_rtcp/source/rtp_format_vp9.h b/webrtc/modules/rtp_rtcp/source/rtp_format_vp9.h index 3feca4392a..2036ce49f4 100644 --- a/webrtc/modules/rtp_rtcp/source/rtp_format_vp9.h +++ b/webrtc/modules/rtp_rtcp/source/rtp_format_vp9.h @@ -49,15 +49,11 @@ class RtpPacketizerVp9 : public RtpPacketizer { const RTPFragmentationHeader* fragmentation) override; // Gets the next payload with VP9 payload header. - // |buffer| is a pointer to where the output will be written. - // |bytes_to_send| is an output variable that will contain number of bytes - // written to buffer. - // |last_packet| is true for the last packet of the frame, false otherwise - // (i.e. call the function again to get the next packet). + // Write payload and set marker bit of the |packet|. + // The parameter |last_packet| is true for the last packet of the frame, false + // otherwise (i.e., call the function again to get the next packet). // Returns true on success, false otherwise. - bool NextPacket(uint8_t* buffer, - size_t* bytes_to_send, - bool* last_packet) override; + bool NextPacket(RtpPacketToSend* packet, bool* last_packet) override; typedef struct { size_t payload_start_pos; @@ -76,8 +72,7 @@ class RtpPacketizerVp9 : public RtpPacketizer { // |bytes_to_send| contains the number of written bytes to the buffer. // Returns true on success, false otherwise. bool WriteHeaderAndPayload(const PacketInfo& packet_info, - uint8_t* buffer, - size_t* bytes_to_send) const; + RtpPacketToSend* packet) const; // Writes payload descriptor header to |buffer|. // Returns true on success, false otherwise. diff --git a/webrtc/modules/rtp_rtcp/source/rtp_format_vp9_unittest.cc b/webrtc/modules/rtp_rtcp/source/rtp_format_vp9_unittest.cc index 2848ea0dd0..3f1ead87b5 100644 --- a/webrtc/modules/rtp_rtcp/source/rtp_format_vp9_unittest.cc +++ b/webrtc/modules/rtp_rtcp/source/rtp_format_vp9_unittest.cc @@ -12,6 +12,7 @@ #include #include "webrtc/modules/rtp_rtcp/source/rtp_format_vp9.h" +#include "webrtc/modules/rtp_rtcp/source/rtp_packet_to_send.h" #include "webrtc/test/gmock.h" #include "webrtc/test/gtest.h" #include "webrtc/typedefs.h" @@ -123,12 +124,15 @@ void ParseAndCheckPacket(const uint8_t* packet, class RtpPacketizerVp9Test : public ::testing::Test { protected: - RtpPacketizerVp9Test() {} + static constexpr RtpPacketToSend::ExtensionManager* kNoExtensions = nullptr; + static constexpr size_t kMaxPacketSize = 1200; + + RtpPacketizerVp9Test() : packet_(kNoExtensions, kMaxPacketSize) {} virtual void SetUp() { expected_.InitRTPVideoHeaderVP9(); } - std::unique_ptr packet_; + RtpPacketToSend packet_; std::unique_ptr payload_; size_t payload_size_; size_t payload_pos_; @@ -142,9 +146,6 @@ class RtpPacketizerVp9Test : public ::testing::Test { payload_pos_ = 0; packetizer_.reset(new RtpPacketizerVp9(expected_, packet_size)); packetizer_->SetPayloadData(payload_.get(), payload_size_, NULL); - - const int kMaxPayloadDescriptorLength = 100; - packet_.reset(new uint8_t[payload_size_ + kMaxPayloadDescriptorLength]); } void CheckPayload(const uint8_t* packet, @@ -161,20 +162,22 @@ class RtpPacketizerVp9Test : public ::testing::Test { const size_t* expected_sizes, size_t expected_num_packets) { ASSERT_TRUE(packetizer_.get() != NULL); - size_t length = 0; bool last = false; if (expected_num_packets == 0) { - EXPECT_FALSE(packetizer_->NextPacket(packet_.get(), &length, &last)); + EXPECT_FALSE(packetizer_->NextPacket(&packet_, &last)); return; } for (size_t i = 0; i < expected_num_packets; ++i) { - EXPECT_TRUE(packetizer_->NextPacket(packet_.get(), &length, &last)); - EXPECT_EQ(expected_sizes[i], length); + EXPECT_TRUE(packetizer_->NextPacket(&packet_, &last)); + auto rtp_payload = packet_.payload(); + EXPECT_EQ(expected_sizes[i], rtp_payload.size()); RTPVideoHeaderVP9 hdr = expected_; hdr.beginning_of_frame = (i == 0); hdr.end_of_frame = last; - ParseAndCheckPacket(packet_.get(), hdr, expected_hdr_sizes[i], length); - CheckPayload(packet_.get(), expected_hdr_sizes[i], length, last); + ParseAndCheckPacket(rtp_payload.data(), hdr, expected_hdr_sizes[i], + rtp_payload.size()); + CheckPayload(rtp_payload.data(), expected_hdr_sizes[i], + rtp_payload.size(), last); } EXPECT_TRUE(last); } @@ -429,6 +432,51 @@ TEST_F(RtpPacketizerVp9Test, TestSsData) { CreateParseAndCheckPackets(kExpectedHdrSizes, kExpectedSizes, kExpectedNum); } +TEST_F(RtpPacketizerVp9Test, TestOnlyHighestSpatialLayerSetMarker) { + const size_t kFrameSize = 10; + const size_t kPacketSize = 9; // 2 packet per frame. + const uint8_t kFrame[kFrameSize] = {7}; + const RTPFragmentationHeader* kNoFragmentation = nullptr; + + RTPVideoHeaderVP9 vp9_header; + vp9_header.InitRTPVideoHeaderVP9(); + vp9_header.flexible_mode = true; + vp9_header.num_spatial_layers = 3; + + RtpPacketToSend packet(kNoExtensions); + bool last; + + vp9_header.spatial_idx = 0; + RtpPacketizerVp9 packetizer0(vp9_header, kPacketSize); + packetizer0.SetPayloadData(kFrame, sizeof(kFrame), kNoFragmentation); + ASSERT_TRUE(packetizer0.NextPacket(&packet, &last)); + EXPECT_FALSE(last); + EXPECT_FALSE(packet.Marker()); + ASSERT_TRUE(packetizer0.NextPacket(&packet, &last)); + EXPECT_TRUE(last); + EXPECT_FALSE(packet.Marker()); + + vp9_header.spatial_idx = 1; + RtpPacketizerVp9 packetizer1(vp9_header, kPacketSize); + packetizer1.SetPayloadData(kFrame, sizeof(kFrame), kNoFragmentation); + ASSERT_TRUE(packetizer1.NextPacket(&packet, &last)); + EXPECT_FALSE(last); + EXPECT_FALSE(packet.Marker()); + ASSERT_TRUE(packetizer1.NextPacket(&packet, &last)); + EXPECT_TRUE(last); + EXPECT_FALSE(packet.Marker()); + + vp9_header.spatial_idx = 2; + RtpPacketizerVp9 packetizer2(vp9_header, kPacketSize); + packetizer2.SetPayloadData(kFrame, sizeof(kFrame), kNoFragmentation); + ASSERT_TRUE(packetizer2.NextPacket(&packet, &last)); + EXPECT_FALSE(last); + EXPECT_FALSE(packet.Marker()); + ASSERT_TRUE(packetizer2.NextPacket(&packet, &last)); + EXPECT_TRUE(last); + EXPECT_TRUE(packet.Marker()); +} + TEST_F(RtpPacketizerVp9Test, TestBaseLayerProtectionAndStorageType) { const size_t kFrameSize = 10; const size_t kPacketSize = 12; diff --git a/webrtc/modules/rtp_rtcp/source/rtp_sender_video.cc b/webrtc/modules/rtp_rtcp/source/rtp_sender_video.cc index 22bf1079d0..490bfbae4a 100644 --- a/webrtc/modules/rtp_rtcp/source/rtp_sender_video.cc +++ b/webrtc/modules/rtp_rtcp/source/rtp_sender_video.cc @@ -362,15 +362,11 @@ bool RTPSenderVideo::SendVideo(RtpVideoCodecTypes video_type, bool last = false; while (!last) { std::unique_ptr packet(new RtpPacketToSend(*rtp_header)); - uint8_t* payload = packet->AllocatePayload(max_data_payload_length); - RTC_DCHECK(payload); - size_t payload_bytes_in_packet = 0; - if (!packetizer->NextPacket(payload, &payload_bytes_in_packet, &last)) + if (!packetizer->NextPacket(packet.get(), &last)) return false; + RTC_DCHECK_LE(packet->payload_size(), max_data_payload_length); - packet->SetPayloadSize(payload_bytes_in_packet); - packet->SetMarker(last); if (!rtp_sender_->AssignSequenceNumber(packet.get())) return false;