| OLD | NEW |
| 1 // Copyright 2013 The Chromium Authors. All rights reserved. | 1 // Copyright 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_decoder_job.h" | 5 #include "media/base/android/media_decoder_job.h" |
| 6 | 6 |
| 7 #include "base/bind.h" | 7 #include "base/bind.h" |
| 8 #include "base/callback_helpers.h" | 8 #include "base/callback_helpers.h" |
| 9 #include "base/message_loop/message_loop_proxy.h" | 9 #include "base/message_loop/message_loop_proxy.h" |
| 10 #include "base/trace_event/trace_event.h" | 10 #include "base/trace_event/trace_event.h" |
| (...skipping 92 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 103 if (HasData()) { | 103 if (HasData()) { |
| 104 DVLOG(1) << __FUNCTION__ << " : using previously received data"; | 104 DVLOG(1) << __FUNCTION__ << " : using previously received data"; |
| 105 ui_task_runner_->PostTask(FROM_HERE, prefetch_cb); | 105 ui_task_runner_->PostTask(FROM_HERE, prefetch_cb); |
| 106 return; | 106 return; |
| 107 } | 107 } |
| 108 | 108 |
| 109 DVLOG(1) << __FUNCTION__ << " : requesting data"; | 109 DVLOG(1) << __FUNCTION__ << " : requesting data"; |
| 110 RequestData(prefetch_cb); | 110 RequestData(prefetch_cb); |
| 111 } | 111 } |
| 112 | 112 |
| 113 bool MediaDecoderJob::Decode( | 113 MediaDecoderJob::MediaDecoderJobStatus MediaDecoderJob::Decode( |
| 114 base::TimeTicks start_time_ticks, | 114 base::TimeTicks start_time_ticks, |
| 115 base::TimeDelta start_presentation_timestamp, | 115 base::TimeDelta start_presentation_timestamp, |
| 116 const DecoderCallback& callback) { | 116 const DecoderCallback& callback) { |
| 117 DCHECK(decode_cb_.is_null()); | 117 DCHECK(decode_cb_.is_null()); |
| 118 DCHECK(data_received_cb_.is_null()); | 118 DCHECK(data_received_cb_.is_null()); |
| 119 DCHECK(ui_task_runner_->BelongsToCurrentThread()); | 119 DCHECK(ui_task_runner_->BelongsToCurrentThread()); |
| 120 if (!media_codec_bridge_ || need_to_reconfig_decoder_job_) { | 120 if (!media_codec_bridge_ || need_to_reconfig_decoder_job_) { |
| 121 if (drain_decoder_) | 121 if (drain_decoder_) |
| 122 OnDecoderDrained(); | 122 OnDecoderDrained(); |
| 123 need_to_reconfig_decoder_job_ = !CreateMediaCodecBridge(); | 123 MediaDecoderJobStatus status = CreateMediaCodecBridge(); |
| 124 need_to_reconfig_decoder_job_ = (status != STATUS_SUCCESS); |
| 124 skip_eos_enqueue_ = true; | 125 skip_eos_enqueue_ = true; |
| 125 if (need_to_reconfig_decoder_job_) | 126 if (need_to_reconfig_decoder_job_) |
| 126 return false; | 127 return status; |
| 127 } | 128 } |
| 128 | 129 |
| 129 decode_cb_ = callback; | 130 decode_cb_ = callback; |
| 130 | 131 |
| 131 if (!HasData()) { | 132 if (!HasData()) { |
| 132 RequestData(base::Bind(&MediaDecoderJob::DecodeCurrentAccessUnit, | 133 RequestData(base::Bind(&MediaDecoderJob::DecodeCurrentAccessUnit, |
| 133 base::Unretained(this), | 134 base::Unretained(this), |
| 134 start_time_ticks, | 135 start_time_ticks, |
| 135 start_presentation_timestamp)); | 136 start_presentation_timestamp)); |
| 136 return true; | 137 return STATUS_SUCCESS; |
| 137 } | 138 } |
| 138 | 139 |
| 139 DecodeCurrentAccessUnit(start_time_ticks, start_presentation_timestamp); | 140 DecodeCurrentAccessUnit(start_time_ticks, start_presentation_timestamp); |
| 140 return true; | 141 return STATUS_SUCCESS; |
| 141 } | 142 } |
| 142 | 143 |
| 143 void MediaDecoderJob::StopDecode() { | 144 void MediaDecoderJob::StopDecode() { |
| 144 DCHECK(ui_task_runner_->BelongsToCurrentThread()); | 145 DCHECK(ui_task_runner_->BelongsToCurrentThread()); |
| 145 DCHECK(is_decoding()); | 146 DCHECK(is_decoding()); |
| 146 stop_decode_pending_ = true; | 147 stop_decode_pending_ = true; |
| 147 } | 148 } |
| 148 | 149 |
| 149 bool MediaDecoderJob::OutputEOSReached() const { | 150 bool MediaDecoderJob::OutputEOSReached() const { |
| 150 return !drain_decoder_ && output_eos_encountered_; | 151 return !drain_decoder_ && output_eos_encountered_; |
| (...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 198 release_resources_pending_ = true; | 199 release_resources_pending_ = true; |
| 199 } | 200 } |
| 200 | 201 |
| 201 base::android::ScopedJavaLocalRef<jobject> MediaDecoderJob::GetMediaCrypto() { | 202 base::android::ScopedJavaLocalRef<jobject> MediaDecoderJob::GetMediaCrypto() { |
| 202 base::android::ScopedJavaLocalRef<jobject> media_crypto; | 203 base::android::ScopedJavaLocalRef<jobject> media_crypto; |
| 203 if (drm_bridge_) | 204 if (drm_bridge_) |
| 204 media_crypto = drm_bridge_->GetMediaCrypto(); | 205 media_crypto = drm_bridge_->GetMediaCrypto(); |
| 205 return media_crypto; | 206 return media_crypto; |
| 206 } | 207 } |
| 207 | 208 |
| 209 bool MediaDecoderJob::SetCurrentFrameToPreviouslyCachedKeyFrame() { |
| 210 const std::vector<AccessUnit>& access_units = |
| 211 received_data_[current_demuxer_data_index_].access_units; |
| 212 // If the current data chunk is empty, the player must be in an initial or |
| 213 // seek state. The next access unit will always be a key frame. |
| 214 if (access_units.size() == 0) |
| 215 return true; |
| 216 |
| 217 // Find key frame in all the access units the decoder have decoded, |
| 218 // or is about to decode. |
| 219 int i = std::min(access_unit_index_[current_demuxer_data_index_], |
| 220 access_units.size() - 1); |
| 221 for (; i >= 0; --i) { |
| 222 // Config change is always the last access unit, and it always come with |
| 223 // a key frame afterwards. |
| 224 if (access_units[i].status == DemuxerStream::kConfigChanged) |
| 225 return true; |
| 226 if (access_units[i].is_key_frame) { |
| 227 access_unit_index_[current_demuxer_data_index_] = i; |
| 228 return true; |
| 229 } |
| 230 } |
| 231 return false; |
| 232 } |
| 233 |
| 234 |
| 208 void MediaDecoderJob::Release() { | 235 void MediaDecoderJob::Release() { |
| 209 DCHECK(ui_task_runner_->BelongsToCurrentThread()); | 236 DCHECK(ui_task_runner_->BelongsToCurrentThread()); |
| 210 DVLOG(1) << __FUNCTION__; | 237 DVLOG(1) << __FUNCTION__; |
| 211 | 238 |
| 212 // If the decoder job is still decoding, we cannot delete the job immediately. | 239 // If the decoder job is still decoding, we cannot delete the job immediately. |
| 213 destroy_pending_ = is_decoding(); | 240 destroy_pending_ = is_decoding(); |
| 214 | 241 |
| 215 request_data_cb_.Reset(); | 242 request_data_cb_.Reset(); |
| 216 data_received_cb_.Reset(); | 243 data_received_cb_.Reset(); |
| 217 decode_cb_.Reset(); | 244 decode_cb_.Reset(); |
| (...skipping 293 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 511 if (current_presentation_timestamp != kNoTimestamp() || | 538 if (current_presentation_timestamp != kNoTimestamp() || |
| 512 status == MEDIA_CODEC_OUTPUT_END_OF_STREAM) { | 539 status == MEDIA_CODEC_OUTPUT_END_OF_STREAM) { |
| 513 prerolling_ = false; | 540 prerolling_ = false; |
| 514 } | 541 } |
| 515 | 542 |
| 516 switch (status) { | 543 switch (status) { |
| 517 case MEDIA_CODEC_OK: | 544 case MEDIA_CODEC_OK: |
| 518 case MEDIA_CODEC_DEQUEUE_OUTPUT_AGAIN_LATER: | 545 case MEDIA_CODEC_DEQUEUE_OUTPUT_AGAIN_LATER: |
| 519 case MEDIA_CODEC_OUTPUT_FORMAT_CHANGED: | 546 case MEDIA_CODEC_OUTPUT_FORMAT_CHANGED: |
| 520 case MEDIA_CODEC_OUTPUT_END_OF_STREAM: | 547 case MEDIA_CODEC_OUTPUT_END_OF_STREAM: |
| 521 if (!input_eos_encountered_) { | 548 if (!input_eos_encountered_) |
| 522 CurrentDataConsumed( | |
| 523 CurrentAccessUnit().status == DemuxerStream::kConfigChanged); | |
| 524 access_unit_index_[current_demuxer_data_index_]++; | 549 access_unit_index_[current_demuxer_data_index_]++; |
| 525 } | |
| 526 break; | 550 break; |
| 527 | 551 |
| 528 case MEDIA_CODEC_DEQUEUE_INPUT_AGAIN_LATER: | 552 case MEDIA_CODEC_DEQUEUE_INPUT_AGAIN_LATER: |
| 529 case MEDIA_CODEC_INPUT_END_OF_STREAM: | 553 case MEDIA_CODEC_INPUT_END_OF_STREAM: |
| 530 case MEDIA_CODEC_NO_KEY: | 554 case MEDIA_CODEC_NO_KEY: |
| 531 case MEDIA_CODEC_ABORT: | 555 case MEDIA_CODEC_ABORT: |
| 532 case MEDIA_CODEC_ERROR: | 556 case MEDIA_CODEC_ERROR: |
| 533 // Do nothing. | 557 // Do nothing. |
| 534 break; | 558 break; |
| 535 | 559 |
| (...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 582 } | 606 } |
| 583 | 607 |
| 584 void MediaDecoderJob::RequestCurrentChunkIfEmpty() { | 608 void MediaDecoderJob::RequestCurrentChunkIfEmpty() { |
| 585 DCHECK(ui_task_runner_->BelongsToCurrentThread()); | 609 DCHECK(ui_task_runner_->BelongsToCurrentThread()); |
| 586 DCHECK(HasData()); | 610 DCHECK(HasData()); |
| 587 if (!NoAccessUnitsRemainingInChunk(true)) | 611 if (!NoAccessUnitsRemainingInChunk(true)) |
| 588 return; | 612 return; |
| 589 | 613 |
| 590 // Requests new data if the the last access unit of the next chunk is not EOS. | 614 // Requests new data if the the last access unit of the next chunk is not EOS. |
| 591 current_demuxer_data_index_ = inactive_demuxer_data_index(); | 615 current_demuxer_data_index_ = inactive_demuxer_data_index(); |
| 592 const AccessUnit last_access_unit = | 616 const AccessUnit& last_access_unit = |
| 593 received_data_[current_demuxer_data_index_].access_units.back(); | 617 received_data_[current_demuxer_data_index_].access_units.back(); |
| 594 if (!last_access_unit.is_end_of_stream && | 618 if (!last_access_unit.is_end_of_stream && |
| 595 last_access_unit.status != DemuxerStream::kAborted) { | 619 last_access_unit.status != DemuxerStream::kAborted) { |
| 596 RequestData(base::Closure()); | 620 RequestData(base::Closure()); |
| 597 } | 621 } |
| 598 } | 622 } |
| 599 | 623 |
| 600 void MediaDecoderJob::InitializeReceivedData() { | 624 void MediaDecoderJob::InitializeReceivedData() { |
| 601 for (size_t i = 0; i < 2; ++i) { | 625 for (size_t i = 0; i < 2; ++i) { |
| 602 received_data_[i] = DemuxerData(); | 626 received_data_[i] = DemuxerData(); |
| 603 access_unit_index_[i] = 0; | 627 access_unit_index_[i] = 0; |
| 604 } | 628 } |
| 605 } | 629 } |
| 606 | 630 |
| 607 void MediaDecoderJob::OnDecoderDrained() { | 631 void MediaDecoderJob::OnDecoderDrained() { |
| 608 DVLOG(1) << __FUNCTION__; | 632 DVLOG(1) << __FUNCTION__; |
| 609 DCHECK(ui_task_runner_->BelongsToCurrentThread()); | 633 DCHECK(ui_task_runner_->BelongsToCurrentThread()); |
| 610 DCHECK(drain_decoder_); | 634 DCHECK(drain_decoder_); |
| 611 | 635 |
| 612 input_eos_encountered_ = false; | 636 input_eos_encountered_ = false; |
| 613 output_eos_encountered_ = false; | 637 output_eos_encountered_ = false; |
| 614 drain_decoder_ = false; | 638 drain_decoder_ = false; |
| 615 ReleaseMediaCodecBridge(); | 639 ReleaseMediaCodecBridge(); |
| 616 // Increase the access unit index so that the new decoder will not handle | 640 // Increase the access unit index so that the new decoder will not handle |
| 617 // the config change again. | 641 // the config change again. |
| 618 access_unit_index_[current_demuxer_data_index_]++; | 642 access_unit_index_[current_demuxer_data_index_]++; |
| 619 CurrentDataConsumed(true); | |
| 620 } | 643 } |
| 621 | 644 |
| 622 bool MediaDecoderJob::CreateMediaCodecBridge() { | 645 MediaDecoderJob::MediaDecoderJobStatus |
| 646 MediaDecoderJob::CreateMediaCodecBridge() { |
| 623 DVLOG(1) << __FUNCTION__; | 647 DVLOG(1) << __FUNCTION__; |
| 624 DCHECK(ui_task_runner_->BelongsToCurrentThread()); | 648 DCHECK(ui_task_runner_->BelongsToCurrentThread()); |
| 625 DCHECK(decode_cb_.is_null()); | 649 DCHECK(decode_cb_.is_null()); |
| 626 | 650 |
| 627 if (!HasStream()) { | 651 if (!HasStream()) { |
| 628 ReleaseMediaCodecBridge(); | 652 ReleaseMediaCodecBridge(); |
| 629 return false; | 653 return STATUS_FAILURE; |
| 630 } | 654 } |
| 631 | 655 |
| 632 // Create |media_codec_bridge_| only if config changes. | 656 // Create |media_codec_bridge_| only if config changes. |
| 633 if (media_codec_bridge_ && !need_to_reconfig_decoder_job_) | 657 if (media_codec_bridge_ && !need_to_reconfig_decoder_job_) |
| 634 return true; | 658 return STATUS_SUCCESS; |
| 635 | 659 |
| 636 base::android::ScopedJavaLocalRef<jobject> media_crypto = GetMediaCrypto(); | 660 base::android::ScopedJavaLocalRef<jobject> media_crypto = GetMediaCrypto(); |
| 637 if (is_content_encrypted_ && media_crypto.is_null()) | 661 if (is_content_encrypted_ && media_crypto.is_null()) |
| 638 return false; | 662 return STATUS_FAILURE; |
| 639 | 663 |
| 640 ReleaseMediaCodecBridge(); | 664 ReleaseMediaCodecBridge(); |
| 641 DVLOG(1) << __FUNCTION__ << " : creating new media codec bridge"; | 665 DVLOG(1) << __FUNCTION__ << " : creating new media codec bridge"; |
| 642 | 666 |
| 643 return CreateMediaCodecBridgeInternal(); | 667 return CreateMediaCodecBridgeInternal(); |
| 644 } | 668 } |
| 645 | 669 |
| 646 bool MediaDecoderJob::IsCodecReconfigureNeeded( | 670 bool MediaDecoderJob::IsCodecReconfigureNeeded( |
| 647 const DemuxerConfigs& configs) const { | 671 const DemuxerConfigs& configs) const { |
| 648 if (!AreDemuxerConfigsChanged(configs)) | 672 if (!AreDemuxerConfigsChanged(configs)) |
| 649 return false; | 673 return false; |
| 650 return true; | 674 return true; |
| 651 } | 675 } |
| 652 | 676 |
| 653 void MediaDecoderJob::OnOutputFormatChanged() {} | 677 void MediaDecoderJob::OnOutputFormatChanged() {} |
| 654 | 678 |
| 655 bool MediaDecoderJob::UpdateOutputFormat() { | 679 bool MediaDecoderJob::UpdateOutputFormat() { |
| 656 return false; | 680 return false; |
| 657 } | 681 } |
| 658 | 682 |
| 659 void MediaDecoderJob::ReleaseMediaCodecBridge() { | 683 void MediaDecoderJob::ReleaseMediaCodecBridge() { |
| 660 if (!media_codec_bridge_) | 684 if (!media_codec_bridge_) |
| 661 return; | 685 return; |
| 662 | 686 |
| 663 media_codec_bridge_.reset(); | 687 media_codec_bridge_.reset(); |
| 664 input_buf_index_ = -1; | 688 input_buf_index_ = -1; |
| 665 } | 689 } |
| 666 | 690 |
| 667 } // namespace media | 691 } // namespace media |
| OLD | NEW |