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 32e6b6776a3f2f2527aba968cb847396a5239deb..b105536c41aeeb4eedbb4dcf5a91843caa63aa23 100644 |
--- a/content/common/gpu/media/gpu_video_decode_accelerator.cc |
+++ b/content/common/gpu/media/gpu_video_decode_accelerator.cc |
@@ -132,6 +132,7 @@ GpuVideoDecodeAccelerator::GpuVideoDecodeAccelerator( |
host_route_id_(host_route_id), |
stub_(stub), |
texture_target_(0), |
+ filter_removed_(true, false), |
Pawel Osciak
2013/12/24 03:45:24
Please rebase.
|
io_message_loop_(io_message_loop), |
weak_factory_for_io_(this) { |
DCHECK(stub_); |
@@ -143,14 +144,15 @@ GpuVideoDecodeAccelerator::GpuVideoDecodeAccelerator( |
} |
GpuVideoDecodeAccelerator::~GpuVideoDecodeAccelerator() { |
- if (video_decode_accelerator_) |
- video_decode_accelerator_.release()->Destroy(); |
+ // This class can only be self-deleted from OnWillDestroyStub(), which means |
+ // the VDA has already been destroyed in there. |
+ CHECK(!video_decode_accelerator_.get()); |
} |
bool GpuVideoDecodeAccelerator::OnMessageReceived(const IPC::Message& msg) { |
- DCHECK(stub_); |
if (!video_decode_accelerator_) |
return false; |
+ |
bool handled = true; |
IPC_BEGIN_MESSAGE_MAP(GpuVideoDecodeAccelerator, msg) |
IPC_MESSAGE_HANDLER(AcceleratedVideoDecoderMsg_Decode, OnDecode) |
@@ -245,7 +247,6 @@ void GpuVideoDecodeAccelerator::NotifyError( |
void GpuVideoDecodeAccelerator::Initialize( |
const media::VideoCodecProfile profile, |
IPC::Message* init_done_msg) { |
- DCHECK(stub_); |
DCHECK(!video_decode_accelerator_.get()); |
DCHECK(!init_done_msg_); |
DCHECK(init_done_msg); |
@@ -270,9 +271,8 @@ void GpuVideoDecodeAccelerator::Initialize( |
video_decode_accelerator_.reset(new DXVAVideoDecodeAccelerator( |
this, make_context_current_)); |
#elif defined(OS_CHROMEOS) && defined(ARCH_CPU_ARMEL) && defined(USE_X11) |
- video_decode_accelerator_.reset(new ExynosVideoDecodeAccelerator( |
+ video_decode_accelerator_.reset(new V4L2VideoDecodeAccelerator( |
gfx::GLSurfaceEGL::GetHardwareDisplay(), |
- stub_->decoder()->GetGLContext()->GetHandle(), |
this, |
weak_factory_for_io_.GetWeakPtr(), |
make_context_current_, |
@@ -280,11 +280,8 @@ void GpuVideoDecodeAccelerator::Initialize( |
#elif defined(OS_CHROMEOS) && defined(ARCH_CPU_X86_FAMILY) && defined(USE_X11) |
gfx::GLContextGLX* glx_context = |
static_cast<gfx::GLContextGLX*>(stub_->decoder()->GetGLContext()); |
- GLXContext glx_context_handle = |
- static_cast<GLXContext>(glx_context->GetHandle()); |
video_decode_accelerator_.reset(new VaapiVideoDecodeAccelerator( |
- glx_context->display(), glx_context_handle, this, |
- make_context_current_)); |
+ glx_context->display(), this, make_context_current_)); |
#elif defined(OS_ANDROID) |
video_decode_accelerator_.reset(new AndroidVideoDecodeAccelerator( |
this, |
@@ -329,7 +326,6 @@ void GpuVideoDecodeAccelerator::OnDecode( |
void GpuVideoDecodeAccelerator::OnAssignPictureBuffers( |
const std::vector<int32>& buffer_ids, |
const std::vector<uint32>& texture_ids) { |
- DCHECK(stub_); |
if (buffer_ids.size() != texture_ids.size()) { |
NotifyError(media::VideoDecodeAccelerator::INVALID_ARGUMENT); |
return; |
@@ -427,7 +423,7 @@ void GpuVideoDecodeAccelerator::OnDestroy() { |
void GpuVideoDecodeAccelerator::OnFilterRemoved() { |
// We're destroying; cancel all callbacks. |
weak_factory_for_io_.InvalidateWeakPtrs(); |
- child_message_loop_->DeleteSoon(FROM_HERE, this); |
+ filter_removed_.Signal(); |
} |
void GpuVideoDecodeAccelerator::NotifyEndOfBitstreamBuffer( |
@@ -459,24 +455,29 @@ void GpuVideoDecodeAccelerator::NotifyResetDone() { |
} |
void GpuVideoDecodeAccelerator::OnWillDestroyStub() { |
- DCHECK(stub_); |
- stub_->channel()->RemoveRoute(host_route_id_); |
- stub_->RemoveDestructionObserver(this); |
- { |
- DebugAutoLock auto_lock(debug_uncleared_textures_lock_); |
- uncleared_textures_.clear(); |
- } |
+ // The stub is going away, so we have to stop and destroy VDA here, before |
+ // returning, because the VDA may need the GL context to run and/or do its |
+ // cleanup. We cannot destroy the VDA before the IO thread message filter is |
+ // removed however, since we cannot service incoming messages with VDA gone. |
+ // We cannot simply check for existence of VDA on IO thread though, because |
+ // we don't want to synchronize the IO thread with the ChildThread. |
+ // So we have to wait for the RemoveFilter callback here instead and remove |
+ // the VDA after it arrives and before returning. |
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; |
+ filter_removed_.Wait(); |
} |
+ |
+ stub_->channel()->RemoveRoute(host_route_id_); |
+ stub_->RemoveDestructionObserver(this); |
+ |
+ if (video_decode_accelerator_) |
+ video_decode_accelerator_.release()->Destroy(); |
+ |
+ delete this; |
} |
bool GpuVideoDecodeAccelerator::Send(IPC::Message* message) { |
- DCHECK(stub_); |
if (filter_.get() && io_message_loop_->BelongsToCurrentThread()) |
return filter_->SendOnIOThread(message); |
DCHECK(child_message_loop_->BelongsToCurrentThread()); |