summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorkcwu <kcwu@chromium.org>2015-06-22 03:17:35 -0700
committerCommit bot <commit-bot@chromium.org>2015-06-22 10:19:22 +0000
commit4073b070231e84d823cd368d478ec4014b9d2455 (patch)
treec969fbd614eeafc01c6651bb07cd358c8843e9e3
parentf7a6f277680a14a9bccb316d8b07b169855b3a3e (diff)
downloadchromium_src-4073b070231e84d823cd368d478ec4014b9d2455.zip
chromium_src-4073b070231e84d823cd368d478ec4014b9d2455.tar.gz
chromium_src-4073b070231e84d823cd368d478ec4014b9d2455.tar.bz2
MJPEG acceleration for video capture, the GPU host part
BUG=335778 TEST=none Review URL: https://codereview.chromium.org/1165943008 Cr-Commit-Position: refs/heads/master@{#335484}
-rw-r--r--content/common/gpu/client/gpu_channel_host.cc23
-rw-r--r--content/common/gpu/client/gpu_channel_host.h6
-rw-r--r--content/common/gpu/client/gpu_jpeg_decode_accelerator_host.cc194
-rw-r--r--content/common/gpu/client/gpu_jpeg_decode_accelerator_host.h68
-rw-r--r--content/content_common.gypi2
5 files changed, 293 insertions, 0 deletions
diff --git a/content/common/gpu/client/gpu_channel_host.cc b/content/common/gpu/client/gpu_channel_host.cc
index 7bd55f9..237a1d3 100644
--- a/content/common/gpu/client/gpu_channel_host.cc
+++ b/content/common/gpu/client/gpu_channel_host.cc
@@ -14,6 +14,7 @@
#include "base/threading/thread_restrictions.h"
#include "base/trace_event/trace_event.h"
#include "content/common/gpu/client/command_buffer_proxy_impl.h"
+#include "content/common/gpu/client/gpu_jpeg_decode_accelerator_host.h"
#include "content/common/gpu/gpu_messages.h"
#include "ipc/ipc_sync_message_filter.h"
#include "url/gurl.h"
@@ -258,6 +259,28 @@ scoped_ptr<media::VideoEncodeAccelerator> GpuChannelHost::CreateVideoEncoder(
return it->second->CreateVideoEncoder();
}
+scoped_ptr<media::JpegDecodeAccelerator> GpuChannelHost::CreateJpegDecoder(
+ media::JpegDecodeAccelerator::Client* client) {
+ TRACE_EVENT0("gpu", "GpuChannelHost::CreateJpegDecoder");
+
+ scoped_refptr<base::SingleThreadTaskRunner> io_task_runner =
+ factory_->GetIOThreadTaskRunner();
+ int32 route_id = GenerateRouteID();
+ scoped_ptr<GpuJpegDecodeAcceleratorHost> decoder(
+ new GpuJpegDecodeAcceleratorHost(this, route_id, io_task_runner));
+ if (!decoder->Initialize(client)) {
+ return nullptr;
+ }
+
+ // The reply message of jpeg decoder should run on IO thread.
+ io_task_runner->PostTask(FROM_HERE,
+ base::Bind(&GpuChannelHost::MessageFilter::AddRoute,
+ channel_filter_.get(), route_id,
+ decoder->GetReceiver(), io_task_runner));
+
+ return decoder.Pass();
+}
+
void GpuChannelHost::DestroyCommandBuffer(
CommandBufferProxyImpl* command_buffer) {
TRACE_EVENT0("gpu", "GpuChannelHost::DestroyCommandBuffer");
diff --git a/content/common/gpu/client/gpu_channel_host.h b/content/common/gpu/client/gpu_channel_host.h
index 83b5d96..81ddbff 100644
--- a/content/common/gpu/client/gpu_channel_host.h
+++ b/content/common/gpu/client/gpu_channel_host.h
@@ -24,6 +24,7 @@
#include "ipc/ipc_channel_handle.h"
#include "ipc/ipc_sync_channel.h"
#include "ipc/message_filter.h"
+#include "media/video/jpeg_decode_accelerator.h"
#include "ui/events/latency_info.h"
#include "ui/gfx/geometry/size.h"
#include "ui/gfx/gpu_memory_buffer.h"
@@ -44,6 +45,7 @@ class SyncMessageFilter;
}
namespace media {
+class JpegDecodeAccelerator;
class VideoDecodeAccelerator;
class VideoEncodeAccelerator;
}
@@ -149,6 +151,10 @@ class GpuChannelHost : public IPC::Sender,
scoped_ptr<media::VideoEncodeAccelerator> CreateVideoEncoder(
int command_buffer_route_id);
+ // Creates a JPEG decoder in the GPU process.
+ scoped_ptr<media::JpegDecodeAccelerator> CreateJpegDecoder(
+ media::JpegDecodeAccelerator::Client* client);
+
// Destroy a command buffer created by this channel.
void DestroyCommandBuffer(CommandBufferProxyImpl* command_buffer);
diff --git a/content/common/gpu/client/gpu_jpeg_decode_accelerator_host.cc b/content/common/gpu/client/gpu_jpeg_decode_accelerator_host.cc
new file mode 100644
index 0000000..22114e5
--- /dev/null
+++ b/content/common/gpu/client/gpu_jpeg_decode_accelerator_host.cc
@@ -0,0 +1,194 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/common/gpu/client/gpu_jpeg_decode_accelerator_host.h"
+
+#include "base/bind.h"
+#include "base/logging.h"
+#include "base/memory/shared_memory_handle.h"
+#include "base/memory/weak_ptr.h"
+#include "base/synchronization/waitable_event.h"
+#include "content/common/gpu/client/gpu_channel_host.h"
+#include "content/common/gpu/gpu_messages.h"
+#include "ipc/ipc_listener.h"
+#include "ipc/ipc_message_macros.h"
+#include "ipc/ipc_message_utils.h"
+
+namespace content {
+
+// Class to receive AcceleratedJpegDecoderHostMsg_DecodeAck IPC message on IO
+// thread. This does very similar what MessageFilter usually does. It is not
+// MessageFilter because GpuChannelHost doesn't support AddFilter.
+class GpuJpegDecodeAcceleratorHost::Receiver : public IPC::Listener,
+ public base::NonThreadSafe {
+ public:
+ Receiver(Client* client,
+ const scoped_refptr<base::SingleThreadTaskRunner>& io_task_runner)
+ : client_(client),
+ io_task_runner_(io_task_runner),
+ weak_factory_for_io_(this) {
+ DCHECK(CalledOnValidThread());
+ }
+
+ ~Receiver() override { DCHECK(CalledOnValidThread()); }
+
+ void InvalidateWeakPtr(base::WaitableEvent* event) {
+ DCHECK(io_task_runner_->BelongsToCurrentThread());
+ weak_factory_for_io_.InvalidateWeakPtrs();
+ event->Signal();
+ }
+
+ // IPC::Listener implementation.
+ void OnChannelError() override {
+ DCHECK(io_task_runner_->BelongsToCurrentThread());
+
+ OnDecodeAck(kInvalidBitstreamBufferId, PLATFORM_FAILURE);
+ }
+
+ bool OnMessageReceived(const IPC::Message& msg) override {
+ DCHECK(io_task_runner_->BelongsToCurrentThread());
+
+ bool handled = true;
+ IPC_BEGIN_MESSAGE_MAP(GpuJpegDecodeAcceleratorHost::Receiver, msg)
+ IPC_MESSAGE_HANDLER(AcceleratedJpegDecoderHostMsg_DecodeAck, OnDecodeAck)
+ IPC_MESSAGE_UNHANDLED(handled = false)
+ IPC_END_MESSAGE_MAP()
+ DCHECK(handled);
+ return handled;
+ }
+
+ base::WeakPtr<IPC::Listener> AsWeakPtrForIO() {
+ return weak_factory_for_io_.GetWeakPtr();
+ }
+
+ private:
+ void OnDecodeAck(int32_t bitstream_buffer_id, Error error) {
+ DCHECK(io_task_runner_->BelongsToCurrentThread());
+
+ if (!client_)
+ return;
+
+ if (error == media::JpegDecodeAccelerator::NO_ERRORS) {
+ client_->VideoFrameReady(bitstream_buffer_id);
+ } else {
+ // Only NotifyError once.
+ // Client::NotifyError() may trigger deletion of |this| (on another
+ // thread), so calling it needs to be the last thing done on this stack!
+ media::JpegDecodeAccelerator::Client* client = nullptr;
+ std::swap(client, client_);
+ client->NotifyError(bitstream_buffer_id, error);
+ }
+ }
+
+ Client* client_;
+
+ // GPU IO task runner.
+ scoped_refptr<base::SingleThreadTaskRunner> io_task_runner_;
+
+ // Weak pointers will be invalidated on IO thread.
+ base::WeakPtrFactory<Receiver> weak_factory_for_io_;
+
+ DISALLOW_COPY_AND_ASSIGN(Receiver);
+};
+
+GpuJpegDecodeAcceleratorHost::GpuJpegDecodeAcceleratorHost(
+ GpuChannelHost* channel,
+ int32 route_id,
+ const scoped_refptr<base::SingleThreadTaskRunner>& io_task_runner)
+ : channel_(channel),
+ decoder_route_id_(route_id),
+ io_task_runner_(io_task_runner) {
+ DCHECK(channel_);
+ DCHECK_NE(decoder_route_id_, MSG_ROUTING_NONE);
+}
+
+GpuJpegDecodeAcceleratorHost::~GpuJpegDecodeAcceleratorHost() {
+ DCHECK(CalledOnValidThread());
+ Send(new AcceleratedJpegDecoderMsg_Destroy(decoder_route_id_));
+
+ channel_->RemoveRoute(decoder_route_id_);
+
+ // Invalidate weak ptr of |receiver_|. After that, no more messages will be
+ // routed to |receiver_| on IO thread.
+ base::WaitableEvent event(false, false);
+ io_task_runner_->PostTask(
+ FROM_HERE,
+ base::Bind(&Receiver::InvalidateWeakPtr,
+ base::Unretained(receiver_.get()), base::Unretained(&event)));
+ event.Wait();
+}
+
+bool GpuJpegDecodeAcceleratorHost::Initialize(
+ media::JpegDecodeAccelerator::Client* client) {
+ DCHECK(CalledOnValidThread());
+
+ bool succeeded = false;
+ // This cannot be on IO thread because the msg is synchronous.
+ Send(new GpuMsg_CreateJpegDecoder(decoder_route_id_, &succeeded));
+
+ if (!succeeded) {
+ DLOG(ERROR) << "Send(GpuMsg_CreateJpegDecoder()) failed";
+ return false;
+ }
+
+ receiver_.reset(new Receiver(client, io_task_runner_));
+
+ return true;
+}
+
+void GpuJpegDecodeAcceleratorHost::Decode(
+ const media::BitstreamBuffer& bitstream_buffer,
+ const scoped_refptr<media::VideoFrame>& video_frame) {
+ DCHECK(CalledOnValidThread());
+
+ DCHECK(
+ base::SharedMemory::IsHandleValid(video_frame->shared_memory_handle()));
+
+ base::SharedMemoryHandle input_handle =
+ channel_->ShareToGpuProcess(bitstream_buffer.handle());
+ if (!base::SharedMemory::IsHandleValid(input_handle)) {
+ DLOG(ERROR) << "Failed to duplicate handle of BitstreamBuffer";
+ return;
+ }
+ base::SharedMemoryHandle output_handle =
+ channel_->ShareToGpuProcess(video_frame->shared_memory_handle());
+ if (!base::SharedMemory::IsHandleValid(output_handle)) {
+ DLOG(ERROR) << "Failed to duplicate handle of VideoFrame";
+#if defined(OS_POSIX) && !(defined(OS_MACOSX) && !defined(OS_IOS))
+ if (input_handle.auto_close) {
+ // Defer closing task to the ScopedFD.
+ base::ScopedFD(input_handle.fd);
+ }
+#else
+ // TODO(kcwu) fix the handle leak after crbug.com/493414 resolved.
+#endif
+ return;
+ }
+
+ size_t output_buffer_size = media::VideoFrame::AllocationSize(
+ video_frame->format(), video_frame->coded_size());
+
+ AcceleratedJpegDecoderMsg_Decode_Params decode_params;
+ decode_params.coded_size = video_frame->coded_size();
+ decode_params.input_buffer_id = bitstream_buffer.id();
+ decode_params.input_buffer_handle = input_handle;
+ decode_params.input_buffer_size = bitstream_buffer.size();
+ decode_params.output_video_frame_handle = output_handle;
+ decode_params.output_buffer_size = output_buffer_size;
+ Send(new AcceleratedJpegDecoderMsg_Decode(decoder_route_id_, decode_params));
+}
+
+void GpuJpegDecodeAcceleratorHost::Send(IPC::Message* message) {
+ DCHECK(CalledOnValidThread());
+
+ if (!channel_->Send(message)) {
+ DLOG(ERROR) << "Send(" << message->type() << ") failed";
+ }
+}
+
+base::WeakPtr<IPC::Listener> GpuJpegDecodeAcceleratorHost::GetReceiver() {
+ return receiver_->AsWeakPtrForIO();
+}
+
+} // namespace content
diff --git a/content/common/gpu/client/gpu_jpeg_decode_accelerator_host.h b/content/common/gpu/client/gpu_jpeg_decode_accelerator_host.h
new file mode 100644
index 0000000..1682a16
--- /dev/null
+++ b/content/common/gpu/client/gpu_jpeg_decode_accelerator_host.h
@@ -0,0 +1,68 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_COMMON_GPU_CLIENT_GPU_JPEG_DECODE_ACCELERATOR_HOST_H_
+#define CONTENT_COMMON_GPU_CLIENT_GPU_JPEG_DECODE_ACCELERATOR_HOST_H_
+
+#include "base/memory/weak_ptr.h"
+#include "base/threading/non_thread_safe.h"
+#include "media/video/jpeg_decode_accelerator.h"
+
+namespace base {
+class SingleThreadTaskRunner;
+}
+
+namespace IPC {
+class Listener;
+class Message;
+}
+
+namespace content {
+class GpuChannelHost;
+
+// This class is used to talk to JpegDecodeAccelerator in the GPU process
+// through IPC messages.
+class GpuJpegDecodeAcceleratorHost : public media::JpegDecodeAccelerator,
+ public base::NonThreadSafe {
+ public:
+ // GpuJpegDecoder owns |this| and |channel|. And GpuJpegDecoder delete |this|
+ // before |channel|. So |this| is guaranteed not to outlive |channel|.
+ GpuJpegDecodeAcceleratorHost(
+ GpuChannelHost* channel,
+ int32 route_id,
+ const scoped_refptr<base::SingleThreadTaskRunner>& io_task_runner);
+ ~GpuJpegDecodeAcceleratorHost() override;
+
+ // media::JpegDecodeAccelerator implementation.
+ // |client| is called on the IO thread, but is never called into after the
+ // GpuJpegDecodeAcceleratorHost is destroyed.
+ bool Initialize(media::JpegDecodeAccelerator::Client* client) override;
+ void Decode(const media::BitstreamBuffer& bitstream_buffer,
+ const scoped_refptr<media::VideoFrame>& video_frame) override;
+
+ base::WeakPtr<IPC::Listener> GetReceiver();
+
+ private:
+ class Receiver;
+
+ void Send(IPC::Message* message);
+
+ // Unowned reference to the GpuChannelHost to send IPC messages to the GPU
+ // process.
+ GpuChannelHost* channel_;
+
+ // Route ID for the associated decoder in the GPU process.
+ int32 decoder_route_id_;
+
+ // GPU IO task runner.
+ scoped_refptr<base::SingleThreadTaskRunner> io_task_runner_;
+
+ scoped_ptr<Receiver> receiver_;
+
+ DISALLOW_COPY_AND_ASSIGN(GpuJpegDecodeAcceleratorHost);
+};
+
+} // namespace content
+
+#endif // CONTENT_COMMON_GPU_CLIENT_GPU_JPEG_DECODE_ACCELERATOR_HOST_H_
diff --git a/content/content_common.gypi b/content/content_common.gypi
index d507356..4e33d50 100644
--- a/content/content_common.gypi
+++ b/content/content_common.gypi
@@ -285,6 +285,8 @@
'common/gpu/client/gl_helper_scaling.h',
'common/gpu/client/gpu_channel_host.cc',
'common/gpu/client/gpu_channel_host.h',
+ 'common/gpu/client/gpu_jpeg_decode_accelerator_host.cc',
+ 'common/gpu/client/gpu_jpeg_decode_accelerator_host.h',
'common/gpu/client/gpu_memory_buffer_factory_host.h',
'common/gpu/client/gpu_memory_buffer_impl.cc',
'common/gpu/client/gpu_memory_buffer_impl.h',