Chromium Code Reviews| Index: media/base/android/access_unit_queue_unittest.cc |
| diff --git a/media/base/android/access_unit_queue_unittest.cc b/media/base/android/access_unit_queue_unittest.cc |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..120739ad5b22712f1ef01022c2785143d57f4a99 |
| --- /dev/null |
| +++ b/media/base/android/access_unit_queue_unittest.cc |
| @@ -0,0 +1,314 @@ |
| +// Copyright 2015 The Chromium Authors. All rights reserved. |
| +// Use of this source code is governed by a BSD-style license that can be |
| +// found in the LICENSE file. |
| + |
| +#include "media/base/android/access_unit_queue.h" |
| +#include "testing/gtest/include/gtest/gtest.h" |
| + |
| +#define ARRAY_SIZE(x) (int)(sizeof(x)/sizeof(x[0])) |
|
wolenetz
2015/06/08 21:37:09
nit ditto: size_t to int truncation.
nit: add spac
Tima Vaisburd
2015/06/09 21:29:21
Done.
|
| + |
| +namespace media { |
| + |
| +class AccessUnitQueueTest : public testing::Test { |
| + public: |
| + AccessUnitQueueTest() {} |
| + ~AccessUnitQueueTest() override {} |
| + |
| + protected: |
| + enum Flags {kNone = 0, kKeyFrame = 1, kEOS = 2, kConfig = 4}; |
|
qinmin
2015/06/08 19:39:38
nit: these flags are not used together, just enum
wolenetz
2015/06/08 21:37:09
Suggestion: Please run this CL through clang forma
Tima Vaisburd
2015/06/09 21:29:21
Done.
Tima Vaisburd
2015/06/09 21:29:21
Done renaming and ran through CL. After that I mod
|
| + struct AUDescriptor { |
| + int flags; |
|
wolenetz
2015/06/08 21:37:09
nit: s/flags/unit_type/ (or unit_status ?) ?
Tima Vaisburd
2015/06/09 21:29:21
Done.
|
| + std::string data; |
| + }; |
| + |
| + DemuxerData CreateDemuxerData(const AUDescriptor* descr, int descr_length); |
| +}; |
| + |
| +DemuxerData AccessUnitQueueTest::CreateDemuxerData( |
| + const AUDescriptor* descr, int descr_length) { |
| + DemuxerData result; |
| + result.type = DemuxerStream::AUDIO; // assign a valid type |
|
wolenetz
2015/06/08 21:37:09
nit: Here and elsewhere: two spaces prior to same-
Tima Vaisburd
2015/06/09 21:29:21
Done.
|
| + |
| + for (int i = 0; i < descr_length; ++i) { |
| + result.access_units.push_back(AccessUnit()); |
| + AccessUnit& au = result.access_units.back(); |
| + au.status = (descr[i].flags & kConfig) ? |
| + DemuxerStream::kConfigChanged : DemuxerStream::kOk; |
| + if (au.status == DemuxerStream::kConfigChanged) { |
| + result.demuxer_configs.push_back(DemuxerConfigs()); |
| + continue; |
| + } |
| + |
| + au.data = std::vector<uint8>(descr[i].data.begin(), descr[i].data.end()); |
| + au.is_key_frame = (descr[i].flags & kKeyFrame); |
| + au.is_end_of_stream = (descr[i].flags & kEOS); |
| + } |
| + return result; |
| +} |
| + |
| +#define VERIFY_FIRST_BYTE(expected, info) \ |
| + do { \ |
| + EXPECT_NE(nullptr, info.front_unit); \ |
| + EXPECT_TRUE(info.front_unit->data.size() > 0); \ |
| + EXPECT_EQ(expected, info.front_unit->data[0]); \ |
| + } \ |
| + while (0) |
|
wolenetz
2015/06/08 21:37:09
nit: put while on previous line
Tima Vaisburd
2015/06/09 21:29:21
Done.
|
| + |
| +TEST_F(AccessUnitQueueTest, InitializedEmpty) { |
| + AccessUnitQueue au_queue; |
| + AccessUnitQueue::Info info = au_queue.GetInfo(); |
| + |
| + EXPECT_EQ(0, info.length); |
| + EXPECT_FALSE(info.has_eos); |
| + EXPECT_EQ(nullptr, info.front_unit); |
| + EXPECT_EQ(nullptr, info.configs); |
| +} |
| + |
| +TEST_F(AccessUnitQueueTest, SkipToKeyFrameEmptyQueue) { |
| + AccessUnitQueue au_queue; |
| + EXPECT_FALSE(au_queue.SkipToKeyFrame()); |
| +} |
| + |
| +TEST_F(AccessUnitQueueTest, PushAndAdvance) { |
| + AUDescriptor chunk1[] = { |
| + {kNone, "0"}, |
|
qinmin
2015/06/08 19:39:38
nit: space before '}' and after '{', same below
Tima Vaisburd
2015/06/09 21:29:21
cl format removed these spaces.
|
| + {kNone, "1"}, |
| + {kNone, "2"}, |
| + {kNone, "3"}, |
| + {kNone, "4"}, |
| + {kNone, "5"} |
| + }; |
| + AUDescriptor chunk2[] = { |
| + {kNone, "6"}, |
| + {kNone, "7"}, |
| + {kNone, "8"} |
| + }; |
| + |
| + int total_size = ARRAY_SIZE(chunk1) + ARRAY_SIZE(chunk2); |
| + |
| + AccessUnitQueue au_queue; |
| + au_queue.PushBack(CreateDemuxerData(chunk1, ARRAY_SIZE(chunk1))); |
| + au_queue.PushBack(CreateDemuxerData(chunk2, ARRAY_SIZE(chunk2))); |
| + |
| + AccessUnitQueue::Info info; |
| + for (int i = 0; i < total_size; ++i) { |
| + info = au_queue.GetInfo(); |
| + |
| + EXPECT_FALSE(info.has_eos); |
| + EXPECT_EQ(total_size - i, info.length); |
| + EXPECT_EQ(nullptr, info.configs); |
| + |
| + EXPECT_NE(nullptr, info.front_unit); |
| + EXPECT_TRUE(info.front_unit->data.size() > 0); |
| + EXPECT_EQ('0' + i, info.front_unit->data[0]); |
| + |
| + au_queue.Advance(); |
| + } |
| + |
| + // After we advanced past the last AU, GetInfo() should report starvation. |
| + info = au_queue.GetInfo(); |
| + |
| + EXPECT_EQ(0, info.length); |
| + EXPECT_FALSE(info.has_eos); |
| + EXPECT_EQ(nullptr, info.front_unit); |
| + EXPECT_EQ(nullptr, info.configs); |
| +} |
| + |
| +TEST_F(AccessUnitQueueTest, ChunksDoNotLeak) { |
| + AUDescriptor chunk[] = { |
| + {kNone, "0"}, |
| + {kNone, "1"}, |
| + {kNone, "2"}, |
| + {kNone, "3"} |
| + }; |
| + |
| + AccessUnitQueue au_queue; |
| + au_queue.PushBack(CreateDemuxerData(chunk, ARRAY_SIZE(chunk))); |
| + |
| + // Verify that the old chunks get deleted (we rely on NumChunksForTesting()) |
| + for (int i = 0; i < 100; ++i) { |
| + au_queue.PushBack(CreateDemuxerData(chunk, ARRAY_SIZE(chunk))); |
| + for (int j = 0; j < ARRAY_SIZE(chunk); ++j) |
| + au_queue.Advance(); |
| + |
| + // 5 is an arbitrary number, it implies that we keep 4 chunks of history. |
| + EXPECT_GT(5U, au_queue.NumChunksForTesting()); |
| + } |
| +} |
| + |
| +TEST_F(AccessUnitQueueTest, PushAfterStarvation) { |
| + // Two chunks |
| + AUDescriptor chunk[][4] = {{ |
| + {kNone, "0"}, |
| + {kNone, "1"}, |
| + {kNone, "2"}, |
| + {kNone, "3"} |
| + }, { |
| + {kNone, "4"}, |
| + {kNone, "5"}, |
| + {kNone, "6"}, |
| + {kNone, "7"} |
| + } |
| + }; |
| + |
| + AccessUnitQueue au_queue; |
| + |
| + // Push the first chunk. |
| + au_queue.PushBack(CreateDemuxerData(chunk[0], ARRAY_SIZE(chunk[0]))); |
| + |
| + // Advance past the end of queue. |
| + for (int i = 0; i < ARRAY_SIZE(chunk[0]); ++i) |
| + au_queue.Advance(); |
| + |
| + // An extra Advance() should not change anything. |
| + au_queue.Advance(); |
| + |
| + // Push the second chunk |
| + au_queue.PushBack(CreateDemuxerData(chunk[1], ARRAY_SIZE(chunk[1]))); |
| + |
| + // Verify that we get the next access unit. |
| + AccessUnitQueue::Info info = au_queue.GetInfo(); |
| + VERIFY_FIRST_BYTE('4', info); |
| +} |
| + |
| +TEST_F(AccessUnitQueueTest, HasEOS) { |
| + // Two chunks |
| + AUDescriptor chunk[][4] = {{ |
| + {kNone, "0"}, |
| + {kNone, "1"}, |
| + {kNone, "2"}, |
| + {kNone, "3"} |
| + }, { |
| + {kNone, "4"}, |
| + {kNone, "5"}, |
| + {kNone, "6"}, |
| + {kEOS, "7"} |
| + } |
| + }; |
| + |
| + AccessUnitQueue au_queue; |
| + au_queue.PushBack(CreateDemuxerData(chunk[0], ARRAY_SIZE(chunk[0]))); |
| + au_queue.PushBack(CreateDemuxerData(chunk[1], ARRAY_SIZE(chunk[1]))); |
| + |
| + // Verify that after EOS has been pushed into the queue, |
| + // it is reported for every GetInfo() |
| + for (int i = 0; i < 8; ++i) { |
| + AccessUnitQueue::Info info = au_queue.GetInfo(); |
| + |
| + EXPECT_TRUE(info.has_eos); |
| + EXPECT_EQ(nullptr, info.configs); |
| + |
| + VERIFY_FIRST_BYTE('0' + i, info); |
| + |
| + au_queue.Advance(); |
| + } |
| +} |
| + |
| +TEST_F(AccessUnitQueueTest, HasConfigs) { |
| + AUDescriptor chunk[] = { |
| + {kNone, "0"}, |
| + {kNone, "1"}, |
| + {kNone, "2"}, |
| + {kConfig, "3"} |
| + }; |
| + |
| + AccessUnitQueue au_queue; |
| + au_queue.PushBack(CreateDemuxerData(chunk, ARRAY_SIZE(chunk))); |
| + |
| + for (int i = 0; i < 4; ++i) { |
| + AccessUnitQueue::Info info = au_queue.GetInfo(); |
| + |
| + if (i != 3) |
| + EXPECT_EQ(nullptr, info.configs); |
| + else |
| + EXPECT_NE(nullptr, info.configs); |
| + |
| + au_queue.Advance(); |
| + } |
| +} |
| + |
| +TEST_F(AccessUnitQueueTest, ConfigsAndKeyFrame) { |
| + // Two chunks |
| + AUDescriptor chunk[][4] = {{ |
| + {kNone, "0"}, |
| + {kKeyFrame, "1"}, |
| + {kNone, "2"}, |
| + {kConfig, "3"} |
| + }, { |
| + {kKeyFrame, "4"}, |
| + {kNone, "5"}, |
| + {kNone, "6"}, |
| + {kNone, "7"} |
| + } |
| + }; |
| + |
| + AccessUnitQueue::Info info; |
| + |
| + AccessUnitQueue au_queue; |
| + au_queue.PushBack(CreateDemuxerData(chunk[0], ARRAY_SIZE(chunk[0]))); |
| + au_queue.PushBack(CreateDemuxerData(chunk[1], ARRAY_SIZE(chunk[1]))); |
| + |
| + // There is no prior key frame |
| + EXPECT_FALSE(au_queue.SkipToKeyFrame()); |
| + |
| + // Consume first access unit. |
| + au_queue.Advance(); |
| + |
| + // Now the current one is the key frame. It would be safe to configure codec |
| + // at this moment, so SkipToKeyFrame() should return true. |
| + EXPECT_TRUE(au_queue.SkipToKeyFrame()); |
| + |
| + info = au_queue.GetInfo(); |
| + VERIFY_FIRST_BYTE('1', info); |
| + |
| + au_queue.Advance(); // now current unit is "2" |
| + |
| + info = au_queue.GetInfo(); |
| + VERIFY_FIRST_BYTE('2', info); |
| + |
| + EXPECT_TRUE(au_queue.SkipToKeyFrame()); // should go back to "1" |
| + |
| + info = au_queue.GetInfo(); |
| + VERIFY_FIRST_BYTE('1', info); |
| + |
| + au_queue.Advance(); // now current unit is "2" |
| + au_queue.Advance(); // now current unit is "3" |
| + |
| + // Verify that we are at "3". |
| + info = au_queue.GetInfo(); |
| + EXPECT_NE(nullptr, info.configs); |
| + |
| + // Although it would be safe to configure codec (with old config) in this |
| + // position since it will be immediately reconfigured from the next unit "3", |
| + // current implementation returns unit "1". |
| + |
| + EXPECT_TRUE(au_queue.SkipToKeyFrame()); // should go back to "1" |
| + |
| + info = au_queue.GetInfo(); |
| + VERIFY_FIRST_BYTE('1', info); |
| + |
| + au_queue.Advance(); // now current unit is "2" |
| + au_queue.Advance(); // now current unit is "3" |
| + au_queue.Advance(); // now current unit is "4" |
| + |
| + info = au_queue.GetInfo(); |
| + VERIFY_FIRST_BYTE('4', info); |
| + |
| + EXPECT_TRUE(au_queue.SkipToKeyFrame()); // should stay at "4" |
| + |
| + info = au_queue.GetInfo(); |
| + VERIFY_FIRST_BYTE('4', info); |
| + |
| + au_queue.Advance(); // now current unit is "5" |
| + au_queue.Advance(); // now current unit is "6" |
| + |
| + info = au_queue.GetInfo(); |
| + VERIFY_FIRST_BYTE('6', info); |
| + |
| + EXPECT_TRUE(au_queue.SkipToKeyFrame()); // should go back to "4" |
| + |
| + info = au_queue.GetInfo(); |
| + VERIFY_FIRST_BYTE('4', info); |
| +} |
| + |
| +} // namespace media |