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/active_decode_targets_helper.h"
12
13 #include <vector>
14
15 #include "absl/types/optional.h"
16 #include "test/gtest.h"
17
18 namespace webrtc {
19 namespace {
20 constexpr std::bitset<32> kAll = ~uint32_t{0};
21 } // namespace
22
TEST(ActiveDecodeTargetsHelperTest,ReturnsNulloptOnKeyFrameWhenAllDecodeTargetsAreActive)23 TEST(ActiveDecodeTargetsHelperTest,
24 ReturnsNulloptOnKeyFrameWhenAllDecodeTargetsAreActive) {
25 constexpr int kDecodeTargetProtectedByChain[] = {0, 0};
26 ActiveDecodeTargetsHelper helper;
27 int chain_diffs[] = {0};
28 helper.OnFrame(kDecodeTargetProtectedByChain,
29 /*active_decode_targets=*/0b11,
30 /*is_keyframe=*/true, /*frame_id=*/1, chain_diffs);
31
32 EXPECT_EQ(helper.ActiveDecodeTargetsBitmask(), absl::nullopt);
33 }
34
TEST(ActiveDecodeTargetsHelperTest,ReturnsNulloptOnKeyFrameWhenAllDecodeTargetsAreActiveAfterDeltaFrame)35 TEST(ActiveDecodeTargetsHelperTest,
36 ReturnsNulloptOnKeyFrameWhenAllDecodeTargetsAreActiveAfterDeltaFrame) {
37 constexpr int kDecodeTargetProtectedByChain[] = {0, 0};
38 ActiveDecodeTargetsHelper helper;
39 int chain_diffs_key[] = {0};
40 helper.OnFrame(kDecodeTargetProtectedByChain,
41 /*active_decode_targets=*/0b11,
42 /*is_keyframe=*/true, /*frame_id=*/1, chain_diffs_key);
43 int chain_diffs_delta[] = {1};
44 helper.OnFrame(kDecodeTargetProtectedByChain,
45 /*active_decode_targets=*/0b01,
46 /*is_keyframe=*/false, /*frame_id=*/2, chain_diffs_delta);
47
48 ASSERT_EQ(helper.ActiveDecodeTargetsBitmask(), 0b01u);
49 helper.OnFrame(kDecodeTargetProtectedByChain,
50 /*active_decode_targets=*/0b11,
51 /*is_keyframe=*/true, /*frame_id=*/3, chain_diffs_key);
52
53 EXPECT_EQ(helper.ActiveDecodeTargetsBitmask(), absl::nullopt);
54 }
55
TEST(ActiveDecodeTargetsHelperTest,ReturnsBitmaskOnKeyFrameWhenSomeDecodeTargetsAreInactive)56 TEST(ActiveDecodeTargetsHelperTest,
57 ReturnsBitmaskOnKeyFrameWhenSomeDecodeTargetsAreInactive) {
58 constexpr int kDecodeTargetProtectedByChain[] = {0, 0};
59 ActiveDecodeTargetsHelper helper;
60 int chain_diffs[] = {0};
61 helper.OnFrame(kDecodeTargetProtectedByChain,
62 /*active_decode_targets=*/0b01,
63 /*is_keyframe=*/true, /*frame_id=*/1, chain_diffs);
64
65 EXPECT_EQ(helper.ActiveDecodeTargetsBitmask(), 0b01u);
66 }
67
TEST(ActiveDecodeTargetsHelperTest,ReturnsBitmaskOnKeyFrameWhenSomeDecodeTargetsAreInactiveAfterDeltaFrame)68 TEST(ActiveDecodeTargetsHelperTest,
69 ReturnsBitmaskOnKeyFrameWhenSomeDecodeTargetsAreInactiveAfterDeltaFrame) {
70 constexpr int kDecodeTargetProtectedByChain[] = {0, 0};
71 ActiveDecodeTargetsHelper helper;
72 int chain_diffs_key[] = {0};
73 helper.OnFrame(kDecodeTargetProtectedByChain,
74 /*active_decode_targets=*/0b01,
75 /*is_keyframe=*/true, /*frame_id=*/1, chain_diffs_key);
76 int chain_diffs_delta[] = {1};
77 helper.OnFrame(kDecodeTargetProtectedByChain,
78 /*active_decode_targets=*/0b01,
79 /*is_keyframe=*/false, /*frame_id=*/2, chain_diffs_delta);
80
81 ASSERT_EQ(helper.ActiveDecodeTargetsBitmask(), absl::nullopt);
82 helper.OnFrame(kDecodeTargetProtectedByChain,
83 /*active_decode_targets=*/0b01,
84 /*is_keyframe=*/true, /*frame_id=*/3, chain_diffs_key);
85
86 EXPECT_EQ(helper.ActiveDecodeTargetsBitmask(), 0b01u);
87 }
88
TEST(ActiveDecodeTargetsHelperTest,ReturnsNulloptWhenActiveDecodeTargetsAreUnused)89 TEST(ActiveDecodeTargetsHelperTest,
90 ReturnsNulloptWhenActiveDecodeTargetsAreUnused) {
91 constexpr int kDecodeTargetProtectedByChain[] = {0, 0};
92 ActiveDecodeTargetsHelper helper;
93 int chain_diffs[] = {0};
94 helper.OnFrame(kDecodeTargetProtectedByChain,
95 /*active_decode_targets=*/kAll,
96 /*is_keyframe=*/true, /*frame_id=*/1, chain_diffs);
97 EXPECT_EQ(helper.ActiveDecodeTargetsBitmask(), absl::nullopt);
98
99 helper.OnFrame(kDecodeTargetProtectedByChain,
100 /*active_decode_targets=*/kAll,
101 /*is_keyframe=*/false, /*frame_id=*/2, chain_diffs);
102 EXPECT_EQ(helper.ActiveDecodeTargetsBitmask(), absl::nullopt);
103 }
104
TEST(ActiveDecodeTargetsHelperTest,ReturnsNulloptOnDeltaFrameAfterSentOnKeyFrame)105 TEST(ActiveDecodeTargetsHelperTest,
106 ReturnsNulloptOnDeltaFrameAfterSentOnKeyFrame) {
107 constexpr int kDecodeTargetProtectedByChain[] = {0, 0};
108 ActiveDecodeTargetsHelper helper;
109 int chain_diffs_key[] = {0};
110 helper.OnFrame(kDecodeTargetProtectedByChain,
111 /*active_decode_targets=*/0b01,
112 /*is_keyframe=*/true, /*frame_id=*/1, chain_diffs_key);
113 int chain_diffs_delta[] = {1};
114 helper.OnFrame(kDecodeTargetProtectedByChain,
115 /*active_decode_targets=*/0b01,
116 /*is_keyframe=*/false, /*frame_id=*/2, chain_diffs_delta);
117
118 EXPECT_EQ(helper.ActiveDecodeTargetsBitmask(), absl::nullopt);
119 }
120
TEST(ActiveDecodeTargetsHelperTest,ReturnsNewBitmaskOnDeltaFrame)121 TEST(ActiveDecodeTargetsHelperTest, ReturnsNewBitmaskOnDeltaFrame) {
122 constexpr int kDecodeTargetProtectedByChain[] = {0, 0};
123 ActiveDecodeTargetsHelper helper;
124 int chain_diffs_key[] = {0};
125 helper.OnFrame(kDecodeTargetProtectedByChain,
126 /*active_decode_targets=*/0b11,
127 /*is_keyframe=*/true, /*frame_id=*/1, chain_diffs_key);
128 ASSERT_EQ(helper.ActiveDecodeTargetsBitmask(), absl::nullopt);
129 int chain_diffs_delta[] = {1};
130 helper.OnFrame(kDecodeTargetProtectedByChain,
131 /*active_decode_targets=*/0b01,
132 /*is_keyframe=*/false, /*frame_id=*/2, chain_diffs_delta);
133
134 EXPECT_EQ(helper.ActiveDecodeTargetsBitmask(), 0b01u);
135 }
136
TEST(ActiveDecodeTargetsHelperTest,ReturnsBitmaskWhenAllDecodeTargetsReactivatedOnDeltaFrame)137 TEST(ActiveDecodeTargetsHelperTest,
138 ReturnsBitmaskWhenAllDecodeTargetsReactivatedOnDeltaFrame) {
139 constexpr int kDecodeTargetProtectedByChain[] = {0, 0};
140 ActiveDecodeTargetsHelper helper;
141 int chain_diffs_key[] = {0};
142 helper.OnFrame(kDecodeTargetProtectedByChain,
143 /*active_decode_targets=*/0b01,
144 /*is_keyframe=*/true, /*frame_id=*/1, chain_diffs_key);
145 ASSERT_NE(helper.ActiveDecodeTargetsBitmask(), absl::nullopt);
146 int chain_diffs_delta[] = {1};
147 helper.OnFrame(kDecodeTargetProtectedByChain,
148 /*active_decode_targets=*/0b01,
149 /*is_keyframe=*/false, /*frame_id=*/2, chain_diffs_delta);
150 ASSERT_EQ(helper.ActiveDecodeTargetsBitmask(), absl::nullopt);
151
152 // Reactive all the decode targets
153 helper.OnFrame(kDecodeTargetProtectedByChain,
154 /*active_decode_targets=*/kAll,
155 /*is_keyframe=*/false, /*frame_id=*/3, chain_diffs_delta);
156 EXPECT_EQ(helper.ActiveDecodeTargetsBitmask(), 0b11u);
157 }
158
TEST(ActiveDecodeTargetsHelperTest,ReturnsNulloptAfterSentOnAllActiveChains)159 TEST(ActiveDecodeTargetsHelperTest, ReturnsNulloptAfterSentOnAllActiveChains) {
160 // Active decode targets (0 and 1) are protected by chains 1 and 2.
161 const std::bitset<32> kSome = 0b011;
162 constexpr int kDecodeTargetProtectedByChain[] = {2, 1, 0};
163
164 ActiveDecodeTargetsHelper helper;
165 int chain_diffs_key[] = {0, 0, 0};
166 helper.OnFrame(kDecodeTargetProtectedByChain,
167 /*active_decode_targets=*/0b111,
168 /*is_keyframe=*/true,
169 /*frame_id=*/0, chain_diffs_key);
170 ASSERT_EQ(helper.ActiveDecodeTargetsBitmask(), absl::nullopt);
171
172 int chain_diffs_delta1[] = {1, 1, 1};
173 helper.OnFrame(kDecodeTargetProtectedByChain,
174 /*active_decode_targets=*/kSome,
175 /*is_keyframe=*/false,
176 /*frame_id=*/1, chain_diffs_delta1);
177 EXPECT_EQ(helper.ActiveDecodeTargetsBitmask(), 0b011u);
178
179 int chain_diffs_delta2[] = {2, 2, 1}; // Previous frame was part of chain#2
180 helper.OnFrame(kDecodeTargetProtectedByChain,
181 /*active_decode_targets=*/kSome,
182 /*is_keyframe=*/false,
183 /*frame_id=*/2, chain_diffs_delta2);
184 EXPECT_EQ(helper.ActiveDecodeTargetsBitmask(), 0b011u);
185
186 // active_decode_targets_bitmask was send on chains 1 and 2. It was never sent
187 // on chain 0, but chain 0 only protects inactive decode target#2
188 int chain_diffs_delta3[] = {3, 1, 2}; // Previous frame was part of chain#1
189 helper.OnFrame(kDecodeTargetProtectedByChain,
190 /*active_decode_targets=*/kSome,
191 /*is_keyframe=*/false,
192 /*frame_id=*/3, chain_diffs_delta3);
193 EXPECT_EQ(helper.ActiveDecodeTargetsBitmask(), absl::nullopt);
194 }
195
TEST(ActiveDecodeTargetsHelperTest,ReturnsBitmaskWhenChanged)196 TEST(ActiveDecodeTargetsHelperTest, ReturnsBitmaskWhenChanged) {
197 constexpr int kDecodeTargetProtectedByChain[] = {0, 1, 1};
198
199 ActiveDecodeTargetsHelper helper;
200 int chain_diffs_key[] = {0, 0};
201 helper.OnFrame(kDecodeTargetProtectedByChain, /*active_decode_targets=*/0b111,
202 /*is_keyframe=*/true,
203 /*frame_id=*/0, chain_diffs_key);
204 int chain_diffs_delta1[] = {1, 1};
205 helper.OnFrame(kDecodeTargetProtectedByChain,
206 /*active_decode_targets=*/0b011,
207 /*is_keyframe=*/false,
208 /*frame_id=*/1, chain_diffs_delta1);
209 EXPECT_EQ(helper.ActiveDecodeTargetsBitmask(), 0b011u);
210
211 int chain_diffs_delta2[] = {1, 2};
212 helper.OnFrame(kDecodeTargetProtectedByChain,
213 /*active_decode_targets=*/0b101,
214 /*is_keyframe=*/false,
215 /*frame_id=*/2, chain_diffs_delta2);
216 EXPECT_EQ(helper.ActiveDecodeTargetsBitmask(), 0b101u);
217
218 // active_decode_target_bitmask was send on chain0, but it was an old one.
219 int chain_diffs_delta3[] = {2, 1};
220 helper.OnFrame(kDecodeTargetProtectedByChain,
221 /*active_decode_targets=*/0b101,
222 /*is_keyframe=*/false,
223 /*frame_id=*/3, chain_diffs_delta3);
224 EXPECT_EQ(helper.ActiveDecodeTargetsBitmask(), 0b101u);
225 }
226
TEST(ActiveDecodeTargetsHelperTest,ReturnsNulloptWhenChainsAreNotUsed)227 TEST(ActiveDecodeTargetsHelperTest, ReturnsNulloptWhenChainsAreNotUsed) {
228 const rtc::ArrayView<const int> kDecodeTargetProtectedByChain;
229 const rtc::ArrayView<const int> kNoChainDiffs;
230
231 ActiveDecodeTargetsHelper helper;
232 helper.OnFrame(kDecodeTargetProtectedByChain, /*active_decode_targets=*/kAll,
233 /*is_keyframe=*/true,
234 /*frame_id=*/0, kNoChainDiffs);
235 EXPECT_EQ(helper.ActiveDecodeTargetsBitmask(), absl::nullopt);
236
237 helper.OnFrame(kDecodeTargetProtectedByChain,
238 /*active_decode_targets=*/0b101,
239 /*is_keyframe=*/false,
240 /*frame_id=*/1, kNoChainDiffs);
241 EXPECT_EQ(helper.ActiveDecodeTargetsBitmask(), absl::nullopt);
242 }
243
TEST(ActiveDecodeTargetsHelperTest,Supports32DecodeTargets)244 TEST(ActiveDecodeTargetsHelperTest, Supports32DecodeTargets) {
245 std::bitset<32> some;
246 std::vector<int> decode_target_protected_by_chain(32);
247 for (int i = 0; i < 32; ++i) {
248 decode_target_protected_by_chain[i] = i;
249 some[i] = i % 2 == 0;
250 }
251
252 ActiveDecodeTargetsHelper helper;
253 std::vector<int> chain_diffs_key(32, 0);
254 helper.OnFrame(decode_target_protected_by_chain,
255 /*active_decode_targets=*/some,
256 /*is_keyframe=*/true,
257 /*frame_id=*/1, chain_diffs_key);
258 EXPECT_EQ(helper.ActiveDecodeTargetsBitmask(), some.to_ulong());
259 std::vector<int> chain_diffs_delta(32, 1);
260 helper.OnFrame(decode_target_protected_by_chain,
261 /*active_decode_targets=*/some,
262 /*is_keyframe=*/false,
263 /*frame_id=*/2, chain_diffs_delta);
264 EXPECT_EQ(helper.ActiveDecodeTargetsBitmask(), absl::nullopt);
265 helper.OnFrame(decode_target_protected_by_chain,
266 /*active_decode_targets=*/kAll,
267 /*is_keyframe=*/false,
268 /*frame_id=*/2, chain_diffs_delta);
269 EXPECT_EQ(helper.ActiveDecodeTargetsBitmask(), kAll.to_ulong());
270 }
271
272 } // namespace webrtc
273