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.
5 #include "media/base/android/access_unit_queue.h"
6 #include "testing/gtest/include/gtest/gtest.h"
8 #define ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0]))
12 class AccessUnitQueueTest
: public testing::Test
{
14 AccessUnitQueueTest() {}
15 ~AccessUnitQueueTest() override
{}
18 enum UnitType
{ kNormal
= 0, kKeyFrame
, kEOS
, kConfig
};
24 DemuxerData
CreateDemuxerData(const AUDescriptor
* descr
, int descr_length
);
27 DemuxerData
AccessUnitQueueTest::CreateDemuxerData(const AUDescriptor
* descr
,
30 result
.type
= DemuxerStream::AUDIO
; // assign a valid type
32 for (int i
= 0; i
< descr_length
; ++i
) {
33 result
.access_units
.push_back(AccessUnit());
34 AccessUnit
& au
= result
.access_units
.back();
36 if (descr
[i
].unit_type
== kConfig
) {
37 au
.status
= DemuxerStream::kConfigChanged
;
38 result
.demuxer_configs
.push_back(DemuxerConfigs());
43 au
.status
= DemuxerStream::kOk
;
45 if (descr
[i
].unit_type
== kEOS
) {
46 au
.is_end_of_stream
= true;
51 au
.data
= std::vector
<uint8
>(descr
[i
].data
.begin(), descr
[i
].data
.end());
53 if (descr
[i
].unit_type
== kKeyFrame
)
54 au
.is_key_frame
= true;
59 #define VERIFY_FIRST_BYTE(expected, info) \
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]); \
66 TEST_F(AccessUnitQueueTest
, InitializedEmpty
) {
67 AccessUnitQueue au_queue
;
68 AccessUnitQueue::Info info
= au_queue
.GetInfo();
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
);
76 TEST_F(AccessUnitQueueTest
, RewindToLastKeyFrameEmptyQueue
) {
77 AccessUnitQueue au_queue
;
78 EXPECT_FALSE(au_queue
.RewindToLastKeyFrame());
81 TEST_F(AccessUnitQueueTest
, PushAndAdvance
) {
82 AUDescriptor chunk1
[] = {{kNormal
, "0"},
88 AUDescriptor chunk2
[] = {{kNormal
, "6"},
92 int total_size
= ARRAY_SIZE(chunk1
) + ARRAY_SIZE(chunk2
);
94 AccessUnitQueue au_queue
;
95 au_queue
.PushBack(CreateDemuxerData(chunk1
, ARRAY_SIZE(chunk1
)));
96 au_queue
.PushBack(CreateDemuxerData(chunk2
, ARRAY_SIZE(chunk2
)));
98 AccessUnitQueue::Info info
;
99 for (int i
= 0; i
< total_size
; ++i
) {
100 info
= au_queue
.GetInfo();
102 EXPECT_FALSE(info
.has_eos
);
103 EXPECT_EQ(total_size
- i
, info
.length
);
104 EXPECT_EQ(nullptr, info
.configs
);
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]);
113 // After we advanced past the last AU, GetInfo() should report starvation.
114 info
= au_queue
.GetInfo();
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
);
122 TEST_F(AccessUnitQueueTest
, ChunksDoNotLeak
) {
123 AUDescriptor chunk
[] = {
124 {kNormal
, "0"}, {kNormal
, "1"}, {kNormal
, "2"}, {kNormal
, "3"}};
126 AccessUnitQueue au_queue
;
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
)
135 EXPECT_EQ(0U, au_queue
.NumChunksForTesting());
138 // Change the history size and run again.
139 au_queue
.SetHistorySizeForTesting(5);
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
)
147 EXPECT_EQ(i
+ 1, au_queue
.NumChunksForTesting());
149 EXPECT_EQ(5U, au_queue
.NumChunksForTesting());
153 TEST_F(AccessUnitQueueTest
, PushAfterStarvation
) {
155 AUDescriptor chunk
[][4] = {
156 {{kNormal
, "0"}, {kNormal
, "1"}, {kNormal
, "2"}, {kNormal
, "3"}},
157 {{kNormal
, "4"}, {kNormal
, "5"}, {kNormal
, "6"}, {kNormal
, "7"}}};
159 AccessUnitQueue au_queue
;
161 // Push the first chunk.
162 au_queue
.PushBack(CreateDemuxerData(chunk
[0], ARRAY_SIZE(chunk
[0])));
164 // Advance past the end of queue.
165 for (size_t i
= 0; i
< ARRAY_SIZE(chunk
[0]); ++i
)
168 // An extra Advance() should not change anything.
171 // Push the second chunk
172 au_queue
.PushBack(CreateDemuxerData(chunk
[1], ARRAY_SIZE(chunk
[1])));
174 // Verify that we get the next access unit.
175 AccessUnitQueue::Info info
= au_queue
.GetInfo();
176 VERIFY_FIRST_BYTE('4', info
);
179 TEST_F(AccessUnitQueueTest
, HasEOS
) {
181 AUDescriptor chunk
[][4] = {
182 {{kNormal
, "0"}, {kNormal
, "1"}, {kNormal
, "2"}, {kNormal
, "3"}},
183 {{kNormal
, "4"}, {kNormal
, "5"}, {kNormal
, "6"}, {kEOS
, "7"}}};
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])));
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();
194 EXPECT_TRUE(info
.has_eos
);
195 EXPECT_EQ(nullptr, info
.configs
);
198 EXPECT_TRUE(info
.front_unit
->is_end_of_stream
);
200 VERIFY_FIRST_BYTE('0' + i
, info
);
206 TEST_F(AccessUnitQueueTest
, HasConfigs
) {
207 AUDescriptor chunk
[] = {
208 {kNormal
, "0"}, {kNormal
, "1"}, {kNormal
, "2"}, {kConfig
, "3"}};
210 AccessUnitQueue au_queue
;
211 au_queue
.PushBack(CreateDemuxerData(chunk
, ARRAY_SIZE(chunk
)));
213 for (int i
= 0; i
< 4; ++i
) {
214 AccessUnitQueue::Info info
= au_queue
.GetInfo();
217 EXPECT_EQ(nullptr, info
.configs
);
219 EXPECT_NE(nullptr, info
.configs
);
225 TEST_F(AccessUnitQueueTest
, ConfigsAndKeyFrame
) {
227 AUDescriptor chunk
[][4] = {
228 {{kNormal
, "0"}, {kKeyFrame
, "1"}, {kNormal
, "2"}, {kConfig
, "3"}},
229 {{kKeyFrame
, "4"}, {kNormal
, "5"}, {kNormal
, "6"}, {kNormal
, "7"}}};
231 AccessUnitQueue::Info info
;
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])));
237 // There is no prior key frame
238 EXPECT_FALSE(au_queue
.RewindToLastKeyFrame());
240 // Consume first access unit.
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());
247 info
= au_queue
.GetInfo();
248 VERIFY_FIRST_BYTE('1', info
);
250 au_queue
.Advance(); // now current unit is "2"
252 info
= au_queue
.GetInfo();
253 VERIFY_FIRST_BYTE('2', info
);
255 EXPECT_TRUE(au_queue
.RewindToLastKeyFrame()); // should go back to "1"
257 info
= au_queue
.GetInfo();
258 VERIFY_FIRST_BYTE('1', info
);
260 au_queue
.Advance(); // now current unit is "2"
261 au_queue
.Advance(); // now current unit is "3"
263 // Verify that we are at "3".
264 info
= au_queue
.GetInfo();
265 EXPECT_NE(nullptr, info
.configs
);
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".
271 EXPECT_TRUE(au_queue
.RewindToLastKeyFrame()); // should go back to "1"
273 info
= au_queue
.GetInfo();
274 VERIFY_FIRST_BYTE('1', info
);
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"
280 info
= au_queue
.GetInfo();
281 VERIFY_FIRST_BYTE('4', info
);
283 EXPECT_TRUE(au_queue
.RewindToLastKeyFrame()); // should stay at "4"
285 info
= au_queue
.GetInfo();
286 VERIFY_FIRST_BYTE('4', info
);
288 au_queue
.Advance(); // now current unit is "5"
289 au_queue
.Advance(); // now current unit is "6"
291 info
= au_queue
.GetInfo();
292 VERIFY_FIRST_BYTE('6', info
);
294 EXPECT_TRUE(au_queue
.RewindToLastKeyFrame()); // should go back to "4"
296 info
= au_queue
.GetInfo();
297 VERIFY_FIRST_BYTE('4', info
);
300 TEST_F(AccessUnitQueueTest
, KeyFrameWithLongHistory
) {
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"}}};
308 AccessUnitQueue::Info info
;
310 AccessUnitQueue au_queue
;
311 for (int i
= 0; i
< 4; ++i
)
312 au_queue
.PushBack(CreateDemuxerData(chunk
[i
], ARRAY_SIZE(chunk
[i
])));
314 au_queue
.SetHistorySizeForTesting(3);
317 for (int i
= 0; i
< 3; ++i
)
320 info
= au_queue
.GetInfo();
321 VERIFY_FIRST_BYTE('3', info
);
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
);
329 for (int i
= 0; i
< 11; ++i
)
332 info
= au_queue
.GetInfo();
333 VERIFY_FIRST_BYTE('c', info
);
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
);
340 // Set history size to 0 (default)
341 au_queue
.SetHistorySizeForTesting(0);
343 // Advance to 'd'. Should erase all chunks except the last.
344 for (int i
= 0; i
< 12; ++i
)
347 info
= au_queue
.GetInfo();
348 VERIFY_FIRST_BYTE('d', info
);
350 // Rewind should not find any key frames.
351 EXPECT_FALSE(au_queue
.RewindToLastKeyFrame());
353 au_queue
.Advance(); // Advance to key frame 'e'.
354 info
= au_queue
.GetInfo();
355 VERIFY_FIRST_BYTE('e', info
);
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
);