• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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,CommandBufferProxyImpl * impl)23 GpuVideoDecodeAcceleratorHost::GpuVideoDecodeAcceleratorHost(
24     GpuChannelHost* channel,
25     CommandBufferProxyImpl* impl)
26     : channel_(channel),
27       decoder_route_id_(MSG_ROUTING_NONE),
28       client_(NULL),
29       impl_(impl),
30       weak_this_factory_(this) {
31   DCHECK(channel_);
32   DCHECK(impl_);
33   impl_->AddDeletionObserver(this);
34 }
35 
~GpuVideoDecodeAcceleratorHost()36 GpuVideoDecodeAcceleratorHost::~GpuVideoDecodeAcceleratorHost() {
37   DCHECK(CalledOnValidThread());
38 
39   if (channel_ && decoder_route_id_ != MSG_ROUTING_NONE)
40     channel_->RemoveRoute(decoder_route_id_);
41   if (impl_)
42     impl_->RemoveDeletionObserver(this);
43 }
44 
OnMessageReceived(const IPC::Message & msg)45 bool GpuVideoDecodeAcceleratorHost::OnMessageReceived(const IPC::Message& msg) {
46   DCHECK(CalledOnValidThread());
47   bool handled = true;
48   IPC_BEGIN_MESSAGE_MAP(GpuVideoDecodeAcceleratorHost, msg)
49     IPC_MESSAGE_HANDLER(AcceleratedVideoDecoderHostMsg_BitstreamBufferProcessed,
50                         OnBitstreamBufferProcessed)
51     IPC_MESSAGE_HANDLER(AcceleratedVideoDecoderHostMsg_ProvidePictureBuffers,
52                         OnProvidePictureBuffer)
53     IPC_MESSAGE_HANDLER(AcceleratedVideoDecoderHostMsg_PictureReady,
54                         OnPictureReady)
55     IPC_MESSAGE_HANDLER(AcceleratedVideoDecoderHostMsg_FlushDone,
56                         OnFlushDone)
57     IPC_MESSAGE_HANDLER(AcceleratedVideoDecoderHostMsg_ResetDone,
58                         OnResetDone)
59     IPC_MESSAGE_HANDLER(AcceleratedVideoDecoderHostMsg_ErrorNotification,
60                         OnNotifyError)
61     IPC_MESSAGE_HANDLER(AcceleratedVideoDecoderHostMsg_DismissPictureBuffer,
62                         OnDismissPictureBuffer)
63     IPC_MESSAGE_UNHANDLED(handled = false)
64   IPC_END_MESSAGE_MAP()
65   DCHECK(handled);
66   // See OnNotifyError for why |this| mustn't be used after OnNotifyError might
67   // have been called above.
68   return handled;
69 }
70 
OnChannelError()71 void GpuVideoDecodeAcceleratorHost::OnChannelError() {
72   DCHECK(CalledOnValidThread());
73   if (channel_) {
74     if (decoder_route_id_ != MSG_ROUTING_NONE)
75       channel_->RemoveRoute(decoder_route_id_);
76     channel_ = NULL;
77   }
78   DLOG(ERROR) << "OnChannelError()";
79   PostNotifyError(PLATFORM_FAILURE);
80 }
81 
Initialize(media::VideoCodecProfile profile,Client * client)82 bool GpuVideoDecodeAcceleratorHost::Initialize(media::VideoCodecProfile profile,
83                                                Client* client) {
84   DCHECK(CalledOnValidThread());
85   client_ = client;
86 
87   if (!impl_)
88     return false;
89 
90   int32 route_id = channel_->GenerateRouteID();
91   channel_->AddRoute(route_id, weak_this_factory_.GetWeakPtr());
92 
93   bool succeeded = false;
94   Send(new GpuCommandBufferMsg_CreateVideoDecoder(
95       impl_->GetRouteID(), profile, route_id, &succeeded));
96 
97   if (!succeeded) {
98     DLOG(ERROR) << "Send(GpuCommandBufferMsg_CreateVideoDecoder()) failed";
99     PostNotifyError(PLATFORM_FAILURE);
100     channel_->RemoveRoute(route_id);
101     return false;
102   }
103   decoder_route_id_ = route_id;
104   return true;
105 }
106 
Decode(const media::BitstreamBuffer & bitstream_buffer)107 void GpuVideoDecodeAcceleratorHost::Decode(
108     const media::BitstreamBuffer& bitstream_buffer) {
109   DCHECK(CalledOnValidThread());
110   if (!channel_)
111     return;
112 
113   base::SharedMemoryHandle handle = channel_->ShareToGpuProcess(
114       bitstream_buffer.handle());
115   if (!base::SharedMemory::IsHandleValid(handle)) {
116     NOTREACHED() << "Failed to duplicate buffer handler";
117     return;
118   }
119 
120   Send(new AcceleratedVideoDecoderMsg_Decode(
121       decoder_route_id_, handle, bitstream_buffer.id(),
122       bitstream_buffer.size()));
123 }
124 
AssignPictureBuffers(const std::vector<media::PictureBuffer> & buffers)125 void GpuVideoDecodeAcceleratorHost::AssignPictureBuffers(
126     const std::vector<media::PictureBuffer>& buffers) {
127   DCHECK(CalledOnValidThread());
128   if (!channel_)
129     return;
130   // Rearrange data for IPC command.
131   std::vector<int32> buffer_ids;
132   std::vector<uint32> texture_ids;
133   for (uint32 i = 0; i < buffers.size(); i++) {
134     const media::PictureBuffer& buffer = buffers[i];
135     if (buffer.size() != picture_buffer_dimensions_) {
136       DLOG(ERROR) << "buffer.size() invalid: expected "
137                   << picture_buffer_dimensions_.ToString()
138                   << ", got " << buffer.size().ToString();
139       PostNotifyError(INVALID_ARGUMENT);
140       return;
141     }
142     texture_ids.push_back(buffer.texture_id());
143     buffer_ids.push_back(buffer.id());
144   }
145   Send(new AcceleratedVideoDecoderMsg_AssignPictureBuffers(
146       decoder_route_id_, buffer_ids, texture_ids));
147 }
148 
ReusePictureBuffer(int32 picture_buffer_id)149 void GpuVideoDecodeAcceleratorHost::ReusePictureBuffer(
150     int32 picture_buffer_id) {
151   DCHECK(CalledOnValidThread());
152   if (!channel_)
153     return;
154   Send(new AcceleratedVideoDecoderMsg_ReusePictureBuffer(
155       decoder_route_id_, picture_buffer_id));
156 }
157 
Flush()158 void GpuVideoDecodeAcceleratorHost::Flush() {
159   DCHECK(CalledOnValidThread());
160   if (!channel_)
161     return;
162   Send(new AcceleratedVideoDecoderMsg_Flush(decoder_route_id_));
163 }
164 
Reset()165 void GpuVideoDecodeAcceleratorHost::Reset() {
166   DCHECK(CalledOnValidThread());
167   if (!channel_)
168     return;
169   Send(new AcceleratedVideoDecoderMsg_Reset(decoder_route_id_));
170 }
171 
Destroy()172 void GpuVideoDecodeAcceleratorHost::Destroy() {
173   DCHECK(CalledOnValidThread());
174   if (channel_)
175     Send(new AcceleratedVideoDecoderMsg_Destroy(decoder_route_id_));
176   client_ = NULL;
177   delete this;
178 }
179 
OnWillDeleteImpl()180 void GpuVideoDecodeAcceleratorHost::OnWillDeleteImpl() {
181   DCHECK(CalledOnValidThread());
182   impl_ = NULL;
183 
184   // The CommandBufferProxyImpl is going away; error out this VDA.
185   OnChannelError();
186 }
187 
PostNotifyError(Error error)188 void GpuVideoDecodeAcceleratorHost::PostNotifyError(Error error) {
189   DCHECK(CalledOnValidThread());
190   DVLOG(2) << "PostNotifyError(): error=" << error;
191   base::MessageLoopProxy::current()->PostTask(
192       FROM_HERE,
193       base::Bind(&GpuVideoDecodeAcceleratorHost::OnNotifyError,
194                  weak_this_factory_.GetWeakPtr(),
195                  error));
196 }
197 
Send(IPC::Message * message)198 void GpuVideoDecodeAcceleratorHost::Send(IPC::Message* message) {
199   DCHECK(CalledOnValidThread());
200   uint32 message_type = message->type();
201   if (!channel_->Send(message)) {
202     DLOG(ERROR) << "Send(" << message_type << ") failed";
203     PostNotifyError(PLATFORM_FAILURE);
204   }
205 }
206 
OnBitstreamBufferProcessed(int32 bitstream_buffer_id)207 void GpuVideoDecodeAcceleratorHost::OnBitstreamBufferProcessed(
208     int32 bitstream_buffer_id) {
209   DCHECK(CalledOnValidThread());
210   if (client_)
211     client_->NotifyEndOfBitstreamBuffer(bitstream_buffer_id);
212 }
213 
OnProvidePictureBuffer(uint32 num_requested_buffers,const gfx::Size & dimensions,uint32 texture_target)214 void GpuVideoDecodeAcceleratorHost::OnProvidePictureBuffer(
215     uint32 num_requested_buffers,
216     const gfx::Size& dimensions,
217     uint32 texture_target) {
218   DCHECK(CalledOnValidThread());
219   picture_buffer_dimensions_ = dimensions;
220   if (client_) {
221     client_->ProvidePictureBuffers(
222         num_requested_buffers, dimensions, texture_target);
223   }
224 }
225 
OnDismissPictureBuffer(int32 picture_buffer_id)226 void GpuVideoDecodeAcceleratorHost::OnDismissPictureBuffer(
227     int32 picture_buffer_id) {
228   DCHECK(CalledOnValidThread());
229   if (client_)
230     client_->DismissPictureBuffer(picture_buffer_id);
231 }
232 
OnPictureReady(int32 picture_buffer_id,int32 bitstream_buffer_id)233 void GpuVideoDecodeAcceleratorHost::OnPictureReady(
234     int32 picture_buffer_id, int32 bitstream_buffer_id) {
235   DCHECK(CalledOnValidThread());
236   if (!client_)
237     return;
238   media::Picture picture(picture_buffer_id, bitstream_buffer_id);
239   client_->PictureReady(picture);
240 }
241 
OnFlushDone()242 void GpuVideoDecodeAcceleratorHost::OnFlushDone() {
243   DCHECK(CalledOnValidThread());
244   if (client_)
245     client_->NotifyFlushDone();
246 }
247 
OnResetDone()248 void GpuVideoDecodeAcceleratorHost::OnResetDone() {
249   DCHECK(CalledOnValidThread());
250   if (client_)
251     client_->NotifyResetDone();
252 }
253 
OnNotifyError(uint32 error)254 void GpuVideoDecodeAcceleratorHost::OnNotifyError(uint32 error) {
255   DCHECK(CalledOnValidThread());
256   if (!client_)
257     return;
258   weak_this_factory_.InvalidateWeakPtrs();
259 
260   // Client::NotifyError() may Destroy() |this|, so calling it needs to be the
261   // last thing done on this stack!
262   media::VideoDecodeAccelerator::Client* client = NULL;
263   std::swap(client, client_);
264   client->NotifyError(static_cast<media::VideoDecodeAccelerator::Error>(error));
265 }
266 
267 }  // namespace content
268