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