summaryrefslogtreecommitdiffstats
path: root/chromium/content/renderer/media/renderer_gpu_video_accelerator_factories.cc
diff options
context:
space:
mode:
Diffstat (limited to 'chromium/content/renderer/media/renderer_gpu_video_accelerator_factories.cc')
-rw-r--r--chromium/content/renderer/media/renderer_gpu_video_accelerator_factories.cc263
1 files changed, 102 insertions, 161 deletions
diff --git a/chromium/content/renderer/media/renderer_gpu_video_accelerator_factories.cc b/chromium/content/renderer/media/renderer_gpu_video_accelerator_factories.cc
index 7d4db85513f..94e0d78217f 100644
--- a/chromium/content/renderer/media/renderer_gpu_video_accelerator_factories.cc
+++ b/chromium/content/renderer/media/renderer_gpu_video_accelerator_factories.cc
@@ -14,133 +14,99 @@
#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 "media/video/video_decode_accelerator.h"
+#include "media/video/video_encode_accelerator.h"
+#include "third_party/skia/include/core/SkBitmap.h"
#include "third_party/skia/include/core/SkPixelRef.h"
namespace content {
-RendererGpuVideoAcceleratorFactories::~RendererGpuVideoAcceleratorFactories() {}
+// static
+scoped_refptr<RendererGpuVideoAcceleratorFactories>
+RendererGpuVideoAcceleratorFactories::Create(
+ GpuChannelHost* gpu_channel_host,
+ const scoped_refptr<base::MessageLoopProxy>& message_loop_proxy,
+ const scoped_refptr<ContextProviderCommandBuffer>& context_provider) {
+ scoped_refptr<RendererGpuVideoAcceleratorFactories> factories =
+ new RendererGpuVideoAcceleratorFactories(
+ gpu_channel_host, message_loop_proxy, context_provider);
+ // Post task from outside constructor, since AddRef()/Release() is unsafe from
+ // within.
+ message_loop_proxy->PostTask(
+ FROM_HERE,
+ base::Bind(&RendererGpuVideoAcceleratorFactories::BindContext,
+ factories));
+ return factories;
+}
+
RendererGpuVideoAcceleratorFactories::RendererGpuVideoAcceleratorFactories(
GpuChannelHost* gpu_channel_host,
+ const scoped_refptr<base::MessageLoopProxy>& message_loop_proxy,
const scoped_refptr<ContextProviderCommandBuffer>& context_provider)
- : message_loop_(
- RenderThreadImpl::current()->GetMediaThreadMessageLoopProxy()),
+ : task_runner_(message_loop_proxy),
gpu_channel_host_(gpu_channel_host),
context_provider_(context_provider),
- thread_safe_sender_(ChildThread::current()->thread_safe_sender()),
- aborted_waiter_(true, false),
- message_loop_async_waiter_(false, false) {
- // |context_provider_| is only required to support HW-accelerated decode.
- if (!context_provider_)
- return;
+ thread_safe_sender_(ChildThread::current()->thread_safe_sender()) {}
- if (message_loop_->BelongsToCurrentThread()) {
- AsyncBindContext();
- message_loop_async_waiter_.Reset();
- return;
- }
- // Wait for the context to be acquired.
- message_loop_->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)));
- message_loop_async_waiter_.Wait();
-}
+RendererGpuVideoAcceleratorFactories::~RendererGpuVideoAcceleratorFactories() {}
-RendererGpuVideoAcceleratorFactories::RendererGpuVideoAcceleratorFactories()
- : aborted_waiter_(true, false),
- message_loop_async_waiter_(false, false) {}
+void RendererGpuVideoAcceleratorFactories::BindContext() {
+ DCHECK(task_runner_->BelongsToCurrentThread());
+ if (!context_provider_->BindToCurrentThread())
+ context_provider_ = NULL;
+}
WebGraphicsContext3DCommandBufferImpl*
RendererGpuVideoAcceleratorFactories::GetContext3d() {
- DCHECK(message_loop_->BelongsToCurrentThread());
+ DCHECK(task_runner_->BelongsToCurrentThread());
if (!context_provider_)
return NULL;
- WebGraphicsContext3DCommandBufferImpl* context =
- context_provider_->Context3d();
- if (context->isContextLost()) {
+ if (context_provider_->IsContextLost()) {
context_provider_->VerifyContexts();
context_provider_ = NULL;
return NULL;
}
- return context;
-}
-
-void RendererGpuVideoAcceleratorFactories::AsyncBindContext() {
- DCHECK(message_loop_->BelongsToCurrentThread());
- if (!context_provider_->BindToCurrentThread())
- context_provider_ = NULL;
- message_loop_async_waiter_.Signal();
+ return context_provider_->WebContext3D();
}
scoped_ptr<media::VideoDecodeAccelerator>
-RendererGpuVideoAcceleratorFactories::CreateVideoDecodeAccelerator(
- media::VideoCodecProfile profile,
- media::VideoDecodeAccelerator::Client* client) {
- if (message_loop_->BelongsToCurrentThread()) {
- AsyncCreateVideoDecodeAccelerator(profile, client);
- message_loop_async_waiter_.Reset();
- return vda_.Pass();
- }
- // The VDA is returned in the vda_ member variable by the
- // AsyncCreateVideoDecodeAccelerator() function.
- message_loop_->PostTask(FROM_HERE,
- base::Bind(&RendererGpuVideoAcceleratorFactories::
- AsyncCreateVideoDecodeAccelerator,
- this,
- profile,
- client));
-
- base::WaitableEvent* objects[] = {&aborted_waiter_,
- &message_loop_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.
- message_loop_->PostTask(FROM_HERE,
- base::Bind(&RendererGpuVideoAcceleratorFactories::
- AsyncDestroyVideoDecodeAccelerator,
- this));
- return scoped_ptr<media::VideoDecodeAccelerator>();
- }
- return vda_.Pass();
-}
+RendererGpuVideoAcceleratorFactories::CreateVideoDecodeAccelerator() {
+ DCHECK(task_runner_->BelongsToCurrentThread());
-scoped_ptr<media::VideoEncodeAccelerator>
-RendererGpuVideoAcceleratorFactories::CreateVideoEncodeAccelerator(
- media::VideoEncodeAccelerator::Client* client) {
- DCHECK(message_loop_->BelongsToCurrentThread());
+ WebGraphicsContext3DCommandBufferImpl* context = GetContext3d();
+ if (context && context->GetCommandBufferProxy()) {
+ return gpu_channel_host_->CreateVideoDecoder(
+ context->GetCommandBufferProxy()->GetRouteID());
+ }
- return gpu_channel_host_->CreateVideoEncoder(client);
+ return scoped_ptr<media::VideoDecodeAccelerator>();
}
-void RendererGpuVideoAcceleratorFactories::AsyncCreateVideoDecodeAccelerator(
- media::VideoCodecProfile profile,
- media::VideoDecodeAccelerator::Client* client) {
- DCHECK(message_loop_->BelongsToCurrentThread());
+scoped_ptr<media::VideoEncodeAccelerator>
+RendererGpuVideoAcceleratorFactories::CreateVideoEncodeAccelerator() {
+ DCHECK(task_runner_->BelongsToCurrentThread());
WebGraphicsContext3DCommandBufferImpl* context = GetContext3d();
if (context && context->GetCommandBufferProxy()) {
- vda_ = gpu_channel_host_->CreateVideoDecoder(
- context->GetCommandBufferProxy()->GetRouteID(), profile, client);
+ return gpu_channel_host_->CreateVideoEncoder(
+ context->GetCommandBufferProxy()->GetRouteID());
}
- message_loop_async_waiter_.Signal();
+
+ return scoped_ptr<media::VideoEncodeAccelerator>();
}
-uint32 RendererGpuVideoAcceleratorFactories::CreateTextures(
+bool RendererGpuVideoAcceleratorFactories::CreateTextures(
int32 count,
const gfx::Size& size,
std::vector<uint32>* texture_ids,
std::vector<gpu::Mailbox>* texture_mailboxes,
uint32 texture_target) {
- DCHECK(message_loop_->BelongsToCurrentThread());
+ DCHECK(task_runner_->BelongsToCurrentThread());
DCHECK(texture_target);
WebGraphicsContext3DCommandBufferImpl* context = GetContext3d();
if (!context)
- return 0;
+ return false;
gpu::gles2::GLES2Implementation* gles2 = context->GetImplementation();
texture_ids->resize(count);
@@ -170,17 +136,17 @@ uint32 RendererGpuVideoAcceleratorFactories::CreateTextures(
texture_mailboxes->at(i).name);
}
- // We need a glFlush here to guarantee the decoder (in the GPU process) can
- // use the texture ids we return here. Since textures are expected to be
- // reused, this should not be unacceptably expensive.
- gles2->Flush();
+ // We need ShallowFlushCHROMIUM() here to order the command buffer commands
+ // with respect to IPC to the GPU process, to guarantee that the decoder in
+ // the GPU process can use these textures as soon as it receives IPC
+ // notification of them.
+ gles2->ShallowFlushCHROMIUM();
DCHECK_EQ(gles2->GetError(), static_cast<GLenum>(GL_NO_ERROR));
-
- return gles2->InsertSyncPointCHROMIUM();
+ return true;
}
void RendererGpuVideoAcceleratorFactories::DeleteTexture(uint32 texture_id) {
- DCHECK(message_loop_->BelongsToCurrentThread());
+ DCHECK(task_runner_->BelongsToCurrentThread());
WebGraphicsContext3DCommandBufferImpl* context = GetContext3d();
if (!context)
@@ -192,7 +158,7 @@ void RendererGpuVideoAcceleratorFactories::DeleteTexture(uint32 texture_id) {
}
void RendererGpuVideoAcceleratorFactories::WaitSyncPoint(uint32 sync_point) {
- DCHECK(message_loop_->BelongsToCurrentThread());
+ DCHECK(task_runner_->BelongsToCurrentThread());
WebGraphicsContext3DCommandBufferImpl* context = GetContext3d();
if (!context)
@@ -206,42 +172,15 @@ void RendererGpuVideoAcceleratorFactories::WaitSyncPoint(uint32 sync_point) {
gles2->ShallowFlushCHROMIUM();
}
-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 (!message_loop_->BelongsToCurrentThread()) {
- message_loop_->PostTask(
- FROM_HERE,
- base::Bind(&RendererGpuVideoAcceleratorFactories::AsyncReadPixels,
- this,
- texture_id,
- size));
- base::WaitableEvent* objects[] = {&aborted_waiter_,
- &message_loop_async_waiter_};
- if (base::WaitableEvent::WaitMany(objects, arraysize(objects)) == 0)
- return;
- } else {
- AsyncReadPixels(texture_id, size);
- message_loop_async_waiter_.Reset();
- }
- read_pixels_bitmap_.setPixelRef(NULL);
-}
-
-void RendererGpuVideoAcceleratorFactories::AsyncReadPixels(
+void RendererGpuVideoAcceleratorFactories::ReadPixels(
uint32 texture_id,
- const gfx::Size& size) {
- DCHECK(message_loop_->BelongsToCurrentThread());
+ const gfx::Rect& visible_rect,
+ const SkBitmap& pixels) {
+ DCHECK(task_runner_->BelongsToCurrentThread());
+
WebGraphicsContext3DCommandBufferImpl* context = GetContext3d();
- if (!context) {
- message_loop_async_waiter_.Signal();
+ if (!context)
return;
- }
gpu::gles2::GLES2Implementation* gles2 = context->GetImplementation();
@@ -261,61 +200,63 @@ void RendererGpuVideoAcceleratorFactories::AsyncReadPixels(
gles2->FramebufferTexture2D(
GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, tmp_texture, 0);
gles2->PixelStorei(GL_PACK_ALIGNMENT, 4);
+
#if SK_B32_SHIFT == 0 && SK_G32_SHIFT == 8 && SK_R32_SHIFT == 16 && \
SK_A32_SHIFT == 24
GLenum skia_format = GL_BGRA_EXT;
+ GLenum read_format = GL_BGRA_EXT;
+ GLint supported_format = 0;
+ GLint supported_type = 0;
+ gles2->GetIntegerv(GL_IMPLEMENTATION_COLOR_READ_FORMAT, &supported_format);
+ gles2->GetIntegerv(GL_IMPLEMENTATION_COLOR_READ_TYPE, &supported_type);
+ if (supported_format != GL_BGRA_EXT || supported_type != GL_UNSIGNED_BYTE) {
+ read_format = GL_RGBA;
+ }
#elif SK_R32_SHIFT == 0 && SK_G32_SHIFT == 8 && SK_B32_SHIFT == 16 && \
SK_A32_SHIFT == 24
GLenum skia_format = GL_RGBA;
+ GLenum read_format = GL_RGBA;
#else
#error Unexpected Skia ARGB_8888 layout!
#endif
- gles2->ReadPixels(0,
- 0,
- size.width(),
- size.height(),
- skia_format,
+ gles2->ReadPixels(visible_rect.x(),
+ visible_rect.y(),
+ visible_rect.width(),
+ visible_rect.height(),
+ read_format,
GL_UNSIGNED_BYTE,
- read_pixels_bitmap_.pixelRef()->pixels());
+ pixels.pixelRef()->pixels());
gles2->DeleteFramebuffers(1, &fb);
gles2->DeleteTextures(1, &tmp_texture);
+
+ if (skia_format != read_format) {
+ DCHECK(read_format == GL_RGBA);
+ int pixel_count = visible_rect.width() * visible_rect.height();
+ uint32_t* pixels_ptr = static_cast<uint32_t*>(pixels.pixelRef()->pixels());
+ for (int i = 0; i < pixel_count; ++i) {
+ uint32_t r = pixels_ptr[i] & 0xFF;
+ uint32_t g = (pixels_ptr[i] >> 8) & 0xFF;
+ uint32_t b = (pixels_ptr[i] >> 16) & 0xFF;
+ uint32_t a = (pixels_ptr[i] >> 24) & 0xFF;
+ pixels_ptr[i] = (r << SK_R32_SHIFT) |
+ (g << SK_G32_SHIFT) |
+ (b << SK_B32_SHIFT) |
+ (a << SK_A32_SHIFT);
+ }
+ }
+
DCHECK_EQ(gles2->GetError(), static_cast<GLenum>(GL_NO_ERROR));
- message_loop_async_waiter_.Signal();
}
base::SharedMemory* RendererGpuVideoAcceleratorFactories::CreateSharedMemory(
size_t size) {
- DCHECK(message_loop_->BelongsToCurrentThread());
+ DCHECK(task_runner_->BelongsToCurrentThread());
return ChildThread::AllocateSharedMemory(size, thread_safe_sender_.get());
}
-scoped_refptr<base::MessageLoopProxy>
-RendererGpuVideoAcceleratorFactories::GetMessageLoop() {
- return message_loop_;
-}
-
-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->message_loop_ = message_loop_;
- 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();
+scoped_refptr<base::SingleThreadTaskRunner>
+RendererGpuVideoAcceleratorFactories::GetTaskRunner() {
+ return task_runner_;
}
} // namespace content