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
20using media::VideoDecodeAccelerator;
21namespace content {
22
23GpuVideoDecodeAcceleratorHost::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
36GpuVideoDecodeAcceleratorHost::~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
45bool 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
71void 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
82bool 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
107void 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
125void 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
149void 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
158void GpuVideoDecodeAcceleratorHost::Flush() {
159  DCHECK(CalledOnValidThread());
160  if (!channel_)
161    return;
162  Send(new AcceleratedVideoDecoderMsg_Flush(decoder_route_id_));
163}
164
165void GpuVideoDecodeAcceleratorHost::Reset() {
166  DCHECK(CalledOnValidThread());
167  if (!channel_)
168    return;
169  Send(new AcceleratedVideoDecoderMsg_Reset(decoder_route_id_));
170}
171
172void GpuVideoDecodeAcceleratorHost::Destroy() {
173  DCHECK(CalledOnValidThread());
174  if (channel_)
175    Send(new AcceleratedVideoDecoderMsg_Destroy(decoder_route_id_));
176  client_ = NULL;
177  delete this;
178}
179
180void GpuVideoDecodeAcceleratorHost::OnWillDeleteImpl() {
181  DCHECK(CalledOnValidThread());
182  impl_ = NULL;
183
184  // The CommandBufferProxyImpl is going away; error out this VDA.
185  OnChannelError();
186}
187
188void 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
198void 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
207void GpuVideoDecodeAcceleratorHost::OnBitstreamBufferProcessed(
208    int32 bitstream_buffer_id) {
209  DCHECK(CalledOnValidThread());
210  if (client_)
211    client_->NotifyEndOfBitstreamBuffer(bitstream_buffer_id);
212}
213
214void 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
226void GpuVideoDecodeAcceleratorHost::OnDismissPictureBuffer(
227    int32 picture_buffer_id) {
228  DCHECK(CalledOnValidThread());
229  if (client_)
230    client_->DismissPictureBuffer(picture_buffer_id);
231}
232
233void GpuVideoDecodeAcceleratorHost::OnPictureReady(
234    int32 picture_buffer_id,
235    int32 bitstream_buffer_id,
236    const gfx::Rect& visible_rect) {
237  DCHECK(CalledOnValidThread());
238  if (!client_)
239    return;
240  media::Picture picture(picture_buffer_id, bitstream_buffer_id, visible_rect);
241  client_->PictureReady(picture);
242}
243
244void GpuVideoDecodeAcceleratorHost::OnFlushDone() {
245  DCHECK(CalledOnValidThread());
246  if (client_)
247    client_->NotifyFlushDone();
248}
249
250void GpuVideoDecodeAcceleratorHost::OnResetDone() {
251  DCHECK(CalledOnValidThread());
252  if (client_)
253    client_->NotifyResetDone();
254}
255
256void GpuVideoDecodeAcceleratorHost::OnNotifyError(uint32 error) {
257  DCHECK(CalledOnValidThread());
258  if (!client_)
259    return;
260  weak_this_factory_.InvalidateWeakPtrs();
261
262  // Client::NotifyError() may Destroy() |this|, so calling it needs to be the
263  // last thing done on this stack!
264  media::VideoDecodeAccelerator::Client* client = NULL;
265  std::swap(client, client_);
266  client->NotifyError(static_cast<media::VideoDecodeAccelerator::Error>(error));
267}
268
269}  // namespace content
270