Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(333)

Side by Side Diff: media/base/android/media_source_player.cc

Issue 196133020: Reducing the IPC latency for MSE video decoding (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 6 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
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 43 matching lines...) Expand 10 before | Expand all | Expand 10 after
54 is_video_encrypted_(false), 54 is_video_encrypted_(false),
55 volume_(-1.0), 55 volume_(-1.0),
56 clock_(&default_tick_clock_), 56 clock_(&default_tick_clock_),
57 next_video_data_is_iframe_(true), 57 next_video_data_is_iframe_(true),
58 doing_browser_seek_(false), 58 doing_browser_seek_(false),
59 pending_seek_(false), 59 pending_seek_(false),
60 reconfig_audio_decoder_(false), 60 reconfig_audio_decoder_(false),
61 reconfig_video_decoder_(false), 61 reconfig_video_decoder_(false),
62 weak_this_(this), 62 weak_this_(this),
63 drm_bridge_(NULL), 63 drm_bridge_(NULL),
64 is_waiting_for_key_(false) { 64 is_waiting_for_key_(false),
65 has_pending_audio_data_request_(false),
66 has_pending_video_data_request_(false) {
65 demuxer_->Initialize(this); 67 demuxer_->Initialize(this);
66 clock_.SetMaxTime(base::TimeDelta()); 68 clock_.SetMaxTime(base::TimeDelta());
67 } 69 }
68 70
69 MediaSourcePlayer::~MediaSourcePlayer() { 71 MediaSourcePlayer::~MediaSourcePlayer() {
70 Release(); 72 Release();
71 } 73 }
72 74
73 void MediaSourcePlayer::SetVideoSurface(gfx::ScopedJavaSurface surface) { 75 void MediaSourcePlayer::SetVideoSurface(gfx::ScopedJavaSurface surface) {
74 // For an empty surface, always pass it to the decoder job so that it 76 // For an empty surface, always pass it to the decoder job so that it
(...skipping 140 matching lines...) Expand 10 before | Expand all | Expand 10 after
215 // or drop data received across Release()+Start(). See http://crbug.com/306314 217 // or drop data received across Release()+Start(). See http://crbug.com/306314
216 // and http://crbug.com/304234. 218 // and http://crbug.com/304234.
217 bool process_pending_events = false; 219 bool process_pending_events = false;
218 process_pending_events = IsEventPending(PREFETCH_DONE_EVENT_PENDING) || 220 process_pending_events = IsEventPending(PREFETCH_DONE_EVENT_PENDING) ||
219 (audio_decoder_job_ && audio_decoder_job_->is_decoding()) || 221 (audio_decoder_job_ && audio_decoder_job_->is_decoding()) ||
220 (video_decoder_job_ && video_decoder_job_->is_decoding()); 222 (video_decoder_job_ && video_decoder_job_->is_decoding());
221 223
222 // Clear all the pending events except seeks and config changes. 224 // Clear all the pending events except seeks and config changes.
223 pending_event_ &= (SEEK_EVENT_PENDING | CONFIG_CHANGE_EVENT_PENDING); 225 pending_event_ &= (SEEK_EVENT_PENDING | CONFIG_CHANGE_EVENT_PENDING);
224 is_surface_in_use_ = false; 226 is_surface_in_use_ = false;
225 audio_decoder_job_.reset(); 227 ResetAudioDecoderJob();
226 ResetVideoDecoderJob(); 228 ResetVideoDecoderJob();
227 229
228 // Prevent job re-creation attempts in OnDemuxerConfigsAvailable() 230 // Prevent job re-creation attempts in OnDemuxerConfigsAvailable()
229 reconfig_audio_decoder_ = false; 231 reconfig_audio_decoder_ = false;
230 reconfig_video_decoder_ = false; 232 reconfig_video_decoder_ = false;
231 233
232 // Prevent player restart, including job re-creation attempts. 234 // Prevent player restart, including job re-creation attempts.
233 playing_ = false; 235 playing_ = false;
234 236
235 decoder_starvation_callback_.Cancel(); 237 decoder_starvation_callback_.Cancel();
(...skipping 102 matching lines...) Expand 10 before | Expand all | Expand 10 after
338 340
339 // Resume decoding after the config change if we are still playing. 341 // Resume decoding after the config change if we are still playing.
340 if (playing_) 342 if (playing_)
341 StartInternal(); 343 StartInternal();
342 } 344 }
343 } 345 }
344 346
345 void MediaSourcePlayer::OnDemuxerDataAvailable(const DemuxerData& data) { 347 void MediaSourcePlayer::OnDemuxerDataAvailable(const DemuxerData& data) {
346 DVLOG(1) << __FUNCTION__ << "(" << data.type << ")"; 348 DVLOG(1) << __FUNCTION__ << "(" << data.type << ")";
347 DCHECK_LT(0u, data.access_units.size()); 349 DCHECK_LT(0u, data.access_units.size());
350
351 if (has_pending_audio_data_request_ && data.type == DemuxerStream::AUDIO) {
wolenetz 2014/03/17 19:51:00 Do I understand correctly that we drop on the floo
qinmin 2014/03/18 18:58:58 Yes, the purpose of this is to drop the request th
352 has_pending_audio_data_request_ = false;
353 ProcessPendingEvents();
354 return;
355 }
356
357 if (has_pending_video_data_request_ && data.type == DemuxerStream::VIDEO) {
358 next_video_data_is_iframe_ = false;
359 has_pending_video_data_request_ = false;
360 ProcessPendingEvents();
361 return;
362 }
363
348 if (data.type == DemuxerStream::AUDIO && audio_decoder_job_) { 364 if (data.type == DemuxerStream::AUDIO && audio_decoder_job_) {
349 audio_decoder_job_->OnDataReceived(data); 365 audio_decoder_job_->OnDataReceived(data);
350 } else if (data.type == DemuxerStream::VIDEO) { 366 } else if (data.type == DemuxerStream::VIDEO) {
351 next_video_data_is_iframe_ = false; 367 next_video_data_is_iframe_ = false;
352 if (video_decoder_job_) 368 if (video_decoder_job_)
353 video_decoder_job_->OnDataReceived(data); 369 video_decoder_job_->OnDataReceived(data);
354 } 370 }
355 } 371 }
356 372
357 void MediaSourcePlayer::OnDemuxerDurationChanged(base::TimeDelta duration) { 373 void MediaSourcePlayer::OnDemuxerDurationChanged(base::TimeDelta duration) {
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after
411 DCHECK(doing_browser_seek_); 427 DCHECK(doing_browser_seek_);
412 pending_seek_ = false; 428 pending_seek_ = false;
413 SeekTo(pending_seek_time_); 429 SeekTo(pending_seek_time_);
414 return; 430 return;
415 } 431 }
416 432
417 // It is possible that a browser seek to I-frame had to seek to a buffered 433 // It is possible that a browser seek to I-frame had to seek to a buffered
418 // I-frame later than the requested one due to data removal or GC. Update 434 // I-frame later than the requested one due to data removal or GC. Update
419 // player clock to the actual seek target. 435 // player clock to the actual seek target.
420 if (doing_browser_seek_) { 436 if (doing_browser_seek_) {
421 DCHECK(actual_browser_seek_time != kNoTimestamp()); 437 base::TimeDelta seek_time = (actual_browser_seek_time == kNoTimestamp()) ?
438 base::TimeDelta() : actual_browser_seek_time;
422 // A browser seek must not jump into the past. Ideally, it seeks to the 439 // A browser seek must not jump into the past. Ideally, it seeks to the
423 // requested time, but it might jump into the future. 440 // requested time, but it might jump into the future.
424 DCHECK(actual_browser_seek_time >= GetCurrentTime()); 441 DCHECK(seek_time >= GetCurrentTime());
425 DVLOG(1) << __FUNCTION__ << " : setting clock to actual browser seek time: " 442 DVLOG(1) << __FUNCTION__ << " : setting clock to actual browser seek time: "
426 << actual_browser_seek_time.InSecondsF(); 443 << seek_time.InSecondsF();
427 clock_.SetTime(actual_browser_seek_time, actual_browser_seek_time); 444 clock_.SetTime(seek_time, seek_time);
428 if (audio_timestamp_helper_) 445 if (audio_timestamp_helper_)
429 audio_timestamp_helper_->SetBaseTimestamp(actual_browser_seek_time); 446 audio_timestamp_helper_->SetBaseTimestamp(seek_time);
430 } 447 }
431 448
432 reached_audio_eos_ = false; 449 reached_audio_eos_ = false;
433 reached_video_eos_ = false; 450 reached_video_eos_ = false;
434 451
435 base::TimeDelta current_time = GetCurrentTime(); 452 base::TimeDelta current_time = GetCurrentTime();
436 // TODO(qinmin): Simplify the logic by using |start_presentation_timestamp_| 453 // TODO(qinmin): Simplify the logic by using |start_presentation_timestamp_|
437 // to preroll media decoder jobs. Currently |start_presentation_timestamp_| 454 // to preroll media decoder jobs. Currently |start_presentation_timestamp_|
438 // is calculated from decoder output, while preroll relies on the access 455 // is calculated from decoder output, while preroll relies on the access
439 // unit's timestamp. There are some differences between the two. 456 // unit's timestamp. There are some differences between the two.
(...skipping 29 matching lines...) Expand all
469 if (video_decoder_job_ && video_decoder_job_->is_decoding()) { 486 if (video_decoder_job_ && video_decoder_job_->is_decoding()) {
470 DVLOG(1) << __FUNCTION__ << " : A video job is still decoding."; 487 DVLOG(1) << __FUNCTION__ << " : A video job is still decoding.";
471 return; 488 return;
472 } 489 }
473 490
474 if (audio_decoder_job_ && audio_decoder_job_->is_decoding()) { 491 if (audio_decoder_job_ && audio_decoder_job_->is_decoding()) {
475 DVLOG(1) << __FUNCTION__ << " : An audio job is still decoding."; 492 DVLOG(1) << __FUNCTION__ << " : An audio job is still decoding.";
476 return; 493 return;
477 } 494 }
478 495
496 if (has_pending_audio_data_request_ || has_pending_video_data_request_) {
497 DVLOG(1) << __FUNCTION__ << " : has pending data request.";
498 return;
499 }
500
479 if (IsEventPending(PREFETCH_DONE_EVENT_PENDING)) { 501 if (IsEventPending(PREFETCH_DONE_EVENT_PENDING)) {
480 DVLOG(1) << __FUNCTION__ << " : PREFETCH_DONE still pending."; 502 DVLOG(1) << __FUNCTION__ << " : PREFETCH_DONE still pending.";
481 return; 503 return;
482 } 504 }
483 505
484 if (IsEventPending(SEEK_EVENT_PENDING)) { 506 if (IsEventPending(SEEK_EVENT_PENDING)) {
485 DVLOG(1) << __FUNCTION__ << " : Handling SEEK_EVENT"; 507 DVLOG(1) << __FUNCTION__ << " : Handling SEEK_EVENT";
486 ClearDecodingData(); 508 ClearDecodingData();
487 demuxer_->RequestDemuxerSeek(GetCurrentTime(), doing_browser_seek_); 509 demuxer_->RequestDemuxerSeek(GetCurrentTime(), doing_browser_seek_);
488 return; 510 return;
(...skipping 14 matching lines...) Expand all
503 ConfigureVideoDecoderJob(); 525 ConfigureVideoDecoderJob();
504 526
505 // Return early if we can't successfully configure a new video decoder job 527 // Return early if we can't successfully configure a new video decoder job
506 // yet. 528 // yet.
507 if (HasVideo() && !video_decoder_job_) 529 if (HasVideo() && !video_decoder_job_)
508 return; 530 return;
509 } 531 }
510 532
511 if (IsEventPending(PREFETCH_REQUEST_EVENT_PENDING)) { 533 if (IsEventPending(PREFETCH_REQUEST_EVENT_PENDING)) {
512 DVLOG(1) << __FUNCTION__ << " : Handling PREFETCH_REQUEST_EVENT."; 534 DVLOG(1) << __FUNCTION__ << " : Handling PREFETCH_REQUEST_EVENT.";
535 // If one of the decoder is not initialized, cancel this event as it will be
wolenetz 2014/03/17 19:51:00 Were we hitting the DCHECK's below? In other words
qinmin 2014/03/18 18:58:58 This is possible with the new implementation. Cons
536 // called later when Start() is called again.
537 if ((HasVideo() && !video_decoder_job_) ||
538 (HasAudio() && !audio_decoder_job_)) {
539 ClearPendingEvent(PREFETCH_REQUEST_EVENT_PENDING);
540 return;
541 }
542
513 DCHECK(audio_decoder_job_ || AudioFinished()); 543 DCHECK(audio_decoder_job_ || AudioFinished());
514 DCHECK(video_decoder_job_ || VideoFinished()); 544 DCHECK(video_decoder_job_ || VideoFinished());
515 545
516 int count = (AudioFinished() ? 0 : 1) + (VideoFinished() ? 0 : 1); 546 int count = (AudioFinished() ? 0 : 1) + (VideoFinished() ? 0 : 1);
517 547
518 // It is possible that all streams have finished decode, yet starvation 548 // It is possible that all streams have finished decode, yet starvation
519 // occurred during the last stream's EOS decode. In this case, prefetch is a 549 // occurred during the last stream's EOS decode. In this case, prefetch is a
520 // no-op. 550 // no-op.
521 ClearPendingEvent(PREFETCH_REQUEST_EVENT_PENDING); 551 ClearPendingEvent(PREFETCH_REQUEST_EVENT_PENDING);
522 if (count == 0) 552 if (count == 0)
(...skipping 217 matching lines...) Expand 10 before | Expand all | Expand 10 after
740 bool MediaSourcePlayer::AudioFinished() { 770 bool MediaSourcePlayer::AudioFinished() {
741 return reached_audio_eos_ || !HasAudio(); 771 return reached_audio_eos_ || !HasAudio();
742 } 772 }
743 773
744 bool MediaSourcePlayer::VideoFinished() { 774 bool MediaSourcePlayer::VideoFinished() {
745 return reached_video_eos_ || !HasVideo(); 775 return reached_video_eos_ || !HasVideo();
746 } 776 }
747 777
748 void MediaSourcePlayer::ConfigureAudioDecoderJob() { 778 void MediaSourcePlayer::ConfigureAudioDecoderJob() {
749 if (!HasAudio()) { 779 if (!HasAudio()) {
750 audio_decoder_job_.reset(); 780 ResetAudioDecoderJob();
751 return; 781 return;
752 } 782 }
753 783
754 // Create audio decoder job only if config changes. 784 // Create audio decoder job only if config changes.
755 if (audio_decoder_job_ && !reconfig_audio_decoder_) 785 if (audio_decoder_job_ && !reconfig_audio_decoder_)
756 return; 786 return;
757 787
758 base::android::ScopedJavaLocalRef<jobject> media_crypto = GetMediaCrypto(); 788 base::android::ScopedJavaLocalRef<jobject> media_crypto = GetMediaCrypto();
759 if (is_audio_encrypted_ && media_crypto.is_null()) 789 if (is_audio_encrypted_ && media_crypto.is_null())
760 return; 790 return;
761 791
762 DCHECK(!audio_decoder_job_ || !audio_decoder_job_->is_decoding()); 792 DCHECK(!audio_decoder_job_ || !audio_decoder_job_->is_decoding());
763 793
794 ResetAudioDecoderJob();
764 DVLOG(1) << __FUNCTION__ << " : creating new audio decoder job"; 795 DVLOG(1) << __FUNCTION__ << " : creating new audio decoder job";
765
766 audio_decoder_job_.reset(AudioDecoderJob::Create( 796 audio_decoder_job_.reset(AudioDecoderJob::Create(
767 audio_codec_, sampling_rate_, num_channels_, &audio_extra_data_[0], 797 audio_codec_, sampling_rate_, num_channels_, &audio_extra_data_[0],
768 audio_extra_data_.size(), media_crypto.obj(), 798 audio_extra_data_.size(), media_crypto.obj(),
769 base::Bind(&DemuxerAndroid::RequestDemuxerData, 799 base::Bind(&DemuxerAndroid::RequestDemuxerData,
770 base::Unretained(demuxer_.get()), DemuxerStream::AUDIO))); 800 base::Unretained(demuxer_.get()), DemuxerStream::AUDIO)));
771 801
772 if (audio_decoder_job_) { 802 if (audio_decoder_job_) {
773 SetVolumeInternal(); 803 SetVolumeInternal();
774 audio_decoder_job_->BeginPrerolling(preroll_timestamp_); 804 audio_decoder_job_->BeginPrerolling(preroll_timestamp_);
775 reconfig_audio_decoder_ = false; 805 reconfig_audio_decoder_ = false;
776 } 806 }
777 } 807 }
778 808
779 void MediaSourcePlayer::ResetVideoDecoderJob() { 809 void MediaSourcePlayer::ResetVideoDecoderJob() {
810 if (video_decoder_job_) {
811 has_pending_video_data_request_ =
812 video_decoder_job_->is_requesting_demuxer_data();
813 }
780 video_decoder_job_.reset(); 814 video_decoder_job_.reset();
781 815
782 // Any eventual video decoder job re-creation will use the current |surface_|. 816 // Any eventual video decoder job re-creation will use the current |surface_|.
783 if (IsEventPending(SURFACE_CHANGE_EVENT_PENDING)) 817 if (IsEventPending(SURFACE_CHANGE_EVENT_PENDING))
784 ClearPendingEvent(SURFACE_CHANGE_EVENT_PENDING); 818 ClearPendingEvent(SURFACE_CHANGE_EVENT_PENDING);
785 } 819 }
786 820
821 void MediaSourcePlayer::ResetAudioDecoderJob() {
822 if (audio_decoder_job_) {
823 has_pending_audio_data_request_ =
824 audio_decoder_job_->is_requesting_demuxer_data();
825 }
826 audio_decoder_job_.reset();
827 }
828
787 void MediaSourcePlayer::ConfigureVideoDecoderJob() { 829 void MediaSourcePlayer::ConfigureVideoDecoderJob() {
788 if (!HasVideo() || surface_.IsEmpty()) { 830 if (!HasVideo() || surface_.IsEmpty()) {
789 ResetVideoDecoderJob(); 831 ResetVideoDecoderJob();
790 return; 832 return;
791 } 833 }
792 834
793 // Create video decoder job only if config changes or we don't have a job. 835 // Create video decoder job only if config changes or we don't have a job.
794 if (video_decoder_job_ && !reconfig_video_decoder_) { 836 if (video_decoder_job_ && !reconfig_video_decoder_) {
795 DCHECK(!IsEventPending(SURFACE_CHANGE_EVENT_PENDING)); 837 DCHECK(!IsEventPending(SURFACE_CHANGE_EVENT_PENDING));
796 return; 838 return;
(...skipping 171 matching lines...) Expand 10 before | Expand all | Expand 10 after
968 1010
969 void MediaSourcePlayer::ClearPendingEvent(PendingEventFlags event) { 1011 void MediaSourcePlayer::ClearPendingEvent(PendingEventFlags event) {
970 DVLOG(1) << __FUNCTION__ << "(" << GetEventName(event) << ")"; 1012 DVLOG(1) << __FUNCTION__ << "(" << GetEventName(event) << ")";
971 DCHECK_NE(event, NO_EVENT_PENDING); 1013 DCHECK_NE(event, NO_EVENT_PENDING);
972 DCHECK(IsEventPending(event)) << GetEventName(event); 1014 DCHECK(IsEventPending(event)) << GetEventName(event);
973 1015
974 pending_event_ &= ~event; 1016 pending_event_ &= ~event;
975 } 1017 }
976 1018
977 } // namespace media 1019 } // namespace media
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698