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