Home | History | Annotate | Download | only in client
      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 
     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 
     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 
     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 
     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 
     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 
    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 
    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 
    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 
    158 void GpuVideoDecodeAcceleratorHost::Flush() {
    159   DCHECK(CalledOnValidThread());
    160   if (!channel_)
    161     return;
    162   Send(new AcceleratedVideoDecoderMsg_Flush(decoder_route_id_));
    163 }
    164 
    165 void GpuVideoDecodeAcceleratorHost::Reset() {
    166   DCHECK(CalledOnValidThread());
    167   if (!channel_)
    168     return;
    169   Send(new AcceleratedVideoDecoderMsg_Reset(decoder_route_id_));
    170 }
    171 
    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 
    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 
    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 
    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 
    207 void GpuVideoDecodeAcceleratorHost::OnBitstreamBufferProcessed(
    208     int32 bitstream_buffer_id) {
    209   DCHECK(CalledOnValidThread());
    210   if (client_)
    211     client_->NotifyEndOfBitstreamBuffer(bitstream_buffer_id);
    212 }
    213 
    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 
    226 void GpuVideoDecodeAcceleratorHost::OnDismissPictureBuffer(
    227     int32 picture_buffer_id) {
    228   DCHECK(CalledOnValidThread());
    229   if (client_)
    230     client_->DismissPictureBuffer(picture_buffer_id);
    231 }
    232 
    233 void 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 
    244 void GpuVideoDecodeAcceleratorHost::OnFlushDone() {
    245   DCHECK(CalledOnValidThread());
    246   if (client_)
    247     client_->NotifyFlushDone();
    248 }
    249 
    250 void GpuVideoDecodeAcceleratorHost::OnResetDone() {
    251   DCHECK(CalledOnValidThread());
    252   if (client_)
    253     client_->NotifyResetDone();
    254 }
    255 
    256 void 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