Chromium Code Reviews| 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 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 |
| OLD | NEW |