Commit bbc15776 authored by qinmin's avatar qinmin Committed by Commit bot

Preroll decoders when video starts playing

When video starts playing, HTMLMediaElement no longer issues a seek(0) call.
As a result, decoders needs to be prerolled so that video and audio will start outputting frames at the same time.
This change also fixes an issue that when EOS is reached, the decoder does not clean up the prerolling state

internal b/17812723

BUG=

Review URL: https://codereview.chromium.org/638233002

Cr-Commit-Position: refs/heads/master@{#299006}
parent f08c3c1d
...@@ -116,7 +116,6 @@ bool MediaDecoderJob::Decode( ...@@ -116,7 +116,6 @@ bool MediaDecoderJob::Decode(
DCHECK(decode_cb_.is_null()); DCHECK(decode_cb_.is_null());
DCHECK(data_received_cb_.is_null()); DCHECK(data_received_cb_.is_null());
DCHECK(ui_task_runner_->BelongsToCurrentThread()); DCHECK(ui_task_runner_->BelongsToCurrentThread());
if (!media_codec_bridge_ || need_to_reconfig_decoder_job_) { if (!media_codec_bridge_ || need_to_reconfig_decoder_job_) {
need_to_reconfig_decoder_job_ = !CreateMediaCodecBridge(); need_to_reconfig_decoder_job_ = !CreateMediaCodecBridge();
if (drain_decoder_) { if (drain_decoder_) {
...@@ -511,8 +510,10 @@ void MediaDecoderJob::OnDecodeCompleted( ...@@ -511,8 +510,10 @@ void MediaDecoderJob::OnDecodeCompleted(
DCHECK(!decode_cb_.is_null()); DCHECK(!decode_cb_.is_null());
// If output was queued for rendering, then we have completed prerolling. // If output was queued for rendering, then we have completed prerolling.
if (current_presentation_timestamp != kNoTimestamp()) if (current_presentation_timestamp != kNoTimestamp() ||
status == MEDIA_CODEC_OUTPUT_END_OF_STREAM) {
prerolling_ = false; prerolling_ = false;
}
switch (status) { switch (status) {
case MEDIA_CODEC_OK: case MEDIA_CODEC_OK:
......
...@@ -44,7 +44,7 @@ MediaSourcePlayer::MediaSourcePlayer( ...@@ -44,7 +44,7 @@ MediaSourcePlayer::MediaSourcePlayer(
is_waiting_for_key_(false), is_waiting_for_key_(false),
is_waiting_for_audio_decoder_(false), is_waiting_for_audio_decoder_(false),
is_waiting_for_video_decoder_(false), is_waiting_for_video_decoder_(false),
prerolling_(false), prerolling_(true),
weak_factory_(this) { weak_factory_(this) {
audio_decoder_job_.reset(new AudioDecoderJob( audio_decoder_job_.reset(new AudioDecoderJob(
base::Bind(&DemuxerAndroid::RequestDemuxerData, base::Bind(&DemuxerAndroid::RequestDemuxerData,
......
...@@ -355,7 +355,10 @@ class MediaSourcePlayerTest : public testing::Test { ...@@ -355,7 +355,10 @@ class MediaSourcePlayerTest : public testing::Test {
new_current_time.InMilliseconds()); new_current_time.InMilliseconds());
current_time = new_current_time; current_time = new_current_time;
if (manager_.timestamp_updated()) { if (manager_.timestamp_updated()) {
EXPECT_LT(start_timestamp.InMillisecondsF(), // TODO(qinmin): the current time is from the decoder thread and it does
// not take the delay from posting the task into consideration.
// http://crbug.com/421616.
EXPECT_LE(start_timestamp.InMillisecondsF(),
new_current_time.InMillisecondsF()); new_current_time.InMillisecondsF());
return; return;
} }
...@@ -1178,9 +1181,9 @@ TEST_F(MediaSourcePlayerTest, StartTimeTicksResetAfterDecoderUnderruns) { ...@@ -1178,9 +1181,9 @@ TEST_F(MediaSourcePlayerTest, StartTimeTicksResetAfterDecoderUnderruns) {
DecodeAudioDataUntilOutputBecomesAvailable(); DecodeAudioDataUntilOutputBecomesAvailable();
// The decoder job should finish and a new request will be sent. // The decoder job should finish prerolling and start prefetching.
base::TimeTicks previous = StartTimeTicks();
player_.OnDemuxerDataAvailable(CreateReadFromDemuxerAckForAudio(3)); player_.OnDemuxerDataAvailable(CreateReadFromDemuxerAckForAudio(3));
base::TimeTicks previous = StartTimeTicks();
// Let the decoder starve. // Let the decoder starve.
TriggerPlayerStarvation(); TriggerPlayerStarvation();
...@@ -1738,6 +1741,12 @@ TEST_F(MediaSourcePlayerTest, SimultaneousAudioVideoConfigChange) { ...@@ -1738,6 +1741,12 @@ TEST_F(MediaSourcePlayerTest, SimultaneousAudioVideoConfigChange) {
EnableAdaptiveVideoPlayback(false); EnableAdaptiveVideoPlayback(false);
WaitForAudioVideoDecodeDone(); WaitForAudioVideoDecodeDone();
EXPECT_TRUE(IsPrerolling(true));
EXPECT_TRUE(IsPrerolling(false));
PrerollDecoderToTime(true, base::TimeDelta(), base::TimeDelta(), true);
PrerollDecoderToTime(false, base::TimeDelta(), base::TimeDelta(), false);
int expected_num_data_requests = demuxer_->num_data_requests();
// Simulate audio |kConfigChanged| prefetched as standalone access unit. // Simulate audio |kConfigChanged| prefetched as standalone access unit.
DemuxerConfigs audio_configs = CreateAudioDemuxerConfigs(kCodecVorbis, true); DemuxerConfigs audio_configs = CreateAudioDemuxerConfigs(kCodecVorbis, true);
player_.OnDemuxerDataAvailable( player_.OnDemuxerDataAvailable(
...@@ -1747,7 +1756,7 @@ TEST_F(MediaSourcePlayerTest, SimultaneousAudioVideoConfigChange) { ...@@ -1747,7 +1756,7 @@ TEST_F(MediaSourcePlayerTest, SimultaneousAudioVideoConfigChange) {
player_.OnDemuxerDataAvailable( player_.OnDemuxerDataAvailable(
CreateReadFromDemuxerAckWithConfigChanged( CreateReadFromDemuxerAckWithConfigChanged(
false, 0, CreateVideoDemuxerConfigs(true))); false, 0, CreateVideoDemuxerConfigs(true)));
EXPECT_EQ(6, demuxer_->num_data_requests()); EXPECT_EQ(expected_num_data_requests + 2, demuxer_->num_data_requests());
EXPECT_TRUE(IsDrainingDecoder(true)); EXPECT_TRUE(IsDrainingDecoder(true));
EXPECT_TRUE(IsDrainingDecoder(false)); EXPECT_TRUE(IsDrainingDecoder(false));
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment