Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "media/base/android/media_source_player.h" | 5 #include "media/base/android/media_source_player.h" |
| 6 | 6 |
| 7 #include "base/android/jni_android.h" | 7 #include "base/android/jni_android.h" |
| 8 #include "base/android/jni_string.h" | 8 #include "base/android/jni_string.h" |
| 9 #include "base/barrier_closure.h" | 9 #include "base/barrier_closure.h" |
| 10 #include "base/basictypes.h" | 10 #include "base/basictypes.h" |
| (...skipping 134 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 145 base::TimeDelta MediaSourcePlayer::GetCurrentTime() { | 145 base::TimeDelta MediaSourcePlayer::GetCurrentTime() { |
| 146 return clock_.Elapsed(); | 146 return clock_.Elapsed(); |
| 147 } | 147 } |
| 148 | 148 |
| 149 base::TimeDelta MediaSourcePlayer::GetDuration() { | 149 base::TimeDelta MediaSourcePlayer::GetDuration() { |
| 150 return duration_; | 150 return duration_; |
| 151 } | 151 } |
| 152 | 152 |
| 153 void MediaSourcePlayer::Release() { | 153 void MediaSourcePlayer::Release() { |
| 154 DVLOG(1) << __FUNCTION__; | 154 DVLOG(1) << __FUNCTION__; |
| 155 ClearDecodingData(); | |
|
acolwell GONE FROM CHROMIUM
2013/08/30 18:27:38
Not needed since the jobs are getting Release()'ed
| |
| 156 audio_decoder_job_.reset(); | 155 audio_decoder_job_.reset(); |
| 157 video_decoder_job_.reset(); | 156 video_decoder_job_.reset(); |
| 158 reconfig_audio_decoder_ = false; | 157 reconfig_audio_decoder_ = false; |
| 159 reconfig_video_decoder_ = false; | 158 reconfig_video_decoder_ = false; |
| 160 playing_ = false; | 159 playing_ = false; |
| 161 pending_event_ = NO_EVENT_PENDING; | 160 pending_event_ = NO_EVENT_PENDING; |
| 162 surface_ = gfx::ScopedJavaSurface(); | 161 surface_ = gfx::ScopedJavaSurface(); |
| 163 ReleaseMediaResourcesFromManager(); | 162 ReleaseMediaResourcesFromManager(); |
| 164 } | 163 } |
| 165 | 164 |
| (...skipping 144 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 310 return; | 309 return; |
| 311 | 310 |
| 312 ClearPendingEvent(SEEK_EVENT_PENDING); | 311 ClearPendingEvent(SEEK_EVENT_PENDING); |
| 313 | 312 |
| 314 OnSeekComplete(); | 313 OnSeekComplete(); |
| 315 ProcessPendingEvents(); | 314 ProcessPendingEvents(); |
| 316 } | 315 } |
| 317 | 316 |
| 318 void MediaSourcePlayer::UpdateTimestamps( | 317 void MediaSourcePlayer::UpdateTimestamps( |
| 319 const base::TimeDelta& presentation_timestamp, size_t audio_output_bytes) { | 318 const base::TimeDelta& presentation_timestamp, size_t audio_output_bytes) { |
| 319 base::TimeDelta new_max_time = presentation_timestamp; | |
| 320 | |
| 320 if (audio_output_bytes > 0) { | 321 if (audio_output_bytes > 0) { |
| 321 audio_timestamp_helper_->AddFrames( | 322 audio_timestamp_helper_->AddFrames( |
| 322 audio_output_bytes / (kBytesPerAudioOutputSample * num_channels_)); | 323 audio_output_bytes / (kBytesPerAudioOutputSample * num_channels_)); |
| 323 clock_.SetMaxTime(audio_timestamp_helper_->GetTimestamp()); | 324 new_max_time = audio_timestamp_helper_->GetTimestamp(); |
| 324 } else { | |
| 325 clock_.SetMaxTime(presentation_timestamp); | |
| 326 } | 325 } |
| 327 | 326 |
| 327 clock_.SetMaxTime(new_max_time); | |
| 328 OnTimeUpdated(); | 328 OnTimeUpdated(); |
| 329 } | 329 } |
| 330 | 330 |
| 331 void MediaSourcePlayer::ProcessPendingEvents() { | 331 void MediaSourcePlayer::ProcessPendingEvents() { |
| 332 DVLOG(1) << __FUNCTION__ << " : 0x" | 332 DVLOG(1) << __FUNCTION__ << " : 0x" |
| 333 << std::hex << pending_event_; | 333 << std::hex << pending_event_; |
| 334 // Wait for all the decoding jobs to finish before processing pending tasks. | 334 // Wait for all the decoding jobs to finish before processing pending tasks. |
| 335 if ((audio_decoder_job_ && audio_decoder_job_->is_decoding()) || | 335 if ((audio_decoder_job_ && audio_decoder_job_->is_decoding()) || |
| 336 (video_decoder_job_ && video_decoder_job_->is_decoding())) { | 336 (video_decoder_job_ && video_decoder_job_->is_decoding())) { |
| 337 DVLOG(1) << __FUNCTION__ << " : A job is still decoding."; | 337 DVLOG(1) << __FUNCTION__ << " : A job is still decoding."; |
| (...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 389 // Now that all pending events have been handled, resume decoding if we are | 389 // Now that all pending events have been handled, resume decoding if we are |
| 390 // still playing. | 390 // still playing. |
| 391 if (playing_) | 391 if (playing_) |
| 392 StartInternal(); | 392 StartInternal(); |
| 393 } | 393 } |
| 394 | 394 |
| 395 void MediaSourcePlayer::MediaDecoderCallback( | 395 void MediaSourcePlayer::MediaDecoderCallback( |
| 396 bool is_audio, MediaDecoderJob::DecodeStatus decode_status, | 396 bool is_audio, MediaDecoderJob::DecodeStatus decode_status, |
| 397 const base::TimeDelta& presentation_timestamp, size_t audio_output_bytes) { | 397 const base::TimeDelta& presentation_timestamp, size_t audio_output_bytes) { |
| 398 DVLOG(1) << __FUNCTION__; | 398 DVLOG(1) << __FUNCTION__; |
| 399 if (is_audio) | 399 |
| 400 bool is_clock_manager = is_audio || !HasAudio(); | |
| 401 | |
| 402 if (is_clock_manager) | |
|
acolwell GONE FROM CHROMIUM
2013/08/30 18:27:38
The starvation callback gets scheduled in the vide
| |
| 400 decoder_starvation_callback_.Cancel(); | 403 decoder_starvation_callback_.Cancel(); |
| 401 | 404 |
| 402 if (decode_status == MediaDecoderJob::DECODE_FAILED) { | 405 if (decode_status == MediaDecoderJob::DECODE_FAILED) { |
| 403 Release(); | 406 Release(); |
| 404 OnMediaError(MEDIA_ERROR_DECODE); | 407 OnMediaError(MEDIA_ERROR_DECODE); |
| 405 return; | 408 return; |
| 406 } | 409 } |
| 407 | 410 |
| 408 if (pending_event_ != NO_EVENT_PENDING) { | 411 if (pending_event_ != NO_EVENT_PENDING) { |
| 409 ProcessPendingEvents(); | 412 ProcessPendingEvents(); |
| 410 return; | 413 return; |
| 411 } | 414 } |
| 412 | 415 |
| 413 if (decode_status == MediaDecoderJob::DECODE_SUCCEEDED && | |
|
qinmin
2013/08/30 22:27:43
why changing the order of these 2 if statement?
F
acolwell GONE FROM CHROMIUM
2013/09/06 00:34:55
The blocks are mutually exclusive. decode status c
qinmin
2013/09/06 00:56:33
Looks like this is a bug. When decode status is DE
| |
| 414 (is_audio || !HasAudio())) { | |
| 415 UpdateTimestamps(presentation_timestamp, audio_output_bytes); | |
| 416 } | |
| 417 | |
| 418 if (decode_status == MediaDecoderJob::DECODE_OUTPUT_END_OF_STREAM) { | 416 if (decode_status == MediaDecoderJob::DECODE_OUTPUT_END_OF_STREAM) { |
| 419 PlaybackCompleted(is_audio); | 417 PlaybackCompleted(is_audio); |
| 420 return; | 418 return; |
| 421 } | 419 } |
| 422 | 420 |
| 421 if (decode_status == MediaDecoderJob::DECODE_SUCCEEDED && is_clock_manager) | |
| 422 UpdateTimestamps(presentation_timestamp, audio_output_bytes); | |
| 423 | |
| 423 if (!playing_) { | 424 if (!playing_) { |
| 424 if (is_audio || !HasAudio()) | 425 if (is_clock_manager) |
| 425 clock_.Pause(); | 426 clock_.Pause(); |
| 426 return; | 427 return; |
| 427 } | 428 } |
| 428 | 429 |
| 429 base::TimeDelta current_timestamp = GetCurrentTime(); | 430 if (is_clock_manager && decode_status == MediaDecoderJob::DECODE_SUCCEEDED) |
| 431 StartStarvationCallback(presentation_timestamp); | |
| 432 | |
| 430 if (is_audio) { | 433 if (is_audio) { |
| 431 if (decode_status == MediaDecoderJob::DECODE_SUCCEEDED) { | 434 DecodeMoreAudio(); |
| 432 base::TimeDelta timeout = | |
| 433 audio_timestamp_helper_->GetTimestamp() - current_timestamp; | |
| 434 StartStarvationCallback(timeout); | |
| 435 } | |
| 436 DecodeMoreAudio(); | |
| 437 return; | 435 return; |
| 438 } | 436 } |
| 439 | 437 |
| 440 if (!HasAudio() && decode_status == MediaDecoderJob::DECODE_SUCCEEDED) { | |
| 441 DCHECK(current_timestamp <= presentation_timestamp); | |
| 442 // For video only streams, fps can be estimated from the difference | |
| 443 // between the previous and current presentation timestamps. The | |
| 444 // previous presentation timestamp is equal to current_timestamp. | |
| 445 // TODO(qinmin): determine whether 2 is a good coefficient for estimating | |
| 446 // video frame timeout. | |
| 447 StartStarvationCallback(2 * (presentation_timestamp - current_timestamp)); | |
| 448 } | |
| 449 | |
| 450 DecodeMoreVideo(); | 438 DecodeMoreVideo(); |
| 451 } | 439 } |
| 452 | 440 |
| 453 void MediaSourcePlayer::DecodeMoreAudio() { | 441 void MediaSourcePlayer::DecodeMoreAudio() { |
| 454 DVLOG(1) << __FUNCTION__; | 442 DVLOG(1) << __FUNCTION__; |
| 455 DCHECK(!audio_decoder_job_->is_decoding()); | 443 DCHECK(!audio_decoder_job_->is_decoding()); |
| 456 | 444 |
| 457 if (audio_decoder_job_->Decode( | 445 if (audio_decoder_job_->Decode( |
| 458 start_time_ticks_, start_presentation_timestamp_, base::Bind( | 446 start_time_ticks_, start_presentation_timestamp_, base::Bind( |
| 459 &MediaSourcePlayer::MediaDecoderCallback, | 447 &MediaSourcePlayer::MediaDecoderCallback, |
| (...skipping 123 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 583 OnMediaMetadataChanged(duration_, width_, height_, true); | 571 OnMediaMetadataChanged(duration_, width_, height_, true); |
| 584 } | 572 } |
| 585 | 573 |
| 586 void MediaSourcePlayer::OnDecoderStarved() { | 574 void MediaSourcePlayer::OnDecoderStarved() { |
| 587 DVLOG(1) << __FUNCTION__; | 575 DVLOG(1) << __FUNCTION__; |
| 588 SetPendingEvent(PREFETCH_REQUEST_EVENT_PENDING); | 576 SetPendingEvent(PREFETCH_REQUEST_EVENT_PENDING); |
| 589 ProcessPendingEvents(); | 577 ProcessPendingEvents(); |
| 590 } | 578 } |
| 591 | 579 |
| 592 void MediaSourcePlayer::StartStarvationCallback( | 580 void MediaSourcePlayer::StartStarvationCallback( |
| 593 const base::TimeDelta& timeout) { | 581 const base::TimeDelta& presentation_timestamp) { |
| 594 DVLOG(1) << __FUNCTION__ << "(" << timeout.InSecondsF() << ")"; | 582 // 20ms was chosen because it is the typical size of a compressed audio frame. |
| 583 // Anything smaller than this would likely cause unnecessary cycling in and | |
| 584 // out of the prefetch state. | |
| 585 const base::TimeDelta kMinStarvationTimeout = | |
| 586 base::TimeDelta::FromMilliseconds(20); | |
| 587 | |
| 588 base::TimeDelta current_timestamp = GetCurrentTime(); | |
| 589 base::TimeDelta timeout; | |
| 590 if (HasAudio()) { | |
| 591 timeout = audio_timestamp_helper_->GetTimestamp() - current_timestamp; | |
| 592 } else { | |
| 593 DCHECK(current_timestamp <= presentation_timestamp); | |
| 594 | |
| 595 // For video only streams, fps can be estimated from the difference | |
| 596 // between the previous and current presentation timestamps. The | |
| 597 // previous presentation timestamp is equal to current_timestamp. | |
| 598 // TODO(qinmin): determine whether 2 is a good coefficient for estimating | |
| 599 // video frame timeout. | |
| 600 timeout = 2 * (presentation_timestamp - current_timestamp); | |
| 601 } | |
| 602 | |
| 603 timeout = std::max(timeout, kMinStarvationTimeout); | |
|
acolwell GONE FROM CHROMIUM
2013/08/30 18:27:38
This fixes a bug that was in the code where it wou
| |
| 595 | 604 |
| 596 decoder_starvation_callback_.Reset( | 605 decoder_starvation_callback_.Reset( |
| 597 base::Bind(&MediaSourcePlayer::OnDecoderStarved, | 606 base::Bind(&MediaSourcePlayer::OnDecoderStarved, |
| 598 weak_this_.GetWeakPtr())); | 607 weak_this_.GetWeakPtr())); |
| 599 base::MessageLoop::current()->PostDelayedTask( | 608 base::MessageLoop::current()->PostDelayedTask( |
| 600 FROM_HERE, decoder_starvation_callback_.callback(), timeout); | 609 FROM_HERE, decoder_starvation_callback_.callback(), timeout); |
| 601 } | 610 } |
| 602 | 611 |
| 603 void MediaSourcePlayer::SetVolumeInternal() { | 612 void MediaSourcePlayer::SetVolumeInternal() { |
| 604 if (audio_decoder_job_ && volume_ >= 0) | 613 if (audio_decoder_job_ && volume_ >= 0) |
| (...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 666 | 675 |
| 667 void MediaSourcePlayer::ClearPendingEvent(PendingEventFlags event) { | 676 void MediaSourcePlayer::ClearPendingEvent(PendingEventFlags event) { |
| 668 DVLOG(1) << __FUNCTION__ << "(" << GetEventName(event) << ")"; | 677 DVLOG(1) << __FUNCTION__ << "(" << GetEventName(event) << ")"; |
| 669 DCHECK_NE(event, NO_EVENT_PENDING); | 678 DCHECK_NE(event, NO_EVENT_PENDING); |
| 670 DCHECK(IsEventPending(event)); | 679 DCHECK(IsEventPending(event)); |
| 671 | 680 |
| 672 pending_event_ &= ~event; | 681 pending_event_ &= ~event; |
| 673 } | 682 } |
| 674 | 683 |
| 675 } // namespace media | 684 } // namespace media |
| OLD | NEW |