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