| Index: media/gpu/android_video_decode_accelerator.cc
|
| diff --git a/media/gpu/android_video_decode_accelerator.cc b/media/gpu/android_video_decode_accelerator.cc
|
| index d054d1b564f85b9015f908384992566fc1061615..fda7952399e512d576923cda9db2330c77659cbd 100644
|
| --- a/media/gpu/android_video_decode_accelerator.cc
|
| +++ b/media/gpu/android_video_decode_accelerator.cc
|
| @@ -18,6 +18,7 @@
|
| #include "base/logging.h"
|
| #include "base/message_loop/message_loop.h"
|
| #include "base/metrics/histogram.h"
|
| +#include "base/sys_info.h"
|
| #include "base/task_runner_util.h"
|
| #include "base/threading/thread_checker.h"
|
| #include "base/threading/thread_task_runner_handle.h"
|
| @@ -324,6 +325,16 @@ class AVDAManager {
|
| waiter->OnSurfaceAvailable(true);
|
| }
|
|
|
| + // On low end devices (< KitKat is always low-end due to buggy MediaCodec),
|
| + // defer the surface creation until the codec is actually used if we know no
|
| + // software fallback exists.
|
| + bool ShouldDeferSurfaceCreation(int surface_id, VideoCodec codec) {
|
| + return surface_id == AndroidVideoDecodeAccelerator::Config::kNoSurfaceID &&
|
| + codec == kCodecH264 && !thread_avda_instances_.empty() &&
|
| + (base::android::BuildInfo::GetInstance()->sdk_int() <= 18 ||
|
| + base::SysInfo::IsLowEndDevice());
|
| + }
|
| +
|
| private:
|
| friend struct base::DefaultLazyInstanceTraits<AVDAManager>;
|
|
|
| @@ -425,6 +436,7 @@ AndroidVideoDecodeAccelerator::AndroidVideoDecodeAccelerator(
|
| defer_errors_(false),
|
| deferred_initialization_pending_(false),
|
| codec_needs_reset_(false),
|
| + defer_surface_creation_(false),
|
| weak_this_factory_(this) {}
|
|
|
| AndroidVideoDecodeAccelerator::~AndroidVideoDecodeAccelerator() {
|
| @@ -471,15 +483,6 @@ bool AndroidVideoDecodeAccelerator::Initialize(const Config& config,
|
| codec_config_->initial_expected_coded_size_ =
|
| config.initial_expected_coded_size;
|
|
|
| - // We signalled that we support deferred initialization, so see if the client
|
| - // does also.
|
| - deferred_initialization_pending_ = config.is_deferred_initialization_allowed;
|
| -
|
| - if (config_.is_encrypted && !deferred_initialization_pending_) {
|
| - DLOG(ERROR) << "Deferred initialization must be used for encrypted streams";
|
| - return false;
|
| - }
|
| -
|
| if (codec_config_->codec_ != kCodecVP8 &&
|
| codec_config_->codec_ != kCodecVP9 &&
|
| #if BUILDFLAG(ENABLE_HEVC_DEMUXING)
|
| @@ -507,13 +510,31 @@ bool AndroidVideoDecodeAccelerator::Initialize(const Config& config,
|
| return false;
|
| }
|
|
|
| - if (!make_context_current_cb_.Run()) {
|
| - LOG(ERROR) << "Failed to make this decoder's GL context current.";
|
| + // If we're low on resources, we may decide to defer creation of the surface
|
| + // until the codec is actually used.
|
| + if (g_avda_manager.Get().ShouldDeferSurfaceCreation(config_.surface_id,
|
| + codec_config_->codec_)) {
|
| + DCHECK(!deferred_initialization_pending_);
|
| +
|
| + // We should never be here if a SurfaceView is required.
|
| + DCHECK_EQ(config_.surface_id, Config::kNoSurfaceID);
|
| + DCHECK(g_avda_manager.Get().AllocateSurface(config_.surface_id, this));
|
| +
|
| + defer_surface_creation_ = true;
|
| + NotifyInitializationComplete(true);
|
| + return true;
|
| + }
|
| +
|
| + // We signaled that we support deferred initialization, so see if the client
|
| + // does also.
|
| + deferred_initialization_pending_ = config.is_deferred_initialization_allowed;
|
| + if (config_.is_encrypted && !deferred_initialization_pending_) {
|
| + DLOG(ERROR) << "Deferred initialization must be used for encrypted streams";
|
| return false;
|
| }
|
|
|
| if (g_avda_manager.Get().AllocateSurface(config_.surface_id, this)) {
|
| - // We have succesfully owned the surface, so finish initialization now.
|
| + // We have successfully owned the surface, so finish initialization now.
|
| return InitializePictureBufferManager();
|
| }
|
|
|
| @@ -524,6 +545,7 @@ bool AndroidVideoDecodeAccelerator::Initialize(const Config& config,
|
|
|
| void AndroidVideoDecodeAccelerator::OnSurfaceAvailable(bool success) {
|
| DCHECK(deferred_initialization_pending_);
|
| + DCHECK(!defer_surface_creation_);
|
|
|
| if (!success || !InitializePictureBufferManager()) {
|
| NotifyInitializationComplete(false);
|
| @@ -532,6 +554,11 @@ void AndroidVideoDecodeAccelerator::OnSurfaceAvailable(bool success) {
|
| }
|
|
|
| bool AndroidVideoDecodeAccelerator::InitializePictureBufferManager() {
|
| + if (!make_context_current_cb_.Run()) {
|
| + LOG(ERROR) << "Failed to make this decoder's GL context current.";
|
| + return false;
|
| + }
|
| +
|
| codec_config_->surface_ =
|
| picture_buffer_manager_.Initialize(this, config_.surface_id);
|
| if (codec_config_->surface_.IsEmpty())
|
| @@ -552,7 +579,8 @@ bool AndroidVideoDecodeAccelerator::InitializePictureBufferManager() {
|
| return true;
|
| }
|
|
|
| - if (deferred_initialization_pending_) {
|
| + if (deferred_initialization_pending_ || defer_surface_creation_) {
|
| + defer_surface_creation_ = false;
|
| ConfigureMediaCodecAsynchronously();
|
| return true;
|
| }
|
| @@ -790,7 +818,7 @@ bool AndroidVideoDecodeAccelerator::DequeueOutput() {
|
| // decoded images. Breaking their connection to the decoded image will
|
| // cause rendering of black frames. Instead, we let the existing
|
| // PictureBuffers live on and we simply update their size the next time
|
| - // they're attachted to an image of the new resolution. See the
|
| + // they're attached to an image of the new resolution. See the
|
| // size update in |SendDecodedFrameToClient| and https://crbug/587994.
|
| if (output_picture_buffers_.empty() && !picturebuffers_requested_) {
|
| picturebuffers_requested_ = true;
|
| @@ -928,6 +956,12 @@ void AndroidVideoDecodeAccelerator::Decode(
|
| const BitstreamBuffer& bitstream_buffer) {
|
| DCHECK(thread_checker_.CalledOnValidThread());
|
|
|
| + if (defer_surface_creation_ && !InitializePictureBufferManager()) {
|
| + POST_ERROR(PLATFORM_FAILURE,
|
| + "Failed deferred surface and MediaCodec initialization.");
|
| + return;
|
| + }
|
| +
|
| // If we previously deferred a codec restart, take care of it now. This can
|
| // happen on older devices where configuration changes require a codec reset.
|
| if (codec_needs_reset_) {
|
| @@ -1027,7 +1061,7 @@ void AndroidVideoDecodeAccelerator::Flush() {
|
| DVLOG(1) << __FUNCTION__;
|
| DCHECK(thread_checker_.CalledOnValidThread());
|
|
|
| - if (state_ == SURFACE_DESTROYED)
|
| + if (state_ == SURFACE_DESTROYED || defer_surface_creation_)
|
| NotifyFlushDone();
|
| else
|
| StartCodecDrain(DRAIN_FOR_FLUSH);
|
| @@ -1258,7 +1292,7 @@ void AndroidVideoDecodeAccelerator::ResetCodecState() {
|
|
|
| // Flush the codec if possible, or create a new one if not.
|
| if (!did_codec_error_happen &&
|
| - !media::MediaCodecUtil::CodecNeedsFlushWorkaround(media_codec_.get())) {
|
| + !MediaCodecUtil::CodecNeedsFlushWorkaround(media_codec_.get())) {
|
| DVLOG(3) << __FUNCTION__ << " Flushing MediaCodec.";
|
| media_codec_->Flush();
|
| // Since we just flushed all the output buffers, make sure that nothing is
|
| @@ -1277,6 +1311,16 @@ void AndroidVideoDecodeAccelerator::Reset() {
|
| DCHECK(thread_checker_.CalledOnValidThread());
|
| TRACE_EVENT0("media", "AVDA::Reset");
|
|
|
| + if (defer_surface_creation_) {
|
| + DCHECK(!media_codec_);
|
| + DCHECK(pending_bitstream_records_.empty());
|
| + DCHECK_EQ(state_, NO_ERROR);
|
| + base::ThreadTaskRunnerHandle::Get()->PostTask(
|
| + FROM_HERE, base::Bind(&AndroidVideoDecodeAccelerator::NotifyResetDone,
|
| + weak_this_factory_.GetWeakPtr()));
|
| + return;
|
| + }
|
| +
|
| while (!pending_bitstream_records_.empty()) {
|
| int32_t bitstream_buffer_id =
|
| pending_bitstream_records_.front().buffer.id();
|
| @@ -1635,10 +1679,10 @@ AndroidVideoDecodeAccelerator::GetCapabilities(
|
| // is disabled (http://crbug.com/582170).
|
| if (gpu_preferences.enable_threaded_texture_mailboxes) {
|
| capabilities.flags |=
|
| - media::VideoDecodeAccelerator::Capabilities::REQUIRES_TEXTURE_COPY;
|
| - } else if (media::MediaCodecUtil::IsSurfaceViewOutputSupported()) {
|
| - capabilities.flags |= media::VideoDecodeAccelerator::Capabilities::
|
| - SUPPORTS_EXTERNAL_OUTPUT_SURFACE;
|
| + VideoDecodeAccelerator::Capabilities::REQUIRES_TEXTURE_COPY;
|
| + } else if (MediaCodecUtil::IsSurfaceViewOutputSupported()) {
|
| + capabilities.flags |=
|
| + VideoDecodeAccelerator::Capabilities::SUPPORTS_EXTERNAL_OUTPUT_SURFACE;
|
| }
|
|
|
| #if BUILDFLAG(ENABLE_HEVC_DEMUXING)
|
|
|