1 // Copyright 2015 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "content/common/gpu/client/gpu_jpeg_decode_accelerator_host.h"
8 #include "base/logging.h"
9 #include "base/memory/shared_memory_handle.h"
10 #include "base/memory/weak_ptr.h"
11 #include "base/synchronization/waitable_event.h"
12 #include "content/common/gpu/client/gpu_channel_host.h"
13 #include "content/common/gpu/gpu_messages.h"
14 #include "ipc/ipc_listener.h"
15 #include "ipc/ipc_message_macros.h"
16 #include "ipc/ipc_message_utils.h"
20 // Class to receive AcceleratedJpegDecoderHostMsg_DecodeAck IPC message on IO
21 // thread. This does very similar what MessageFilter usually does. It is not
22 // MessageFilter because GpuChannelHost doesn't support AddFilter.
23 class GpuJpegDecodeAcceleratorHost::Receiver
: public IPC::Listener
,
24 public base::NonThreadSafe
{
26 Receiver(Client
* client
,
27 const scoped_refptr
<base::SingleThreadTaskRunner
>& io_task_runner
)
29 io_task_runner_(io_task_runner
),
30 weak_factory_for_io_(this) {
31 DCHECK(CalledOnValidThread());
34 ~Receiver() override
{ DCHECK(CalledOnValidThread()); }
36 void InvalidateWeakPtr(base::WaitableEvent
* event
) {
37 DCHECK(io_task_runner_
->BelongsToCurrentThread());
38 weak_factory_for_io_
.InvalidateWeakPtrs();
42 // IPC::Listener implementation.
43 void OnChannelError() override
{
44 DCHECK(io_task_runner_
->BelongsToCurrentThread());
46 OnDecodeAck(kInvalidBitstreamBufferId
, PLATFORM_FAILURE
);
49 bool OnMessageReceived(const IPC::Message
& msg
) override
{
50 DCHECK(io_task_runner_
->BelongsToCurrentThread());
53 IPC_BEGIN_MESSAGE_MAP(GpuJpegDecodeAcceleratorHost::Receiver
, msg
)
54 IPC_MESSAGE_HANDLER(AcceleratedJpegDecoderHostMsg_DecodeAck
, OnDecodeAck
)
55 IPC_MESSAGE_UNHANDLED(handled
= false)
61 base::WeakPtr
<IPC::Listener
> AsWeakPtrForIO() {
62 return weak_factory_for_io_
.GetWeakPtr();
66 void OnDecodeAck(int32_t bitstream_buffer_id
, Error error
) {
67 DCHECK(io_task_runner_
->BelongsToCurrentThread());
72 if (error
== media::JpegDecodeAccelerator::NO_ERRORS
) {
73 client_
->VideoFrameReady(bitstream_buffer_id
);
75 // Only NotifyError once.
76 // Client::NotifyError() may trigger deletion of |this| (on another
77 // thread), so calling it needs to be the last thing done on this stack!
78 media::JpegDecodeAccelerator::Client
* client
= nullptr;
79 std::swap(client
, client_
);
80 client
->NotifyError(bitstream_buffer_id
, error
);
86 // GPU IO task runner.
87 scoped_refptr
<base::SingleThreadTaskRunner
> io_task_runner_
;
89 // Weak pointers will be invalidated on IO thread.
90 base::WeakPtrFactory
<Receiver
> weak_factory_for_io_
;
92 DISALLOW_COPY_AND_ASSIGN(Receiver
);
95 GpuJpegDecodeAcceleratorHost::GpuJpegDecodeAcceleratorHost(
96 GpuChannelHost
* channel
,
98 const scoped_refptr
<base::SingleThreadTaskRunner
>& io_task_runner
)
100 decoder_route_id_(route_id
),
101 io_task_runner_(io_task_runner
) {
103 DCHECK_NE(decoder_route_id_
, MSG_ROUTING_NONE
);
106 GpuJpegDecodeAcceleratorHost::~GpuJpegDecodeAcceleratorHost() {
107 DCHECK(CalledOnValidThread());
108 Send(new AcceleratedJpegDecoderMsg_Destroy(decoder_route_id_
));
111 channel_
->RemoveRoute(decoder_route_id_
);
113 // Invalidate weak ptr of |receiver_|. After that, no more messages will be
114 // routed to |receiver_| on IO thread.
115 base::WaitableEvent
event(false, false);
116 io_task_runner_
->PostTask(FROM_HERE
,
117 base::Bind(&Receiver::InvalidateWeakPtr
,
118 base::Unretained(receiver_
.get()),
119 base::Unretained(&event
)));
124 bool GpuJpegDecodeAcceleratorHost::Initialize(
125 media::JpegDecodeAccelerator::Client
* client
) {
126 DCHECK(CalledOnValidThread());
128 bool succeeded
= false;
129 // This cannot be on IO thread because the msg is synchronous.
130 Send(new GpuMsg_CreateJpegDecoder(decoder_route_id_
, &succeeded
));
133 DLOG(ERROR
) << "Send(GpuMsg_CreateJpegDecoder()) failed";
137 receiver_
.reset(new Receiver(client
, io_task_runner_
));
142 void GpuJpegDecodeAcceleratorHost::Decode(
143 const media::BitstreamBuffer
& bitstream_buffer
,
144 const scoped_refptr
<media::VideoFrame
>& video_frame
) {
145 DCHECK(CalledOnValidThread());
148 base::SharedMemory::IsHandleValid(video_frame
->shared_memory_handle()));
150 base::SharedMemoryHandle input_handle
=
151 channel_
->ShareToGpuProcess(bitstream_buffer
.handle());
152 if (!base::SharedMemory::IsHandleValid(input_handle
)) {
153 DLOG(ERROR
) << "Failed to duplicate handle of BitstreamBuffer";
156 base::SharedMemoryHandle output_handle
=
157 channel_
->ShareToGpuProcess(video_frame
->shared_memory_handle());
158 if (!base::SharedMemory::IsHandleValid(output_handle
)) {
159 DLOG(ERROR
) << "Failed to duplicate handle of VideoFrame";
160 #if defined(OS_POSIX) && !(defined(OS_MACOSX) && !defined(OS_IOS))
161 if (input_handle
.auto_close
) {
162 // Defer closing task to the ScopedFD.
163 base::ScopedFD(input_handle
.fd
);
166 // TODO(kcwu) fix the handle leak after crbug.com/493414 resolved.
171 size_t output_buffer_size
= media::VideoFrame::AllocationSize(
172 video_frame
->format(), video_frame
->coded_size());
174 AcceleratedJpegDecoderMsg_Decode_Params decode_params
;
175 decode_params
.coded_size
= video_frame
->coded_size();
176 decode_params
.input_buffer_id
= bitstream_buffer
.id();
177 decode_params
.input_buffer_handle
= input_handle
;
178 decode_params
.input_buffer_size
= bitstream_buffer
.size();
179 decode_params
.output_video_frame_handle
= output_handle
;
180 decode_params
.output_buffer_size
= output_buffer_size
;
181 Send(new AcceleratedJpegDecoderMsg_Decode(decoder_route_id_
, decode_params
));
184 bool GpuJpegDecodeAcceleratorHost::IsSupported() {
185 return channel_
->gpu_info().jpeg_decode_accelerator_supported
;
188 void GpuJpegDecodeAcceleratorHost::Send(IPC::Message
* message
) {
189 DCHECK(CalledOnValidThread());
191 if (!channel_
->Send(message
)) {
192 DLOG(ERROR
) << "Send(" << message
->type() << ") failed";
196 base::WeakPtr
<IPC::Listener
> GpuJpegDecodeAcceleratorHost::GetReceiver() {
197 return receiver_
->AsWeakPtrForIO();
200 } // namespace content