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])) | |
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 ASSERT_NE(nullptr, info.front_unit); | |
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 | |
128 // Verify that the old chunks get deleted (we rely on NumChunksForTesting()). | |
129 | |
wolenetz
2015/06/12 22:05:19
nit: drop extra blank line.
Tima Vaisburd
2015/06/12 22:44:01
Done.
| |
130 // First, run the loop with default history size, which is zero chunks. | |
131 for (size_t i = 0; i < 100; ++i) { | |
132 au_queue.PushBack(CreateDemuxerData(chunk, ARRAY_SIZE(chunk))); | |
133 for (size_t j = 0; j < ARRAY_SIZE(chunk); ++j) | |
134 au_queue.Advance(); | |
135 | |
136 EXPECT_GE(1U, au_queue.NumChunksForTesting()); | |
wolenetz
2015/06/12 22:05:19
s/GE(1U/EQ(0/ : Each of 100 iterations, we push a
Tima Vaisburd
2015/06/12 22:44:01
Yes, my bad thinking. I thought for some reason it
| |
137 } | |
138 | |
139 // Change the history size and run again. | |
140 au_queue.SetHistorySizeForTesting(5); | |
141 | |
142 for (size_t i = 0; i < 100; ++i) { | |
143 au_queue.PushBack(CreateDemuxerData(chunk, ARRAY_SIZE(chunk))); | |
144 for (size_t j = 0; j < ARRAY_SIZE(chunk); ++j) | |
145 au_queue.Advance(); | |
146 | |
147 if (i > 5) | |
148 EXPECT_LE(5U, au_queue.NumChunksForTesting()); | |
wolenetz
2015/06/12 22:05:19
Once we've advanced past the end of the 5th chunk
Tima Vaisburd
2015/06/12 22:44:01
Done.
| |
149 | |
150 EXPECT_GE(6U, au_queue.NumChunksForTesting()); | |
wolenetz
2015/06/12 22:05:19
We know exactly how many chunks should be there: p
Tima Vaisburd
2015/06/12 22:44:01
Done.
| |
151 } | |
152 } | |
153 | |
154 TEST_F(AccessUnitQueueTest, PushAfterStarvation) { | |
155 // Two chunks | |
156 AUDescriptor chunk[][4] = { | |
157 {{kNormal, "0"}, {kNormal, "1"}, {kNormal, "2"}, {kNormal, "3"}}, | |
158 {{kNormal, "4"}, {kNormal, "5"}, {kNormal, "6"}, {kNormal, "7"}}}; | |
159 | |
160 AccessUnitQueue au_queue; | |
161 | |
162 // Push the first chunk. | |
163 au_queue.PushBack(CreateDemuxerData(chunk[0], ARRAY_SIZE(chunk[0]))); | |
164 | |
165 // Advance past the end of queue. | |
166 for (size_t i = 0; i < ARRAY_SIZE(chunk[0]); ++i) | |
167 au_queue.Advance(); | |
168 | |
169 // An extra Advance() should not change anything. | |
170 au_queue.Advance(); | |
171 | |
172 // Push the second chunk | |
173 au_queue.PushBack(CreateDemuxerData(chunk[1], ARRAY_SIZE(chunk[1]))); | |
174 | |
175 // Verify that we get the next access unit. | |
176 AccessUnitQueue::Info info = au_queue.GetInfo(); | |
177 VERIFY_FIRST_BYTE('4', info); | |
178 } | |
179 | |
180 TEST_F(AccessUnitQueueTest, HasEOS) { | |
181 // Two chunks | |
182 AUDescriptor chunk[][4] = { | |
183 {{kNormal, "0"}, {kNormal, "1"}, {kNormal, "2"}, {kNormal, "3"}}, | |
184 {{kNormal, "4"}, {kNormal, "5"}, {kNormal, "6"}, {kEOS, "7"}}}; | |
185 | |
186 AccessUnitQueue au_queue; | |
187 au_queue.PushBack(CreateDemuxerData(chunk[0], ARRAY_SIZE(chunk[0]))); | |
188 au_queue.PushBack(CreateDemuxerData(chunk[1], ARRAY_SIZE(chunk[1]))); | |
189 | |
190 // Verify that after EOS has been pushed into the queue, | |
191 // it is reported for every GetInfo() | |
192 for (int i = 0; i < 8; ++i) { | |
193 AccessUnitQueue::Info info = au_queue.GetInfo(); | |
194 | |
195 EXPECT_TRUE(info.has_eos); | |
196 EXPECT_EQ(nullptr, info.configs); | |
197 | |
198 if (i == 7) | |
199 EXPECT_TRUE(info.front_unit->is_end_of_stream); | |
200 else | |
201 VERIFY_FIRST_BYTE('0' + i, info); | |
202 | |
203 au_queue.Advance(); | |
204 } | |
205 } | |
206 | |
207 TEST_F(AccessUnitQueueTest, HasConfigs) { | |
208 AUDescriptor chunk[] = { | |
209 {kNormal, "0"}, {kNormal, "1"}, {kNormal, "2"}, {kConfig, "3"}}; | |
210 | |
211 AccessUnitQueue au_queue; | |
212 au_queue.PushBack(CreateDemuxerData(chunk, ARRAY_SIZE(chunk))); | |
213 | |
214 for (int i = 0; i < 4; ++i) { | |
215 AccessUnitQueue::Info info = au_queue.GetInfo(); | |
216 | |
217 if (i != 3) | |
218 EXPECT_EQ(nullptr, info.configs); | |
219 else | |
220 EXPECT_NE(nullptr, info.configs); | |
221 | |
222 au_queue.Advance(); | |
223 } | |
224 } | |
225 | |
226 TEST_F(AccessUnitQueueTest, ConfigsAndKeyFrame) { | |
227 // Two chunks | |
228 AUDescriptor chunk[][4] = { | |
229 {{kNormal, "0"}, {kKeyFrame, "1"}, {kNormal, "2"}, {kConfig, "3"}}, | |
230 {{kKeyFrame, "4"}, {kNormal, "5"}, {kNormal, "6"}, {kNormal, "7"}}}; | |
231 | |
232 AccessUnitQueue::Info info; | |
233 | |
234 AccessUnitQueue au_queue; | |
235 au_queue.PushBack(CreateDemuxerData(chunk[0], ARRAY_SIZE(chunk[0]))); | |
236 au_queue.PushBack(CreateDemuxerData(chunk[1], ARRAY_SIZE(chunk[1]))); | |
237 | |
238 // There is no prior key frame | |
239 EXPECT_FALSE(au_queue.RewindToLastKeyFrame()); | |
240 | |
241 // Consume first access unit. | |
242 au_queue.Advance(); | |
243 | |
244 // Now the current one is the key frame. It would be safe to configure codec | |
245 // at this moment, so RewindToLastKeyFrame() should return true. | |
246 EXPECT_TRUE(au_queue.RewindToLastKeyFrame()); | |
247 | |
248 info = au_queue.GetInfo(); | |
249 VERIFY_FIRST_BYTE('1', info); | |
250 | |
251 au_queue.Advance(); // now current unit is "2" | |
252 | |
253 info = au_queue.GetInfo(); | |
254 VERIFY_FIRST_BYTE('2', info); | |
255 | |
256 EXPECT_TRUE(au_queue.RewindToLastKeyFrame()); // should go back to "1" | |
257 | |
258 info = au_queue.GetInfo(); | |
259 VERIFY_FIRST_BYTE('1', info); | |
260 | |
261 au_queue.Advance(); // now current unit is "2" | |
262 au_queue.Advance(); // now current unit is "3" | |
263 | |
264 // Verify that we are at "3". | |
265 info = au_queue.GetInfo(); | |
266 EXPECT_NE(nullptr, info.configs); | |
267 | |
268 // Although it would be safe to configure codec (with old config) in this | |
269 // position since it will be immediately reconfigured from the next unit "3", | |
270 // current implementation returns unit "1". | |
271 | |
272 EXPECT_TRUE(au_queue.RewindToLastKeyFrame()); // should go back to "1" | |
273 | |
274 info = au_queue.GetInfo(); | |
275 VERIFY_FIRST_BYTE('1', info); | |
276 | |
277 au_queue.Advance(); // now current unit is "2" | |
278 au_queue.Advance(); // now current unit is "3" | |
279 au_queue.Advance(); // now current unit is "4" | |
280 | |
281 info = au_queue.GetInfo(); | |
282 VERIFY_FIRST_BYTE('4', info); | |
283 | |
284 EXPECT_TRUE(au_queue.RewindToLastKeyFrame()); // should stay at "4" | |
285 | |
286 info = au_queue.GetInfo(); | |
287 VERIFY_FIRST_BYTE('4', info); | |
288 | |
289 au_queue.Advance(); // now current unit is "5" | |
290 au_queue.Advance(); // now current unit is "6" | |
291 | |
292 info = au_queue.GetInfo(); | |
293 VERIFY_FIRST_BYTE('6', info); | |
294 | |
295 EXPECT_TRUE(au_queue.RewindToLastKeyFrame()); // should go back to "4" | |
296 | |
297 info = au_queue.GetInfo(); | |
298 VERIFY_FIRST_BYTE('4', info); | |
299 } | |
300 | |
301 TEST_F(AccessUnitQueueTest, KeyFrameWithLongHistory) { | |
302 // Four chunks | |
303 AUDescriptor chunk[][4] = { | |
304 {{kNormal, "0"}, {kKeyFrame, "1"}, {kNormal, "2"}, {kNormal, "3"}}, | |
305 {{kNormal, "4"}, {kNormal, "5"}, {kNormal, "6"}, {kNormal, "7"}}, | |
306 {{kNormal, "8"}, {kNormal, "9"}, {kNormal, "a"}, {kNormal, "b"}}, | |
307 {{kNormal, "c"}, {kNormal, "d"}, {kKeyFrame, "e"}, {kNormal, "f"}}}; | |
308 | |
309 AccessUnitQueue::Info info; | |
310 | |
311 AccessUnitQueue au_queue; | |
312 for (int i = 0; i < 4; ++i) | |
313 au_queue.PushBack(CreateDemuxerData(chunk[i], ARRAY_SIZE(chunk[i]))); | |
314 | |
315 au_queue.SetHistorySizeForTesting(3); | |
316 | |
317 // Advance to '3'. | |
318 for (int i = 0; i < 3; ++i) | |
319 au_queue.Advance(); | |
320 | |
321 info = au_queue.GetInfo(); | |
322 VERIFY_FIRST_BYTE('3', info); | |
323 | |
324 // Rewind to key frame, the current unit should be '1'. | |
325 EXPECT_TRUE(au_queue.RewindToLastKeyFrame()); | |
326 info = au_queue.GetInfo(); | |
327 VERIFY_FIRST_BYTE('1', info); | |
328 | |
329 // Advance to 'c'. | |
330 for (int i = 0; i < 11; ++i) | |
331 au_queue.Advance(); | |
332 | |
333 info = au_queue.GetInfo(); | |
334 VERIFY_FIRST_BYTE('c', info); | |
335 | |
336 // Rewind to key frame, the current unit should be '1' again. | |
337 EXPECT_TRUE(au_queue.RewindToLastKeyFrame()); | |
338 info = au_queue.GetInfo(); | |
339 VERIFY_FIRST_BYTE('1', info); | |
340 | |
341 // Set history size to 0 (default) | |
342 au_queue.SetHistorySizeForTesting(0); | |
343 | |
344 // Advance to 'd'. Should erase all chunks except the last. | |
345 for (int i = 0; i < 12; ++i) | |
346 au_queue.Advance(); | |
347 | |
348 info = au_queue.GetInfo(); | |
349 VERIFY_FIRST_BYTE('d', info); | |
350 | |
351 // Rewind should not find any key frames. | |
352 EXPECT_FALSE(au_queue.RewindToLastKeyFrame()); | |
353 | |
354 au_queue.Advance(); // Advance to key frame 'e'. | |
355 info = au_queue.GetInfo(); | |
356 VERIFY_FIRST_BYTE('e', info); | |
357 | |
358 // Rewind should find the same unit 'e. | |
359 EXPECT_TRUE(au_queue.RewindToLastKeyFrame()); | |
360 info = au_queue.GetInfo(); | |
361 VERIFY_FIRST_BYTE('e', info); | |
362 } | |
363 | |
364 } // namespace media | |
OLD | NEW |