blob: 3f6de76aed2aef31f405eb34d54dfc431c48c43f [file] [log] [blame]
/*
* 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 "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"
#define CHECK_ARRAY_SIZE(expected_size, array) \
static_assert(expected_size == sizeof(array) / sizeof(array[0]), \
"check array size");
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
// +-+-+-+-+-+-+-+-+
// |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;
const size_t kMaxPayloadSize = 13;
RtpPacketizerVp8 packetizer(hdr_info_, kMaxPayloadSize, 0, kStrict);
size_t num_packets = packetizer.SetPayloadData(helper_->payload_data(),
helper_->payload_size(),
helper_->fragmentation());
// The expected sizes are obtained by hand.
const size_t kExpectedSizes[] = {9, 9, 12, 13, 13, 13};
const int kExpectedPart[] = {0, 0, 1, 2, 2, 2};
const bool kExpectedFragStart[] = {true, false, true, true, false, false};
const size_t kExpectedNum = GTEST_ARRAY_SIZE_(kExpectedSizes);
CHECK_ARRAY_SIZE(kExpectedNum, kExpectedPart);
CHECK_ARRAY_SIZE(kExpectedNum, kExpectedFragStart);
ASSERT_EQ(num_packets, kExpectedNum);
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_F(RtpPacketizerVp8Test, 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;
const int kMaxPayloadSize = 14;
RtpPacketizerVp8 packetizer(hdr_info_, kMaxPayloadSize, 0, kStrict);
size_t num_packets = packetizer.SetPayloadData(helper_->payload_data(),
helper_->payload_size(),
helper_->fragmentation());
// The expected sizes are obtained by hand.
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);
ASSERT_EQ(num_packets, kExpectedNum);
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;
const size_t kMaxPayloadSize = 25;
RtpPacketizerVp8 packetizer(hdr_info_, kMaxPayloadSize, 0, kAggregate);
size_t num_packets = packetizer.SetPayloadData(helper_->payload_data(),
helper_->payload_size(),
helper_->fragmentation());
// The expected sizes are obtained by hand.
const size_t kExpectedSizes[] = {24, 24, 24, 24};
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);
ASSERT_EQ(num_packets, kExpectedNum);
helper_->GetAllPacketsAndCheck(&packetizer,
kExpectedSizes,
kExpectedPart,
kExpectedFragStart,
kExpectedNum);
}
TEST_F(RtpPacketizerVp8Test, TestAggregateModePacketReductionCauseExtraPacket) {
const size_t kSizeVector[] = {60, 10, 10};
const size_t kNumPartitions = GTEST_ARRAY_SIZE_(kSizeVector);
ASSERT_TRUE(Init(kSizeVector, kNumPartitions));
hdr_info_.pictureId = 20;
const size_t kMaxPayloadSize = 25;
const size_t kLastPacketReductionLen = 5;
RtpPacketizerVp8 packetizer(hdr_info_, kMaxPayloadSize,
kLastPacketReductionLen, kAggregate);
size_t num_packets = packetizer.SetPayloadData(helper_->payload_data(),
helper_->payload_size(),
helper_->fragmentation());
// The expected sizes are obtained by hand.
const size_t kExpectedSizes[] = {24, 24, 24, 14, 14};
const int kExpectedPart[] = {0, 0, 0, 1, 2};
const bool kExpectedFragStart[] = {true, false, false, true, true};
const size_t kExpectedNum = GTEST_ARRAY_SIZE_(kExpectedSizes);
CHECK_ARRAY_SIZE(kExpectedNum, kExpectedPart);
CHECK_ARRAY_SIZE(kExpectedNum, kExpectedFragStart);
ASSERT_EQ(num_packets, kExpectedNum);
helper_->GetAllPacketsAndCheck(&packetizer, kExpectedSizes, kExpectedPart,
kExpectedFragStart, kExpectedNum);
}
TEST_F(RtpPacketizerVp8Test, TestAggregateModePacketReduction) {
const size_t kSizeVector[] = {60, 10, 10};
const size_t kNumPartitions = GTEST_ARRAY_SIZE_(kSizeVector);
ASSERT_TRUE(Init(kSizeVector, kNumPartitions));
hdr_info_.pictureId = 20;
const size_t kMaxPayloadSize = 25;
const size_t kLastPacketReductionLen = 1;
RtpPacketizerVp8 packetizer(hdr_info_, kMaxPayloadSize,
kLastPacketReductionLen, kAggregate);
size_t num_packets = packetizer.SetPayloadData(helper_->payload_data(),
helper_->payload_size(),
helper_->fragmentation());
// The expected sizes are obtained by hand.
const size_t kExpectedSizes[] = {24, 24, 24, 24};
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);
ASSERT_EQ(num_packets, kExpectedNum);
helper_->GetAllPacketsAndCheck(&packetizer, kExpectedSizes, kExpectedPart,
kExpectedFragStart, kExpectedNum);
}
TEST_F(RtpPacketizerVp8Test, TestAggregateModeSmallPartitions) {
const size_t kSizeVector[] = {3, 4, 2, 5, 2, 4};
const size_t kNumPartitions = GTEST_ARRAY_SIZE_(kSizeVector);
ASSERT_TRUE(Init(kSizeVector, kNumPartitions));
hdr_info_.pictureId = 20;
const size_t kMaxPayloadSize = 13;
RtpPacketizerVp8 packetizer(hdr_info_, kMaxPayloadSize, 0, kAggregate);
size_t num_packets = packetizer.SetPayloadData(helper_->payload_data(),
helper_->payload_size(),
helper_->fragmentation());
// The expected sizes are obtained by hand.
const size_t kExpectedSizes[] = {11, 11, 10};
const int kExpectedPart[] = {0, 2, 4};
const bool kExpectedFragStart[] = {true, true, true};
const size_t kExpectedNum = GTEST_ARRAY_SIZE_(kExpectedSizes);
CHECK_ARRAY_SIZE(kExpectedNum, kExpectedPart);
CHECK_ARRAY_SIZE(kExpectedNum, kExpectedFragStart);
ASSERT_EQ(num_packets, kExpectedNum);
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;
const size_t kMaxPayloadSize = 1000;
RtpPacketizerVp8 packetizer(hdr_info_, kMaxPayloadSize, 0, kAggregate);
size_t num_packets = packetizer.SetPayloadData(helper_->payload_data(),
helper_->payload_size(),
helper_->fragmentation());
// The expected sizes are obtained by hand.
const size_t kExpectedSizes[] = {804, 804, 804, 804};
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);
ASSERT_EQ(num_packets, kExpectedNum);
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;
const size_t kMaxPayloadSize = 1000;
RtpPacketizerVp8 packetizer(hdr_info_, kMaxPayloadSize, 0, kAggregate);
size_t num_packets = packetizer.SetPayloadData(helper_->payload_data(),
helper_->payload_size(),
helper_->fragmentation());
// The expected sizes are obtained by hand.
const size_t kExpectedSizes[] = {803, 804, 604, 804, 804, 804};
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);
ASSERT_EQ(num_packets, kExpectedNum);
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;
const size_t kMaxPayloadSize = 1460;
RtpPacketizerVp8 packetizer(hdr_info_, kMaxPayloadSize, 0, kAggregate);
size_t num_packets = packetizer.SetPayloadData(helper_->payload_data(),
helper_->payload_size(),
helper_->fragmentation());
// The expected sizes are obtained by hand.
const size_t kExpectedSizes[] = {831, 831, 1138, 1138};
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);
ASSERT_EQ(num_packets, kExpectedNum);
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 kMaxPayloadSize = 12; // Small enough to produce 4 packets.
RtpPacketizerVp8 packetizer(hdr_info_, kMaxPayloadSize, 0);
size_t num_packets = packetizer.SetPayloadData(
helper_->payload_data(), helper_->payload_size(), nullptr);
// Expecting three full packets, and one with the remainder.
const size_t kExpectedSizes[] = {11, 11, 12, 12};
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);
ASSERT_EQ(num_packets, kExpectedNum);
helper_->set_sloppy_partitioning(true);
helper_->GetAllPacketsAndCheck(&packetizer,
kExpectedSizes,
kExpectedPart,
kExpectedFragStart,
kExpectedNum);
}
TEST_F(RtpPacketizerVp8Test, TestEqualSizeWithLastPacketReduction) {
const size_t kSizeVector[] = {30, 10, 3};
const size_t kNumPartitions = GTEST_ARRAY_SIZE_(kSizeVector);
ASSERT_TRUE(Init(kSizeVector, kNumPartitions));
hdr_info_.pictureId = 200;
const size_t kMaxPayloadSize = 15; // Small enough to produce 5 packets.
const size_t kLastPacketReduction = 5;
RtpPacketizerVp8 packetizer(hdr_info_, kMaxPayloadSize, kLastPacketReduction);
size_t num_packets = packetizer.SetPayloadData(
helper_->payload_data(), helper_->payload_size(), nullptr);
// Calculated by hand. VP8 payload descriptors are 4 byte each. 5 packets is
// minimum possible to fit 43 payload bytes into packets with capacity of
// 15 - 4 = 11 and leave 5 free bytes in the last packet. All packets are
// almost equal in size, even last packet if counted with free space (which
// will be filled up the stack by extra long RTP header).
const size_t kExpectedSizes[] = {13, 13, 14, 14, 9};
const int kExpectedPart[] = {0, 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, false};
const size_t kExpectedNum = GTEST_ARRAY_SIZE_(kExpectedSizes);
CHECK_ARRAY_SIZE(kExpectedNum, kExpectedPart);
CHECK_ARRAY_SIZE(kExpectedNum, kExpectedFragStart);
ASSERT_EQ(num_packets, kExpectedNum);
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 kMaxPayloadSize = 25; // Small enough to produce two packets.
RtpPacketizerVp8 packetizer(hdr_info_, kMaxPayloadSize, 0);
size_t num_packets = packetizer.SetPayloadData(
helper_->payload_data(), helper_->payload_size(), nullptr);
// 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);
ASSERT_EQ(num_packets, kExpectedNum);
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;
// kMaxPayloadSize is only limited by allocated buffer size.
const size_t kMaxPayloadSize = helper_->buffer_size();
RtpPacketizerVp8 packetizer(hdr_info_, kMaxPayloadSize, 0, kAggregate);
size_t num_packets = 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);
ASSERT_EQ(num_packets, kExpectedNum);
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;
// kMaxPayloadSize is only limited by allocated buffer size.
const size_t kMaxPayloadSize = helper_->buffer_size();
RtpPacketizerVp8 packetizer(hdr_info_, kMaxPayloadSize, 0, kAggregate);
size_t num_packets = 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);
ASSERT_EQ(num_packets, kExpectedNum);
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;
// kMaxPayloadSize is only limited by allocated buffer size.
const size_t kMaxPayloadSize = helper_->buffer_size();
RtpPacketizerVp8 packetizer(hdr_info_, kMaxPayloadSize, 0, kAggregate);
size_t num_packets = 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);
ASSERT_EQ(num_packets, kExpectedNum);
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};
RtpPacketToSend packet(kNoExtensions);
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, 0);
EXPECT_EQ(packetizer.SetPayloadData(data, 10, NULL), 1u);
ASSERT_TRUE(packetizer.NextPacket(&packet));
EXPECT_TRUE(packet.Marker());
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);
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