Update V8 to version 4.7.56.
[chromium-blink-merge.git] / media / base / android / media_codec_decoder.cc
blobfd8d84ecc60787c1eced4114010f086dd985e1e3
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
3 // found in the LICENSE file.
5 #include "media/base/android/media_codec_decoder.h"
7 #include "base/bind.h"
8 #include "base/bind_helpers.h"
9 #include "base/callback_helpers.h"
10 #include "base/logging.h"
11 #include "media/base/android/media_codec_bridge.h"
13 namespace media {
15 namespace {
17 // Stop requesting new data in the kPrefetching state when the queue size
18 // reaches this limit.
19 const int kPrefetchLimit = 8;
21 // Request new data in the kRunning state if the queue size is less than this.
22 const int kPlaybackLowLimit = 4;
24 // Posting delay of the next frame processing, in milliseconds
25 const int kNextFrameDelay = 1;
27 // Timeout for dequeuing an input buffer from MediaCodec in milliseconds.
28 const int kInputBufferTimeout = 20;
30 // Timeout for dequeuing an output buffer from MediaCodec in milliseconds.
31 const int kOutputBufferTimeout = 20;
34 MediaCodecDecoder::MediaCodecDecoder(
35 const scoped_refptr<base::SingleThreadTaskRunner>& media_task_runner,
36 const base::Closure& external_request_data_cb,
37 const base::Closure& starvation_cb,
38 const base::Closure& decoder_drained_cb,
39 const base::Closure& stop_done_cb,
40 const base::Closure& error_cb,
41 const char* decoder_thread_name)
42 : media_task_runner_(media_task_runner),
43 decoder_thread_(decoder_thread_name),
44 needs_reconfigure_(false),
45 drain_decoder_(false),
46 always_reconfigure_for_tests_(false),
47 external_request_data_cb_(external_request_data_cb),
48 starvation_cb_(starvation_cb),
49 decoder_drained_cb_(decoder_drained_cb),
50 stop_done_cb_(stop_done_cb),
51 error_cb_(error_cb),
52 state_(kStopped),
53 is_prepared_(false),
54 eos_enqueued_(false),
55 completed_(false),
56 last_frame_posted_(false),
57 is_data_request_in_progress_(false),
58 is_incoming_data_invalid_(false),
59 #ifndef NDEBUG
60 verify_next_frame_is_key_(false),
61 #endif
62 weak_factory_(this) {
63 DCHECK(media_task_runner_->BelongsToCurrentThread());
65 DVLOG(1) << "Decoder::Decoder() " << decoder_thread_name;
67 internal_error_cb_ =
68 base::Bind(&MediaCodecDecoder::OnCodecError, weak_factory_.GetWeakPtr());
69 internal_preroll_done_cb_ =
70 base::Bind(&MediaCodecDecoder::OnPrerollDone, weak_factory_.GetWeakPtr());
71 request_data_cb_ =
72 base::Bind(&MediaCodecDecoder::RequestData, weak_factory_.GetWeakPtr());
75 MediaCodecDecoder::~MediaCodecDecoder() {}
77 const char* MediaCodecDecoder::class_name() const {
78 return "Decoder";
81 void MediaCodecDecoder::Flush() {
82 DCHECK(media_task_runner_->BelongsToCurrentThread());
84 DVLOG(1) << class_name() << "::" << __FUNCTION__;
86 DCHECK_EQ(GetState(), kStopped);
88 // Flush() is a part of the Seek request. Whenever we request a seek we need
89 // to invalidate the current data request.
90 if (is_data_request_in_progress_)
91 is_incoming_data_invalid_ = true;
93 eos_enqueued_ = false;
94 completed_ = false;
95 drain_decoder_ = false;
96 au_queue_.Flush();
98 // |is_prepared_| is set on the decoder thread, it shouldn't be running now.
99 DCHECK(!decoder_thread_.IsRunning());
100 is_prepared_ = false;
102 #ifndef NDEBUG
103 // We check and reset |verify_next_frame_is_key_| on Decoder thread.
104 // We have just DCHECKed that decoder thread is not running.
106 // For video the first frame after flush must be key frame.
107 verify_next_frame_is_key_ = true;
108 #endif
110 if (media_codec_bridge_) {
111 // MediaCodecBridge::Reset() performs MediaCodecBridge.flush()
112 MediaCodecStatus flush_status = media_codec_bridge_->Reset();
113 if (flush_status != MEDIA_CODEC_OK) {
114 DVLOG(0) << class_name() << "::" << __FUNCTION__
115 << "MediaCodecBridge::Reset() failed";
116 media_task_runner_->PostTask(FROM_HERE, internal_error_cb_);
121 void MediaCodecDecoder::ReleaseMediaCodec() {
122 DCHECK(media_task_runner_->BelongsToCurrentThread());
124 DVLOG(1) << class_name() << "::" << __FUNCTION__;
126 DCHECK(!decoder_thread_.IsRunning());
128 media_codec_bridge_.reset();
130 // |is_prepared_| is set on the decoder thread, it shouldn't be running now.
131 is_prepared_ = false;
134 bool MediaCodecDecoder::IsPrefetchingOrPlaying() const {
135 DCHECK(media_task_runner_->BelongsToCurrentThread());
137 // Whether decoder needs to be stopped.
138 base::AutoLock lock(state_lock_);
139 switch (state_) {
140 case kPrefetching:
141 case kPrefetched:
142 case kPrerolling:
143 case kPrerolled:
144 case kRunning:
145 return true;
146 case kStopped:
147 case kStopping:
148 case kInEmergencyStop:
149 case kError:
150 return false;
152 NOTREACHED();
153 return false;
156 bool MediaCodecDecoder::IsStopped() const {
157 DCHECK(media_task_runner_->BelongsToCurrentThread());
159 return GetState() == kStopped;
162 bool MediaCodecDecoder::IsCompleted() const {
163 DCHECK(media_task_runner_->BelongsToCurrentThread());
165 return completed_;
168 bool MediaCodecDecoder::NotCompletedAndNeedsPreroll() const {
169 DCHECK(media_task_runner_->BelongsToCurrentThread());
171 return HasStream() && !completed_ &&
172 (!is_prepared_ || preroll_timestamp_ != base::TimeDelta());
175 void MediaCodecDecoder::SetPrerollTimestamp(base::TimeDelta preroll_timestamp) {
176 DCHECK(media_task_runner_->BelongsToCurrentThread());
177 DVLOG(1) << class_name() << "::" << __FUNCTION__ << ": " << preroll_timestamp;
179 preroll_timestamp_ = preroll_timestamp;
182 base::android::ScopedJavaLocalRef<jobject> MediaCodecDecoder::GetMediaCrypto() {
183 base::android::ScopedJavaLocalRef<jobject> media_crypto;
185 // TODO(timav): implement DRM.
186 // drm_bridge_ is not implemented
187 // if (drm_bridge_)
188 // media_crypto = drm_bridge_->GetMediaCrypto();
189 return media_crypto;
192 void MediaCodecDecoder::Prefetch(const base::Closure& prefetch_done_cb) {
193 DCHECK(media_task_runner_->BelongsToCurrentThread());
195 DVLOG(1) << class_name() << "::" << __FUNCTION__;
197 DCHECK(GetState() == kStopped);
199 prefetch_done_cb_ = prefetch_done_cb;
201 SetState(kPrefetching);
202 PrefetchNextChunk();
205 MediaCodecDecoder::ConfigStatus MediaCodecDecoder::Configure() {
206 DCHECK(media_task_runner_->BelongsToCurrentThread());
208 DVLOG(1) << class_name() << "::" << __FUNCTION__;
210 if (GetState() == kError) {
211 DVLOG(0) << class_name() << "::" << __FUNCTION__ << ": wrong state kError";
212 return kConfigFailure;
215 if (needs_reconfigure_) {
216 DVLOG(1) << class_name() << "::" << __FUNCTION__
217 << ": needs reconfigure, deleting MediaCodec";
218 needs_reconfigure_ = false;
219 ReleaseMediaCodec();
222 if (media_codec_bridge_) {
223 DVLOG(1) << class_name() << "::" << __FUNCTION__
224 << ": reconfiguration is not required, ignoring";
225 return kConfigOk;
228 // Read all |kConfigChanged| units preceding the data one.
229 AccessUnitQueue::Info au_info = au_queue_.GetInfo();
230 while (au_info.configs) {
231 SetDemuxerConfigs(*au_info.configs);
232 au_queue_.Advance();
233 au_info = au_queue_.GetInfo();
236 MediaCodecDecoder::ConfigStatus result = ConfigureInternal();
238 #ifndef NDEBUG
239 // We check and reset |verify_next_frame_is_key_| on Decoder thread.
240 // This DCHECK ensures we won't need to lock this variable.
241 DCHECK(!decoder_thread_.IsRunning());
243 // For video the first frame after reconfiguration must be key frame.
244 if (result == kConfigOk)
245 verify_next_frame_is_key_ = true;
246 #endif
248 return result;
251 bool MediaCodecDecoder::Preroll(const base::Closure& preroll_done_cb) {
252 DCHECK(media_task_runner_->BelongsToCurrentThread());
254 DVLOG(1) << class_name() << "::" << __FUNCTION__
255 << " preroll_timestamp:" << preroll_timestamp_;
257 DecoderState state = GetState();
258 if (state != kPrefetched) {
259 DVLOG(0) << class_name() << "::" << __FUNCTION__ << ": wrong state "
260 << AsString(state) << ", ignoring";
261 return false;
264 if (!media_codec_bridge_) {
265 DVLOG(0) << class_name() << "::" << __FUNCTION__
266 << ": not configured, ignoring";
267 return false;
270 DCHECK(!decoder_thread_.IsRunning());
272 preroll_done_cb_ = preroll_done_cb;
274 // We only synchronize video stream.
275 DissociatePTSFromTime(); // associaton will happen after preroll is done.
277 last_frame_posted_ = false;
279 // Start the decoder thread
280 if (!decoder_thread_.Start()) {
281 DVLOG(0) << class_name() << "::" << __FUNCTION__
282 << ": cannot start decoder thread";
283 return false;
286 SetState(kPrerolling);
288 decoder_thread_.task_runner()->PostTask(
289 FROM_HERE,
290 base::Bind(&MediaCodecDecoder::ProcessNextFrame, base::Unretained(this)));
292 return true;
295 bool MediaCodecDecoder::Start(base::TimeDelta start_timestamp) {
296 DCHECK(media_task_runner_->BelongsToCurrentThread());
298 DVLOG(1) << class_name() << "::" << __FUNCTION__
299 << " start_timestamp:" << start_timestamp;
301 DecoderState state = GetState();
303 if (state != kPrefetched && state != kPrerolled) {
304 DVLOG(0) << class_name() << "::" << __FUNCTION__ << ": wrong state "
305 << AsString(state) << ", ignoring";
306 return false;
309 if (!media_codec_bridge_) {
310 DVLOG(0) << class_name() << "::" << __FUNCTION__
311 << ": not configured, ignoring";
312 return false;
315 // We only synchronize video stream.
316 AssociateCurrentTimeWithPTS(start_timestamp);
318 DCHECK(preroll_timestamp_ == base::TimeDelta());
320 // Start the decoder thread
321 if (!decoder_thread_.IsRunning()) {
322 last_frame_posted_ = false;
323 if (!decoder_thread_.Start()) {
324 DVLOG(1) << class_name() << "::" << __FUNCTION__
325 << ": cannot start decoder thread";
326 return false;
330 SetState(kRunning);
332 decoder_thread_.task_runner()->PostTask(
333 FROM_HERE,
334 base::Bind(&MediaCodecDecoder::ProcessNextFrame, base::Unretained(this)));
336 return true;
339 void MediaCodecDecoder::SyncStop() {
340 DCHECK(media_task_runner_->BelongsToCurrentThread());
342 DVLOG(1) << class_name() << "::" << __FUNCTION__;
344 if (GetState() == kError) {
345 DVLOG(0) << class_name() << "::" << __FUNCTION__
346 << ": wrong state kError, ignoring";
347 return;
350 DoEmergencyStop();
352 ReleaseDelayedBuffers();
355 void MediaCodecDecoder::RequestToStop() {
356 DCHECK(media_task_runner_->BelongsToCurrentThread());
358 DVLOG(1) << class_name() << "::" << __FUNCTION__;
360 DecoderState state = GetState();
361 switch (state) {
362 case kError:
363 DVLOG(0) << class_name() << "::" << __FUNCTION__
364 << ": wrong state kError, ignoring";
365 break;
366 case kRunning:
367 SetState(kStopping);
368 break;
369 case kPrerolling:
370 case kPrerolled:
371 DCHECK(decoder_thread_.IsRunning());
372 // Synchronous stop.
373 decoder_thread_.Stop();
374 SetState(kStopped);
375 media_task_runner_->PostTask(FROM_HERE, stop_done_cb_);
376 break;
377 case kStopping:
378 case kStopped:
379 break; // ignore
380 case kPrefetching:
381 case kPrefetched:
382 // There is nothing to wait for, we can sent notification right away.
383 DCHECK(!decoder_thread_.IsRunning());
384 SetState(kStopped);
385 media_task_runner_->PostTask(FROM_HERE, stop_done_cb_);
386 break;
387 default:
388 NOTREACHED();
389 break;
393 void MediaCodecDecoder::OnLastFrameRendered(bool eos_encountered) {
394 DCHECK(media_task_runner_->BelongsToCurrentThread());
396 DVLOG(1) << class_name() << "::" << __FUNCTION__
397 << " eos_encountered:" << eos_encountered;
399 decoder_thread_.Stop(); // synchronous
401 SetState(kStopped);
402 completed_ = (eos_encountered && !drain_decoder_);
404 // 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.
406 if (completed_ && !preroll_done_cb_.is_null()) {
407 preroll_timestamp_ = base::TimeDelta();
408 media_task_runner_->PostTask(FROM_HERE,
409 base::ResetAndReturn(&preroll_done_cb_));
412 if (eos_encountered && drain_decoder_) {
413 drain_decoder_ = false;
414 eos_enqueued_ = false;
415 ReleaseMediaCodec();
416 media_task_runner_->PostTask(FROM_HERE, decoder_drained_cb_);
419 media_task_runner_->PostTask(FROM_HERE, stop_done_cb_);
422 void MediaCodecDecoder::OnPrerollDone() {
423 DCHECK(media_task_runner_->BelongsToCurrentThread());
425 DVLOG(1) << class_name() << "::" << __FUNCTION__
426 << " state:" << AsString(GetState());
428 preroll_timestamp_ = base::TimeDelta();
430 // The state might be kStopping (?)
431 if (GetState() == kPrerolling)
432 SetState(kPrerolled);
434 if (!preroll_done_cb_.is_null())
435 base::ResetAndReturn(&preroll_done_cb_).Run();
438 void MediaCodecDecoder::OnDemuxerDataAvailable(const DemuxerData& data) {
439 DCHECK(media_task_runner_->BelongsToCurrentThread());
441 // If |data| contains an aborted data, the last AU will have kAborted status.
442 bool aborted_data =
443 !data.access_units.empty() &&
444 data.access_units.back().status == DemuxerStream::kAborted;
446 #ifndef NDEBUG
447 const char* explain_if_skipped =
448 is_incoming_data_invalid_ ? " skipped as invalid"
449 : (aborted_data ? " skipped as aborted" : "");
451 for (const auto& unit : data.access_units)
452 DVLOG(2) << class_name() << "::" << __FUNCTION__ << explain_if_skipped
453 << " au: " << unit;
454 for (const auto& configs : data.demuxer_configs)
455 DVLOG(2) << class_name() << "::" << __FUNCTION__ << " configs: " << configs;
456 #endif
458 if (!is_incoming_data_invalid_ && !aborted_data)
459 au_queue_.PushBack(data);
461 is_incoming_data_invalid_ = false;
462 is_data_request_in_progress_ = false;
464 // Do not request data if we got kAborted. There is no point to request the
465 // data after kAborted and before the OnDemuxerSeekDone.
466 if (GetState() == kPrefetching && !aborted_data)
467 PrefetchNextChunk();
470 bool MediaCodecDecoder::IsPrerollingForTests() const {
471 // UI task runner.
472 return GetState() == kPrerolling;
475 void MediaCodecDecoder::SetAlwaysReconfigureForTests() {
476 // UI task runner.
477 always_reconfigure_for_tests_ = true;
480 void MediaCodecDecoder::SetCodecCreatedCallbackForTests(base::Closure cb) {
481 // UI task runner.
482 codec_created_for_tests_cb_ = cb;
485 int MediaCodecDecoder::NumDelayedRenderTasks() const {
486 return 0;
489 void MediaCodecDecoder::DoEmergencyStop() {
490 DCHECK(media_task_runner_->BelongsToCurrentThread());
491 DVLOG(1) << class_name() << "::" << __FUNCTION__;
493 // After this method returns, decoder thread will not be running.
495 // Set [kInEmergencyStop| state to block already posted ProcessNextFrame().
496 SetState(kInEmergencyStop);
498 decoder_thread_.Stop(); // synchronous
500 SetState(kStopped);
503 void MediaCodecDecoder::CheckLastFrame(bool eos_encountered,
504 bool has_delayed_tasks) {
505 DCHECK(decoder_thread_.task_runner()->BelongsToCurrentThread());
507 bool last_frame_when_stopping = GetState() == kStopping && !has_delayed_tasks;
509 if (last_frame_when_stopping || eos_encountered) {
510 media_task_runner_->PostTask(
511 FROM_HERE, base::Bind(&MediaCodecDecoder::OnLastFrameRendered,
512 weak_factory_.GetWeakPtr(), eos_encountered));
513 last_frame_posted_ = true;
517 void MediaCodecDecoder::OnCodecError() {
518 DCHECK(media_task_runner_->BelongsToCurrentThread());
520 // Ignore codec errors from the moment surface is changed till the
521 // |media_codec_bridge_| is deleted.
522 if (needs_reconfigure_) {
523 DVLOG(1) << class_name() << "::" << __FUNCTION__
524 << ": needs reconfigure, ignoring";
525 return;
528 SetState(kError);
529 error_cb_.Run();
532 void MediaCodecDecoder::RequestData() {
533 DCHECK(media_task_runner_->BelongsToCurrentThread());
535 // Ensure one data request at a time.
536 if (!is_data_request_in_progress_) {
537 is_data_request_in_progress_ = true;
538 external_request_data_cb_.Run();
542 void MediaCodecDecoder::PrefetchNextChunk() {
543 DCHECK(media_task_runner_->BelongsToCurrentThread());
545 DVLOG(1) << class_name() << "::" << __FUNCTION__;
547 AccessUnitQueue::Info au_info = au_queue_.GetInfo();
549 if (eos_enqueued_ || au_info.data_length >= kPrefetchLimit ||
550 au_info.has_eos) {
551 // We are done prefetching
552 SetState(kPrefetched);
553 DVLOG(1) << class_name() << "::" << __FUNCTION__ << " posting PrefetchDone";
554 media_task_runner_->PostTask(FROM_HERE,
555 base::ResetAndReturn(&prefetch_done_cb_));
556 return;
559 request_data_cb_.Run();
562 void MediaCodecDecoder::ProcessNextFrame() {
563 DCHECK(decoder_thread_.task_runner()->BelongsToCurrentThread());
565 DVLOG(2) << class_name() << "::" << __FUNCTION__;
567 DecoderState state = GetState();
569 if (state != kPrerolling && state != kRunning && state != kStopping) {
570 DVLOG(1) << class_name() << "::" << __FUNCTION__
571 << ": state: " << AsString(state) << " stopping frame processing";
572 return;
575 if (state == kStopping) {
576 if (NumDelayedRenderTasks() == 0 && !last_frame_posted_) {
577 media_task_runner_->PostTask(
578 FROM_HERE, base::Bind(&MediaCodecDecoder::OnLastFrameRendered,
579 weak_factory_.GetWeakPtr(), false));
580 last_frame_posted_ = true;
583 // We can stop processing, the |au_queue_| and MediaCodec queues can freeze.
584 // We only need to let finish the delayed rendering tasks.
585 DVLOG(1) << class_name() << "::" << __FUNCTION__ << " kStopping, returning";
586 return;
589 DCHECK(state == kPrerolling || state == kRunning);
591 if (!EnqueueInputBuffer())
592 return;
594 if (!DepleteOutputBufferQueue())
595 return;
597 // We need a small delay if we want to stop this thread by
598 // decoder_thread_.Stop() reliably.
599 // The decoder thread message loop processes all pending
600 // (but not delayed) tasks before it can quit; without a delay
601 // the message loop might be forever processing the pendng tasks.
602 decoder_thread_.task_runner()->PostDelayedTask(
603 FROM_HERE,
604 base::Bind(&MediaCodecDecoder::ProcessNextFrame, base::Unretained(this)),
605 base::TimeDelta::FromMilliseconds(kNextFrameDelay));
608 // Returns false if we should stop decoding process. Right now
609 // it happens if we got MediaCodec error or detected starvation.
610 bool MediaCodecDecoder::EnqueueInputBuffer() {
611 DCHECK(decoder_thread_.task_runner()->BelongsToCurrentThread());
613 DVLOG(2) << class_name() << "::" << __FUNCTION__;
615 if (eos_enqueued_) {
616 DVLOG(1) << class_name() << "::" << __FUNCTION__
617 << ": eos_enqueued, returning";
618 return true; // Nothing to do
621 // Keep the number pending video frames low, ideally maintaining
622 // the same audio and video duration after stop request
623 if (NumDelayedRenderTasks() > 1) {
624 DVLOG(2) << class_name() << "::" << __FUNCTION__ << ": # delayed buffers ("
625 << NumDelayedRenderTasks() << ") exceeds 1, returning";
626 return true; // Nothing to do
629 // Get the next frame from the queue. As we go, request more data and
630 // consume |kConfigChanged| units.
632 // |drain_decoder_| can be already set here if we could not dequeue the input
633 // buffer for it right away.
635 AccessUnitQueue::Info au_info;
636 if (!drain_decoder_) {
637 au_info = AdvanceAccessUnitQueue(&drain_decoder_);
638 if (!au_info.length) {
639 // Report starvation and return, Start() will be called again later.
640 DVLOG(1) << class_name() << "::" << __FUNCTION__
641 << ": starvation detected";
642 media_task_runner_->PostTask(FROM_HERE, starvation_cb_);
643 return true;
646 DCHECK(au_info.front_unit);
648 #ifndef NDEBUG
649 if (verify_next_frame_is_key_) {
650 verify_next_frame_is_key_ = false;
651 VerifyUnitIsKeyFrame(au_info.front_unit);
653 #endif
656 // Dequeue input buffer
658 base::TimeDelta timeout =
659 base::TimeDelta::FromMilliseconds(kInputBufferTimeout);
660 int index = -1;
661 MediaCodecStatus status =
662 media_codec_bridge_->DequeueInputBuffer(timeout, &index);
664 DVLOG(2) << class_name() << ":: DequeueInputBuffer index:" << index;
666 switch (status) {
667 case MEDIA_CODEC_ERROR:
668 DVLOG(0) << class_name() << "::" << __FUNCTION__
669 << ": MEDIA_CODEC_ERROR DequeueInputBuffer failed";
670 media_task_runner_->PostTask(FROM_HERE, internal_error_cb_);
671 return false;
673 case MEDIA_CODEC_DEQUEUE_INPUT_AGAIN_LATER:
674 DVLOG(2)
675 << class_name() << "::" << __FUNCTION__
676 << ": DequeueInputBuffer returned MediaCodec.INFO_TRY_AGAIN_LATER.";
677 return true;
679 default:
680 break;
683 // We got the buffer
684 DCHECK_EQ(status, MEDIA_CODEC_OK);
685 DCHECK_GE(index, 0);
687 const AccessUnit* unit = au_info.front_unit;
689 if (drain_decoder_ || unit->is_end_of_stream) {
690 DVLOG(1) << class_name() << "::" << __FUNCTION__ << ": QueueEOS";
691 media_codec_bridge_->QueueEOS(index);
692 eos_enqueued_ = true;
693 return true;
696 DCHECK(unit);
698 DVLOG(2) << class_name() << "::" << __FUNCTION__
699 << ": QueueInputBuffer pts:" << unit->timestamp;
701 status = media_codec_bridge_->QueueInputBuffer(
702 index, &unit->data[0], unit->data.size(), unit->timestamp);
704 if (status == MEDIA_CODEC_ERROR) {
705 DVLOG(0) << class_name() << "::" << __FUNCTION__
706 << ": MEDIA_CODEC_ERROR: QueueInputBuffer failed";
707 media_task_runner_->PostTask(FROM_HERE, internal_error_cb_);
708 return false;
711 // Have successfully queued input buffer, go to next access unit.
712 au_queue_.Advance();
713 return true;
716 AccessUnitQueue::Info MediaCodecDecoder::AdvanceAccessUnitQueue(
717 bool* drain_decoder) {
718 DCHECK(decoder_thread_.task_runner()->BelongsToCurrentThread());
719 DVLOG(2) << class_name() << "::" << __FUNCTION__;
721 // Retrieve access units from the |au_queue_| in a loop until we either get
722 // a non-config front unit or until the queue is empty.
724 DCHECK(drain_decoder != nullptr);
726 AccessUnitQueue::Info au_info;
728 do {
729 // Get current frame
730 au_info = au_queue_.GetInfo();
732 // Request the data from Demuxer
733 if (au_info.data_length <= kPlaybackLowLimit && !au_info.has_eos)
734 media_task_runner_->PostTask(FROM_HERE, request_data_cb_);
736 if (!au_info.length)
737 break; // Starvation
739 if (au_info.configs) {
740 DVLOG(1) << class_name() << "::" << __FUNCTION__ << ": received configs "
741 << (*au_info.configs);
743 // Compare the new and current configs.
744 if (IsCodecReconfigureNeeded(*au_info.configs)) {
745 DVLOG(1) << class_name() << "::" << __FUNCTION__
746 << ": reconfiguration and decoder drain required";
747 *drain_decoder = true;
750 // Replace the current configs.
751 SetDemuxerConfigs(*au_info.configs);
753 // Move to the next frame
754 au_queue_.Advance();
756 } while (au_info.configs);
758 return au_info;
761 // Returns false if there was MediaCodec error.
762 bool MediaCodecDecoder::DepleteOutputBufferQueue() {
763 DCHECK(decoder_thread_.task_runner()->BelongsToCurrentThread());
765 DVLOG(2) << class_name() << "::" << __FUNCTION__;
767 int buffer_index = 0;
768 size_t offset = 0;
769 size_t size = 0;
770 base::TimeDelta pts;
771 MediaCodecStatus status;
772 bool eos_encountered = false;
774 RenderMode render_mode;
776 base::TimeDelta timeout =
777 base::TimeDelta::FromMilliseconds(kOutputBufferTimeout);
779 // Extract all output buffers that are available.
780 // Usually there will be only one, but sometimes it is preceeded by
781 // MEDIA_CODEC_OUTPUT_BUFFERS_CHANGED or MEDIA_CODEC_OUTPUT_FORMAT_CHANGED.
782 do {
783 status = media_codec_bridge_->DequeueOutputBuffer(
784 timeout, &buffer_index, &offset, &size, &pts, &eos_encountered,
785 nullptr);
787 // Reset the timeout to 0 for the subsequent DequeueOutputBuffer() calls
788 // to quickly break the loop after we got all currently available buffers.
789 timeout = base::TimeDelta::FromMilliseconds(0);
791 switch (status) {
792 case MEDIA_CODEC_OUTPUT_BUFFERS_CHANGED:
793 // Output buffers are replaced in MediaCodecBridge, nothing to do.
794 DVLOG(2) << class_name() << "::" << __FUNCTION__
795 << " MEDIA_CODEC_OUTPUT_BUFFERS_CHANGED";
796 break;
798 case MEDIA_CODEC_OUTPUT_FORMAT_CHANGED:
799 DVLOG(2) << class_name() << "::" << __FUNCTION__
800 << " MEDIA_CODEC_OUTPUT_FORMAT_CHANGED";
801 OnOutputFormatChanged();
802 break;
804 case MEDIA_CODEC_OK:
805 // We got the decoded frame.
807 is_prepared_ = true;
809 if (pts < preroll_timestamp_)
810 render_mode = kRenderSkip;
811 else if (GetState() == kPrerolling)
812 render_mode = kRenderAfterPreroll;
813 else
814 render_mode = kRenderNow;
816 Render(buffer_index, offset, size, render_mode, pts, eos_encountered);
818 if (render_mode == kRenderAfterPreroll) {
819 DVLOG(1) << class_name() << "::" << __FUNCTION__ << " pts " << pts
820 << " >= preroll timestamp " << preroll_timestamp_
821 << " preroll done, stopping frame processing";
822 media_task_runner_->PostTask(FROM_HERE, internal_preroll_done_cb_);
823 return false;
825 break;
827 case MEDIA_CODEC_DEQUEUE_OUTPUT_AGAIN_LATER:
828 // Nothing to do.
829 DVLOG(2) << class_name() << "::" << __FUNCTION__
830 << " MEDIA_CODEC_DEQUEUE_OUTPUT_AGAIN_LATER";
831 break;
833 case MEDIA_CODEC_ERROR:
834 DVLOG(0) << class_name() << "::" << __FUNCTION__
835 << ": MEDIA_CODEC_ERROR from DequeueOutputBuffer";
836 media_task_runner_->PostTask(FROM_HERE, internal_error_cb_);
837 break;
839 default:
840 NOTREACHED();
841 break;
844 } while (status != MEDIA_CODEC_DEQUEUE_OUTPUT_AGAIN_LATER &&
845 status != MEDIA_CODEC_ERROR && !eos_encountered);
847 if (eos_encountered) {
848 DVLOG(1) << class_name() << "::" << __FUNCTION__
849 << " EOS dequeued, stopping frame processing";
850 return false;
853 if (status == MEDIA_CODEC_ERROR) {
854 DVLOG(0) << class_name() << "::" << __FUNCTION__
855 << " MediaCodec error, stopping frame processing";
856 return false;
859 return true;
862 MediaCodecDecoder::DecoderState MediaCodecDecoder::GetState() const {
863 base::AutoLock lock(state_lock_);
864 return state_;
867 void MediaCodecDecoder::SetState(DecoderState state) {
868 DVLOG(1) << class_name() << "::" << __FUNCTION__ << " " << AsString(state);
870 base::AutoLock lock(state_lock_);
871 state_ = state;
874 #undef RETURN_STRING
875 #define RETURN_STRING(x) \
876 case x: \
877 return #x;
879 const char* MediaCodecDecoder::AsString(RenderMode render_mode) {
880 switch (render_mode) {
881 RETURN_STRING(kRenderSkip);
882 RETURN_STRING(kRenderAfterPreroll);
883 RETURN_STRING(kRenderNow);
885 return nullptr; // crash early
888 const char* MediaCodecDecoder::AsString(DecoderState state) {
889 switch (state) {
890 RETURN_STRING(kStopped);
891 RETURN_STRING(kPrefetching);
892 RETURN_STRING(kPrefetched);
893 RETURN_STRING(kPrerolling);
894 RETURN_STRING(kPrerolled);
895 RETURN_STRING(kRunning);
896 RETURN_STRING(kStopping);
897 RETURN_STRING(kInEmergencyStop);
898 RETURN_STRING(kError);
900 return nullptr; // crash early
903 #undef RETURN_STRING
905 } // namespace media