1 /*
2 * Copyright (c) 2020 The WebRTC project authors. All Rights Reserved.
3 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10
11 #include "modules/rtp_rtcp/source/rtp_dependency_descriptor_extension.h"
12
13 #include "api/array_view.h"
14 #include "api/transport/rtp/dependency_descriptor.h"
15 #include "common_video/generic_frame_descriptor/generic_frame_info.h"
16
17 #include "test/gmock.h"
18
19 namespace webrtc {
20 namespace {
21
22 using ::testing::Each;
23
TEST(RtpDependencyDescriptorExtensionTest,Writer3BytesForPerfectTemplate)24 TEST(RtpDependencyDescriptorExtensionTest, Writer3BytesForPerfectTemplate) {
25 uint8_t buffer[3];
26 FrameDependencyStructure structure;
27 structure.num_decode_targets = 2;
28 structure.num_chains = 2;
29 structure.templates = {
30 FrameDependencyTemplate().Dtis("SR").FrameDiffs({1}).ChainDiffs({2, 2})};
31 DependencyDescriptor descriptor;
32 descriptor.frame_dependencies = structure.templates[0];
33
34 EXPECT_EQ(RtpDependencyDescriptorExtension::ValueSize(structure, descriptor),
35 3u);
36 EXPECT_TRUE(
37 RtpDependencyDescriptorExtension::Write(buffer, structure, descriptor));
38 }
39
TEST(RtpDependencyDescriptorExtensionTest,WriteZeroInUnusedBits)40 TEST(RtpDependencyDescriptorExtensionTest, WriteZeroInUnusedBits) {
41 uint8_t buffer[32];
42 std::memset(buffer, 0xff, sizeof(buffer));
43 FrameDependencyStructure structure;
44 structure.num_decode_targets = 2;
45 structure.num_chains = 2;
46 structure.templates = {
47 FrameDependencyTemplate().Dtis("SR").FrameDiffs({1}).ChainDiffs({1, 1})};
48 DependencyDescriptor descriptor;
49 descriptor.frame_dependencies = structure.templates[0];
50 descriptor.frame_dependencies.frame_diffs = {2};
51
52 // To test unused bytes are zeroed, need a buffer large enough.
53 size_t value_size =
54 RtpDependencyDescriptorExtension::ValueSize(structure, descriptor);
55 ASSERT_LT(value_size, sizeof(buffer));
56
57 ASSERT_TRUE(
58 RtpDependencyDescriptorExtension::Write(buffer, structure, descriptor));
59
60 const uint8_t* unused_bytes = buffer + value_size;
61 size_t num_unused_bytes = buffer + sizeof(buffer) - unused_bytes;
62 // Check remaining bytes are zeroed.
63 EXPECT_THAT(rtc::MakeArrayView(unused_bytes, num_unused_bytes), Each(0));
64 }
65
66 // In practice chain diff for inactive chain will grow uboundly because no
67 // frames are produced for it, that shouldn't block writing the extension.
TEST(RtpDependencyDescriptorExtensionTest,TemplateMatchingSkipsInactiveChains)68 TEST(RtpDependencyDescriptorExtensionTest,
69 TemplateMatchingSkipsInactiveChains) {
70 uint8_t buffer[3];
71 FrameDependencyStructure structure;
72 structure.num_decode_targets = 2;
73 structure.num_chains = 2;
74 structure.templates = {
75 FrameDependencyTemplate().Dtis("SR").ChainDiffs({2, 2})};
76 DependencyDescriptor descriptor;
77 descriptor.frame_dependencies = structure.templates[0];
78
79 // Set only 1st chain as active.
80 std::bitset<32> active_chains = 0b01;
81 descriptor.frame_dependencies.chain_diffs[1] = 1000;
82
83 // Expect perfect template match since the only difference is for an inactive
84 // chain. Pefect template match consumes 3 bytes.
85 EXPECT_EQ(RtpDependencyDescriptorExtension::ValueSize(
86 structure, active_chains, descriptor),
87 3u);
88 EXPECT_TRUE(RtpDependencyDescriptorExtension::Write(
89 buffer, structure, active_chains, descriptor));
90 }
91
TEST(RtpDependencyDescriptorExtensionTest,AcceptsInvalidChainDiffForInactiveChainWhenChainsAreCustom)92 TEST(RtpDependencyDescriptorExtensionTest,
93 AcceptsInvalidChainDiffForInactiveChainWhenChainsAreCustom) {
94 uint8_t buffer[256];
95 FrameDependencyStructure structure;
96 structure.num_decode_targets = 2;
97 structure.num_chains = 2;
98 structure.templates = {
99 FrameDependencyTemplate().Dtis("SR").ChainDiffs({2, 2})};
100 DependencyDescriptor descriptor;
101 descriptor.frame_dependencies = structure.templates[0];
102
103 // Set only 1st chain as active.
104 std::bitset<32> active_chains = 0b01;
105 // Set chain_diff different to the template to make it custom.
106 descriptor.frame_dependencies.chain_diffs[0] = 1;
107 // Set chain diff for inactive chain beyound limit of 255 max chain diff.
108 descriptor.frame_dependencies.chain_diffs[1] = 1000;
109
110 // Because chains are custom, should use more than base 3 bytes.
111 EXPECT_GT(RtpDependencyDescriptorExtension::ValueSize(
112 structure, active_chains, descriptor),
113 3u);
114 EXPECT_TRUE(RtpDependencyDescriptorExtension::Write(
115 buffer, structure, active_chains, descriptor));
116 }
117
TEST(RtpDependencyDescriptorExtensionTest,FailsToWriteInvalidDescriptor)118 TEST(RtpDependencyDescriptorExtensionTest, FailsToWriteInvalidDescriptor) {
119 uint8_t buffer[256];
120 FrameDependencyStructure structure;
121 structure.num_decode_targets = 2;
122 structure.num_chains = 2;
123 structure.templates = {
124 FrameDependencyTemplate().T(0).Dtis("SR").ChainDiffs({2, 2})};
125 DependencyDescriptor descriptor;
126 descriptor.frame_dependencies = structure.templates[0];
127 descriptor.frame_dependencies.temporal_id = 1;
128
129 EXPECT_EQ(
130 RtpDependencyDescriptorExtension::ValueSize(structure, 0b11, descriptor),
131 0u);
132 EXPECT_FALSE(RtpDependencyDescriptorExtension::Write(buffer, structure, 0b11,
133 descriptor));
134 }
135
136 } // namespace
137 } // namespace webrtc
138