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"
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"
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
),
56 last_frame_posted_(false),
57 is_data_request_in_progress_(false),
58 is_incoming_data_invalid_(false),
60 verify_next_frame_is_key_(false),
63 DCHECK(media_task_runner_
->BelongsToCurrentThread());
65 DVLOG(1) << "Decoder::Decoder() " << decoder_thread_name
;
68 base::Bind(&MediaCodecDecoder::OnCodecError
, weak_factory_
.GetWeakPtr());
69 internal_preroll_done_cb_
=
70 base::Bind(&MediaCodecDecoder::OnPrerollDone
, weak_factory_
.GetWeakPtr());
72 base::Bind(&MediaCodecDecoder::RequestData
, weak_factory_
.GetWeakPtr());
75 MediaCodecDecoder::~MediaCodecDecoder() {}
77 const char* MediaCodecDecoder::class_name() const {
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;
95 drain_decoder_
= false;
98 // |is_prepared_| is set on the decoder thread, it shouldn't be running now.
99 DCHECK(!decoder_thread_
.IsRunning());
100 is_prepared_
= false;
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;
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_
);
148 case kInEmergencyStop
:
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());
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
188 // media_crypto = drm_bridge_->GetMediaCrypto();
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
);
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;
222 if (media_codec_bridge_
) {
223 DVLOG(1) << class_name() << "::" << __FUNCTION__
224 << ": reconfiguration is not required, ignoring";
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
);
233 au_info
= au_queue_
.GetInfo();
236 MediaCodecDecoder::ConfigStatus result
= ConfigureInternal();
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;
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";
264 if (!media_codec_bridge_
) {
265 DVLOG(0) << class_name() << "::" << __FUNCTION__
266 << ": not configured, ignoring";
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";
286 SetState(kPrerolling
);
288 decoder_thread_
.task_runner()->PostTask(
290 base::Bind(&MediaCodecDecoder::ProcessNextFrame
, base::Unretained(this)));
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";
309 if (!media_codec_bridge_
) {
310 DVLOG(0) << class_name() << "::" << __FUNCTION__
311 << ": not configured, ignoring";
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";
332 decoder_thread_
.task_runner()->PostTask(
334 base::Bind(&MediaCodecDecoder::ProcessNextFrame
, base::Unretained(this)));
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";
352 ReleaseDelayedBuffers();
355 void MediaCodecDecoder::RequestToStop() {
356 DCHECK(media_task_runner_
->BelongsToCurrentThread());
358 DVLOG(1) << class_name() << "::" << __FUNCTION__
;
360 DecoderState state
= GetState();
363 DVLOG(0) << class_name() << "::" << __FUNCTION__
364 << ": wrong state kError, ignoring";
371 DCHECK(decoder_thread_
.IsRunning());
373 decoder_thread_
.Stop();
375 media_task_runner_
->PostTask(FROM_HERE
, stop_done_cb_
);
382 // There is nothing to wait for, we can sent notification right away.
383 DCHECK(!decoder_thread_
.IsRunning());
385 media_task_runner_
->PostTask(FROM_HERE
, stop_done_cb_
);
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
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;
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.
443 !data
.access_units
.empty() &&
444 data
.access_units
.back().status
== DemuxerStream::kAborted
;
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
454 for (const auto& configs
: data
.demuxer_configs
)
455 DVLOG(2) << class_name() << "::" << __FUNCTION__
<< " configs: " << configs
;
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
)
470 bool MediaCodecDecoder::IsPrerollingForTests() const {
472 return GetState() == kPrerolling
;
475 void MediaCodecDecoder::SetAlwaysReconfigureForTests() {
477 always_reconfigure_for_tests_
= true;
480 void MediaCodecDecoder::SetCodecCreatedCallbackForTests(base::Closure cb
) {
482 codec_created_for_tests_cb_
= cb
;
485 int MediaCodecDecoder::NumDelayedRenderTasks() const {
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
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";
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
||
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_
));
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";
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";
589 DCHECK(state
== kPrerolling
|| state
== kRunning
);
591 if (!EnqueueInputBuffer())
594 if (!DepleteOutputBufferQueue())
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(
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__
;
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_
);
646 DCHECK(au_info
.front_unit
);
649 if (verify_next_frame_is_key_
) {
650 verify_next_frame_is_key_
= false;
651 VerifyUnitIsKeyFrame(au_info
.front_unit
);
656 // Dequeue input buffer
658 base::TimeDelta timeout
=
659 base::TimeDelta::FromMilliseconds(kInputBufferTimeout
);
661 MediaCodecStatus status
=
662 media_codec_bridge_
->DequeueInputBuffer(timeout
, &index
);
664 DVLOG(2) << class_name() << ":: DequeueInputBuffer index:" << index
;
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_
);
673 case MEDIA_CODEC_DEQUEUE_INPUT_AGAIN_LATER
:
675 << class_name() << "::" << __FUNCTION__
676 << ": DequeueInputBuffer returned MediaCodec.INFO_TRY_AGAIN_LATER.";
684 DCHECK_EQ(status
, MEDIA_CODEC_OK
);
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;
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_
);
711 // Have successfully queued input buffer, go to next access unit.
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
;
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_
);
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
756 } while (au_info
.configs
);
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;
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.
783 status
= media_codec_bridge_
->DequeueOutputBuffer(
784 timeout
, &buffer_index
, &offset
, &size
, &pts
, &eos_encountered
,
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);
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";
798 case MEDIA_CODEC_OUTPUT_FORMAT_CHANGED
:
799 DVLOG(2) << class_name() << "::" << __FUNCTION__
800 << " MEDIA_CODEC_OUTPUT_FORMAT_CHANGED";
801 OnOutputFormatChanged();
805 // We got the decoded frame.
809 if (pts
< preroll_timestamp_
)
810 render_mode
= kRenderSkip
;
811 else if (GetState() == kPrerolling
)
812 render_mode
= kRenderAfterPreroll
;
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_
);
827 case MEDIA_CODEC_DEQUEUE_OUTPUT_AGAIN_LATER
:
829 DVLOG(2) << class_name() << "::" << __FUNCTION__
830 << " MEDIA_CODEC_DEQUEUE_OUTPUT_AGAIN_LATER";
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_
);
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";
853 if (status
== MEDIA_CODEC_ERROR
) {
854 DVLOG(0) << class_name() << "::" << __FUNCTION__
855 << " MediaCodec error, stopping frame processing";
862 MediaCodecDecoder::DecoderState
MediaCodecDecoder::GetState() const {
863 base::AutoLock
lock(state_lock_
);
867 void MediaCodecDecoder::SetState(DecoderState state
) {
868 DVLOG(1) << class_name() << "::" << __FUNCTION__
<< " " << AsString(state
);
870 base::AutoLock
lock(state_lock_
);
875 #define RETURN_STRING(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
) {
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