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