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 |