| Index: media/base/android/media_codec_player_unittest.cc
|
| diff --git a/media/base/android/media_codec_player_unittest.cc b/media/base/android/media_codec_player_unittest.cc
|
| index c20cf7daa7b7fdfa758cc6f1a5467dd5d48d6b54..0742bf78bb468d6c5db4097040f57a8fb32809cb 100644
|
| --- a/media/base/android/media_codec_player_unittest.cc
|
| +++ b/media/base/android/media_codec_player_unittest.cc
|
| @@ -2,6 +2,8 @@
|
| // Use of this source code is governed by a BSD-style license that can be
|
| // found in the LICENSE file.
|
|
|
| +#include <stdint.h>
|
| +
|
| #include "base/bind.h"
|
| #include "base/logging.h"
|
| #include "base/timer/timer.h"
|
| @@ -43,6 +45,11 @@ const base::TimeDelta kAudioFramePeriod =
|
| base::TimeDelta::FromSecondsD(1024.0 / 44100); // 1024 samples @ 44100 Hz
|
| const base::TimeDelta kVideoFramePeriod = base::TimeDelta::FromMilliseconds(20);
|
|
|
| +enum Flags {
|
| + kAlwaysReconfigAudio = 0x1,
|
| + kAlwaysReconfigVideo = 0x2,
|
| +};
|
| +
|
| // The predicate that always returns false, used for WaitForDelay implementation
|
| bool AlwaysFalse() {
|
| return false;
|
| @@ -217,6 +224,7 @@ DemuxerConfigs CreateAudioVideoConfigs(const TestDataFactory* audio,
|
| result.video_codec = vconf.video_codec;
|
| result.video_size = vconf.video_size;
|
| result.is_video_encrypted = vconf.is_video_encrypted;
|
| + result.duration = std::max(result.duration, vconf.duration);
|
| return result;
|
| }
|
|
|
| @@ -530,13 +538,20 @@ class MediaCodecPlayerTest : public testing::Test {
|
| // started.
|
| bool StartVideoPlayback(base::TimeDelta duration, const char* test_name);
|
|
|
| + // Helper method that starts audio and video streams.
|
| + bool StartAVPlayback(scoped_ptr<AudioFactory> audio_factory,
|
| + scoped_ptr<VideoFactory> video_factory,
|
| + uint32_t flags,
|
| + const char* test_name);
|
| +
|
| // Helper method that starts audio and video streams with preroll.
|
| // The preroll is achieved by setting significant video preroll interval
|
| // so video will have to catch up with audio. To make room for this interval
|
| // the Start() command is preceded by SeekTo().
|
| - bool StartAVSeekAndPreroll(base::TimeDelta duration,
|
| + bool StartAVSeekAndPreroll(scoped_ptr<AudioFactory> audio_factory,
|
| + scoped_ptr<VideoFactory> video_factory,
|
| base::TimeDelta seek_position,
|
| - base::TimeDelta video_preroll,
|
| + uint32_t flags,
|
| const char* test_name);
|
|
|
| // Callback sent when demuxer is being deleted.
|
| @@ -702,26 +717,78 @@ bool MediaCodecPlayerTest::StartVideoPlayback(base::TimeDelta duration,
|
| return true;
|
| }
|
|
|
| -bool MediaCodecPlayerTest::StartAVSeekAndPreroll(base::TimeDelta duration,
|
| - base::TimeDelta seek_position,
|
| - base::TimeDelta video_preroll,
|
| - const char* test_name) {
|
| - const base::TimeDelta start_timeout = base::TimeDelta::FromMilliseconds(800);
|
| +bool MediaCodecPlayerTest::StartAVPlayback(
|
| + scoped_ptr<AudioFactory> audio_factory,
|
| + scoped_ptr<VideoFactory> video_factory,
|
| + uint32_t flags,
|
| + const char* test_name) {
|
| + demuxer_->SetAudioFactory(audio_factory.Pass());
|
| + demuxer_->SetVideoFactory(video_factory.Pass());
|
|
|
| - demuxer_->SetVideoPrerollInterval(video_preroll);
|
| + CreatePlayer();
|
| + SetVideoSurface();
|
|
|
| - demuxer_->SetAudioFactory(
|
| - scoped_ptr<AudioFactory>(new AudioFactory(duration)));
|
| - demuxer_->SetVideoFactory(
|
| - scoped_ptr<VideoFactory>(new VideoFactory(duration)));
|
| + // Wait till the player is initialized on media thread.
|
| + EXPECT_TRUE(WaitForCondition(base::Bind(&MockDemuxerAndroid::IsInitialized,
|
| + base::Unretained(demuxer_))));
|
|
|
| - CreatePlayer();
|
| + if (!demuxer_->IsInitialized()) {
|
| + DVLOG(0) << test_name << ": demuxer is not initialized";
|
| + return false;
|
| + }
|
|
|
| - // Set special testing callback to receive PTS from decoders.
|
| + // Ask decoders to always reconfigure after the player has been initialized.
|
| + if (flags & kAlwaysReconfigAudio)
|
| + player_->SetAlwaysReconfigureForTests(DemuxerStream::AUDIO);
|
| + if (flags & kAlwaysReconfigVideo)
|
| + player_->SetAlwaysReconfigureForTests(DemuxerStream::VIDEO);
|
| +
|
| + // Set a testing callback to receive PTS from decoders.
|
| player_->SetDecodersTimeCallbackForTests(
|
| base::Bind(&MockMediaPlayerManager::OnDecodersTimeUpdate,
|
| base::Unretained(&manager_)));
|
|
|
| + // Set a testing callback to receive MediaCodec creation events from decoders.
|
| + player_->SetCodecCreatedCallbackForTests(
|
| + base::Bind(&MockMediaPlayerManager::OnMediaCodecCreated,
|
| + base::Unretained(&manager_)));
|
| +
|
| + // Post configuration after the player has been initialized.
|
| + demuxer_->PostInternalConfigs();
|
| +
|
| + // Start and wait for playback.
|
| + player_->Start();
|
| +
|
| + // Wait till we start to play.
|
| + base::TimeDelta start_timeout = base::TimeDelta::FromMilliseconds(2000);
|
| +
|
| + EXPECT_TRUE(
|
| + WaitForCondition(base::Bind(&MockMediaPlayerManager::IsPlaybackStarted,
|
| + base::Unretained(&manager_)),
|
| + start_timeout));
|
| +
|
| + if (!manager_.IsPlaybackStarted()) {
|
| + DVLOG(0) << test_name << ": playback did not start";
|
| + return false;
|
| + }
|
| +
|
| + return true;
|
| +}
|
| +
|
| +bool MediaCodecPlayerTest::StartAVSeekAndPreroll(
|
| + scoped_ptr<AudioFactory> audio_factory,
|
| + scoped_ptr<VideoFactory> video_factory,
|
| + base::TimeDelta seek_position,
|
| + uint32_t flags,
|
| + const char* test_name) {
|
| + // Initialize A/V playback
|
| +
|
| + demuxer_->SetAudioFactory(audio_factory.Pass());
|
| + demuxer_->SetVideoFactory(video_factory.Pass());
|
| +
|
| + CreatePlayer();
|
| + SetVideoSurface();
|
| +
|
| // Wait till the player is initialized on media thread.
|
| EXPECT_TRUE(WaitForCondition(base::Bind(&MockDemuxerAndroid::IsInitialized,
|
| base::Unretained(demuxer_))));
|
| @@ -731,7 +798,21 @@ bool MediaCodecPlayerTest::StartAVSeekAndPreroll(base::TimeDelta duration,
|
| return false;
|
| }
|
|
|
| - SetVideoSurface();
|
| + // Ask decoders to always reconfigure after the player has been initialized.
|
| + if (flags & kAlwaysReconfigAudio)
|
| + player_->SetAlwaysReconfigureForTests(DemuxerStream::AUDIO);
|
| + if (flags & kAlwaysReconfigVideo)
|
| + player_->SetAlwaysReconfigureForTests(DemuxerStream::VIDEO);
|
| +
|
| + // Set a testing callback to receive PTS from decoders.
|
| + player_->SetDecodersTimeCallbackForTests(
|
| + base::Bind(&MockMediaPlayerManager::OnDecodersTimeUpdate,
|
| + base::Unretained(&manager_)));
|
| +
|
| + // Set a testing callback to receive MediaCodec creation events from decoders.
|
| + player_->SetCodecCreatedCallbackForTests(
|
| + base::Bind(&MockMediaPlayerManager::OnMediaCodecCreated,
|
| + base::Unretained(&manager_)));
|
|
|
| // Post configuration after the player has been initialized.
|
| demuxer_->PostInternalConfigs();
|
| @@ -743,6 +824,7 @@ bool MediaCodecPlayerTest::StartAVSeekAndPreroll(base::TimeDelta duration,
|
| player_->Start();
|
|
|
| // Wait till preroll starts.
|
| + base::TimeDelta start_timeout = base::TimeDelta::FromMilliseconds(2000);
|
| EXPECT_TRUE(WaitForCondition(
|
| base::Bind(&MediaCodecPlayer::IsPrerollingForTests,
|
| base::Unretained(player_), DemuxerStream::VIDEO),
|
| @@ -1367,7 +1449,13 @@ TEST_F(MediaCodecPlayerTest, AVPrerollAudioWaitsForVideo) {
|
| base::TimeDelta preroll_intvl = base::TimeDelta::FromMilliseconds(500);
|
| base::TimeDelta preroll_timeout = base::TimeDelta::FromMilliseconds(1000);
|
|
|
| - ASSERT_TRUE(StartAVSeekAndPreroll(duration, seek_position, preroll_intvl,
|
| + scoped_ptr<AudioFactory> audio_factory(new AudioFactory(duration));
|
| + scoped_ptr<VideoFactory> video_factory(new VideoFactory(duration));
|
| +
|
| + demuxer_->SetVideoPrerollInterval(preroll_intvl);
|
| +
|
| + ASSERT_TRUE(StartAVSeekAndPreroll(audio_factory.Pass(), video_factory.Pass(),
|
| + seek_position, 0,
|
| "AVPrerollAudioWaitsForVideo"));
|
|
|
| // Wait till preroll finishes and the real playback starts.
|
| @@ -1410,7 +1498,13 @@ TEST_F(MediaCodecPlayerTest, AVPrerollReleaseAndRestart) {
|
| base::TimeDelta start_timeout = base::TimeDelta::FromMilliseconds(800);
|
| base::TimeDelta preroll_timeout = base::TimeDelta::FromMilliseconds(1000);
|
|
|
| - ASSERT_TRUE(StartAVSeekAndPreroll(duration, seek_position, preroll_intvl,
|
| + scoped_ptr<AudioFactory> audio_factory(new AudioFactory(duration));
|
| + scoped_ptr<VideoFactory> video_factory(new VideoFactory(duration));
|
| +
|
| + demuxer_->SetVideoPrerollInterval(preroll_intvl);
|
| +
|
| + ASSERT_TRUE(StartAVSeekAndPreroll(audio_factory.Pass(), video_factory.Pass(),
|
| + seek_position, 0,
|
| "AVPrerollReleaseAndRestart"));
|
|
|
| // Issue Release().
|
| @@ -1478,7 +1572,13 @@ TEST_F(MediaCodecPlayerTest, AVPrerollStopAndRestart) {
|
| base::TimeDelta start_timeout = base::TimeDelta::FromMilliseconds(800);
|
| base::TimeDelta preroll_timeout = base::TimeDelta::FromMilliseconds(1000);
|
|
|
| - ASSERT_TRUE(StartAVSeekAndPreroll(duration, seek_position, preroll_intvl,
|
| + scoped_ptr<AudioFactory> audio_factory(new AudioFactory(duration));
|
| + scoped_ptr<VideoFactory> video_factory(new VideoFactory(duration));
|
| +
|
| + demuxer_->SetVideoPrerollInterval(preroll_intvl);
|
| +
|
| + ASSERT_TRUE(StartAVSeekAndPreroll(audio_factory.Pass(), video_factory.Pass(),
|
| + seek_position, 0,
|
| "AVPrerollStopAndRestart"));
|
|
|
| // Video stream should be prerolling. Request to stop.
|
| @@ -1681,7 +1781,7 @@ TEST_F(MediaCodecPlayerTest, VideoConfigChangeWhilePlaying) {
|
| base::Unretained(demuxer_))));
|
|
|
| if (!demuxer_->IsInitialized()) {
|
| - DVLOG(0) << "AVConfigChangeWhilePlaying: demuxer is not initialized";
|
| + DVLOG(0) << "VideoConfigChangeWhilePlaying: demuxer is not initialized";
|
| return;
|
| }
|
|
|
| @@ -1735,52 +1835,16 @@ TEST_F(MediaCodecPlayerTest, AVVideoConfigChangeWhilePlaying) {
|
| base::TimeDelta config_change_position =
|
| base::TimeDelta::FromMilliseconds(1000);
|
|
|
| - base::TimeDelta start_timeout = base::TimeDelta::FromMilliseconds(2000);
|
| base::TimeDelta completion_timeout = base::TimeDelta::FromMilliseconds(3000);
|
|
|
| - demuxer_->SetAudioFactory(
|
| - scoped_ptr<AudioFactory>(new AudioFactory(duration)));
|
| - demuxer_->SetVideoFactory(
|
| - scoped_ptr<VideoFactory>(new VideoFactory(duration)));
|
| -
|
| - demuxer_->video_factory()->RequestConfigChange(config_change_position);
|
| -
|
| - CreatePlayer();
|
| - SetVideoSurface();
|
| -
|
| - // Wait till the player is initialized on media thread.
|
| - EXPECT_TRUE(WaitForCondition(base::Bind(&MockDemuxerAndroid::IsInitialized,
|
| - base::Unretained(demuxer_))));
|
| -
|
| - if (!demuxer_->IsInitialized()) {
|
| - DVLOG(0) << "AVConfigChangeWhilePlaying: demuxer is not initialized";
|
| - return;
|
| - }
|
| -
|
| - // Ask decoders to always reconfigure after the player has been initialized.
|
| - player_->SetAlwaysReconfigureForTests(DemuxerStream::VIDEO);
|
| -
|
| - // Set a testing callback to receive PTS from decoders.
|
| - player_->SetDecodersTimeCallbackForTests(
|
| - base::Bind(&MockMediaPlayerManager::OnDecodersTimeUpdate,
|
| - base::Unretained(&manager_)));
|
| -
|
| - // Set a testing callback to receive MediaCodec creation events from decoders.
|
| - player_->SetCodecCreatedCallbackForTests(
|
| - base::Bind(&MockMediaPlayerManager::OnMediaCodecCreated,
|
| - base::Unretained(&manager_)));
|
| -
|
| - // Post configuration after the player has been initialized.
|
| - demuxer_->PostInternalConfigs();
|
| + scoped_ptr<AudioFactory> audio_factory(new AudioFactory(duration));
|
| + scoped_ptr<VideoFactory> video_factory(new VideoFactory(duration));
|
|
|
| - // Start and wait for playback.
|
| - player_->Start();
|
| + video_factory->RequestConfigChange(config_change_position);
|
|
|
| - // Wait till we start to play.
|
| - EXPECT_TRUE(
|
| - WaitForCondition(base::Bind(&MockMediaPlayerManager::IsPlaybackStarted,
|
| - base::Unretained(&manager_)),
|
| - start_timeout));
|
| + ASSERT_TRUE(StartAVPlayback(audio_factory.Pass(), video_factory.Pass(),
|
| + kAlwaysReconfigVideo,
|
| + "AVVideoConfigChangeWhilePlaying"));
|
|
|
| // Wait till completion
|
| EXPECT_TRUE(
|
| @@ -1799,11 +1863,11 @@ TEST_F(MediaCodecPlayerTest, AVVideoConfigChangeWhilePlaying) {
|
| EXPECT_EQ(expected_video_frames,
|
| manager_.render_stat_[DemuxerStream::VIDEO].num_values());
|
|
|
| - // Check that we did not miss audio frames. We expect two postponed frames
|
| + // Check that we did not miss audio frames. We expect one postponed frames
|
| // that are not reported.
|
| // For Nexus 4 KitKat the AAC decoder seems to swallow the first frame
|
| // but reports the last pts twice, maybe it just shifts the reported PTS.
|
| - int expected_audio_frames = duration / kAudioFramePeriod + 1 - 2;
|
| + int expected_audio_frames = duration / kAudioFramePeriod + 1 - 1;
|
| EXPECT_EQ(expected_audio_frames,
|
| manager_.render_stat_[DemuxerStream::AUDIO].num_values());
|
| }
|
| @@ -1813,57 +1877,113 @@ TEST_F(MediaCodecPlayerTest, AVAudioConfigChangeWhilePlaying) {
|
|
|
| // Test that A/V playback continues after audio config change.
|
|
|
| - // Initialize A/V playback
|
| base::TimeDelta duration = base::TimeDelta::FromMilliseconds(1200);
|
| base::TimeDelta config_change_position =
|
| base::TimeDelta::FromMilliseconds(1000);
|
|
|
| - base::TimeDelta start_timeout = base::TimeDelta::FromMilliseconds(2000);
|
| base::TimeDelta completion_timeout = base::TimeDelta::FromMilliseconds(3000);
|
|
|
| - demuxer_->SetAudioFactory(
|
| - scoped_ptr<AudioFactory>(new AudioFactory(duration)));
|
| - demuxer_->SetVideoFactory(
|
| - scoped_ptr<VideoFactory>(new VideoFactory(duration)));
|
| + scoped_ptr<AudioFactory> audio_factory(new AudioFactory(duration));
|
| + scoped_ptr<VideoFactory> video_factory(new VideoFactory(duration));
|
|
|
| - demuxer_->audio_factory()->RequestConfigChange(config_change_position);
|
| + audio_factory->RequestConfigChange(config_change_position);
|
|
|
| - CreatePlayer();
|
| - SetVideoSurface();
|
| + ASSERT_TRUE(StartAVPlayback(audio_factory.Pass(), video_factory.Pass(),
|
| + kAlwaysReconfigAudio,
|
| + "AVAudioConfigChangeWhilePlaying"));
|
|
|
| - // Wait till the player is initialized on media thread.
|
| - EXPECT_TRUE(WaitForCondition(base::Bind(&MockDemuxerAndroid::IsInitialized,
|
| - base::Unretained(demuxer_))));
|
| + // Wait till completion
|
| + EXPECT_TRUE(
|
| + WaitForCondition(base::Bind(&MockMediaPlayerManager::IsPlaybackCompleted,
|
| + base::Unretained(&manager_)),
|
| + completion_timeout));
|
|
|
| - if (!demuxer_->IsInitialized()) {
|
| - DVLOG(0) << "AVConfigChangeWhilePlaying: demuxer is not initialized";
|
| - return;
|
| - }
|
| + // The audio codec should be recreated upon config changes.
|
| + EXPECT_EQ(2, manager_.num_audio_codecs_created());
|
|
|
| - // Ask decoders to always reconfigure after the player has been initialized.
|
| - player_->SetAlwaysReconfigureForTests(DemuxerStream::AUDIO);
|
| + // The video codec should be kept.
|
| + EXPECT_EQ(1, manager_.num_video_codecs_created());
|
|
|
| - // Set a testing callback to receive PTS from decoders.
|
| - player_->SetDecodersTimeCallbackForTests(
|
| - base::Bind(&MockMediaPlayerManager::OnDecodersTimeUpdate,
|
| - base::Unretained(&manager_)));
|
| + // Check that we did not miss video frames.
|
| + int expected_video_frames = duration / kVideoFramePeriod + 1;
|
| + EXPECT_EQ(expected_video_frames,
|
| + manager_.render_stat_[DemuxerStream::VIDEO].num_values());
|
|
|
| - // Set a testing callback to receive MediaCodec creation events from decoders.
|
| - player_->SetCodecCreatedCallbackForTests(
|
| - base::Bind(&MockMediaPlayerManager::OnMediaCodecCreated,
|
| - base::Unretained(&manager_)));
|
| + // Check that we did not miss audio frames. We expect two postponed frames
|
| + // that are not reported.
|
| + int expected_audio_frames = duration / kAudioFramePeriod + 1 - 2;
|
| + EXPECT_EQ(expected_audio_frames,
|
| + manager_.render_stat_[DemuxerStream::AUDIO].num_values());
|
| +}
|
|
|
| - // Post configuration after the player has been initialized.
|
| - demuxer_->PostInternalConfigs();
|
| +TEST_F(MediaCodecPlayerTest, AVSimultaneousConfigChange_1) {
|
| + SKIP_TEST_IF_MEDIA_CODEC_BRIDGE_IS_NOT_AVAILABLE();
|
|
|
| - // Start and wait for playback.
|
| - player_->Start();
|
| + // Test that the playback continues if audio and video config changes happen
|
| + // at the same time.
|
|
|
| - // Wait till we start to play.
|
| + base::TimeDelta duration = base::TimeDelta::FromMilliseconds(1200);
|
| + base::TimeDelta config_change_audio = base::TimeDelta::FromMilliseconds(1000);
|
| + base::TimeDelta config_change_video = base::TimeDelta::FromMilliseconds(1000);
|
| +
|
| + base::TimeDelta completion_timeout = base::TimeDelta::FromMilliseconds(3000);
|
| +
|
| + scoped_ptr<AudioFactory> audio_factory(new AudioFactory(duration));
|
| + scoped_ptr<VideoFactory> video_factory(new VideoFactory(duration));
|
| +
|
| + audio_factory->RequestConfigChange(config_change_audio);
|
| + video_factory->RequestConfigChange(config_change_video);
|
| +
|
| + ASSERT_TRUE(StartAVPlayback(audio_factory.Pass(), video_factory.Pass(),
|
| + kAlwaysReconfigAudio | kAlwaysReconfigVideo,
|
| + "AVSimultaneousConfigChange_1"));
|
| +
|
| + // Wait till completion
|
| EXPECT_TRUE(
|
| - WaitForCondition(base::Bind(&MockMediaPlayerManager::IsPlaybackStarted,
|
| + WaitForCondition(base::Bind(&MockMediaPlayerManager::IsPlaybackCompleted,
|
| base::Unretained(&manager_)),
|
| - start_timeout));
|
| + completion_timeout));
|
| +
|
| + // The audio codec should be recreated upon config changes.
|
| + EXPECT_EQ(2, manager_.num_audio_codecs_created());
|
| +
|
| + // The video codec should be recreated upon config changes.
|
| + EXPECT_EQ(2, manager_.num_video_codecs_created());
|
| +
|
| + // Check that we did not miss video frames.
|
| + int expected_video_frames = duration / kVideoFramePeriod + 1;
|
| + EXPECT_EQ(expected_video_frames,
|
| + manager_.render_stat_[DemuxerStream::VIDEO].num_values());
|
| +
|
| + // Check that we did not miss audio frames. We expect two postponed frames
|
| + // that are not reported.
|
| + int expected_audio_frames = duration / kAudioFramePeriod + 1 - 2;
|
| + EXPECT_EQ(expected_audio_frames,
|
| + manager_.render_stat_[DemuxerStream::AUDIO].num_values());
|
| +}
|
| +
|
| +TEST_F(MediaCodecPlayerTest, AVSimultaneousConfigChange_2) {
|
| + SKIP_TEST_IF_MEDIA_CODEC_BRIDGE_IS_NOT_AVAILABLE();
|
| +
|
| + // Test that the playback continues if audio and video config changes happen
|
| + // at the same time. Move audio change moment slightly to make it drained
|
| + // after video.
|
| +
|
| + base::TimeDelta duration = base::TimeDelta::FromMilliseconds(1200);
|
| + base::TimeDelta config_change_audio = base::TimeDelta::FromMilliseconds(1020);
|
| + base::TimeDelta config_change_video = base::TimeDelta::FromMilliseconds(1000);
|
| +
|
| + base::TimeDelta completion_timeout = base::TimeDelta::FromMilliseconds(3000);
|
| +
|
| + scoped_ptr<AudioFactory> audio_factory(new AudioFactory(duration));
|
| + scoped_ptr<VideoFactory> video_factory(new VideoFactory(duration));
|
| +
|
| + audio_factory->RequestConfigChange(config_change_audio);
|
| + video_factory->RequestConfigChange(config_change_video);
|
| +
|
| + ASSERT_TRUE(StartAVPlayback(audio_factory.Pass(), video_factory.Pass(),
|
| + kAlwaysReconfigAudio | kAlwaysReconfigVideo,
|
| + "AVSimultaneousConfigChange_2"));
|
|
|
| // Wait till completion
|
| EXPECT_TRUE(
|
| @@ -1874,8 +1994,8 @@ TEST_F(MediaCodecPlayerTest, AVAudioConfigChangeWhilePlaying) {
|
| // The audio codec should be recreated upon config changes.
|
| EXPECT_EQ(2, manager_.num_audio_codecs_created());
|
|
|
| - // The video codec should be kept.
|
| - EXPECT_EQ(1, manager_.num_video_codecs_created());
|
| + // The video codec should be recreated upon config changes.
|
| + EXPECT_EQ(2, manager_.num_video_codecs_created());
|
|
|
| // Check that we did not miss video frames.
|
| int expected_video_frames = duration / kVideoFramePeriod + 1;
|
| @@ -1889,4 +2009,197 @@ TEST_F(MediaCodecPlayerTest, AVAudioConfigChangeWhilePlaying) {
|
| manager_.render_stat_[DemuxerStream::AUDIO].num_values());
|
| }
|
|
|
| +TEST_F(MediaCodecPlayerTest, AVAudioEndsAcrossVideoConfigChange) {
|
| + SKIP_TEST_IF_MEDIA_CODEC_BRIDGE_IS_NOT_AVAILABLE();
|
| +
|
| + // Test that audio can end while video config change processing.
|
| +
|
| + base::TimeDelta audio_duration = base::TimeDelta::FromMilliseconds(1000);
|
| + base::TimeDelta video_duration = base::TimeDelta::FromMilliseconds(1200);
|
| + base::TimeDelta config_change_video = base::TimeDelta::FromMilliseconds(1000);
|
| +
|
| + base::TimeDelta completion_timeout = base::TimeDelta::FromMilliseconds(3000);
|
| +
|
| + scoped_ptr<AudioFactory> audio_factory(new AudioFactory(audio_duration));
|
| + scoped_ptr<VideoFactory> video_factory(new VideoFactory(video_duration));
|
| +
|
| + video_factory->RequestConfigChange(config_change_video);
|
| +
|
| + ASSERT_TRUE(StartAVPlayback(audio_factory.Pass(), video_factory.Pass(),
|
| + kAlwaysReconfigVideo,
|
| + "AVAudioEndsAcrossVideoConfigChange"));
|
| +
|
| + // Wait till completion
|
| + EXPECT_TRUE(
|
| + WaitForCondition(base::Bind(&MockMediaPlayerManager::IsPlaybackCompleted,
|
| + base::Unretained(&manager_)),
|
| + completion_timeout));
|
| +
|
| + // The audio codec should not be recreated.
|
| + EXPECT_EQ(1, manager_.num_audio_codecs_created());
|
| +
|
| + // The video codec should be recreated upon config changes.
|
| + EXPECT_EQ(2, manager_.num_video_codecs_created());
|
| +
|
| + // Check that we did not miss video frames.
|
| + int expected_video_frames = video_duration / kVideoFramePeriod + 1;
|
| + EXPECT_EQ(expected_video_frames,
|
| + manager_.render_stat_[DemuxerStream::VIDEO].num_values());
|
| +
|
| + // Check the last video frame timestamp. The maximum render pts may differ
|
| + // from |video_duration| because of the testing artefact: if the last video
|
| + // chunk is incomplete if will have different last pts due to B-frames
|
| + // rearrangements.
|
| + EXPECT_LE(video_duration,
|
| + manager_.render_stat_[DemuxerStream::VIDEO].max().pts);
|
| +
|
| + // Check that the playback time reported by the player goes past
|
| + // the audio time and corresponds to video after the audio ended.
|
| + EXPECT_EQ(video_duration, manager_.pts_stat_.max());
|
| +}
|
| +
|
| +TEST_F(MediaCodecPlayerTest, AVVideoEndsAcrossAudioConfigChange) {
|
| + SKIP_TEST_IF_MEDIA_CODEC_BRIDGE_IS_NOT_AVAILABLE();
|
| +
|
| + // Test that video can end while audio config change processing.
|
| + base::TimeDelta audio_duration = base::TimeDelta::FromMilliseconds(1200);
|
| + base::TimeDelta video_duration = base::TimeDelta::FromMilliseconds(1000);
|
| + base::TimeDelta config_change_audio = base::TimeDelta::FromMilliseconds(1000);
|
| +
|
| + base::TimeDelta completion_timeout = base::TimeDelta::FromMilliseconds(3000);
|
| +
|
| + scoped_ptr<AudioFactory> audio_factory(new AudioFactory(audio_duration));
|
| + scoped_ptr<VideoFactory> video_factory(new VideoFactory(video_duration));
|
| +
|
| + audio_factory->RequestConfigChange(config_change_audio);
|
| +
|
| + ASSERT_TRUE(StartAVPlayback(audio_factory.Pass(), video_factory.Pass(),
|
| + kAlwaysReconfigAudio,
|
| + "AVVideoEndsAcrossAudioConfigChange"));
|
| +
|
| + // Wait till completion
|
| + EXPECT_TRUE(
|
| + WaitForCondition(base::Bind(&MockMediaPlayerManager::IsPlaybackCompleted,
|
| + base::Unretained(&manager_)),
|
| + completion_timeout));
|
| +
|
| + // The audio codec should be recreated upon config changes.
|
| + EXPECT_EQ(2, manager_.num_audio_codecs_created());
|
| +
|
| + // The video codec should not be recreated.
|
| + EXPECT_EQ(1, manager_.num_video_codecs_created());
|
| +
|
| + // Check that we did not miss audio frames. We expect two postponed frames
|
| + // that are not reported.
|
| + int expected_audio_frames = audio_duration / kAudioFramePeriod + 1 - 2;
|
| + EXPECT_EQ(expected_audio_frames,
|
| + manager_.render_stat_[DemuxerStream::AUDIO].num_values());
|
| +}
|
| +
|
| +TEST_F(MediaCodecPlayerTest, AVPrerollAcrossVideoConfigChange) {
|
| + SKIP_TEST_IF_MEDIA_CODEC_BRIDGE_IS_NOT_AVAILABLE();
|
| +
|
| + // Test that preroll continues if interrupted by video config change.
|
| +
|
| + base::TimeDelta duration = base::TimeDelta::FromMilliseconds(1200);
|
| + base::TimeDelta seek_position = base::TimeDelta::FromMilliseconds(1000);
|
| + base::TimeDelta config_change_position =
|
| + base::TimeDelta::FromMilliseconds(800);
|
| + base::TimeDelta video_preroll_intvl = base::TimeDelta::FromMilliseconds(500);
|
| + base::TimeDelta preroll_timeout = base::TimeDelta::FromMilliseconds(3000);
|
| +
|
| + demuxer_->SetVideoPrerollInterval(video_preroll_intvl);
|
| +
|
| + scoped_ptr<AudioFactory> audio_factory(new AudioFactory(duration));
|
| +
|
| + scoped_ptr<VideoFactory> video_factory(new VideoFactory(duration));
|
| + video_factory->RequestConfigChange(config_change_position);
|
| +
|
| + ASSERT_TRUE(StartAVSeekAndPreroll(audio_factory.Pass(), video_factory.Pass(),
|
| + seek_position, kAlwaysReconfigVideo,
|
| + "AVPrerollAcrossVideoConfigChange"));
|
| +
|
| + // Wait till preroll finishes and the real playback starts.
|
| + EXPECT_TRUE(
|
| + WaitForCondition(base::Bind(&MockMediaPlayerManager::IsPlaybackStarted,
|
| + base::Unretained(&manager_)),
|
| + preroll_timeout));
|
| +
|
| + // The presense of config change should not affect preroll behavior:
|
| +
|
| + // Ensure that the first audio and video pts are close to each other and are
|
| + // reported at the close moments in time.
|
| +
|
| + EXPECT_TRUE(manager_.HasFirstFrame(DemuxerStream::AUDIO));
|
| + EXPECT_TRUE(WaitForCondition(
|
| + base::Bind(&MockMediaPlayerManager::HasFirstFrame,
|
| + base::Unretained(&manager_), DemuxerStream::VIDEO)));
|
| +
|
| + EXPECT_TRUE(AlmostEqual(manager_.FirstFramePTS(DemuxerStream::AUDIO),
|
| + manager_.FirstFramePTS(DemuxerStream::VIDEO), 25));
|
| +
|
| + EXPECT_TRUE(AlmostEqual(manager_.FirstFrameTime(DemuxerStream::AUDIO),
|
| + manager_.FirstFrameTime(DemuxerStream::VIDEO), 50));
|
| +
|
| + // The playback should start at |seek_position|
|
| + EXPECT_TRUE(AlmostEqual(seek_position, manager_.pts_stat_.min(), 25));
|
| +}
|
| +
|
| +TEST_F(MediaCodecPlayerTest, AVPrerollAcrossAudioConfigChange) {
|
| + SKIP_TEST_IF_MEDIA_CODEC_BRIDGE_IS_NOT_AVAILABLE();
|
| +
|
| + // Test that preroll continues if interrupted by video config change.
|
| +
|
| + base::TimeDelta duration = base::TimeDelta::FromMilliseconds(1200);
|
| + base::TimeDelta seek_position = base::TimeDelta::FromMilliseconds(1000);
|
| + base::TimeDelta config_change_position =
|
| + base::TimeDelta::FromMilliseconds(800);
|
| + base::TimeDelta audio_preroll_intvl = base::TimeDelta::FromMilliseconds(400);
|
| + base::TimeDelta preroll_timeout = base::TimeDelta::FromMilliseconds(3000);
|
| +
|
| + demuxer_->SetAudioPrerollInterval(audio_preroll_intvl);
|
| +
|
| + scoped_ptr<AudioFactory> audio_factory(new AudioFactory(duration));
|
| + audio_factory->RequestConfigChange(config_change_position);
|
| +
|
| + scoped_ptr<VideoFactory> video_factory(new VideoFactory(duration));
|
| +
|
| + ASSERT_TRUE(StartAVSeekAndPreroll(audio_factory.Pass(), video_factory.Pass(),
|
| + seek_position, kAlwaysReconfigAudio,
|
| + "AVPrerollAcrossAudioConfigChange"));
|
| +
|
| + // Wait till preroll finishes and the real playback starts.
|
| + EXPECT_TRUE(
|
| + WaitForCondition(base::Bind(&MockMediaPlayerManager::IsPlaybackStarted,
|
| + base::Unretained(&manager_)),
|
| + preroll_timeout));
|
| +
|
| + // The presense of config change should not affect preroll behavior:
|
| +
|
| + // Ensure that the first audio and video pts are close to each other and are
|
| + // reported at the close moments in time.
|
| +
|
| + EXPECT_TRUE(manager_.HasFirstFrame(DemuxerStream::AUDIO));
|
| + EXPECT_TRUE(WaitForCondition(
|
| + base::Bind(&MockMediaPlayerManager::HasFirstFrame,
|
| + base::Unretained(&manager_), DemuxerStream::VIDEO)));
|
| +
|
| + // Wait for some more video
|
| + WaitForDelay(base::TimeDelta::FromMilliseconds(100));
|
| +
|
| + EXPECT_TRUE(AlmostEqual(manager_.FirstFramePTS(DemuxerStream::AUDIO),
|
| + manager_.FirstFramePTS(DemuxerStream::VIDEO), 25));
|
| +
|
| + // Because for video preroll the first frame after preroll renders during the
|
| + // preroll stage (and not after the preroll is done) we cannot guarantee the
|
| + // proper video timimg in this test.
|
| + // TODO(timav): maybe we should not call the testing callback for
|
| + // kRenderAfterPreroll for video (for audio we already do not call).
|
| + // EXPECT_TRUE(AlmostEqual(manager_.FirstFrameTime(DemuxerStream::AUDIO),
|
| + // manager_.FirstFrameTime(DemuxerStream::VIDEO), 50));
|
| +
|
| + // The playback should start at |seek_position|
|
| + EXPECT_TRUE(AlmostEqual(seek_position, manager_.pts_stat_.min(), 25));
|
| +}
|
| +
|
| } // namespace media
|
|
|