OLD | NEW |
---|---|
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "content/common/gpu/media/gpu_video_decode_accelerator.h" | 5 #include "content/common/gpu/media/gpu_video_decode_accelerator.h" |
6 | 6 |
7 #include <vector> | 7 #include <vector> |
8 | 8 |
9 #include "base/bind.h" | 9 #include "base/bind.h" |
10 #include "base/command_line.h" | 10 #include "base/command_line.h" |
(...skipping 114 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
125 }; | 125 }; |
126 | 126 |
127 GpuVideoDecodeAccelerator::GpuVideoDecodeAccelerator( | 127 GpuVideoDecodeAccelerator::GpuVideoDecodeAccelerator( |
128 int32 host_route_id, | 128 int32 host_route_id, |
129 GpuCommandBufferStub* stub, | 129 GpuCommandBufferStub* stub, |
130 const scoped_refptr<base::MessageLoopProxy>& io_message_loop) | 130 const scoped_refptr<base::MessageLoopProxy>& io_message_loop) |
131 : init_done_msg_(NULL), | 131 : init_done_msg_(NULL), |
132 host_route_id_(host_route_id), | 132 host_route_id_(host_route_id), |
133 stub_(stub), | 133 stub_(stub), |
134 texture_target_(0), | 134 texture_target_(0), |
135 filter_removed_(true, false), | |
Pawel Osciak
2013/12/24 03:45:24
Please rebase.
| |
135 io_message_loop_(io_message_loop), | 136 io_message_loop_(io_message_loop), |
136 weak_factory_for_io_(this) { | 137 weak_factory_for_io_(this) { |
137 DCHECK(stub_); | 138 DCHECK(stub_); |
138 stub_->AddDestructionObserver(this); | 139 stub_->AddDestructionObserver(this); |
139 stub_->channel()->AddRoute(host_route_id_, this); | 140 stub_->channel()->AddRoute(host_route_id_, this); |
140 child_message_loop_ = base::MessageLoopProxy::current(); | 141 child_message_loop_ = base::MessageLoopProxy::current(); |
141 make_context_current_ = | 142 make_context_current_ = |
142 base::Bind(&MakeDecoderContextCurrent, stub_->AsWeakPtr()); | 143 base::Bind(&MakeDecoderContextCurrent, stub_->AsWeakPtr()); |
143 } | 144 } |
144 | 145 |
145 GpuVideoDecodeAccelerator::~GpuVideoDecodeAccelerator() { | 146 GpuVideoDecodeAccelerator::~GpuVideoDecodeAccelerator() { |
146 if (video_decode_accelerator_) | 147 // This class can only be self-deleted from OnWillDestroyStub(), which means |
147 video_decode_accelerator_.release()->Destroy(); | 148 // the VDA has already been destroyed in there. |
149 CHECK(!video_decode_accelerator_.get()); | |
148 } | 150 } |
149 | 151 |
150 bool GpuVideoDecodeAccelerator::OnMessageReceived(const IPC::Message& msg) { | 152 bool GpuVideoDecodeAccelerator::OnMessageReceived(const IPC::Message& msg) { |
151 DCHECK(stub_); | |
152 if (!video_decode_accelerator_) | 153 if (!video_decode_accelerator_) |
153 return false; | 154 return false; |
155 | |
154 bool handled = true; | 156 bool handled = true; |
155 IPC_BEGIN_MESSAGE_MAP(GpuVideoDecodeAccelerator, msg) | 157 IPC_BEGIN_MESSAGE_MAP(GpuVideoDecodeAccelerator, msg) |
156 IPC_MESSAGE_HANDLER(AcceleratedVideoDecoderMsg_Decode, OnDecode) | 158 IPC_MESSAGE_HANDLER(AcceleratedVideoDecoderMsg_Decode, OnDecode) |
157 IPC_MESSAGE_HANDLER(AcceleratedVideoDecoderMsg_AssignPictureBuffers, | 159 IPC_MESSAGE_HANDLER(AcceleratedVideoDecoderMsg_AssignPictureBuffers, |
158 OnAssignPictureBuffers) | 160 OnAssignPictureBuffers) |
159 IPC_MESSAGE_HANDLER(AcceleratedVideoDecoderMsg_ReusePictureBuffer, | 161 IPC_MESSAGE_HANDLER(AcceleratedVideoDecoderMsg_ReusePictureBuffer, |
160 OnReusePictureBuffer) | 162 OnReusePictureBuffer) |
161 IPC_MESSAGE_HANDLER(AcceleratedVideoDecoderMsg_Flush, OnFlush) | 163 IPC_MESSAGE_HANDLER(AcceleratedVideoDecoderMsg_Flush, OnFlush) |
162 IPC_MESSAGE_HANDLER(AcceleratedVideoDecoderMsg_Reset, OnReset) | 164 IPC_MESSAGE_HANDLER(AcceleratedVideoDecoderMsg_Reset, OnReset) |
163 IPC_MESSAGE_HANDLER(AcceleratedVideoDecoderMsg_Destroy, OnDestroy) | 165 IPC_MESSAGE_HANDLER(AcceleratedVideoDecoderMsg_Destroy, OnDestroy) |
(...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
238 if (!Send(new AcceleratedVideoDecoderHostMsg_ErrorNotification( | 240 if (!Send(new AcceleratedVideoDecoderHostMsg_ErrorNotification( |
239 host_route_id_, error))) { | 241 host_route_id_, error))) { |
240 DLOG(ERROR) << "Send(AcceleratedVideoDecoderHostMsg_ErrorNotification) " | 242 DLOG(ERROR) << "Send(AcceleratedVideoDecoderHostMsg_ErrorNotification) " |
241 << "failed"; | 243 << "failed"; |
242 } | 244 } |
243 } | 245 } |
244 | 246 |
245 void GpuVideoDecodeAccelerator::Initialize( | 247 void GpuVideoDecodeAccelerator::Initialize( |
246 const media::VideoCodecProfile profile, | 248 const media::VideoCodecProfile profile, |
247 IPC::Message* init_done_msg) { | 249 IPC::Message* init_done_msg) { |
248 DCHECK(stub_); | |
249 DCHECK(!video_decode_accelerator_.get()); | 250 DCHECK(!video_decode_accelerator_.get()); |
250 DCHECK(!init_done_msg_); | 251 DCHECK(!init_done_msg_); |
251 DCHECK(init_done_msg); | 252 DCHECK(init_done_msg); |
252 init_done_msg_ = init_done_msg; | 253 init_done_msg_ = init_done_msg; |
253 | 254 |
254 #if !defined(OS_WIN) | 255 #if !defined(OS_WIN) |
255 // Ensure we will be able to get a GL context at all before initializing | 256 // Ensure we will be able to get a GL context at all before initializing |
256 // non-Windows VDAs. | 257 // non-Windows VDAs. |
257 if (!make_context_current_.Run()) { | 258 if (!make_context_current_.Run()) { |
258 NotifyError(media::VideoDecodeAccelerator::PLATFORM_FAILURE); | 259 NotifyError(media::VideoDecodeAccelerator::PLATFORM_FAILURE); |
259 return; | 260 return; |
260 } | 261 } |
261 #endif | 262 #endif |
262 | 263 |
263 #if defined(OS_WIN) | 264 #if defined(OS_WIN) |
264 if (base::win::GetVersion() < base::win::VERSION_WIN7) { | 265 if (base::win::GetVersion() < base::win::VERSION_WIN7) { |
265 NOTIMPLEMENTED() << "HW video decode acceleration not available."; | 266 NOTIMPLEMENTED() << "HW video decode acceleration not available."; |
266 NotifyError(media::VideoDecodeAccelerator::PLATFORM_FAILURE); | 267 NotifyError(media::VideoDecodeAccelerator::PLATFORM_FAILURE); |
267 return; | 268 return; |
268 } | 269 } |
269 DVLOG(0) << "Initializing DXVA HW decoder for windows."; | 270 DVLOG(0) << "Initializing DXVA HW decoder for windows."; |
270 video_decode_accelerator_.reset(new DXVAVideoDecodeAccelerator( | 271 video_decode_accelerator_.reset(new DXVAVideoDecodeAccelerator( |
271 this, make_context_current_)); | 272 this, make_context_current_)); |
272 #elif defined(OS_CHROMEOS) && defined(ARCH_CPU_ARMEL) && defined(USE_X11) | 273 #elif defined(OS_CHROMEOS) && defined(ARCH_CPU_ARMEL) && defined(USE_X11) |
273 video_decode_accelerator_.reset(new ExynosVideoDecodeAccelerator( | 274 video_decode_accelerator_.reset(new V4L2VideoDecodeAccelerator( |
274 gfx::GLSurfaceEGL::GetHardwareDisplay(), | 275 gfx::GLSurfaceEGL::GetHardwareDisplay(), |
275 stub_->decoder()->GetGLContext()->GetHandle(), | |
276 this, | 276 this, |
277 weak_factory_for_io_.GetWeakPtr(), | 277 weak_factory_for_io_.GetWeakPtr(), |
278 make_context_current_, | 278 make_context_current_, |
279 io_message_loop_)); | 279 io_message_loop_)); |
280 #elif defined(OS_CHROMEOS) && defined(ARCH_CPU_X86_FAMILY) && defined(USE_X11) | 280 #elif defined(OS_CHROMEOS) && defined(ARCH_CPU_X86_FAMILY) && defined(USE_X11) |
281 gfx::GLContextGLX* glx_context = | 281 gfx::GLContextGLX* glx_context = |
282 static_cast<gfx::GLContextGLX*>(stub_->decoder()->GetGLContext()); | 282 static_cast<gfx::GLContextGLX*>(stub_->decoder()->GetGLContext()); |
283 GLXContext glx_context_handle = | |
284 static_cast<GLXContext>(glx_context->GetHandle()); | |
285 video_decode_accelerator_.reset(new VaapiVideoDecodeAccelerator( | 283 video_decode_accelerator_.reset(new VaapiVideoDecodeAccelerator( |
286 glx_context->display(), glx_context_handle, this, | 284 glx_context->display(), this, make_context_current_)); |
287 make_context_current_)); | |
288 #elif defined(OS_ANDROID) | 285 #elif defined(OS_ANDROID) |
289 video_decode_accelerator_.reset(new AndroidVideoDecodeAccelerator( | 286 video_decode_accelerator_.reset(new AndroidVideoDecodeAccelerator( |
290 this, | 287 this, |
291 stub_->decoder()->AsWeakPtr(), | 288 stub_->decoder()->AsWeakPtr(), |
292 make_context_current_)); | 289 make_context_current_)); |
293 #else | 290 #else |
294 NOTIMPLEMENTED() << "HW video decode acceleration not available."; | 291 NOTIMPLEMENTED() << "HW video decode acceleration not available."; |
295 NotifyError(media::VideoDecodeAccelerator::PLATFORM_FAILURE); | 292 NotifyError(media::VideoDecodeAccelerator::PLATFORM_FAILURE); |
296 return; | 293 return; |
297 #endif | 294 #endif |
(...skipping 24 matching lines...) Expand all Loading... | |
322 media::VideoDecodeAccelerator::INVALID_ARGUMENT)); | 319 media::VideoDecodeAccelerator::INVALID_ARGUMENT)); |
323 } | 320 } |
324 return; | 321 return; |
325 } | 322 } |
326 video_decode_accelerator_->Decode(media::BitstreamBuffer(id, handle, size)); | 323 video_decode_accelerator_->Decode(media::BitstreamBuffer(id, handle, size)); |
327 } | 324 } |
328 | 325 |
329 void GpuVideoDecodeAccelerator::OnAssignPictureBuffers( | 326 void GpuVideoDecodeAccelerator::OnAssignPictureBuffers( |
330 const std::vector<int32>& buffer_ids, | 327 const std::vector<int32>& buffer_ids, |
331 const std::vector<uint32>& texture_ids) { | 328 const std::vector<uint32>& texture_ids) { |
332 DCHECK(stub_); | |
333 if (buffer_ids.size() != texture_ids.size()) { | 329 if (buffer_ids.size() != texture_ids.size()) { |
334 NotifyError(media::VideoDecodeAccelerator::INVALID_ARGUMENT); | 330 NotifyError(media::VideoDecodeAccelerator::INVALID_ARGUMENT); |
335 return; | 331 return; |
336 } | 332 } |
337 | 333 |
338 gpu::gles2::GLES2Decoder* command_decoder = stub_->decoder(); | 334 gpu::gles2::GLES2Decoder* command_decoder = stub_->decoder(); |
339 gpu::gles2::TextureManager* texture_manager = | 335 gpu::gles2::TextureManager* texture_manager = |
340 command_decoder->GetContextGroup()->texture_manager(); | 336 command_decoder->GetContextGroup()->texture_manager(); |
341 | 337 |
342 std::vector<media::PictureBuffer> buffers; | 338 std::vector<media::PictureBuffer> buffers; |
(...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
420 } | 416 } |
421 | 417 |
422 void GpuVideoDecodeAccelerator::OnDestroy() { | 418 void GpuVideoDecodeAccelerator::OnDestroy() { |
423 DCHECK(video_decode_accelerator_.get()); | 419 DCHECK(video_decode_accelerator_.get()); |
424 OnWillDestroyStub(); | 420 OnWillDestroyStub(); |
425 } | 421 } |
426 | 422 |
427 void GpuVideoDecodeAccelerator::OnFilterRemoved() { | 423 void GpuVideoDecodeAccelerator::OnFilterRemoved() { |
428 // We're destroying; cancel all callbacks. | 424 // We're destroying; cancel all callbacks. |
429 weak_factory_for_io_.InvalidateWeakPtrs(); | 425 weak_factory_for_io_.InvalidateWeakPtrs(); |
430 child_message_loop_->DeleteSoon(FROM_HERE, this); | 426 filter_removed_.Signal(); |
431 } | 427 } |
432 | 428 |
433 void GpuVideoDecodeAccelerator::NotifyEndOfBitstreamBuffer( | 429 void GpuVideoDecodeAccelerator::NotifyEndOfBitstreamBuffer( |
434 int32 bitstream_buffer_id) { | 430 int32 bitstream_buffer_id) { |
435 if (!Send(new AcceleratedVideoDecoderHostMsg_BitstreamBufferProcessed( | 431 if (!Send(new AcceleratedVideoDecoderHostMsg_BitstreamBufferProcessed( |
436 host_route_id_, bitstream_buffer_id))) { | 432 host_route_id_, bitstream_buffer_id))) { |
437 DLOG(ERROR) | 433 DLOG(ERROR) |
438 << "Send(AcceleratedVideoDecoderHostMsg_BitstreamBufferProcessed) " | 434 << "Send(AcceleratedVideoDecoderHostMsg_BitstreamBufferProcessed) " |
439 << "failed"; | 435 << "failed"; |
440 } | 436 } |
(...skipping 11 matching lines...) Expand all Loading... | |
452 if (!Send(new AcceleratedVideoDecoderHostMsg_FlushDone(host_route_id_))) | 448 if (!Send(new AcceleratedVideoDecoderHostMsg_FlushDone(host_route_id_))) |
453 DLOG(ERROR) << "Send(AcceleratedVideoDecoderHostMsg_FlushDone) failed"; | 449 DLOG(ERROR) << "Send(AcceleratedVideoDecoderHostMsg_FlushDone) failed"; |
454 } | 450 } |
455 | 451 |
456 void GpuVideoDecodeAccelerator::NotifyResetDone() { | 452 void GpuVideoDecodeAccelerator::NotifyResetDone() { |
457 if (!Send(new AcceleratedVideoDecoderHostMsg_ResetDone(host_route_id_))) | 453 if (!Send(new AcceleratedVideoDecoderHostMsg_ResetDone(host_route_id_))) |
458 DLOG(ERROR) << "Send(AcceleratedVideoDecoderHostMsg_ResetDone) failed"; | 454 DLOG(ERROR) << "Send(AcceleratedVideoDecoderHostMsg_ResetDone) failed"; |
459 } | 455 } |
460 | 456 |
461 void GpuVideoDecodeAccelerator::OnWillDestroyStub() { | 457 void GpuVideoDecodeAccelerator::OnWillDestroyStub() { |
462 DCHECK(stub_); | 458 // The stub is going away, so we have to stop and destroy VDA here, before |
459 // returning, because the VDA may need the GL context to run and/or do its | |
460 // cleanup. We cannot destroy the VDA before the IO thread message filter is | |
461 // removed however, since we cannot service incoming messages with VDA gone. | |
462 // We cannot simply check for existence of VDA on IO thread though, because | |
463 // we don't want to synchronize the IO thread with the ChildThread. | |
464 // So we have to wait for the RemoveFilter callback here instead and remove | |
465 // the VDA after it arrives and before returning. | |
466 if (filter_.get()) { | |
467 stub_->channel()->RemoveFilter(filter_.get()); | |
468 filter_removed_.Wait(); | |
469 } | |
470 | |
463 stub_->channel()->RemoveRoute(host_route_id_); | 471 stub_->channel()->RemoveRoute(host_route_id_); |
464 stub_->RemoveDestructionObserver(this); | 472 stub_->RemoveDestructionObserver(this); |
465 { | 473 |
466 DebugAutoLock auto_lock(debug_uncleared_textures_lock_); | 474 if (video_decode_accelerator_) |
467 uncleared_textures_.clear(); | 475 video_decode_accelerator_.release()->Destroy(); |
468 } | 476 |
469 if (filter_.get()) { | 477 delete this; |
470 // Remove the filter first because the member variables can be accessed on | |
471 // IO thread. When filter is removed, OnFilterRemoved will delete |this|. | |
472 stub_->channel()->RemoveFilter(filter_.get()); | |
473 } else { | |
474 delete this; | |
475 } | |
476 } | 478 } |
477 | 479 |
478 bool GpuVideoDecodeAccelerator::Send(IPC::Message* message) { | 480 bool GpuVideoDecodeAccelerator::Send(IPC::Message* message) { |
479 DCHECK(stub_); | |
480 if (filter_.get() && io_message_loop_->BelongsToCurrentThread()) | 481 if (filter_.get() && io_message_loop_->BelongsToCurrentThread()) |
481 return filter_->SendOnIOThread(message); | 482 return filter_->SendOnIOThread(message); |
482 DCHECK(child_message_loop_->BelongsToCurrentThread()); | 483 DCHECK(child_message_loop_->BelongsToCurrentThread()); |
483 return stub_->channel()->Send(message); | 484 return stub_->channel()->Send(message); |
484 } | 485 } |
485 | 486 |
486 void GpuVideoDecodeAccelerator::SetTextureCleared( | 487 void GpuVideoDecodeAccelerator::SetTextureCleared( |
487 const media::Picture& picture) { | 488 const media::Picture& picture) { |
488 DCHECK(child_message_loop_->BelongsToCurrentThread()); | 489 DCHECK(child_message_loop_->BelongsToCurrentThread()); |
489 DebugAutoLock auto_lock(debug_uncleared_textures_lock_); | 490 DebugAutoLock auto_lock(debug_uncleared_textures_lock_); |
490 std::map<int32, scoped_refptr<gpu::gles2::TextureRef> >::iterator it; | 491 std::map<int32, scoped_refptr<gpu::gles2::TextureRef> >::iterator it; |
491 it = uncleared_textures_.find(picture.picture_buffer_id()); | 492 it = uncleared_textures_.find(picture.picture_buffer_id()); |
492 if (it == uncleared_textures_.end()) | 493 if (it == uncleared_textures_.end()) |
493 return; // the texture has been cleared | 494 return; // the texture has been cleared |
494 | 495 |
495 scoped_refptr<gpu::gles2::TextureRef> texture_ref = it->second; | 496 scoped_refptr<gpu::gles2::TextureRef> texture_ref = it->second; |
496 GLenum target = texture_ref->texture()->target(); | 497 GLenum target = texture_ref->texture()->target(); |
497 gpu::gles2::TextureManager* texture_manager = | 498 gpu::gles2::TextureManager* texture_manager = |
498 stub_->decoder()->GetContextGroup()->texture_manager(); | 499 stub_->decoder()->GetContextGroup()->texture_manager(); |
499 DCHECK(!texture_ref->texture()->IsLevelCleared(target, 0)); | 500 DCHECK(!texture_ref->texture()->IsLevelCleared(target, 0)); |
500 texture_manager->SetLevelCleared(texture_ref, target, 0, true); | 501 texture_manager->SetLevelCleared(texture_ref, target, 0, true); |
501 uncleared_textures_.erase(it); | 502 uncleared_textures_.erase(it); |
502 } | 503 } |
503 | 504 |
504 } // namespace content | 505 } // namespace content |
OLD | NEW |