diff options
author | fischman@chromium.org <fischman@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-07-17 19:39:37 +0000 |
---|---|---|
committer | fischman@chromium.org <fischman@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-07-17 19:39:37 +0000 |
commit | 085390b899d3dcec1abd27ebbddd375ddea98067 (patch) | |
tree | a4981d18ead6b8fa1708048e8c510cc16801ea91 | |
parent | f9e6c45351f6ca73755cfb0ebb8bf11935ec86c4 (diff) | |
download | chromium_src-085390b899d3dcec1abd27ebbddd375ddea98067.zip chromium_src-085390b899d3dcec1abd27ebbddd375ddea98067.tar.gz chromium_src-085390b899d3dcec1abd27ebbddd375ddea98067.tar.bz2 |
VideoDecodeAccelerator now SupportsWeakPtr instead of being RefCountedThreadSafe.
Claiming both (which GpuVideoDecodeAcceleratorHost was doing) is confusing and
RCTS encourages sloppy lifecycle management. Instead drop RCTS in favor of
WeakPtr<>s and explicit lifecycle management (scoped_ptr, with Pass).
BUG=136294
Review URL: https://chromiumcodereview.appspot.com/10749019
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@147069 0039d316-1c4b-4281-b951-d872f2087c98
23 files changed, 231 insertions, 169 deletions
diff --git a/content/common/gpu/client/command_buffer_proxy_impl.cc b/content/common/gpu/client/command_buffer_proxy_impl.cc index 80e0b1c..2d6a1685 100644 --- a/content/common/gpu/client/command_buffer_proxy_impl.cc +++ b/content/common/gpu/client/command_buffer_proxy_impl.cc @@ -46,6 +46,10 @@ CommandBufferProxyImpl::~CommandBufferProxyImpl() { delete it->second.shared_memory; it->second.shared_memory = NULL; } + for (Decoders::iterator it = video_decoder_hosts_.begin(); + it != video_decoder_hosts_.end(); ++it) { + it->second->Destroy(); + } } bool CommandBufferProxyImpl::OnMessageReceived(const IPC::Message& message) { @@ -483,7 +487,7 @@ void CommandBufferProxyImpl::SetNotifyRepaintTask(const base::Closure& task) { notify_repaint_task_ = task; } -scoped_refptr<GpuVideoDecodeAcceleratorHost> +GpuVideoDecodeAcceleratorHost* CommandBufferProxyImpl::CreateVideoDecoder( media::VideoCodecProfile profile, media::VideoDecodeAccelerator::Client* client) { @@ -499,13 +503,13 @@ CommandBufferProxyImpl::CreateVideoDecoder( return NULL; } - scoped_refptr<GpuVideoDecodeAcceleratorHost> decoder_host = + GpuVideoDecodeAcceleratorHost* decoder_host = new GpuVideoDecodeAcceleratorHost(channel_, decoder_route_id, client); bool inserted = video_decoder_hosts_.insert(std::make_pair( decoder_route_id, decoder_host)).second; DCHECK(inserted); - channel_->AddRoute(decoder_route_id, decoder_host->AsWeakPtr()); + channel_->AddRoute(decoder_route_id, base::AsWeakPtr(decoder_host)); return decoder_host; } diff --git a/content/common/gpu/client/command_buffer_proxy_impl.h b/content/common/gpu/client/command_buffer_proxy_impl.h index b21c51c..7f774639 100644 --- a/content/common/gpu/client/command_buffer_proxy_impl.h +++ b/content/common/gpu/client/command_buffer_proxy_impl.h @@ -50,7 +50,7 @@ class CommandBufferProxyImpl // Note that the GpuVideoDecodeAccelerator may still fail to be created in // the GPU process, even if this returns non-NULL. In this case the client is // notified of an error later. - scoped_refptr<GpuVideoDecodeAcceleratorHost> CreateVideoDecoder( + GpuVideoDecodeAcceleratorHost* CreateVideoDecoder( media::VideoCodecProfile profile, media::VideoDecodeAccelerator::Client* client); @@ -107,7 +107,7 @@ class CommandBufferProxyImpl private: typedef std::map<int32, gpu::Buffer> TransferBufferMap; - typedef std::map<int, scoped_refptr<GpuVideoDecodeAcceleratorHost> > Decoders; + typedef std::map<int, GpuVideoDecodeAcceleratorHost*> Decoders; typedef base::hash_map<uint32, base::Closure> SignalTaskMap; // Send an IPC message over the GPU channel. This is private to fully diff --git a/content/common/gpu/client/gpu_video_decode_accelerator_host.cc b/content/common/gpu/client/gpu_video_decode_accelerator_host.cc index 77cdd3a..078171f 100644 --- a/content/common/gpu/client/gpu_video_decode_accelerator_host.cc +++ b/content/common/gpu/client/gpu_video_decode_accelerator_host.cc @@ -122,6 +122,7 @@ void GpuVideoDecodeAcceleratorHost::Destroy() { channel_->RemoveRoute(decoder_route_id_); client_ = NULL; Send(new AcceleratedVideoDecoderMsg_Destroy(decoder_route_id_)); + delete this; } GpuVideoDecodeAcceleratorHost::~GpuVideoDecodeAcceleratorHost() {} diff --git a/content/common/gpu/client/gpu_video_decode_accelerator_host.h b/content/common/gpu/client/gpu_video_decode_accelerator_host.h index 0339e0f..e33129f 100644 --- a/content/common/gpu/client/gpu_video_decode_accelerator_host.h +++ b/content/common/gpu/client/gpu_video_decode_accelerator_host.h @@ -19,13 +19,13 @@ class GpuChannelHost; class GpuVideoDecodeAcceleratorHost : public IPC::Listener, public media::VideoDecodeAccelerator, - public base::NonThreadSafe, - public base::SupportsWeakPtr<GpuVideoDecodeAcceleratorHost> { + public base::NonThreadSafe { public: // |channel| is used to send IPC messages to GPU process. GpuVideoDecodeAcceleratorHost(GpuChannelHost* channel, int32 decoder_route_id, media::VideoDecodeAccelerator::Client* client); + virtual ~GpuVideoDecodeAcceleratorHost(); // IPC::Listener implementation. virtual void OnChannelError() OVERRIDE; @@ -41,9 +41,6 @@ class GpuVideoDecodeAcceleratorHost virtual void Reset() OVERRIDE; virtual void Destroy() OVERRIDE; - protected: - virtual ~GpuVideoDecodeAcceleratorHost(); - private: void Send(IPC::Message* message); diff --git a/content/common/gpu/media/dxva_video_decode_accelerator.cc b/content/common/gpu/media/dxva_video_decode_accelerator.cc index 2edc138..c99121c 100644 --- a/content/common/gpu/media/dxva_video_decode_accelerator.cc +++ b/content/common/gpu/media/dxva_video_decode_accelerator.cc @@ -548,8 +548,9 @@ bool DXVAVideoDecodeAccelerator::Initialize(media::VideoCodecProfile profile) { PLATFORM_FAILURE, false); state_ = kNormal; - MessageLoop::current()->PostTask(FROM_HERE, - base::Bind(&DXVAVideoDecodeAccelerator::NotifyInitializeDone, this)); + MessageLoop::current()->PostTask(FROM_HERE, base::Bind( + &DXVAVideoDecodeAccelerator::NotifyInitializeDone, + base::AsWeakPtr(this))); return true; } @@ -597,7 +598,7 @@ void DXVAVideoDecodeAccelerator::Decode( // decoder to emit an output packet for every input packet. // http://code.google.com/p/chromium/issues/detail?id=108121 MessageLoop::current()->PostTask(FROM_HERE, base::Bind( - &DXVAVideoDecodeAccelerator::NotifyInputBufferRead, this, + &DXVAVideoDecodeAccelerator::NotifyInputBufferRead, base::AsWeakPtr(this), bitstream_buffer.id())); } @@ -658,7 +659,7 @@ void DXVAVideoDecodeAccelerator::Flush() { } MessageLoop::current()->PostTask(FROM_HERE, base::Bind( - &DXVAVideoDecodeAccelerator::NotifyFlushDone, this)); + &DXVAVideoDecodeAccelerator::NotifyFlushDone, base::AsWeakPtr(this))); state_ = kNormal; } @@ -677,7 +678,7 @@ void DXVAVideoDecodeAccelerator::Reset() { "Reset: Failed to send message.", PLATFORM_FAILURE,); MessageLoop::current()->PostTask(FROM_HERE, base::Bind( - &DXVAVideoDecodeAccelerator::NotifyResetDone, this)); + &DXVAVideoDecodeAccelerator::NotifyResetDone, base::AsWeakPtr(this))); state_ = DXVAVideoDecodeAccelerator::kNormal; } @@ -685,6 +686,7 @@ void DXVAVideoDecodeAccelerator::Reset() { void DXVAVideoDecodeAccelerator::Destroy() { DCHECK(CalledOnValidThread()); Invalidate(); + delete this; } bool DXVAVideoDecodeAccelerator::InitDecoder() { @@ -946,7 +948,7 @@ bool DXVAVideoDecodeAccelerator::ProcessOutputSample(IMFSample* sample) { // Go ahead and request picture buffers. MessageLoop::current()->PostTask(FROM_HERE, base::Bind( &DXVAVideoDecodeAccelerator::RequestPictureBuffers, - this, surface_desc.Width, surface_desc.Height)); + base::AsWeakPtr(this), surface_desc.Width, surface_desc.Height)); pictures_requested_ = true; return true; @@ -973,8 +975,8 @@ void DXVAVideoDecodeAccelerator::ProcessPendingSamples() { media::Picture output_picture(index->second->id(), sample_info.input_buffer_id); MessageLoop::current()->PostTask(FROM_HERE, base::Bind( - &DXVAVideoDecodeAccelerator::NotifyPictureReady, this, - output_picture)); + &DXVAVideoDecodeAccelerator::NotifyPictureReady, + base::AsWeakPtr(this), output_picture)); index->second->set_available(false); pending_output_samples_.pop_front(); diff --git a/content/common/gpu/media/gpu_video_decode_accelerator.cc b/content/common/gpu/media/gpu_video_decode_accelerator.cc index ab8415d..f164acc 100644 --- a/content/common/gpu/media/gpu_video_decode_accelerator.cc +++ b/content/common/gpu/media/gpu_video_decode_accelerator.cc @@ -70,12 +70,12 @@ GpuVideoDecodeAccelerator::GpuVideoDecodeAccelerator( GpuVideoDecodeAccelerator::~GpuVideoDecodeAccelerator() { if (stub_) stub_->RemoveDestructionObserver(this); - if (video_decode_accelerator_) - video_decode_accelerator_->Destroy(); + if (video_decode_accelerator_.get()) + video_decode_accelerator_.release()->Destroy(); } bool GpuVideoDecodeAccelerator::OnMessageReceived(const IPC::Message& msg) { - if (!stub_ || !video_decode_accelerator_) + if (!stub_ || !video_decode_accelerator_.get()) return false; bool handled = true; IPC_BEGIN_MESSAGE_MAP(GpuVideoDecodeAccelerator, msg) @@ -169,31 +169,31 @@ void GpuVideoDecodeAccelerator::Initialize( return; } DLOG(INFO) << "Initializing DXVA HW decoder for windows."; - scoped_refptr<DXVAVideoDecodeAccelerator> video_decoder( + scoped_ptr<DXVAVideoDecodeAccelerator> video_decoder( new DXVAVideoDecodeAccelerator(this)); - video_decode_accelerator_ = video_decoder; + video_decode_accelerator_ = video_decoder.Pass(); #elif defined(OS_CHROMEOS) && defined(ARCH_CPU_ARMEL) - scoped_refptr<OmxVideoDecodeAccelerator> video_decoder( + scoped_ptr<OmxVideoDecodeAccelerator> video_decoder( new OmxVideoDecodeAccelerator(this)); video_decoder->SetEglState( gfx::GLSurfaceEGL::GetHardwareDisplay(), stub_->decoder()->GetGLContext()->GetHandle()); - video_decode_accelerator_ = video_decoder; + video_decode_accelerator_ = video_decoder.Pass(); #elif defined(OS_CHROMEOS) && defined(ARCH_CPU_X86_FAMILY) - scoped_refptr<VaapiVideoDecodeAccelerator> video_decoder( + scoped_ptr<VaapiVideoDecodeAccelerator> video_decoder( new VaapiVideoDecodeAccelerator(this, make_context_current_)); gfx::GLContextGLX* glx_context = static_cast<gfx::GLContextGLX*>(stub_->decoder()->GetGLContext()); GLXContext glx_context_handle = static_cast<GLXContext>(glx_context->GetHandle()); video_decoder->SetGlxState(glx_context->display(), glx_context_handle); - video_decode_accelerator_ = video_decoder; + video_decode_accelerator_ = video_decoder.Pass(); #elif defined(OS_MACOSX) - scoped_refptr<MacVideoDecodeAccelerator> video_decoder( + scoped_ptr<MacVideoDecodeAccelerator> video_decoder( new MacVideoDecodeAccelerator(this)); video_decoder->SetCGLContext(static_cast<CGLContextObj>( stub_->decoder()->GetGLContext()->GetHandle())); - video_decode_accelerator_ = video_decoder; + video_decode_accelerator_ = video_decoder.Pass(); #else NOTIMPLEMENTED() << "HW video decode acceleration not available."; NotifyError(media::VideoDecodeAccelerator::PLATFORM_FAILURE); @@ -263,7 +263,7 @@ void GpuVideoDecodeAccelerator::OnReset() { void GpuVideoDecodeAccelerator::OnDestroy() { DCHECK(video_decode_accelerator_.get()); - video_decode_accelerator_->Destroy(); + video_decode_accelerator_.release()->Destroy(); } void GpuVideoDecodeAccelerator::NotifyEndOfBitstreamBuffer( @@ -296,10 +296,8 @@ void GpuVideoDecodeAccelerator::NotifyResetDone() { void GpuVideoDecodeAccelerator::OnWillDestroyStub(GpuCommandBufferStub* stub) { DCHECK_EQ(stub, stub_.get()); - if (video_decode_accelerator_) { - video_decode_accelerator_->Destroy(); - video_decode_accelerator_ = NULL; - } + if (video_decode_accelerator_.get()) + video_decode_accelerator_.release()->Destroy(); if (stub_) { stub_->RemoveDestructionObserver(this); stub_.reset(); diff --git a/content/common/gpu/media/gpu_video_decode_accelerator.h b/content/common/gpu/media/gpu_video_decode_accelerator.h index e635670..6f7566c 100644 --- a/content/common/gpu/media/gpu_video_decode_accelerator.h +++ b/content/common/gpu/media/gpu_video_decode_accelerator.h @@ -84,8 +84,8 @@ class GpuVideoDecodeAccelerator // Unowned pointer to the underlying GpuCommandBufferStub. base::WeakPtr<GpuCommandBufferStub> stub_; - // Pointer to the underlying VideoDecodeAccelerator. - scoped_refptr<media::VideoDecodeAccelerator> video_decode_accelerator_; + // The underlying VideoDecodeAccelerator. + scoped_ptr<media::VideoDecodeAccelerator> video_decode_accelerator_; // Callback for making the relevant context current for GL calls. // Returns false if failed. diff --git a/content/common/gpu/media/mac_video_decode_accelerator.h b/content/common/gpu/media/mac_video_decode_accelerator.h index 55cb55b..2aa3830 100644 --- a/content/common/gpu/media/mac_video_decode_accelerator.h +++ b/content/common/gpu/media/mac_video_decode_accelerator.h @@ -33,6 +33,7 @@ class CONTENT_EXPORT MacVideoDecodeAccelerator public: // Does not take ownership of |client| which must outlive |*this|. MacVideoDecodeAccelerator(media::VideoDecodeAccelerator::Client* client); + virtual ~MacVideoDecodeAccelerator(); // Set the OpenGL context to use. void SetCGLContext(CGLContextObj cgl_context); @@ -48,7 +49,6 @@ class CONTENT_EXPORT MacVideoDecodeAccelerator virtual void Destroy() OVERRIDE; private: - virtual ~MacVideoDecodeAccelerator(); // Callback for a completed frame. void OnFrameReady(int32 bitstream_buffer_id, @@ -85,6 +85,9 @@ class CONTENT_EXPORT MacVideoDecodeAccelerator // has been processed. void NotifyInputBufferRead(int input_buffer_id); + // Helper for Destroy(), doing all the actual work except for deleting self. + void Cleanup(); + // To expose client callbacks from VideoDecodeAccelerator. Client* client_; // C++ wrapper around the Mac VDA API. diff --git a/content/common/gpu/media/mac_video_decode_accelerator.mm b/content/common/gpu/media/mac_video_decode_accelerator.mm index b10ec55..7aa9c6c 100644 --- a/content/common/gpu/media/mac_video_decode_accelerator.mm +++ b/content/common/gpu/media/mac_video_decode_accelerator.mm @@ -112,7 +112,7 @@ bool MacVideoDecodeAccelerator::Initialize(media::VideoCodecProfile profile) { return false; MessageLoop::current()->PostTask(FROM_HERE, base::Bind( - &MacVideoDecodeAccelerator::NotifyInitializeDone, this)); + &MacVideoDecodeAccelerator::NotifyInitializeDone, base::AsWeakPtr(this))); return true; } @@ -134,8 +134,8 @@ void MacVideoDecodeAccelerator::Decode( if (result == content::H264Parser::kEOStream) { if (bitstream_nalu_count_.count(bitstream_buffer.id()) == 0) { MessageLoop::current()->PostTask(FROM_HERE, base::Bind( - &MacVideoDecodeAccelerator::NotifyInputBufferRead, this, - bitstream_buffer.id())); + &MacVideoDecodeAccelerator::NotifyInputBufferRead, + base::AsWeakPtr(this), bitstream_buffer.id())); } return; } @@ -197,7 +197,7 @@ void MacVideoDecodeAccelerator::Flush() { "Call to Flush() during invalid state.", ILLEGAL_STATE,); vda_support_->Flush(true); MessageLoop::current()->PostTask(FROM_HERE, base::Bind( - &MacVideoDecodeAccelerator::NotifyFlushDone, this)); + &MacVideoDecodeAccelerator::NotifyFlushDone, base::AsWeakPtr(this))); } void MacVideoDecodeAccelerator::Reset() { @@ -206,10 +206,10 @@ void MacVideoDecodeAccelerator::Reset() { "Call to Reset() during invalid state.", ILLEGAL_STATE,); vda_support_->Flush(false); MessageLoop::current()->PostTask(FROM_HERE, base::Bind( - &MacVideoDecodeAccelerator::NotifyResetDone, this)); + &MacVideoDecodeAccelerator::NotifyResetDone, base::AsWeakPtr(this))); } -void MacVideoDecodeAccelerator::Destroy() { +void MacVideoDecodeAccelerator::Cleanup() { DCHECK(CalledOnValidThread()); if (vda_support_) { vda_support_->Destroy(); @@ -219,9 +219,17 @@ void MacVideoDecodeAccelerator::Destroy() { decoded_images_.clear(); } +void MacVideoDecodeAccelerator::Destroy() { + DCHECK(CalledOnValidThread()); + Cleanup(); + delete this; +} + MacVideoDecodeAccelerator::~MacVideoDecodeAccelerator() { DCHECK(CalledOnValidThread()); - Destroy(); + DCHECK(!vda_support_); + DCHECK(!client_); + DCHECK(decoded_images_.empty()); } void MacVideoDecodeAccelerator::OnFrameReady( @@ -247,8 +255,8 @@ void MacVideoDecodeAccelerator::OnFrameReady( if (--bitstream_count_it->second == 0) { bitstream_nalu_count_.erase(bitstream_count_it); MessageLoop::current()->PostTask(FROM_HERE, base::Bind( - &MacVideoDecodeAccelerator::NotifyInputBufferRead, this, - bitstream_buffer_id)); + &MacVideoDecodeAccelerator::NotifyInputBufferRead, + base::AsWeakPtr(this), bitstream_buffer_id)); } } @@ -279,7 +287,7 @@ void MacVideoDecodeAccelerator::StopOnError( media::VideoDecodeAccelerator::Error error) { if (client_) client_->NotifyError(error); - Destroy(); + Cleanup(); } bool MacVideoDecodeAccelerator::CreateDecoder( @@ -298,7 +306,7 @@ bool MacVideoDecodeAccelerator::CreateDecoder( PLATFORM_FAILURE, false); MessageLoop::current()->PostTask(FROM_HERE, base::Bind( - &MacVideoDecodeAccelerator::RequestPictures, this)); + &MacVideoDecodeAccelerator::RequestPictures, base::AsWeakPtr(this))); return true; } @@ -321,9 +329,9 @@ void MacVideoDecodeAccelerator::DecodeNALU(const content::H264NALU& nalu, // Keep a ref counted copy of the buffer. scoped_refptr<base::RefCountedBytes> bytes( base::RefCountedBytes::TakeVector(&data)); - vda_support_->Decode(bytes->front(), bytes->size(), - base::Bind(&MacVideoDecodeAccelerator::OnFrameReady, - this, bitstream_buffer_id, bytes)); + vda_support_->Decode(bytes->front(), bytes->size(), base::Bind( + &MacVideoDecodeAccelerator::OnFrameReady, + base::AsWeakPtr(this), bitstream_buffer_id, bytes)); } void MacVideoDecodeAccelerator::NotifyInitializeDone() { diff --git a/content/common/gpu/media/omx_video_decode_accelerator.cc b/content/common/gpu/media/omx_video_decode_accelerator.cc index 7bcd1bb..d8045ab 100644 --- a/content/common/gpu/media/omx_video_decode_accelerator.cc +++ b/content/common/gpu/media/omx_video_decode_accelerator.cc @@ -101,6 +101,7 @@ OmxVideoDecodeAccelerator::OmxVideoDecodeAccelerator( media::VideoDecodeAccelerator::Client* client) : message_loop_(MessageLoop::current()), component_handle_(NULL), + weak_this_(base::AsWeakPtr(this)), init_begun_(false), client_state_(OMX_StateMax), current_state_change_(NO_TRANSITION), @@ -190,7 +191,6 @@ bool OmxVideoDecodeAccelerator::CreateComponent() { PLATFORM_FAILURE, false); // Get the handle to the component. - AddRef(); // To reflect passing |this| to OMX_GetHandle below. result = omx_gethandle( &component_handle_, reinterpret_cast<OMX_STRING>(component.get()), this, &omx_accelerator_callbacks); @@ -439,6 +439,9 @@ void OmxVideoDecodeAccelerator::Reset() { void OmxVideoDecodeAccelerator::Destroy() { DCHECK_EQ(message_loop_, MessageLoop::current()); + + scoped_ptr<OmxVideoDecodeAccelerator> deleter(this); + if (current_state_change_ == ERRORING || current_state_change_ == DESTROYING) { return; @@ -462,7 +465,7 @@ void OmxVideoDecodeAccelerator::Destroy() { current_state_change_ = DESTROYING; client_ = NULL; BeginTransitionToState(OMX_StateIdle); - BusyLoopInDestroying(); + BusyLoopInDestroying(deleter.Pass()); } void OmxVideoDecodeAccelerator::BeginTransitionToState( @@ -562,14 +565,15 @@ void OmxVideoDecodeAccelerator::OnReachedExecutingInResetting() { // outlives the shutdown dance, even during process shutdown. We do this by // repeatedly enqueuing a no-op task until shutdown is complete, since // MessageLoop's shutdown drains pending tasks. -void OmxVideoDecodeAccelerator::BusyLoopInDestroying() { +void OmxVideoDecodeAccelerator::BusyLoopInDestroying( + scoped_ptr<OmxVideoDecodeAccelerator> self) { if (!component_handle_) return; // Can't use PostDelayedTask here because MessageLoop doesn't drain delayed // tasks. Instead we sleep for 5ms. Really. base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(5)); - message_loop_->PostTask( - FROM_HERE, base::Bind( - &OmxVideoDecodeAccelerator::BusyLoopInDestroying, this)); + MessageLoop::current()->PostTask(FROM_HERE, base::Bind( + &OmxVideoDecodeAccelerator::BusyLoopInDestroying, + base::Unretained(this), base::Passed(&self))); } void OmxVideoDecodeAccelerator::OnReachedIdleInDestroying() { @@ -590,8 +594,6 @@ void OmxVideoDecodeAccelerator::OnReachedIdleInDestroying() { FreeInputBuffers(); if (!output_buffers_at_component_) FreeOutputBuffers(); - - BusyLoopInDestroying(); } void OmxVideoDecodeAccelerator::OnReachedLoadedInDestroying() { @@ -610,12 +612,10 @@ void OmxVideoDecodeAccelerator::ShutdownComponent() { OMX_ERRORTYPE result = omx_free_handle(component_handle_); if (result != OMX_ErrorNone) DLOG(ERROR) << "OMX_FreeHandle() error. Error code: " << result; - component_handle_ = NULL; client_state_ = OMX_StateMax; - // This Release() call must happen *after* any access to |*this| because it - // might result in |this| being deleted. - Release(); // Since OMX no longer has |this| to call back to. omx_deinit(); + // Allow BusyLoopInDestroying to exit and delete |this|. + component_handle_ = NULL; } void OmxVideoDecodeAccelerator::StopOnError( @@ -1000,8 +1000,8 @@ OMX_ERRORTYPE OmxVideoDecodeAccelerator::EventHandler(OMX_HANDLETYPE component, static_cast<OmxVideoDecodeAccelerator*>(priv_data); DCHECK_EQ(component, decoder->component_handle_); decoder->message_loop_->PostTask(FROM_HERE, base::Bind( - &OmxVideoDecodeAccelerator::EventHandlerCompleteTask, decoder, - event, data1, data2)); + &OmxVideoDecodeAccelerator::EventHandlerCompleteTask, + decoder->weak_this(), event, data1, data2)); return OMX_ErrorNone; } @@ -1017,7 +1017,8 @@ OMX_ERRORTYPE OmxVideoDecodeAccelerator::EmptyBufferCallback( static_cast<OmxVideoDecodeAccelerator*>(priv_data); DCHECK_EQ(component, decoder->component_handle_); decoder->message_loop_->PostTask(FROM_HERE, base::Bind( - &OmxVideoDecodeAccelerator::EmptyBufferDoneTask, decoder, buffer)); + &OmxVideoDecodeAccelerator::EmptyBufferDoneTask, decoder->weak_this(), + buffer)); return OMX_ErrorNone; } @@ -1037,7 +1038,8 @@ OMX_ERRORTYPE OmxVideoDecodeAccelerator::FillBufferCallback( static_cast<OmxVideoDecodeAccelerator*>(priv_data); DCHECK_EQ(component, decoder->component_handle_); decoder->message_loop_->PostTask(FROM_HERE, base::Bind( - &OmxVideoDecodeAccelerator::FillBufferDoneTask, decoder, buffer)); + &OmxVideoDecodeAccelerator::FillBufferDoneTask, decoder->weak_this(), + buffer)); return OMX_ErrorNone; } diff --git a/content/common/gpu/media/omx_video_decode_accelerator.h b/content/common/gpu/media/omx_video_decode_accelerator.h index b42a39b..1c186a2 100644 --- a/content/common/gpu/media/omx_video_decode_accelerator.h +++ b/content/common/gpu/media/omx_video_decode_accelerator.h @@ -15,7 +15,6 @@ #include "base/compiler_specific.h" #include "base/logging.h" -#include "base/memory/ref_counted.h" #include "base/message_loop.h" #include "base/shared_memory.h" #include "content/common/content_export.h" @@ -32,16 +31,15 @@ class Gles2TextureToEglImageTranslator; // The implementation assumes an OpenMAX IL 1.1.2 implementation conforming to // http://www.khronos.org/registry/omxil/specs/OpenMAX_IL_1_1_2_Specification.pdf // -// This class lives on a single thread and DCHECKs that it is never accessed -// from any other. OMX callbacks are trampolined from the OMX component's -// thread to maintain this invariant. The only exception to thread-unsafety is -// that references can be added from any thread (practically used only by the -// OMX thread). +// This class lives on a single thread (the GPU process ChildThread) and DCHECKs +// that it is never accessed from any other. OMX callbacks are trampolined from +// the OMX component's thread to maintain this invariant, using |weak_this()|. class CONTENT_EXPORT OmxVideoDecodeAccelerator : public media::VideoDecodeAccelerator { public: // Does not take ownership of |client| which must outlive |*this|. OmxVideoDecodeAccelerator(media::VideoDecodeAccelerator::Client* client); + virtual ~OmxVideoDecodeAccelerator(); // media::VideoDecodeAccelerator implementation. bool Initialize(media::VideoCodecProfile profile) OVERRIDE; @@ -55,9 +53,9 @@ class CONTENT_EXPORT OmxVideoDecodeAccelerator : void SetEglState(EGLDisplay egl_display, EGLContext egl_context); - private: - virtual ~OmxVideoDecodeAccelerator(); + base::WeakPtr<OmxVideoDecodeAccelerator> weak_this() { return weak_this_; } + private: // Because OMX state-transitions are described solely by the "state reached" // (3.1.2.9.1, table 3-7 of the spec), we track what transition was requested // using this enum. Note that it is an error to request a transition while @@ -114,7 +112,7 @@ class CONTENT_EXPORT OmxVideoDecodeAccelerator : void OnReachedEOSInFlushing(); void OnReachedInvalidInErroring(); void ShutdownComponent(); - void BusyLoopInDestroying(); + void BusyLoopInDestroying(scoped_ptr<OmxVideoDecodeAccelerator> self); // Port-flushing helpers. void FlushIOPorts(); @@ -138,6 +136,11 @@ class CONTENT_EXPORT OmxVideoDecodeAccelerator : // Decode bitstream buffers that were queued (see queued_bitstream_buffers_). void DecodeQueuedBitstreamBuffers(); + // Weak pointer to |this|; used to safely trampoline calls from the OMX thread + // to the ChildThread. Since |this| is kept alive until OMX is fully shut + // down, only the OMX->Child thread direction needs to be guarded this way. + base::WeakPtr<OmxVideoDecodeAccelerator> weak_this_; + // True once Initialize() has returned true; before this point there's never a // point in calling client_->NotifyError(). bool init_begun_; diff --git a/content/common/gpu/media/vaapi_video_decode_accelerator.cc b/content/common/gpu/media/vaapi_video_decode_accelerator.cc index 389d406..a9bddee 100644 --- a/content/common/gpu/media/vaapi_video_decode_accelerator.cc +++ b/content/common/gpu/media/vaapi_video_decode_accelerator.cc @@ -36,8 +36,9 @@ VaapiVideoDecodeAccelerator::InputBuffer::~InputBuffer() { void VaapiVideoDecodeAccelerator::NotifyError(Error error) { if (message_loop_ != MessageLoop::current()) { + DCHECK_EQ(decoder_thread_.message_loop(), MessageLoop::current()); message_loop_->PostTask(FROM_HERE, base::Bind( - &VaapiVideoDecodeAccelerator::NotifyError, this, error)); + &VaapiVideoDecodeAccelerator::NotifyError, weak_this_, error)); return; } @@ -47,7 +48,7 @@ void VaapiVideoDecodeAccelerator::NotifyError(Error error) { client_->NotifyError(error); client_ptr_factory_.InvalidateWeakPtrs(); } - Destroy(); + Cleanup(); } VaapiVideoDecodeAccelerator::VaapiVideoDecodeAccelerator( @@ -58,6 +59,7 @@ VaapiVideoDecodeAccelerator::VaapiVideoDecodeAccelerator( input_ready_(&lock_), output_ready_(&lock_), message_loop_(MessageLoop::current()), + weak_this_(base::AsWeakPtr(this)), client_ptr_factory_(client), client_(client_ptr_factory_.GetWeakPtr()), decoder_thread_("VaapiDecoderThread") { @@ -78,7 +80,8 @@ bool VaapiVideoDecodeAccelerator::Initialize( bool res = decoder_.Initialize( profile, x_display_, glx_context_, make_context_current_, - base::Bind(&VaapiVideoDecodeAccelerator::OutputPicCallback, this)); + base::Bind(&VaapiVideoDecodeAccelerator::OutputPicCallback, + base::Unretained(this))); if (!res) { DVLOG(1) << "Failed initializing decoder"; return false; @@ -181,7 +184,8 @@ void VaapiVideoDecodeAccelerator::InitialDecodeTask() { DCHECK_EQ(state_, kIdle); state_ = kDecoding; decoder_thread_.message_loop()->PostTask(FROM_HERE, base::Bind( - &VaapiVideoDecodeAccelerator::DecodeTask, this)); + &VaapiVideoDecodeAccelerator::DecodeTask, + base::Unretained(this))); } return; @@ -342,8 +346,9 @@ void VaapiVideoDecodeAccelerator::Decode( switch (state_) { case kInitialized: // Initial decode to get the required size of output buffers. - decoder_thread_.message_loop()->PostTask(FROM_HERE, - base::Bind(&VaapiVideoDecodeAccelerator::InitialDecodeTask, this)); + decoder_thread_.message_loop()->PostTask(FROM_HERE, base::Bind( + &VaapiVideoDecodeAccelerator::InitialDecodeTask, + base::Unretained(this))); break; case kPicturesRequested: @@ -355,8 +360,9 @@ void VaapiVideoDecodeAccelerator::Decode( case kIdle: // Need to get decoder into suitable stream location to resume. - decoder_thread_.message_loop()->PostTask(FROM_HERE, - base::Bind(&VaapiVideoDecodeAccelerator::InitialDecodeTask, this)); + decoder_thread_.message_loop()->PostTask(FROM_HERE, base::Bind( + &VaapiVideoDecodeAccelerator::InitialDecodeTask, + base::Unretained(this))); break; default: @@ -384,8 +390,8 @@ void VaapiVideoDecodeAccelerator::AssignPictureBuffers( } state_ = kDecoding; - decoder_thread_.message_loop()->PostTask(FROM_HERE, - base::Bind(&VaapiVideoDecodeAccelerator::DecodeTask, this)); + decoder_thread_.message_loop()->PostTask(FROM_HERE, base::Bind( + &VaapiVideoDecodeAccelerator::DecodeTask, base::Unretained(this))); } void VaapiVideoDecodeAccelerator::ReusePictureBuffer(int32 picture_buffer_id) { @@ -411,8 +417,8 @@ void VaapiVideoDecodeAccelerator::FlushTask() { // Put the decoder in idle state, ready to resume. decoder_.Reset(); - message_loop_->PostTask(FROM_HERE, - base::Bind(&VaapiVideoDecodeAccelerator::FinishFlush, this)); + message_loop_->PostTask(FROM_HERE, base::Bind( + &VaapiVideoDecodeAccelerator::FinishFlush, weak_this_)); } void VaapiVideoDecodeAccelerator::Flush() { @@ -422,8 +428,8 @@ void VaapiVideoDecodeAccelerator::Flush() { base::AutoLock auto_lock(lock_); state_ = kFlushing; // Queue a flush task after all existing decoding tasks to clean up. - decoder_thread_.message_loop()->PostTask(FROM_HERE, - base::Bind(&VaapiVideoDecodeAccelerator::FlushTask, this)); + decoder_thread_.message_loop()->PostTask(FROM_HERE, base::Bind( + &VaapiVideoDecodeAccelerator::FlushTask, base::Unretained(this))); input_ready_.Signal(); output_ready_.Signal(); @@ -460,7 +466,7 @@ void VaapiVideoDecodeAccelerator::ResetTask() { // And let client know that we are done with reset. message_loop_->PostTask(FROM_HERE, base::Bind( - &VaapiVideoDecodeAccelerator::FinishReset, this)); + &VaapiVideoDecodeAccelerator::FinishReset, weak_this_)); } void VaapiVideoDecodeAccelerator::Reset() { @@ -471,8 +477,8 @@ void VaapiVideoDecodeAccelerator::Reset() { base::AutoLock auto_lock(lock_); state_ = kResetting; - decoder_thread_.message_loop()->PostTask(FROM_HERE, - base::Bind(&VaapiVideoDecodeAccelerator::ResetTask, this)); + decoder_thread_.message_loop()->PostTask(FROM_HERE, base::Bind( + &VaapiVideoDecodeAccelerator::ResetTask, base::Unretained(this))); input_ready_.Signal(); output_ready_.Signal(); @@ -503,7 +509,7 @@ void VaapiVideoDecodeAccelerator::FinishReset() { DVLOG(1) << "Reset finished"; } -void VaapiVideoDecodeAccelerator::Destroy() { +void VaapiVideoDecodeAccelerator::Cleanup() { DCHECK_EQ(message_loop_, MessageLoop::current()); if (state_ == kUninitialized || state_ == kDestroying) @@ -524,12 +530,19 @@ void VaapiVideoDecodeAccelerator::Destroy() { input_ready_.Signal(); output_ready_.Signal(); waiter.Wait(); + decoder_thread_.Stop(); } decoder_.Destroy(); state_ = kUninitialized; } +void VaapiVideoDecodeAccelerator::Destroy() { + DCHECK_EQ(message_loop_, MessageLoop::current()); + Cleanup(); + delete this; +} + void VaapiVideoDecodeAccelerator::OutputPicCallback(int32 input_id, int32 output_id) { TRACE_EVENT2("Video Decoder", "VAVDA::OutputPicCallback", @@ -539,7 +552,7 @@ void VaapiVideoDecodeAccelerator::OutputPicCallback(int32 input_id, // Forward the request to the main thread. DCHECK_EQ(decoder_thread_.message_loop(), MessageLoop::current()); - message_loop_->PostTask(FROM_HERE, - base::Bind(&VaapiVideoDecodeAccelerator::SyncAndNotifyPictureReady, - this, input_id, output_id)); + message_loop_->PostTask(FROM_HERE, base::Bind( + &VaapiVideoDecodeAccelerator::SyncAndNotifyPictureReady, weak_this_, + input_id, output_id)); } diff --git a/content/common/gpu/media/vaapi_video_decode_accelerator.h b/content/common/gpu/media/vaapi_video_decode_accelerator.h index 6624792..9fdffde 100644 --- a/content/common/gpu/media/vaapi_video_decode_accelerator.h +++ b/content/common/gpu/media/vaapi_video_decode_accelerator.h @@ -32,12 +32,18 @@ // Class to provide video decode acceleration for Intel systems with hardware // support for it, and on which libva is available. // Decoding tasks are performed in a separate decoding thread. +// +// Threading/life-cycle: this object is created & destroyed on the GPU +// ChildThread. A few methods on it are called on the decoder thread which is +// stopped during |this->Destroy()|, so any tasks posted to the decoder thread +// can assume |*this| is still alive. See |weak_this_| below for more details. class CONTENT_EXPORT VaapiVideoDecodeAccelerator : public media::VideoDecodeAccelerator { public: VaapiVideoDecodeAccelerator( Client* client, const base::Callback<bool(void)>& make_context_current); + virtual ~VaapiVideoDecodeAccelerator(); // media::VideoDecodeAccelerator implementation. virtual bool Initialize(media::VideoCodecProfile profile) OVERRIDE; @@ -53,8 +59,6 @@ class CONTENT_EXPORT VaapiVideoDecodeAccelerator : void SetGlxState(Display* x_display, GLXContext glx_context); private: - virtual ~VaapiVideoDecodeAccelerator(); - // Ensure data has been synced with the output texture and notify // the client it is ready for displaying. void SyncAndNotifyPictureReady(int32 input_id, int32 output_id); @@ -116,6 +120,9 @@ class CONTENT_EXPORT VaapiVideoDecodeAccelerator : // finished. void FinishReset(); + // Helper for Destroy(), doing all the actual work except for deleting self. + void Cleanup(); + // Client-provided X/GLX state. Display* x_display_; GLXContext glx_context_; @@ -174,6 +181,14 @@ class CONTENT_EXPORT VaapiVideoDecodeAccelerator : // ChildThread's message loop MessageLoop* message_loop_; + // WeakPtr<> pointing to |this| for use in posting tasks from the decoder + // thread back to the ChildThread. Because the decoder thread is a member of + // this class, any task running on the decoder thread is guaranteed that this + // object is still alive. As a result, tasks posted from ChildThread to + // decoder thread should use base::Unretained(this), and tasks posted from the + // decoder thread to the ChildThread should use |weak_this_|. + base::WeakPtr<VaapiVideoDecodeAccelerator> weak_this_; + // To expose client callbacks from VideoDecodeAccelerator. // NOTE: all calls to these objects *MUST* be executed on message_loop_. base::WeakPtrFactory<Client> client_ptr_factory_; diff --git a/content/common/gpu/media/video_decode_accelerator_unittest.cc b/content/common/gpu/media/video_decode_accelerator_unittest.cc index 8b01a05..59f6f20 100644 --- a/content/common/gpu/media/video_decode_accelerator_unittest.cc +++ b/content/common/gpu/media/video_decode_accelerator_unittest.cc @@ -224,7 +224,7 @@ class GLRenderingVDAClient : public VideoDecodeAccelerator::Client { int num_done_bitstream_buffers() { return num_done_bitstream_buffers_; } int num_decoded_frames() { return num_decoded_frames_; } double frames_per_second(); - bool decoder_deleted() { return !decoder_; } + bool decoder_deleted() { return !decoder_.get(); } private: typedef std::map<int, media::PictureBuffer*> PictureBufferById; @@ -250,7 +250,7 @@ class GLRenderingVDAClient : public VideoDecodeAccelerator::Client { size_t encoded_data_next_pos_to_decode_; int next_bitstream_buffer_id_; ClientStateNotification* note_; - scoped_refptr<VideoDecodeAccelerator> decoder_; + scoped_ptr<VideoDecodeAccelerator> decoder_; std::set<int> outstanding_texture_ids_; int remaining_play_throughs_; int reset_after_frame_num_; @@ -308,27 +308,27 @@ static bool DoNothingReturnTrue() { return true; } void GLRenderingVDAClient::CreateDecoder() { CHECK(decoder_deleted()); #if defined(OS_WIN) - scoped_refptr<DXVAVideoDecodeAccelerator> decoder = - new DXVAVideoDecodeAccelerator(this); + scoped_ptr<DXVAVideoDecodeAccelerator> decoder( + new DXVAVideoDecodeAccelerator(this)); #elif defined(OS_MACOSX) - scoped_refptr<MacVideoDecodeAccelerator> decoder = - new MacVideoDecodeAccelerator(this); + scoped_ptr<MacVideoDecodeAccelerator> decoder( + new MacVideoDecodeAccelerator(this)); decoder->SetCGLContext( static_cast<CGLContextObj>(rendering_helper_->GetGLContext())); #elif defined(ARCH_CPU_ARMEL) - scoped_refptr<OmxVideoDecodeAccelerator> decoder = - new OmxVideoDecodeAccelerator(this); + scoped_ptr<OmxVideoDecodeAccelerator> decoder( + new OmxVideoDecodeAccelerator(this)); decoder->SetEglState( static_cast<EGLDisplay>(rendering_helper_->GetGLDisplay()), static_cast<EGLContext>(rendering_helper_->GetGLContext())); #elif defined(ARCH_CPU_X86_FAMILY) - scoped_refptr<VaapiVideoDecodeAccelerator> decoder = - new VaapiVideoDecodeAccelerator(this, base::Bind(&DoNothingReturnTrue)); + scoped_ptr<VaapiVideoDecodeAccelerator> decoder( + new VaapiVideoDecodeAccelerator(this, base::Bind(&DoNothingReturnTrue))); decoder->SetGlxState( static_cast<Display*>(rendering_helper_->GetGLDisplay()), static_cast<GLXContext>(rendering_helper_->GetGLContext())); #endif // OS_WIN - decoder_ = decoder.release(); + decoder_ = decoder.Pass(); SetState(CS_DECODER_SET); if (decoder_deleted()) return; @@ -483,8 +483,7 @@ void GLRenderingVDAClient::SetState(ClientState new_state) { void GLRenderingVDAClient::DeleteDecoder() { if (decoder_deleted()) return; - decoder_->Destroy(); - decoder_ = NULL; + decoder_.release()->Destroy(); STLClearObject(&encoded_data_); for (std::set<int>::iterator it = outstanding_texture_ids_.begin(); it != outstanding_texture_ids_.end(); ++it) { diff --git a/content/content_tests.gypi b/content/content_tests.gypi index 30f8bb5..c0672bb 100644 --- a/content/content_tests.gypi +++ b/content/content_tests.gypi @@ -629,7 +629,9 @@ '../third_party/angle/src/build_angle.gyp:libGLESv2', ], }], - ['OS=="win" and win_use_allocator_shim==1', { + ['(OS=="win" and win_use_allocator_shim==1) or ' + '(os_posix == 1 and OS != "mac" and OS != "android" and ' + ' linux_use_tcmalloc==1)', { 'dependencies': [ '../base/allocator/allocator.gyp:allocator', ], diff --git a/content/renderer/media/pepper_platform_video_decoder_impl.cc b/content/renderer/media/pepper_platform_video_decoder_impl.cc index 62e5d23..b00f36c 100644 --- a/content/renderer/media/pepper_platform_video_decoder_impl.cc +++ b/content/renderer/media/pepper_platform_video_decoder_impl.cc @@ -26,7 +26,7 @@ PlatformVideoDecoderImpl::~PlatformVideoDecoderImpl() {} bool PlatformVideoDecoderImpl::Initialize(media::VideoCodecProfile profile) { // TODO(vrk): Support multiple decoders. - if (decoder_) + if (decoder_.get()) return true; RenderThreadImpl* render_thread = RenderThreadImpl::current(); @@ -43,43 +43,43 @@ bool PlatformVideoDecoderImpl::Initialize(media::VideoCodecProfile profile) { DCHECK_EQ(channel->state(), GpuChannelHost::kConnected); // Send IPC message to initialize decoder in GPU process. - decoder_ = channel->CreateVideoDecoder( - command_buffer_route_id_, profile, this); + decoder_.reset(channel->CreateVideoDecoder( + command_buffer_route_id_, profile, this)); return decoder_.get() != NULL; } void PlatformVideoDecoderImpl::Decode(const BitstreamBuffer& bitstream_buffer) { - DCHECK(decoder_); + DCHECK(decoder_.get()); decoder_->Decode(bitstream_buffer); } void PlatformVideoDecoderImpl::AssignPictureBuffers( const std::vector<media::PictureBuffer>& buffers) { - DCHECK(decoder_); + DCHECK(decoder_.get()); decoder_->AssignPictureBuffers(buffers); } void PlatformVideoDecoderImpl::ReusePictureBuffer( int32 picture_buffer_id) { - DCHECK(decoder_); + DCHECK(decoder_.get()); decoder_->ReusePictureBuffer(picture_buffer_id); } void PlatformVideoDecoderImpl::Flush() { - DCHECK(decoder_); + DCHECK(decoder_.get()); decoder_->Flush(); } void PlatformVideoDecoderImpl::Reset() { - DCHECK(decoder_); + DCHECK(decoder_.get()); decoder_->Reset(); } void PlatformVideoDecoderImpl::Destroy() { - DCHECK(decoder_); - decoder_->Destroy(); + DCHECK(decoder_.get()); + decoder_.release()->Destroy(); client_ = NULL; - decoder_ = NULL; + delete this; } void PlatformVideoDecoderImpl::NotifyError( diff --git a/content/renderer/media/pepper_platform_video_decoder_impl.h b/content/renderer/media/pepper_platform_video_decoder_impl.h index d79ce01..0008531 100644 --- a/content/renderer/media/pepper_platform_video_decoder_impl.h +++ b/content/renderer/media/pepper_platform_video_decoder_impl.h @@ -58,7 +58,7 @@ class PlatformVideoDecoderImpl int32 command_buffer_route_id_; // Holds a GpuVideoDecodeAcceleratorHost. - scoped_refptr<media::VideoDecodeAccelerator> decoder_; + scoped_ptr<media::VideoDecodeAccelerator> decoder_; DISALLOW_COPY_AND_ASSIGN(PlatformVideoDecoderImpl); }; diff --git a/media/filters/gpu_video_decoder.cc b/media/filters/gpu_video_decoder.cc index 7415db8..e5bca0d 100644 --- a/media/filters/gpu_video_decoder.cc +++ b/media/filters/gpu_video_decoder.cc @@ -72,7 +72,7 @@ void GpuVideoDecoder::Reset(const base::Closure& closure) { // Throw away any already-decoded, not-yet-delivered frames. ready_video_frames_.clear(); - if (!vda_) { + if (!vda_.get()) { closure.Run(); return; } @@ -94,7 +94,7 @@ void GpuVideoDecoder::Reset(const base::Closure& closure) { } vda_loop_proxy_->PostTask(FROM_HERE, base::Bind( - &VideoDecodeAccelerator::Reset, vda_)); + &VideoDecodeAccelerator::Reset, weak_vda_)); } void GpuVideoDecoder::Stop(const base::Closure& closure) { @@ -103,13 +103,13 @@ void GpuVideoDecoder::Stop(const base::Closure& closure) { &GpuVideoDecoder::Stop, this, closure)); return; } - if (!vda_) { + if (!vda_.get()) { closure.Run(); return; } + VideoDecodeAccelerator* vda ALLOW_UNUSED = vda_.release(); vda_loop_proxy_->PostTask(FROM_HERE, base::Bind( - &VideoDecodeAccelerator::Destroy, vda_)); - vda_ = NULL; + &VideoDecodeAccelerator::Destroy, weak_vda_)); closure.Run(); } @@ -141,8 +141,9 @@ void GpuVideoDecoder::Initialize(const scoped_refptr<DemuxerStream>& stream, return; } - vda_ = factories_->CreateVideoDecodeAccelerator(config.profile(), this); - if (!vda_) { + VideoDecodeAccelerator* vda = + factories_->CreateVideoDecodeAccelerator(config.profile(), this); + if (!vda) { status_cb.Run(DECODER_ERROR_NOT_SUPPORTED); return; } @@ -156,7 +157,16 @@ void GpuVideoDecoder::Initialize(const scoped_refptr<DemuxerStream>& stream, config_frame_duration_ = GetFrameDuration(config); DVLOG(1) << "GpuVideoDecoder::Initialize() succeeded."; - status_cb.Run(PIPELINE_OK); + vda_loop_proxy_->PostTaskAndReply( + FROM_HERE, + base::Bind(&GpuVideoDecoder::SetVDA, this, vda), + base::Bind(status_cb, PIPELINE_OK)); +} + +void GpuVideoDecoder::SetVDA(VideoDecodeAccelerator* vda) { + DCHECK(vda_loop_proxy_->BelongsToCurrentThread()); + vda_.reset(vda); + weak_vda_ = vda->AsWeakPtr(); } void GpuVideoDecoder::Read(const ReadCB& read_cb) { @@ -171,7 +181,7 @@ void GpuVideoDecoder::Read(const ReadCB& read_cb) { return; } - if (!vda_) { + if (!vda_.get()) { read_cb.Run(kOk, VideoFrame::CreateEmptyFrame()); return; } @@ -218,7 +228,7 @@ void GpuVideoDecoder::RequestBufferDecode( return; } - if (!vda_) { + if (!vda_.get()) { EnqueueFrameAndTriggerFrameDelivery(VideoFrame::CreateEmptyFrame()); return; } @@ -227,7 +237,7 @@ void GpuVideoDecoder::RequestBufferDecode( if (state_ == kNormal) { state_ = kDrainingDecoder; vda_loop_proxy_->PostTask(FROM_HERE, base::Bind( - &VideoDecodeAccelerator::Flush, vda_)); + &VideoDecodeAccelerator::Flush, weak_vda_)); } return; } @@ -243,7 +253,7 @@ void GpuVideoDecoder::RequestBufferDecode( RecordBufferTimeData(bitstream_buffer, *buffer); vda_loop_proxy_->PostTask(FROM_HERE, base::Bind( - &VideoDecodeAccelerator::Decode, vda_, bitstream_buffer)); + &VideoDecodeAccelerator::Decode, weak_vda_, bitstream_buffer)); } void GpuVideoDecoder::RecordBufferTimeData( @@ -319,7 +329,7 @@ void GpuVideoDecoder::ProvidePictureBuffers(uint32 count, return; } - if (!vda_) + if (!vda_.get()) return; std::vector<PictureBuffer> picture_buffers; @@ -331,7 +341,8 @@ void GpuVideoDecoder::ProvidePictureBuffers(uint32 count, DCHECK(inserted); } vda_loop_proxy_->PostTask(FROM_HERE, base::Bind( - &VideoDecodeAccelerator::AssignPictureBuffers, vda_, picture_buffers)); + &VideoDecodeAccelerator::AssignPictureBuffers, weak_vda_, + picture_buffers)); } void GpuVideoDecoder::DismissPictureBuffer(int32 id) { @@ -409,10 +420,11 @@ void GpuVideoDecoder::ReusePictureBuffer(int64 picture_buffer_id) { &GpuVideoDecoder::ReusePictureBuffer, this, picture_buffer_id)); return; } - if (!vda_) + if (!vda_.get()) return; vda_loop_proxy_->PostTask(FROM_HERE, base::Bind( - &VideoDecodeAccelerator::ReusePictureBuffer, vda_, picture_buffer_id)); + &VideoDecodeAccelerator::ReusePictureBuffer, weak_vda_, + picture_buffer_id)); } GpuVideoDecoder::SHMBuffer* GpuVideoDecoder::GetSHM(size_t min_size) { @@ -467,7 +479,7 @@ void GpuVideoDecoder::NotifyEndOfBitstreamBuffer(int32 id) { } GpuVideoDecoder::~GpuVideoDecoder() { - DCHECK(!vda_); // Stop should have been already called. + DCHECK(!vda_.get()); // Stop should have been already called. DCHECK(pending_read_cb_.is_null()); for (size_t i = 0; i < available_shm_segments_.size(); ++i) { available_shm_segments_[i]->shm->Close(); @@ -510,7 +522,7 @@ void GpuVideoDecoder::NotifyResetDone() { return; } - if (!vda_) + if (!vda_.get()) return; DCHECK(ready_video_frames_.empty()); @@ -532,9 +544,9 @@ void GpuVideoDecoder::NotifyError(media::VideoDecodeAccelerator::Error error) { &GpuVideoDecoder::NotifyError, this, error)); return; } - if (!vda_) + if (!vda_.get()) return; - vda_ = NULL; + vda_loop_proxy_->DeleteSoon(FROM_HERE, vda_.release()); DLOG(ERROR) << "VDA Error: " << error; error_occured_ = true; diff --git a/media/filters/gpu_video_decoder.h b/media/filters/gpu_video_decoder.h index f4c3c63..1ccbbde 100644 --- a/media/filters/gpu_video_decoder.h +++ b/media/filters/gpu_video_decoder.h @@ -119,6 +119,10 @@ class MEDIA_EXPORT GpuVideoDecoder void GetBufferTimeData( int32 id, base::TimeDelta* timestamp, base::TimeDelta* duration); + // Set |vda_| and |weak_vda_| on the VDA thread (in practice the render + // thread). + void SetVDA(VideoDecodeAccelerator* vda); + // A shared memory segment and its allocated size. struct SHMBuffer { SHMBuffer(base::SharedMemory* m, size_t s); @@ -158,8 +162,11 @@ class MEDIA_EXPORT GpuVideoDecoder scoped_refptr<Factories> factories_; - // Populated during Initialize() (on success) and unchanged thereafter. - scoped_refptr<VideoDecodeAccelerator> vda_; + // Populated during Initialize() via SetVDA() (on success) and unchanged + // until an error occurs + scoped_ptr<VideoDecodeAccelerator> vda_; + // Used to post tasks from the GVD thread to the VDA thread safely. + base::WeakPtr<VideoDecodeAccelerator> weak_vda_; // Callbacks that are !is_null() only during their respective operation being // asynchronously executed. diff --git a/media/video/video_decode_accelerator.h b/media/video/video_decode_accelerator.h index 83d0b95..63553a9 100644 --- a/media/video/video_decode_accelerator.h +++ b/media/video/video_decode_accelerator.h @@ -8,6 +8,7 @@ #include <vector> #include "base/basictypes.h" +#include "base/memory/weak_ptr.h" #include "media/base/bitstream_buffer.h" #include "media/base/video_decoder_config.h" #include "media/video/picture.h" @@ -18,12 +19,11 @@ namespace media { // Video decoder interface. // This interface is extended by the various components that ultimately // implement the backend of PPB_VideoDecode_Dev. -// -// No thread-safety guarantees are implied by the use of RefCountedThreadSafe -// below. class MEDIA_EXPORT VideoDecodeAccelerator - : public base::RefCountedThreadSafe<VideoDecodeAccelerator> { + : public base::SupportsWeakPtr<VideoDecodeAccelerator> { public: + virtual ~VideoDecodeAccelerator(); + // Enumeration of potential errors generated by the API. // Note: Keep these in sync with PP_VideoDecodeError_Dev. enum Error { @@ -126,12 +126,9 @@ class MEDIA_EXPORT VideoDecodeAccelerator // Destroys the decoder: all pending inputs are dropped immediately and the // component is freed. This call may asynchornously free system resources, // but its client-visible effects are synchronous. After this method returns - // no more callbacks will be made on the client. + // no more callbacks will be made on the client. Deletes |this| + // unconditionally, so make sure to drop all pointers to it! virtual void Destroy() = 0; - - protected: - friend class base::RefCountedThreadSafe<VideoDecodeAccelerator>; - virtual ~VideoDecodeAccelerator(); }; } // namespace media diff --git a/webkit/plugins/ppapi/plugin_delegate.h b/webkit/plugins/ppapi/plugin_delegate.h index 9c3e38c..c393d0c 100644 --- a/webkit/plugins/ppapi/plugin_delegate.h +++ b/webkit/plugins/ppapi/plugin_delegate.h @@ -269,7 +269,7 @@ class PluginDelegate { // Interface for PlatformVideoDecoder is directly inherited from general media // VideoDecodeAccelerator interface. class PlatformVideoDecoder : public media::VideoDecodeAccelerator { - protected: + public: virtual ~PlatformVideoDecoder() {} }; diff --git a/webkit/plugins/ppapi/ppb_video_decoder_impl.cc b/webkit/plugins/ppapi/ppb_video_decoder_impl.cc index 9c63e13..b1bcc9d 100644 --- a/webkit/plugins/ppapi/ppb_video_decoder_impl.cc +++ b/webkit/plugins/ppapi/ppb_video_decoder_impl.cc @@ -116,9 +116,9 @@ bool PPB_VideoDecoder_Impl::Init( if (!plugin_delegate) return false; - platform_video_decoder_ = plugin_delegate->CreateVideoDecoder( - this, command_buffer_route_id); - if (!platform_video_decoder_) + platform_video_decoder_.reset(plugin_delegate->CreateVideoDecoder( + this, command_buffer_route_id)); + if (!platform_video_decoder_.get()) return false; FlushCommandBuffer(); @@ -128,7 +128,7 @@ bool PPB_VideoDecoder_Impl::Init( int32_t PPB_VideoDecoder_Impl::Decode( const PP_VideoBitstreamBuffer_Dev* bitstream_buffer, scoped_refptr<TrackedCallback> callback) { - if (!platform_video_decoder_) + if (!platform_video_decoder_.get()) return PP_ERROR_BADRESOURCE; EnterResourceNoLock<PPB_Buffer_API> enter(bitstream_buffer->data, true); @@ -151,7 +151,7 @@ int32_t PPB_VideoDecoder_Impl::Decode( void PPB_VideoDecoder_Impl::AssignPictureBuffers( uint32_t no_of_buffers, const PP_PictureBuffer_Dev* buffers) { - if (!platform_video_decoder_) + if (!platform_video_decoder_.get()) return; std::vector<media::PictureBuffer> wrapped_buffers; @@ -169,7 +169,7 @@ void PPB_VideoDecoder_Impl::AssignPictureBuffers( } void PPB_VideoDecoder_Impl::ReusePictureBuffer(int32_t picture_buffer_id) { - if (!platform_video_decoder_) + if (!platform_video_decoder_.get()) return; FlushCommandBuffer(); @@ -177,7 +177,7 @@ void PPB_VideoDecoder_Impl::ReusePictureBuffer(int32_t picture_buffer_id) { } int32_t PPB_VideoDecoder_Impl::Flush(scoped_refptr<TrackedCallback> callback) { - if (!platform_video_decoder_) + if (!platform_video_decoder_.get()) return PP_ERROR_BADRESOURCE; if (!SetFlushCallback(callback)) @@ -189,7 +189,7 @@ int32_t PPB_VideoDecoder_Impl::Flush(scoped_refptr<TrackedCallback> callback) { } int32_t PPB_VideoDecoder_Impl::Reset(scoped_refptr<TrackedCallback> callback) { - if (!platform_video_decoder_) + if (!platform_video_decoder_.get()) return PP_ERROR_BADRESOURCE; if (!SetResetCallback(callback)) @@ -201,13 +201,12 @@ int32_t PPB_VideoDecoder_Impl::Reset(scoped_refptr<TrackedCallback> callback) { } void PPB_VideoDecoder_Impl::Destroy() { - if (!platform_video_decoder_) + if (!platform_video_decoder_.get()) return; FlushCommandBuffer(); - platform_video_decoder_->Destroy(); + platform_video_decoder_.release()->Destroy(); ::ppapi::PPB_VideoDecoder_Shared::Destroy(); - platform_video_decoder_ = NULL; ppp_videodecoder_ = NULL; } diff --git a/webkit/plugins/ppapi/ppb_video_decoder_impl.h b/webkit/plugins/ppapi/ppb_video_decoder_impl.h index f82f702..ea29305 100644 --- a/webkit/plugins/ppapi/ppb_video_decoder_impl.h +++ b/webkit/plugins/ppapi/ppb_video_decoder_impl.h @@ -73,7 +73,7 @@ class PPB_VideoDecoder_Impl : public ::ppapi::PPB_VideoDecoder_Shared, // This is NULL before initialization, and if this PPB_VideoDecoder_Impl is // swapped with another. - scoped_refptr<PluginDelegate::PlatformVideoDecoder> platform_video_decoder_; + scoped_ptr<PluginDelegate::PlatformVideoDecoder> platform_video_decoder_; // Reference to the plugin requesting this interface. const PPP_VideoDecoder_Dev* ppp_videodecoder_; |