| 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
|
|
|