blob: 0c9ad609c67bf95da4dc0955fa00a59837980426 [file] [log] [blame]
/*
* Copyright (c) 2011 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.
*/
/*
* This file includes unit tests for the VP8 packetizer.
*/
#include <gtest/gtest.h>
#include "typedefs.h"
#include "rtp_format_vp8.h"
namespace {
using webrtc::RTPFragmentationHeader;
using webrtc::RtpFormatVp8;
using webrtc::RTPVideoHeaderVP8;
const WebRtc_UWord32 kPayloadSize = 30;
class RtpFormatVp8Test : public ::testing::Test {
protected:
RtpFormatVp8Test() {};
virtual void SetUp();
virtual void TearDown();
void CheckHeader(bool first_in_frame, bool frag_start, bool frag_end);
void CheckPayload(int payload_end);
void CheckLast(bool last) const;
void CheckPacket(int send_bytes, int expect_bytes, bool last,
bool first_in_frame, bool frag_start, bool frag_end);
WebRtc_UWord8 payload_data_[kPayloadSize];
WebRtc_UWord8 buffer_[kPayloadSize];
WebRtc_UWord8 *data_ptr_;
RTPFragmentationHeader* fragmentation_;
RTPVideoHeaderVP8 hdr_info_;
int payload_start_;
};
void RtpFormatVp8Test::SetUp() {
for (int i = 0; i < kPayloadSize; i++)
{
payload_data_[i] = i / 10; // integer division
}
data_ptr_ = payload_data_;
fragmentation_ = new RTPFragmentationHeader;
fragmentation_->VerifyAndAllocateFragmentationHeader(3);
fragmentation_->fragmentationLength[0] = 10;
fragmentation_->fragmentationLength[1] = 10;
fragmentation_->fragmentationLength[2] = 10;
fragmentation_->fragmentationOffset[0] = 0;
fragmentation_->fragmentationOffset[1] = 10;
fragmentation_->fragmentationOffset[2] = 20;
hdr_info_.pictureId = 0;
hdr_info_.nonReference = false;
}
void RtpFormatVp8Test::TearDown() {
delete fragmentation_;
}
#define EXPECT_BIT_EQ(x,n,a) EXPECT_EQ((((x)>>n)&0x1), a)
#define EXPECT_RSV_ZERO(x) EXPECT_EQ(((x)&0xE0), 0)
//#define EXPECT_BIT_I_EQ(x,a) EXPECT_EQ((((x)&0x10) > 0), (a > 0))
#define EXPECT_BIT_I_EQ(x,a) EXPECT_BIT_EQ(x, 4, a)
#define EXPECT_BIT_N_EQ(x,a) EXPECT_EQ((((x)&0x08) > 0), (a > 0))
#define EXPECT_FI_EQ(x,a) EXPECT_EQ((((x)&0x06) >> 1), a)
#define EXPECT_BIT_B_EQ(x,a) EXPECT_EQ((((x)&0x01) > 0), (a > 0))
void RtpFormatVp8Test::CheckHeader(bool first_in_frame, bool frag_start,
bool frag_end)
{
payload_start_ = 1;
EXPECT_RSV_ZERO(buffer_[0]);
if (first_in_frame & hdr_info_.pictureId != webrtc::kNoPictureId)
{
EXPECT_BIT_I_EQ(buffer_[0], 1);
if (hdr_info_.pictureId > 0x7F)
{
EXPECT_BIT_EQ(buffer_[1], 7, 1);
EXPECT_EQ(buffer_[1] & 0x7F,
(hdr_info_.pictureId >> 8) & 0x7F);
EXPECT_EQ(buffer_[2], hdr_info_.pictureId & 0xFF);
payload_start_ += 2;
}
else
{
EXPECT_BIT_EQ(buffer_[1], 7, 0);
EXPECT_EQ(buffer_[1] & 0x7F,
(hdr_info_.pictureId) & 0x7F);
payload_start_ += 1;
}
}
EXPECT_BIT_N_EQ(buffer_[0], 0);
WebRtc_UWord8 fi = 0x03;
if (frag_start) fi = fi & 0x01;
if (frag_end) fi = fi & 0x02;
EXPECT_FI_EQ(buffer_[0], fi);
if (first_in_frame) EXPECT_BIT_B_EQ(buffer_[0], 1);
}
void RtpFormatVp8Test::CheckPayload(int payload_end)
{
for (int i = payload_start_; i < payload_end; i++, data_ptr_++)
EXPECT_EQ(buffer_[i], *data_ptr_);
}
void RtpFormatVp8Test::CheckLast(bool last) const
{
EXPECT_EQ(last, data_ptr_ == payload_data_ + kPayloadSize);
}
void RtpFormatVp8Test::CheckPacket(int send_bytes, int expect_bytes, bool last,
bool first_in_frame, bool frag_start, bool frag_end)
{
EXPECT_EQ(send_bytes, expect_bytes);
CheckHeader(first_in_frame, frag_start, frag_end);
CheckPayload(send_bytes);
CheckLast(last);
}
TEST_F(RtpFormatVp8Test, TestStrictMode)
{
int send_bytes = 0;
bool last;
bool first_in_frame = true;
hdr_info_.pictureId = 200; // > 0x7F should produce 2-byte PictureID
RtpFormatVp8 packetizer = RtpFormatVp8(payload_data_, kPayloadSize,
hdr_info_, *fragmentation_, webrtc::kStrict);
// get first packet, expect balanced size = same as second packet
EXPECT_EQ(0, packetizer.NextPacket(8, buffer_, &send_bytes, &last));
CheckPacket(send_bytes, 7, last,
first_in_frame,
/* frag_start */ true,
/* frag_end */ false);
first_in_frame = false;
// get second packet
EXPECT_EQ(0, packetizer.NextPacket(8, buffer_, &send_bytes, &last));
CheckPacket(send_bytes, 7, last,
first_in_frame,
/* frag_start */ false,
/* frag_end */ true);
// Second partition
// Get first (and only) packet
EXPECT_EQ(0, packetizer.NextPacket(20, buffer_, &send_bytes, &last));
CheckPacket(send_bytes, 11, last,
first_in_frame,
/* frag_start */ true,
/* frag_end */ true);
// Third partition
// Get first packet (of four)
EXPECT_EQ(0, packetizer.NextPacket(4, buffer_, &send_bytes, &last));
CheckPacket(send_bytes, 4, last,
first_in_frame,
/* frag_start */ true,
/* frag_end */ false);
// Get second packet (of four)
EXPECT_EQ(0, packetizer.NextPacket(4, buffer_, &send_bytes, &last));
CheckPacket(send_bytes, 3, last,
first_in_frame,
/* frag_start */ false,
/* frag_end */ false);
// Get third packet (of four)
EXPECT_EQ(0, packetizer.NextPacket(4, buffer_, &send_bytes, &last));
CheckPacket(send_bytes, 4, last,
first_in_frame,
/* frag_start */ false,
/* frag_end */ false);
// Get fourth and last packet
EXPECT_EQ(0, packetizer.NextPacket(4, buffer_, &send_bytes, &last));
CheckPacket(send_bytes, 3, last,
first_in_frame,
/* frag_start */ false,
/* frag_end */ true);
}
TEST_F(RtpFormatVp8Test, TestAggregateMode)
{
int send_bytes = 0;
bool last;
bool first_in_frame = true;
hdr_info_.pictureId = 20; // <= 0x7F should produce 1-byte PictureID
RtpFormatVp8 packetizer = RtpFormatVp8(payload_data_, kPayloadSize,
hdr_info_, *fragmentation_, webrtc::kAggregate);
// get first packet
// first half of first partition
EXPECT_EQ(0, packetizer.NextPacket(6, buffer_, &send_bytes, &last));
CheckPacket(send_bytes, 6, last,
first_in_frame,
/* frag_start */ true,
/* frag_end */ false);
first_in_frame = false;
// get second packet
// second half of first partition
EXPECT_EQ(0, packetizer.NextPacket(10, buffer_, &send_bytes, &last));
CheckPacket(send_bytes, 7, last,
first_in_frame,
/* frag_start */ false,
/* frag_end */ true);
// get third packet
// last two partitions aggregated
EXPECT_EQ(0, packetizer.NextPacket(25, buffer_, &send_bytes, &last));
CheckPacket(send_bytes, 21, last,
first_in_frame,
/* frag_start */ true,
/* frag_end */ true);
}
TEST_F(RtpFormatVp8Test, TestSloppyMode)
{
int send_bytes = 0;
bool last;
bool first_in_frame = true;
hdr_info_.pictureId = webrtc::kNoPictureId; // no PictureID
RtpFormatVp8 packetizer = RtpFormatVp8(payload_data_, kPayloadSize,
hdr_info_, *fragmentation_, webrtc::kSloppy);
// get first packet
EXPECT_EQ(0, packetizer.NextPacket(9, buffer_, &send_bytes, &last));
CheckPacket(send_bytes, 9, last,
first_in_frame,
/* frag_start */ true,
/* frag_end */ false);
first_in_frame = false;
// get second packet
// fragments of first and second partitions
EXPECT_EQ(0, packetizer.NextPacket(9, buffer_, &send_bytes, &last));
CheckPacket(send_bytes, 9, last,
first_in_frame,
/* frag_start */ false,
/* frag_end */ false);
// get third packet
// fragments of second and third partitions
EXPECT_EQ(0, packetizer.NextPacket(9, buffer_, &send_bytes, &last));
CheckPacket(send_bytes, 9, last,
first_in_frame,
/* frag_start */ false,
/* frag_end */ false);
// get fourth packet
// second half of last partition
EXPECT_EQ(0, packetizer.NextPacket(9, buffer_, &send_bytes, &last));
CheckPacket(send_bytes, 7, last,
first_in_frame,
/* frag_start */ false,
/* frag_end */ true);
}
// Verify that sloppy mode is forced if fragmentation info is missing.
TEST_F(RtpFormatVp8Test, TestSloppyModeFallback)
{
int send_bytes = 0;
bool last;
bool first_in_frame = true;
hdr_info_.pictureId = 200; // > 0x7F should produce 2-byte PictureID
RtpFormatVp8 packetizer = RtpFormatVp8(payload_data_, kPayloadSize,
hdr_info_);
// get first packet
EXPECT_EQ(0, packetizer.NextPacket(9, buffer_, &send_bytes, &last));
CheckPacket(send_bytes, 9, last,
first_in_frame,
/* frag_start */ true,
/* frag_end */ false);
first_in_frame = false;
// get second packet
// fragments of first and second partitions
EXPECT_EQ(0, packetizer.NextPacket(9, buffer_, &send_bytes, &last));
CheckPacket(send_bytes, 9, last,
first_in_frame,
/* frag_start */ false,
/* frag_end */ false);
// get third packet
// fragments of second and third partitions
EXPECT_EQ(0, packetizer.NextPacket(9, buffer_, &send_bytes, &last));
CheckPacket(send_bytes, 9, last,
first_in_frame,
/* frag_start */ false,
/* frag_end */ false);
// get fourth packet
// second half of last partition
EXPECT_EQ(0, packetizer.NextPacket(9, buffer_, &send_bytes, &last));
CheckPacket(send_bytes, 9, last,
first_in_frame,
/* frag_start */ false,
/* frag_end */ true);
}
// Verify that non-reference bit is set.
TEST_F(RtpFormatVp8Test, TestNonReferenceBit) {
int send_bytes = 0;
bool last;
bool first_in_frame = true;
hdr_info_.nonReference = true;
RtpFormatVp8 packetizer = RtpFormatVp8(payload_data_, kPayloadSize,
hdr_info_);
// get first packet
ASSERT_EQ(0, packetizer.NextPacket(25, buffer_, &send_bytes, &last));
ASSERT_FALSE(last);
EXPECT_BIT_N_EQ(buffer_[0], 1);
// get second packet
ASSERT_EQ(0, packetizer.NextPacket(25, buffer_, &send_bytes, &last));
ASSERT_TRUE(last);
EXPECT_BIT_N_EQ(buffer_[0], 1);
}
int main(int argc, char** argv) {
::testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}
} // namespace