| 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 29 matching lines...) Expand all Loading... |
| 40 doing_browser_seek_(false), | 40 doing_browser_seek_(false), |
| 41 pending_seek_(false), | 41 pending_seek_(false), |
| 42 drm_bridge_(NULL), | 42 drm_bridge_(NULL), |
| 43 cdm_registration_id_(0), | 43 cdm_registration_id_(0), |
| 44 is_waiting_for_key_(false), | 44 is_waiting_for_key_(false), |
| 45 key_added_while_decode_pending_(false), | 45 key_added_while_decode_pending_(false), |
| 46 is_waiting_for_audio_decoder_(false), | 46 is_waiting_for_audio_decoder_(false), |
| 47 is_waiting_for_video_decoder_(false), | 47 is_waiting_for_video_decoder_(false), |
| 48 prerolling_(true), | 48 prerolling_(true), |
| 49 weak_factory_(this) { | 49 weak_factory_(this) { |
| 50 media_stat_.reset(new MediaStatistics()); |
| 51 |
| 50 audio_decoder_job_.reset(new AudioDecoderJob( | 52 audio_decoder_job_.reset(new AudioDecoderJob( |
| 51 base::Bind(&DemuxerAndroid::RequestDemuxerData, | 53 base::Bind(&DemuxerAndroid::RequestDemuxerData, |
| 52 base::Unretained(demuxer_.get()), | 54 base::Unretained(demuxer_.get()), |
| 53 DemuxerStream::AUDIO), | 55 DemuxerStream::AUDIO), |
| 54 base::Bind(&MediaSourcePlayer::OnDemuxerConfigsChanged, | 56 base::Bind(&MediaSourcePlayer::OnDemuxerConfigsChanged, |
| 55 weak_factory_.GetWeakPtr()))); | 57 weak_factory_.GetWeakPtr()), |
| 58 &media_stat_->audio_frame_stats())); |
| 56 video_decoder_job_.reset(new VideoDecoderJob( | 59 video_decoder_job_.reset(new VideoDecoderJob( |
| 57 base::Bind(&DemuxerAndroid::RequestDemuxerData, | 60 base::Bind(&DemuxerAndroid::RequestDemuxerData, |
| 58 base::Unretained(demuxer_.get()), | 61 base::Unretained(demuxer_.get()), |
| 59 DemuxerStream::VIDEO), | 62 DemuxerStream::VIDEO), |
| 60 base::Bind(request_media_resources_cb_, player_id), | 63 base::Bind(request_media_resources_cb_, player_id), |
| 61 base::Bind(&MediaSourcePlayer::OnDemuxerConfigsChanged, | 64 base::Bind(&MediaSourcePlayer::OnDemuxerConfigsChanged, |
| 62 weak_factory_.GetWeakPtr()))); | 65 weak_factory_.GetWeakPtr()), |
| 66 &media_stat_->video_frame_stats())); |
| 67 |
| 63 demuxer_->Initialize(this); | 68 demuxer_->Initialize(this); |
| 64 interpolator_.SetUpperBound(base::TimeDelta()); | 69 interpolator_.SetUpperBound(base::TimeDelta()); |
| 65 weak_this_ = weak_factory_.GetWeakPtr(); | 70 weak_this_ = weak_factory_.GetWeakPtr(); |
| 66 } | 71 } |
| 67 | 72 |
| 68 MediaSourcePlayer::~MediaSourcePlayer() { | 73 MediaSourcePlayer::~MediaSourcePlayer() { |
| 69 Release(); | 74 Release(); |
| 70 DCHECK_EQ(!drm_bridge_, !cdm_registration_id_); | 75 DCHECK_EQ(!drm_bridge_, !cdm_registration_id_); |
| 71 if (drm_bridge_) { | 76 if (drm_bridge_) { |
| 72 drm_bridge_->UnregisterPlayer(cdm_registration_id_); | 77 drm_bridge_->UnregisterPlayer(cdm_registration_id_); |
| (...skipping 387 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 460 | 465 |
| 461 bool is_clock_manager = is_audio || !HasAudio(); | 466 bool is_clock_manager = is_audio || !HasAudio(); |
| 462 | 467 |
| 463 if (is_clock_manager) | 468 if (is_clock_manager) |
| 464 decoder_starvation_callback_.Cancel(); | 469 decoder_starvation_callback_.Cancel(); |
| 465 | 470 |
| 466 if (status == MEDIA_CODEC_ERROR) { | 471 if (status == MEDIA_CODEC_ERROR) { |
| 467 DVLOG(1) << __FUNCTION__ << " : decode error"; | 472 DVLOG(1) << __FUNCTION__ << " : decode error"; |
| 468 Release(); | 473 Release(); |
| 469 manager()->OnError(player_id(), MEDIA_ERROR_DECODE); | 474 manager()->OnError(player_id(), MEDIA_ERROR_DECODE); |
| 475 media_stat_->StopAndReport(GetCurrentTime()); |
| 470 return; | 476 return; |
| 471 } | 477 } |
| 472 | 478 |
| 473 DCHECK(!IsEventPending(PREFETCH_DONE_EVENT_PENDING)); | 479 DCHECK(!IsEventPending(PREFETCH_DONE_EVENT_PENDING)); |
| 474 | 480 |
| 475 // Let |SEEK_EVENT_PENDING| (the highest priority event outside of | 481 // Let |SEEK_EVENT_PENDING| (the highest priority event outside of |
| 476 // |PREFETCH_DONE_EVENT_PENDING|) preempt output EOS detection here. Process | 482 // |PREFETCH_DONE_EVENT_PENDING|) preempt output EOS detection here. Process |
| 477 // any other pending events only after handling EOS detection. | 483 // any other pending events only after handling EOS detection. |
| 478 if (IsEventPending(SEEK_EVENT_PENDING)) { | 484 if (IsEventPending(SEEK_EVENT_PENDING)) { |
| 479 ProcessPendingEvents(); | 485 ProcessPendingEvents(); |
| 486 media_stat_->StopAndReport(GetCurrentTime()); |
| 480 return; | 487 return; |
| 481 } | 488 } |
| 482 | 489 |
| 483 if ((status == MEDIA_CODEC_OK || status == MEDIA_CODEC_INPUT_END_OF_STREAM) && | 490 if ((status == MEDIA_CODEC_OK || status == MEDIA_CODEC_INPUT_END_OF_STREAM) && |
| 484 is_clock_manager && current_presentation_timestamp != kNoTimestamp()) { | 491 is_clock_manager && current_presentation_timestamp != kNoTimestamp()) { |
| 485 UpdateTimestamps(current_presentation_timestamp, | 492 UpdateTimestamps(current_presentation_timestamp, |
| 486 max_presentation_timestamp); | 493 max_presentation_timestamp); |
| 487 } | 494 } |
| 488 | 495 |
| 489 if (status == MEDIA_CODEC_OUTPUT_END_OF_STREAM) { | 496 if (status == MEDIA_CODEC_OUTPUT_END_OF_STREAM) { |
| 490 PlaybackCompleted(is_audio); | 497 PlaybackCompleted(is_audio); |
| 491 if (is_clock_manager) | 498 if (is_clock_manager) |
| 492 interpolator_.StopInterpolating(); | 499 interpolator_.StopInterpolating(); |
| 493 } | 500 } |
| 494 | 501 |
| 495 if (pending_event_ != NO_EVENT_PENDING) { | 502 if (pending_event_ != NO_EVENT_PENDING) { |
| 496 ProcessPendingEvents(); | 503 ProcessPendingEvents(); |
| 497 return; | 504 return; |
| 498 } | 505 } |
| 499 | 506 |
| 500 if (status == MEDIA_CODEC_OUTPUT_END_OF_STREAM) | 507 if (status == MEDIA_CODEC_OUTPUT_END_OF_STREAM) { |
| 508 media_stat_->StopAndReport(GetCurrentTime()); |
| 501 return; | 509 return; |
| 510 } |
| 502 | 511 |
| 503 if (!playing_) { | 512 if (!playing_) { |
| 504 if (is_clock_manager) | 513 if (is_clock_manager) |
| 505 interpolator_.StopInterpolating(); | 514 interpolator_.StopInterpolating(); |
| 506 | 515 |
| 516 media_stat_->StopAndReport(GetCurrentTime()); |
| 507 return; | 517 return; |
| 508 } | 518 } |
| 509 | 519 |
| 510 if (status == MEDIA_CODEC_NO_KEY) { | 520 if (status == MEDIA_CODEC_NO_KEY) { |
| 511 if (key_added_while_decode_pending_) { | 521 if (key_added_while_decode_pending_) { |
| 512 DVLOG(2) << __FUNCTION__ << ": Key was added during decoding."; | 522 DVLOG(2) << __FUNCTION__ << ": Key was added during decoding."; |
| 513 ResumePlaybackAfterKeyAdded(); | 523 ResumePlaybackAfterKeyAdded(); |
| 514 } else { | 524 } else { |
| 515 is_waiting_for_key_ = true; | 525 is_waiting_for_key_ = true; |
| 516 manager()->OnWaitingForDecryptionKey(player_id()); | 526 manager()->OnWaitingForDecryptionKey(player_id()); |
| 527 media_stat_->StopAndReport(GetCurrentTime()); |
| 517 } | 528 } |
| 518 return; | 529 return; |
| 519 } | 530 } |
| 520 | 531 |
| 521 // If |key_added_while_decode_pending_| is true and both audio and video | 532 // If |key_added_while_decode_pending_| is true and both audio and video |
| 522 // decoding succeeded, we should clear |key_added_while_decode_pending_| here. | 533 // decoding succeeded, we should clear |key_added_while_decode_pending_| here. |
| 523 // But that would add more complexity into this function. If we don't clear it | 534 // But that would add more complexity into this function. If we don't clear it |
| 524 // here, the worst case would be we call ResumePlaybackAfterKeyAdded() when | 535 // here, the worst case would be we call ResumePlaybackAfterKeyAdded() when |
| 525 // we don't really have a new key. This should rarely happen and the | 536 // we don't really have a new key. This should rarely happen and the |
| 526 // performance impact should be pretty small. | 537 // performance impact should be pretty small. |
| 527 // TODO(qinmin/xhwang): This class is complicated because we handle both audio | 538 // TODO(qinmin/xhwang): This class is complicated because we handle both audio |
| 528 // and video in one file. If we separate them, we should be able to remove a | 539 // and video in one file. If we separate them, we should be able to remove a |
| 529 // lot of duplication. | 540 // lot of duplication. |
| 530 | 541 |
| 531 // If the status is MEDIA_CODEC_ABORT, stop decoding new data. The player is | 542 // If the status is MEDIA_CODEC_ABORT, stop decoding new data. The player is |
| 532 // in the middle of a seek or stop event and needs to wait for the IPCs to | 543 // in the middle of a seek or stop event and needs to wait for the IPCs to |
| 533 // come. | 544 // come. |
| 534 if (status == MEDIA_CODEC_ABORT) | 545 if (status == MEDIA_CODEC_ABORT) { |
| 546 media_stat_->StopAndReport(GetCurrentTime()); |
| 535 return; | 547 return; |
| 548 } |
| 536 | 549 |
| 537 if (prerolling_ && IsPrerollFinished(is_audio)) { | 550 if (prerolling_ && IsPrerollFinished(is_audio)) { |
| 538 if (IsPrerollFinished(!is_audio)) { | 551 if (IsPrerollFinished(!is_audio)) { |
| 539 prerolling_ = false; | 552 prerolling_ = false; |
| 540 StartInternal(); | 553 StartInternal(); |
| 541 } | 554 } |
| 542 return; | 555 return; |
| 543 } | 556 } |
| 544 | 557 |
| 545 if (is_clock_manager) { | 558 if (is_clock_manager) { |
| (...skipping 101 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 647 return audio_decoder_job_->OutputEOSReached() || !HasAudio(); | 660 return audio_decoder_job_->OutputEOSReached() || !HasAudio(); |
| 648 } | 661 } |
| 649 | 662 |
| 650 bool MediaSourcePlayer::VideoFinished() { | 663 bool MediaSourcePlayer::VideoFinished() { |
| 651 return video_decoder_job_->OutputEOSReached() || !HasVideo(); | 664 return video_decoder_job_->OutputEOSReached() || !HasVideo(); |
| 652 } | 665 } |
| 653 | 666 |
| 654 void MediaSourcePlayer::OnDecoderStarved() { | 667 void MediaSourcePlayer::OnDecoderStarved() { |
| 655 DVLOG(1) << __FUNCTION__; | 668 DVLOG(1) << __FUNCTION__; |
| 656 | 669 |
| 670 media_stat_->AddStarvation(); |
| 671 |
| 657 SetPendingEvent(PREFETCH_REQUEST_EVENT_PENDING); | 672 SetPendingEvent(PREFETCH_REQUEST_EVENT_PENDING); |
| 658 ProcessPendingEvents(); | 673 ProcessPendingEvents(); |
| 659 } | 674 } |
| 660 | 675 |
| 661 void MediaSourcePlayer::StartStarvationCallback( | 676 void MediaSourcePlayer::StartStarvationCallback( |
| 662 base::TimeDelta current_presentation_timestamp, | 677 base::TimeDelta current_presentation_timestamp, |
| 663 base::TimeDelta max_presentation_timestamp) { | 678 base::TimeDelta max_presentation_timestamp) { |
| 664 // 20ms was chosen because it is the typical size of a compressed audio frame. | 679 // 20ms was chosen because it is the typical size of a compressed audio frame. |
| 665 // Anything smaller than this would likely cause unnecessary cycling in and | 680 // Anything smaller than this would likely cause unnecessary cycling in and |
| 666 // out of the prefetch state. | 681 // out of the prefetch state. |
| (...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 713 } | 728 } |
| 714 | 729 |
| 715 if (!playing_) | 730 if (!playing_) |
| 716 return; | 731 return; |
| 717 | 732 |
| 718 start_time_ticks_ = base::TimeTicks::Now(); | 733 start_time_ticks_ = base::TimeTicks::Now(); |
| 719 start_presentation_timestamp_ = GetCurrentTime(); | 734 start_presentation_timestamp_ = GetCurrentTime(); |
| 720 if (!interpolator_.interpolating()) | 735 if (!interpolator_.interpolating()) |
| 721 interpolator_.StartInterpolating(); | 736 interpolator_.StartInterpolating(); |
| 722 | 737 |
| 738 media_stat_->Start(start_presentation_timestamp_); |
| 739 |
| 723 if (!AudioFinished()) | 740 if (!AudioFinished()) |
| 724 DecodeMoreAudio(); | 741 DecodeMoreAudio(); |
| 725 | 742 |
| 726 if (!VideoFinished()) | 743 if (!VideoFinished()) |
| 727 DecodeMoreVideo(); | 744 DecodeMoreVideo(); |
| 728 } | 745 } |
| 729 | 746 |
| 730 void MediaSourcePlayer::OnDemuxerConfigsChanged() { | 747 void MediaSourcePlayer::OnDemuxerConfigsChanged() { |
| 731 manager()->OnMediaMetadataChanged( | 748 manager()->OnMediaMetadataChanged( |
| 732 player_id(), duration_, GetVideoWidth(), GetVideoHeight(), true); | 749 player_id(), duration_, GetVideoWidth(), GetVideoHeight(), true); |
| (...skipping 84 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 817 // support setMediaKeys(0) (see http://crbug.com/330324), or when we release | 834 // support setMediaKeys(0) (see http://crbug.com/330324), or when we release |
| 818 // MediaDrm when the video is paused, or when the device goes to sleep (see | 835 // MediaDrm when the video is paused, or when the device goes to sleep (see |
| 819 // http://crbug.com/272421). | 836 // http://crbug.com/272421). |
| 820 audio_decoder_job_->SetDrmBridge(NULL); | 837 audio_decoder_job_->SetDrmBridge(NULL); |
| 821 video_decoder_job_->SetDrmBridge(NULL); | 838 video_decoder_job_->SetDrmBridge(NULL); |
| 822 cdm_registration_id_ = 0; | 839 cdm_registration_id_ = 0; |
| 823 drm_bridge_ = NULL; | 840 drm_bridge_ = NULL; |
| 824 } | 841 } |
| 825 | 842 |
| 826 } // namespace media | 843 } // namespace media |
| OLD | NEW |