Chromium Code Reviews| 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 |