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 <limits> | 7 #include <limits> |
8 | 8 |
9 #include "base/android/jni_android.h" | 9 #include "base/android/jni_android.h" |
10 #include "base/android/jni_string.h" | 10 #include "base/android/jni_string.h" |
(...skipping 324 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
335 return; | 335 return; |
336 | 336 |
337 ClearPendingEvent(SEEK_EVENT_PENDING); | 337 ClearPendingEvent(SEEK_EVENT_PENDING); |
338 | 338 |
339 OnSeekComplete(); | 339 OnSeekComplete(); |
340 ProcessPendingEvents(); | 340 ProcessPendingEvents(); |
341 } | 341 } |
342 | 342 |
343 void MediaSourcePlayer::UpdateTimestamps( | 343 void MediaSourcePlayer::UpdateTimestamps( |
344 const base::TimeDelta& presentation_timestamp, size_t audio_output_bytes) { | 344 const base::TimeDelta& presentation_timestamp, size_t audio_output_bytes) { |
| 345 base::TimeDelta new_max_time = presentation_timestamp; |
| 346 |
345 if (audio_output_bytes > 0) { | 347 if (audio_output_bytes > 0) { |
346 audio_timestamp_helper_->AddFrames( | 348 audio_timestamp_helper_->AddFrames( |
347 audio_output_bytes / (kBytesPerAudioOutputSample * num_channels_)); | 349 audio_output_bytes / (kBytesPerAudioOutputSample * num_channels_)); |
348 clock_.SetMaxTime(audio_timestamp_helper_->GetTimestamp()); | 350 new_max_time = audio_timestamp_helper_->GetTimestamp(); |
349 } else { | |
350 clock_.SetMaxTime(presentation_timestamp); | |
351 } | 351 } |
352 | 352 |
| 353 clock_.SetMaxTime(new_max_time); |
353 OnTimeUpdated(); | 354 OnTimeUpdated(); |
354 } | 355 } |
355 | 356 |
356 void MediaSourcePlayer::ProcessPendingEvents() { | 357 void MediaSourcePlayer::ProcessPendingEvents() { |
357 DVLOG(1) << __FUNCTION__ << " : 0x" << std::hex << pending_event_; | 358 DVLOG(1) << __FUNCTION__ << " : 0x" << std::hex << pending_event_; |
358 // Wait for all the decoding jobs to finish before processing pending tasks. | 359 // Wait for all the decoding jobs to finish before processing pending tasks. |
359 if (video_decoder_job_ && video_decoder_job_->is_decoding()) { | 360 if (video_decoder_job_ && video_decoder_job_->is_decoding()) { |
360 DVLOG(1) << __FUNCTION__ << " : A video job is still decoding."; | 361 DVLOG(1) << __FUNCTION__ << " : A video job is still decoding."; |
361 return; | 362 return; |
362 } | 363 } |
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
417 // Now that all pending events have been handled, resume decoding if we are | 418 // Now that all pending events have been handled, resume decoding if we are |
418 // still playing. | 419 // still playing. |
419 if (playing_) | 420 if (playing_) |
420 StartInternal(); | 421 StartInternal(); |
421 } | 422 } |
422 | 423 |
423 void MediaSourcePlayer::MediaDecoderCallback( | 424 void MediaSourcePlayer::MediaDecoderCallback( |
424 bool is_audio, MediaCodecStatus status, | 425 bool is_audio, MediaCodecStatus status, |
425 const base::TimeDelta& presentation_timestamp, size_t audio_output_bytes) { | 426 const base::TimeDelta& presentation_timestamp, size_t audio_output_bytes) { |
426 DVLOG(1) << __FUNCTION__ << ": " << is_audio << ", " << status; | 427 DVLOG(1) << __FUNCTION__ << ": " << is_audio << ", " << status; |
427 if (is_audio) | 428 |
| 429 bool is_clock_manager = is_audio || !HasAudio(); |
| 430 |
| 431 if (is_clock_manager) |
428 decoder_starvation_callback_.Cancel(); | 432 decoder_starvation_callback_.Cancel(); |
429 | 433 |
430 if (status == MEDIA_CODEC_ERROR) { | 434 if (status == MEDIA_CODEC_ERROR) { |
431 Release(); | 435 Release(); |
432 OnMediaError(MEDIA_ERROR_DECODE); | 436 OnMediaError(MEDIA_ERROR_DECODE); |
433 return; | 437 return; |
434 } | 438 } |
435 | 439 |
436 if (pending_event_ != NO_EVENT_PENDING) { | 440 if (pending_event_ != NO_EVENT_PENDING) { |
437 ProcessPendingEvents(); | 441 ProcessPendingEvents(); |
438 return; | 442 return; |
439 } | 443 } |
440 | 444 |
441 if (status == MEDIA_CODEC_OK && (is_audio || !HasAudio())) { | |
442 UpdateTimestamps(presentation_timestamp, audio_output_bytes); | |
443 } | |
444 | |
445 if (status == MEDIA_CODEC_OUTPUT_END_OF_STREAM) { | 445 if (status == MEDIA_CODEC_OUTPUT_END_OF_STREAM) { |
446 PlaybackCompleted(is_audio); | 446 PlaybackCompleted(is_audio); |
447 return; | 447 return; |
448 } | 448 } |
449 | 449 |
| 450 if (status == MEDIA_CODEC_OK && is_clock_manager) |
| 451 UpdateTimestamps(presentation_timestamp, audio_output_bytes); |
| 452 |
450 if (!playing_) { | 453 if (!playing_) { |
451 if (is_audio || !HasAudio()) | 454 if (is_clock_manager) |
452 clock_.Pause(); | 455 clock_.Pause(); |
453 return; | 456 return; |
454 } | 457 } |
455 | 458 |
456 if (status == MEDIA_CODEC_NO_KEY) | 459 if (status == MEDIA_CODEC_NO_KEY) |
457 return; | 460 return; |
458 | 461 |
459 base::TimeDelta current_timestamp = GetCurrentTime(); | 462 if (status == MEDIA_CODEC_OK && is_clock_manager) |
| 463 StartStarvationCallback(presentation_timestamp); |
| 464 |
460 if (is_audio) { | 465 if (is_audio) { |
461 if (status == MEDIA_CODEC_OK) { | |
462 base::TimeDelta timeout = | |
463 audio_timestamp_helper_->GetTimestamp() - current_timestamp; | |
464 StartStarvationCallback(timeout); | |
465 } | |
466 DecodeMoreAudio(); | 466 DecodeMoreAudio(); |
467 return; | 467 return; |
468 } | 468 } |
469 | 469 |
470 if (!HasAudio() && status == MEDIA_CODEC_OK) { | |
471 DCHECK(current_timestamp <= presentation_timestamp); | |
472 // For video only streams, fps can be estimated from the difference | |
473 // between the previous and current presentation timestamps. The | |
474 // previous presentation timestamp is equal to current_timestamp. | |
475 // TODO(qinmin): determine whether 2 is a good coefficient for estimating | |
476 // video frame timeout. | |
477 StartStarvationCallback(2 * (presentation_timestamp - current_timestamp)); | |
478 } | |
479 | |
480 DecodeMoreVideo(); | 470 DecodeMoreVideo(); |
481 } | 471 } |
482 | 472 |
483 void MediaSourcePlayer::DecodeMoreAudio() { | 473 void MediaSourcePlayer::DecodeMoreAudio() { |
484 DVLOG(1) << __FUNCTION__; | 474 DVLOG(1) << __FUNCTION__; |
485 DCHECK(!audio_decoder_job_->is_decoding()); | 475 DCHECK(!audio_decoder_job_->is_decoding()); |
486 | 476 |
487 if (audio_decoder_job_->Decode( | 477 if (audio_decoder_job_->Decode( |
488 start_time_ticks_, start_presentation_timestamp_, base::Bind( | 478 start_time_ticks_, start_presentation_timestamp_, base::Bind( |
489 &MediaSourcePlayer::MediaDecoderCallback, | 479 &MediaSourcePlayer::MediaDecoderCallback, |
(...skipping 123 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
613 OnMediaMetadataChanged(duration_, width_, height_, true); | 603 OnMediaMetadataChanged(duration_, width_, height_, true); |
614 } | 604 } |
615 | 605 |
616 void MediaSourcePlayer::OnDecoderStarved() { | 606 void MediaSourcePlayer::OnDecoderStarved() { |
617 DVLOG(1) << __FUNCTION__; | 607 DVLOG(1) << __FUNCTION__; |
618 SetPendingEvent(PREFETCH_REQUEST_EVENT_PENDING); | 608 SetPendingEvent(PREFETCH_REQUEST_EVENT_PENDING); |
619 ProcessPendingEvents(); | 609 ProcessPendingEvents(); |
620 } | 610 } |
621 | 611 |
622 void MediaSourcePlayer::StartStarvationCallback( | 612 void MediaSourcePlayer::StartStarvationCallback( |
623 const base::TimeDelta& timeout) { | 613 const base::TimeDelta& presentation_timestamp) { |
624 DVLOG(1) << __FUNCTION__ << "(" << timeout.InSecondsF() << ")"; | 614 // 20ms was chosen because it is the typical size of a compressed audio frame. |
| 615 // Anything smaller than this would likely cause unnecessary cycling in and |
| 616 // out of the prefetch state. |
| 617 const base::TimeDelta kMinStarvationTimeout = |
| 618 base::TimeDelta::FromMilliseconds(20); |
| 619 |
| 620 base::TimeDelta current_timestamp = GetCurrentTime(); |
| 621 base::TimeDelta timeout; |
| 622 if (HasAudio()) { |
| 623 timeout = audio_timestamp_helper_->GetTimestamp() - current_timestamp; |
| 624 } else { |
| 625 DCHECK(current_timestamp <= presentation_timestamp); |
| 626 |
| 627 // For video only streams, fps can be estimated from the difference |
| 628 // between the previous and current presentation timestamps. The |
| 629 // previous presentation timestamp is equal to current_timestamp. |
| 630 // TODO(qinmin): determine whether 2 is a good coefficient for estimating |
| 631 // video frame timeout. |
| 632 timeout = 2 * (presentation_timestamp - current_timestamp); |
| 633 } |
| 634 |
| 635 timeout = std::max(timeout, kMinStarvationTimeout); |
625 | 636 |
626 decoder_starvation_callback_.Reset( | 637 decoder_starvation_callback_.Reset( |
627 base::Bind(&MediaSourcePlayer::OnDecoderStarved, | 638 base::Bind(&MediaSourcePlayer::OnDecoderStarved, |
628 weak_this_.GetWeakPtr())); | 639 weak_this_.GetWeakPtr())); |
629 base::MessageLoop::current()->PostDelayedTask( | 640 base::MessageLoop::current()->PostDelayedTask( |
630 FROM_HERE, decoder_starvation_callback_.callback(), timeout); | 641 FROM_HERE, decoder_starvation_callback_.callback(), timeout); |
631 } | 642 } |
632 | 643 |
633 void MediaSourcePlayer::SetVolumeInternal() { | 644 void MediaSourcePlayer::SetVolumeInternal() { |
634 if (audio_decoder_job_ && volume_ >= 0) | 645 if (audio_decoder_job_ && volume_ >= 0) |
(...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
696 | 707 |
697 void MediaSourcePlayer::ClearPendingEvent(PendingEventFlags event) { | 708 void MediaSourcePlayer::ClearPendingEvent(PendingEventFlags event) { |
698 DVLOG(1) << __FUNCTION__ << "(" << GetEventName(event) << ")"; | 709 DVLOG(1) << __FUNCTION__ << "(" << GetEventName(event) << ")"; |
699 DCHECK_NE(event, NO_EVENT_PENDING); | 710 DCHECK_NE(event, NO_EVENT_PENDING); |
700 DCHECK(IsEventPending(event)); | 711 DCHECK(IsEventPending(event)); |
701 | 712 |
702 pending_event_ &= ~event; | 713 pending_event_ &= ~event; |
703 } | 714 } |
704 | 715 |
705 } // namespace media | 716 } // namespace media |
OLD | NEW |