Index: content/renderer/media/renderer_gpu_video_accelerator_factories.cc |
diff --git a/content/renderer/media/renderer_gpu_video_accelerator_factories.cc b/content/renderer/media/renderer_gpu_video_accelerator_factories.cc |
index 4ecd4218fbf33416536029e024b8cedf40ee2730..34c1e2d665dc6222889ca4dccffe17e88ff35eb6 100644 |
--- a/content/renderer/media/renderer_gpu_video_accelerator_factories.cc |
+++ b/content/renderer/media/renderer_gpu_video_accelerator_factories.cc |
@@ -14,7 +14,6 @@ |
#include "content/common/gpu/client/webgraphicscontext3d_command_buffer_impl.h" |
#include "content/renderer/render_thread_impl.h" |
#include "gpu/command_buffer/client/gles2_implementation.h" |
-#include "third_party/skia/include/core/SkBitmap.h" |
#include "third_party/skia/include/core/SkPixelRef.h" |
namespace content { |
@@ -22,12 +21,37 @@ |
RendererGpuVideoAcceleratorFactories::~RendererGpuVideoAcceleratorFactories() {} |
RendererGpuVideoAcceleratorFactories::RendererGpuVideoAcceleratorFactories( |
GpuChannelHost* gpu_channel_host, |
- const scoped_refptr<base::MessageLoopProxy>& message_loop_proxy, |
const scoped_refptr<ContextProviderCommandBuffer>& context_provider) |
- : task_runner_(message_loop_proxy), |
+ : task_runner_( |
+ RenderThreadImpl::current()->GetMediaThreadMessageLoopProxy()), |
gpu_channel_host_(gpu_channel_host), |
context_provider_(context_provider), |
- thread_safe_sender_(ChildThread::current()->thread_safe_sender()) {} |
+ thread_safe_sender_(ChildThread::current()->thread_safe_sender()), |
+ aborted_waiter_(true, false), |
+ task_runner_async_waiter_(false, false) { |
+ // |context_provider_| is only required to support HW-accelerated decode. |
+ if (!context_provider_) |
+ return; |
+ |
+ if (task_runner_->BelongsToCurrentThread()) { |
+ AsyncBindContext(); |
+ task_runner_async_waiter_.Reset(); |
+ return; |
+ } |
+ // Wait for the context to be acquired. |
+ task_runner_->PostTask( |
+ FROM_HERE, |
+ base::Bind(&RendererGpuVideoAcceleratorFactories::AsyncBindContext, |
+ // Unretained to avoid ref/deref'ing |*this|, which is not yet |
+ // stored in a scoped_refptr. Safe because the Wait() below |
+ // keeps us alive until this task completes. |
+ base::Unretained(this))); |
+ task_runner_async_waiter_.Wait(); |
+} |
+ |
+RendererGpuVideoAcceleratorFactories::RendererGpuVideoAcceleratorFactories() |
+ : aborted_waiter_(true, false), |
+ task_runner_async_waiter_(false, false) {} |
WebGraphicsContext3DCommandBufferImpl* |
RendererGpuVideoAcceleratorFactories::GetContext3d() { |
@@ -42,19 +66,44 @@ |
return context_provider_->WebContext3D(); |
} |
+void RendererGpuVideoAcceleratorFactories::AsyncBindContext() { |
+ DCHECK(task_runner_->BelongsToCurrentThread()); |
+ if (!context_provider_->BindToCurrentThread()) |
+ context_provider_ = NULL; |
+ task_runner_async_waiter_.Signal(); |
+} |
+ |
scoped_ptr<media::VideoDecodeAccelerator> |
RendererGpuVideoAcceleratorFactories::CreateVideoDecodeAccelerator( |
media::VideoCodecProfile profile, |
media::VideoDecodeAccelerator::Client* client) { |
- DCHECK(task_runner_->BelongsToCurrentThread()); |
- |
- WebGraphicsContext3DCommandBufferImpl* context = GetContext3d(); |
- if (context && context->GetCommandBufferProxy()) { |
- return gpu_channel_host_->CreateVideoDecoder( |
- context->GetCommandBufferProxy()->GetRouteID(), profile, client); |
- } |
- |
- return scoped_ptr<media::VideoDecodeAccelerator>(); |
+ if (task_runner_->BelongsToCurrentThread()) { |
+ AsyncCreateVideoDecodeAccelerator(profile, client); |
+ task_runner_async_waiter_.Reset(); |
+ return vda_.Pass(); |
+ } |
+ // The VDA is returned in the vda_ member variable by the |
+ // AsyncCreateVideoDecodeAccelerator() function. |
+ task_runner_->PostTask(FROM_HERE, |
+ base::Bind(&RendererGpuVideoAcceleratorFactories:: |
+ AsyncCreateVideoDecodeAccelerator, |
+ this, |
+ profile, |
+ client)); |
+ |
+ base::WaitableEvent* objects[] = {&aborted_waiter_, |
+ &task_runner_async_waiter_}; |
+ if (base::WaitableEvent::WaitMany(objects, arraysize(objects)) == 0) { |
+ // If we are aborting and the VDA is created by the |
+ // AsyncCreateVideoDecodeAccelerator() function later we need to ensure |
+ // that it is destroyed on the same thread. |
+ task_runner_->PostTask(FROM_HERE, |
+ base::Bind(&RendererGpuVideoAcceleratorFactories:: |
+ AsyncDestroyVideoDecodeAccelerator, |
+ this)); |
+ return scoped_ptr<media::VideoDecodeAccelerator>(); |
+ } |
+ return vda_.Pass(); |
} |
scoped_ptr<media::VideoEncodeAccelerator> |
@@ -63,6 +112,19 @@ |
DCHECK(task_runner_->BelongsToCurrentThread()); |
return gpu_channel_host_->CreateVideoEncoder(client); |
+} |
+ |
+void RendererGpuVideoAcceleratorFactories::AsyncCreateVideoDecodeAccelerator( |
+ media::VideoCodecProfile profile, |
+ media::VideoDecodeAccelerator::Client* client) { |
+ DCHECK(task_runner_->BelongsToCurrentThread()); |
+ |
+ WebGraphicsContext3DCommandBufferImpl* context = GetContext3d(); |
+ if (context && context->GetCommandBufferProxy()) { |
+ vda_ = gpu_channel_host_->CreateVideoDecoder( |
+ context->GetCommandBufferProxy()->GetRouteID(), profile, client); |
+ } |
+ task_runner_async_waiter_.Signal(); |
} |
uint32 RendererGpuVideoAcceleratorFactories::CreateTextures( |
@@ -142,15 +204,42 @@ |
gles2->ShallowFlushCHROMIUM(); |
} |
-void RendererGpuVideoAcceleratorFactories::ReadPixels( |
+void RendererGpuVideoAcceleratorFactories::ReadPixels(uint32 texture_id, |
+ const gfx::Size& size, |
+ const SkBitmap& pixels) { |
+ // SkBitmaps use the SkPixelRef object to refcount the underlying pixels. |
+ // Multiple SkBitmaps can share a SkPixelRef instance. We use this to |
+ // ensure that the underlying pixels in the SkBitmap passed in remain valid |
+ // until the AsyncReadPixels() call completes. |
+ read_pixels_bitmap_.setPixelRef(pixels.pixelRef()); |
+ |
+ if (!task_runner_->BelongsToCurrentThread()) { |
+ task_runner_->PostTask( |
+ FROM_HERE, |
+ base::Bind(&RendererGpuVideoAcceleratorFactories::AsyncReadPixels, |
+ this, |
+ texture_id, |
+ size)); |
+ base::WaitableEvent* objects[] = {&aborted_waiter_, |
+ &task_runner_async_waiter_}; |
+ if (base::WaitableEvent::WaitMany(objects, arraysize(objects)) == 0) |
+ return; |
+ } else { |
+ AsyncReadPixels(texture_id, size); |
+ task_runner_async_waiter_.Reset(); |
+ } |
+ read_pixels_bitmap_.setPixelRef(NULL); |
+} |
+ |
+void RendererGpuVideoAcceleratorFactories::AsyncReadPixels( |
uint32 texture_id, |
- const gfx::Rect& visible_rect, |
- const SkBitmap& pixels) { |
- DCHECK(task_runner_->BelongsToCurrentThread()); |
- |
- WebGraphicsContext3DCommandBufferImpl* context = GetContext3d(); |
- if (!context) |
- return; |
+ const gfx::Size& size) { |
+ DCHECK(task_runner_->BelongsToCurrentThread()); |
+ WebGraphicsContext3DCommandBufferImpl* context = GetContext3d(); |
+ if (!context) { |
+ task_runner_async_waiter_.Signal(); |
+ return; |
+ } |
gpu::gles2::GLES2Implementation* gles2 = context->GetImplementation(); |
@@ -179,16 +268,17 @@ |
#else |
#error Unexpected Skia ARGB_8888 layout! |
#endif |
- gles2->ReadPixels(visible_rect.x(), |
- visible_rect.y(), |
- visible_rect.width(), |
- visible_rect.height(), |
+ gles2->ReadPixels(0, |
+ 0, |
+ size.width(), |
+ size.height(), |
skia_format, |
GL_UNSIGNED_BYTE, |
- pixels.pixelRef()->pixels()); |
+ read_pixels_bitmap_.pixelRef()->pixels()); |
gles2->DeleteFramebuffers(1, &fb); |
gles2->DeleteTextures(1, &tmp_texture); |
DCHECK_EQ(gles2->GetError(), static_cast<GLenum>(GL_NO_ERROR)); |
+ task_runner_async_waiter_.Signal(); |
} |
base::SharedMemory* RendererGpuVideoAcceleratorFactories::CreateSharedMemory( |
@@ -202,4 +292,28 @@ |
return task_runner_; |
} |
+void RendererGpuVideoAcceleratorFactories::Abort() { aborted_waiter_.Signal(); } |
+ |
+bool RendererGpuVideoAcceleratorFactories::IsAborted() { |
+ return aborted_waiter_.IsSignaled(); |
+} |
+ |
+scoped_refptr<RendererGpuVideoAcceleratorFactories> |
+RendererGpuVideoAcceleratorFactories::Clone() { |
+ scoped_refptr<RendererGpuVideoAcceleratorFactories> factories = |
+ new RendererGpuVideoAcceleratorFactories(); |
+ factories->task_runner_ = task_runner_; |
+ factories->gpu_channel_host_ = gpu_channel_host_; |
+ factories->context_provider_ = context_provider_; |
+ factories->thread_safe_sender_ = thread_safe_sender_; |
+ return factories; |
+} |
+ |
+void |
+RendererGpuVideoAcceleratorFactories::AsyncDestroyVideoDecodeAccelerator() { |
+ // OK to release because Destroy() will delete the VDA instance. |
+ if (vda_) |
+ vda_.release()->Destroy(); |
+} |
+ |
} // namespace content |