| 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 "base/bind.h" |
| 6 #include "base/logging.h" |
| 7 #include "base/strings/stringprintf.h" |
| 8 #include "base/thread_task_runner_handle.h" |
| 9 #include "base/timer/timer.h" |
| 10 #include "media/base/android/media_codec_audio_decoder.h" |
| 11 #include "media/base/android/media_codec_bridge.h" |
| 12 #include "media/base/android/media_codec_video_decoder.h" |
| 13 #include "media/base/decoder_buffer.h" |
| 14 #include "media/base/test_data_util.h" |
| 15 #include "testing/gtest/include/gtest/gtest.h" |
| 16 #include "ui/gl/android/surface_texture.h" |
| 17 |
| 18 namespace media { |
| 19 |
| 20 // Helper macro to skip the test if MediaCodecBridge isn't available. |
| 21 #define SKIP_TEST_IF_MEDIA_CODEC_BRIDGE_IS_NOT_AVAILABLE() \ |
| 22 do { \ |
| 23 if (!MediaCodecBridge::IsAvailable()) { \ |
| 24 VLOG(0) << "Could not run test - not supported on device."; \ |
| 25 return; \ |
| 26 } \ |
| 27 } while (0) |
| 28 |
| 29 namespace { |
| 30 |
| 31 const base::TimeDelta kDefaultTimeout = base::TimeDelta::FromMilliseconds(200); |
| 32 const base::TimeDelta kAudioFramePeriod = base::TimeDelta::FromMilliseconds(20); |
| 33 const base::TimeDelta kVideoFramePeriod = base::TimeDelta::FromMilliseconds(20); |
| 34 |
| 35 DemuxerConfigs CreateAudioConfigs(AudioCodec audio_codec, |
| 36 const base::TimeDelta& duration) { |
| 37 DemuxerConfigs configs; |
| 38 configs.audio_codec = audio_codec; |
| 39 configs.audio_channels = 2; |
| 40 configs.is_audio_encrypted = false; |
| 41 configs.duration = duration; |
| 42 |
| 43 // Other codecs are not yet supported by this helper. |
| 44 EXPECT_TRUE(audio_codec == kCodecAAC || audio_codec == kCodecVorbis); |
| 45 |
| 46 switch (audio_codec) { |
| 47 case kCodecVorbis: { |
| 48 configs.audio_sampling_rate = 44100; |
| 49 scoped_refptr<DecoderBuffer> buffer = |
| 50 ReadTestDataFile("vorbis-extradata"); |
| 51 configs.audio_extra_data = std::vector<uint8>( |
| 52 buffer->data(), buffer->data() + buffer->data_size()); |
| 53 } break; |
| 54 |
| 55 case kCodecAAC: { |
| 56 configs.audio_sampling_rate = 48000; |
| 57 uint8 aac_extra_data[] = {0x13, 0x10}; |
| 58 configs.audio_extra_data = |
| 59 std::vector<uint8>(aac_extra_data, aac_extra_data + 2); |
| 60 } break; |
| 61 |
| 62 default: |
| 63 NOTREACHED(); |
| 64 break; |
| 65 } |
| 66 |
| 67 return configs; |
| 68 } |
| 69 |
| 70 DemuxerConfigs CreateVideoConfigs(const base::TimeDelta& duration) { |
| 71 DemuxerConfigs configs; |
| 72 configs.video_codec = kCodecH264; |
| 73 configs.video_size = gfx::Size(320, 240); |
| 74 configs.is_video_encrypted = false; |
| 75 configs.duration = duration; |
| 76 return configs; |
| 77 } |
| 78 |
| 79 } // namespace (anonymous) |
| 80 |
| 81 // DataFactory defines how the data will be generated. |
| 82 |
| 83 class DataFactory { |
| 84 public: |
| 85 DataFactory(const char* file_name_format, |
| 86 const base::TimeDelta& duration, |
| 87 const base::TimeDelta& frame_period); |
| 88 virtual ~DataFactory() {} |
| 89 |
| 90 void CreateChunk(DemuxerData* chunk, base::TimeDelta* delay); |
| 91 |
| 92 base::TimeDelta last_pts() const { return last_pts_; } |
| 93 |
| 94 protected: |
| 95 virtual void FillAccessUnit(int index_in_chunk, AccessUnit* unit) = 0; |
| 96 |
| 97 base::TimeDelta duration_; |
| 98 base::TimeDelta frame_period_; |
| 99 std::vector<uint8> packet_[4]; |
| 100 base::TimeDelta regular_pts_; |
| 101 base::TimeDelta last_pts_; |
| 102 }; |
| 103 |
| 104 class AudioFactory : public DataFactory { |
| 105 public: |
| 106 AudioFactory(const base::TimeDelta& duration); |
| 107 |
| 108 protected: |
| 109 void FillAccessUnit(int index_in_chunk, AccessUnit* unit) override; |
| 110 }; |
| 111 |
| 112 class VideoFactory : public DataFactory { |
| 113 public: |
| 114 VideoFactory(const base::TimeDelta& duration); |
| 115 |
| 116 protected: |
| 117 void FillAccessUnit(int index_in_chunk, AccessUnit* unit) override; |
| 118 }; |
| 119 |
| 120 DataFactory::DataFactory(const char* file_name_format, |
| 121 const base::TimeDelta& duration, |
| 122 const base::TimeDelta& frame_period) |
| 123 : duration_(duration), frame_period_(frame_period) { |
| 124 // Load packets |
| 125 for (int i = 0; i < 4; ++i) { |
| 126 scoped_refptr<DecoderBuffer> buffer = |
| 127 ReadTestDataFile(base::StringPrintf(file_name_format, i)); |
| 128 packet_[i] = std::vector<uint8>(buffer->data(), |
| 129 buffer->data() + buffer->data_size()); |
| 130 } |
| 131 } |
| 132 |
| 133 void DataFactory::CreateChunk(DemuxerData* chunk, base::TimeDelta* delay) { |
| 134 DCHECK(chunk); |
| 135 DCHECK(delay); |
| 136 |
| 137 *delay = base::TimeDelta(); |
| 138 |
| 139 for (int i = 0; i < 4; ++i) { |
| 140 chunk->access_units.push_back(AccessUnit()); |
| 141 AccessUnit& unit = chunk->access_units.back(); |
| 142 unit.status = DemuxerStream::kOk; |
| 143 |
| 144 unit.timestamp = regular_pts_; |
| 145 regular_pts_ += frame_period_; |
| 146 |
| 147 if (unit.timestamp > duration_) { |
| 148 unit.is_end_of_stream = true; |
| 149 break; // EOS units have no data |
| 150 } |
| 151 |
| 152 FillAccessUnit(i, &unit); |
| 153 |
| 154 // Maintain last PTS. FillAccessUnit can modify unit's PTS. |
| 155 if (last_pts_ < unit.timestamp) |
| 156 last_pts_ = unit.timestamp; |
| 157 } |
| 158 } |
| 159 |
| 160 AudioFactory::AudioFactory(const base::TimeDelta& duration) |
| 161 : DataFactory("vorbis-packet-%d", duration, kAudioFramePeriod) { |
| 162 } |
| 163 |
| 164 void AudioFactory::FillAccessUnit(int index_in_chunk, AccessUnit* unit) { |
| 165 unit->data = packet_[index_in_chunk]; |
| 166 |
| 167 // Vorbis needs 4 extra bytes padding on Android to decode properly. Check |
| 168 // NuMediaExtractor.cpp in Android source code. |
| 169 uint8 padding[4] = {0xff, 0xff, 0xff, 0xff}; |
| 170 unit->data.insert(unit->data.end(), padding, padding + 4); |
| 171 } |
| 172 |
| 173 VideoFactory::VideoFactory(const base::TimeDelta& duration) |
| 174 : DataFactory("h264-320x180-frame-%d", duration, kVideoFramePeriod) { |
| 175 } |
| 176 |
| 177 void VideoFactory::FillAccessUnit(int index_in_chunk, AccessUnit* unit) { |
| 178 unit->data = packet_[index_in_chunk]; |
| 179 |
| 180 // The frames are taken from High profile and some are B-frames. |
| 181 // The first 4 frames appear in the file in the following order: |
| 182 // |
| 183 // Frames: I P B P |
| 184 // Decoding order: 0 1 2 3 |
| 185 // Presentation order: 0 2 1 4(3) |
| 186 // |
| 187 // I keep the last PTS to be 3 for simplicity. |
| 188 |
| 189 // Swap pts for second and third frames. |
| 190 if (index_in_chunk == 1) // second frame |
| 191 unit->timestamp += frame_period_; |
| 192 if (index_in_chunk == 2) // third frame |
| 193 unit->timestamp -= frame_period_; |
| 194 |
| 195 if (index_in_chunk == 0) |
| 196 unit->is_key_frame = true; |
| 197 } |
| 198 |
| 199 // Class that computes statistics: number of calls, minimum and maximum values. |
| 200 // It is used for PTS statistics to verify that playback did actually happen. |
| 201 |
| 202 template <typename T> |
| 203 class Minimax { |
| 204 public: |
| 205 Minimax() : num_values_(0) {} |
| 206 ~Minimax() {} |
| 207 |
| 208 void AddValue(const T& value) { |
| 209 ++num_values_; |
| 210 if (value < min_) |
| 211 min_ = value; |
| 212 else if (max_ < value) |
| 213 max_ = value; |
| 214 } |
| 215 |
| 216 const T& min() const { return min_; } |
| 217 const T& max() const { return max_; } |
| 218 int num_values() const { return num_values_; } |
| 219 |
| 220 private: |
| 221 T min_; |
| 222 T max_; |
| 223 int num_values_; |
| 224 }; |
| 225 |
| 226 // The test fixture for MediaCodecDecoder |
| 227 |
| 228 class MediaCodecDecoderTest : public testing::Test { |
| 229 public: |
| 230 MediaCodecDecoderTest(); |
| 231 ~MediaCodecDecoderTest() override; |
| 232 |
| 233 // Conditions we wait for. |
| 234 bool is_prefetched() const { return is_prefetched_; } |
| 235 bool is_stopped() const { return is_stopped_; } |
| 236 bool is_starved() const { return is_starved_; } |
| 237 |
| 238 // Prefetch callback has to be public. |
| 239 void SetPrefetched() { is_prefetched_ = true; } |
| 240 |
| 241 protected: |
| 242 typedef base::Callback<bool()> Predicate; |
| 243 |
| 244 typedef base::Callback<void(const DemuxerData&)> DataAvailableCallback; |
| 245 |
| 246 // Waits for condition to become true or for timeout to expire. |
| 247 // Returns true if the condition becomes true. |
| 248 bool WaitForCondition(const Predicate& condition, |
| 249 const base::TimeDelta& timeout = kDefaultTimeout); |
| 250 |
| 251 void SetDataFactory(scoped_ptr<DataFactory> factory) { |
| 252 data_factory_ = factory.Pass(); |
| 253 } |
| 254 |
| 255 void CreateAudioDecoder(); |
| 256 void CreateVideoDecoder(); |
| 257 void SetVideoSurface(); |
| 258 |
| 259 // Decoder callbacks. |
| 260 void OnDataRequested(); |
| 261 void OnStarvation() { is_starved_ = true; } |
| 262 void OnStopDone() { is_stopped_ = true; } |
| 263 void OnError() {} |
| 264 void OnUpdateCurrentTime(base::TimeDelta now_playing, |
| 265 base::TimeDelta last_buffered) { |
| 266 pts_stat_.AddValue(now_playing); |
| 267 } |
| 268 void OnVideoSizeChanged(const gfx::Size& video_size) {} |
| 269 void OnVideoCodecCreated() {} |
| 270 |
| 271 scoped_ptr<MediaCodecDecoder> decoder_; |
| 272 scoped_ptr<DataFactory> data_factory_; |
| 273 Minimax<base::TimeDelta> pts_stat_; |
| 274 |
| 275 private: |
| 276 bool is_timeout_expired() const { return is_timeout_expired_; } |
| 277 void SetTimeoutExpired(bool value) { is_timeout_expired_ = value; } |
| 278 |
| 279 base::MessageLoop message_loop_; |
| 280 bool is_timeout_expired_; |
| 281 |
| 282 bool is_prefetched_; |
| 283 bool is_stopped_; |
| 284 bool is_starved_; |
| 285 |
| 286 scoped_refptr<base::SingleThreadTaskRunner> task_runner_; |
| 287 DataAvailableCallback data_available_cb_; |
| 288 scoped_refptr<gfx::SurfaceTexture> surface_texture_; |
| 289 |
| 290 DISALLOW_COPY_AND_ASSIGN(MediaCodecDecoderTest); |
| 291 }; |
| 292 |
| 293 MediaCodecDecoderTest::MediaCodecDecoderTest() |
| 294 : is_timeout_expired_(false), |
| 295 is_prefetched_(false), |
| 296 is_stopped_(false), |
| 297 is_starved_(false), |
| 298 task_runner_(base::ThreadTaskRunnerHandle::Get()) { |
| 299 } |
| 300 |
| 301 MediaCodecDecoderTest::~MediaCodecDecoderTest() { |
| 302 } |
| 303 |
| 304 bool MediaCodecDecoderTest::WaitForCondition(const Predicate& condition, |
| 305 const base::TimeDelta& timeout) { |
| 306 // Let the message_loop_ process events. |
| 307 // We start the timer and RunUntilIdle() until it signals. |
| 308 |
| 309 SetTimeoutExpired(false); |
| 310 |
| 311 base::Timer timer(false, false); |
| 312 timer.Start(FROM_HERE, timeout, |
| 313 base::Bind(&MediaCodecDecoderTest::SetTimeoutExpired, |
| 314 base::Unretained(this), true)); |
| 315 |
| 316 do { |
| 317 if (condition.Run()) { |
| 318 timer.Stop(); |
| 319 return true; |
| 320 } |
| 321 message_loop_.RunUntilIdle(); |
| 322 } while (!is_timeout_expired()); |
| 323 |
| 324 DCHECK(!timer.IsRunning()); |
| 325 return false; |
| 326 } |
| 327 |
| 328 void MediaCodecDecoderTest::CreateAudioDecoder() { |
| 329 decoder_ = scoped_ptr<MediaCodecDecoder>(new MediaCodecAudioDecoder( |
| 330 task_runner_, base::Bind(&MediaCodecDecoderTest::OnDataRequested, |
| 331 base::Unretained(this)), |
| 332 base::Bind(&MediaCodecDecoderTest::OnStarvation, base::Unretained(this)), |
| 333 base::Bind(&MediaCodecDecoderTest::OnStopDone, base::Unretained(this)), |
| 334 base::Bind(&MediaCodecDecoderTest::OnError, base::Unretained(this)), |
| 335 base::Bind(&MediaCodecDecoderTest::OnUpdateCurrentTime, |
| 336 base::Unretained(this)))); |
| 337 |
| 338 data_available_cb_ = base::Bind(&MediaCodecDecoder::OnDemuxerDataAvailable, |
| 339 base::Unretained(decoder_.get())); |
| 340 } |
| 341 |
| 342 void MediaCodecDecoderTest::CreateVideoDecoder() { |
| 343 decoder_ = scoped_ptr<MediaCodecDecoder>(new MediaCodecVideoDecoder( |
| 344 task_runner_, base::Bind(&MediaCodecDecoderTest::OnDataRequested, |
| 345 base::Unretained(this)), |
| 346 base::Bind(&MediaCodecDecoderTest::OnStarvation, base::Unretained(this)), |
| 347 base::Bind(&MediaCodecDecoderTest::OnStopDone, base::Unretained(this)), |
| 348 base::Bind(&MediaCodecDecoderTest::OnError, base::Unretained(this)), |
| 349 base::Bind(&MediaCodecDecoderTest::OnUpdateCurrentTime, |
| 350 base::Unretained(this)), |
| 351 base::Bind(&MediaCodecDecoderTest::OnVideoSizeChanged, |
| 352 base::Unretained(this)), |
| 353 base::Bind(&MediaCodecDecoderTest::OnVideoCodecCreated, |
| 354 base::Unretained(this)))); |
| 355 |
| 356 data_available_cb_ = base::Bind(&MediaCodecDecoder::OnDemuxerDataAvailable, |
| 357 base::Unretained(decoder_.get())); |
| 358 } |
| 359 |
| 360 void MediaCodecDecoderTest::OnDataRequested() { |
| 361 if (!data_factory_) |
| 362 return; |
| 363 |
| 364 DemuxerData data; |
| 365 base::TimeDelta delay; |
| 366 data_factory_->CreateChunk(&data, &delay); |
| 367 |
| 368 task_runner_->PostDelayedTask(FROM_HERE, base::Bind(data_available_cb_, data), |
| 369 delay); |
| 370 } |
| 371 |
| 372 void MediaCodecDecoderTest::SetVideoSurface() { |
| 373 surface_texture_ = gfx::SurfaceTexture::Create(0); |
| 374 gfx::ScopedJavaSurface surface(surface_texture_.get()); |
| 375 ASSERT_NE(nullptr, decoder_.get()); |
| 376 MediaCodecVideoDecoder* video_decoder = |
| 377 static_cast<MediaCodecVideoDecoder*>(decoder_.get()); |
| 378 video_decoder->SetPendingSurface(surface.Pass()); |
| 379 } |
| 380 |
| 381 TEST_F(MediaCodecDecoderTest, AudioPrefetch) { |
| 382 CreateAudioDecoder(); |
| 383 |
| 384 base::TimeDelta duration = base::TimeDelta::FromMilliseconds(500); |
| 385 SetDataFactory(scoped_ptr<DataFactory>(new AudioFactory(duration))); |
| 386 |
| 387 decoder_->Prefetch(base::Bind(&MediaCodecDecoderTest::SetPrefetched, |
| 388 base::Unretained(this))); |
| 389 |
| 390 EXPECT_TRUE(WaitForCondition(base::Bind(&MediaCodecDecoderTest::is_prefetched, |
| 391 base::Unretained(this)))); |
| 392 } |
| 393 |
| 394 TEST_F(MediaCodecDecoderTest, VideoPrefetch) { |
| 395 CreateVideoDecoder(); |
| 396 |
| 397 base::TimeDelta duration = base::TimeDelta::FromMilliseconds(500); |
| 398 SetDataFactory(scoped_ptr<DataFactory>(new VideoFactory(duration))); |
| 399 |
| 400 decoder_->Prefetch(base::Bind(&MediaCodecDecoderTest::SetPrefetched, |
| 401 base::Unretained(this))); |
| 402 |
| 403 EXPECT_TRUE(WaitForCondition(base::Bind(&MediaCodecDecoderTest::is_prefetched, |
| 404 base::Unretained(this)))); |
| 405 } |
| 406 |
| 407 TEST_F(MediaCodecDecoderTest, AudioConfigureNoParams) { |
| 408 SKIP_TEST_IF_MEDIA_CODEC_BRIDGE_IS_NOT_AVAILABLE(); |
| 409 |
| 410 CreateAudioDecoder(); |
| 411 |
| 412 // Cannot configure without config parameters. |
| 413 EXPECT_EQ(MediaCodecDecoder::CONFIG_FAILURE, decoder_->Configure()); |
| 414 } |
| 415 |
| 416 TEST_F(MediaCodecDecoderTest, AudioConfigureValidParams) { |
| 417 SKIP_TEST_IF_MEDIA_CODEC_BRIDGE_IS_NOT_AVAILABLE(); |
| 418 |
| 419 CreateAudioDecoder(); |
| 420 |
| 421 base::TimeDelta duration = base::TimeDelta::FromMilliseconds(500); |
| 422 decoder_->SetDemuxerConfigs(CreateAudioConfigs(kCodecVorbis, duration)); |
| 423 |
| 424 EXPECT_EQ(MediaCodecDecoder::CONFIG_OK, decoder_->Configure()); |
| 425 } |
| 426 |
| 427 TEST_F(MediaCodecDecoderTest, VideoConfigureNoParams) { |
| 428 SKIP_TEST_IF_MEDIA_CODEC_BRIDGE_IS_NOT_AVAILABLE(); |
| 429 |
| 430 CreateVideoDecoder(); |
| 431 |
| 432 // Cannot configure without config parameters. |
| 433 EXPECT_EQ(MediaCodecDecoder::CONFIG_FAILURE, decoder_->Configure()); |
| 434 } |
| 435 |
| 436 TEST_F(MediaCodecDecoderTest, VideoConfigureNoSurface) { |
| 437 SKIP_TEST_IF_MEDIA_CODEC_BRIDGE_IS_NOT_AVAILABLE(); |
| 438 |
| 439 CreateVideoDecoder(); |
| 440 |
| 441 // decoder_->Configure() searches back for the key frame. |
| 442 // We have to prefetch decoder. |
| 443 |
| 444 base::TimeDelta duration = base::TimeDelta::FromMilliseconds(500); |
| 445 SetDataFactory(scoped_ptr<DataFactory>(new VideoFactory(duration))); |
| 446 |
| 447 decoder_->Prefetch(base::Bind(&MediaCodecDecoderTest::SetPrefetched, |
| 448 base::Unretained(this))); |
| 449 |
| 450 EXPECT_TRUE(WaitForCondition(base::Bind(&MediaCodecDecoderTest::is_prefetched, |
| 451 base::Unretained(this)))); |
| 452 |
| 453 decoder_->SetDemuxerConfigs(CreateVideoConfigs(duration)); |
| 454 |
| 455 // Surface is not set, Configure() should fail. |
| 456 |
| 457 EXPECT_EQ(MediaCodecDecoder::CONFIG_FAILURE, decoder_->Configure()); |
| 458 } |
| 459 |
| 460 TEST_F(MediaCodecDecoderTest, VideoConfigureInvalidSurface) { |
| 461 SKIP_TEST_IF_MEDIA_CODEC_BRIDGE_IS_NOT_AVAILABLE(); |
| 462 |
| 463 CreateVideoDecoder(); |
| 464 |
| 465 // decoder_->Configure() searches back for the key frame. |
| 466 // We have to prefetch decoder. |
| 467 |
| 468 base::TimeDelta duration = base::TimeDelta::FromMilliseconds(500); |
| 469 SetDataFactory(scoped_ptr<DataFactory>(new VideoFactory(duration))); |
| 470 |
| 471 decoder_->Prefetch(base::Bind(&MediaCodecDecoderTest::SetPrefetched, |
| 472 base::Unretained(this))); |
| 473 |
| 474 EXPECT_TRUE(WaitForCondition(base::Bind(&MediaCodecDecoderTest::is_prefetched, |
| 475 base::Unretained(this)))); |
| 476 |
| 477 decoder_->SetDemuxerConfigs(CreateVideoConfigs(duration)); |
| 478 |
| 479 // Prepare the surface. |
| 480 scoped_refptr<gfx::SurfaceTexture> surface_texture( |
| 481 gfx::SurfaceTexture::Create(0)); |
| 482 gfx::ScopedJavaSurface surface(surface_texture.get()); |
| 483 |
| 484 // Release the surface texture. |
| 485 surface_texture = NULL; |
| 486 |
| 487 MediaCodecVideoDecoder* video_decoder = |
| 488 static_cast<MediaCodecVideoDecoder*>(decoder_.get()); |
| 489 video_decoder->SetPendingSurface(surface.Pass()); |
| 490 |
| 491 EXPECT_EQ(MediaCodecDecoder::CONFIG_FAILURE, decoder_->Configure()); |
| 492 } |
| 493 |
| 494 TEST_F(MediaCodecDecoderTest, VideoConfigureValidParams) { |
| 495 SKIP_TEST_IF_MEDIA_CODEC_BRIDGE_IS_NOT_AVAILABLE(); |
| 496 |
| 497 CreateVideoDecoder(); |
| 498 |
| 499 // decoder_->Configure() searches back for the key frame. |
| 500 // We have to prefetch decoder. |
| 501 |
| 502 base::TimeDelta duration = base::TimeDelta::FromMilliseconds(500); |
| 503 SetDataFactory(scoped_ptr<DataFactory>(new VideoFactory(duration))); |
| 504 |
| 505 decoder_->Prefetch(base::Bind(&MediaCodecDecoderTest::SetPrefetched, |
| 506 base::Unretained(this))); |
| 507 |
| 508 EXPECT_TRUE(WaitForCondition(base::Bind(&MediaCodecDecoderTest::is_prefetched, |
| 509 base::Unretained(this)))); |
| 510 |
| 511 decoder_->SetDemuxerConfigs(CreateVideoConfigs(duration)); |
| 512 |
| 513 SetVideoSurface(); |
| 514 |
| 515 // Now we can expect Configure() to succeed. |
| 516 |
| 517 EXPECT_EQ(MediaCodecDecoder::CONFIG_OK, decoder_->Configure()); |
| 518 } |
| 519 |
| 520 TEST_F(MediaCodecDecoderTest, AudioStartWithoutConfigure) { |
| 521 SKIP_TEST_IF_MEDIA_CODEC_BRIDGE_IS_NOT_AVAILABLE(); |
| 522 |
| 523 CreateAudioDecoder(); |
| 524 |
| 525 // Decoder has to be configured first. |
| 526 EXPECT_FALSE(decoder_->Start(base::TimeDelta::FromMilliseconds(0))); |
| 527 } |
| 528 |
| 529 TEST_F(MediaCodecDecoderTest, AudioStarvation) { |
| 530 SKIP_TEST_IF_MEDIA_CODEC_BRIDGE_IS_NOT_AVAILABLE(); |
| 531 |
| 532 CreateAudioDecoder(); |
| 533 |
| 534 // We do not set data factory and do not call Prefetch. |
| 535 // In this case decoder shoudl report starvation right after Start. |
| 536 |
| 537 base::TimeDelta duration = base::TimeDelta::FromMilliseconds(500); |
| 538 decoder_->SetDemuxerConfigs(CreateAudioConfigs(kCodecVorbis, duration)); |
| 539 |
| 540 EXPECT_EQ(MediaCodecDecoder::CONFIG_OK, decoder_->Configure()); |
| 541 |
| 542 EXPECT_TRUE(decoder_->Start(base::TimeDelta::FromMilliseconds(0))); |
| 543 |
| 544 EXPECT_TRUE(WaitForCondition( |
| 545 base::Bind(&MediaCodecDecoderTest::is_starved, base::Unretained(this)))); |
| 546 } |
| 547 |
| 548 TEST_F(MediaCodecDecoderTest, AudioPlayTillCompletion) { |
| 549 SKIP_TEST_IF_MEDIA_CODEC_BRIDGE_IS_NOT_AVAILABLE(); |
| 550 |
| 551 CreateAudioDecoder(); |
| 552 |
| 553 base::TimeDelta duration = base::TimeDelta::FromMilliseconds(500); |
| 554 base::TimeDelta timeout = base::TimeDelta::FromMilliseconds(600); |
| 555 SetDataFactory(scoped_ptr<DataFactory>(new AudioFactory(duration))); |
| 556 |
| 557 // Prefetch to avoid starvation at the beginning of playback. |
| 558 decoder_->Prefetch(base::Bind(&MediaCodecDecoderTest::SetPrefetched, |
| 559 base::Unretained(this))); |
| 560 |
| 561 EXPECT_TRUE(WaitForCondition(base::Bind(&MediaCodecDecoderTest::is_prefetched, |
| 562 base::Unretained(this)))); |
| 563 |
| 564 decoder_->SetDemuxerConfigs(CreateAudioConfigs(kCodecVorbis, duration)); |
| 565 |
| 566 EXPECT_EQ(MediaCodecDecoder::CONFIG_OK, decoder_->Configure()); |
| 567 |
| 568 EXPECT_TRUE(decoder_->Start(base::TimeDelta::FromMilliseconds(0))); |
| 569 |
| 570 EXPECT_TRUE(WaitForCondition( |
| 571 base::Bind(&MediaCodecDecoderTest::is_stopped, base::Unretained(this)), |
| 572 timeout)); |
| 573 |
| 574 EXPECT_TRUE(decoder_->IsStopped()); |
| 575 EXPECT_TRUE(decoder_->IsCompleted()); |
| 576 |
| 577 // It is hard to properly estimate minimum and maximum values because |
| 578 // reported times are different from PTS. |
| 579 EXPECT_EQ(25, pts_stat_.num_values()); |
| 580 } |
| 581 |
| 582 TEST_F(MediaCodecDecoderTest, VideoPlayTillCompletion) { |
| 583 SKIP_TEST_IF_MEDIA_CODEC_BRIDGE_IS_NOT_AVAILABLE(); |
| 584 |
| 585 CreateVideoDecoder(); |
| 586 |
| 587 base::TimeDelta duration = base::TimeDelta::FromMilliseconds(500); |
| 588 base::TimeDelta timeout = base::TimeDelta::FromMilliseconds(600); |
| 589 SetDataFactory(scoped_ptr<DataFactory>(new VideoFactory(duration))); |
| 590 |
| 591 // Prefetch |
| 592 decoder_->Prefetch(base::Bind(&MediaCodecDecoderTest::SetPrefetched, |
| 593 base::Unretained(this))); |
| 594 |
| 595 EXPECT_TRUE(WaitForCondition(base::Bind(&MediaCodecDecoderTest::is_prefetched, |
| 596 base::Unretained(this)))); |
| 597 |
| 598 decoder_->SetDemuxerConfigs(CreateVideoConfigs(duration)); |
| 599 |
| 600 SetVideoSurface(); |
| 601 |
| 602 EXPECT_EQ(MediaCodecDecoder::CONFIG_OK, decoder_->Configure()); |
| 603 |
| 604 EXPECT_TRUE(decoder_->Start(base::TimeDelta::FromMilliseconds(0))); |
| 605 |
| 606 EXPECT_TRUE(WaitForCondition( |
| 607 base::Bind(&MediaCodecDecoderTest::is_stopped, base::Unretained(this)), |
| 608 timeout)); |
| 609 |
| 610 EXPECT_TRUE(decoder_->IsStopped()); |
| 611 EXPECT_TRUE(decoder_->IsCompleted()); |
| 612 |
| 613 EXPECT_EQ(26, pts_stat_.num_values()); |
| 614 EXPECT_EQ(data_factory_->last_pts(), pts_stat_.max()); |
| 615 } |
| 616 |
| 617 } // namespace media |
| OLD | NEW |