1 // Copyright (c) 2012 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.
4
5 #include "content/common/gpu/client/gpu_video_decode_accelerator_host.h"
6
7 #include "base/bind.h"
8 #include "base/logging.h"
9 #include "base/message_loop/message_loop.h"
10 #include "content/common/gpu/client/gpu_channel_host.h"
11 #include "content/common/gpu/gpu_messages.h"
12 #include "content/common/view_messages.h"
13 #include "ipc/ipc_message_macros.h"
14 #include "ipc/ipc_message_utils.h"
15
16 #if defined(OS_WIN)
17 #include "content/public/common/sandbox_init.h"
18 #endif // OS_WIN
19
20 using media::VideoDecodeAccelerator;
21 namespace content {
22
GpuVideoDecodeAcceleratorHost(GpuChannelHost * channel,int32 decoder_route_id,VideoDecodeAccelerator::Client * client,CommandBufferProxyImpl * impl)23 GpuVideoDecodeAcceleratorHost::GpuVideoDecodeAcceleratorHost(
24 GpuChannelHost* channel,
25 int32 decoder_route_id,
26 VideoDecodeAccelerator::Client* client,
27 CommandBufferProxyImpl* impl)
28 : channel_(channel),
29 decoder_route_id_(decoder_route_id),
30 client_(client),
31 impl_(impl) {
32 DCHECK(channel_);
33 DCHECK(client_);
34 channel_->AddRoute(decoder_route_id, base::AsWeakPtr(this));
35 impl_->AddDeletionObserver(this);
36 }
37
OnChannelError()38 void GpuVideoDecodeAcceleratorHost::OnChannelError() {
39 DLOG(ERROR) << "GpuVideoDecodeAcceleratorHost::OnChannelError()";
40 if (channel_) {
41 channel_->RemoveRoute(decoder_route_id_);
42 channel_ = NULL;
43 }
44 // See OnErrorNotification for why this needs to be the last thing in this
45 // function.
46 OnErrorNotification(PLATFORM_FAILURE);
47 }
48
OnMessageReceived(const IPC::Message & msg)49 bool GpuVideoDecodeAcceleratorHost::OnMessageReceived(const IPC::Message& msg) {
50 DCHECK(CalledOnValidThread());
51 bool handled = true;
52 IPC_BEGIN_MESSAGE_MAP(GpuVideoDecodeAcceleratorHost, msg)
53 IPC_MESSAGE_HANDLER(AcceleratedVideoDecoderHostMsg_BitstreamBufferProcessed,
54 OnBitstreamBufferProcessed)
55 IPC_MESSAGE_HANDLER(AcceleratedVideoDecoderHostMsg_ProvidePictureBuffers,
56 OnProvidePictureBuffer)
57 IPC_MESSAGE_HANDLER(AcceleratedVideoDecoderHostMsg_PictureReady,
58 OnPictureReady)
59 IPC_MESSAGE_HANDLER(AcceleratedVideoDecoderHostMsg_FlushDone,
60 OnFlushDone)
61 IPC_MESSAGE_HANDLER(AcceleratedVideoDecoderHostMsg_ResetDone,
62 OnResetDone)
63 IPC_MESSAGE_HANDLER(AcceleratedVideoDecoderHostMsg_ErrorNotification,
64 OnErrorNotification)
65 IPC_MESSAGE_HANDLER(AcceleratedVideoDecoderHostMsg_DismissPictureBuffer,
66 OnDismissPictureBuffer)
67 IPC_MESSAGE_UNHANDLED(handled = false)
68 IPC_END_MESSAGE_MAP()
69 DCHECK(handled);
70 // See OnErrorNotification for why |this| mustn't be used after
71 // OnErrorNotification might have been called above.
72 return handled;
73 }
74
Initialize(media::VideoCodecProfile profile)75 bool GpuVideoDecodeAcceleratorHost::Initialize(
76 media::VideoCodecProfile profile) {
77 NOTREACHED();
78 return true;
79 }
80
Decode(const media::BitstreamBuffer & bitstream_buffer)81 void GpuVideoDecodeAcceleratorHost::Decode(
82 const media::BitstreamBuffer& bitstream_buffer) {
83 DCHECK(CalledOnValidThread());
84 // Can happen if a decode task was posted before an error was delivered.
85 if (!channel_)
86 return;
87
88 base::SharedMemoryHandle handle = channel_->ShareToGpuProcess(
89 bitstream_buffer.handle());
90 if (!base::SharedMemory::IsHandleValid(handle)) {
91 NOTREACHED() << "Failed to duplicate buffer handler";
92 return;
93 }
94
95 Send(new AcceleratedVideoDecoderMsg_Decode(
96 decoder_route_id_, handle, bitstream_buffer.id(),
97 bitstream_buffer.size()));
98 }
99
AssignPictureBuffers(const std::vector<media::PictureBuffer> & buffers)100 void GpuVideoDecodeAcceleratorHost::AssignPictureBuffers(
101 const std::vector<media::PictureBuffer>& buffers) {
102 DCHECK(CalledOnValidThread());
103 // Rearrange data for IPC command.
104 std::vector<int32> buffer_ids;
105 std::vector<uint32> texture_ids;
106 for (uint32 i = 0; i < buffers.size(); i++) {
107 const media::PictureBuffer& buffer = buffers[i];
108 if (buffer.size() != picture_buffer_dimensions_) {
109 OnErrorNotification(INVALID_ARGUMENT);
110 return;
111 }
112 texture_ids.push_back(buffer.texture_id());
113 buffer_ids.push_back(buffer.id());
114 }
115 Send(new AcceleratedVideoDecoderMsg_AssignPictureBuffers(
116 decoder_route_id_, buffer_ids, texture_ids));
117 }
118
ReusePictureBuffer(int32 picture_buffer_id)119 void GpuVideoDecodeAcceleratorHost::ReusePictureBuffer(
120 int32 picture_buffer_id) {
121 DCHECK(CalledOnValidThread());
122 Send(new AcceleratedVideoDecoderMsg_ReusePictureBuffer(
123 decoder_route_id_, picture_buffer_id));
124 }
125
Flush()126 void GpuVideoDecodeAcceleratorHost::Flush() {
127 DCHECK(CalledOnValidThread());
128 Send(new AcceleratedVideoDecoderMsg_Flush(decoder_route_id_));
129 }
130
Reset()131 void GpuVideoDecodeAcceleratorHost::Reset() {
132 DCHECK(CalledOnValidThread());
133 Send(new AcceleratedVideoDecoderMsg_Reset(decoder_route_id_));
134 }
135
Destroy()136 void GpuVideoDecodeAcceleratorHost::Destroy() {
137 DCHECK(CalledOnValidThread());
138 client_ = NULL;
139 Send(new AcceleratedVideoDecoderMsg_Destroy(decoder_route_id_));
140 delete this;
141 }
142
OnWillDeleteImpl()143 void GpuVideoDecodeAcceleratorHost::OnWillDeleteImpl() {
144 impl_ = NULL;
145
146 // The CommandBufferProxyImpl is going away; error out this VDA.
147 OnChannelError();
148 }
149
~GpuVideoDecodeAcceleratorHost()150 GpuVideoDecodeAcceleratorHost::~GpuVideoDecodeAcceleratorHost() {
151 DCHECK(CalledOnValidThread());
152 DCHECK(!client_) << "destructor called without Destroy being called!";
153
154 if (channel_)
155 channel_->RemoveRoute(decoder_route_id_);
156 if (impl_)
157 impl_->RemoveDeletionObserver(this);
158 }
159
Send(IPC::Message * message)160 void GpuVideoDecodeAcceleratorHost::Send(IPC::Message* message) {
161 // After OnChannelError is called, the client should no longer send
162 // messages to the gpu channel through this object. But queued posted tasks
163 // can still be draining, so we're forgiving and simply ignore them.
164 bool error = false;
165 uint32 message_type = message->type();
166 if (!channel_) {
167 delete message;
168 DLOG(ERROR) << "Send(" << message_type << ") after error ignored";
169 error = true;
170 } else if (!channel_->Send(message)) {
171 DLOG(ERROR) << "Send(" << message_type << ") failed";
172 error = true;
173 }
174 // See OnErrorNotification for why this needs to be the last thing in this
175 // function.
176 if (error)
177 OnErrorNotification(PLATFORM_FAILURE);
178 }
179
OnBitstreamBufferProcessed(int32 bitstream_buffer_id)180 void GpuVideoDecodeAcceleratorHost::OnBitstreamBufferProcessed(
181 int32 bitstream_buffer_id) {
182 DCHECK(CalledOnValidThread());
183 if (client_)
184 client_->NotifyEndOfBitstreamBuffer(bitstream_buffer_id);
185 }
186
OnProvidePictureBuffer(uint32 num_requested_buffers,const gfx::Size & dimensions,uint32 texture_target)187 void GpuVideoDecodeAcceleratorHost::OnProvidePictureBuffer(
188 uint32 num_requested_buffers,
189 const gfx::Size& dimensions,
190 uint32 texture_target) {
191 DCHECK(CalledOnValidThread());
192 picture_buffer_dimensions_ = dimensions;
193 if (client_) {
194 client_->ProvidePictureBuffers(
195 num_requested_buffers, dimensions, texture_target);
196 }
197 }
198
OnDismissPictureBuffer(int32 picture_buffer_id)199 void GpuVideoDecodeAcceleratorHost::OnDismissPictureBuffer(
200 int32 picture_buffer_id) {
201 DCHECK(CalledOnValidThread());
202 if (client_)
203 client_->DismissPictureBuffer(picture_buffer_id);
204 }
205
OnPictureReady(int32 picture_buffer_id,int32 bitstream_buffer_id)206 void GpuVideoDecodeAcceleratorHost::OnPictureReady(
207 int32 picture_buffer_id, int32 bitstream_buffer_id) {
208 DCHECK(CalledOnValidThread());
209 if (!client_)
210 return;
211 media::Picture picture(picture_buffer_id, bitstream_buffer_id);
212 client_->PictureReady(picture);
213 }
214
OnFlushDone()215 void GpuVideoDecodeAcceleratorHost::OnFlushDone() {
216 DCHECK(CalledOnValidThread());
217 if (client_)
218 client_->NotifyFlushDone();
219 }
220
OnResetDone()221 void GpuVideoDecodeAcceleratorHost::OnResetDone() {
222 DCHECK(CalledOnValidThread());
223 if (client_)
224 client_->NotifyResetDone();
225 }
226
OnErrorNotification(uint32 error)227 void GpuVideoDecodeAcceleratorHost::OnErrorNotification(uint32 error) {
228 DCHECK(CalledOnValidThread());
229 if (!client_)
230 return;
231
232 // Client::NotifyError() may Destroy() |this|, so calling it needs to be the
233 // last thing done on this stack!
234 media::VideoDecodeAccelerator::Client* client = NULL;
235 std::swap(client, client_);
236 client->NotifyError(
237 static_cast<media::VideoDecodeAccelerator::Error>(error));
238 }
239
240 } // namespace content
241