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

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

Issue 1242913004: MediaCodecPlayer implementation (stage 3 - browser seek and surface change) (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@mtplayer-seek
Patch Set: Fixed SeekTo() followed by Release() and added uunit tests for this case 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 22 matching lines...) Expand all
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& stop_done_cb, 38 const base::Closure& stop_done_cb,
39 const base::Closure& error_cb, 39 const base::Closure& error_cb,
40 const char* decoder_thread_name) 40 const char* decoder_thread_name)
41 : media_task_runner_(media_task_runner), 41 : media_task_runner_(media_task_runner),
42 decoder_thread_(decoder_thread_name), 42 decoder_thread_(decoder_thread_name),
43 needs_reconfigure_(false),
43 external_request_data_cb_(external_request_data_cb), 44 external_request_data_cb_(external_request_data_cb),
44 starvation_cb_(starvation_cb), 45 starvation_cb_(starvation_cb),
45 stop_done_cb_(stop_done_cb), 46 stop_done_cb_(stop_done_cb),
46 error_cb_(error_cb), 47 error_cb_(error_cb),
47 state_(kStopped), 48 state_(kStopped),
48 eos_enqueued_(false), 49 eos_enqueued_(false),
49 completed_(false), 50 completed_(false),
50 last_frame_posted_(false), 51 last_frame_posted_(false),
51 is_data_request_in_progress_(false), 52 is_data_request_in_progress_(false),
52 is_incoming_data_invalid_(false), 53 is_incoming_data_invalid_(false),
(...skipping 22 matching lines...) Expand all
75 76
76 const char* MediaCodecDecoder::class_name() const { 77 const char* MediaCodecDecoder::class_name() const {
77 return "Decoder"; 78 return "Decoder";
78 } 79 }
79 80
80 void MediaCodecDecoder::ReleaseDecoderResources() { 81 void MediaCodecDecoder::ReleaseDecoderResources() {
81 DCHECK(media_task_runner_->BelongsToCurrentThread()); 82 DCHECK(media_task_runner_->BelongsToCurrentThread());
82 83
83 DVLOG(1) << class_name() << "::" << __FUNCTION__; 84 DVLOG(1) << class_name() << "::" << __FUNCTION__;
84 85
86 // Set [kInEmergencyStop| state to block already posted ProcessNextFrame().
87 SetState(kInEmergencyStop);
88
85 decoder_thread_.Stop(); // synchronous 89 decoder_thread_.Stop(); // synchronous
86 state_ = kStopped; 90
91 SetState(kStopped);
87 media_codec_bridge_.reset(); 92 media_codec_bridge_.reset();
88 } 93 }
89 94
90 void MediaCodecDecoder::Flush() { 95 void MediaCodecDecoder::Flush() {
91 DCHECK(media_task_runner_->BelongsToCurrentThread()); 96 DCHECK(media_task_runner_->BelongsToCurrentThread());
92 97
93 DVLOG(1) << class_name() << "::" << __FUNCTION__; 98 DVLOG(1) << class_name() << "::" << __FUNCTION__;
94 99
95 DCHECK_EQ(GetState(), kStopped); 100 DCHECK_EQ(GetState(), kStopped);
96 101
(...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after
176 MediaCodecDecoder::ConfigStatus MediaCodecDecoder::Configure() { 181 MediaCodecDecoder::ConfigStatus MediaCodecDecoder::Configure() {
177 DCHECK(media_task_runner_->BelongsToCurrentThread()); 182 DCHECK(media_task_runner_->BelongsToCurrentThread());
178 183
179 DVLOG(1) << class_name() << "::" << __FUNCTION__; 184 DVLOG(1) << class_name() << "::" << __FUNCTION__;
180 185
181 if (GetState() == kError) { 186 if (GetState() == kError) {
182 DVLOG(0) << class_name() << "::" << __FUNCTION__ << ": wrong state kError"; 187 DVLOG(0) << class_name() << "::" << __FUNCTION__ << ": wrong state kError";
183 return CONFIG_FAILURE; 188 return CONFIG_FAILURE;
184 } 189 }
185 190
191 if (needs_reconfigure_) {
192 DVLOG(1) << class_name() << "::" << __FUNCTION__
193 << ": needs reconfigure, deleting MediaCodec";
194 needs_reconfigure_ = false;
195 media_codec_bridge_.reset();
196
197 // No need to release these buffers since the MediaCodec is deleted, just
198 // remove their indexes from |delayed_buffers_|.
199
200 // Shall we move |delayed_buffers_| from VideoDecoder to Decoder class?
wolenetz 2015/07/29 22:37:02 Seems there should be either a TODO or a CR commen
Tima Vaisburd 2015/07/30 20:28:35 Yes, but now I tend to think that having a method
wolenetz 2015/07/30 21:10:39 Acknowledged.
201 ClearDelayedBuffers(false);
202 }
203
186 MediaCodecDecoder::ConfigStatus result; 204 MediaCodecDecoder::ConfigStatus result;
187 if (media_codec_bridge_) { 205 if (media_codec_bridge_) {
188 DVLOG(1) << class_name() << "::" << __FUNCTION__ 206 DVLOG(1) << class_name() << "::" << __FUNCTION__
189 << ": reconfiguration is not required, ignoring"; 207 << ": reconfiguration is not required, ignoring";
190 result = CONFIG_OK; 208 result = CONFIG_OK;
191 } else { 209 } else {
192 result = ConfigureInternal(); 210 result = ConfigureInternal();
193 211
194 #ifndef NDEBUG 212 #ifndef NDEBUG
195 // We check and reset |verify_next_frame_is_key_| on Decoder thread. 213 // We check and reset |verify_next_frame_is_key_| on Decoder thread.
(...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after
259 DVLOG(1) << class_name() << "::" << __FUNCTION__; 277 DVLOG(1) << class_name() << "::" << __FUNCTION__;
260 278
261 if (GetState() == kError) { 279 if (GetState() == kError) {
262 DVLOG(0) << class_name() << "::" << __FUNCTION__ 280 DVLOG(0) << class_name() << "::" << __FUNCTION__
263 << ": wrong state kError, ignoring"; 281 << ": wrong state kError, ignoring";
264 return; 282 return;
265 } 283 }
266 284
267 // After this method returns, decoder thread will not be running. 285 // After this method returns, decoder thread will not be running.
268 286
287 // Set [kInEmergencyStop| state to block already posted ProcessNextFrame().
288 SetState(kInEmergencyStop);
289
269 decoder_thread_.Stop(); // synchronous 290 decoder_thread_.Stop(); // synchronous
270 state_ = kStopped; 291
292 SetState(kStopped);
271 293
272 // Shall we move |delayed_buffers_| from VideoDecoder to Decoder class? 294 // Shall we move |delayed_buffers_| from VideoDecoder to Decoder class?
wolenetz 2015/07/29 22:37:02 ditto
Tima Vaisburd 2015/07/30 20:28:35 Same as above, removed the comment in the code as
wolenetz 2015/07/30 21:10:39 Acknowledged.
273 ReleaseDelayedBuffers(); 295 ClearDelayedBuffers(true); // release prior to clearing |delayed_buffers_|.
274 } 296 }
275 297
276 void MediaCodecDecoder::RequestToStop() { 298 void MediaCodecDecoder::RequestToStop() {
277 DCHECK(media_task_runner_->BelongsToCurrentThread()); 299 DCHECK(media_task_runner_->BelongsToCurrentThread());
278 300
279 DVLOG(1) << class_name() << "::" << __FUNCTION__; 301 DVLOG(1) << class_name() << "::" << __FUNCTION__;
280 302
281 DecoderState state = GetState(); 303 DecoderState state = GetState();
282 switch (state) { 304 switch (state) {
283 case kError: 305 case kError:
(...skipping 19 matching lines...) Expand all
303 } 325 }
304 } 326 }
305 327
306 void MediaCodecDecoder::OnLastFrameRendered(bool completed) { 328 void MediaCodecDecoder::OnLastFrameRendered(bool completed) {
307 DCHECK(media_task_runner_->BelongsToCurrentThread()); 329 DCHECK(media_task_runner_->BelongsToCurrentThread());
308 330
309 DVLOG(1) << class_name() << "::" << __FUNCTION__ 331 DVLOG(1) << class_name() << "::" << __FUNCTION__
310 << " completed:" << completed; 332 << " completed:" << completed;
311 333
312 decoder_thread_.Stop(); // synchronous 334 decoder_thread_.Stop(); // synchronous
313 state_ = kStopped; 335
336 SetState(kStopped);
314 completed_ = completed; 337 completed_ = completed;
315 338
316 media_task_runner_->PostTask(FROM_HERE, stop_done_cb_); 339 media_task_runner_->PostTask(FROM_HERE, stop_done_cb_);
317 } 340 }
318 341
319 void MediaCodecDecoder::OnDemuxerDataAvailable(const DemuxerData& data) { 342 void MediaCodecDecoder::OnDemuxerDataAvailable(const DemuxerData& data) {
320 DCHECK(media_task_runner_->BelongsToCurrentThread()); 343 DCHECK(media_task_runner_->BelongsToCurrentThread());
321 344
322 // If |data| contains an aborted data, the last AU will have kAborted status. 345 // If |data| contains an aborted data, the last AU will have kAborted status.
323 bool aborted_data = 346 bool aborted_data =
324 !data.access_units.empty() && 347 !data.access_units.empty() &&
325 data.access_units.back().status == DemuxerStream::kAborted; 348 data.access_units.back().status == DemuxerStream::kAborted;
326 349
327 #ifndef NDEBUG 350 #ifndef NDEBUG
328 const char* explain_if_skipped = 351 const char* explain_if_skipped =
329 is_incoming_data_invalid_ ? " skipped as invalid" 352 is_incoming_data_invalid_ ? " skipped as invalid"
330 : (aborted_data ? " skipped as aborted" : ""); 353 : (aborted_data ? " skipped as aborted" : "");
331 354
332 for (const auto& unit : data.access_units) 355 for (const auto& unit : data.access_units)
333 DVLOG(1) << class_name() << "::" << __FUNCTION__ << explain_if_skipped 356 DVLOG(2) << class_name() << "::" << __FUNCTION__ << explain_if_skipped
334 << " au: " << unit; 357 << " au: " << unit;
335 for (const auto& configs : data.demuxer_configs) 358 for (const auto& configs : data.demuxer_configs)
336 DVLOG(1) << class_name() << "::" << __FUNCTION__ << " configs: " << configs; 359 DVLOG(2) << class_name() << "::" << __FUNCTION__ << " configs: " << configs;
337 #endif 360 #endif
338 361
339 if (!is_incoming_data_invalid_ && !aborted_data) 362 if (!is_incoming_data_invalid_ && !aborted_data)
340 au_queue_.PushBack(data); 363 au_queue_.PushBack(data);
341 364
342 is_incoming_data_invalid_ = false; 365 is_incoming_data_invalid_ = false;
343 is_data_request_in_progress_ = false; 366 is_data_request_in_progress_ = false;
344 367
345 // Do not request data if we got kAborted. There is no point to request the 368 // Do not request data if we got kAborted. There is no point to request the
346 // data after kAborted and before the OnDemuxerSeekDone. 369 // data after kAborted and before the OnDemuxerSeekDone.
347 if (state_ == kPrefetching && !aborted_data) 370 if (GetState() == kPrefetching && !aborted_data)
348 PrefetchNextChunk(); 371 PrefetchNextChunk();
349 } 372 }
350 373
351 int MediaCodecDecoder::NumDelayedRenderTasks() const { 374 int MediaCodecDecoder::NumDelayedRenderTasks() const {
352 return 0; 375 return 0;
353 } 376 }
354 377
355 void MediaCodecDecoder::CheckLastFrame(bool eos_encountered, 378 void MediaCodecDecoder::CheckLastFrame(bool eos_encountered,
356 bool has_delayed_tasks) { 379 bool has_delayed_tasks) {
357 DCHECK(decoder_thread_.task_runner()->BelongsToCurrentThread()); 380 DCHECK(decoder_thread_.task_runner()->BelongsToCurrentThread());
358 381
359 bool last_frame_when_stopping = GetState() == kStopping && !has_delayed_tasks; 382 bool last_frame_when_stopping = GetState() == kStopping && !has_delayed_tasks;
360 383
361 if (last_frame_when_stopping || eos_encountered) { 384 if (last_frame_when_stopping || eos_encountered) {
362 media_task_runner_->PostTask( 385 media_task_runner_->PostTask(
363 FROM_HERE, base::Bind(&MediaCodecDecoder::OnLastFrameRendered, 386 FROM_HERE, base::Bind(&MediaCodecDecoder::OnLastFrameRendered,
364 weak_factory_.GetWeakPtr(), eos_encountered)); 387 weak_factory_.GetWeakPtr(), eos_encountered));
365 last_frame_posted_ = true; 388 last_frame_posted_ = true;
366 } 389 }
367 } 390 }
368 391
369 void MediaCodecDecoder::OnCodecError() { 392 void MediaCodecDecoder::OnCodecError() {
370 DCHECK(media_task_runner_->BelongsToCurrentThread()); 393 DCHECK(media_task_runner_->BelongsToCurrentThread());
371 394
395 // Ignore codec errors from the moment surface is changed till the
396 // |media_codec_bridge_| is deleted.
397 if (needs_reconfigure_) {
398 DVLOG(1) << class_name() << "::" << __FUNCTION__
399 << ": needs reconfigure, ignoring";
400 return;
401 }
402
372 SetState(kError); 403 SetState(kError);
373 error_cb_.Run(); 404 error_cb_.Run();
374 } 405 }
375 406
376 void MediaCodecDecoder::RequestData() { 407 void MediaCodecDecoder::RequestData() {
377 DCHECK(media_task_runner_->BelongsToCurrentThread()); 408 DCHECK(media_task_runner_->BelongsToCurrentThread());
378 409
379 // Ensure one data request at a time. 410 // Ensure one data request at a time.
380 if (!is_data_request_in_progress_) { 411 if (!is_data_request_in_progress_) {
381 is_data_request_in_progress_ = true; 412 is_data_request_in_progress_ = true;
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after
427 // We can stop processing, the |au_queue_| and MediaCodec queues can freeze. 458 // We can stop processing, the |au_queue_| and MediaCodec queues can freeze.
428 // We only need to let finish the delayed rendering tasks. 459 // We only need to let finish the delayed rendering tasks.
429 return; 460 return;
430 } 461 }
431 462
432 DCHECK(state == kRunning); 463 DCHECK(state == kRunning);
433 464
434 if (!EnqueueInputBuffer()) 465 if (!EnqueueInputBuffer())
435 return; 466 return;
436 467
437 bool eos_encountered = false; 468 if (!DepleteOutputBufferQueue())
438 if (!DepleteOutputBufferQueue(&eos_encountered))
439 return; 469 return;
440 470
441 if (eos_encountered) {
442 DVLOG(1) << class_name() << "::" << __FUNCTION__
443 << " EOS dequeued, stopping frame processing";
444 return;
445 }
446
447 // We need a small delay if we want to stop this thread by 471 // We need a small delay if we want to stop this thread by
448 // decoder_thread_.Stop() reliably. 472 // decoder_thread_.Stop() reliably.
449 // The decoder thread message loop processes all pending 473 // The decoder thread message loop processes all pending
450 // (but not delayed) tasks before it can quit; without a delay 474 // (but not delayed) tasks before it can quit; without a delay
451 // the message loop might be forever processing the pendng tasks. 475 // the message loop might be forever processing the pendng tasks.
452 decoder_thread_.task_runner()->PostDelayedTask( 476 decoder_thread_.task_runner()->PostDelayedTask(
453 FROM_HERE, 477 FROM_HERE,
454 base::Bind(&MediaCodecDecoder::ProcessNextFrame, base::Unretained(this)), 478 base::Bind(&MediaCodecDecoder::ProcessNextFrame, base::Unretained(this)),
455 base::TimeDelta::FromMilliseconds(kNextFrameDelay)); 479 base::TimeDelta::FromMilliseconds(kNextFrameDelay));
456 } 480 }
(...skipping 102 matching lines...) Expand 10 before | Expand all | Expand 10 after
559 media_task_runner_->PostTask(FROM_HERE, internal_error_cb_); 583 media_task_runner_->PostTask(FROM_HERE, internal_error_cb_);
560 return false; 584 return false;
561 } 585 }
562 586
563 // Have successfully queued input buffer, go to next access unit. 587 // Have successfully queued input buffer, go to next access unit.
564 au_queue_.Advance(); 588 au_queue_.Advance();
565 return true; 589 return true;
566 } 590 }
567 591
568 // Returns false if there was MediaCodec error. 592 // Returns false if there was MediaCodec error.
569 bool MediaCodecDecoder::DepleteOutputBufferQueue(bool* eos_encountered) { 593 bool MediaCodecDecoder::DepleteOutputBufferQueue() {
570 DCHECK(decoder_thread_.task_runner()->BelongsToCurrentThread()); 594 DCHECK(decoder_thread_.task_runner()->BelongsToCurrentThread());
571 595
572 DVLOG(2) << class_name() << "::" << __FUNCTION__; 596 DVLOG(2) << class_name() << "::" << __FUNCTION__;
573 597
574 int buffer_index = 0; 598 int buffer_index = 0;
575 size_t offset = 0; 599 size_t offset = 0;
576 size_t size = 0; 600 size_t size = 0;
577 base::TimeDelta pts; 601 base::TimeDelta pts;
578 MediaCodecStatus status; 602 MediaCodecStatus status;
603 bool eos_encountered = false;
579 604
580 base::TimeDelta timeout = 605 base::TimeDelta timeout =
581 base::TimeDelta::FromMilliseconds(kOutputBufferTimeout); 606 base::TimeDelta::FromMilliseconds(kOutputBufferTimeout);
582 607
583 // Extract all output buffers that are available. 608 // Extract all output buffers that are available.
584 // Usually there will be only one, but sometimes it is preceeded by 609 // Usually there will be only one, but sometimes it is preceeded by
585 // MEDIA_CODEC_OUTPUT_BUFFERS_CHANGED or MEDIA_CODEC_OUTPUT_FORMAT_CHANGED. 610 // MEDIA_CODEC_OUTPUT_BUFFERS_CHANGED or MEDIA_CODEC_OUTPUT_FORMAT_CHANGED.
586 do { 611 do {
587 status = media_codec_bridge_->DequeueOutputBuffer( 612 status = media_codec_bridge_->DequeueOutputBuffer(
588 timeout, &buffer_index, &offset, &size, &pts, eos_encountered, nullptr); 613 timeout, &buffer_index, &offset, &size, &pts, &eos_encountered,
614 nullptr);
589 615
590 // Reset the timeout to 0 for the subsequent DequeueOutputBuffer() calls 616 // Reset the timeout to 0 for the subsequent DequeueOutputBuffer() calls
591 // to quickly break the loop after we got all currently available buffers. 617 // to quickly break the loop after we got all currently available buffers.
592 timeout = base::TimeDelta::FromMilliseconds(0); 618 timeout = base::TimeDelta::FromMilliseconds(0);
593 619
594 switch (status) { 620 switch (status) {
595 case MEDIA_CODEC_OUTPUT_BUFFERS_CHANGED: 621 case MEDIA_CODEC_OUTPUT_BUFFERS_CHANGED:
596 // Output buffers are replaced in MediaCodecBridge, nothing to do. 622 // Output buffers are replaced in MediaCodecBridge, nothing to do.
597 break; 623 break;
598 624
599 case MEDIA_CODEC_OUTPUT_FORMAT_CHANGED: 625 case MEDIA_CODEC_OUTPUT_FORMAT_CHANGED:
600 DVLOG(2) << class_name() << "::" << __FUNCTION__ 626 DVLOG(2) << class_name() << "::" << __FUNCTION__
601 << " MEDIA_CODEC_OUTPUT_FORMAT_CHANGED"; 627 << " MEDIA_CODEC_OUTPUT_FORMAT_CHANGED";
602 OnOutputFormatChanged(); 628 OnOutputFormatChanged();
603 break; 629 break;
604 630
605 case MEDIA_CODEC_OK: 631 case MEDIA_CODEC_OK:
606 // We got the decoded frame 632 // We got the decoded frame
607 Render(buffer_index, size, true, pts, *eos_encountered); 633 Render(buffer_index, size, true, pts, eos_encountered);
608 break; 634 break;
609 635
610 case MEDIA_CODEC_DEQUEUE_OUTPUT_AGAIN_LATER: 636 case MEDIA_CODEC_DEQUEUE_OUTPUT_AGAIN_LATER:
611 // Nothing to do. 637 // Nothing to do.
612 break; 638 break;
613 639
614 case MEDIA_CODEC_ERROR: 640 case MEDIA_CODEC_ERROR:
615 DVLOG(0) << class_name() << "::" << __FUNCTION__ 641 DVLOG(0) << class_name() << "::" << __FUNCTION__
616 << ": MEDIA_CODEC_ERROR from DequeueOutputBuffer"; 642 << ": MEDIA_CODEC_ERROR from DequeueOutputBuffer";
617 media_task_runner_->PostTask(FROM_HERE, internal_error_cb_); 643 media_task_runner_->PostTask(FROM_HERE, internal_error_cb_);
618 break; 644 break;
619 645
620 default: 646 default:
621 NOTREACHED(); 647 NOTREACHED();
622 break; 648 break;
623 } 649 }
624 650
625 } while (status != MEDIA_CODEC_DEQUEUE_OUTPUT_AGAIN_LATER && 651 } while (status != MEDIA_CODEC_DEQUEUE_OUTPUT_AGAIN_LATER &&
626 status != MEDIA_CODEC_ERROR && !*eos_encountered); 652 status != MEDIA_CODEC_ERROR && !eos_encountered);
627 653
628 return status != MEDIA_CODEC_ERROR; 654 if (eos_encountered) {
655 DVLOG(1) << class_name() << "::" << __FUNCTION__
656 << " EOS dequeued, stopping frame processing";
657 return false;
658 }
659
660 if (status == MEDIA_CODEC_ERROR) {
661 DVLOG(1) << class_name() << "::" << __FUNCTION__
662 << " MediaCodec error, stopping frame processing";
663 return false;
664 }
665
666 return true;
629 } 667 }
630 668
631 MediaCodecDecoder::DecoderState MediaCodecDecoder::GetState() const { 669 MediaCodecDecoder::DecoderState MediaCodecDecoder::GetState() const {
632 base::AutoLock lock(state_lock_); 670 base::AutoLock lock(state_lock_);
633 return state_; 671 return state_;
634 } 672 }
635 673
636 void MediaCodecDecoder::SetState(DecoderState state) { 674 void MediaCodecDecoder::SetState(DecoderState state) {
637 DVLOG(1) << class_name() << "::" << __FUNCTION__ << " " << state; 675 DVLOG(1) << class_name() << "::" << __FUNCTION__ << " " << AsString(state);
638 676
639 base::AutoLock lock(state_lock_); 677 base::AutoLock lock(state_lock_);
640 state_ = state; 678 state_ = state;
641 } 679 }
642 680
643 #undef RETURN_STRING 681 #undef RETURN_STRING
644 #define RETURN_STRING(x) \ 682 #define RETURN_STRING(x) \
645 case x: \ 683 case x: \
646 return #x; 684 return #x;
647 685
648 const char* MediaCodecDecoder::AsString(DecoderState state) { 686 const char* MediaCodecDecoder::AsString(DecoderState state) {
649 switch (state) { 687 switch (state) {
650 RETURN_STRING(kStopped); 688 RETURN_STRING(kStopped);
651 RETURN_STRING(kPrefetching); 689 RETURN_STRING(kPrefetching);
652 RETURN_STRING(kPrefetched); 690 RETURN_STRING(kPrefetched);
653 RETURN_STRING(kRunning); 691 RETURN_STRING(kRunning);
654 RETURN_STRING(kStopping); 692 RETURN_STRING(kStopping);
693 RETURN_STRING(kInEmergencyStop);
655 RETURN_STRING(kError); 694 RETURN_STRING(kError);
656 default: 695 default:
657 return "Unknown DecoderState"; 696 return "Unknown DecoderState";
658 } 697 }
659 } 698 }
660 699
661 #undef RETURN_STRING 700 #undef RETURN_STRING
662 701
663 } // namespace media 702 } // namespace media
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698