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