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

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

Issue 1287423004: MediaCodecPlayer implementation (stage 5 - reconfiguration) (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@mtplayer-cleanuptest
Patch Set: Deleted better Created 5 years, 4 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 17 matching lines...) Expand all
28 const int kInputBufferTimeout = 20; 28 const int kInputBufferTimeout = 20;
29 29
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& stop_done_cb, 39 const base::Closure& stop_done_cb,
39 const base::Closure& error_cb, 40 const base::Closure& error_cb,
40 const char* decoder_thread_name) 41 const char* decoder_thread_name)
41 : media_task_runner_(media_task_runner), 42 : media_task_runner_(media_task_runner),
42 decoder_thread_(decoder_thread_name), 43 decoder_thread_(decoder_thread_name),
43 needs_reconfigure_(false), 44 needs_reconfigure_(false),
45 drain_decoder_(false),
46 always_reconfigure_for_tests_(false),
44 external_request_data_cb_(external_request_data_cb), 47 external_request_data_cb_(external_request_data_cb),
45 starvation_cb_(starvation_cb), 48 starvation_cb_(starvation_cb),
49 decoder_drained_cb_(decoder_drained_cb),
46 stop_done_cb_(stop_done_cb), 50 stop_done_cb_(stop_done_cb),
47 error_cb_(error_cb), 51 error_cb_(error_cb),
48 state_(kStopped), 52 state_(kStopped),
49 needs_preroll_(true), 53 needs_preroll_(true),
50 eos_enqueued_(false), 54 eos_enqueued_(false),
51 completed_(false), 55 completed_(false),
52 last_frame_posted_(false), 56 last_frame_posted_(false),
53 is_data_request_in_progress_(false), 57 is_data_request_in_progress_(false),
54 is_incoming_data_invalid_(false), 58 is_incoming_data_invalid_(false),
55 #ifndef NDEBUG 59 #ifndef NDEBUG
(...skipping 30 matching lines...) Expand all
86 90
87 DVLOG(1) << class_name() << "::" << __FUNCTION__; 91 DVLOG(1) << class_name() << "::" << __FUNCTION__;
88 92
89 // Set [kInEmergencyStop| state to block already posted ProcessNextFrame(). 93 // Set [kInEmergencyStop| state to block already posted ProcessNextFrame().
90 SetState(kInEmergencyStop); 94 SetState(kInEmergencyStop);
91 95
92 decoder_thread_.Stop(); // synchronous 96 decoder_thread_.Stop(); // synchronous
93 97
94 SetState(kStopped); 98 SetState(kStopped);
95 ReleaseMediaCodec(); 99 ReleaseMediaCodec();
96
97 needs_preroll_ = true;
98 } 100 }
99 101
100 void MediaCodecDecoder::Flush() { 102 void MediaCodecDecoder::Flush() {
101 DCHECK(media_task_runner_->BelongsToCurrentThread()); 103 DCHECK(media_task_runner_->BelongsToCurrentThread());
102 104
103 DVLOG(1) << class_name() << "::" << __FUNCTION__; 105 DVLOG(1) << class_name() << "::" << __FUNCTION__;
104 106
105 DCHECK_EQ(GetState(), kStopped); 107 DCHECK_EQ(GetState(), kStopped);
106 108
107 // Flush() is a part of the Seek request. Whenever we request a seek we need 109 // Flush() is a part of the Seek request. Whenever we request a seek we need
108 // to invalidate the current data request. 110 // to invalidate the current data request.
109 if (is_data_request_in_progress_) 111 if (is_data_request_in_progress_)
110 is_incoming_data_invalid_ = true; 112 is_incoming_data_invalid_ = true;
111 113
112 eos_enqueued_ = false; 114 eos_enqueued_ = false;
113 completed_ = false; 115 completed_ = false;
116 drain_decoder_ = false;
114 au_queue_.Flush(); 117 au_queue_.Flush();
115 118
116 #ifndef NDEBUG 119 #ifndef NDEBUG
117 // We check and reset |verify_next_frame_is_key_| on Decoder thread. 120 // We check and reset |verify_next_frame_is_key_| on Decoder thread.
118 // This DCHECK ensures we won't need to lock this variable. 121 // This DCHECK ensures we won't need to lock this variable.
119 DCHECK(!decoder_thread_.IsRunning()); 122 DCHECK(!decoder_thread_.IsRunning());
120 123
121 // For video the first frame after flush must be key frame. 124 // For video the first frame after flush must be key frame.
122 verify_next_frame_is_key_ = true; 125 verify_next_frame_is_key_ = true;
123 #endif 126 #endif
(...skipping 10 matching lines...) Expand all
134 } 137 }
135 } 138 }
136 } 139 }
137 140
138 void MediaCodecDecoder::ReleaseMediaCodec() { 141 void MediaCodecDecoder::ReleaseMediaCodec() {
139 DCHECK(media_task_runner_->BelongsToCurrentThread()); 142 DCHECK(media_task_runner_->BelongsToCurrentThread());
140 143
141 DVLOG(1) << class_name() << "::" << __FUNCTION__; 144 DVLOG(1) << class_name() << "::" << __FUNCTION__;
142 145
143 media_codec_bridge_.reset(); 146 media_codec_bridge_.reset();
147
148 needs_preroll_ = true;
144 } 149 }
145 150
146 bool MediaCodecDecoder::IsPrefetchingOrPlaying() const { 151 bool MediaCodecDecoder::IsPrefetchingOrPlaying() const {
147 DCHECK(media_task_runner_->BelongsToCurrentThread()); 152 DCHECK(media_task_runner_->BelongsToCurrentThread());
148 153
149 // Whether decoder needs to be stopped. 154 // Whether decoder needs to be stopped.
150 base::AutoLock lock(state_lock_); 155 base::AutoLock lock(state_lock_);
151 switch (state_) { 156 switch (state_) {
152 case kPrefetching: 157 case kPrefetching:
153 case kPrefetched: 158 case kPrefetched:
(...skipping 22 matching lines...) Expand all
176 181
177 return completed_; 182 return completed_;
178 } 183 }
179 184
180 bool MediaCodecDecoder::NeedsPreroll() const { 185 bool MediaCodecDecoder::NeedsPreroll() const {
181 DCHECK(media_task_runner_->BelongsToCurrentThread()); 186 DCHECK(media_task_runner_->BelongsToCurrentThread());
182 187
183 return HasStream() && needs_preroll_ && !completed_; 188 return HasStream() && needs_preroll_ && !completed_;
184 } 189 }
185 190
191 void MediaCodecDecoder::SetNeedsPreroll() {
192 DCHECK(media_task_runner_->BelongsToCurrentThread());
193 DVLOG(1) << class_name() << "::" << __FUNCTION__;
194
195 needs_preroll_ = true;
196 }
197
186 base::android::ScopedJavaLocalRef<jobject> MediaCodecDecoder::GetMediaCrypto() { 198 base::android::ScopedJavaLocalRef<jobject> MediaCodecDecoder::GetMediaCrypto() {
187 base::android::ScopedJavaLocalRef<jobject> media_crypto; 199 base::android::ScopedJavaLocalRef<jobject> media_crypto;
188 200
189 // TODO(timav): implement DRM. 201 // TODO(timav): implement DRM.
190 // drm_bridge_ is not implemented 202 // drm_bridge_ is not implemented
191 // if (drm_bridge_) 203 // if (drm_bridge_)
192 // media_crypto = drm_bridge_->GetMediaCrypto(); 204 // media_crypto = drm_bridge_->GetMediaCrypto();
193 return media_crypto; 205 return media_crypto;
194 } 206 }
195 207
(...skipping 20 matching lines...) Expand all
216 return kConfigFailure; 228 return kConfigFailure;
217 } 229 }
218 230
219 if (needs_reconfigure_) { 231 if (needs_reconfigure_) {
220 DVLOG(1) << class_name() << "::" << __FUNCTION__ 232 DVLOG(1) << class_name() << "::" << __FUNCTION__
221 << ": needs reconfigure, deleting MediaCodec"; 233 << ": needs reconfigure, deleting MediaCodec";
222 needs_reconfigure_ = false; 234 needs_reconfigure_ = false;
223 ReleaseMediaCodec(); 235 ReleaseMediaCodec();
224 } 236 }
225 237
226 MediaCodecDecoder::ConfigStatus result;
227 if (media_codec_bridge_) { 238 if (media_codec_bridge_) {
228 DVLOG(1) << class_name() << "::" << __FUNCTION__ 239 DVLOG(1) << class_name() << "::" << __FUNCTION__
229 << ": reconfiguration is not required, ignoring"; 240 << ": reconfiguration is not required, ignoring";
230 result = kConfigOk; 241 return kConfigOk;
231 } else { 242 }
232 result = ConfigureInternal(); 243
244 // Read all |kConfigChanged| units preceding the data one.
245 AccessUnitQueue::Info au_info = au_queue_.GetInfo();
246 while (au_info.configs) {
247 SetDemuxerConfigs(*au_info.configs);
248 au_queue_.Advance();
249 au_info = au_queue_.GetInfo();
250 }
251
252 MediaCodecDecoder::ConfigStatus result = ConfigureInternal();
233 253
234 #ifndef NDEBUG 254 #ifndef NDEBUG
235 // We check and reset |verify_next_frame_is_key_| on Decoder thread. 255 // We check and reset |verify_next_frame_is_key_| on Decoder thread.
236 // This DCHECK ensures we won't need to lock this variable. 256 // This DCHECK ensures we won't need to lock this variable.
237 DCHECK(!decoder_thread_.IsRunning()); 257 DCHECK(!decoder_thread_.IsRunning());
238 258
239 // For video the first frame after reconfiguration must be key frame. 259 // For video the first frame after reconfiguration must be key frame.
240 if (result == kConfigOk) 260 if (result == kConfigOk)
241 verify_next_frame_is_key_ = true; 261 verify_next_frame_is_key_ = true;
242 #endif 262 #endif
243 }
244 263
245 return result; 264 return result;
246 } 265 }
247 266
248 bool MediaCodecDecoder::Preroll(base::TimeDelta preroll_timestamp, 267 bool MediaCodecDecoder::Preroll(base::TimeDelta preroll_timestamp,
249 const base::Closure& preroll_done_cb) { 268 const base::Closure& preroll_done_cb) {
250 DCHECK(media_task_runner_->BelongsToCurrentThread()); 269 DCHECK(media_task_runner_->BelongsToCurrentThread());
251 270
252 DVLOG(1) << class_name() << "::" << __FUNCTION__ 271 DVLOG(1) << class_name() << "::" << __FUNCTION__
253 << " preroll_timestamp:" << preroll_timestamp; 272 << " preroll_timestamp:" << preroll_timestamp;
(...skipping 124 matching lines...) Expand 10 before | Expand all | Expand 10 after
378 // Synchronous stop. 397 // Synchronous stop.
379 decoder_thread_.Stop(); 398 decoder_thread_.Stop();
380 SetState(kStopped); 399 SetState(kStopped);
381 media_task_runner_->PostTask(FROM_HERE, stop_done_cb_); 400 media_task_runner_->PostTask(FROM_HERE, stop_done_cb_);
382 break; 401 break;
383 case kStopping: 402 case kStopping:
384 break; // ignore 403 break; // ignore
385 case kStopped: 404 case kStopped:
386 case kPrefetching: 405 case kPrefetching:
387 case kPrefetched: 406 case kPrefetched:
388 // There is nothing to wait for, we can sent nofigication right away. 407 // There is nothing to wait for, we can sent notification right away.
389 DCHECK(!decoder_thread_.IsRunning()); 408 DCHECK(!decoder_thread_.IsRunning());
390 SetState(kStopped); 409 SetState(kStopped);
391 media_task_runner_->PostTask(FROM_HERE, stop_done_cb_); 410 media_task_runner_->PostTask(FROM_HERE, stop_done_cb_);
392 break; 411 break;
393 default: 412 default:
394 NOTREACHED(); 413 NOTREACHED();
395 break; 414 break;
396 } 415 }
397 } 416 }
398 417
399 void MediaCodecDecoder::OnLastFrameRendered(bool completed) { 418 void MediaCodecDecoder::OnLastFrameRendered(bool eos_encountered) {
400 DCHECK(media_task_runner_->BelongsToCurrentThread()); 419 DCHECK(media_task_runner_->BelongsToCurrentThread());
401 420
402 DVLOG(0) << class_name() << "::" << __FUNCTION__ 421 DVLOG(1) << class_name() << "::" << __FUNCTION__
403 << " completed:" << completed; 422 << " eos_encountered:" << eos_encountered;
404 423
405 decoder_thread_.Stop(); // synchronous 424 decoder_thread_.Stop(); // synchronous
406 425
407 SetState(kStopped); 426 SetState(kStopped);
408 completed_ = completed; 427 completed_ = (eos_encountered && !drain_decoder_);
409 428
410 if (completed_ && !preroll_done_cb_.is_null()) 429 if (completed_ && !preroll_done_cb_.is_null()) {
411 media_task_runner_->PostTask(FROM_HERE, 430 media_task_runner_->PostTask(FROM_HERE,
412 base::ResetAndReturn(&preroll_done_cb_)); 431 base::ResetAndReturn(&preroll_done_cb_));
432 }
433
434 if (eos_encountered && drain_decoder_) {
435 ReleaseMediaCodec();
436 drain_decoder_ = false;
437 eos_enqueued_ = false;
438 media_task_runner_->PostTask(FROM_HERE, decoder_drained_cb_);
439 }
413 440
414 media_task_runner_->PostTask(FROM_HERE, stop_done_cb_); 441 media_task_runner_->PostTask(FROM_HERE, stop_done_cb_);
415 } 442 }
416 443
417 void MediaCodecDecoder::OnPrerollDone() { 444 void MediaCodecDecoder::OnPrerollDone() {
418 DCHECK(media_task_runner_->BelongsToCurrentThread()); 445 DCHECK(media_task_runner_->BelongsToCurrentThread());
419 446
420 DVLOG(1) << class_name() << "::" << __FUNCTION__; 447 DVLOG(1) << class_name() << "::" << __FUNCTION__;
421 448
422 if (GetState() == kPrerolling) { 449 if (GetState() == kPrerolling) {
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after
457 // data after kAborted and before the OnDemuxerSeekDone. 484 // data after kAborted and before the OnDemuxerSeekDone.
458 if (GetState() == kPrefetching && !aborted_data) 485 if (GetState() == kPrefetching && !aborted_data)
459 PrefetchNextChunk(); 486 PrefetchNextChunk();
460 } 487 }
461 488
462 bool MediaCodecDecoder::IsPrerollingForTests() const { 489 bool MediaCodecDecoder::IsPrerollingForTests() const {
463 // UI task runner. 490 // UI task runner.
464 return GetState() == kPrerolling; 491 return GetState() == kPrerolling;
465 } 492 }
466 493
494 void MediaCodecDecoder::SetAlwaysReconfigureForTests() {
495 // UI task runner.
496 always_reconfigure_for_tests_ = true;
497 }
498
467 int MediaCodecDecoder::NumDelayedRenderTasks() const { 499 int MediaCodecDecoder::NumDelayedRenderTasks() const {
468 return 0; 500 return 0;
469 } 501 }
470 502
471 void MediaCodecDecoder::CheckLastFrame(bool eos_encountered, 503 void MediaCodecDecoder::CheckLastFrame(bool eos_encountered,
472 bool has_delayed_tasks) { 504 bool has_delayed_tasks) {
473 DCHECK(decoder_thread_.task_runner()->BelongsToCurrentThread()); 505 DCHECK(decoder_thread_.task_runner()->BelongsToCurrentThread());
474 506
475 bool last_frame_when_stopping = GetState() == kStopping && !has_delayed_tasks; 507 bool last_frame_when_stopping = GetState() == kStopping && !has_delayed_tasks;
476 508
(...skipping 111 matching lines...) Expand 10 before | Expand all | Expand 10 after
588 // Keep the number pending video frames low, ideally maintaining 620 // Keep the number pending video frames low, ideally maintaining
589 // the same audio and video duration after stop request 621 // the same audio and video duration after stop request
590 if (NumDelayedRenderTasks() > 1) { 622 if (NumDelayedRenderTasks() > 1) {
591 DVLOG(2) << class_name() << "::" << __FUNCTION__ << ": # delayed buffers (" 623 DVLOG(2) << class_name() << "::" << __FUNCTION__ << ": # delayed buffers ("
592 << NumDelayedRenderTasks() << ") exceeds 1, returning"; 624 << NumDelayedRenderTasks() << ") exceeds 1, returning";
593 return true; // Nothing to do 625 return true; // Nothing to do
594 } 626 }
595 627
596 // Get the next frame from the queue and the queue info 628 // Get the next frame from the queue and the queue info
597 629
598 AccessUnitQueue::Info au_info = au_queue_.GetInfo(); 630 // Retrieve access units from the |au_queue_| in a loop until we either get
631 // a non-config front unit or until the new config is incompatible and we need
632 // to drain decoder.
599 633
600 // Request the data from Demuxer 634 AccessUnitQueue::Info au_info;
601 if (au_info.length <= kPlaybackLowLimit && !au_info.has_eos) 635 do {
602 media_task_runner_->PostTask(FROM_HERE, request_data_cb_); 636 // |drain_decoder_| can be set here upon the first time we enter the loop if
637 // we could not dequeue the input buffer for it right away.
638 if (drain_decoder_)
639 break;
603 640
604 // Get the next frame from the queue 641 au_info = au_queue_.GetInfo();
605 642
606 if (!au_info.length) { 643 // Request the data from Demuxer
607 // Report starvation and return, Start() will be called again later. 644 if (au_info.length <= kPlaybackLowLimit && !au_info.has_eos)
608 DVLOG(1) << class_name() << "::" << __FUNCTION__ << ": starvation detected"; 645 media_task_runner_->PostTask(FROM_HERE, request_data_cb_);
609 media_task_runner_->PostTask(FROM_HERE, starvation_cb_);
610 return true;
611 }
612 646
613 if (au_info.configs) { 647 // Get the next frame from the queue
614 DVLOG(1) << class_name() << "::" << __FUNCTION__ 648
615 << ": received new configs, not implemented"; 649 if (!au_info.length) {
616 // post an error for now? 650 // Report starvation and return, Start() will be called again later.
617 media_task_runner_->PostTask(FROM_HERE, internal_error_cb_); 651 DVLOG(1) << class_name() << "::" << __FUNCTION__
618 return false; 652 << ": starvation detected";
619 } 653 media_task_runner_->PostTask(FROM_HERE, starvation_cb_);
654 return true;
655 }
656
657 if (au_info.configs) {
658 DVLOG(1) << class_name() << "::" << __FUNCTION__ << ": received configs "
659 << (*au_info.configs);
660
661 // Compare the new and current configs.
662 if (IsCodecReconfigureNeeded(*au_info.configs)) {
663 DVLOG(1) << class_name() << "::" << __FUNCTION__
664 << ": reconfiguration required";
665 drain_decoder_ = true;
666 }
667
668 // Replace the current configs.
669 SetDemuxerConfigs(*au_info.configs);
670
671 // Remove the configs from the queue.
672 au_queue_.Advance();
673 }
674 } while (au_info.configs);
620 675
621 // We are ready to enqueue the front unit. 676 // We are ready to enqueue the front unit.
622 677
678 DCHECK(au_info.front_unit);
679
623 #ifndef NDEBUG 680 #ifndef NDEBUG
624 if (verify_next_frame_is_key_) { 681 if (verify_next_frame_is_key_ && !drain_decoder_) {
625 verify_next_frame_is_key_ = false; 682 verify_next_frame_is_key_ = false;
626 VerifyUnitIsKeyFrame(au_info.front_unit); 683 VerifyUnitIsKeyFrame(au_info.front_unit);
627 } 684 }
628 #endif 685 #endif
629 686
630 // Dequeue input buffer 687 // Dequeue input buffer
631 688
632 base::TimeDelta timeout = 689 base::TimeDelta timeout =
633 base::TimeDelta::FromMilliseconds(kInputBufferTimeout); 690 base::TimeDelta::FromMilliseconds(kInputBufferTimeout);
634 int index = -1; 691 int index = -1;
(...skipping 17 matching lines...) Expand all
652 709
653 default: 710 default:
654 break; 711 break;
655 } 712 }
656 713
657 // We got the buffer 714 // We got the buffer
658 DCHECK_EQ(status, MEDIA_CODEC_OK); 715 DCHECK_EQ(status, MEDIA_CODEC_OK);
659 DCHECK_GE(index, 0); 716 DCHECK_GE(index, 0);
660 717
661 const AccessUnit* unit = au_info.front_unit; 718 const AccessUnit* unit = au_info.front_unit;
719
662 DCHECK(unit); 720 DCHECK(unit);
663 721
664 if (unit->is_end_of_stream) { 722 if (drain_decoder_ || unit->is_end_of_stream) {
665 DVLOG(1) << class_name() << "::" << __FUNCTION__ << ": QueueEOS"; 723 DVLOG(1) << class_name() << "::" << __FUNCTION__ << ": QueueEOS";
666 media_codec_bridge_->QueueEOS(index); 724 media_codec_bridge_->QueueEOS(index);
667 eos_enqueued_ = true; 725 eos_enqueued_ = true;
668 return true; 726 return true;
669 } 727 }
670 728
671 DVLOG(2) << class_name() << ":: QueueInputBuffer pts:" << unit->timestamp; 729 DVLOG(2) << class_name() << ":: QueueInputBuffer pts:" << unit->timestamp;
672 730
673 status = media_codec_bridge_->QueueInputBuffer( 731 status = media_codec_bridge_->QueueInputBuffer(
674 index, &unit->data[0], unit->data.size(), unit->timestamp); 732 index, &unit->data[0], unit->data.size(), unit->timestamp);
(...skipping 141 matching lines...) Expand 10 before | Expand all | Expand 10 after
816 RETURN_STRING(kStopping); 874 RETURN_STRING(kStopping);
817 RETURN_STRING(kInEmergencyStop); 875 RETURN_STRING(kInEmergencyStop);
818 RETURN_STRING(kError); 876 RETURN_STRING(kError);
819 } 877 }
820 return nullptr; // crash early 878 return nullptr; // crash early
821 } 879 }
822 880
823 #undef RETURN_STRING 881 #undef RETURN_STRING
824 882
825 } // namespace media 883 } // namespace media
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698