diff options
author | kcwu <kcwu@chromium.org> | 2015-06-22 03:17:35 -0700 |
---|---|---|
committer | Commit bot <commit-bot@chromium.org> | 2015-06-22 10:19:22 +0000 |
commit | 4073b070231e84d823cd368d478ec4014b9d2455 (patch) | |
tree | c969fbd614eeafc01c6651bb07cd358c8843e9e3 | |
parent | f7a6f277680a14a9bccb316d8b07b169855b3a3e (diff) | |
download | chromium_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.cc | 23 | ||||
-rw-r--r-- | content/common/gpu/client/gpu_channel_host.h | 6 | ||||
-rw-r--r-- | content/common/gpu/client/gpu_jpeg_decode_accelerator_host.cc | 194 | ||||
-rw-r--r-- | content/common/gpu/client/gpu_jpeg_decode_accelerator_host.h | 68 | ||||
-rw-r--r-- | content/content_common.gypi | 2 |
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', |