Index: webrtc/modules/rtp_rtcp/source/rtp_format_h264_unittest.cc |
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 12c2db564bda22447678ab95eee7c311636d988e..d4cffaea02816db69aeb58301ca379bf047fe3a6 100644 |
--- a/webrtc/modules/rtp_rtcp/source/rtp_format_h264_unittest.cc |
+++ b/webrtc/modules/rtp_rtcp/source/rtp_format_h264_unittest.cc |
@@ -15,6 +15,8 @@ |
#include "testing/gtest/include/gtest/gtest.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/common_video/h264/h264_common.h" |
#include "webrtc/modules/rtp_rtcp/source/rtp_format.h" |
namespace webrtc { |
@@ -379,6 +381,106 @@ TEST(RtpPacketizerH264Test, TestFUABig) { |
sizeof(kExpectedPayloadSizes) / sizeof(size_t))); |
} |
+namespace { |
+const uint8_t kStartSequence[] = {0x00, 0x00, 0x00, 0x01}; |
+const uint8_t kOriginalSps[] = {kSps, 0x00, 0x00, 0x03, 0x03, |
+ 0xF4, 0x05, 0x03, 0xC7, 0xC0}; |
+const uint8_t kRewrittenSps[] = {kSps, 0x00, 0x00, 0x03, 0x03, 0xF4, 0x05, 0x03, |
+ 0xC7, 0xE0, 0x1B, 0x41, 0x10, 0x8D, 0x00}; |
+const uint8_t kIdrOne[] = {kIdr, 0xFF, 0x00, 0x00, 0x04}; |
+const uint8_t kIdrTwo[] = {kIdr, 0xFF, 0x00, 0x11}; |
+} |
+ |
+class RtpPacketizerH264TestSpsRewriting : public ::testing::Test { |
+ public: |
+ void SetUp() override { |
+ fragmentation_header_.VerifyAndAllocateFragmentationHeader(3); |
+ fragmentation_header_.fragmentationVectorSize = 3; |
+ in_buffer_.AppendData(kStartSequence); |
+ |
+ fragmentation_header_.fragmentationOffset[0] = in_buffer_.size(); |
+ fragmentation_header_.fragmentationLength[0] = sizeof(kOriginalSps); |
+ in_buffer_.AppendData(kOriginalSps); |
+ |
+ fragmentation_header_.fragmentationOffset[1] = in_buffer_.size(); |
+ fragmentation_header_.fragmentationLength[1] = sizeof(kIdrOne); |
+ in_buffer_.AppendData(kIdrOne); |
+ |
+ fragmentation_header_.fragmentationOffset[2] = in_buffer_.size(); |
+ fragmentation_header_.fragmentationLength[2] = sizeof(kIdrTwo); |
+ in_buffer_.AppendData(kIdrTwo); |
+ } |
+ |
+ protected: |
+ rtc::Buffer in_buffer_; |
+ RTPFragmentationHeader fragmentation_header_; |
+ std::unique_ptr<RtpPacketizer> packetizer_; |
+}; |
+ |
+TEST_F(RtpPacketizerH264TestSpsRewriting, FuASps) { |
+ const size_t kHeaderOverhead = kFuAHeaderSize + 1; |
+ |
+ // Set size to fragment SPS into two FU-A packets. |
+ packetizer_.reset(RtpPacketizer::Create( |
+ kRtpVideoH264, sizeof(kOriginalSps) - 2 + kHeaderOverhead, nullptr, |
+ kEmptyFrame)); |
+ |
+ packetizer_->SetPayloadData(in_buffer_.data(), in_buffer_.size(), |
+ &fragmentation_header_); |
+ |
+ bool last_packet = true; |
+ uint8_t buffer[sizeof(kOriginalSps) + kHeaderOverhead] = {}; |
+ size_t num_bytes = 0; |
+ |
+ EXPECT_TRUE(packetizer_->NextPacket(buffer, &num_bytes, &last_packet)); |
+ size_t offset = H264::kNaluTypeSize; |
+ size_t length = num_bytes - kFuAHeaderSize; |
+ std::vector<uint8_t> expected_payload(&kRewrittenSps[offset], |
+ &kRewrittenSps[offset + length]); |
+ EXPECT_THAT(expected_payload, |
+ ::testing::ElementsAreArray(&buffer[kFuAHeaderSize], length)); |
+ offset += length; |
+ |
+ EXPECT_TRUE(packetizer_->NextPacket(buffer, &num_bytes, &last_packet)); |
+ length = num_bytes - kFuAHeaderSize; |
+ expected_payload = std::vector<uint8_t>(&kRewrittenSps[offset], |
+ &kRewrittenSps[offset + length]); |
+ EXPECT_THAT(expected_payload, |
+ ::testing::ElementsAreArray(&buffer[kFuAHeaderSize], length)); |
+ offset += length; |
+ |
+ EXPECT_EQ(offset, sizeof(kRewrittenSps)); |
+} |
+ |
+TEST_F(RtpPacketizerH264TestSpsRewriting, StapASps) { |
+ const size_t kHeaderOverhead = kFuAHeaderSize + 1; |
+ const size_t kExpectedTotalSize = H264::kNaluTypeSize + // Stap-A type. |
+ sizeof(kRewrittenSps) + sizeof(kIdrOne) + |
+ sizeof(kIdrTwo) + (kLengthFieldLength * 3); |
+ |
+ // Set size to include SPS and the rest of the packets in a Stap-A package. |
+ packetizer_.reset(RtpPacketizer::Create(kRtpVideoH264, |
+ kExpectedTotalSize + kHeaderOverhead, |
+ nullptr, kEmptyFrame)); |
+ |
+ packetizer_->SetPayloadData(in_buffer_.data(), in_buffer_.size(), |
+ &fragmentation_header_); |
+ |
+ bool last_packet = true; |
+ uint8_t buffer[kExpectedTotalSize + kHeaderOverhead] = {}; |
+ size_t num_bytes = 0; |
+ |
+ EXPECT_TRUE(packetizer_->NextPacket(buffer, &num_bytes, &last_packet)); |
+ EXPECT_EQ(kExpectedTotalSize, num_bytes); |
+ |
+ std::vector<uint8_t> expected_payload(kRewrittenSps, |
+ &kRewrittenSps[sizeof(kRewrittenSps)]); |
+ EXPECT_THAT(expected_payload, |
+ ::testing::ElementsAreArray( |
+ &buffer[H264::kNaluTypeSize + kLengthFieldLength], |
+ sizeof(kRewrittenSps))); |
+} |
+ |
class RtpDepacketizerH264Test : public ::testing::Test { |
protected: |
RtpDepacketizerH264Test() |
@@ -414,7 +516,7 @@ TEST_F(RtpDepacketizerH264Test, TestSingleNalu) { |
TEST_F(RtpDepacketizerH264Test, TestSingleNaluSpsWithResolution) { |
uint8_t packet[] = {kSps, 0x7A, 0x00, 0x1F, 0xBC, 0xD9, 0x40, 0x50, |
0x05, 0xBA, 0x10, 0x00, 0x00, 0x03, 0x00, 0xC0, |
- 0x00, 0x00, 0x2A, 0xE0, 0xF1, 0x83, 0x19, 0x60}; |
+ 0x00, 0x00, 0x03, 0x2A, 0xE0, 0xF1, 0x83, 0x25}; |
RtpDepacketizer::ParsedPayload payload; |
ASSERT_TRUE(depacketizer_->Parse(&payload, packet, sizeof(packet))); |
@@ -449,11 +551,12 @@ TEST_F(RtpDepacketizerH264Test, TestStapAKey) { |
TEST_F(RtpDepacketizerH264Test, TestStapANaluSpsWithResolution) { |
uint8_t packet[] = {kStapA, // F=0, NRI=0, Type=24. |
// Length (2 bytes), nal header, payload. |
- 0, 24, kSps, 0x7A, 0x00, 0x1F, 0xBC, 0xD9, |
- 0x40, 0x50, 0x05, 0xBA, 0x10, 0x00, 0x00, 0x03, |
- 0x00, 0xC0, 0x00, 0x00, 0x2A, 0xE0, 0xF1, 0x83, |
- 0x19, 0x60, 0, 0x03, kIdr, 0xFF, 0x00, 0, |
- 0x04, kIdr, 0xFF, 0x00, 0x11}; |
+ 0x00, 0x19, kSps, 0x7A, 0x00, 0x1F, 0xBC, 0xD9, 0x40, |
+ 0x50, 0x05, 0xBA, 0x10, 0x00, 0x00, 0x03, 0x00, 0xC0, |
+ 0x00, 0x00, 0x03, 0x2A, 0xE0, 0xF1, 0x83, 0x25, 0x80, |
+ 0x00, 0x03, kIdr, 0xFF, 0x00, 0x00, 0x04, kIdr, 0xFF, |
+ 0x00, 0x11}; |
+ |
RtpDepacketizer::ParsedPayload payload; |
ASSERT_TRUE(depacketizer_->Parse(&payload, packet, sizeof(packet))); |
@@ -466,6 +569,92 @@ TEST_F(RtpDepacketizerH264Test, TestStapANaluSpsWithResolution) { |
EXPECT_EQ(720u, payload.type.Video.height); |
} |
+TEST_F(RtpDepacketizerH264Test, DepacketizeWithRewriting) { |
+ rtc::Buffer in_buffer; |
+ rtc::Buffer out_buffer; |
+ |
+ uint8_t kHeader[2] = {kStapA}; |
+ in_buffer.AppendData(kHeader, 1); |
+ out_buffer.AppendData(kHeader, 1); |
+ |
+ ByteWriter<uint16_t>::WriteBigEndian(kHeader, sizeof(kOriginalSps)); |
+ in_buffer.AppendData(kHeader, 2); |
+ in_buffer.AppendData(kOriginalSps); |
+ ByteWriter<uint16_t>::WriteBigEndian(kHeader, sizeof(kRewrittenSps)); |
+ out_buffer.AppendData(kHeader, 2); |
+ out_buffer.AppendData(kRewrittenSps); |
+ |
+ ByteWriter<uint16_t>::WriteBigEndian(kHeader, sizeof(kIdrOne)); |
+ in_buffer.AppendData(kHeader, 2); |
+ in_buffer.AppendData(kIdrOne); |
+ out_buffer.AppendData(kHeader, 2); |
+ out_buffer.AppendData(kIdrOne); |
+ |
+ ByteWriter<uint16_t>::WriteBigEndian(kHeader, sizeof(kIdrTwo)); |
+ in_buffer.AppendData(kHeader, 2); |
+ in_buffer.AppendData(kIdrTwo); |
+ out_buffer.AppendData(kHeader, 2); |
+ out_buffer.AppendData(kIdrTwo); |
+ |
+ RtpDepacketizer::ParsedPayload payload; |
+ EXPECT_TRUE( |
+ depacketizer_->Parse(&payload, in_buffer.data(), in_buffer.size())); |
+ |
+ std::vector<uint8_t> expected_packet_payload( |
+ out_buffer.data(), &out_buffer.data()[out_buffer.size()]); |
+ |
+ EXPECT_THAT( |
+ expected_packet_payload, |
+ ::testing::ElementsAreArray(payload.payload, payload.payload_length)); |
+} |
+ |
+TEST_F(RtpDepacketizerH264Test, DepacketizeWithDoubleRewriting) { |
+ rtc::Buffer in_buffer; |
+ rtc::Buffer out_buffer; |
+ |
+ uint8_t kHeader[2] = {kStapA}; |
+ in_buffer.AppendData(kHeader, 1); |
+ out_buffer.AppendData(kHeader, 1); |
+ |
+ // First SPS will be kept... |
+ ByteWriter<uint16_t>::WriteBigEndian(kHeader, sizeof(kOriginalSps)); |
+ in_buffer.AppendData(kHeader, 2); |
+ in_buffer.AppendData(kOriginalSps); |
+ out_buffer.AppendData(kHeader, 2); |
+ out_buffer.AppendData(kOriginalSps); |
+ |
+ // ...only the second one will be rewritten. |
+ ByteWriter<uint16_t>::WriteBigEndian(kHeader, sizeof(kOriginalSps)); |
+ in_buffer.AppendData(kHeader, 2); |
+ in_buffer.AppendData(kOriginalSps); |
+ ByteWriter<uint16_t>::WriteBigEndian(kHeader, sizeof(kRewrittenSps)); |
+ out_buffer.AppendData(kHeader, 2); |
+ out_buffer.AppendData(kRewrittenSps); |
+ |
+ ByteWriter<uint16_t>::WriteBigEndian(kHeader, sizeof(kIdrOne)); |
+ in_buffer.AppendData(kHeader, 2); |
+ in_buffer.AppendData(kIdrOne); |
+ out_buffer.AppendData(kHeader, 2); |
+ out_buffer.AppendData(kIdrOne); |
+ |
+ ByteWriter<uint16_t>::WriteBigEndian(kHeader, sizeof(kIdrTwo)); |
+ in_buffer.AppendData(kHeader, 2); |
+ in_buffer.AppendData(kIdrTwo); |
+ out_buffer.AppendData(kHeader, 2); |
+ out_buffer.AppendData(kIdrTwo); |
+ |
+ RtpDepacketizer::ParsedPayload payload; |
+ EXPECT_TRUE( |
+ depacketizer_->Parse(&payload, in_buffer.data(), in_buffer.size())); |
+ |
+ std::vector<uint8_t> expected_packet_payload( |
+ out_buffer.data(), &out_buffer.data()[out_buffer.size()]); |
+ |
+ EXPECT_THAT( |
+ expected_packet_payload, |
+ ::testing::ElementsAreArray(payload.payload, payload.payload_length)); |
+} |
+ |
TEST_F(RtpDepacketizerH264Test, TestStapADelta) { |
uint8_t packet[16] = {kStapA, // F=0, NRI=0, Type=24. |
// Length, nal header, payload. |