Chromium Code Reviews| 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) (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.
| |
| 9 | |
| 10 namespace media { | |
| 11 | |
| 12 class AccessUnitQueueTest : public testing::Test { | |
| 13 public: | |
| 14 AccessUnitQueueTest() {} | |
| 15 ~AccessUnitQueueTest() override {} | |
| 16 | |
| 17 protected: | |
| 18 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
| |
| 19 struct AUDescriptor { | |
| 20 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.
| |
| 21 std::string data; | |
| 22 }; | |
| 23 | |
| 24 DemuxerData CreateDemuxerData(const AUDescriptor* descr, int descr_length); | |
| 25 }; | |
| 26 | |
| 27 DemuxerData AccessUnitQueueTest::CreateDemuxerData( | |
| 28 const AUDescriptor* descr, int descr_length) { | |
| 29 DemuxerData result; | |
| 30 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.
| |
| 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 au.status = (descr[i].flags & kConfig) ? | |
| 36 DemuxerStream::kConfigChanged : DemuxerStream::kOk; | |
| 37 if (au.status == DemuxerStream::kConfigChanged) { | |
| 38 result.demuxer_configs.push_back(DemuxerConfigs()); | |
| 39 continue; | |
| 40 } | |
| 41 | |
| 42 au.data = std::vector<uint8>(descr[i].data.begin(), descr[i].data.end()); | |
| 43 au.is_key_frame = (descr[i].flags & kKeyFrame); | |
| 44 au.is_end_of_stream = (descr[i].flags & kEOS); | |
| 45 } | |
| 46 return result; | |
| 47 } | |
| 48 | |
| 49 #define VERIFY_FIRST_BYTE(expected, info) \ | |
| 50 do { \ | |
| 51 EXPECT_NE(nullptr, info.front_unit); \ | |
| 52 EXPECT_TRUE(info.front_unit->data.size() > 0); \ | |
| 53 EXPECT_EQ(expected, info.front_unit->data[0]); \ | |
| 54 } \ | |
| 55 while (0) | |
|
wolenetz
2015/06/08 21:37:09
nit: put while on previous line
Tima Vaisburd
2015/06/09 21:29:21
Done.
| |
| 56 | |
| 57 TEST_F(AccessUnitQueueTest, InitializedEmpty) { | |
| 58 AccessUnitQueue au_queue; | |
| 59 AccessUnitQueue::Info info = au_queue.GetInfo(); | |
| 60 | |
| 61 EXPECT_EQ(0, info.length); | |
| 62 EXPECT_FALSE(info.has_eos); | |
| 63 EXPECT_EQ(nullptr, info.front_unit); | |
| 64 EXPECT_EQ(nullptr, info.configs); | |
| 65 } | |
| 66 | |
| 67 TEST_F(AccessUnitQueueTest, SkipToKeyFrameEmptyQueue) { | |
| 68 AccessUnitQueue au_queue; | |
| 69 EXPECT_FALSE(au_queue.SkipToKeyFrame()); | |
| 70 } | |
| 71 | |
| 72 TEST_F(AccessUnitQueueTest, PushAndAdvance) { | |
| 73 AUDescriptor chunk1[] = { | |
| 74 {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.
| |
| 75 {kNone, "1"}, | |
| 76 {kNone, "2"}, | |
| 77 {kNone, "3"}, | |
| 78 {kNone, "4"}, | |
| 79 {kNone, "5"} | |
| 80 }; | |
| 81 AUDescriptor chunk2[] = { | |
| 82 {kNone, "6"}, | |
| 83 {kNone, "7"}, | |
| 84 {kNone, "8"} | |
| 85 }; | |
| 86 | |
| 87 int total_size = ARRAY_SIZE(chunk1) + ARRAY_SIZE(chunk2); | |
| 88 | |
| 89 AccessUnitQueue au_queue; | |
| 90 au_queue.PushBack(CreateDemuxerData(chunk1, ARRAY_SIZE(chunk1))); | |
| 91 au_queue.PushBack(CreateDemuxerData(chunk2, ARRAY_SIZE(chunk2))); | |
| 92 | |
| 93 AccessUnitQueue::Info info; | |
| 94 for (int i = 0; i < total_size; ++i) { | |
| 95 info = au_queue.GetInfo(); | |
| 96 | |
| 97 EXPECT_FALSE(info.has_eos); | |
| 98 EXPECT_EQ(total_size - i, info.length); | |
| 99 EXPECT_EQ(nullptr, info.configs); | |
| 100 | |
| 101 EXPECT_NE(nullptr, info.front_unit); | |
| 102 EXPECT_TRUE(info.front_unit->data.size() > 0); | |
| 103 EXPECT_EQ('0' + i, info.front_unit->data[0]); | |
| 104 | |
| 105 au_queue.Advance(); | |
| 106 } | |
| 107 | |
| 108 // After we advanced past the last AU, GetInfo() should report starvation. | |
| 109 info = au_queue.GetInfo(); | |
| 110 | |
| 111 EXPECT_EQ(0, info.length); | |
| 112 EXPECT_FALSE(info.has_eos); | |
| 113 EXPECT_EQ(nullptr, info.front_unit); | |
| 114 EXPECT_EQ(nullptr, info.configs); | |
| 115 } | |
| 116 | |
| 117 TEST_F(AccessUnitQueueTest, ChunksDoNotLeak) { | |
| 118 AUDescriptor chunk[] = { | |
| 119 {kNone, "0"}, | |
| 120 {kNone, "1"}, | |
| 121 {kNone, "2"}, | |
| 122 {kNone, "3"} | |
| 123 }; | |
| 124 | |
| 125 AccessUnitQueue au_queue; | |
| 126 au_queue.PushBack(CreateDemuxerData(chunk, ARRAY_SIZE(chunk))); | |
| 127 | |
| 128 // Verify that the old chunks get deleted (we rely on NumChunksForTesting()) | |
| 129 for (int i = 0; i < 100; ++i) { | |
| 130 au_queue.PushBack(CreateDemuxerData(chunk, ARRAY_SIZE(chunk))); | |
| 131 for (int j = 0; j < ARRAY_SIZE(chunk); ++j) | |
| 132 au_queue.Advance(); | |
| 133 | |
| 134 // 5 is an arbitrary number, it implies that we keep 4 chunks of history. | |
| 135 EXPECT_GT(5U, au_queue.NumChunksForTesting()); | |
| 136 } | |
| 137 } | |
| 138 | |
| 139 TEST_F(AccessUnitQueueTest, PushAfterStarvation) { | |
| 140 // Two chunks | |
| 141 AUDescriptor chunk[][4] = {{ | |
| 142 {kNone, "0"}, | |
| 143 {kNone, "1"}, | |
| 144 {kNone, "2"}, | |
| 145 {kNone, "3"} | |
| 146 }, { | |
| 147 {kNone, "4"}, | |
| 148 {kNone, "5"}, | |
| 149 {kNone, "6"}, | |
| 150 {kNone, "7"} | |
| 151 } | |
| 152 }; | |
| 153 | |
| 154 AccessUnitQueue au_queue; | |
| 155 | |
| 156 // Push the first chunk. | |
| 157 au_queue.PushBack(CreateDemuxerData(chunk[0], ARRAY_SIZE(chunk[0]))); | |
| 158 | |
| 159 // Advance past the end of queue. | |
| 160 for (int i = 0; i < ARRAY_SIZE(chunk[0]); ++i) | |
| 161 au_queue.Advance(); | |
| 162 | |
| 163 // An extra Advance() should not change anything. | |
| 164 au_queue.Advance(); | |
| 165 | |
| 166 // Push the second chunk | |
| 167 au_queue.PushBack(CreateDemuxerData(chunk[1], ARRAY_SIZE(chunk[1]))); | |
| 168 | |
| 169 // Verify that we get the next access unit. | |
| 170 AccessUnitQueue::Info info = au_queue.GetInfo(); | |
| 171 VERIFY_FIRST_BYTE('4', info); | |
| 172 } | |
| 173 | |
| 174 TEST_F(AccessUnitQueueTest, HasEOS) { | |
| 175 // Two chunks | |
| 176 AUDescriptor chunk[][4] = {{ | |
| 177 {kNone, "0"}, | |
| 178 {kNone, "1"}, | |
| 179 {kNone, "2"}, | |
| 180 {kNone, "3"} | |
| 181 }, { | |
| 182 {kNone, "4"}, | |
| 183 {kNone, "5"}, | |
| 184 {kNone, "6"}, | |
| 185 {kEOS, "7"} | |
| 186 } | |
| 187 }; | |
| 188 | |
| 189 AccessUnitQueue au_queue; | |
| 190 au_queue.PushBack(CreateDemuxerData(chunk[0], ARRAY_SIZE(chunk[0]))); | |
| 191 au_queue.PushBack(CreateDemuxerData(chunk[1], ARRAY_SIZE(chunk[1]))); | |
| 192 | |
| 193 // Verify that after EOS has been pushed into the queue, | |
| 194 // it is reported for every GetInfo() | |
| 195 for (int i = 0; i < 8; ++i) { | |
| 196 AccessUnitQueue::Info info = au_queue.GetInfo(); | |
| 197 | |
| 198 EXPECT_TRUE(info.has_eos); | |
| 199 EXPECT_EQ(nullptr, info.configs); | |
| 200 | |
| 201 VERIFY_FIRST_BYTE('0' + i, info); | |
| 202 | |
| 203 au_queue.Advance(); | |
| 204 } | |
| 205 } | |
| 206 | |
| 207 TEST_F(AccessUnitQueueTest, HasConfigs) { | |
| 208 AUDescriptor chunk[] = { | |
| 209 {kNone, "0"}, | |
| 210 {kNone, "1"}, | |
| 211 {kNone, "2"}, | |
| 212 {kConfig, "3"} | |
| 213 }; | |
| 214 | |
| 215 AccessUnitQueue au_queue; | |
| 216 au_queue.PushBack(CreateDemuxerData(chunk, ARRAY_SIZE(chunk))); | |
| 217 | |
| 218 for (int i = 0; i < 4; ++i) { | |
| 219 AccessUnitQueue::Info info = au_queue.GetInfo(); | |
| 220 | |
| 221 if (i != 3) | |
| 222 EXPECT_EQ(nullptr, info.configs); | |
| 223 else | |
| 224 EXPECT_NE(nullptr, info.configs); | |
| 225 | |
| 226 au_queue.Advance(); | |
| 227 } | |
| 228 } | |
| 229 | |
| 230 TEST_F(AccessUnitQueueTest, ConfigsAndKeyFrame) { | |
| 231 // Two chunks | |
| 232 AUDescriptor chunk[][4] = {{ | |
| 233 {kNone, "0"}, | |
| 234 {kKeyFrame, "1"}, | |
| 235 {kNone, "2"}, | |
| 236 {kConfig, "3"} | |
| 237 }, { | |
| 238 {kKeyFrame, "4"}, | |
| 239 {kNone, "5"}, | |
| 240 {kNone, "6"}, | |
| 241 {kNone, "7"} | |
| 242 } | |
| 243 }; | |
| 244 | |
| 245 AccessUnitQueue::Info info; | |
| 246 | |
| 247 AccessUnitQueue au_queue; | |
| 248 au_queue.PushBack(CreateDemuxerData(chunk[0], ARRAY_SIZE(chunk[0]))); | |
| 249 au_queue.PushBack(CreateDemuxerData(chunk[1], ARRAY_SIZE(chunk[1]))); | |
| 250 | |
| 251 // There is no prior key frame | |
| 252 EXPECT_FALSE(au_queue.SkipToKeyFrame()); | |
| 253 | |
| 254 // Consume first access unit. | |
| 255 au_queue.Advance(); | |
| 256 | |
| 257 // Now the current one is the key frame. It would be safe to configure codec | |
| 258 // at this moment, so SkipToKeyFrame() should return true. | |
| 259 EXPECT_TRUE(au_queue.SkipToKeyFrame()); | |
| 260 | |
| 261 info = au_queue.GetInfo(); | |
| 262 VERIFY_FIRST_BYTE('1', info); | |
| 263 | |
| 264 au_queue.Advance(); // now current unit is "2" | |
| 265 | |
| 266 info = au_queue.GetInfo(); | |
| 267 VERIFY_FIRST_BYTE('2', info); | |
| 268 | |
| 269 EXPECT_TRUE(au_queue.SkipToKeyFrame()); // should go back to "1" | |
| 270 | |
| 271 info = au_queue.GetInfo(); | |
| 272 VERIFY_FIRST_BYTE('1', info); | |
| 273 | |
| 274 au_queue.Advance(); // now current unit is "2" | |
| 275 au_queue.Advance(); // now current unit is "3" | |
| 276 | |
| 277 // Verify that we are at "3". | |
| 278 info = au_queue.GetInfo(); | |
| 279 EXPECT_NE(nullptr, info.configs); | |
| 280 | |
| 281 // Although it would be safe to configure codec (with old config) in this | |
| 282 // position since it will be immediately reconfigured from the next unit "3", | |
| 283 // current implementation returns unit "1". | |
| 284 | |
| 285 EXPECT_TRUE(au_queue.SkipToKeyFrame()); // should go back to "1" | |
| 286 | |
| 287 info = au_queue.GetInfo(); | |
| 288 VERIFY_FIRST_BYTE('1', info); | |
| 289 | |
| 290 au_queue.Advance(); // now current unit is "2" | |
| 291 au_queue.Advance(); // now current unit is "3" | |
| 292 au_queue.Advance(); // now current unit is "4" | |
| 293 | |
| 294 info = au_queue.GetInfo(); | |
| 295 VERIFY_FIRST_BYTE('4', info); | |
| 296 | |
| 297 EXPECT_TRUE(au_queue.SkipToKeyFrame()); // should stay at "4" | |
| 298 | |
| 299 info = au_queue.GetInfo(); | |
| 300 VERIFY_FIRST_BYTE('4', info); | |
| 301 | |
| 302 au_queue.Advance(); // now current unit is "5" | |
| 303 au_queue.Advance(); // now current unit is "6" | |
| 304 | |
| 305 info = au_queue.GetInfo(); | |
| 306 VERIFY_FIRST_BYTE('6', info); | |
| 307 | |
| 308 EXPECT_TRUE(au_queue.SkipToKeyFrame()); // should go back to "4" | |
| 309 | |
| 310 info = au_queue.GetInfo(); | |
| 311 VERIFY_FIRST_BYTE('4', info); | |
| 312 } | |
| 313 | |
| 314 } // namespace media | |
| OLD | NEW |