OLD | NEW |
1 // Copyright 2015 The Chromium Authors. All rights reserved. | 1 // Copyright 2015 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_codec_decoder.h" | 5 #include "media/base/android/media_codec_decoder.h" |
6 | 6 |
7 #include "base/bind.h" | 7 #include "base/bind.h" |
8 #include "base/bind_helpers.h" | 8 #include "base/bind_helpers.h" |
9 #include "base/callback_helpers.h" | 9 #include "base/callback_helpers.h" |
10 #include "base/logging.h" | 10 #include "base/logging.h" |
11 #include "media/base/android/media_codec_bridge.h" | 11 #include "media/base/android/media_codec_bridge.h" |
| 12 #include "media/base/android/media_drm_bridge.h" |
12 | 13 |
13 namespace media { | 14 namespace media { |
14 | 15 |
15 namespace { | 16 namespace { |
16 | 17 |
17 // Stop requesting new data in the kPrefetching state when the queue size | 18 // Stop requesting new data in the kPrefetching state when the queue size |
18 // reaches this limit. | 19 // reaches this limit. |
19 const int kPrefetchLimit = 8; | 20 const int kPrefetchLimit = 8; |
20 | 21 |
21 // Request new data in the kRunning state if the queue size is less than this. | 22 // Request new data in the kRunning state if the queue size is less than this. |
22 const int kPlaybackLowLimit = 4; | 23 const int kPlaybackLowLimit = 4; |
23 | 24 |
24 // Posting delay of the next frame processing, in milliseconds | 25 // Posting delay of the next frame processing, in milliseconds |
25 const int kNextFrameDelay = 1; | 26 const int kNextFrameDelay = 1; |
26 | 27 |
27 // Timeout for dequeuing an input buffer from MediaCodec in milliseconds. | 28 // Timeout for dequeuing an input buffer from MediaCodec in milliseconds. |
28 const int kInputBufferTimeout = 20; | 29 const int kInputBufferTimeout = 20; |
29 | 30 |
30 // Timeout for dequeuing an output buffer from MediaCodec in milliseconds. | 31 // Timeout for dequeuing an output buffer from MediaCodec in milliseconds. |
31 const int kOutputBufferTimeout = 20; | 32 const int kOutputBufferTimeout = 20; |
32 } | 33 } |
33 | 34 |
34 MediaCodecDecoder::MediaCodecDecoder( | 35 MediaCodecDecoder::MediaCodecDecoder( |
35 const scoped_refptr<base::SingleThreadTaskRunner>& media_task_runner, | 36 const scoped_refptr<base::SingleThreadTaskRunner>& media_task_runner, |
36 const base::Closure& external_request_data_cb, | 37 const base::Closure& external_request_data_cb, |
37 const base::Closure& starvation_cb, | 38 const base::Closure& starvation_cb, |
38 const base::Closure& decoder_drained_cb, | 39 const base::Closure& decoder_drained_cb, |
39 const base::Closure& stop_done_cb, | 40 const base::Closure& stop_done_cb, |
| 41 const base::Closure& key_required_cb, |
40 const base::Closure& error_cb, | 42 const base::Closure& error_cb, |
41 const char* decoder_thread_name) | 43 const char* decoder_thread_name) |
42 : media_task_runner_(media_task_runner), | 44 : media_task_runner_(media_task_runner), |
43 decoder_thread_(decoder_thread_name), | 45 decoder_thread_(decoder_thread_name), |
| 46 drm_bridge_(nullptr), |
44 needs_reconfigure_(false), | 47 needs_reconfigure_(false), |
45 drain_decoder_(false), | 48 drain_decoder_(false), |
46 always_reconfigure_for_tests_(false), | 49 always_reconfigure_for_tests_(false), |
47 external_request_data_cb_(external_request_data_cb), | 50 external_request_data_cb_(external_request_data_cb), |
48 starvation_cb_(starvation_cb), | 51 starvation_cb_(starvation_cb), |
49 decoder_drained_cb_(decoder_drained_cb), | 52 decoder_drained_cb_(decoder_drained_cb), |
50 stop_done_cb_(stop_done_cb), | 53 stop_done_cb_(stop_done_cb), |
| 54 key_required_cb_(key_required_cb), |
51 error_cb_(error_cb), | 55 error_cb_(error_cb), |
52 state_(kStopped), | 56 state_(kStopped), |
53 is_prepared_(false), | 57 is_prepared_(false), |
54 eos_enqueued_(false), | 58 eos_enqueued_(false), |
| 59 key_request_posted_(false), |
55 completed_(false), | 60 completed_(false), |
56 last_frame_posted_(false), | 61 last_frame_posted_(false), |
57 is_data_request_in_progress_(false), | 62 is_data_request_in_progress_(false), |
58 is_incoming_data_invalid_(false), | 63 is_incoming_data_invalid_(false), |
59 #ifndef NDEBUG | 64 #ifndef NDEBUG |
60 verify_next_frame_is_key_(false), | 65 verify_next_frame_is_key_(false), |
61 #endif | 66 #endif |
62 weak_factory_(this) { | 67 weak_factory_(this) { |
63 DCHECK(media_task_runner_->BelongsToCurrentThread()); | 68 DCHECK(media_task_runner_->BelongsToCurrentThread()); |
64 | 69 |
(...skipping 107 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
172 (!is_prepared_ || preroll_timestamp_ != base::TimeDelta()); | 177 (!is_prepared_ || preroll_timestamp_ != base::TimeDelta()); |
173 } | 178 } |
174 | 179 |
175 void MediaCodecDecoder::SetPrerollTimestamp(base::TimeDelta preroll_timestamp) { | 180 void MediaCodecDecoder::SetPrerollTimestamp(base::TimeDelta preroll_timestamp) { |
176 DCHECK(media_task_runner_->BelongsToCurrentThread()); | 181 DCHECK(media_task_runner_->BelongsToCurrentThread()); |
177 DVLOG(1) << class_name() << "::" << __FUNCTION__ << ": " << preroll_timestamp; | 182 DVLOG(1) << class_name() << "::" << __FUNCTION__ << ": " << preroll_timestamp; |
178 | 183 |
179 preroll_timestamp_ = preroll_timestamp; | 184 preroll_timestamp_ = preroll_timestamp; |
180 } | 185 } |
181 | 186 |
| 187 void MediaCodecDecoder::SetDrmBridge(MediaDrmBridge* drm_bridge) { |
| 188 DCHECK(media_task_runner_->BelongsToCurrentThread()); |
| 189 |
| 190 DVLOG(1) << class_name() << "::" << __FUNCTION__; |
| 191 |
| 192 drm_bridge_ = drm_bridge; |
| 193 |
| 194 needs_reconfigure_ = true; |
| 195 } |
| 196 |
182 base::android::ScopedJavaLocalRef<jobject> MediaCodecDecoder::GetMediaCrypto() { | 197 base::android::ScopedJavaLocalRef<jobject> MediaCodecDecoder::GetMediaCrypto() { |
183 base::android::ScopedJavaLocalRef<jobject> media_crypto; | 198 base::android::ScopedJavaLocalRef<jobject> media_crypto; |
184 | 199 if (drm_bridge_) |
185 // TODO(timav): implement DRM. | 200 media_crypto = drm_bridge_->GetMediaCrypto(); |
186 // drm_bridge_ is not implemented | |
187 // if (drm_bridge_) | |
188 // media_crypto = drm_bridge_->GetMediaCrypto(); | |
189 return media_crypto; | 201 return media_crypto; |
190 } | 202 } |
191 | 203 |
192 void MediaCodecDecoder::Prefetch(const base::Closure& prefetch_done_cb) { | 204 void MediaCodecDecoder::Prefetch(const base::Closure& prefetch_done_cb) { |
193 DCHECK(media_task_runner_->BelongsToCurrentThread()); | 205 DCHECK(media_task_runner_->BelongsToCurrentThread()); |
194 | 206 |
195 DVLOG(1) << class_name() << "::" << __FUNCTION__; | 207 DVLOG(1) << class_name() << "::" << __FUNCTION__; |
196 | 208 |
197 DCHECK(GetState() == kStopped); | 209 DCHECK(GetState() == kStopped); |
198 | 210 |
(...skipping 19 matching lines...) Expand all Loading... |
218 needs_reconfigure_ = false; | 230 needs_reconfigure_ = false; |
219 ReleaseMediaCodec(); | 231 ReleaseMediaCodec(); |
220 } | 232 } |
221 | 233 |
222 if (media_codec_bridge_) { | 234 if (media_codec_bridge_) { |
223 DVLOG(1) << class_name() << "::" << __FUNCTION__ | 235 DVLOG(1) << class_name() << "::" << __FUNCTION__ |
224 << ": reconfiguration is not required, ignoring"; | 236 << ": reconfiguration is not required, ignoring"; |
225 return kConfigOk; | 237 return kConfigOk; |
226 } | 238 } |
227 | 239 |
| 240 if (IsContentEncrypted() && GetMediaCrypto().is_null()) { |
| 241 DVLOG(1) << class_name() << "::" << __FUNCTION__ |
| 242 << ": MediaCrypto is missing"; |
| 243 return kConfigNoCrypto; |
| 244 } |
| 245 |
228 // Read all |kConfigChanged| units preceding the data one. | 246 // Read all |kConfigChanged| units preceding the data one. |
229 AccessUnitQueue::Info au_info = au_queue_.GetInfo(); | 247 AccessUnitQueue::Info au_info = au_queue_.GetInfo(); |
230 while (au_info.configs) { | 248 while (au_info.configs) { |
231 SetDemuxerConfigs(*au_info.configs); | 249 SetDemuxerConfigs(*au_info.configs); |
232 au_queue_.Advance(); | 250 au_queue_.Advance(); |
233 au_info = au_queue_.GetInfo(); | 251 au_info = au_queue_.GetInfo(); |
234 } | 252 } |
235 | 253 |
236 MediaCodecDecoder::ConfigStatus result = ConfigureInternal(); | 254 MediaCodecDecoder::ConfigStatus result = ConfigureInternal(); |
237 | 255 |
(...skipping 156 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
394 DCHECK(media_task_runner_->BelongsToCurrentThread()); | 412 DCHECK(media_task_runner_->BelongsToCurrentThread()); |
395 | 413 |
396 DVLOG(1) << class_name() << "::" << __FUNCTION__ | 414 DVLOG(1) << class_name() << "::" << __FUNCTION__ |
397 << " eos_encountered:" << eos_encountered; | 415 << " eos_encountered:" << eos_encountered; |
398 | 416 |
399 decoder_thread_.Stop(); // synchronous | 417 decoder_thread_.Stop(); // synchronous |
400 | 418 |
401 SetState(kStopped); | 419 SetState(kStopped); |
402 completed_ = (eos_encountered && !drain_decoder_); | 420 completed_ = (eos_encountered && !drain_decoder_); |
403 | 421 |
| 422 key_request_posted_ = false; |
| 423 |
404 // If the stream is completed during preroll we need to report it since | 424 // If the stream is completed during preroll we need to report it since |
405 // another stream might be running and the player waits for two callbacks. | 425 // another stream might be running and the player waits for two callbacks. |
406 if (completed_ && !preroll_done_cb_.is_null()) { | 426 if (completed_ && !preroll_done_cb_.is_null()) { |
407 preroll_timestamp_ = base::TimeDelta(); | 427 preroll_timestamp_ = base::TimeDelta(); |
408 media_task_runner_->PostTask(FROM_HERE, | 428 media_task_runner_->PostTask(FROM_HERE, |
409 base::ResetAndReturn(&preroll_done_cb_)); | 429 base::ResetAndReturn(&preroll_done_cb_)); |
410 } | 430 } |
411 | 431 |
412 if (eos_encountered && drain_decoder_) { | 432 if (eos_encountered && drain_decoder_) { |
413 drain_decoder_ = false; | 433 drain_decoder_ = false; |
(...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
491 DVLOG(1) << class_name() << "::" << __FUNCTION__; | 511 DVLOG(1) << class_name() << "::" << __FUNCTION__; |
492 | 512 |
493 // After this method returns, decoder thread will not be running. | 513 // After this method returns, decoder thread will not be running. |
494 | 514 |
495 // Set [kInEmergencyStop| state to block already posted ProcessNextFrame(). | 515 // Set [kInEmergencyStop| state to block already posted ProcessNextFrame(). |
496 SetState(kInEmergencyStop); | 516 SetState(kInEmergencyStop); |
497 | 517 |
498 decoder_thread_.Stop(); // synchronous | 518 decoder_thread_.Stop(); // synchronous |
499 | 519 |
500 SetState(kStopped); | 520 SetState(kStopped); |
| 521 |
| 522 key_request_posted_ = false; |
501 } | 523 } |
502 | 524 |
503 void MediaCodecDecoder::CheckLastFrame(bool eos_encountered, | 525 void MediaCodecDecoder::CheckLastFrame(bool eos_encountered, |
504 bool has_delayed_tasks) { | 526 bool has_delayed_tasks) { |
505 DCHECK(decoder_thread_.task_runner()->BelongsToCurrentThread()); | 527 DCHECK(decoder_thread_.task_runner()->BelongsToCurrentThread()); |
506 | 528 |
507 bool last_frame_when_stopping = GetState() == kStopping && !has_delayed_tasks; | 529 bool last_frame_when_stopping = GetState() == kStopping && !has_delayed_tasks; |
508 | 530 |
509 if (last_frame_when_stopping || eos_encountered) { | 531 if (last_frame_when_stopping || eos_encountered) { |
510 media_task_runner_->PostTask( | 532 media_task_runner_->PostTask( |
(...skipping 100 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
611 DCHECK(decoder_thread_.task_runner()->BelongsToCurrentThread()); | 633 DCHECK(decoder_thread_.task_runner()->BelongsToCurrentThread()); |
612 | 634 |
613 DVLOG(2) << class_name() << "::" << __FUNCTION__; | 635 DVLOG(2) << class_name() << "::" << __FUNCTION__; |
614 | 636 |
615 if (eos_enqueued_) { | 637 if (eos_enqueued_) { |
616 DVLOG(1) << class_name() << "::" << __FUNCTION__ | 638 DVLOG(1) << class_name() << "::" << __FUNCTION__ |
617 << ": eos_enqueued, returning"; | 639 << ": eos_enqueued, returning"; |
618 return true; // Nothing to do | 640 return true; // Nothing to do |
619 } | 641 } |
620 | 642 |
| 643 if (key_request_posted_) { |
| 644 DVLOG(1) << class_name() << "::" << __FUNCTION__ |
| 645 << ": key_request_posted, returning"; |
| 646 return true; // Nothing to do |
| 647 } |
| 648 |
621 // Keep the number pending video frames low, ideally maintaining | 649 // Keep the number pending video frames low, ideally maintaining |
622 // the same audio and video duration after stop request | 650 // the same audio and video duration after stop request |
623 if (NumDelayedRenderTasks() > 1) { | 651 if (NumDelayedRenderTasks() > 1) { |
624 DVLOG(2) << class_name() << "::" << __FUNCTION__ << ": # delayed buffers (" | 652 DVLOG(2) << class_name() << "::" << __FUNCTION__ << ": # delayed buffers (" |
625 << NumDelayedRenderTasks() << ") exceeds 1, returning"; | 653 << NumDelayedRenderTasks() << ") exceeds 1, returning"; |
626 return true; // Nothing to do | 654 return true; // Nothing to do |
627 } | 655 } |
628 | 656 |
629 // Get the next frame from the queue. As we go, request more data and | 657 // Get the next frame from the queue. As we go, request more data and |
630 // consume |kConfigChanged| units. | 658 // consume |kConfigChanged| units. |
(...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
688 | 716 |
689 if (drain_decoder_ || unit->is_end_of_stream) { | 717 if (drain_decoder_ || unit->is_end_of_stream) { |
690 DVLOG(1) << class_name() << "::" << __FUNCTION__ << ": QueueEOS"; | 718 DVLOG(1) << class_name() << "::" << __FUNCTION__ << ": QueueEOS"; |
691 media_codec_bridge_->QueueEOS(index); | 719 media_codec_bridge_->QueueEOS(index); |
692 eos_enqueued_ = true; | 720 eos_enqueued_ = true; |
693 return true; | 721 return true; |
694 } | 722 } |
695 | 723 |
696 DCHECK(unit); | 724 DCHECK(unit); |
697 | 725 |
698 DVLOG(2) << class_name() << "::" << __FUNCTION__ | 726 if (unit->key_id.empty() || unit->iv.empty()) { |
699 << ": QueueInputBuffer pts:" << unit->timestamp; | 727 DVLOG(2) << class_name() << "::" << __FUNCTION__ |
| 728 << ": QueueInputBuffer pts:" << unit->timestamp; |
700 | 729 |
701 status = media_codec_bridge_->QueueInputBuffer( | 730 status = media_codec_bridge_->QueueInputBuffer( |
702 index, &unit->data[0], unit->data.size(), unit->timestamp); | 731 index, &unit->data[0], unit->data.size(), unit->timestamp); |
| 732 } else { |
| 733 DVLOG(2) << class_name() << "::" << __FUNCTION__ |
| 734 << ": QueueSecureInputBuffer pts:" << unit->timestamp |
| 735 << " key_id size:" << unit->key_id.size() |
| 736 << " iv size:" << unit->iv.size() |
| 737 << " subsamples size:" << unit->subsamples.size(); |
703 | 738 |
704 if (status == MEDIA_CODEC_ERROR) { | 739 status = media_codec_bridge_->QueueSecureInputBuffer( |
705 DVLOG(0) << class_name() << "::" << __FUNCTION__ | 740 index, &unit->data[0], unit->data.size(), |
706 << ": MEDIA_CODEC_ERROR: QueueInputBuffer failed"; | 741 reinterpret_cast<const uint8_t*>(&unit->key_id[0]), unit->key_id.size(), |
707 media_task_runner_->PostTask(FROM_HERE, internal_error_cb_); | 742 reinterpret_cast<const uint8_t*>(&unit->iv[0]), unit->iv.size(), |
708 return false; | 743 unit->subsamples.empty() ? nullptr : &unit->subsamples[0], |
| 744 unit->subsamples.size(), unit->timestamp); |
| 745 } |
| 746 |
| 747 switch (status) { |
| 748 case MEDIA_CODEC_OK: |
| 749 break; |
| 750 |
| 751 case MEDIA_CODEC_ERROR: |
| 752 DVLOG(0) << class_name() << "::" << __FUNCTION__ |
| 753 << ": MEDIA_CODEC_ERROR: QueueInputBuffer failed"; |
| 754 media_task_runner_->PostTask(FROM_HERE, internal_error_cb_); |
| 755 return false; |
| 756 |
| 757 case MEDIA_CODEC_NO_KEY: |
| 758 DVLOG(1) << class_name() << "::" << __FUNCTION__ |
| 759 << ": MEDIA_CODEC_NO_KEY"; |
| 760 media_task_runner_->PostTask(FROM_HERE, key_required_cb_); |
| 761 |
| 762 // In response to the |key_required_cb_| the player will request to stop |
| 763 // decoder. We need to keep running to properly perform the stop, but |
| 764 // prevent enqueuing the same frame over and over again so we won't |
| 765 // generate more |key_required_cb_|. |
| 766 key_request_posted_ = true; |
| 767 return true; |
| 768 |
| 769 default: |
| 770 NOTREACHED() << class_name() << "::" << __FUNCTION__ |
| 771 << ": unexpected error code " << status; |
| 772 media_task_runner_->PostTask(FROM_HERE, internal_error_cb_); |
| 773 return false; |
709 } | 774 } |
710 | 775 |
711 // Have successfully queued input buffer, go to next access unit. | 776 // Have successfully queued input buffer, go to next access unit. |
712 au_queue_.Advance(); | 777 au_queue_.Advance(); |
713 return true; | 778 return true; |
714 } | 779 } |
715 | 780 |
716 AccessUnitQueue::Info MediaCodecDecoder::AdvanceAccessUnitQueue( | 781 AccessUnitQueue::Info MediaCodecDecoder::AdvanceAccessUnitQueue( |
717 bool* drain_decoder) { | 782 bool* drain_decoder) { |
718 DCHECK(decoder_thread_.task_runner()->BelongsToCurrentThread()); | 783 DCHECK(decoder_thread_.task_runner()->BelongsToCurrentThread()); |
(...skipping 177 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
896 RETURN_STRING(kStopping); | 961 RETURN_STRING(kStopping); |
897 RETURN_STRING(kInEmergencyStop); | 962 RETURN_STRING(kInEmergencyStop); |
898 RETURN_STRING(kError); | 963 RETURN_STRING(kError); |
899 } | 964 } |
900 return nullptr; // crash early | 965 return nullptr; // crash early |
901 } | 966 } |
902 | 967 |
903 #undef RETURN_STRING | 968 #undef RETURN_STRING |
904 | 969 |
905 } // namespace media | 970 } // namespace media |
OLD | NEW |