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()); |