Index: content/common/gpu/media/gpu_video_decode_accelerator.cc |
diff --git a/content/common/gpu/media/gpu_video_decode_accelerator.cc b/content/common/gpu/media/gpu_video_decode_accelerator.cc |
index 2b0bb848b69fba9b2acf8d68839441932af28917..a1062e3c106777dd728d2af897282434e117b29d 100644 |
--- a/content/common/gpu/media/gpu_video_decode_accelerator.cc |
+++ b/content/common/gpu/media/gpu_video_decode_accelerator.cc |
@@ -9,6 +9,7 @@ |
#include "base/bind.h" |
#include "base/command_line.h" |
#include "base/logging.h" |
+#include "base/message_loop/message_loop_proxy.h" |
#include "base/stl_util.h" |
#include "content/common/gpu/gpu_channel.h" |
@@ -54,6 +55,36 @@ static bool MakeDecoderContextCurrent( |
return true; |
} |
+class GpuVideoDecodeAccelerator::MessageFilter |
+ : public IPC::ChannelProxy::MessageFilter { |
+ public: |
+ MessageFilter(GpuVideoDecodeAccelerator* owner, int32 host_route_id) |
+ : owner_(owner), host_route_id_(host_route_id) {} |
+ |
+ virtual void OnFilterRemoved() OVERRIDE { |
+ // This will delete |owner_| and |this|. |
+ owner_->OnFilterRemoved(); |
+ } |
+ virtual bool OnMessageReceived(const IPC::Message& msg) OVERRIDE { |
+ if (msg.routing_id() != host_route_id_) |
+ return false; |
+ |
+ IPC_BEGIN_MESSAGE_MAP(MessageFilter, msg) |
+ IPC_MESSAGE_FORWARD(AcceleratedVideoDecoderMsg_Decode, owner_, |
+ GpuVideoDecodeAccelerator::OnDecode) |
+ IPC_MESSAGE_UNHANDLED(return false;) |
+ IPC_END_MESSAGE_MAP() |
+ return true; |
+ } |
+ |
+ protected: |
+ virtual ~MessageFilter() {} |
+ |
+ private: |
+ GpuVideoDecodeAccelerator* owner_; |
+ int32 host_route_id_; |
+}; |
+ |
GpuVideoDecodeAccelerator::GpuVideoDecodeAccelerator(int32 host_route_id, |
GpuCommandBufferStub* stub) |
: init_done_msg_(NULL), |
@@ -63,17 +94,14 @@ GpuVideoDecodeAccelerator::GpuVideoDecodeAccelerator(int32 host_route_id, |
DCHECK(stub_); |
stub_->AddDestructionObserver(this); |
stub_->channel()->AddRoute(host_route_id_, this); |
+ child_message_loop_ = base::MessageLoopProxy::current(); |
make_context_current_ = |
base::Bind(&MakeDecoderContextCurrent, stub_->AsWeakPtr()); |
} |
GpuVideoDecodeAccelerator::~GpuVideoDecodeAccelerator() { |
- DCHECK(stub_); |
if (video_decode_accelerator_) |
video_decode_accelerator_.release()->Destroy(); |
- |
- stub_->channel()->RemoveRoute(host_route_id_); |
- stub_->RemoveDestructionObserver(this); |
} |
bool GpuVideoDecodeAccelerator::OnMessageReceived(const IPC::Message& msg) { |
@@ -149,7 +177,8 @@ void GpuVideoDecodeAccelerator::NotifyError( |
void GpuVideoDecodeAccelerator::Initialize( |
const media::VideoCodecProfile profile, |
- IPC::Message* init_done_msg) { |
+ IPC::Message* init_done_msg, |
+ const scoped_refptr<base::MessageLoopProxy>& io_message_loop) { |
DCHECK(stub_); |
DCHECK(!video_decode_accelerator_.get()); |
DCHECK(!init_done_msg_); |
@@ -179,7 +208,8 @@ void GpuVideoDecodeAccelerator::Initialize( |
gfx::GLSurfaceEGL::GetHardwareDisplay(), |
stub_->decoder()->GetGLContext()->GetHandle(), |
this, |
- make_context_current_)); |
+ make_context_current_, |
+ io_message_loop)); |
#elif defined(OS_CHROMEOS) && defined(ARCH_CPU_X86_FAMILY) && defined(USE_X11) |
gfx::GLContextGLX* glx_context = |
static_cast<gfx::GLContextGLX*>(stub_->decoder()->GetGLContext()); |
@@ -199,16 +229,31 @@ void GpuVideoDecodeAccelerator::Initialize( |
return; |
#endif |
+ if (video_decode_accelerator_->CanDecodeOnIOThread()) { |
+ filter_ = new MessageFilter(this, host_route_id_); |
+ stub_->channel()->AddFilter(filter_.get()); |
+ } |
+ |
if (!video_decode_accelerator_->Initialize(profile)) |
NotifyError(media::VideoDecodeAccelerator::PLATFORM_FAILURE); |
} |
+// Runs on IO thread if video_decode_accelerator_->CanDecodeOnIOThread() is |
+// true, otherwise on the main thread. |
void GpuVideoDecodeAccelerator::OnDecode( |
base::SharedMemoryHandle handle, int32 id, uint32 size) { |
DCHECK(video_decode_accelerator_.get()); |
if (id < 0) { |
DLOG(FATAL) << "BitstreamBuffer id " << id << " out of range"; |
- NotifyError(media::VideoDecodeAccelerator::INVALID_ARGUMENT); |
+ if (child_message_loop_->BelongsToCurrentThread()) { |
+ NotifyError(media::VideoDecodeAccelerator::INVALID_ARGUMENT); |
+ } else { |
+ child_message_loop_->PostTask( |
+ FROM_HERE, |
+ base::Bind(&GpuVideoDecodeAccelerator::NotifyError, |
+ base::Unretained(this), |
+ media::VideoDecodeAccelerator::INVALID_ARGUMENT)); |
+ } |
return; |
} |
video_decode_accelerator_->Decode(media::BitstreamBuffer(id, handle, size)); |
@@ -297,7 +342,20 @@ void GpuVideoDecodeAccelerator::OnReset() { |
void GpuVideoDecodeAccelerator::OnDestroy() { |
DCHECK(video_decode_accelerator_.get()); |
- delete this; |
+ DCHECK(stub_); |
+ stub_->channel()->RemoveRoute(host_route_id_); |
+ stub_->RemoveDestructionObserver(this); |
+ if (filter_.get()) { |
+ // Remove the filter first because the member variables can be accessed on |
+ // IO thread. When filter is removed, OnFilterRemoved will delete |this|. |
+ stub_->channel()->RemoveFilter(filter_.get()); |
+ } else { |
+ delete this; |
+ } |
+} |
+ |
+void GpuVideoDecodeAccelerator::OnFilterRemoved() { |
+ child_message_loop_->DeleteSoon(FROM_HERE, this); |
} |
void GpuVideoDecodeAccelerator::NotifyEndOfBitstreamBuffer( |
@@ -328,9 +386,7 @@ void GpuVideoDecodeAccelerator::NotifyResetDone() { |
DLOG(ERROR) << "Send(AcceleratedVideoDecoderHostMsg_ResetDone) failed"; |
} |
-void GpuVideoDecodeAccelerator::OnWillDestroyStub() { |
- delete this; |
-} |
+void GpuVideoDecodeAccelerator::OnWillDestroyStub() { OnDestroy(); } |
bool GpuVideoDecodeAccelerator::Send(IPC::Message* message) { |
DCHECK(stub_); |