Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(778)

Unified Diff: media/base/android/media_source_player_unittest.cc

Issue 79283006: Let only seeks reset Android MSE stream playback completion (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Rebased and addresses PS3 comments Created 7 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: media/base/android/media_source_player_unittest.cc
diff --git a/media/base/android/media_source_player_unittest.cc b/media/base/android/media_source_player_unittest.cc
index 1da6641b83485f9240aca0355057cb990e7de8ca..e0cc4217e87a643453c617f3fc827c8e66985089 100644
--- a/media/base/android/media_source_player_unittest.cc
+++ b/media/base/android/media_source_player_unittest.cc
@@ -365,9 +365,12 @@ class MediaSourcePlayerTest : public testing::Test {
}
// Seek, including simulated receipt of |kAborted| read between SeekTo()
- // and OnDemuxerSeekDone(). Use this helper method only when the player
- // already has created the decoder job.
- void SeekPlayer(bool is_audio, const base::TimeDelta& seek_time) {
+ // and OnDemuxerSeekDone() if |abort| is true. Use this helper method only
+ // when the player already has created the decoder job. If |abort| is false,
+ // |is_audio| is ignored. |expected_new_data_requests| is compared to the
+ // actual increase in data request count due to the seek.
+ void SeekPlayer(bool is_audio, const base::TimeDelta& seek_time, bool abort,
+ int expected_new_data_requests) {
EXPECT_TRUE(GetMediaDecoderJob(is_audio));
int original_num_seeks = demuxer_->num_seek_requests();
@@ -377,23 +380,25 @@ class MediaSourcePlayerTest : public testing::Test {
// Instead behave as if the renderer has asked us to seek.
player_.SeekTo(seek_time);
- // Verify that the seek does not occur until previously outstanding data
- // request is satisfied.
- EXPECT_EQ(original_num_seeks, demuxer_->num_seek_requests());
+ if (abort) {
+ // Verify that the seek does not occur until previously outstanding data
+ // request is satisfied.
+ EXPECT_EQ(original_num_seeks, demuxer_->num_seek_requests());
- // Simulate seeking causes the demuxer to abort the outstanding read caused
- // by the seek.
- player_.OnDemuxerDataAvailable(CreateAbortedAck(is_audio));
+ // Simulate seeking causes the demuxer to abort the outstanding read
+ // caused by the seek.
+ player_.OnDemuxerDataAvailable(CreateAbortedAck(is_audio));
+ }
- // Verify that the seek is requested now that the outstanding read is
- // completed by aborted access unit.
+ // Verify that the seek is requested.
EXPECT_EQ(original_num_seeks + 1, demuxer_->num_seek_requests());
// Send back the seek done notification. This should trigger the player to
// call OnReadFromDemuxer() again.
EXPECT_EQ(original_num_data_requests, demuxer_->num_data_requests());
player_.OnDemuxerSeekDone(kNoTimestamp());
- EXPECT_EQ(original_num_data_requests + 1, demuxer_->num_data_requests());
+ EXPECT_EQ(original_num_data_requests + expected_new_data_requests,
+ demuxer_->num_data_requests());
// No other seek should have been requested.
EXPECT_EQ(original_num_seeks + 1, demuxer_->num_seek_requests());
@@ -673,7 +678,7 @@ TEST_F(MediaSourcePlayerTest, ReadFromDemuxerAfterSeek) {
StartAudioDecoderJob();
EXPECT_TRUE(GetMediaDecoderJob(true));
EXPECT_EQ(1, demuxer_->num_data_requests());
- SeekPlayer(true, base::TimeDelta());
+ SeekPlayer(true, base::TimeDelta(), true, 1);
EXPECT_EQ(2, demuxer_->num_data_requests());
}
@@ -917,13 +922,13 @@ TEST_F(MediaSourcePlayerTest, StartTimeTicksResetAfterDecoderUnderruns) {
EXPECT_LE(100.0, (current - previous).InMillisecondsF());
}
-TEST_F(MediaSourcePlayerTest, NoRequestForDataAfterInputEOS) {
+TEST_F(MediaSourcePlayerTest, SecondVideoDataIsEOSAndSeekPlusStartResumesPlay) {
SKIP_TEST_IF_MEDIA_CODEC_BRIDGE_IS_NOT_AVAILABLE();
- // Test MediaSourcePlayer will not request for new data after input EOS is
- // reached.
+ // Test MediaSourcePlayer can replay video after input EOS is reached.
CreateNextTextureAndSetVideoSurface();
StartVideoDecoderJob();
+
// Player should not seek the demuxer on setting initial surface.
EXPECT_EQ(0, demuxer_->num_seek_requests());
@@ -935,81 +940,263 @@ TEST_F(MediaSourcePlayerTest, NoRequestForDataAfterInputEOS) {
// Send EOS.
player_.OnDemuxerDataAvailable(CreateEOSAck(false));
+ EXPECT_FALSE(manager_.playback_completed());
message_loop_.Run();
- // No more request for data should be made.
+ EXPECT_TRUE(manager_.playback_completed());
EXPECT_EQ(2, demuxer_->num_data_requests());
- // Reconfirm no seek request has occurred.
- EXPECT_EQ(0, demuxer_->num_seek_requests());
+ // Playback should resume with further data request following seek and start.
+ SeekPlayer(false, base::TimeDelta(), false, 0);
+ StartVideoDecoderJob();
+ EXPECT_EQ(3, demuxer_->num_data_requests());
}
-TEST_F(MediaSourcePlayerTest, ReplayAfterInputEOS) {
+TEST_F(MediaSourcePlayerTest, FirstAudioDataIsEOSAndSeekPlusStartResumesPlay) {
SKIP_TEST_IF_MEDIA_CODEC_BRIDGE_IS_NOT_AVAILABLE();
- // Test MediaSourcePlayer can replay after input EOS is
- // reached.
- CreateNextTextureAndSetVideoSurface();
- StartVideoDecoderJob();
-
- // Player should not seek the demuxer on setting initial surface.
- EXPECT_EQ(0, demuxer_->num_seek_requests());
+ // Test decode of audio EOS buffer without any prior decode. See also
+ // http://b/11696552.
+ // Also tests that seeking+Start() after completing audio playback resumes
+ // playback.
+ Start(CreateAudioDemuxerConfigs(kCodecAAC));
+ EXPECT_TRUE(GetMediaDecoderJob(true));
EXPECT_EQ(1, demuxer_->num_data_requests());
- // Send the first input chunk.
- player_.OnDemuxerDataAvailable(CreateReadFromDemuxerAckForVideo());
+ player_.OnDemuxerDataAvailable(CreateEOSAck(true));
+ EXPECT_FALSE(manager_.playback_completed());
message_loop_.Run();
- EXPECT_EQ(2, demuxer_->num_data_requests());
+ EXPECT_TRUE(manager_.playback_completed());
+ EXPECT_EQ(1, demuxer_->num_data_requests());
- // Send EOS.
- player_.OnDemuxerDataAvailable(CreateEOSAck(false));
- message_loop_.Run();
- // No more request for data should be made.
+ // Playback should resume with further data request following seek and start.
+ SeekPlayer(true, base::TimeDelta(), false, 0);
+ Start(CreateAudioDemuxerConfigs(kCodecAAC));
EXPECT_EQ(2, demuxer_->num_data_requests());
+}
- // Initiate a seek. Skip requesting element seek of renderer.
- // Instead behave as if the renderer has asked us to seek.
- player_.SeekTo(base::TimeDelta());
+TEST_F(MediaSourcePlayerTest, FirstVideoDataAfterSeekIsEOS) {
+ SKIP_TEST_IF_MEDIA_CODEC_BRIDGE_IS_NOT_AVAILABLE();
+
+ // Test decode of video EOS buffer, just after seeking, without any prior
+ // decode (other than the simulated |kAborted| resulting from the seek
+ // process.)
+ CreateNextTextureAndSetVideoSurface();
StartVideoDecoderJob();
- EXPECT_EQ(1, demuxer_->num_seek_requests());
- player_.OnDemuxerSeekDone(kNoTimestamp());
- // Seek/Play after EOS should request more data.
- EXPECT_EQ(3, demuxer_->num_data_requests());
+ EXPECT_TRUE(GetMediaDecoderJob(false));
- // Reconfirm only 1 seek request has occurred.
- EXPECT_EQ(1, demuxer_->num_seek_requests());
+ SeekPlayer(false, base::TimeDelta(), true, 1);
+ EXPECT_EQ(2, demuxer_->num_data_requests());
+ player_.OnDemuxerDataAvailable(CreateEOSAck(false));
+ EXPECT_FALSE(manager_.playback_completed());
+ message_loop_.Run();
+ EXPECT_TRUE(manager_.playback_completed());
+ EXPECT_EQ(2, demuxer_->num_data_requests());
}
-TEST_F(MediaSourcePlayerTest, FirstDataIsEOS) {
+TEST_F(MediaSourcePlayerTest, FirstAudioDataAfterSeekIsEOS) {
SKIP_TEST_IF_MEDIA_CODEC_BRIDGE_IS_NOT_AVAILABLE();
- // Test decode of EOS buffer without any prior decode. See also
- // http://b/11696552.
+ // Test decode of audio EOS buffer, just after seeking, without any prior
+ // decode (other than the simulated |kAborted| resulting from the seek
+ // process.) See also http://b/11696552.
Start(CreateAudioDemuxerConfigs(kCodecAAC));
EXPECT_TRUE(GetMediaDecoderJob(true));
- EXPECT_EQ(1, demuxer_->num_data_requests());
+ SeekPlayer(true, base::TimeDelta(), true, 1);
+ EXPECT_EQ(2, demuxer_->num_data_requests());
player_.OnDemuxerDataAvailable(CreateEOSAck(true));
EXPECT_FALSE(manager_.playback_completed());
-
message_loop_.Run();
EXPECT_TRUE(manager_.playback_completed());
- EXPECT_EQ(1, demuxer_->num_data_requests());
+ EXPECT_EQ(2, demuxer_->num_data_requests());
}
-TEST_F(MediaSourcePlayerTest, FirstDataAfterSeekIsEOS) {
+TEST_F(MediaSourcePlayerTest, AV_PlaybackCompletionAcrossConfigChange) {
SKIP_TEST_IF_MEDIA_CODEC_BRIDGE_IS_NOT_AVAILABLE();
- // Test decode of EOS buffer, just after seeking, without any prior decode
- // (other than the simulated |kAborted| resulting from the seek process.)
- // See also http://b/11696552.
- Start(CreateAudioDemuxerConfigs(kCodecAAC));
- EXPECT_TRUE(GetMediaDecoderJob(true));
+ // Test that if one stream (audio) has completed decode of EOS and the other
+ // stream (video) processes config change, that subsequent video EOS completes
+ // A/V playback.
+ // Also tests that seeking+Start() after completing playback resumes playback.
+ Start(CreateAudioVideoDemuxerConfigs());
+ CreateNextTextureAndSetVideoSurface();
+ EXPECT_TRUE(GetMediaDecoderJob(true) && GetMediaDecoderJob(false));
+ EXPECT_EQ(2, demuxer_->num_data_requests());
+ player_.OnDemuxerDataAvailable(CreateEOSAck(true)); // Audio EOS
+ EXPECT_EQ(0, demuxer_->num_config_requests());
+ player_.OnDemuxerDataAvailable(CreateReadFromDemuxerAckWithConfigChanged(
+ false, 0)); // Video |kConfigChanged| as first unit.
+
+ while (GetMediaDecoderJob(true)->is_decoding() ||
+ GetMediaDecoderJob(false)->is_decoding()) {
+ message_loop_.RunUntilIdle();
+ }
- SeekPlayer(true, base::TimeDelta());
+ EXPECT_EQ(1, demuxer_->num_config_requests());
EXPECT_EQ(2, demuxer_->num_data_requests());
- player_.OnDemuxerDataAvailable(CreateEOSAck(true));
+ player_.OnDemuxerConfigsAvailable(CreateAudioVideoDemuxerConfigs());
+ EXPECT_EQ(3, demuxer_->num_data_requests());
+
+ // At no time after completing audio EOS decode, above, should the
+ // audio decoder job resume decoding.
+ EXPECT_FALSE(GetMediaDecoderJob(true)->is_decoding());
+ player_.OnDemuxerDataAvailable(CreateEOSAck(false)); // Video EOS
+ EXPECT_FALSE(GetMediaDecoderJob(true)->is_decoding());
+
+ // Decode the video EOS. Spot-check that audio decode doesn't resume.
+ EXPECT_FALSE(manager_.playback_completed());
+ do {
+ message_loop_.RunUntilIdle();
+ EXPECT_FALSE(GetMediaDecoderJob(true)->is_decoding());
+ } while (GetMediaDecoderJob(false)->is_decoding());
+
+ EXPECT_TRUE(manager_.playback_completed());
+ EXPECT_EQ(3, demuxer_->num_data_requests());
+
+ // Playback should resume with further data requests following seek and start.
+ SeekPlayer(true /* ignored */, base::TimeDelta(), false, 0);
+ Start(CreateAudioVideoDemuxerConfigs());
+ EXPECT_EQ(5, demuxer_->num_data_requests());
+}
+
+TEST_F(MediaSourcePlayerTest, VA_PlaybackCompletionAcrossConfigChange) {
+ SKIP_TEST_IF_MEDIA_CODEC_BRIDGE_IS_NOT_AVAILABLE();
+
+ // Test that if one stream (video) has completed decode of EOS and the other
+ // stream (audio) processes config change, that subsequent audio EOS completes
+ // A/V playback.
+ // Also tests that seeking+Start() after completing playback resumes playback.
+ Start(CreateAudioVideoDemuxerConfigs());
+ CreateNextTextureAndSetVideoSurface();
+ EXPECT_TRUE(GetMediaDecoderJob(true) && GetMediaDecoderJob(false));
+ EXPECT_EQ(2, demuxer_->num_data_requests());
+ player_.OnDemuxerDataAvailable(CreateEOSAck(false)); // Video EOS
+ EXPECT_EQ(0, demuxer_->num_config_requests());
+ player_.OnDemuxerDataAvailable(CreateReadFromDemuxerAckWithConfigChanged(
+ true, 0)); // Audio |kConfigChanged| as first unit.
+
+ while (GetMediaDecoderJob(true)->is_decoding() ||
+ GetMediaDecoderJob(false)->is_decoding()) {
+ message_loop_.RunUntilIdle();
+ }
+
+ // TODO(wolenetz/qinmin): Prevent redundant demuxer config request and change
+ // expectation to 1 here. See http://crbug.com/325528.
+ EXPECT_EQ(2, demuxer_->num_config_requests());
+ EXPECT_EQ(2, demuxer_->num_data_requests());
+ player_.OnDemuxerConfigsAvailable(CreateAudioVideoDemuxerConfigs());
+ EXPECT_EQ(3, demuxer_->num_data_requests());
+
+ // At no time after completing video EOS decode, above, should the
+ // video decoder job resume decoding.
+ EXPECT_FALSE(GetMediaDecoderJob(false)->is_decoding());
+ player_.OnDemuxerDataAvailable(CreateEOSAck(true)); // Audio EOS
+ EXPECT_FALSE(GetMediaDecoderJob(false)->is_decoding());
+
+ // Decode the audio EOS. Spot-check that video decode doesn't resume.
EXPECT_FALSE(manager_.playback_completed());
+ do {
+ message_loop_.RunUntilIdle();
+ EXPECT_FALSE(GetMediaDecoderJob(false)->is_decoding());
+ } while (GetMediaDecoderJob(true)->is_decoding());
+
+ EXPECT_TRUE(manager_.playback_completed());
+ EXPECT_EQ(3, demuxer_->num_data_requests());
+ // Playback should resume with further data requests following seek and start.
+ SeekPlayer(true /* ignored */, base::TimeDelta(), false, 0);
+ Start(CreateAudioVideoDemuxerConfigs());
+ EXPECT_EQ(5, demuxer_->num_data_requests());
+}
+
+TEST_F(MediaSourcePlayerTest, AV_NoPrefetchForFinishedVideoOnAudioStarvation) {
+ SKIP_TEST_IF_MEDIA_CODEC_BRIDGE_IS_NOT_AVAILABLE();
+
+ // Test that if one stream (video) has completed decode of EOS, prefetch
+ // resulting from player starvation occurs only for the other stream (audio),
+ // and responding to that prefetch with EOS completes A/V playback, even if
+ // another starvation occurs during the latter EOS's decode.
+ Start(CreateAudioVideoDemuxerConfigs());
+ CreateNextTextureAndSetVideoSurface();
+ EXPECT_TRUE(GetMediaDecoderJob(true) && GetMediaDecoderJob(false));
+ EXPECT_EQ(2, demuxer_->num_data_requests());
+ player_.OnDemuxerDataAvailable(CreateReadFromDemuxerAckForAudio(0));
+ player_.OnDemuxerDataAvailable(CreateEOSAck(false)); // Video EOS
+
+ // Wait until video EOS is processed and more data (assumed to be audio) is
+ // requested.
+ while (demuxer_->num_data_requests() < 3 ||
+ GetMediaDecoderJob(false)->is_decoding()) {
+ message_loop_.RunUntilIdle();
+ }
+
+ // Simulate decoder underrun to trigger prefetch while still decoding audio.
+ EXPECT_EQ(3, demuxer_->num_data_requests());
+ player_.OnDemuxerDataAvailable(CreateReadFromDemuxerAckForAudio(1));
+ EXPECT_TRUE(GetMediaDecoderJob(true)->is_decoding() &&
+ !GetMediaDecoderJob(false)->is_decoding());
+ TriggerPlayerStarvation();
+
+ // Complete the audio decode that was in progress when simulated player
+ // starvation was triggered. At no time after completing video EOS decode,
+ // above, should the video decoder job resume decoding.
+ while (GetMediaDecoderJob(true)->is_decoding()) {
+ EXPECT_FALSE(GetMediaDecoderJob(false)->is_decoding());
+ message_loop_.RunUntilIdle();
+ }
+ EXPECT_FALSE(GetMediaDecoderJob(false)->is_decoding());
+ EXPECT_EQ(4, demuxer_->num_data_requests());
+
+ player_.OnDemuxerDataAvailable(CreateEOSAck(true)); // Audio EOS
+ EXPECT_FALSE(GetMediaDecoderJob(false)->is_decoding());
+
+ // Simulate another decoder underrun to trigger prefetch while decoding EOS.
+ EXPECT_TRUE(GetMediaDecoderJob(true)->is_decoding());
+ TriggerPlayerStarvation();
+
+ EXPECT_FALSE(manager_.playback_completed());
+ message_loop_.Run();
+ EXPECT_TRUE(manager_.playback_completed());
+ EXPECT_EQ(4, demuxer_->num_data_requests());
+}
+
+TEST_F(MediaSourcePlayerTest, StarvationDuringVideoEOSDecode) {
+ SKIP_TEST_IF_MEDIA_CODEC_BRIDGE_IS_NOT_AVAILABLE();
+
+ // Test that video-only playback completes without further data requested when
+ // starvation occurs during EOS decode.
+ CreateNextTextureAndSetVideoSurface();
+ StartVideoDecoderJob();
+ player_.OnDemuxerDataAvailable(CreateReadFromDemuxerAckForVideo());
+ message_loop_.Run();
+ EXPECT_EQ(2, demuxer_->num_data_requests());
+
+ // Simulate decoder underrun to trigger prefetch while decoding EOS.
+ player_.OnDemuxerDataAvailable(CreateEOSAck(false)); // Video EOS
+ EXPECT_TRUE(GetMediaDecoderJob(false)->is_decoding());
+ TriggerPlayerStarvation();
+ EXPECT_FALSE(manager_.playback_completed());
+ message_loop_.Run();
+ EXPECT_TRUE(manager_.playback_completed());
+ EXPECT_EQ(2, demuxer_->num_data_requests());
+}
+
+TEST_F(MediaSourcePlayerTest, StarvationDuringAudioEOSDecode) {
+ SKIP_TEST_IF_MEDIA_CODEC_BRIDGE_IS_NOT_AVAILABLE();
+
+ // Test that audio-only playback completes without further data requested when
+ // starvation occurs during EOS decode.
+ StartAudioDecoderJob();
+ EXPECT_TRUE(GetMediaDecoderJob(true));
+ player_.OnDemuxerDataAvailable(CreateReadFromDemuxerAckForAudio(0));
+ message_loop_.Run();
+ EXPECT_EQ(2, demuxer_->num_data_requests());
+
+ // Simulate decoder underrun to trigger prefetch while decoding EOS.
+ player_.OnDemuxerDataAvailable(CreateEOSAck(true)); // Audio EOS
+ EXPECT_TRUE(GetMediaDecoderJob(true)->is_decoding());
+ TriggerPlayerStarvation();
+ EXPECT_FALSE(manager_.playback_completed());
message_loop_.Run();
EXPECT_TRUE(manager_.playback_completed());
EXPECT_EQ(2, demuxer_->num_data_requests());
@@ -1137,7 +1324,7 @@ TEST_F(MediaSourcePlayerTest, PrerollAudioAfterSeek) {
EXPECT_TRUE(GetMediaDecoderJob(true));
EXPECT_EQ(1, demuxer_->num_data_requests());
- SeekPlayer(true, base::TimeDelta::FromMilliseconds(100));
+ SeekPlayer(true, base::TimeDelta::FromMilliseconds(100), true, 1);
EXPECT_TRUE(IsPrerolling(true));
EXPECT_EQ(100.0, GetPrerollTimestamp().InMillisecondsF());
@@ -1168,7 +1355,7 @@ TEST_F(MediaSourcePlayerTest, PrerollVideoAfterSeek) {
EXPECT_TRUE(GetMediaDecoderJob(false));
EXPECT_EQ(1, demuxer_->num_data_requests());
- SeekPlayer(false, base::TimeDelta::FromMilliseconds(100));
+ SeekPlayer(false, base::TimeDelta::FromMilliseconds(100), true, 1);
EXPECT_TRUE(IsPrerolling(false));
EXPECT_EQ(100.0, GetPrerollTimestamp().InMillisecondsF());
@@ -1217,7 +1404,7 @@ TEST_F(MediaSourcePlayerTest, SeekingAfterCompletingPrerollRestartsPreroll) {
EXPECT_LT(0.0, player_.GetCurrentTime().InMillisecondsF());
EXPECT_FALSE(IsPrerolling(true));
- SeekPlayer(true, base::TimeDelta::FromMilliseconds(500));
+ SeekPlayer(true, base::TimeDelta::FromMilliseconds(500), true, 1);
// Prerolling should have begun again.
EXPECT_TRUE(IsPrerolling(true));
@@ -1250,7 +1437,7 @@ TEST_F(MediaSourcePlayerTest, PrerollContinuesAcrossReleaseAndStart) {
EXPECT_TRUE(GetMediaDecoderJob(true));
EXPECT_EQ(1, demuxer_->num_data_requests());
- SeekPlayer(true, base::TimeDelta::FromMilliseconds(100));
+ SeekPlayer(true, base::TimeDelta::FromMilliseconds(100), true, 1);
EXPECT_TRUE(IsPrerolling(true));
EXPECT_EQ(100.0, GetPrerollTimestamp().InMillisecondsF());
@@ -1307,7 +1494,7 @@ TEST_F(MediaSourcePlayerTest, PrerollContinuesAcrossConfigChange) {
EXPECT_TRUE(GetMediaDecoderJob(true));
EXPECT_EQ(1, demuxer_->num_data_requests());
- SeekPlayer(true, base::TimeDelta::FromMilliseconds(100));
+ SeekPlayer(true, base::TimeDelta::FromMilliseconds(100), true, 1);
EXPECT_TRUE(IsPrerolling(true));
EXPECT_EQ(100.0, GetPrerollTimestamp().InMillisecondsF());
« media/base/android/media_source_player.cc ('K') | « media/base/android/media_source_player.cc ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698