blob: 13cacb54714a3a515666c448e11c6c9fbb427777 [file] [log] [blame]
/*
* Copyright (c) 2018 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 "modules/rtp_rtcp/source/rtp_generic_frame_descriptor_extension.h"
#include "test/gmock.h"
#include "test/gtest.h"
namespace webrtc {
namespace {
using ::testing::ElementsAre;
using ::testing::ElementsAreArray;
using ::testing::IsEmpty;
constexpr uint8_t kDeprecatedFlags = 0x30;
// TODO(danilchap): Add fuzzer to test for various invalid inputs.
class RtpGenericFrameDescriptorExtensionTest
: public ::testing::Test,
public ::testing::WithParamInterface<int> {
public:
RtpGenericFrameDescriptorExtensionTest() : version_(GetParam()) {}
bool Parse(rtc::ArrayView<const uint8_t> data,
RtpGenericFrameDescriptor* descriptor) const {
switch (version_) {
case 0:
return RtpGenericFrameDescriptorExtension00::Parse(data, descriptor);
case 1:
return RtpGenericFrameDescriptorExtension01::Parse(data, descriptor);
}
RTC_NOTREACHED();
return false;
}
size_t ValueSize(const RtpGenericFrameDescriptor& descriptor) const {
switch (version_) {
case 0:
return RtpGenericFrameDescriptorExtension00::ValueSize(descriptor);
case 1:
return RtpGenericFrameDescriptorExtension01::ValueSize(descriptor);
}
RTC_NOTREACHED();
return 0;
}
bool Write(rtc::ArrayView<uint8_t> data,
const RtpGenericFrameDescriptor& descriptor) const {
switch (version_) {
case 0:
return RtpGenericFrameDescriptorExtension00::Write(data, descriptor);
case 1:
return RtpGenericFrameDescriptorExtension01::Write(data, descriptor);
}
RTC_NOTREACHED();
return false;
}
protected:
const int version_;
};
INSTANTIATE_TEST_SUITE_P(,
RtpGenericFrameDescriptorExtensionTest,
::testing::Values(0, 1));
TEST_P(RtpGenericFrameDescriptorExtensionTest,
ParseFirstPacketOfIndependenSubFrame) {
const int kTemporalLayer = 5;
constexpr uint8_t kRaw[] = {0x80 | kTemporalLayer, 0x49, 0x12, 0x34};
RtpGenericFrameDescriptor descriptor;
ASSERT_TRUE(Parse(kRaw, &descriptor));
EXPECT_TRUE(descriptor.FirstPacketInSubFrame());
EXPECT_FALSE(descriptor.LastPacketInSubFrame());
const absl::optional<bool> discardable = descriptor.Discardable();
if (version_ == 0) {
ASSERT_FALSE(discardable.has_value());
} else {
ASSERT_TRUE(discardable.has_value());
EXPECT_FALSE(discardable.value());
}
EXPECT_THAT(descriptor.FrameDependenciesDiffs(), IsEmpty());
EXPECT_EQ(descriptor.TemporalLayer(), kTemporalLayer);
EXPECT_EQ(descriptor.SpatialLayersBitmask(), 0x49);
EXPECT_EQ(descriptor.FrameId(), 0x3412);
}
TEST_P(RtpGenericFrameDescriptorExtensionTest,
WriteFirstPacketOfIndependenSubFrame) {
const int kTemporalLayer = 5;
uint8_t kRaw[] = {0x80 | kTemporalLayer, 0x49, 0x12, 0x34};
if (version_ == 0) {
kRaw[0] |= kDeprecatedFlags;
}
RtpGenericFrameDescriptor descriptor;
descriptor.SetFirstPacketInSubFrame(true);
descriptor.SetTemporalLayer(kTemporalLayer);
descriptor.SetSpatialLayersBitmask(0x49);
descriptor.SetFrameId(0x3412);
ASSERT_EQ(ValueSize(descriptor), sizeof(kRaw));
uint8_t buffer[sizeof(kRaw)];
EXPECT_TRUE(Write(buffer, descriptor));
EXPECT_THAT(buffer, ElementsAreArray(kRaw));
}
TEST_P(RtpGenericFrameDescriptorExtensionTest, ParseLastPacketOfSubFrame) {
constexpr uint8_t kRaw[] = {0x40};
RtpGenericFrameDescriptor descriptor;
ASSERT_TRUE(Parse(kRaw, &descriptor));
EXPECT_FALSE(descriptor.FirstPacketInSubFrame());
const absl::optional<bool> discardable = descriptor.Discardable();
if (version_ == 0) {
ASSERT_FALSE(discardable.has_value());
} else {
ASSERT_TRUE(discardable.has_value());
EXPECT_FALSE(discardable.value());
}
EXPECT_TRUE(descriptor.LastPacketInSubFrame());
}
TEST_P(RtpGenericFrameDescriptorExtensionTest, WriteLastPacketOfSubFrame) {
uint8_t kRaw[] = {0x40};
if (version_ == 0) {
kRaw[0] |= kDeprecatedFlags;
}
RtpGenericFrameDescriptor descriptor;
descriptor.SetLastPacketInSubFrame(true);
ASSERT_EQ(ValueSize(descriptor), sizeof(kRaw));
uint8_t buffer[sizeof(kRaw)];
EXPECT_TRUE(Write(buffer, descriptor));
EXPECT_THAT(buffer, ElementsAreArray(kRaw));
}
TEST_P(RtpGenericFrameDescriptorExtensionTest, ParseDiscardable) {
if (version_ == 0) {
return;
}
constexpr uint8_t kRaw[] = {0x10};
RtpGenericFrameDescriptor descriptor;
ASSERT_TRUE(Parse(kRaw, &descriptor));
const absl::optional<bool> discardable = descriptor.Discardable();
ASSERT_TRUE(discardable.has_value());
EXPECT_TRUE(discardable.value());
}
TEST_P(RtpGenericFrameDescriptorExtensionTest, WriteDiscardable) {
if (version_ == 0) {
return;
}
constexpr uint8_t kRaw[] = {0x10};
RtpGenericFrameDescriptor descriptor;
descriptor.SetDiscardable(true);
ASSERT_EQ(ValueSize(descriptor), sizeof(kRaw));
uint8_t buffer[sizeof(kRaw)];
EXPECT_TRUE(Write(buffer, descriptor));
EXPECT_THAT(buffer, ElementsAreArray(kRaw));
}
TEST_P(RtpGenericFrameDescriptorExtensionTest, ParseMinShortFrameDependencies) {
constexpr uint16_t kDiff = 1;
constexpr uint8_t kRaw[] = {0x88, 0x01, 0x00, 0x00, 0x04};
RtpGenericFrameDescriptor descriptor;
ASSERT_TRUE(Parse(kRaw, &descriptor));
ASSERT_TRUE(descriptor.FirstPacketInSubFrame());
EXPECT_THAT(descriptor.FrameDependenciesDiffs(), ElementsAre(kDiff));
}
TEST_P(RtpGenericFrameDescriptorExtensionTest, WriteMinShortFrameDependencies) {
constexpr uint16_t kDiff = 1;
uint8_t kRaw[] = {0x88, 0x01, 0x00, 0x00, 0x04};
if (version_ == 0) {
kRaw[0] |= kDeprecatedFlags;
}
RtpGenericFrameDescriptor descriptor;
descriptor.SetFirstPacketInSubFrame(true);
descriptor.AddFrameDependencyDiff(kDiff);
ASSERT_EQ(ValueSize(descriptor), sizeof(kRaw));
uint8_t buffer[sizeof(kRaw)];
EXPECT_TRUE(Write(buffer, descriptor));
EXPECT_THAT(buffer, ElementsAreArray(kRaw));
}
TEST_P(RtpGenericFrameDescriptorExtensionTest, ParseMaxShortFrameDependencies) {
constexpr uint16_t kDiff = 0x3f;
constexpr uint8_t kRaw[] = {0xb8, 0x01, 0x00, 0x00, 0xfc};
RtpGenericFrameDescriptor descriptor;
ASSERT_TRUE(Parse(kRaw, &descriptor));
ASSERT_TRUE(descriptor.FirstPacketInSubFrame());
EXPECT_THAT(descriptor.FrameDependenciesDiffs(), ElementsAre(kDiff));
}
TEST_P(RtpGenericFrameDescriptorExtensionTest, WriteMaxShortFrameDependencies) {
constexpr uint16_t kDiff = 0x3f;
uint8_t kRaw[] = {0x88, 0x01, 0x00, 0x00, 0xfc};
if (version_ == 0) {
kRaw[0] |= kDeprecatedFlags;
}
RtpGenericFrameDescriptor descriptor;
descriptor.SetFirstPacketInSubFrame(true);
descriptor.AddFrameDependencyDiff(kDiff);
ASSERT_EQ(ValueSize(descriptor), sizeof(kRaw));
uint8_t buffer[sizeof(kRaw)];
EXPECT_TRUE(Write(buffer, descriptor));
EXPECT_THAT(buffer, ElementsAreArray(kRaw));
}
TEST_P(RtpGenericFrameDescriptorExtensionTest, ParseMinLongFrameDependencies) {
constexpr uint16_t kDiff = 0x40;
constexpr uint8_t kRaw[] = {0xb8, 0x01, 0x00, 0x00, 0x02, 0x01};
RtpGenericFrameDescriptor descriptor;
ASSERT_TRUE(Parse(kRaw, &descriptor));
ASSERT_TRUE(descriptor.FirstPacketInSubFrame());
EXPECT_THAT(descriptor.FrameDependenciesDiffs(), ElementsAre(kDiff));
}
TEST_P(RtpGenericFrameDescriptorExtensionTest, WriteMinLongFrameDependencies) {
constexpr uint16_t kDiff = 0x40;
uint8_t kRaw[] = {0x88, 0x01, 0x00, 0x00, 0x02, 0x01};
if (version_ == 0) {
kRaw[0] |= kDeprecatedFlags;
}
RtpGenericFrameDescriptor descriptor;
descriptor.SetFirstPacketInSubFrame(true);
descriptor.AddFrameDependencyDiff(kDiff);
ASSERT_EQ(ValueSize(descriptor), sizeof(kRaw));
uint8_t buffer[sizeof(kRaw)];
EXPECT_TRUE(Write(buffer, descriptor));
EXPECT_THAT(buffer, ElementsAreArray(kRaw));
}
TEST_P(RtpGenericFrameDescriptorExtensionTest,
ParseLongFrameDependenciesAsBigEndian) {
constexpr uint16_t kDiff = 0x7654 >> 2;
constexpr uint8_t kRaw[] = {0xb8, 0x01, 0x00, 0x00, 0x54 | 0x02, 0x76};
RtpGenericFrameDescriptor descriptor;
ASSERT_TRUE(Parse(kRaw, &descriptor));
ASSERT_TRUE(descriptor.FirstPacketInSubFrame());
EXPECT_THAT(descriptor.FrameDependenciesDiffs(), ElementsAre(kDiff));
}
TEST_P(RtpGenericFrameDescriptorExtensionTest,
WriteLongFrameDependenciesAsBigEndian) {
constexpr uint16_t kDiff = 0x7654 >> 2;
uint8_t kRaw[] = {0x88, 0x01, 0x00, 0x00, 0x54 | 0x02, 0x76};
if (version_ == 0) {
kRaw[0] |= kDeprecatedFlags;
}
RtpGenericFrameDescriptor descriptor;
descriptor.SetFirstPacketInSubFrame(true);
descriptor.AddFrameDependencyDiff(kDiff);
ASSERT_EQ(ValueSize(descriptor), sizeof(kRaw));
uint8_t buffer[sizeof(kRaw)];
EXPECT_TRUE(Write(buffer, descriptor));
EXPECT_THAT(buffer, ElementsAreArray(kRaw));
}
TEST_P(RtpGenericFrameDescriptorExtensionTest, ParseMaxLongFrameDependencies) {
constexpr uint16_t kDiff = 0x3fff;
constexpr uint8_t kRaw[] = {0xb8, 0x01, 0x00, 0x00, 0xfe, 0xff};
RtpGenericFrameDescriptor descriptor;
ASSERT_TRUE(Parse(kRaw, &descriptor));
ASSERT_TRUE(descriptor.FirstPacketInSubFrame());
EXPECT_THAT(descriptor.FrameDependenciesDiffs(), ElementsAre(kDiff));
}
TEST_P(RtpGenericFrameDescriptorExtensionTest, WriteMaxLongFrameDependencies) {
constexpr uint16_t kDiff = 0x3fff;
uint8_t kRaw[] = {0x88, 0x01, 0x00, 0x00, 0xfe, 0xff};
if (version_ == 0) {
kRaw[0] |= kDeprecatedFlags;
}
RtpGenericFrameDescriptor descriptor;
descriptor.SetFirstPacketInSubFrame(true);
descriptor.AddFrameDependencyDiff(kDiff);
ASSERT_EQ(ValueSize(descriptor), sizeof(kRaw));
uint8_t buffer[sizeof(kRaw)];
EXPECT_TRUE(Write(buffer, descriptor));
EXPECT_THAT(buffer, ElementsAreArray(kRaw));
}
TEST_P(RtpGenericFrameDescriptorExtensionTest, ParseTwoFrameDependencies) {
constexpr uint16_t kDiff1 = 9;
constexpr uint16_t kDiff2 = 15;
constexpr uint8_t kRaw[] = {
0xb8, 0x01, 0x00, 0x00, (kDiff1 << 2) | 0x01, kDiff2 << 2};
RtpGenericFrameDescriptor descriptor;
ASSERT_TRUE(Parse(kRaw, &descriptor));
ASSERT_TRUE(descriptor.FirstPacketInSubFrame());
EXPECT_THAT(descriptor.FrameDependenciesDiffs(), ElementsAre(kDiff1, kDiff2));
}
TEST_P(RtpGenericFrameDescriptorExtensionTest, WriteTwoFrameDependencies) {
constexpr uint16_t kDiff1 = 9;
constexpr uint16_t kDiff2 = 15;
uint8_t kRaw[] = {0x88, 0x01, 0x00, 0x00, (kDiff1 << 2) | 0x01, kDiff2 << 2};
if (version_ == 0) {
kRaw[0] |= kDeprecatedFlags;
}
RtpGenericFrameDescriptor descriptor;
descriptor.SetFirstPacketInSubFrame(true);
descriptor.AddFrameDependencyDiff(kDiff1);
descriptor.AddFrameDependencyDiff(kDiff2);
ASSERT_EQ(ValueSize(descriptor), sizeof(kRaw));
uint8_t buffer[sizeof(kRaw)];
EXPECT_TRUE(Write(buffer, descriptor));
EXPECT_THAT(buffer, ElementsAreArray(kRaw));
}
TEST_P(RtpGenericFrameDescriptorExtensionTest,
ParseResolutionOnIndependentFrame) {
constexpr int kWidth = 0x2468;
constexpr int kHeight = 0x6543;
constexpr uint8_t kRaw[] = {0xb0, 0x01, 0x00, 0x00, 0x24, 0x68, 0x65, 0x43};
RtpGenericFrameDescriptor descriptor;
ASSERT_TRUE(Parse(kRaw, &descriptor));
EXPECT_EQ(descriptor.Width(), kWidth);
EXPECT_EQ(descriptor.Height(), kHeight);
}
TEST_P(RtpGenericFrameDescriptorExtensionTest,
WriteResolutionOnIndependentFrame) {
constexpr int kWidth = 0x2468;
constexpr int kHeight = 0x6543;
uint8_t kRaw[] = {0x80, 0x01, 0x00, 0x00, 0x24, 0x68, 0x65, 0x43};
if (version_ == 0) {
kRaw[0] |= kDeprecatedFlags;
}
RtpGenericFrameDescriptor descriptor;
descriptor.SetFirstPacketInSubFrame(true);
descriptor.SetResolution(kWidth, kHeight);
ASSERT_EQ(ValueSize(descriptor), sizeof(kRaw));
uint8_t buffer[sizeof(kRaw)];
EXPECT_TRUE(Write(buffer, descriptor));
EXPECT_THAT(buffer, ElementsAreArray(kRaw));
}
} // namespace
} // namespace webrtc