OLD | NEW |
---|---|
(Empty) | |
1 // Copyright 2015 The Chromium Authors. All rights reserved. | |
2 // Use of this source code is governed by a BSD-style license that can be | |
3 // found in the LICENSE file. | |
4 | |
5 #include "media/base/android/access_unit_queue.h" | |
6 #include "testing/gtest/include/gtest/gtest.h" | |
7 | |
8 #define ARRAY_SIZE(x) ((sizeof(x) / sizeof(x[0]))) | |
wolenetz
2015/06/11 19:21:21
nit: either remove extra (), or put (some type lik
Tima Vaisburd
2015/06/11 20:54:09
Removed extra ()
| |
9 | |
10 namespace media { | |
11 | |
12 class AccessUnitQueueTest : public testing::Test { | |
13 public: | |
14 AccessUnitQueueTest() {} | |
15 ~AccessUnitQueueTest() override {} | |
16 | |
17 protected: | |
18 enum UnitType { kNormal = 0, kKeyFrame, kEOS, kConfig }; | |
19 struct AUDescriptor { | |
20 UnitType unit_type; | |
21 std::string data; | |
22 }; | |
23 | |
24 DemuxerData CreateDemuxerData(const AUDescriptor* descr, int descr_length); | |
25 }; | |
26 | |
27 DemuxerData AccessUnitQueueTest::CreateDemuxerData(const AUDescriptor* descr, | |
28 int descr_length) { | |
29 DemuxerData result; | |
30 result.type = DemuxerStream::AUDIO; // assign a valid type | |
31 | |
32 for (int i = 0; i < descr_length; ++i) { | |
33 result.access_units.push_back(AccessUnit()); | |
34 AccessUnit& au = result.access_units.back(); | |
35 | |
36 if (descr[i].unit_type == kConfig) { | |
37 au.status = DemuxerStream::kConfigChanged; | |
38 result.demuxer_configs.push_back(DemuxerConfigs()); | |
39 // ignore data | |
40 continue; | |
41 } | |
42 | |
43 au.status = DemuxerStream::kOk; | |
44 | |
45 if (descr[i].unit_type == kEOS) { | |
46 au.is_end_of_stream = true; | |
47 // ignore data | |
48 continue; | |
49 } | |
50 | |
51 au.data = std::vector<uint8>(descr[i].data.begin(), descr[i].data.end()); | |
52 | |
53 if (descr[i].unit_type == kKeyFrame) | |
54 au.is_key_frame = true; | |
55 } | |
56 return result; | |
57 } | |
58 | |
59 #define VERIFY_FIRST_BYTE(expected, info) \ | |
60 do { \ | |
61 EXPECT_NE(nullptr, info.front_unit); \ | |
62 EXPECT_TRUE(info.front_unit->data.size() > 0); \ | |
63 EXPECT_EQ(expected, info.front_unit->data[0]); \ | |
64 } while (0) | |
65 | |
66 TEST_F(AccessUnitQueueTest, InitializedEmpty) { | |
67 AccessUnitQueue au_queue; | |
68 AccessUnitQueue::Info info = au_queue.GetInfo(); | |
69 | |
70 EXPECT_EQ(0, info.length); | |
71 EXPECT_FALSE(info.has_eos); | |
72 EXPECT_EQ(nullptr, info.front_unit); | |
73 EXPECT_EQ(nullptr, info.configs); | |
74 } | |
75 | |
76 TEST_F(AccessUnitQueueTest, RewindToLastKeyFrameEmptyQueue) { | |
77 AccessUnitQueue au_queue; | |
78 EXPECT_FALSE(au_queue.RewindToLastKeyFrame()); | |
79 } | |
80 | |
81 TEST_F(AccessUnitQueueTest, PushAndAdvance) { | |
82 AUDescriptor chunk1[] = {{kNormal, "0"}, | |
83 {kNormal, "1"}, | |
84 {kNormal, "2"}, | |
85 {kNormal, "3"}, | |
86 {kNormal, "4"}, | |
87 {kNormal, "5"}}; | |
88 AUDescriptor chunk2[] = {{kNormal, "6"}, | |
89 {kNormal, "7"}, | |
90 {kNormal, "8"}}; | |
91 | |
92 int total_size = ARRAY_SIZE(chunk1) + ARRAY_SIZE(chunk2); | |
93 | |
94 AccessUnitQueue au_queue; | |
95 au_queue.PushBack(CreateDemuxerData(chunk1, ARRAY_SIZE(chunk1))); | |
96 au_queue.PushBack(CreateDemuxerData(chunk2, ARRAY_SIZE(chunk2))); | |
97 | |
98 AccessUnitQueue::Info info; | |
99 for (int i = 0; i < total_size; ++i) { | |
100 info = au_queue.GetInfo(); | |
101 | |
102 EXPECT_FALSE(info.has_eos); | |
103 EXPECT_EQ(total_size - i, info.length); | |
104 EXPECT_EQ(nullptr, info.configs); | |
105 | |
106 EXPECT_NE(nullptr, info.front_unit); | |
wolenetz
2015/06/11 19:21:21
nit: s/EXPECT/ASSERT to early fail instead of dere
Tima Vaisburd
2015/06/11 20:54:09
Done.
| |
107 EXPECT_TRUE(info.front_unit->data.size() > 0); | |
108 EXPECT_EQ('0' + i, info.front_unit->data[0]); | |
109 | |
110 au_queue.Advance(); | |
111 } | |
112 | |
113 // After we advanced past the last AU, GetInfo() should report starvation. | |
114 info = au_queue.GetInfo(); | |
115 | |
116 EXPECT_EQ(0, info.length); | |
117 EXPECT_FALSE(info.has_eos); | |
118 EXPECT_EQ(nullptr, info.front_unit); | |
119 EXPECT_EQ(nullptr, info.configs); | |
120 } | |
121 | |
122 TEST_F(AccessUnitQueueTest, ChunksDoNotLeak) { | |
123 AUDescriptor chunk[] = { | |
124 {kNormal, "0"}, {kNormal, "1"}, {kNormal, "2"}, {kNormal, "3"}}; | |
125 | |
126 AccessUnitQueue au_queue; | |
127 au_queue.PushBack(CreateDemuxerData(chunk, ARRAY_SIZE(chunk))); | |
128 | |
129 // Verify that the old chunks get deleted (we rely on NumChunksForTesting()) | |
130 for (size_t i = 0; i < 100; ++i) { | |
131 au_queue.PushBack(CreateDemuxerData(chunk, ARRAY_SIZE(chunk))); | |
132 for (size_t j = 0; j < ARRAY_SIZE(chunk); ++j) | |
133 au_queue.Advance(); | |
134 | |
135 // 5 is an arbitrary number, it implies that we keep 4 chunks of history. | |
wolenetz
2015/06/11 19:21:21
Does this need to be arbitrary? If the code change
Tima Vaisburd
2015/06/11 20:54:09
Modified the test. Please see my other comment abo
| |
136 EXPECT_GT(5U, au_queue.NumChunksForTesting()); | |
137 } | |
138 } | |
139 | |
140 TEST_F(AccessUnitQueueTest, PushAfterStarvation) { | |
141 // Two chunks | |
142 AUDescriptor chunk[][4] = { | |
143 {{kNormal, "0"}, {kNormal, "1"}, {kNormal, "2"}, {kNormal, "3"}}, | |
144 {{kNormal, "4"}, {kNormal, "5"}, {kNormal, "6"}, {kNormal, "7"}}}; | |
145 | |
146 AccessUnitQueue au_queue; | |
147 | |
148 // Push the first chunk. | |
149 au_queue.PushBack(CreateDemuxerData(chunk[0], ARRAY_SIZE(chunk[0]))); | |
150 | |
151 // Advance past the end of queue. | |
152 for (size_t i = 0; i < ARRAY_SIZE(chunk[0]); ++i) | |
153 au_queue.Advance(); | |
154 | |
155 // An extra Advance() should not change anything. | |
156 au_queue.Advance(); | |
157 | |
158 // Push the second chunk | |
159 au_queue.PushBack(CreateDemuxerData(chunk[1], ARRAY_SIZE(chunk[1]))); | |
160 | |
161 // Verify that we get the next access unit. | |
162 AccessUnitQueue::Info info = au_queue.GetInfo(); | |
163 VERIFY_FIRST_BYTE('4', info); | |
164 } | |
165 | |
166 TEST_F(AccessUnitQueueTest, HasEOS) { | |
167 // Two chunks | |
168 AUDescriptor chunk[][4] = { | |
169 {{kNormal, "0"}, {kNormal, "1"}, {kNormal, "2"}, {kNormal, "3"}}, | |
170 {{kNormal, "4"}, {kNormal, "5"}, {kNormal, "6"}, {kEOS, "7"}}}; | |
171 | |
172 AccessUnitQueue au_queue; | |
173 au_queue.PushBack(CreateDemuxerData(chunk[0], ARRAY_SIZE(chunk[0]))); | |
174 au_queue.PushBack(CreateDemuxerData(chunk[1], ARRAY_SIZE(chunk[1]))); | |
175 | |
176 // Verify that after EOS has been pushed into the queue, | |
177 // it is reported for every GetInfo() | |
178 for (int i = 0; i < 8; ++i) { | |
179 AccessUnitQueue::Info info = au_queue.GetInfo(); | |
180 | |
181 EXPECT_TRUE(info.has_eos); | |
182 EXPECT_EQ(nullptr, info.configs); | |
183 | |
184 if (i == 7) | |
185 EXPECT_TRUE(info.front_unit->is_end_of_stream); | |
186 else | |
187 VERIFY_FIRST_BYTE('0' + i, info); | |
188 | |
189 au_queue.Advance(); | |
190 } | |
191 } | |
192 | |
193 TEST_F(AccessUnitQueueTest, HasConfigs) { | |
194 AUDescriptor chunk[] = { | |
195 {kNormal, "0"}, {kNormal, "1"}, {kNormal, "2"}, {kConfig, "3"}}; | |
196 | |
197 AccessUnitQueue au_queue; | |
198 au_queue.PushBack(CreateDemuxerData(chunk, ARRAY_SIZE(chunk))); | |
199 | |
200 for (int i = 0; i < 4; ++i) { | |
201 AccessUnitQueue::Info info = au_queue.GetInfo(); | |
202 | |
203 if (i != 3) | |
204 EXPECT_EQ(nullptr, info.configs); | |
205 else | |
206 EXPECT_NE(nullptr, info.configs); | |
207 | |
208 au_queue.Advance(); | |
209 } | |
210 } | |
211 | |
212 TEST_F(AccessUnitQueueTest, ConfigsAndKeyFrame) { | |
213 // Two chunks | |
214 AUDescriptor chunk[][4] = { | |
215 {{kNormal, "0"}, {kKeyFrame, "1"}, {kNormal, "2"}, {kConfig, "3"}}, | |
216 {{kKeyFrame, "4"}, {kNormal, "5"}, {kNormal, "6"}, {kNormal, "7"}}}; | |
217 | |
218 AccessUnitQueue::Info info; | |
219 | |
220 AccessUnitQueue au_queue; | |
221 au_queue.PushBack(CreateDemuxerData(chunk[0], ARRAY_SIZE(chunk[0]))); | |
222 au_queue.PushBack(CreateDemuxerData(chunk[1], ARRAY_SIZE(chunk[1]))); | |
223 | |
224 // There is no prior key frame | |
225 EXPECT_FALSE(au_queue.RewindToLastKeyFrame()); | |
226 | |
227 // Consume first access unit. | |
228 au_queue.Advance(); | |
229 | |
230 // Now the current one is the key frame. It would be safe to configure codec | |
231 // at this moment, so RewindToLastKeyFrame() should return true. | |
232 EXPECT_TRUE(au_queue.RewindToLastKeyFrame()); | |
233 | |
234 info = au_queue.GetInfo(); | |
235 VERIFY_FIRST_BYTE('1', info); | |
236 | |
237 au_queue.Advance(); // now current unit is "2" | |
238 | |
239 info = au_queue.GetInfo(); | |
240 VERIFY_FIRST_BYTE('2', info); | |
241 | |
242 EXPECT_TRUE(au_queue.RewindToLastKeyFrame()); // should go back to "1" | |
243 | |
244 info = au_queue.GetInfo(); | |
245 VERIFY_FIRST_BYTE('1', info); | |
246 | |
247 au_queue.Advance(); // now current unit is "2" | |
248 au_queue.Advance(); // now current unit is "3" | |
249 | |
250 // Verify that we are at "3". | |
251 info = au_queue.GetInfo(); | |
252 EXPECT_NE(nullptr, info.configs); | |
253 | |
254 // Although it would be safe to configure codec (with old config) in this | |
255 // position since it will be immediately reconfigured from the next unit "3", | |
256 // current implementation returns unit "1". | |
257 | |
258 EXPECT_TRUE(au_queue.RewindToLastKeyFrame()); // should go back to "1" | |
259 | |
260 info = au_queue.GetInfo(); | |
261 VERIFY_FIRST_BYTE('1', info); | |
262 | |
263 au_queue.Advance(); // now current unit is "2" | |
264 au_queue.Advance(); // now current unit is "3" | |
265 au_queue.Advance(); // now current unit is "4" | |
266 | |
267 info = au_queue.GetInfo(); | |
268 VERIFY_FIRST_BYTE('4', info); | |
269 | |
270 EXPECT_TRUE(au_queue.RewindToLastKeyFrame()); // should stay at "4" | |
271 | |
272 info = au_queue.GetInfo(); | |
273 VERIFY_FIRST_BYTE('4', info); | |
274 | |
275 au_queue.Advance(); // now current unit is "5" | |
276 au_queue.Advance(); // now current unit is "6" | |
277 | |
278 info = au_queue.GetInfo(); | |
279 VERIFY_FIRST_BYTE('6', info); | |
280 | |
281 EXPECT_TRUE(au_queue.RewindToLastKeyFrame()); // should go back to "4" | |
282 | |
283 info = au_queue.GetInfo(); | |
284 VERIFY_FIRST_BYTE('4', info); | |
285 } | |
286 | |
287 TEST_F(AccessUnitQueueTest, KeyFrameWithLongHistory) { | |
288 // Four chunks | |
289 AUDescriptor chunk[][4] = { | |
290 {{kNormal, "0"}, {kKeyFrame, "1"}, {kNormal, "2"}, {kNormal, "3"}}, | |
291 {{kNormal, "4"}, {kNormal, "5"}, {kNormal, "6"}, {kNormal, "7"}}, | |
292 {{kNormal, "8"}, {kNormal, "9"}, {kNormal, "a"}, {kNormal, "b"}}, | |
293 {{kNormal, "c"}, {kNormal, "d"}, {kKeyFrame, "e"}, {kNormal, "f"}}}; | |
294 | |
295 AccessUnitQueue::Info info; | |
296 | |
297 AccessUnitQueue au_queue; | |
298 for (int i = 0; i < 4; ++i) | |
299 au_queue.PushBack(CreateDemuxerData(chunk[i], ARRAY_SIZE(chunk[i]))); | |
300 | |
301 au_queue.SetHistorySizeForTesting(3); | |
302 | |
303 // Advance to '3'. | |
304 for (int i = 0; i < 3; ++i) | |
305 au_queue.Advance(); | |
306 | |
307 info = au_queue.GetInfo(); | |
308 VERIFY_FIRST_BYTE('3', info); | |
309 | |
310 // Rewind to key frame, the current unit should be '1'. | |
311 EXPECT_TRUE(au_queue.RewindToLastKeyFrame()); | |
312 info = au_queue.GetInfo(); | |
313 VERIFY_FIRST_BYTE('1', info); | |
314 | |
315 // Advance to 'c'. | |
316 for (int i = 0; i < 11; ++i) | |
317 au_queue.Advance(); | |
318 | |
319 info = au_queue.GetInfo(); | |
320 VERIFY_FIRST_BYTE('c', info); | |
321 | |
322 // Rewind to key frame, the current unit should be '1' again. | |
323 EXPECT_TRUE(au_queue.RewindToLastKeyFrame()); | |
324 info = au_queue.GetInfo(); | |
325 VERIFY_FIRST_BYTE('1', info); | |
326 | |
327 // Set history size to 0 (default) | |
328 au_queue.SetHistorySizeForTesting(0); | |
329 | |
330 // Advance to 'd'. Should erase all chunks except the last. | |
331 for (int i = 0; i < 12; ++i) | |
332 au_queue.Advance(); | |
333 | |
334 info = au_queue.GetInfo(); | |
335 VERIFY_FIRST_BYTE('d', info); | |
336 | |
337 // Rewind should not find any key frames. | |
338 EXPECT_FALSE(au_queue.RewindToLastKeyFrame()); | |
339 | |
340 au_queue.Advance(); // Advance to key frame 'e'. | |
341 info = au_queue.GetInfo(); | |
342 VERIFY_FIRST_BYTE('e', info); | |
343 | |
344 // Rewind should find the same unit 'e. | |
345 EXPECT_TRUE(au_queue.RewindToLastKeyFrame()); | |
346 info = au_queue.GetInfo(); | |
347 VERIFY_FIRST_BYTE('e', info); | |
348 } | |
349 | |
350 } // namespace media | |
OLD | NEW |