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