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