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 af65f059f099cd5dced88c820734becf2595d5db..c590a416c00a523973a86f9ed5adae52d7cf8edf 100644 |
--- a/media/base/android/media_codec_player_unittest.cc |
+++ b/media/base/android/media_codec_player_unittest.cc |
@@ -48,8 +48,10 @@ bool AlwaysFalse() { |
return false; |
} |
-// The method used to compare two TimeDelta values in expectations. |
-bool AlmostEqual(base::TimeDelta a, base::TimeDelta b, double tolerance_ms) { |
+// The method used to compare two time values of type T in expectations. |
+// Type T requires that a difference of type base::TimeDelta is defined. |
+template <typename T> |
+bool AlmostEqual(T a, T b, double tolerance_ms) { |
return (a - b).magnitude().InMilliseconds() <= tolerance_ms; |
} |
@@ -66,6 +68,8 @@ class MockMediaPlayerManager : public MediaPlayerManager { |
MediaResourceGetter* GetMediaResourceGetter() override { return nullptr; } |
MediaUrlInterceptor* GetMediaUrlInterceptor() override { return nullptr; } |
+ // Regular time update callback, reports current playback time to |
+ // MediaPlayerManager. |
void OnTimeUpdate(int player_id, |
base::TimeDelta current_timestamp, |
base::TimeTicks current_time_ticks) override { |
@@ -103,6 +107,24 @@ class MockMediaPlayerManager : public MediaPlayerManager { |
void OnMediaResourcesRequested(int player_id) {} |
+ // Time update callback that reports the internal progress of the stream. |
+ // Implementation dependent, used for testing only. |
+ void OnDecodersTimeUpdate(DemuxerStream::Type stream_type, |
+ base::TimeDelta now_playing, |
+ base::TimeDelta last_buffered) { |
+ PTSTime& hit = first_frame_hit_[stream_type]; |
+ if (hit.is_null()) |
+ hit = PTSTime(now_playing, base::TimeTicks::Now()); |
+ } |
+ |
+ // First frame information |
+ base::TimeDelta FirstFramePTS(DemuxerStream::Type stream_type) const { |
+ return first_frame_hit_[stream_type].pts; |
+ } |
+ base::TimeTicks FirstFrameTime(DemuxerStream::Type stream_type) const { |
+ return first_frame_hit_[stream_type].time; |
+ } |
+ |
base::WeakPtr<MockMediaPlayerManager> GetWeakPtr() { |
return weak_ptr_factory_.GetWeakPtr(); |
} |
@@ -115,6 +137,9 @@ class MockMediaPlayerManager : public MediaPlayerManager { |
return pts_stat_.max() > pts; |
} |
bool IsSeekCompleted() const { return num_seeks_completed_ > 0; } |
+ bool HasFirstFrame(DemuxerStream::Type stream_type) const { |
+ return !first_frame_hit_[stream_type].is_null(); |
+ } |
struct MediaMetadata { |
base::TimeDelta duration; |
@@ -131,6 +156,15 @@ class MockMediaPlayerManager : public MediaPlayerManager { |
bool playback_completed_; |
int num_seeks_completed_; |
+ struct PTSTime { |
+ base::TimeDelta pts; |
+ base::TimeTicks time; |
+ PTSTime() : pts(), time() {} |
+ PTSTime(base::TimeDelta p, base::TimeTicks t) : pts(p), time(t) {} |
+ bool is_null() const { return time.is_null(); } |
+ }; |
+ PTSTime first_frame_hit_[DemuxerStream::NUM_TYPES]; |
+ |
base::WeakPtrFactory<MockMediaPlayerManager> weak_ptr_factory_; |
DISALLOW_COPY_AND_ASSIGN(MockMediaPlayerManager); |
@@ -237,7 +271,7 @@ class MockDemuxerAndroid : public DemuxerAndroid { |
// DemuxerAndroid implementation |
void Initialize(DemuxerAndroidClient* client) override; |
void RequestDemuxerData(DemuxerStream::Type type) override; |
- void RequestDemuxerSeek(const base::TimeDelta& time_to_seek, |
+ void RequestDemuxerSeek(const base::TimeDelta& seek_request, |
bool is_browser_seek) override; |
// Sets the audio data factory. |
@@ -250,6 +284,20 @@ class MockDemuxerAndroid : public DemuxerAndroid { |
video_factory_ = factory.Pass(); |
} |
+ // Accessors for data factories. |
+ AudioFactory* audio_factory() const { return audio_factory_.get(); } |
+ VideoFactory* video_factory() const { return video_factory_.get(); } |
+ |
+ // Set the preroll interval after seek for audio stream. |
+ void SetAudioPrerollInterval(base::TimeDelta value) { |
+ audio_preroll_interval_ = value; |
+ } |
+ |
+ // Set the preroll interval after seek for video stream. |
+ void SetVideoPrerollInterval(base::TimeDelta value) { |
+ video_preroll_interval_ = value; |
+ } |
+ |
// Sets the delay in OnDemuxerSeekDone response. |
void SetSeekDoneDelay(base::TimeDelta delay) { seek_done_delay_ = delay; } |
@@ -270,6 +318,8 @@ class MockDemuxerAndroid : public DemuxerAndroid { |
scoped_ptr<DemuxerConfigs> pending_configs_; |
scoped_ptr<AudioFactory> audio_factory_; |
scoped_ptr<VideoFactory> video_factory_; |
+ base::TimeDelta audio_preroll_interval_; |
+ base::TimeDelta video_preroll_interval_; |
base::TimeDelta seek_done_delay_; |
int num_seeks_; |
int num_browser_seeks_; |
@@ -309,12 +359,17 @@ void MockDemuxerAndroid::RequestDemuxerData(DemuxerStream::Type type) { |
delay); |
} |
-void MockDemuxerAndroid::RequestDemuxerSeek(const base::TimeDelta& time_to_seek, |
+void MockDemuxerAndroid::RequestDemuxerSeek(const base::TimeDelta& seek_request, |
bool is_browser_seek) { |
// Tell data factories to start next chunk with the new timestamp. |
- if (audio_factory_) |
+ if (audio_factory_) { |
+ base::TimeDelta time_to_seek = |
+ std::max(base::TimeDelta(), seek_request - audio_preroll_interval_); |
audio_factory_->SeekTo(time_to_seek); |
+ } |
if (video_factory_) { |
+ base::TimeDelta time_to_seek = |
+ std::max(base::TimeDelta(), seek_request - video_preroll_interval_); |
video_factory_->SeekTo(time_to_seek); |
video_factory_->RequestKeyFrame(); |
} |
@@ -326,7 +381,7 @@ void MockDemuxerAndroid::RequestDemuxerSeek(const base::TimeDelta& time_to_seek, |
// Post OnDemuxerSeekDone() to the player. |
DCHECK(client_); |
base::TimeDelta reported_seek_time = |
- is_browser_seek ? time_to_seek : kNoTimestamp(); |
+ is_browser_seek ? seek_request : kNoTimestamp(); |
GetMediaTaskRunner()->PostDelayedTask( |
FROM_HERE, base::Bind(&DemuxerAndroidClient::OnDemuxerSeekDone, |
base::Unretained(client_), reported_seek_time), |
@@ -398,6 +453,14 @@ class MediaCodecPlayerTest : public testing::Test { |
// started. |
void StartVideoPlayback(base::TimeDelta duration); |
+ // 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(). |
+ void StartAVSeekAndPreroll(base::TimeDelta duration, |
+ base::TimeDelta seek_position, |
+ base::TimeDelta video_preroll); |
+ |
base::MessageLoop message_loop_; |
MockMediaPlayerManager manager_; |
MockDemuxerAndroid* demuxer_; // owned by player_ |
@@ -520,6 +583,47 @@ void MediaCodecPlayerTest::StartVideoPlayback(base::TimeDelta duration) { |
start_timeout)); |
} |
+void MediaCodecPlayerTest::StartAVSeekAndPreroll( |
+ base::TimeDelta duration, |
+ base::TimeDelta seek_position, |
+ base::TimeDelta video_preroll) { |
+ const base::TimeDelta start_timeout = base::TimeDelta::FromMilliseconds(800); |
+ |
+ demuxer_->SetVideoPrerollInterval(video_preroll); |
+ |
+ demuxer_->SetAudioFactory( |
+ scoped_ptr<AudioFactory>(new AudioFactory(duration))); |
+ demuxer_->SetVideoFactory( |
+ scoped_ptr<VideoFactory>(new VideoFactory(duration))); |
+ |
+ CreatePlayer(); |
+ SetVideoSurface(); |
+ |
+ // Set special testing callback to receive PTS from decoders. |
+ player_->SetDecodersTimeCallbackForTests( |
+ base::Bind(&MockMediaPlayerManager::OnDecodersTimeUpdate, |
+ base::Unretained(&manager_))); |
+ |
+ // Wait till the player is initialized on media thread. |
+ EXPECT_TRUE(WaitForCondition(base::Bind(&MockDemuxerAndroid::IsInitialized, |
+ base::Unretained(demuxer_)))); |
+ |
+ // Post configuration after the player has been initialized. |
+ demuxer_->PostInternalConfigs(); |
+ |
+ // Issue SeekTo(). |
+ player_->SeekTo(seek_position); |
+ |
+ // Start the playback. |
+ player_->Start(); |
+ |
+ // Wait till preroll starts. |
+ EXPECT_TRUE(WaitForCondition( |
+ base::Bind(&MediaCodecPlayer::IsPrerollingForTests, |
+ base::Unretained(player_), DemuxerStream::VIDEO), |
+ start_timeout)); |
+} |
+ |
TEST_F(MediaCodecPlayerTest, SetAudioConfigsBeforePlayerCreation) { |
// Post configuration when there is no player yet. |
EXPECT_EQ(nullptr, player_); |
@@ -1058,4 +1162,315 @@ TEST_F(MediaCodecPlayerTest, VideoReleaseWhileWaitingForSeek) { |
&MockMediaPlayerManager::IsSeekCompleted, base::Unretained(&manager_)))); |
} |
+TEST_F(MediaCodecPlayerTest, VideoPrerollAfterSeek) { |
+ SKIP_TEST_IF_MEDIA_CODEC_BRIDGE_IS_NOT_AVAILABLE(); |
+ |
+ // A simple test for preroll for video stream only. After the seek is done |
+ // the data factory generates the frames with pts before the seek time, and |
+ // they should not be rendered. We deduce which frame is rendered by looking |
+ // at the reported time progress. |
+ |
+ base::TimeDelta duration = base::TimeDelta::FromMilliseconds(600); |
+ base::TimeDelta seek_position = base::TimeDelta::FromMilliseconds(500); |
+ base::TimeDelta start_timeout = base::TimeDelta::FromMilliseconds(800); |
+ |
+ // Tell demuxer to make the first frame 100ms earlier than the seek request. |
+ demuxer_->SetVideoPrerollInterval(base::TimeDelta::FromMilliseconds(100)); |
+ |
+ demuxer_->SetVideoFactory( |
+ scoped_ptr<VideoFactory>(new VideoFactory(duration))); |
+ |
+ CreatePlayer(); |
+ SetVideoSurface(); |
+ |
+ // Wait till the player is initialized on media thread. |
+ EXPECT_TRUE(WaitForCondition(base::Bind(&MockDemuxerAndroid::IsInitialized, |
+ base::Unretained(demuxer_)))); |
+ |
+ // Post configuration after the player has been initialized. |
+ demuxer_->PostInternalConfigs(); |
+ |
+ // Issue SeekTo(). |
+ player_->SeekTo(seek_position); |
+ |
+ // Start the playback and make sure it is started. |
+ player_->Start(); |
+ |
+ EXPECT_TRUE( |
+ WaitForCondition(base::Bind(&MockMediaPlayerManager::IsPlaybackStarted, |
+ base::Unretained(&manager_)), |
+ start_timeout)); |
+ |
+ // Wait for completion. |
+ EXPECT_TRUE( |
+ WaitForCondition(base::Bind(&MockMediaPlayerManager::IsPlaybackCompleted, |
+ base::Unretained(&manager_)))); |
+ |
+ // The first pts should be equal than seek position even if video frames |
+ // started 100 ms eralier than the seek request. |
+ EXPECT_EQ(seek_position, manager_.pts_stat_.min()); |
+ |
+ EXPECT_EQ(6, manager_.pts_stat_.num_values()); |
+} |
+ |
+TEST_F(MediaCodecPlayerTest, AVPrerollAudioWaitsForVideo) { |
+ SKIP_TEST_IF_MEDIA_CODEC_BRIDGE_IS_NOT_AVAILABLE(); |
+ |
+ // Test that during prerolling neither audio nor video plays and that both |
+ // resume simultaneously after preroll is finished. In other words, test |
+ // that preroll works. |
+ // We put the video into the long preroll and intercept the time when first |
+ // rendering happens in each stream. The moment of rendering is approximated |
+ // with a decoder PTS that is delivered by a test-only callback. |
+ |
+ base::TimeDelta duration = base::TimeDelta::FromMilliseconds(2000); |
+ |
+ // Set significant preroll interval. 500 ms means 25 frames, at 10 ms |
+ // per frame it would take 250 ms to preroll. |
+ base::TimeDelta seek_position = base::TimeDelta::FromMilliseconds(1000); |
+ base::TimeDelta preroll_intvl = base::TimeDelta::FromMilliseconds(500); |
+ base::TimeDelta preroll_timeout = base::TimeDelta::FromMilliseconds(1000); |
+ |
+ StartAVSeekAndPreroll(duration, seek_position, preroll_intvl); |
+ |
+ // Wait till preroll finishes and the real playback starts. |
+ EXPECT_TRUE( |
+ WaitForCondition(base::Bind(&MockMediaPlayerManager::IsPlaybackStarted, |
+ base::Unretained(&manager_)), |
+ preroll_timeout)); |
+ |
+ // 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), 10)); |
+ |
+ 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(), 1)); |
+} |
+ |
+TEST_F(MediaCodecPlayerTest, AVPrerollReleaseAndRestart) { |
+ SKIP_TEST_IF_MEDIA_CODEC_BRIDGE_IS_NOT_AVAILABLE(); |
+ |
+ // Test that player will resume prerolling if prerolling is interrupted by |
+ // Release() and Start(). |
+ |
+ base::TimeDelta duration = base::TimeDelta::FromMilliseconds(2000); |
+ |
+ // Set significant preroll interval. 500 ms means 25 frames, at 10 ms |
+ // per frame it would take 250 ms to preroll. |
+ base::TimeDelta seek_position = base::TimeDelta::FromMilliseconds(1000); |
+ base::TimeDelta preroll_intvl = base::TimeDelta::FromMilliseconds(500); |
+ |
+ base::TimeDelta start_timeout = base::TimeDelta::FromMilliseconds(800); |
+ base::TimeDelta preroll_timeout = base::TimeDelta::FromMilliseconds(1000); |
+ |
+ StartAVSeekAndPreroll(duration, seek_position, preroll_intvl); |
+ |
+ // Issue Release(). |
+ player_->Release(); |
+ |
+ // Make sure we have not been playing. |
+ WaitForDelay(base::TimeDelta::FromMilliseconds(400)); |
+ |
+ EXPECT_FALSE(manager_.HasFirstFrame(DemuxerStream::AUDIO)); |
+ EXPECT_FALSE(manager_.HasFirstFrame(DemuxerStream::VIDEO)); |
+ |
+ EXPECT_FALSE(player_->IsPrerollingForTests(DemuxerStream::AUDIO)); |
+ EXPECT_FALSE(player_->IsPrerollingForTests(DemuxerStream::VIDEO)); |
+ EXPECT_EQ(0, manager_.pts_stat_.num_values()); |
+ |
+ // Restart. Release() removed the video surface, we need to set it again. |
+ SetVideoSurface(); |
+ player_->Start(); |
+ |
+ // The playback should pass through prerolling phase. |
+ EXPECT_TRUE(WaitForCondition( |
+ base::Bind(&MediaCodecPlayer::IsPrerollingForTests, |
+ base::Unretained(player_), DemuxerStream::VIDEO), |
+ start_timeout)); |
+ |
+ // Wait till preroll finishes and the real playback starts. |
+ EXPECT_TRUE( |
+ WaitForCondition(base::Bind(&MockMediaPlayerManager::IsPlaybackStarted, |
+ base::Unretained(&manager_)), |
+ preroll_timeout)); |
+ |
+ // 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), 10)); |
+ |
+ 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(), 1)); |
+} |
+ |
+TEST_F(MediaCodecPlayerTest, AVPrerollStopAndRestart) { |
+ SKIP_TEST_IF_MEDIA_CODEC_BRIDGE_IS_NOT_AVAILABLE(); |
+ |
+ // Test that if Pause() happens during the preroll phase, |
+ // we continue to do preroll after restart. |
+ |
+ base::TimeDelta duration = base::TimeDelta::FromMilliseconds(1200); |
+ |
+ // Set significant preroll interval. 500 ms means 25 frames, at 10 ms |
+ // per frame it would take 250 ms to preroll. |
+ base::TimeDelta seek_position = base::TimeDelta::FromMilliseconds(1000); |
+ base::TimeDelta preroll_intvl = base::TimeDelta::FromMilliseconds(500); |
+ |
+ base::TimeDelta start_timeout = base::TimeDelta::FromMilliseconds(800); |
+ base::TimeDelta preroll_timeout = base::TimeDelta::FromMilliseconds(1000); |
+ |
+ StartAVSeekAndPreroll(duration, seek_position, preroll_intvl); |
+ |
+ // Video stream should be prerolling. Request to stop. |
+ EXPECT_FALSE(IsPaused()); |
+ player_->Pause(true); |
+ |
+ EXPECT_TRUE(WaitForCondition( |
+ base::Bind(&MediaCodecPlayerTest::IsPaused, base::Unretained(this)))); |
+ |
+ // Test that we have not been playing. |
+ EXPECT_FALSE(manager_.HasFirstFrame(DemuxerStream::AUDIO)); |
+ EXPECT_FALSE(manager_.HasFirstFrame(DemuxerStream::VIDEO)); |
+ |
+ EXPECT_FALSE(player_->IsPrerollingForTests(DemuxerStream::AUDIO)); |
+ EXPECT_FALSE(player_->IsPrerollingForTests(DemuxerStream::VIDEO)); |
+ EXPECT_EQ(0, manager_.pts_stat_.num_values()); |
+ |
+ // Restart. |
+ player_->Start(); |
+ |
+ // There should be preroll after the start. |
+ EXPECT_TRUE(WaitForCondition( |
+ base::Bind(&MediaCodecPlayer::IsPrerollingForTests, |
+ base::Unretained(player_), DemuxerStream::VIDEO), |
+ start_timeout)); |
+ |
+ // Wait for a short period of time, so that preroll is still ongoing, |
+ // and pause again. |
+ WaitForDelay(base::TimeDelta::FromMilliseconds(100)); |
+ |
+ EXPECT_FALSE(IsPaused()); |
+ player_->Pause(true); |
+ |
+ EXPECT_TRUE(WaitForCondition( |
+ base::Bind(&MediaCodecPlayerTest::IsPaused, base::Unretained(this)))); |
+ |
+ // Check that we still haven't started rendering. |
+ EXPECT_FALSE(manager_.HasFirstFrame(DemuxerStream::AUDIO)); |
+ EXPECT_FALSE(manager_.HasFirstFrame(DemuxerStream::VIDEO)); |
+ |
+ EXPECT_FALSE(player_->IsPrerollingForTests(DemuxerStream::AUDIO)); |
+ EXPECT_FALSE(player_->IsPrerollingForTests(DemuxerStream::VIDEO)); |
+ EXPECT_EQ(0, manager_.pts_stat_.num_values()); |
+ |
+ // Restart again. |
+ player_->Start(); |
+ |
+ // Wait till we start to play. |
+ EXPECT_TRUE( |
+ WaitForCondition(base::Bind(&MockMediaPlayerManager::IsPlaybackStarted, |
+ base::Unretained(&manager_)), |
+ preroll_timeout)); |
+ |
+ // Check that we did prerolling, i.e. audio did wait for video. |
+ 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), 10)); |
+ |
+ 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(), 1)); |
+} |
+ |
+TEST_F(MediaCodecPlayerTest, AVPrerollVideoEndsWhilePrerolling) { |
+ SKIP_TEST_IF_MEDIA_CODEC_BRIDGE_IS_NOT_AVAILABLE(); |
+ |
+ // Test that when one stream ends in the preroll phase and another is not |
+ // the preroll finishes and playback continues after it. |
+ |
+ base::TimeDelta audio_duration = base::TimeDelta::FromMilliseconds(1100); |
+ base::TimeDelta video_duration = base::TimeDelta::FromMilliseconds(900); |
+ base::TimeDelta seek_position = base::TimeDelta::FromMilliseconds(1000); |
+ base::TimeDelta video_preroll_intvl = base::TimeDelta::FromMilliseconds(200); |
+ |
+ base::TimeDelta start_timeout = base::TimeDelta::FromMilliseconds(800); |
+ base::TimeDelta preroll_timeout = base::TimeDelta::FromMilliseconds(400); |
+ |
+ demuxer_->SetVideoPrerollInterval(video_preroll_intvl); |
+ |
+ demuxer_->SetAudioFactory( |
+ scoped_ptr<AudioFactory>(new AudioFactory(audio_duration))); |
+ demuxer_->SetVideoFactory( |
+ scoped_ptr<VideoFactory>(new VideoFactory(video_duration))); |
+ |
+ CreatePlayer(); |
+ SetVideoSurface(); |
+ |
+ // Set special testing callback to receive PTS from decoders. |
+ player_->SetDecodersTimeCallbackForTests( |
+ base::Bind(&MockMediaPlayerManager::OnDecodersTimeUpdate, |
+ base::Unretained(&manager_))); |
+ |
+ // Wait till the player is initialized on media thread. |
+ EXPECT_TRUE(WaitForCondition(base::Bind(&MockDemuxerAndroid::IsInitialized, |
+ base::Unretained(demuxer_)))); |
+ |
+ // Post configuration after the player has been initialized. |
+ demuxer_->PostInternalConfigs(); |
+ |
+ // Issue SeekTo(). |
+ player_->SeekTo(seek_position); |
+ |
+ // Start the playback. |
+ player_->Start(); |
+ |
+ // The video decoder should start prerolling |
+ // Wait till preroll starts. |
+ EXPECT_TRUE(WaitForCondition( |
+ base::Bind(&MediaCodecPlayer::IsPrerollingForTests, |
+ base::Unretained(player_), DemuxerStream::VIDEO), |
+ start_timeout)); |
+ |
+ // Wait for playback to start. |
+ EXPECT_TRUE( |
+ WaitForCondition(base::Bind(&MockMediaPlayerManager::IsPlaybackStarted, |
+ base::Unretained(&manager_)), |
+ preroll_timeout)); |
+ |
+ EXPECT_TRUE(manager_.HasFirstFrame(DemuxerStream::AUDIO)); |
+ |
+ // Play till completion. |
+ EXPECT_TRUE( |
+ WaitForCondition(base::Bind(&MockMediaPlayerManager::IsPlaybackCompleted, |
+ base::Unretained(&manager_)))); |
+ |
+ // There should not be any video frames. |
+ EXPECT_FALSE(manager_.HasFirstFrame(DemuxerStream::VIDEO)); |
+} |
+ |
} // namespace media |