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

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

Issue 1344133002: MediaCodecPlayer implementation - stage 7 (DRM) (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@mtplayer-drm-prepare
Patch Set: Repost SetMediaCryptoReadyCB on UI thread, further cleanup Created 5 years, 2 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
OLDNEW
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"
(...skipping 19 matching lines...) Expand all
30 // Timeout for dequeuing an output buffer from MediaCodec in milliseconds. 30 // Timeout for dequeuing an output buffer from MediaCodec in milliseconds.
31 const int kOutputBufferTimeout = 20; 31 const int kOutputBufferTimeout = 20;
32 } 32 }
33 33
34 MediaCodecDecoder::MediaCodecDecoder( 34 MediaCodecDecoder::MediaCodecDecoder(
35 const scoped_refptr<base::SingleThreadTaskRunner>& media_task_runner, 35 const scoped_refptr<base::SingleThreadTaskRunner>& media_task_runner,
36 const base::Closure& external_request_data_cb, 36 const base::Closure& external_request_data_cb,
37 const base::Closure& starvation_cb, 37 const base::Closure& starvation_cb,
38 const base::Closure& decoder_drained_cb, 38 const base::Closure& decoder_drained_cb,
39 const base::Closure& stop_done_cb, 39 const base::Closure& stop_done_cb,
40 const base::Closure& key_required_cb,
40 const base::Closure& error_cb, 41 const base::Closure& error_cb,
41 const char* decoder_thread_name) 42 const char* decoder_thread_name)
42 : media_task_runner_(media_task_runner), 43 : media_task_runner_(media_task_runner),
43 decoder_thread_(decoder_thread_name), 44 decoder_thread_(decoder_thread_name),
44 needs_reconfigure_(false), 45 needs_reconfigure_(false),
45 drain_decoder_(false), 46 drain_decoder_(false),
46 always_reconfigure_for_tests_(false), 47 always_reconfigure_for_tests_(false),
47 external_request_data_cb_(external_request_data_cb), 48 external_request_data_cb_(external_request_data_cb),
48 starvation_cb_(starvation_cb), 49 starvation_cb_(starvation_cb),
49 decoder_drained_cb_(decoder_drained_cb), 50 decoder_drained_cb_(decoder_drained_cb),
50 stop_done_cb_(stop_done_cb), 51 stop_done_cb_(stop_done_cb),
52 key_required_cb_(key_required_cb),
51 error_cb_(error_cb), 53 error_cb_(error_cb),
52 state_(kStopped), 54 state_(kStopped),
53 is_prepared_(false), 55 is_prepared_(false),
54 eos_enqueued_(false), 56 eos_enqueued_(false),
57 key_request_posted_(false),
55 completed_(false), 58 completed_(false),
56 last_frame_posted_(false), 59 last_frame_posted_(false),
57 is_data_request_in_progress_(false), 60 is_data_request_in_progress_(false),
58 is_incoming_data_invalid_(false), 61 is_incoming_data_invalid_(false),
59 #ifndef NDEBUG 62 #ifndef NDEBUG
60 verify_next_frame_is_key_(false), 63 verify_next_frame_is_key_(false),
61 #endif 64 #endif
62 weak_factory_(this) { 65 weak_factory_(this) {
63 DCHECK(media_task_runner_->BelongsToCurrentThread()); 66 DCHECK(media_task_runner_->BelongsToCurrentThread());
64 67
65 DVLOG(1) << "Decoder::Decoder() " << decoder_thread_name; 68 DVLOG(1) << "Decoder::Decoder() " << decoder_thread_name;
66 69
67 internal_error_cb_ = 70 internal_error_cb_ =
68 base::Bind(&MediaCodecDecoder::OnCodecError, weak_factory_.GetWeakPtr()); 71 base::Bind(&MediaCodecDecoder::OnCodecError, weak_factory_.GetWeakPtr());
69 internal_preroll_done_cb_ = 72 internal_preroll_done_cb_ =
70 base::Bind(&MediaCodecDecoder::OnPrerollDone, weak_factory_.GetWeakPtr()); 73 base::Bind(&MediaCodecDecoder::OnPrerollDone, weak_factory_.GetWeakPtr());
71 request_data_cb_ = 74 request_data_cb_ =
72 base::Bind(&MediaCodecDecoder::RequestData, weak_factory_.GetWeakPtr()); 75 base::Bind(&MediaCodecDecoder::RequestData, weak_factory_.GetWeakPtr());
73 } 76 }
74 77
75 MediaCodecDecoder::~MediaCodecDecoder() {} 78 MediaCodecDecoder::~MediaCodecDecoder() {}
76 79
77 const char* MediaCodecDecoder::class_name() const { 80 const char* MediaCodecDecoder::class_name() const {
78 return "Decoder"; 81 return "Decoder";
79 } 82 }
80 83
81 void MediaCodecDecoder::Flush() { 84 void MediaCodecDecoder::Flush() {
qinmin 2015/09/23 05:58:26 key_request_posted needs to be reset to false here
Tima Vaisburd 2015/09/24 18:15:43 Yes, thank you. Done.
82 DCHECK(media_task_runner_->BelongsToCurrentThread()); 85 DCHECK(media_task_runner_->BelongsToCurrentThread());
83 86
84 DVLOG(1) << class_name() << "::" << __FUNCTION__; 87 DVLOG(1) << class_name() << "::" << __FUNCTION__;
85 88
86 DCHECK_EQ(GetState(), kStopped); 89 DCHECK_EQ(GetState(), kStopped);
87 90
88 // Flush() is a part of the Seek request. Whenever we request a seek we need 91 // Flush() is a part of the Seek request. Whenever we request a seek we need
89 // to invalidate the current data request. 92 // to invalidate the current data request.
90 if (is_data_request_in_progress_) 93 if (is_data_request_in_progress_)
91 is_incoming_data_invalid_ = true; 94 is_incoming_data_invalid_ = true;
(...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after
172 (!is_prepared_ || preroll_timestamp_ != base::TimeDelta()); 175 (!is_prepared_ || preroll_timestamp_ != base::TimeDelta());
173 } 176 }
174 177
175 void MediaCodecDecoder::SetPrerollTimestamp(base::TimeDelta preroll_timestamp) { 178 void MediaCodecDecoder::SetPrerollTimestamp(base::TimeDelta preroll_timestamp) {
176 DCHECK(media_task_runner_->BelongsToCurrentThread()); 179 DCHECK(media_task_runner_->BelongsToCurrentThread());
177 DVLOG(1) << class_name() << "::" << __FUNCTION__ << ": " << preroll_timestamp; 180 DVLOG(1) << class_name() << "::" << __FUNCTION__ << ": " << preroll_timestamp;
178 181
179 preroll_timestamp_ = preroll_timestamp; 182 preroll_timestamp_ = preroll_timestamp;
180 } 183 }
181 184
182 base::android::ScopedJavaLocalRef<jobject> MediaCodecDecoder::GetMediaCrypto() { 185 void MediaCodecDecoder::SetNeedsReconfigure() {
183 base::android::ScopedJavaLocalRef<jobject> media_crypto; 186 DCHECK(media_task_runner_->BelongsToCurrentThread());
184 187
185 // TODO(timav): implement DRM. 188 DVLOG(1) << class_name() << "::" << __FUNCTION__;
186 // drm_bridge_ is not implemented 189
187 // if (drm_bridge_) 190 needs_reconfigure_ = true;
188 // media_crypto = drm_bridge_->GetMediaCrypto();
189 return media_crypto;
190 } 191 }
191 192
192 void MediaCodecDecoder::Prefetch(const base::Closure& prefetch_done_cb) { 193 void MediaCodecDecoder::Prefetch(const base::Closure& prefetch_done_cb) {
193 DCHECK(media_task_runner_->BelongsToCurrentThread()); 194 DCHECK(media_task_runner_->BelongsToCurrentThread());
194 195
195 DVLOG(1) << class_name() << "::" << __FUNCTION__; 196 DVLOG(1) << class_name() << "::" << __FUNCTION__;
196 197
197 DCHECK(GetState() == kStopped); 198 DCHECK(GetState() == kStopped);
198 199
199 prefetch_done_cb_ = prefetch_done_cb; 200 prefetch_done_cb_ = prefetch_done_cb;
200 201
201 SetState(kPrefetching); 202 SetState(kPrefetching);
202 PrefetchNextChunk(); 203 PrefetchNextChunk();
203 } 204 }
204 205
205 MediaCodecDecoder::ConfigStatus MediaCodecDecoder::Configure() { 206 MediaCodecDecoder::ConfigStatus MediaCodecDecoder::Configure(
207 jobject media_crypto) {
206 DCHECK(media_task_runner_->BelongsToCurrentThread()); 208 DCHECK(media_task_runner_->BelongsToCurrentThread());
207 209
208 DVLOG(1) << class_name() << "::" << __FUNCTION__; 210 DVLOG(1) << class_name() << "::" << __FUNCTION__;
209 211
210 if (GetState() == kError) { 212 if (GetState() == kError) {
211 DVLOG(0) << class_name() << "::" << __FUNCTION__ << ": wrong state kError"; 213 DVLOG(0) << class_name() << "::" << __FUNCTION__ << ": wrong state kError";
212 return kConfigFailure; 214 return kConfigFailure;
213 } 215 }
214 216
215 if (needs_reconfigure_) { 217 if (needs_reconfigure_) {
(...skipping 10 matching lines...) Expand all
226 } 228 }
227 229
228 // Read all |kConfigChanged| units preceding the data one. 230 // Read all |kConfigChanged| units preceding the data one.
229 AccessUnitQueue::Info au_info = au_queue_.GetInfo(); 231 AccessUnitQueue::Info au_info = au_queue_.GetInfo();
230 while (au_info.configs) { 232 while (au_info.configs) {
231 SetDemuxerConfigs(*au_info.configs); 233 SetDemuxerConfigs(*au_info.configs);
232 au_queue_.Advance(); 234 au_queue_.Advance();
233 au_info = au_queue_.GetInfo(); 235 au_info = au_queue_.GetInfo();
234 } 236 }
235 237
236 MediaCodecDecoder::ConfigStatus result = ConfigureInternal(); 238 MediaCodecDecoder::ConfigStatus result = ConfigureInternal(media_crypto);
237 239
238 #ifndef NDEBUG 240 #ifndef NDEBUG
239 // We check and reset |verify_next_frame_is_key_| on Decoder thread. 241 // We check and reset |verify_next_frame_is_key_| on Decoder thread.
240 // This DCHECK ensures we won't need to lock this variable. 242 // This DCHECK ensures we won't need to lock this variable.
241 DCHECK(!decoder_thread_.IsRunning()); 243 DCHECK(!decoder_thread_.IsRunning());
242 244
243 // For video the first frame after reconfiguration must be key frame. 245 // For video the first frame after reconfiguration must be key frame.
244 if (result == kConfigOk) 246 if (result == kConfigOk)
245 verify_next_frame_is_key_ = true; 247 verify_next_frame_is_key_ = true;
246 #endif 248 #endif
(...skipping 147 matching lines...) Expand 10 before | Expand all | Expand 10 after
394 DCHECK(media_task_runner_->BelongsToCurrentThread()); 396 DCHECK(media_task_runner_->BelongsToCurrentThread());
395 397
396 DVLOG(1) << class_name() << "::" << __FUNCTION__ 398 DVLOG(1) << class_name() << "::" << __FUNCTION__
397 << " eos_encountered:" << eos_encountered; 399 << " eos_encountered:" << eos_encountered;
398 400
399 decoder_thread_.Stop(); // synchronous 401 decoder_thread_.Stop(); // synchronous
400 402
401 SetState(kStopped); 403 SetState(kStopped);
402 completed_ = (eos_encountered && !drain_decoder_); 404 completed_ = (eos_encountered && !drain_decoder_);
403 405
406 key_request_posted_ = false;
407
404 // If the stream is completed during preroll we need to report it since 408 // 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. 409 // another stream might be running and the player waits for two callbacks.
406 if (completed_ && !preroll_done_cb_.is_null()) { 410 if (completed_ && !preroll_done_cb_.is_null()) {
407 preroll_timestamp_ = base::TimeDelta(); 411 preroll_timestamp_ = base::TimeDelta();
408 media_task_runner_->PostTask(FROM_HERE, 412 media_task_runner_->PostTask(FROM_HERE,
409 base::ResetAndReturn(&preroll_done_cb_)); 413 base::ResetAndReturn(&preroll_done_cb_));
410 } 414 }
411 415
412 if (eos_encountered && drain_decoder_) { 416 if (eos_encountered && drain_decoder_) {
413 drain_decoder_ = false; 417 drain_decoder_ = false;
(...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after
491 DVLOG(1) << class_name() << "::" << __FUNCTION__; 495 DVLOG(1) << class_name() << "::" << __FUNCTION__;
492 496
493 // After this method returns, decoder thread will not be running. 497 // After this method returns, decoder thread will not be running.
494 498
495 // Set [kInEmergencyStop| state to block already posted ProcessNextFrame(). 499 // Set [kInEmergencyStop| state to block already posted ProcessNextFrame().
496 SetState(kInEmergencyStop); 500 SetState(kInEmergencyStop);
497 501
498 decoder_thread_.Stop(); // synchronous 502 decoder_thread_.Stop(); // synchronous
499 503
500 SetState(kStopped); 504 SetState(kStopped);
505
506 key_request_posted_ = false;
501 } 507 }
502 508
503 void MediaCodecDecoder::CheckLastFrame(bool eos_encountered, 509 void MediaCodecDecoder::CheckLastFrame(bool eos_encountered,
504 bool has_delayed_tasks) { 510 bool has_delayed_tasks) {
505 DCHECK(decoder_thread_.task_runner()->BelongsToCurrentThread()); 511 DCHECK(decoder_thread_.task_runner()->BelongsToCurrentThread());
506 512
507 bool last_frame_when_stopping = GetState() == kStopping && !has_delayed_tasks; 513 bool last_frame_when_stopping = GetState() == kStopping && !has_delayed_tasks;
508 514
509 if (last_frame_when_stopping || eos_encountered) { 515 if (last_frame_when_stopping || eos_encountered) {
510 media_task_runner_->PostTask( 516 media_task_runner_->PostTask(
(...skipping 100 matching lines...) Expand 10 before | Expand all | Expand 10 after
611 DCHECK(decoder_thread_.task_runner()->BelongsToCurrentThread()); 617 DCHECK(decoder_thread_.task_runner()->BelongsToCurrentThread());
612 618
613 DVLOG(2) << class_name() << "::" << __FUNCTION__; 619 DVLOG(2) << class_name() << "::" << __FUNCTION__;
614 620
615 if (eos_enqueued_) { 621 if (eos_enqueued_) {
616 DVLOG(1) << class_name() << "::" << __FUNCTION__ 622 DVLOG(1) << class_name() << "::" << __FUNCTION__
617 << ": eos_enqueued, returning"; 623 << ": eos_enqueued, returning";
618 return true; // Nothing to do 624 return true; // Nothing to do
619 } 625 }
620 626
627 if (key_request_posted_) {
628 DVLOG(1) << class_name() << "::" << __FUNCTION__
629 << ": key_request_posted, returning";
630 return true; // Nothing to do
631 }
632
621 // Keep the number pending video frames low, ideally maintaining 633 // Keep the number pending video frames low, ideally maintaining
622 // the same audio and video duration after stop request 634 // the same audio and video duration after stop request
623 if (NumDelayedRenderTasks() > 1) { 635 if (NumDelayedRenderTasks() > 1) {
624 DVLOG(2) << class_name() << "::" << __FUNCTION__ << ": # delayed buffers (" 636 DVLOG(2) << class_name() << "::" << __FUNCTION__ << ": # delayed buffers ("
625 << NumDelayedRenderTasks() << ") exceeds 1, returning"; 637 << NumDelayedRenderTasks() << ") exceeds 1, returning";
626 return true; // Nothing to do 638 return true; // Nothing to do
627 } 639 }
628 640
629 // Get the next frame from the queue. As we go, request more data and 641 // Get the next frame from the queue. As we go, request more data and
630 // consume |kConfigChanged| units. 642 // consume |kConfigChanged| units.
(...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after
688 700
689 if (drain_decoder_ || unit->is_end_of_stream) { 701 if (drain_decoder_ || unit->is_end_of_stream) {
690 DVLOG(1) << class_name() << "::" << __FUNCTION__ << ": QueueEOS"; 702 DVLOG(1) << class_name() << "::" << __FUNCTION__ << ": QueueEOS";
691 media_codec_bridge_->QueueEOS(index); 703 media_codec_bridge_->QueueEOS(index);
692 eos_enqueued_ = true; 704 eos_enqueued_ = true;
693 return true; 705 return true;
694 } 706 }
695 707
696 DCHECK(unit); 708 DCHECK(unit);
697 709
698 DVLOG(2) << class_name() << "::" << __FUNCTION__ 710 if (unit->key_id.empty() || unit->iv.empty()) {
699 << ": QueueInputBuffer pts:" << unit->timestamp; 711 DVLOG(2) << class_name() << "::" << __FUNCTION__
712 << ": QueueInputBuffer pts:" << unit->timestamp;
700 713
701 status = media_codec_bridge_->QueueInputBuffer( 714 status = media_codec_bridge_->QueueInputBuffer(
702 index, &unit->data[0], unit->data.size(), unit->timestamp); 715 index, &unit->data[0], unit->data.size(), unit->timestamp);
716 } else {
717 DVLOG(2) << class_name() << "::" << __FUNCTION__
718 << ": QueueSecureInputBuffer pts:" << unit->timestamp
719 << " key_id size:" << unit->key_id.size()
720 << " iv size:" << unit->iv.size()
721 << " subsamples size:" << unit->subsamples.size();
703 722
704 if (status == MEDIA_CODEC_ERROR) { 723 status = media_codec_bridge_->QueueSecureInputBuffer(
705 DVLOG(0) << class_name() << "::" << __FUNCTION__ 724 index, &unit->data[0], unit->data.size(),
706 << ": MEDIA_CODEC_ERROR: QueueInputBuffer failed"; 725 reinterpret_cast<const uint8_t*>(&unit->key_id[0]), unit->key_id.size(),
707 media_task_runner_->PostTask(FROM_HERE, internal_error_cb_); 726 reinterpret_cast<const uint8_t*>(&unit->iv[0]), unit->iv.size(),
708 return false; 727 unit->subsamples.empty() ? nullptr : &unit->subsamples[0],
728 unit->subsamples.size(), unit->timestamp);
729 }
730
731 switch (status) {
732 case MEDIA_CODEC_OK:
733 break;
734
735 case MEDIA_CODEC_ERROR:
736 DVLOG(0) << class_name() << "::" << __FUNCTION__
737 << ": MEDIA_CODEC_ERROR: QueueInputBuffer failed";
738 media_task_runner_->PostTask(FROM_HERE, internal_error_cb_);
739 return false;
740
741 case MEDIA_CODEC_NO_KEY:
742 DVLOG(1) << class_name() << "::" << __FUNCTION__
743 << ": MEDIA_CODEC_NO_KEY";
744 media_task_runner_->PostTask(FROM_HERE, key_required_cb_);
745
746 // In response to the |key_required_cb_| the player will request to stop
747 // decoder. We need to keep running to properly perform the stop, but
748 // prevent enqueuing the same frame over and over again so we won't
749 // generate more |key_required_cb_|.
750 key_request_posted_ = true;
751 return true;
752
753 default:
754 NOTREACHED() << class_name() << "::" << __FUNCTION__
755 << ": unexpected error code " << status;
756 media_task_runner_->PostTask(FROM_HERE, internal_error_cb_);
757 return false;
709 } 758 }
710 759
711 // Have successfully queued input buffer, go to next access unit. 760 // Have successfully queued input buffer, go to next access unit.
712 au_queue_.Advance(); 761 au_queue_.Advance();
713 return true; 762 return true;
714 } 763 }
715 764
716 AccessUnitQueue::Info MediaCodecDecoder::AdvanceAccessUnitQueue( 765 AccessUnitQueue::Info MediaCodecDecoder::AdvanceAccessUnitQueue(
717 bool* drain_decoder) { 766 bool* drain_decoder) {
718 DCHECK(decoder_thread_.task_runner()->BelongsToCurrentThread()); 767 DCHECK(decoder_thread_.task_runner()->BelongsToCurrentThread());
(...skipping 177 matching lines...) Expand 10 before | Expand all | Expand 10 after
896 RETURN_STRING(kStopping); 945 RETURN_STRING(kStopping);
897 RETURN_STRING(kInEmergencyStop); 946 RETURN_STRING(kInEmergencyStop);
898 RETURN_STRING(kError); 947 RETURN_STRING(kError);
899 } 948 }
900 return nullptr; // crash early 949 return nullptr; // crash early
901 } 950 }
902 951
903 #undef RETURN_STRING 952 #undef RETURN_STRING
904 953
905 } // namespace media 954 } // namespace media
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698