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     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 
     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 
     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 
     75 bool GpuVideoDecodeAcceleratorHost::Initialize(
     76     media::VideoCodecProfile profile) {
     77   NOTREACHED();
     78   return true;
     79 }
     80 
     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 
    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 
    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 
    126 void GpuVideoDecodeAcceleratorHost::Flush() {
    127   DCHECK(CalledOnValidThread());
    128   Send(new AcceleratedVideoDecoderMsg_Flush(decoder_route_id_));
    129 }
    130 
    131 void GpuVideoDecodeAcceleratorHost::Reset() {
    132   DCHECK(CalledOnValidThread());
    133   Send(new AcceleratedVideoDecoderMsg_Reset(decoder_route_id_));
    134 }
    135 
    136 void GpuVideoDecodeAcceleratorHost::Destroy() {
    137   DCHECK(CalledOnValidThread());
    138   client_ = NULL;
    139   Send(new AcceleratedVideoDecoderMsg_Destroy(decoder_route_id_));
    140   delete this;
    141 }
    142 
    143 void GpuVideoDecodeAcceleratorHost::OnWillDeleteImpl() {
    144   impl_ = NULL;
    145 
    146   // The CommandBufferProxyImpl is going away; error out this VDA.
    147   OnChannelError();
    148 }
    149 
    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 
    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 
    180 void GpuVideoDecodeAcceleratorHost::OnBitstreamBufferProcessed(
    181     int32 bitstream_buffer_id) {
    182   DCHECK(CalledOnValidThread());
    183   if (client_)
    184     client_->NotifyEndOfBitstreamBuffer(bitstream_buffer_id);
    185 }
    186 
    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 
    199 void GpuVideoDecodeAcceleratorHost::OnDismissPictureBuffer(
    200     int32 picture_buffer_id) {
    201   DCHECK(CalledOnValidThread());
    202   if (client_)
    203     client_->DismissPictureBuffer(picture_buffer_id);
    204 }
    205 
    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 
    215 void GpuVideoDecodeAcceleratorHost::OnFlushDone() {
    216   DCHECK(CalledOnValidThread());
    217   if (client_)
    218     client_->NotifyFlushDone();
    219 }
    220 
    221 void GpuVideoDecodeAcceleratorHost::OnResetDone() {
    222   DCHECK(CalledOnValidThread());
    223   if (client_)
    224     client_->NotifyResetDone();
    225 }
    226 
    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