| 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 fcc40220d0614ba6bfa9abe098c8e49196f02977..8ea23a0a7c0c285f80fc62f52460a889e758c16c 100644
|
| --- a/media/gpu/android_video_decode_accelerator.cc
|
| +++ b/media/gpu/android_video_decode_accelerator.cc
|
| @@ -33,9 +33,7 @@
|
| #include "media/base/media.h"
|
| #include "media/base/timestamp_constants.h"
|
| #include "media/base/video_decoder_config.h"
|
| -#include "media/gpu/android_copying_backing_strategy.h"
|
| -#include "media/gpu/android_deferred_rendering_backing_strategy.h"
|
| -#include "media/gpu/avda_return_on_failure.h"
|
| +#include "media/gpu/avda_picture_buffer_manager.h"
|
| #include "media/gpu/shared_memory_region.h"
|
| #include "media/video/picture.h"
|
| #include "ui/gl/android/scoped_java_surface.h"
|
| @@ -126,57 +124,6 @@ inline void RecordFormatChangedMetric(FormatChangedValue value) {
|
|
|
| } // namespace
|
|
|
| -// Handle OnFrameAvailable callbacks safely. Since they occur asynchronously,
|
| -// we take care that the AVDA that wants them still exists. A WeakPtr to
|
| -// the AVDA would be preferable, except that OnFrameAvailable callbacks can
|
| -// occur off the gpu main thread. We also can't guarantee when the
|
| -// SurfaceTexture will quit sending callbacks to coordinate with the
|
| -// destruction of the AVDA, so we have a separate object that the cb can own.
|
| -class AndroidVideoDecodeAccelerator::OnFrameAvailableHandler
|
| - : public base::RefCountedThreadSafe<OnFrameAvailableHandler> {
|
| - public:
|
| - // We do not retain ownership of |owner|. It must remain valid until
|
| - // after ClearOwner() is called. This will register with
|
| - // |surface_texture| to receive OnFrameAvailable callbacks.
|
| - OnFrameAvailableHandler(
|
| - AndroidVideoDecodeAccelerator* owner,
|
| - const scoped_refptr<gl::SurfaceTexture>& surface_texture)
|
| - : owner_(owner) {
|
| - // Note that the callback owns a strong ref to us.
|
| - surface_texture->SetFrameAvailableCallbackOnAnyThread(
|
| - base::Bind(&OnFrameAvailableHandler::OnFrameAvailable,
|
| - scoped_refptr<OnFrameAvailableHandler>(this)));
|
| - }
|
| -
|
| - // Forget about our owner, which is required before one deletes it.
|
| - // No further callbacks will happen once this completes.
|
| - void ClearOwner() {
|
| - base::AutoLock lock(lock_);
|
| - // No callback can happen until we release the lock.
|
| - owner_ = nullptr;
|
| - }
|
| -
|
| - // Call back into our owner if it hasn't been deleted.
|
| - void OnFrameAvailable() {
|
| - base::AutoLock auto_lock(lock_);
|
| - // |owner_| can't be deleted while we have the lock.
|
| - if (owner_)
|
| - owner_->OnFrameAvailable();
|
| - }
|
| -
|
| - private:
|
| - friend class base::RefCountedThreadSafe<OnFrameAvailableHandler>;
|
| - virtual ~OnFrameAvailableHandler() {}
|
| -
|
| - // Protects changes to owner_.
|
| - base::Lock lock_;
|
| -
|
| - // AVDA that wants the OnFrameAvailable callback.
|
| - AndroidVideoDecodeAccelerator* owner_;
|
| -
|
| - DISALLOW_COPY_AND_ASSIGN(OnFrameAvailableHandler);
|
| -};
|
| -
|
| // AVDAManager manages shared resources for a number of AVDA instances.
|
| // Its responsibilities include:
|
| // - Starting and stopping a shared "construction" thread for instantiating and
|
| @@ -552,17 +499,6 @@ bool AndroidVideoDecodeAccelerator::Initialize(const Config& config,
|
| return false;
|
| }
|
|
|
| - const gpu::GpuPreferences& gpu_preferences =
|
| - gles_decoder->GetContextGroup()->gpu_preferences();
|
| -
|
| - if (UseDeferredRenderingStrategy(gpu_preferences)) {
|
| - DVLOG(1) << __FUNCTION__ << ", using deferred rendering strategy.";
|
| - strategy_.reset(new AndroidDeferredRenderingBackingStrategy(this));
|
| - } else {
|
| - DVLOG(1) << __FUNCTION__ << ", using copy back strategy.";
|
| - strategy_.reset(new AndroidCopyingBackingStrategy(this));
|
| - }
|
| -
|
| if (!make_context_current_cb_.Run()) {
|
| LOG(ERROR) << "Failed to make this decoder's GL context current.";
|
| return false;
|
| @@ -570,7 +506,7 @@ bool AndroidVideoDecodeAccelerator::Initialize(const Config& config,
|
|
|
| if (g_avda_manager.Get().AllocateSurface(config_.surface_id, this)) {
|
| // We have succesfully owned the surface, so finish initialization now.
|
| - return InitializeStrategy();
|
| + return InitializePictureBufferManager();
|
| }
|
|
|
| // We have to wait for some other AVDA instance to free up the surface.
|
| @@ -581,19 +517,17 @@ bool AndroidVideoDecodeAccelerator::Initialize(const Config& config,
|
| void AndroidVideoDecodeAccelerator::OnSurfaceAvailable(bool success) {
|
| DCHECK(deferred_initialization_pending_);
|
|
|
| - if (!success || !InitializeStrategy()) {
|
| + if (!success || !InitializePictureBufferManager()) {
|
| NotifyInitializationComplete(false);
|
| deferred_initialization_pending_ = false;
|
| }
|
| }
|
|
|
| -bool AndroidVideoDecodeAccelerator::InitializeStrategy() {
|
| - codec_config_->surface_ = strategy_->Initialize(config_.surface_id);
|
| - if (codec_config_->surface_.IsEmpty()) {
|
| - LOG(ERROR) << "Failed to initialize the backing strategy. The returned "
|
| - "Java surface is empty.";
|
| +bool AndroidVideoDecodeAccelerator::InitializePictureBufferManager() {
|
| + codec_config_->surface_ =
|
| + picture_buffer_manager_.Initialize(this, config_.surface_id);
|
| + if (codec_config_->surface_.IsEmpty())
|
| return false;
|
| - }
|
|
|
| on_destroying_surface_cb_ =
|
| base::Bind(&AndroidVideoDecodeAccelerator::OnDestroyingSurface,
|
| @@ -601,14 +535,6 @@ bool AndroidVideoDecodeAccelerator::InitializeStrategy() {
|
| AVDASurfaceTracker::GetInstance()->RegisterOnDestroyingSurfaceCallback(
|
| on_destroying_surface_cb_);
|
|
|
| - // TODO(watk,liberato): move this into the strategy.
|
| - scoped_refptr<gl::SurfaceTexture> surface_texture =
|
| - strategy_->GetSurfaceTexture();
|
| - if (surface_texture) {
|
| - on_frame_available_handler_ =
|
| - new OnFrameAvailableHandler(this, surface_texture);
|
| - }
|
| -
|
| if (!g_avda_manager.Get().StartThread(this))
|
| return false;
|
|
|
| @@ -640,7 +566,7 @@ void AndroidVideoDecodeAccelerator::DoIOTask(bool start_timer) {
|
| return;
|
| }
|
|
|
| - strategy_->MaybeRenderEarly();
|
| + picture_buffer_manager_.MaybeRenderEarly();
|
| bool did_work = false, did_input = false, did_output = false;
|
| do {
|
| did_input = QueueInput();
|
| @@ -953,22 +879,19 @@ void AndroidVideoDecodeAccelerator::SendDecodedFrameToClient(
|
| free_picture_ids_.pop();
|
| TRACE_COUNTER1("media", "AVDA::FreePictureIds", free_picture_ids_.size());
|
|
|
| - const auto& i = output_picture_buffers_.find(picture_buffer_id);
|
| - if (i == output_picture_buffers_.end()) {
|
| + const auto it = output_picture_buffers_.find(picture_buffer_id);
|
| + if (it == output_picture_buffers_.end()) {
|
| POST_ERROR(PLATFORM_FAILURE,
|
| "Can't find PictureBuffer id: " << picture_buffer_id);
|
| return;
|
| }
|
|
|
| - bool size_changed = false;
|
| - if (i->second.size() != size_) {
|
| - // Size may have changed due to resolution change since the last time this
|
| - // PictureBuffer was used.
|
| - strategy_->UpdatePictureBufferSize(&i->second, size_);
|
| - size_changed = true;
|
| - }
|
| + PictureBuffer& picture_buffer = it->second;
|
| + const bool size_changed = picture_buffer.size() != size_;
|
| + if (size_changed)
|
| + picture_buffer.set_size(size_);
|
|
|
| - const bool allow_overlay = strategy_->ArePicturesOverlayable();
|
| + const bool allow_overlay = picture_buffer_manager_.ArePicturesOverlayable();
|
| UMA_HISTOGRAM_BOOLEAN("Media.AVDA.FrameSentAsOverlay", allow_overlay);
|
| Picture picture(picture_buffer_id, bitstream_id, gfx::Rect(size_),
|
| allow_overlay);
|
| @@ -980,9 +903,9 @@ void AndroidVideoDecodeAccelerator::SendDecodedFrameToClient(
|
| // called, so it is safe to do this.
|
| NotifyPictureReady(picture);
|
|
|
| - // Connect the PictureBuffer to the decoded frame, via whatever mechanism the
|
| - // strategy likes.
|
| - strategy_->UseCodecBufferForPictureBuffer(codec_buffer_index, i->second);
|
| + // Connect the PictureBuffer to the decoded frame.
|
| + picture_buffer_manager_.UseCodecBufferForPictureBuffer(codec_buffer_index,
|
| + picture_buffer);
|
| }
|
|
|
| void AndroidVideoDecodeAccelerator::Decode(
|
| @@ -1026,9 +949,10 @@ void AndroidVideoDecodeAccelerator::DecodeBuffer(
|
|
|
| void AndroidVideoDecodeAccelerator::RequestPictureBuffers() {
|
| if (client_) {
|
| - client_->ProvidePictureBuffers(kNumPictureBuffers, PIXEL_FORMAT_UNKNOWN, 1,
|
| - strategy_->GetPictureBufferSize(),
|
| - strategy_->GetTextureTarget());
|
| + client_->ProvidePictureBuffers(
|
| + kNumPictureBuffers, PIXEL_FORMAT_UNKNOWN, 1,
|
| + picture_buffer_manager_.GetPictureBufferSize(),
|
| + picture_buffer_manager_.GetTextureTarget());
|
| }
|
| }
|
|
|
| @@ -1048,7 +972,7 @@ void AndroidVideoDecodeAccelerator::AssignPictureBuffers(
|
| << "Failed to make GL context current for Assign, continuing.";
|
|
|
| for (size_t i = 0; i < buffers.size(); ++i) {
|
| - if (buffers[i].size() != strategy_->GetPictureBufferSize()) {
|
| + if (buffers[i].size() != picture_buffer_manager_.GetPictureBufferSize()) {
|
| POST_ERROR(INVALID_ARGUMENT,
|
| "Invalid picture buffer size assigned. Wanted "
|
| << size_.ToString() << ", but got "
|
| @@ -1059,7 +983,7 @@ void AndroidVideoDecodeAccelerator::AssignPictureBuffers(
|
| output_picture_buffers_.insert(std::make_pair(id, buffers[i]));
|
| free_picture_ids_.push(id);
|
|
|
| - strategy_->AssignOnePictureBuffer(buffers[i], have_context);
|
| + picture_buffer_manager_.AssignOnePictureBuffer(buffers[i], have_context);
|
| }
|
| TRACE_COUNTER1("media", "AVDA::FreePictureIds", free_picture_ids_.size());
|
| DoIOTask(true);
|
| @@ -1072,15 +996,14 @@ void AndroidVideoDecodeAccelerator::ReusePictureBuffer(
|
| free_picture_ids_.push(picture_buffer_id);
|
| TRACE_COUNTER1("media", "AVDA::FreePictureIds", free_picture_ids_.size());
|
|
|
| - OutputBufferMap::const_iterator i =
|
| - output_picture_buffers_.find(picture_buffer_id);
|
| - if (i == output_picture_buffers_.end()) {
|
| + auto it = output_picture_buffers_.find(picture_buffer_id);
|
| + if (it == output_picture_buffers_.end()) {
|
| POST_ERROR(PLATFORM_FAILURE, "Can't find PictureBuffer id "
|
| << picture_buffer_id);
|
| return;
|
| }
|
|
|
| - strategy_->ReuseOnePictureBuffer(i->second);
|
| + picture_buffer_manager_.ReuseOnePictureBuffer(it->second);
|
| DoIOTask(true);
|
| }
|
|
|
| @@ -1105,14 +1028,14 @@ void AndroidVideoDecodeAccelerator::ConfigureMediaCodecAsynchronously() {
|
|
|
| state_ = WAITING_FOR_CODEC;
|
|
|
| - // Tell the strategy that we're changing codecs. The codec itself could be
|
| - // used normally, since we don't replace it until we're back on the main
|
| - // thread. However, if we're using an output surface, then the incoming codec
|
| - // might access that surface while the main thread is drawing. Telling the
|
| - // strategy to forget the codec avoids this.
|
| + // Tell the picture buffer manager that we're changing codecs. The codec
|
| + // itself could be used normally, since we don't replace it until we're back
|
| + // on the main thread. However, if we're using an output surface, then the
|
| + // incoming codec might access that surface while the main thread is drawing.
|
| + // Telling the manager to forget the codec avoids this.
|
| if (media_codec_) {
|
| ReleaseMediaCodec();
|
| - strategy_->CodecChanged(nullptr);
|
| + picture_buffer_manager_.CodecChanged(nullptr);
|
| }
|
|
|
| // Choose whether to autodetect the codec type. Note that we do this after
|
| @@ -1205,7 +1128,7 @@ void AndroidVideoDecodeAccelerator::OnCodecConfigured(
|
|
|
| DCHECK(!media_codec_);
|
| media_codec_ = std::move(media_codec);
|
| - strategy_->CodecChanged(media_codec_.get());
|
| + picture_buffer_manager_.CodecChanged(media_codec_.get());
|
| if (!media_codec_) {
|
| POST_ERROR(PLATFORM_FAILURE, "Failed to create MediaCodec.");
|
| return;
|
| @@ -1324,7 +1247,7 @@ void AndroidVideoDecodeAccelerator::ResetCodecState() {
|
| media_codec_->Flush();
|
| // Since we just flushed all the output buffers, make sure that nothing is
|
| // using them.
|
| - strategy_->CodecChanged(media_codec_.get());
|
| + picture_buffer_manager_.CodecChanged(media_codec_.get());
|
| } else {
|
| DVLOG(3) << __FUNCTION__
|
| << " Deleting the MediaCodec and creating a new one.";
|
| @@ -1356,8 +1279,7 @@ void AndroidVideoDecodeAccelerator::Reset() {
|
| // Any error that is waiting to post can be ignored.
|
| error_sequence_token_++;
|
|
|
| - DCHECK(strategy_);
|
| - strategy_->ReleaseCodecBuffers(output_picture_buffers_);
|
| + picture_buffer_manager_.ReleaseCodecBuffers(output_picture_buffers_);
|
|
|
| // Some VP8 files require complete MediaCodec drain before we can call
|
| // MediaCodec.flush() or MediaCodec.reset(). http://crbug.com/598963.
|
| @@ -1377,29 +1299,18 @@ void AndroidVideoDecodeAccelerator::Destroy() {
|
| DVLOG(1) << __FUNCTION__;
|
| DCHECK(thread_checker_.CalledOnValidThread());
|
|
|
| - bool have_context = make_context_current_cb_.Run();
|
| - if (!have_context)
|
| - LOG(WARNING) << "Failed make GL context current for Destroy, continuing.";
|
| -
|
| - if (strategy_)
|
| - strategy_->BeginCleanup(have_context, output_picture_buffers_);
|
| -
|
| - // If we have an OnFrameAvailable handler, tell it that we're going away.
|
| - if (on_frame_available_handler_) {
|
| - on_frame_available_handler_->ClearOwner();
|
| - on_frame_available_handler_ = nullptr;
|
| - }
|
| + picture_buffer_manager_.Destroy(output_picture_buffers_);
|
|
|
| client_ = nullptr;
|
|
|
| - // Some VP8 files require complete MediaCodec drain before we can call
|
| - // MediaCodec.flush() or MediaCodec.reset(). http://crbug.com/598963.
|
| + // Some VP8 files require a complete MediaCodec drain before we can call
|
| + // MediaCodec.flush() or MediaCodec.release(). http://crbug.com/598963. In
|
| + // that case, postpone ActualDestroy() until after the drain.
|
| if (media_codec_ && codec_config_->codec_ == kCodecVP8) {
|
| - // Clear pending_bitstream_records_.
|
| + // Clear |pending_bitstream_records_|.
|
| while (!pending_bitstream_records_.empty())
|
| pending_bitstream_records_.pop();
|
|
|
| - // Postpone ActualDestroy after the drain.
|
| StartCodecDrain(DRAIN_FOR_DESTROY);
|
| } else {
|
| ActualDestroy();
|
| @@ -1415,9 +1326,6 @@ void AndroidVideoDecodeAccelerator::ActualDestroy() {
|
| on_destroying_surface_cb_);
|
| }
|
|
|
| - if (strategy_)
|
| - strategy_->EndCleanup();
|
| -
|
| // We no longer care about |surface_id|, in case we did before. It's okay
|
| // if we have no surface and/or weren't the owner or a waiter.
|
| g_avda_manager.Get().DeallocateSurface(config_.surface_id, this);
|
| @@ -1430,6 +1338,7 @@ void AndroidVideoDecodeAccelerator::ActualDestroy() {
|
| g_avda_manager.Get().StopTimer(this);
|
| ReleaseMediaCodec();
|
| }
|
| +
|
| delete this;
|
| }
|
|
|
| @@ -1443,66 +1352,11 @@ const gfx::Size& AndroidVideoDecodeAccelerator::GetSize() const {
|
| return size_;
|
| }
|
|
|
| -const base::ThreadChecker& AndroidVideoDecodeAccelerator::ThreadChecker()
|
| - const {
|
| - return thread_checker_;
|
| -}
|
| -
|
| base::WeakPtr<gpu::gles2::GLES2Decoder>
|
| AndroidVideoDecodeAccelerator::GetGlDecoder() const {
|
| return get_gles2_decoder_cb_.Run();
|
| }
|
|
|
| -gpu::gles2::TextureRef* AndroidVideoDecodeAccelerator::GetTextureForPicture(
|
| - const PictureBuffer& picture_buffer) {
|
| - auto gles_decoder = GetGlDecoder();
|
| - RETURN_ON_FAILURE(this, gles_decoder, "Failed to get GL decoder",
|
| - ILLEGAL_STATE, nullptr);
|
| - RETURN_ON_FAILURE(this, gles_decoder->GetContextGroup(),
|
| - "Null gles_decoder->GetContextGroup()", ILLEGAL_STATE,
|
| - nullptr);
|
| - gpu::gles2::TextureManager* texture_manager =
|
| - gles_decoder->GetContextGroup()->texture_manager();
|
| - RETURN_ON_FAILURE(this, texture_manager, "Null texture_manager",
|
| - ILLEGAL_STATE, nullptr);
|
| -
|
| - DCHECK_LE(1u, picture_buffer.internal_texture_ids().size());
|
| - gpu::gles2::TextureRef* texture_ref =
|
| - texture_manager->GetTexture(picture_buffer.internal_texture_ids()[0]);
|
| - RETURN_ON_FAILURE(this, texture_manager, "Null texture_ref", ILLEGAL_STATE,
|
| - nullptr);
|
| -
|
| - return texture_ref;
|
| -}
|
| -
|
| -scoped_refptr<gl::SurfaceTexture>
|
| -AndroidVideoDecodeAccelerator::CreateAttachedSurfaceTexture(
|
| - GLuint* service_id) {
|
| - GLuint texture_id;
|
| - glGenTextures(1, &texture_id);
|
| -
|
| - glActiveTexture(GL_TEXTURE0);
|
| - glBindTexture(GL_TEXTURE_EXTERNAL_OES, texture_id);
|
| - glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
| - glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
| - glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
| - glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
| -
|
| - auto gl_decoder = GetGlDecoder();
|
| - gl_decoder->RestoreTextureUnitBindings(0);
|
| - gl_decoder->RestoreActiveTexture();
|
| - DCHECK_EQ(static_cast<GLenum>(GL_NO_ERROR), glGetError());
|
| -
|
| - *service_id = texture_id;
|
| - // Previously, to reduce context switching, we used to create an unattached
|
| - // SurfaceTexture and attach it lazily in the compositor's context. But that
|
| - // was flaky because SurfaceTexture#detachFromGLContext() is buggy on a lot of
|
| - // devices. Now we attach it to the current context, which means we might have
|
| - // to context switch later to call updateTexImage(). Fortunately, if virtual
|
| - // contexts are in use, we won't have to context switch.
|
| - return gl::SurfaceTexture::Create(texture_id);
|
| -}
|
| -
|
| void AndroidVideoDecodeAccelerator::OnDestroyingSurface(int surface_id) {
|
| DCHECK(thread_checker_.CalledOnValidThread());
|
| TRACE_EVENT0("media", "AVDA::OnDestroyingSurface");
|
| @@ -1517,7 +1371,7 @@ void AndroidVideoDecodeAccelerator::OnDestroyingSurface(int surface_id) {
|
| state_ = SURFACE_DESTROYED;
|
| if (media_codec_) {
|
| ReleaseMediaCodec();
|
| - strategy_->CodecChanged(media_codec_.get());
|
| + picture_buffer_manager_.CodecChanged(media_codec_.get());
|
| }
|
| // If we're draining, signal completion now because the drain can no longer
|
| // proceed.
|
| @@ -1525,12 +1379,6 @@ void AndroidVideoDecodeAccelerator::OnDestroyingSurface(int surface_id) {
|
| OnDrainCompleted();
|
| }
|
|
|
| -void AndroidVideoDecodeAccelerator::OnFrameAvailable() {
|
| - // Remember: this may be on any thread.
|
| - DCHECK(strategy_);
|
| - strategy_->OnFrameAvailable();
|
| -}
|
| -
|
| void AndroidVideoDecodeAccelerator::PostError(
|
| const ::tracked_objects::Location& from_here,
|
| VideoDecodeAccelerator::Error error) {
|
| @@ -1693,12 +1541,6 @@ void AndroidVideoDecodeAccelerator::ReleaseMediaCodec() {
|
| }
|
|
|
| // static
|
| -bool AndroidVideoDecodeAccelerator::UseDeferredRenderingStrategy(
|
| - const gpu::GpuPreferences& gpu_preferences) {
|
| - return true;
|
| -}
|
| -
|
| -// static
|
| VideoDecodeAccelerator::Capabilities
|
| AndroidVideoDecodeAccelerator::GetCapabilities(
|
| const gpu::GpuPreferences& gpu_preferences) {
|
| @@ -1759,20 +1601,18 @@ AndroidVideoDecodeAccelerator::GetCapabilities(
|
|
|
| capabilities.flags =
|
| VideoDecodeAccelerator::Capabilities::SUPPORTS_DEFERRED_INITIALIZATION;
|
| - if (UseDeferredRenderingStrategy(gpu_preferences)) {
|
| - capabilities.flags |= VideoDecodeAccelerator::Capabilities::
|
| - NEEDS_ALL_PICTURE_BUFFERS_TO_DECODE;
|
| + capabilities.flags |=
|
| + VideoDecodeAccelerator::Capabilities::NEEDS_ALL_PICTURE_BUFFERS_TO_DECODE;
|
|
|
| - // If we're using threaded texture mailboxes the COPY_REQUIRED flag must be
|
| - // set on deferred strategy frames (http://crbug.com/582170), and
|
| - // SurfaceView output 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;
|
| - }
|
| + // If we're using threaded texture mailboxes the COPY_REQUIRED flag must be
|
| + // set on the video frames (http://crbug.com/582170), and SurfaceView output
|
| + // 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;
|
| }
|
|
|
| return capabilities;
|
|
|