|  | /* | 
|  | *  Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. | 
|  | * | 
|  | *  Use of this source code is governed by a BSD-style license | 
|  | *  that can be found in the LICENSE file in the root of the source | 
|  | *  tree. An additional intellectual property rights grant can be found | 
|  | *  in the file PATENTS.  All contributing project authors may | 
|  | *  be found in the AUTHORS file in the root of the source tree. | 
|  | */ | 
|  |  | 
|  | #include <memory> | 
|  |  | 
|  | #include "testing/gmock/include/gmock/gmock.h" | 
|  | #include "testing/gtest/include/gtest/gtest.h" | 
|  | #include "webrtc/modules/rtp_rtcp/source/rtp_format_vp8.h" | 
|  | #include "webrtc/modules/rtp_rtcp/source/rtp_format_vp8_test_helper.h" | 
|  | #include "webrtc/typedefs.h" | 
|  |  | 
|  | #define CHECK_ARRAY_SIZE(expected_size, array)                     \ | 
|  | static_assert(expected_size == sizeof(array) / sizeof(array[0]), \ | 
|  | "check array size"); | 
|  |  | 
|  | namespace webrtc { | 
|  | namespace { | 
|  | // Payload descriptor | 
|  | //       0 1 2 3 4 5 6 7 | 
|  | //      +-+-+-+-+-+-+-+-+ | 
|  | //      |X|R|N|S|PartID | (REQUIRED) | 
|  | //      +-+-+-+-+-+-+-+-+ | 
|  | // X:   |I|L|T|K|  RSV  | (OPTIONAL) | 
|  | //      +-+-+-+-+-+-+-+-+ | 
|  | // I:   |   PictureID   | (OPTIONAL) | 
|  | //      +-+-+-+-+-+-+-+-+ | 
|  | // L:   |   TL0PICIDX   | (OPTIONAL) | 
|  | //      +-+-+-+-+-+-+-+-+ | 
|  | // T/K: |TID:Y| KEYIDX  | (OPTIONAL) | 
|  | //      +-+-+-+-+-+-+-+-+ | 
|  | // | 
|  | // Payload header | 
|  | //       0 1 2 3 4 5 6 7 | 
|  | //      +-+-+-+-+-+-+-+-+ | 
|  | //      |Size0|H| VER |P| | 
|  | //      +-+-+-+-+-+-+-+-+ | 
|  | //      |     Size1     | | 
|  | //      +-+-+-+-+-+-+-+-+ | 
|  | //      |     Size2     | | 
|  | //      +-+-+-+-+-+-+-+-+ | 
|  | //      | Bytes 4..N of | | 
|  | //      | VP8 payload   | | 
|  | //      :               : | 
|  | //      +-+-+-+-+-+-+-+-+ | 
|  | //      | OPTIONAL RTP  | | 
|  | //      | padding       | | 
|  | //      :               : | 
|  | //      +-+-+-+-+-+-+-+-+ | 
|  | void VerifyBasicHeader(RTPTypeHeader* type, bool N, bool S, int part_id) { | 
|  | ASSERT_TRUE(type != NULL); | 
|  | EXPECT_EQ(N, type->Video.codecHeader.VP8.nonReference); | 
|  | EXPECT_EQ(S, type->Video.codecHeader.VP8.beginningOfPartition); | 
|  | EXPECT_EQ(part_id, type->Video.codecHeader.VP8.partitionId); | 
|  | } | 
|  |  | 
|  | void VerifyExtensions(RTPTypeHeader* type, | 
|  | int16_t picture_id,   /* I */ | 
|  | int16_t tl0_pic_idx,  /* L */ | 
|  | uint8_t temporal_idx, /* T */ | 
|  | int key_idx /* K */) { | 
|  | ASSERT_TRUE(type != NULL); | 
|  | EXPECT_EQ(picture_id, type->Video.codecHeader.VP8.pictureId); | 
|  | EXPECT_EQ(tl0_pic_idx, type->Video.codecHeader.VP8.tl0PicIdx); | 
|  | EXPECT_EQ(temporal_idx, type->Video.codecHeader.VP8.temporalIdx); | 
|  | EXPECT_EQ(key_idx, type->Video.codecHeader.VP8.keyIdx); | 
|  | } | 
|  | }  // namespace | 
|  |  | 
|  | class RtpPacketizerVp8Test : public ::testing::Test { | 
|  | protected: | 
|  | RtpPacketizerVp8Test() : helper_(NULL) {} | 
|  | virtual void TearDown() { delete helper_; } | 
|  | bool Init(const size_t* partition_sizes, size_t num_partitions) { | 
|  | hdr_info_.pictureId = kNoPictureId; | 
|  | hdr_info_.nonReference = false; | 
|  | hdr_info_.temporalIdx = kNoTemporalIdx; | 
|  | hdr_info_.layerSync = false; | 
|  | hdr_info_.tl0PicIdx = kNoTl0PicIdx; | 
|  | hdr_info_.keyIdx = kNoKeyIdx; | 
|  | if (helper_ != NULL) | 
|  | return false; | 
|  | helper_ = new test::RtpFormatVp8TestHelper(&hdr_info_); | 
|  | return helper_->Init(partition_sizes, num_partitions); | 
|  | } | 
|  |  | 
|  | RTPVideoHeaderVP8 hdr_info_; | 
|  | test::RtpFormatVp8TestHelper* helper_; | 
|  | }; | 
|  |  | 
|  | TEST_F(RtpPacketizerVp8Test, TestStrictMode) { | 
|  | const size_t kSizeVector[] = {10, 8, 27}; | 
|  | 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 = 13; | 
|  | RtpPacketizerVp8 packetizer(hdr_info_, kMaxSize, kStrict); | 
|  | packetizer.SetPayloadData(helper_->payload_data(), | 
|  | helper_->payload_size(), | 
|  | helper_->fragmentation()); | 
|  |  | 
|  | // The expected sizes are obtained by running a verified good implementation. | 
|  | const size_t kExpectedSizes[] = {9, 9, 12, 11, 11, 11, 10}; | 
|  | const int kExpectedPart[] = {0, 0, 1, 2, 2, 2, 2}; | 
|  | const bool kExpectedFragStart[] = {true,  false, true, true, | 
|  | false, false, false}; | 
|  | const size_t kExpectedNum = GTEST_ARRAY_SIZE_(kExpectedSizes); | 
|  | CHECK_ARRAY_SIZE(kExpectedNum, kExpectedPart); | 
|  | CHECK_ARRAY_SIZE(kExpectedNum, kExpectedFragStart); | 
|  |  | 
|  | helper_->GetAllPacketsAndCheck(&packetizer, | 
|  | kExpectedSizes, | 
|  | kExpectedPart, | 
|  | kExpectedFragStart, | 
|  | kExpectedNum); | 
|  | } | 
|  |  | 
|  | // Verify that we get a minimal number of packets if the partition plus header | 
|  | // size fits exactly in the maximum packet size. | 
|  | // Test is disabled: https://code.google.com/p/webrtc/issues/detail?id=4019. | 
|  | TEST_F(RtpPacketizerVp8Test, DISABLED_TestStrictEqualTightPartitions) { | 
|  | const size_t kSizeVector[] = {10, 10, 10}; | 
|  | const size_t kNumPartitions = GTEST_ARRAY_SIZE_(kSizeVector); | 
|  | 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); | 
|  | packetizer.SetPayloadData(helper_->payload_data(), helper_->payload_size(), | 
|  | helper_->fragmentation()); | 
|  |  | 
|  | // The expected sizes are obtained by running a verified good implementation. | 
|  | const size_t kExpectedSizes[] = {14, 14, 14}; | 
|  | const int kExpectedPart[] = {0, 1, 2}; | 
|  | const bool kExpectedFragStart[] = {true, true, true}; | 
|  | const size_t kExpectedNum = GTEST_ARRAY_SIZE_(kExpectedSizes); | 
|  | CHECK_ARRAY_SIZE(kExpectedNum, kExpectedPart); | 
|  | CHECK_ARRAY_SIZE(kExpectedNum, kExpectedFragStart); | 
|  |  | 
|  | helper_->GetAllPacketsAndCheck(&packetizer, kExpectedSizes, kExpectedPart, | 
|  | kExpectedFragStart, kExpectedNum); | 
|  | } | 
|  |  | 
|  | TEST_F(RtpPacketizerVp8Test, TestAggregateMode) { | 
|  | const size_t kSizeVector[] = {60, 10, 10}; | 
|  | const size_t kNumPartitions = GTEST_ARRAY_SIZE_(kSizeVector); | 
|  | 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); | 
|  | packetizer.SetPayloadData(helper_->payload_data(), | 
|  | helper_->payload_size(), | 
|  | helper_->fragmentation()); | 
|  |  | 
|  | // The expected sizes are obtained by running a verified good implementation. | 
|  | const size_t kExpectedSizes[] = {23, 23, 23, 23}; | 
|  | const int kExpectedPart[] = {0, 0, 0, 1}; | 
|  | const bool kExpectedFragStart[] = {true, false, false, true}; | 
|  | const size_t kExpectedNum = GTEST_ARRAY_SIZE_(kExpectedSizes); | 
|  | CHECK_ARRAY_SIZE(kExpectedNum, kExpectedPart); | 
|  | CHECK_ARRAY_SIZE(kExpectedNum, kExpectedFragStart); | 
|  |  | 
|  | helper_->GetAllPacketsAndCheck(&packetizer, | 
|  | kExpectedSizes, | 
|  | kExpectedPart, | 
|  | kExpectedFragStart, | 
|  | kExpectedNum); | 
|  | } | 
|  |  | 
|  | TEST_F(RtpPacketizerVp8Test, TestAggregateModeManyPartitions1) { | 
|  | const size_t kSizeVector[] = {1600, 200, 200, 200, 200, 200, 200, 200, 200}; | 
|  | const size_t kNumPartitions = GTEST_ARRAY_SIZE_(kSizeVector); | 
|  | 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); | 
|  | packetizer.SetPayloadData(helper_->payload_data(), | 
|  | helper_->payload_size(), | 
|  | helper_->fragmentation()); | 
|  |  | 
|  | // The expected sizes are obtained by running a verified good implementation. | 
|  | const size_t kExpectedSizes[] = {803, 803, 803, 803}; | 
|  | const int kExpectedPart[] = {0, 0, 1, 5}; | 
|  | const bool kExpectedFragStart[] = {true, false, true, true}; | 
|  | const size_t kExpectedNum = GTEST_ARRAY_SIZE_(kExpectedSizes); | 
|  | CHECK_ARRAY_SIZE(kExpectedNum, kExpectedPart); | 
|  | CHECK_ARRAY_SIZE(kExpectedNum, kExpectedFragStart); | 
|  |  | 
|  | helper_->GetAllPacketsAndCheck(&packetizer, | 
|  | kExpectedSizes, | 
|  | kExpectedPart, | 
|  | kExpectedFragStart, | 
|  | kExpectedNum); | 
|  | } | 
|  |  | 
|  | TEST_F(RtpPacketizerVp8Test, TestAggregateModeManyPartitions2) { | 
|  | const size_t kSizeVector[] = {1599, 200, 200, 200, 1600, 200, 200, 200, 200}; | 
|  | const size_t kNumPartitions = GTEST_ARRAY_SIZE_(kSizeVector); | 
|  | 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); | 
|  | packetizer.SetPayloadData(helper_->payload_data(), | 
|  | helper_->payload_size(), | 
|  | helper_->fragmentation()); | 
|  |  | 
|  | // The expected sizes are obtained by running a verified good implementation. | 
|  | const size_t kExpectedSizes[] = {803, 802, 603, 803, 803, 803}; | 
|  | const int kExpectedPart[] = {0, 0, 1, 4, 4, 5}; | 
|  | const bool kExpectedFragStart[] = {true, false, true, true, false, true}; | 
|  | const size_t kExpectedNum = GTEST_ARRAY_SIZE_(kExpectedSizes); | 
|  | CHECK_ARRAY_SIZE(kExpectedNum, kExpectedPart); | 
|  | CHECK_ARRAY_SIZE(kExpectedNum, kExpectedFragStart); | 
|  |  | 
|  | helper_->GetAllPacketsAndCheck(&packetizer, | 
|  | kExpectedSizes, | 
|  | kExpectedPart, | 
|  | kExpectedFragStart, | 
|  | kExpectedNum); | 
|  | } | 
|  |  | 
|  | TEST_F(RtpPacketizerVp8Test, TestAggregateModeTwoLargePartitions) { | 
|  | const size_t kSizeVector[] = {1654, 2268}; | 
|  | const size_t kNumPartitions = GTEST_ARRAY_SIZE_(kSizeVector); | 
|  | 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); | 
|  | packetizer.SetPayloadData(helper_->payload_data(), | 
|  | helper_->payload_size(), | 
|  | helper_->fragmentation()); | 
|  |  | 
|  | // The expected sizes are obtained by running a verified good implementation. | 
|  | const size_t kExpectedSizes[] = {830, 830, 1137, 1137}; | 
|  | const int kExpectedPart[] = {0, 0, 1, 1}; | 
|  | const bool kExpectedFragStart[] = {true, false, true, false}; | 
|  | const size_t kExpectedNum = GTEST_ARRAY_SIZE_(kExpectedSizes); | 
|  | CHECK_ARRAY_SIZE(kExpectedNum, kExpectedPart); | 
|  | CHECK_ARRAY_SIZE(kExpectedNum, kExpectedFragStart); | 
|  |  | 
|  | helper_->GetAllPacketsAndCheck(&packetizer, | 
|  | kExpectedSizes, | 
|  | kExpectedPart, | 
|  | kExpectedFragStart, | 
|  | kExpectedNum); | 
|  | } | 
|  |  | 
|  | // Verify that EqualSize mode is forced if fragmentation info is missing. | 
|  | TEST_F(RtpPacketizerVp8Test, TestEqualSizeModeFallback) { | 
|  | const size_t kSizeVector[] = {10, 10, 10}; | 
|  | 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); | 
|  | packetizer.SetPayloadData( | 
|  | helper_->payload_data(), helper_->payload_size(), NULL); | 
|  |  | 
|  | // Expecting three full packets, and one with the remainder. | 
|  | const size_t kExpectedSizes[] = {12, 11, 12, 11}; | 
|  | const int kExpectedPart[] = {0, 0, 0, 0};  // Always 0 for equal size mode. | 
|  | // Frag start only true for first packet in equal size mode. | 
|  | const bool kExpectedFragStart[] = {true, false, false, false}; | 
|  | const size_t kExpectedNum = GTEST_ARRAY_SIZE_(kExpectedSizes); | 
|  | CHECK_ARRAY_SIZE(kExpectedNum, kExpectedPart); | 
|  | CHECK_ARRAY_SIZE(kExpectedNum, kExpectedFragStart); | 
|  |  | 
|  | helper_->set_sloppy_partitioning(true); | 
|  | helper_->GetAllPacketsAndCheck(&packetizer, | 
|  | kExpectedSizes, | 
|  | kExpectedPart, | 
|  | kExpectedFragStart, | 
|  | kExpectedNum); | 
|  | } | 
|  |  | 
|  | // Verify that non-reference bit is set. EqualSize mode fallback is expected. | 
|  | TEST_F(RtpPacketizerVp8Test, TestNonReferenceBit) { | 
|  | const size_t kSizeVector[] = {10, 10, 10}; | 
|  | const size_t kNumPartitions = GTEST_ARRAY_SIZE_(kSizeVector); | 
|  | 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); | 
|  | packetizer.SetPayloadData( | 
|  | helper_->payload_data(), helper_->payload_size(), NULL); | 
|  |  | 
|  | // EqualSize mode => First packet full; other not. | 
|  | const size_t kExpectedSizes[] = {16, 16}; | 
|  | const int kExpectedPart[] = {0, 0};  // Always 0 for equal size mode. | 
|  | // Frag start only true for first packet in equal size mode. | 
|  | const bool kExpectedFragStart[] = {true, false}; | 
|  | const size_t kExpectedNum = GTEST_ARRAY_SIZE_(kExpectedSizes); | 
|  | CHECK_ARRAY_SIZE(kExpectedNum, kExpectedPart); | 
|  | CHECK_ARRAY_SIZE(kExpectedNum, kExpectedFragStart); | 
|  |  | 
|  | helper_->set_sloppy_partitioning(true); | 
|  | helper_->GetAllPacketsAndCheck(&packetizer, | 
|  | kExpectedSizes, | 
|  | kExpectedPart, | 
|  | kExpectedFragStart, | 
|  | kExpectedNum); | 
|  | } | 
|  |  | 
|  | // Verify Tl0PicIdx and TID fields, and layerSync bit. | 
|  | TEST_F(RtpPacketizerVp8Test, TestTl0PicIdxAndTID) { | 
|  | const size_t kSizeVector[] = {10, 10, 10}; | 
|  | const size_t kNumPartitions = GTEST_ARRAY_SIZE_(kSizeVector); | 
|  | ASSERT_TRUE(Init(kSizeVector, kNumPartitions)); | 
|  |  | 
|  | 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); | 
|  | packetizer.SetPayloadData(helper_->payload_data(), | 
|  | helper_->payload_size(), | 
|  | helper_->fragmentation()); | 
|  |  | 
|  | // Expect one single packet of payload_size() + 4 bytes header. | 
|  | const size_t kExpectedSizes[1] = {helper_->payload_size() + 4}; | 
|  | const int kExpectedPart[1] = {0};  // Packet starts with partition 0. | 
|  | const bool kExpectedFragStart[1] = {true}; | 
|  | const size_t kExpectedNum = GTEST_ARRAY_SIZE_(kExpectedSizes); | 
|  | CHECK_ARRAY_SIZE(kExpectedNum, kExpectedPart); | 
|  | CHECK_ARRAY_SIZE(kExpectedNum, kExpectedFragStart); | 
|  |  | 
|  | helper_->GetAllPacketsAndCheck(&packetizer, | 
|  | kExpectedSizes, | 
|  | kExpectedPart, | 
|  | kExpectedFragStart, | 
|  | kExpectedNum); | 
|  | } | 
|  |  | 
|  | // Verify KeyIdx field. | 
|  | TEST_F(RtpPacketizerVp8Test, TestKeyIdx) { | 
|  | const size_t kSizeVector[] = {10, 10, 10}; | 
|  | const size_t kNumPartitions = GTEST_ARRAY_SIZE_(kSizeVector); | 
|  | 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); | 
|  | packetizer.SetPayloadData(helper_->payload_data(), | 
|  | helper_->payload_size(), | 
|  | helper_->fragmentation()); | 
|  |  | 
|  | // Expect one single packet of payload_size() + 3 bytes header. | 
|  | const size_t kExpectedSizes[1] = {helper_->payload_size() + 3}; | 
|  | const int kExpectedPart[1] = {0};  // Packet starts with partition 0. | 
|  | const bool kExpectedFragStart[1] = {true}; | 
|  | const size_t kExpectedNum = GTEST_ARRAY_SIZE_(kExpectedSizes); | 
|  | CHECK_ARRAY_SIZE(kExpectedNum, kExpectedPart); | 
|  | CHECK_ARRAY_SIZE(kExpectedNum, kExpectedFragStart); | 
|  |  | 
|  | helper_->GetAllPacketsAndCheck(&packetizer, | 
|  | kExpectedSizes, | 
|  | kExpectedPart, | 
|  | kExpectedFragStart, | 
|  | kExpectedNum); | 
|  | } | 
|  |  | 
|  | // Verify TID field and KeyIdx field in combination. | 
|  | TEST_F(RtpPacketizerVp8Test, TestTIDAndKeyIdx) { | 
|  | const size_t kSizeVector[] = {10, 10, 10}; | 
|  | const size_t kNumPartitions = GTEST_ARRAY_SIZE_(kSizeVector); | 
|  | ASSERT_TRUE(Init(kSizeVector, kNumPartitions)); | 
|  |  | 
|  | 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); | 
|  | packetizer.SetPayloadData(helper_->payload_data(), | 
|  | helper_->payload_size(), | 
|  | helper_->fragmentation()); | 
|  |  | 
|  | // Expect one single packet of payload_size() + 3 bytes header. | 
|  | const size_t kExpectedSizes[1] = {helper_->payload_size() + 3}; | 
|  | const int kExpectedPart[1] = {0};  // Packet starts with partition 0. | 
|  | const bool kExpectedFragStart[1] = {true}; | 
|  | const size_t kExpectedNum = GTEST_ARRAY_SIZE_(kExpectedSizes); | 
|  | CHECK_ARRAY_SIZE(kExpectedNum, kExpectedPart); | 
|  | CHECK_ARRAY_SIZE(kExpectedNum, kExpectedFragStart); | 
|  |  | 
|  | helper_->GetAllPacketsAndCheck(&packetizer, | 
|  | kExpectedSizes, | 
|  | kExpectedPart, | 
|  | kExpectedFragStart, | 
|  | kExpectedNum); | 
|  | } | 
|  |  | 
|  | class RtpDepacketizerVp8Test : public ::testing::Test { | 
|  | protected: | 
|  | RtpDepacketizerVp8Test() | 
|  | : depacketizer_(RtpDepacketizer::Create(kRtpVideoVp8)) {} | 
|  |  | 
|  | void ExpectPacket(RtpDepacketizer::ParsedPayload* parsed_payload, | 
|  | const uint8_t* data, | 
|  | size_t length) { | 
|  | ASSERT_TRUE(parsed_payload != NULL); | 
|  | EXPECT_THAT(std::vector<uint8_t>( | 
|  | parsed_payload->payload, | 
|  | parsed_payload->payload + parsed_payload->payload_length), | 
|  | ::testing::ElementsAreArray(data, length)); | 
|  | } | 
|  |  | 
|  | std::unique_ptr<RtpDepacketizer> depacketizer_; | 
|  | }; | 
|  |  | 
|  | TEST_F(RtpDepacketizerVp8Test, BasicHeader) { | 
|  | const uint8_t kHeaderLength = 1; | 
|  | uint8_t packet[4] = {0}; | 
|  | packet[0] = 0x14;  // Binary 0001 0100; S = 1, PartID = 4. | 
|  | packet[1] = 0x01;  // P frame. | 
|  | RtpDepacketizer::ParsedPayload payload; | 
|  |  | 
|  | 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); | 
|  | VerifyExtensions( | 
|  | &payload.type, kNoPictureId, kNoTl0PicIdx, kNoTemporalIdx, kNoKeyIdx); | 
|  | } | 
|  |  | 
|  | TEST_F(RtpDepacketizerVp8Test, PictureID) { | 
|  | const uint8_t kHeaderLength1 = 3; | 
|  | const uint8_t kHeaderLength2 = 4; | 
|  | const uint8_t kPictureId = 17; | 
|  | uint8_t packet[10] = {0}; | 
|  | packet[0] = 0xA0; | 
|  | packet[1] = 0x80; | 
|  | packet[2] = kPictureId; | 
|  | RtpDepacketizer::ParsedPayload payload; | 
|  |  | 
|  | ASSERT_TRUE(depacketizer_->Parse(&payload, packet, sizeof(packet))); | 
|  | ExpectPacket( | 
|  | &payload, packet + kHeaderLength1, sizeof(packet) - kHeaderLength1); | 
|  | EXPECT_EQ(kVideoFrameDelta, payload.frame_type); | 
|  | EXPECT_EQ(kRtpVideoVp8, payload.type.Video.codec); | 
|  | VerifyBasicHeader(&payload.type, 1, 0, 0); | 
|  | VerifyExtensions( | 
|  | &payload.type, kPictureId, kNoTl0PicIdx, kNoTemporalIdx, kNoKeyIdx); | 
|  |  | 
|  | // Re-use packet, but change to long PictureID. | 
|  | packet[2] = 0x80 | kPictureId; | 
|  | packet[3] = kPictureId; | 
|  |  | 
|  | payload = RtpDepacketizer::ParsedPayload(); | 
|  | ASSERT_TRUE(depacketizer_->Parse(&payload, packet, sizeof(packet))); | 
|  | ExpectPacket( | 
|  | &payload, packet + kHeaderLength2, sizeof(packet) - kHeaderLength2); | 
|  | VerifyBasicHeader(&payload.type, 1, 0, 0); | 
|  | VerifyExtensions(&payload.type, | 
|  | (kPictureId << 8) + kPictureId, | 
|  | kNoTl0PicIdx, | 
|  | kNoTemporalIdx, | 
|  | kNoKeyIdx); | 
|  | } | 
|  |  | 
|  | TEST_F(RtpDepacketizerVp8Test, Tl0PicIdx) { | 
|  | const uint8_t kHeaderLength = 3; | 
|  | const uint8_t kTl0PicIdx = 17; | 
|  | uint8_t packet[13] = {0}; | 
|  | packet[0] = 0x90; | 
|  | packet[1] = 0x40; | 
|  | packet[2] = kTl0PicIdx; | 
|  | RtpDepacketizer::ParsedPayload payload; | 
|  |  | 
|  | ASSERT_TRUE(depacketizer_->Parse(&payload, packet, sizeof(packet))); | 
|  | ExpectPacket( | 
|  | &payload, packet + kHeaderLength, sizeof(packet) - kHeaderLength); | 
|  | EXPECT_EQ(kVideoFrameKey, payload.frame_type); | 
|  | EXPECT_EQ(kRtpVideoVp8, payload.type.Video.codec); | 
|  | VerifyBasicHeader(&payload.type, 0, 1, 0); | 
|  | VerifyExtensions( | 
|  | &payload.type, kNoPictureId, kTl0PicIdx, kNoTemporalIdx, kNoKeyIdx); | 
|  | } | 
|  |  | 
|  | TEST_F(RtpDepacketizerVp8Test, TIDAndLayerSync) { | 
|  | const uint8_t kHeaderLength = 3; | 
|  | uint8_t packet[10] = {0}; | 
|  | packet[0] = 0x88; | 
|  | packet[1] = 0x20; | 
|  | packet[2] = 0x80;  // TID(2) + LayerSync(false) | 
|  | RtpDepacketizer::ParsedPayload payload; | 
|  |  | 
|  | 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, 0, 8); | 
|  | VerifyExtensions(&payload.type, kNoPictureId, kNoTl0PicIdx, 2, kNoKeyIdx); | 
|  | EXPECT_FALSE(payload.type.Video.codecHeader.VP8.layerSync); | 
|  | } | 
|  |  | 
|  | TEST_F(RtpDepacketizerVp8Test, KeyIdx) { | 
|  | const uint8_t kHeaderLength = 3; | 
|  | const uint8_t kKeyIdx = 17; | 
|  | uint8_t packet[10] = {0}; | 
|  | packet[0] = 0x88; | 
|  | packet[1] = 0x10;  // K = 1. | 
|  | packet[2] = kKeyIdx; | 
|  | RtpDepacketizer::ParsedPayload payload; | 
|  |  | 
|  | 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, 0, 8); | 
|  | VerifyExtensions( | 
|  | &payload.type, kNoPictureId, kNoTl0PicIdx, kNoTemporalIdx, kKeyIdx); | 
|  | } | 
|  |  | 
|  | TEST_F(RtpDepacketizerVp8Test, MultipleExtensions) { | 
|  | const uint8_t kHeaderLength = 6; | 
|  | uint8_t packet[10] = {0}; | 
|  | packet[0] = 0x88; | 
|  | packet[1] = 0x80 | 0x40 | 0x20 | 0x10; | 
|  | packet[2] = 0x80 | 17;           // PictureID, high 7 bits. | 
|  | packet[3] = 17;                  // PictureID, low 8 bits. | 
|  | packet[4] = 42;                  // Tl0PicIdx. | 
|  | packet[5] = 0x40 | 0x20 | 0x11;  // TID(1) + LayerSync(true) + KEYIDX(17). | 
|  | RtpDepacketizer::ParsedPayload payload; | 
|  |  | 
|  | 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, 0, 8); | 
|  | VerifyExtensions(&payload.type, (17 << 8) + 17, 42, 1, 17); | 
|  | } | 
|  |  | 
|  | TEST_F(RtpDepacketizerVp8Test, TooShortHeader) { | 
|  | uint8_t packet[4] = {0}; | 
|  | packet[0] = 0x88; | 
|  | packet[1] = 0x80 | 0x40 | 0x20 | 0x10;  // All extensions are enabled... | 
|  | packet[2] = 0x80 | 17;  // ... but only 2 bytes PictureID is provided. | 
|  | packet[3] = 17;         // PictureID, low 8 bits. | 
|  | RtpDepacketizer::ParsedPayload payload; | 
|  |  | 
|  | EXPECT_FALSE(depacketizer_->Parse(&payload, packet, sizeof(packet))); | 
|  | } | 
|  |  | 
|  | TEST_F(RtpDepacketizerVp8Test, TestWithPacketizer) { | 
|  | const uint8_t kHeaderLength = 5; | 
|  | uint8_t data[10] = {0}; | 
|  | uint8_t packet[20] = {0}; | 
|  | RTPVideoHeaderVP8 input_header; | 
|  | input_header.nonReference = true; | 
|  | input_header.pictureId = 300; | 
|  | input_header.temporalIdx = 1; | 
|  | input_header.layerSync = false; | 
|  | input_header.tl0PicIdx = kNoTl0PicIdx;  // Disable. | 
|  | input_header.keyIdx = 31; | 
|  | 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(depacketizer_->Parse(&payload, packet, sizeof(packet))); | 
|  | ExpectPacket( | 
|  | &payload, packet + kHeaderLength, sizeof(packet) - kHeaderLength); | 
|  | EXPECT_EQ(kVideoFrameKey, payload.frame_type); | 
|  | EXPECT_EQ(kRtpVideoVp8, payload.type.Video.codec); | 
|  | VerifyBasicHeader(&payload.type, 1, 1, 0); | 
|  | VerifyExtensions(&payload.type, | 
|  | input_header.pictureId, | 
|  | input_header.tl0PicIdx, | 
|  | input_header.temporalIdx, | 
|  | input_header.keyIdx); | 
|  | EXPECT_EQ(payload.type.Video.codecHeader.VP8.layerSync, | 
|  | input_header.layerSync); | 
|  | } | 
|  |  | 
|  | TEST_F(RtpDepacketizerVp8Test, TestEmptyPayload) { | 
|  | // Using a wild pointer to crash on accesses from inside the depacketizer. | 
|  | uint8_t* garbage_ptr = reinterpret_cast<uint8_t*>(0x4711); | 
|  | RtpDepacketizer::ParsedPayload payload; | 
|  | EXPECT_FALSE(depacketizer_->Parse(&payload, garbage_ptr, 0)); | 
|  | } | 
|  | }  // namespace webrtc |