Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(665)

Side by Side Diff: media/base/android/access_unit_queue_unittest.cc

Issue 1162203009: Access unit queue for MediaCodecPlayer (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Addressed comments, some questions. Created 5 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698