| OLD | NEW |
| 1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2013 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 "content/common/gpu/media/android_video_decode_accelerator.h" | 5 #include "content/common/gpu/media/android_video_decode_accelerator.h" |
| 6 | 6 |
| 7 #include <stddef.h> | 7 #include <stddef.h> |
| 8 | 8 |
| 9 #include "base/android/build_info.h" |
| 9 #include "base/bind.h" | 10 #include "base/bind.h" |
| 10 #include "base/command_line.h" | 11 #include "base/command_line.h" |
| 11 #include "base/logging.h" | 12 #include "base/logging.h" |
| 12 #include "base/message_loop/message_loop.h" | 13 #include "base/message_loop/message_loop.h" |
| 13 #include "base/metrics/histogram.h" | 14 #include "base/metrics/histogram.h" |
| 14 #include "base/trace_event/trace_event.h" | 15 #include "base/trace_event/trace_event.h" |
| 15 #include "content/common/gpu/gpu_channel.h" | 16 #include "content/common/gpu/gpu_channel.h" |
| 16 #include "content/common/gpu/media/android_copying_backing_strategy.h" | 17 #include "content/common/gpu/media/android_copying_backing_strategy.h" |
| 17 #include "content/common/gpu/media/android_deferred_rendering_backing_strategy.h
" | 18 #include "content/common/gpu/media/android_deferred_rendering_backing_strategy.h
" |
| 18 #include "content/common/gpu/media/avda_return_on_failure.h" | 19 #include "content/common/gpu/media/avda_return_on_failure.h" |
| (...skipping 327 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 346 } | 347 } |
| 347 | 348 |
| 348 bool eos = false; | 349 bool eos = false; |
| 349 base::TimeDelta presentation_timestamp; | 350 base::TimeDelta presentation_timestamp; |
| 350 int32_t buf_index = 0; | 351 int32_t buf_index = 0; |
| 351 bool should_try_again = false; | 352 bool should_try_again = false; |
| 352 do { | 353 do { |
| 353 size_t offset = 0; | 354 size_t offset = 0; |
| 354 size_t size = 0; | 355 size_t size = 0; |
| 355 | 356 |
| 356 TRACE_EVENT_BEGIN0("media", "AVDA::DequeueOutputBuffer"); | 357 TRACE_EVENT_BEGIN0("media", "AVDA::DequeueOutput"); |
| 357 media::MediaCodecStatus status = media_codec_->DequeueOutputBuffer( | 358 media::MediaCodecStatus status = media_codec_->DequeueOutputBuffer( |
| 358 NoWaitTimeOut(), &buf_index, &offset, &size, &presentation_timestamp, | 359 NoWaitTimeOut(), &buf_index, &offset, &size, &presentation_timestamp, |
| 359 &eos, NULL); | 360 &eos, NULL); |
| 360 TRACE_EVENT_END2("media", "AVDA::DequeueOutputBuffer", "status", status, | 361 TRACE_EVENT_END2("media", "AVDA::DequeueOutput", "status", status, |
| 361 "presentation_timestamp (ms)", | 362 "presentation_timestamp (ms)", |
| 362 presentation_timestamp.InMilliseconds()); | 363 presentation_timestamp.InMilliseconds()); |
| 363 | 364 |
| 364 DVLOG(3) << "AVDA::DequeueOutputBuffer: pts:" << presentation_timestamp | 365 DVLOG(3) << "AVDA::DequeueOutput: pts:" << presentation_timestamp |
| 365 << " buf_index:" << buf_index << " offset:" << offset | 366 << " buf_index:" << buf_index << " offset:" << offset |
| 366 << " size:" << size << " eos:" << eos; | 367 << " size:" << size << " eos:" << eos; |
| 367 | 368 |
| 368 switch (status) { | 369 switch (status) { |
| 369 case media::MEDIA_CODEC_DEQUEUE_OUTPUT_AGAIN_LATER: | 370 case media::MEDIA_CODEC_DEQUEUE_OUTPUT_AGAIN_LATER: |
| 370 case media::MEDIA_CODEC_ERROR: | 371 case media::MEDIA_CODEC_ERROR: |
| 371 return false; | 372 return false; |
| 372 | 373 |
| 373 case media::MEDIA_CODEC_OUTPUT_FORMAT_CHANGED: { | 374 case media::MEDIA_CODEC_OUTPUT_FORMAT_CHANGED: { |
| 374 int32_t width, height; | 375 int32_t width, height; |
| 375 media_codec_->GetOutputFormat(&width, &height); | 376 media_codec_->GetOutputFormat(&width, &height); |
| 376 | 377 |
| 377 if (!picturebuffers_requested_) { | 378 if (!picturebuffers_requested_) { |
| 378 picturebuffers_requested_ = true; | 379 picturebuffers_requested_ = true; |
| 379 size_ = gfx::Size(width, height); | 380 size_ = gfx::Size(width, height); |
| 380 base::MessageLoop::current()->PostTask( | 381 base::MessageLoop::current()->PostTask( |
| 381 FROM_HERE, | 382 FROM_HERE, |
| 382 base::Bind(&AndroidVideoDecodeAccelerator::RequestPictureBuffers, | 383 base::Bind(&AndroidVideoDecodeAccelerator::RequestPictureBuffers, |
| 383 weak_this_factory_.GetWeakPtr())); | 384 weak_this_factory_.GetWeakPtr())); |
| 384 } else { | 385 } else { |
| 385 // Dynamic resolution change support is not specified by the Android | 386 // Dynamic resolution change support is not specified by the Android |
| 386 // platform at and before JB-MR1, so it's not possible to smoothly | 387 // platform at and before JB-MR1, so it's not possible to smoothly |
| 387 // continue playback at this point. Instead, error out immediately, | 388 // continue playback at this point. Instead, error out immediately, |
| 388 // expecting clients to Reset() as appropriate to avoid this. | 389 // expecting clients to Flush() or Reset() as appropriate to avoid |
| 389 // b/7093648 | 390 // this. b/7093648 |
| 390 RETURN_ON_FAILURE(this, size_ == gfx::Size(width, height), | 391 RETURN_ON_FAILURE(this, size_ == gfx::Size(width, height), |
| 391 "Dynamic resolution change is not supported.", | 392 "Dynamic resolution change is not supported.", |
| 392 PLATFORM_FAILURE, false); | 393 PLATFORM_FAILURE, false); |
| 393 } | 394 } |
| 394 return false; | 395 return false; |
| 395 } | 396 } |
| 396 | 397 |
| 397 case media::MEDIA_CODEC_OUTPUT_BUFFERS_CHANGED: | 398 case media::MEDIA_CODEC_OUTPUT_BUFFERS_CHANGED: |
| 398 break; | 399 break; |
| 399 | 400 |
| (...skipping 13 matching lines...) Expand all Loading... |
| 413 // corresponding output frame. | 414 // corresponding output frame. |
| 414 | 415 |
| 415 // However MediaCodecBridge uses timestamp correction and provides | 416 // However MediaCodecBridge uses timestamp correction and provides |
| 416 // non-decreasing timestamp sequence, which might result in timestamp | 417 // non-decreasing timestamp sequence, which might result in timestamp |
| 417 // duplicates. Discard the frame if we cannot get corresponding buffer id. | 418 // duplicates. Discard the frame if we cannot get corresponding buffer id. |
| 418 | 419 |
| 419 // Get the bitstream buffer id from the timestamp. | 420 // Get the bitstream buffer id from the timestamp. |
| 420 auto it = eos ? bitstream_buffers_in_decoder_.end() | 421 auto it = eos ? bitstream_buffers_in_decoder_.end() |
| 421 : bitstream_buffers_in_decoder_.find(presentation_timestamp); | 422 : bitstream_buffers_in_decoder_.find(presentation_timestamp); |
| 422 | 423 |
| 423 if (it == bitstream_buffers_in_decoder_.end()) { | 424 if (eos) { |
| 424 media_codec_->ReleaseOutputBuffer(buf_index, false); | 425 DVLOG(3) << "AVDA::DequeueOutput: Resetting output state after EOS"; |
| 426 ResetCodecState(); |
| 427 |
| 425 base::MessageLoop::current()->PostTask( | 428 base::MessageLoop::current()->PostTask( |
| 426 FROM_HERE, | 429 FROM_HERE, |
| 427 base::Bind(&AndroidVideoDecodeAccelerator::NotifyFlushDone, | 430 base::Bind(&AndroidVideoDecodeAccelerator::NotifyFlushDone, |
| 428 weak_this_factory_.GetWeakPtr())); | 431 weak_this_factory_.GetWeakPtr())); |
| 429 } else { | 432 } else if (it != bitstream_buffers_in_decoder_.end()) { |
| 430 const int32_t bitstream_buffer_id = it->second; | 433 const int32_t bitstream_buffer_id = it->second; |
| 431 bitstream_buffers_in_decoder_.erase(bitstream_buffers_in_decoder_.begin(), | 434 bitstream_buffers_in_decoder_.erase(bitstream_buffers_in_decoder_.begin(), |
| 432 ++it); | 435 ++it); |
| 433 SendCurrentSurfaceToClient(buf_index, bitstream_buffer_id); | 436 SendCurrentSurfaceToClient(buf_index, bitstream_buffer_id); |
| 434 | 437 |
| 435 // If we decoded a frame this time, then try for another. | 438 // If we decoded a frame this time, then try for another. |
| 436 should_try_again = true; | 439 should_try_again = true; |
| 437 | 440 |
| 438 // Removes ids former or equal than the id from decoder. Note that | 441 // Removes ids former or equal than the id from decoder. Note that |
| 439 // |bitstreams_notified_in_advance_| does not mean bitstream ids in decoder | 442 // |bitstreams_notified_in_advance_| does not mean bitstream ids in decoder |
| 440 // because of frame reordering issue. We just maintain this roughly and use | 443 // because of frame reordering issue. We just maintain this roughly and use |
| 441 // for the throttling purpose. | 444 // for the throttling purpose. |
| 442 for (auto bitstream_it = bitstreams_notified_in_advance_.begin(); | 445 for (auto bitstream_it = bitstreams_notified_in_advance_.begin(); |
| 443 bitstream_it != bitstreams_notified_in_advance_.end(); | 446 bitstream_it != bitstreams_notified_in_advance_.end(); |
| 444 ++bitstream_it) { | 447 ++bitstream_it) { |
| 445 if (*bitstream_it == bitstream_buffer_id) { | 448 if (*bitstream_it == bitstream_buffer_id) { |
| 446 bitstreams_notified_in_advance_.erase( | 449 bitstreams_notified_in_advance_.erase( |
| 447 bitstreams_notified_in_advance_.begin(), ++bitstream_it); | 450 bitstreams_notified_in_advance_.begin(), ++bitstream_it); |
| 448 break; | 451 break; |
| 449 } | 452 } |
| 450 } | 453 } |
| 454 } else { |
| 455 DVLOG(3) << "AVDA::DequeueOutput: Releasing buffer with unexpected PTS: " |
| 456 << presentation_timestamp; |
| 457 media_codec_->ReleaseOutputBuffer(buf_index, false); |
| 458 should_try_again = true; |
| 451 } | 459 } |
| 452 | 460 |
| 453 return should_try_again; | 461 return should_try_again; |
| 454 } | 462 } |
| 455 | 463 |
| 456 void AndroidVideoDecodeAccelerator::SendCurrentSurfaceToClient( | 464 void AndroidVideoDecodeAccelerator::SendCurrentSurfaceToClient( |
| 457 int32_t codec_buffer_index, | 465 int32_t codec_buffer_index, |
| 458 int32_t bitstream_id) { | 466 int32_t bitstream_id) { |
| 459 DCHECK(thread_checker_.CalledOnValidThread()); | 467 DCHECK(thread_checker_.CalledOnValidThread()); |
| 460 DCHECK_NE(bitstream_id, -1); | 468 DCHECK_NE(bitstream_id, -1); |
| (...skipping 122 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 583 media_codec_.reset(media::VideoCodecBridge::CreateDecoder( | 591 media_codec_.reset(media::VideoCodecBridge::CreateDecoder( |
| 584 codec_, false, gfx::Size(320, 240), surface.j_surface().obj(), NULL)); | 592 codec_, false, gfx::Size(320, 240), surface.j_surface().obj(), NULL)); |
| 585 strategy_->CodecChanged(media_codec_.get(), output_picture_buffers_); | 593 strategy_->CodecChanged(media_codec_.get(), output_picture_buffers_); |
| 586 if (!media_codec_) | 594 if (!media_codec_) |
| 587 return false; | 595 return false; |
| 588 | 596 |
| 589 ManageTimer(true); | 597 ManageTimer(true); |
| 590 return true; | 598 return true; |
| 591 } | 599 } |
| 592 | 600 |
| 601 void AndroidVideoDecodeAccelerator::ResetCodecState() { |
| 602 // TODO(chcunningham): This will likely dismiss a handful of decoded frames |
| 603 // that have not yet been drawn and returned to us for re-use. Consider |
| 604 // a more complicated design that would wait for these to be drawn before |
| 605 // dismissing. |
| 606 for (const auto& it : output_picture_buffers_) { |
| 607 strategy_->DismissOnePictureBuffer(it.second); |
| 608 client_->DismissPictureBuffer(it.first); |
| 609 dismissed_picture_ids_.insert(it.first); |
| 610 } |
| 611 output_picture_buffers_.clear(); |
| 612 std::queue<int32_t> empty; |
| 613 std::swap(free_picture_ids_, empty); |
| 614 CHECK(free_picture_ids_.empty()); |
| 615 picturebuffers_requested_ = false; |
| 616 bitstream_buffers_in_decoder_.clear(); |
| 617 |
| 618 // When codec is not in error state we can quickly reset (internally calls |
| 619 // flush()) for JB-MR2 and beyond. Prior to JB-MR2, flush() had several bugs |
| 620 // (b/8125974, b/8347958) so we must stop() and reconfigure MediaCodec. The |
| 621 // full reconfigure is much slower and may cause visible freezing if done |
| 622 // mid-stream. |
| 623 if (state_ == NO_ERROR && |
| 624 base::android::BuildInfo::GetInstance()->sdk_int() >= 18) { |
| 625 DVLOG(3) << __FUNCTION__ << " Doing fast MediaCodec reset (flush)."; |
| 626 media_codec_->Reset(); |
| 627 } else { |
| 628 DVLOG(3) << __FUNCTION__ |
| 629 << " Doing slow MediaCodec reset (stop/re-configure)."; |
| 630 io_timer_.Stop(); |
| 631 media_codec_->Stop(); |
| 632 ConfigureMediaCodec(); |
| 633 state_ = NO_ERROR; |
| 634 } |
| 635 } |
| 636 |
| 593 void AndroidVideoDecodeAccelerator::Reset() { | 637 void AndroidVideoDecodeAccelerator::Reset() { |
| 594 DCHECK(thread_checker_.CalledOnValidThread()); | 638 DCHECK(thread_checker_.CalledOnValidThread()); |
| 595 TRACE_EVENT0("media", "AVDA::Reset"); | 639 TRACE_EVENT0("media", "AVDA::Reset"); |
| 596 | 640 |
| 597 while (!pending_bitstream_buffers_.empty()) { | 641 while (!pending_bitstream_buffers_.empty()) { |
| 598 int32_t bitstream_buffer_id = pending_bitstream_buffers_.front().first.id(); | 642 int32_t bitstream_buffer_id = pending_bitstream_buffers_.front().first.id(); |
| 599 pending_bitstream_buffers_.pop(); | 643 pending_bitstream_buffers_.pop(); |
| 600 | 644 |
| 601 if (bitstream_buffer_id != -1) { | 645 if (bitstream_buffer_id != -1) { |
| 602 base::MessageLoop::current()->PostTask( | 646 base::MessageLoop::current()->PostTask( |
| 603 FROM_HERE, | 647 FROM_HERE, |
| 604 base::Bind(&AndroidVideoDecodeAccelerator::NotifyEndOfBitstreamBuffer, | 648 base::Bind(&AndroidVideoDecodeAccelerator::NotifyEndOfBitstreamBuffer, |
| 605 weak_this_factory_.GetWeakPtr(), bitstream_buffer_id)); | 649 weak_this_factory_.GetWeakPtr(), bitstream_buffer_id)); |
| 606 } | 650 } |
| 607 } | 651 } |
| 608 TRACE_COUNTER1("media", "AVDA::PendingBitstreamBufferCount", 0); | 652 TRACE_COUNTER1("media", "AVDA::PendingBitstreamBufferCount", 0); |
| 609 bitstreams_notified_in_advance_.clear(); | 653 bitstreams_notified_in_advance_.clear(); |
| 610 | 654 |
| 611 for (OutputBufferMap::iterator it = output_picture_buffers_.begin(); | 655 ResetCodecState(); |
| 612 it != output_picture_buffers_.end(); | |
| 613 ++it) { | |
| 614 strategy_->DismissOnePictureBuffer(it->second); | |
| 615 client_->DismissPictureBuffer(it->first); | |
| 616 dismissed_picture_ids_.insert(it->first); | |
| 617 } | |
| 618 output_picture_buffers_.clear(); | |
| 619 std::queue<int32_t> empty; | |
| 620 std::swap(free_picture_ids_, empty); | |
| 621 CHECK(free_picture_ids_.empty()); | |
| 622 picturebuffers_requested_ = false; | |
| 623 bitstream_buffers_in_decoder_.clear(); | |
| 624 | |
| 625 // On some devices, and up to at least JB-MR1, | |
| 626 // - flush() can fail after EOS (b/8125974); and | |
| 627 // - mid-stream resolution change is unsupported (b/7093648). | |
| 628 // To cope with these facts, we always stop & restart the codec on Reset(). | |
| 629 io_timer_.Stop(); | |
| 630 media_codec_->Stop(); | |
| 631 ConfigureMediaCodec(); | |
| 632 state_ = NO_ERROR; | |
| 633 | 656 |
| 634 base::MessageLoop::current()->PostTask( | 657 base::MessageLoop::current()->PostTask( |
| 635 FROM_HERE, | 658 FROM_HERE, |
| 636 base::Bind(&AndroidVideoDecodeAccelerator::NotifyResetDone, | 659 base::Bind(&AndroidVideoDecodeAccelerator::NotifyResetDone, |
| 637 weak_this_factory_.GetWeakPtr())); | 660 weak_this_factory_.GetWeakPtr())); |
| 638 } | 661 } |
| 639 | 662 |
| 640 void AndroidVideoDecodeAccelerator::Destroy() { | 663 void AndroidVideoDecodeAccelerator::Destroy() { |
| 641 DCHECK(thread_checker_.CalledOnValidThread()); | 664 DCHECK(thread_checker_.CalledOnValidThread()); |
| 642 | 665 |
| (...skipping 136 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 779 | 802 |
| 780 if (UseDeferredRenderingStrategy()) { | 803 if (UseDeferredRenderingStrategy()) { |
| 781 capabilities.flags = media::VideoDecodeAccelerator::Capabilities:: | 804 capabilities.flags = media::VideoDecodeAccelerator::Capabilities:: |
| 782 NEEDS_ALL_PICTURE_BUFFERS_TO_DECODE; | 805 NEEDS_ALL_PICTURE_BUFFERS_TO_DECODE; |
| 783 } | 806 } |
| 784 | 807 |
| 785 return capabilities; | 808 return capabilities; |
| 786 } | 809 } |
| 787 | 810 |
| 788 } // namespace content | 811 } // namespace content |
| OLD | NEW |