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 |