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 "ppapi/proxy/ppb_video_decoder_proxy.h" 6 7 #include "base/logging.h" 8 #include "gpu/command_buffer/client/gles2_implementation.h" 9 #include "ppapi/proxy/enter_proxy.h" 10 #include "ppapi/proxy/plugin_dispatcher.h" 11 #include "ppapi/proxy/ppapi_messages.h" 12 #include "ppapi/proxy/ppb_buffer_proxy.h" 13 #include "ppapi/proxy/ppb_graphics_3d_proxy.h" 14 #include "ppapi/thunk/enter.h" 15 #include "ppapi/thunk/resource_creation_api.h" 16 #include "ppapi/thunk/thunk.h" 17 18 using ppapi::thunk::EnterResourceNoLock; 19 using ppapi::thunk::PPB_Buffer_API; 20 using ppapi::thunk::PPB_Graphics3D_API; 21 using ppapi::thunk::PPB_VideoDecoder_API; 22 23 namespace ppapi { 24 namespace proxy { 25 26 class VideoDecoder : public PPB_VideoDecoder_Shared { 27 public: 28 // You must call Init() before using this class. 29 explicit VideoDecoder(const HostResource& resource); 30 virtual ~VideoDecoder(); 31 32 static VideoDecoder* Create(const HostResource& resource, 33 PP_Resource graphics_context, 34 PP_VideoDecoder_Profile profile); 35 36 // PPB_VideoDecoder_API implementation. 37 virtual int32_t Decode(const PP_VideoBitstreamBuffer_Dev* bitstream_buffer, 38 scoped_refptr<TrackedCallback> callback) OVERRIDE; 39 virtual void AssignPictureBuffers( 40 uint32_t no_of_buffers, const PP_PictureBuffer_Dev* buffers) OVERRIDE; 41 virtual void ReusePictureBuffer(int32_t picture_buffer_id) OVERRIDE; 42 virtual int32_t Flush(scoped_refptr<TrackedCallback> callback) OVERRIDE; 43 virtual int32_t Reset(scoped_refptr<TrackedCallback> callback) OVERRIDE; 44 virtual void Destroy() OVERRIDE; 45 46 private: 47 friend class PPB_VideoDecoder_Proxy; 48 49 PluginDispatcher* GetDispatcher() const; 50 51 // Run the callbacks that were passed into the plugin interface. 52 void FlushACK(int32_t result); 53 void ResetACK(int32_t result); 54 void EndOfBitstreamACK(int32_t buffer_id, int32_t result); 55 56 DISALLOW_COPY_AND_ASSIGN(VideoDecoder); 57 }; 58 59 VideoDecoder::VideoDecoder(const HostResource& decoder) 60 : PPB_VideoDecoder_Shared(decoder) { 61 } 62 63 VideoDecoder::~VideoDecoder() { 64 FlushCommandBuffer(); 65 PPB_VideoDecoder_Shared::Destroy(); 66 } 67 68 int32_t VideoDecoder::Decode( 69 const PP_VideoBitstreamBuffer_Dev* bitstream_buffer, 70 scoped_refptr<TrackedCallback> callback) { 71 EnterResourceNoLock<PPB_Buffer_API> 72 enter_buffer(bitstream_buffer->data, true); 73 if (enter_buffer.failed()) 74 return PP_ERROR_BADRESOURCE; 75 76 if (!SetBitstreamBufferCallback(bitstream_buffer->id, callback)) 77 return PP_ERROR_BADARGUMENT; 78 79 Buffer* ppb_buffer = 80 static_cast<Buffer*>(enter_buffer.object()); 81 HostResource host_buffer = ppb_buffer->host_resource(); 82 83 FlushCommandBuffer(); 84 GetDispatcher()->Send(new PpapiHostMsg_PPBVideoDecoder_Decode( 85 API_ID_PPB_VIDEO_DECODER_DEV, host_resource(), 86 host_buffer, bitstream_buffer->id, 87 bitstream_buffer->size)); 88 return PP_OK_COMPLETIONPENDING; 89 } 90 91 void VideoDecoder::AssignPictureBuffers(uint32_t no_of_buffers, 92 const PP_PictureBuffer_Dev* buffers) { 93 std::vector<PP_PictureBuffer_Dev> buffer_list( 94 buffers, buffers + no_of_buffers); 95 FlushCommandBuffer(); 96 GetDispatcher()->Send( 97 new PpapiHostMsg_PPBVideoDecoder_AssignPictureBuffers( 98 API_ID_PPB_VIDEO_DECODER_DEV, host_resource(), buffer_list)); 99 } 100 101 void VideoDecoder::ReusePictureBuffer(int32_t picture_buffer_id) { 102 FlushCommandBuffer(); 103 GetDispatcher()->Send(new PpapiHostMsg_PPBVideoDecoder_ReusePictureBuffer( 104 API_ID_PPB_VIDEO_DECODER_DEV, host_resource(), picture_buffer_id)); 105 } 106 107 int32_t VideoDecoder::Flush(scoped_refptr<TrackedCallback> callback) { 108 if (!SetFlushCallback(callback)) 109 return PP_ERROR_INPROGRESS; 110 111 FlushCommandBuffer(); 112 GetDispatcher()->Send(new PpapiHostMsg_PPBVideoDecoder_Flush( 113 API_ID_PPB_VIDEO_DECODER_DEV, host_resource())); 114 return PP_OK_COMPLETIONPENDING; 115 } 116 117 int32_t VideoDecoder::Reset(scoped_refptr<TrackedCallback> callback) { 118 if (!SetResetCallback(callback)) 119 return PP_ERROR_INPROGRESS; 120 121 FlushCommandBuffer(); 122 GetDispatcher()->Send(new PpapiHostMsg_PPBVideoDecoder_Reset( 123 API_ID_PPB_VIDEO_DECODER_DEV, host_resource())); 124 return PP_OK_COMPLETIONPENDING; 125 } 126 127 void VideoDecoder::Destroy() { 128 FlushCommandBuffer(); 129 GetDispatcher()->Send(new PpapiHostMsg_PPBVideoDecoder_Destroy( 130 API_ID_PPB_VIDEO_DECODER_DEV, host_resource())); 131 PPB_VideoDecoder_Shared::Destroy(); 132 } 133 134 PluginDispatcher* VideoDecoder::GetDispatcher() const { 135 return PluginDispatcher::GetForResource(this); 136 } 137 138 void VideoDecoder::ResetACK(int32_t result) { 139 RunResetCallback(result); 140 } 141 142 void VideoDecoder::FlushACK(int32_t result) { 143 RunFlushCallback(result); 144 } 145 146 void VideoDecoder::EndOfBitstreamACK( 147 int32_t bitstream_buffer_id, int32_t result) { 148 RunBitstreamBufferCallback(bitstream_buffer_id, result); 149 } 150 151 PPB_VideoDecoder_Proxy::PPB_VideoDecoder_Proxy(Dispatcher* dispatcher) 152 : InterfaceProxy(dispatcher), 153 callback_factory_(this) { 154 } 155 156 PPB_VideoDecoder_Proxy::~PPB_VideoDecoder_Proxy() { 157 } 158 159 bool PPB_VideoDecoder_Proxy::OnMessageReceived(const IPC::Message& msg) { 160 if (!dispatcher()->permissions().HasPermission(PERMISSION_DEV)) 161 return false; 162 163 bool handled = true; 164 IPC_BEGIN_MESSAGE_MAP(PPB_VideoDecoder_Proxy, msg) 165 IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBVideoDecoder_Create, 166 OnMsgCreate) 167 IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBVideoDecoder_Decode, OnMsgDecode) 168 IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBVideoDecoder_AssignPictureBuffers, 169 OnMsgAssignPictureBuffers) 170 IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBVideoDecoder_ReusePictureBuffer, 171 OnMsgReusePictureBuffer) 172 IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBVideoDecoder_Flush, OnMsgFlush) 173 IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBVideoDecoder_Reset, OnMsgReset) 174 IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBVideoDecoder_Destroy, OnMsgDestroy) 175 IPC_MESSAGE_HANDLER(PpapiMsg_PPBVideoDecoder_ResetACK, OnMsgResetACK) 176 IPC_MESSAGE_HANDLER(PpapiMsg_PPBVideoDecoder_EndOfBitstreamACK, 177 OnMsgEndOfBitstreamACK) 178 IPC_MESSAGE_HANDLER(PpapiMsg_PPBVideoDecoder_FlushACK, OnMsgFlushACK) 179 IPC_MESSAGE_UNHANDLED(handled = false) 180 IPC_END_MESSAGE_MAP() 181 DCHECK(handled); 182 return handled; 183 } 184 185 PP_Resource PPB_VideoDecoder_Proxy::CreateProxyResource( 186 PP_Instance instance, 187 PP_Resource graphics_context, 188 PP_VideoDecoder_Profile profile) { 189 PluginDispatcher* dispatcher = PluginDispatcher::GetForInstance(instance); 190 // Dispatcher is null if it cannot find the instance passed to it (i.e. if the 191 // client passes in an invalid instance). 192 if (!dispatcher) 193 return 0; 194 195 EnterResourceNoLock<PPB_Graphics3D_API> enter_context(graphics_context, 196 true); 197 if (enter_context.failed()) 198 return 0; 199 200 Graphics3D* context = static_cast<Graphics3D*>(enter_context.object()); 201 202 HostResource result; 203 dispatcher->Send(new PpapiHostMsg_PPBVideoDecoder_Create( 204 API_ID_PPB_VIDEO_DECODER_DEV, instance, 205 context->host_resource(), profile, &result)); 206 if (result.is_null()) 207 return 0; 208 209 // Need a scoped_refptr to keep the object alive during the Init call. 210 scoped_refptr<VideoDecoder> decoder(new VideoDecoder(result)); 211 decoder->InitCommon(graphics_context, context->gles2_impl()); 212 return decoder->GetReference(); 213 } 214 215 void PPB_VideoDecoder_Proxy::OnMsgCreate( 216 PP_Instance instance, const HostResource& graphics_context, 217 PP_VideoDecoder_Profile profile, 218 HostResource* result) { 219 thunk::EnterResourceCreation resource_creation(instance); 220 if (resource_creation.failed()) 221 return; 222 223 // Make the resource and get the API pointer to its interface. 224 result->SetHostResource( 225 instance, resource_creation.functions()->CreateVideoDecoder( 226 instance, graphics_context.host_resource(), profile)); 227 } 228 229 void PPB_VideoDecoder_Proxy::OnMsgDecode( 230 const HostResource& decoder, 231 const HostResource& buffer, int32 id, uint32 size) { 232 EnterHostFromHostResourceForceCallback<PPB_VideoDecoder_API> enter( 233 decoder, callback_factory_, 234 &PPB_VideoDecoder_Proxy::SendMsgEndOfBitstreamACKToPlugin, decoder, id); 235 if (enter.failed()) 236 return; 237 PP_VideoBitstreamBuffer_Dev bitstream = { id, buffer.host_resource(), size }; 238 enter.SetResult(enter.object()->Decode(&bitstream, enter.callback())); 239 } 240 241 void PPB_VideoDecoder_Proxy::OnMsgAssignPictureBuffers( 242 const HostResource& decoder, 243 const std::vector<PP_PictureBuffer_Dev>& buffers) { 244 EnterHostFromHostResource<PPB_VideoDecoder_API> enter(decoder); 245 if (enter.succeeded() && !buffers.empty()) { 246 const PP_PictureBuffer_Dev* buffer_array = &buffers.front(); 247 enter.object()->AssignPictureBuffers(buffers.size(), buffer_array); 248 } 249 } 250 251 void PPB_VideoDecoder_Proxy::OnMsgReusePictureBuffer( 252 const HostResource& decoder, int32 picture_buffer_id) { 253 EnterHostFromHostResource<PPB_VideoDecoder_API> enter(decoder); 254 if (enter.succeeded()) 255 enter.object()->ReusePictureBuffer(picture_buffer_id); 256 } 257 258 void PPB_VideoDecoder_Proxy::OnMsgFlush(const HostResource& decoder) { 259 EnterHostFromHostResourceForceCallback<PPB_VideoDecoder_API> enter( 260 decoder, callback_factory_, 261 &PPB_VideoDecoder_Proxy::SendMsgFlushACKToPlugin, decoder); 262 if (enter.succeeded()) 263 enter.SetResult(enter.object()->Flush(enter.callback())); 264 } 265 266 void PPB_VideoDecoder_Proxy::OnMsgReset(const HostResource& decoder) { 267 EnterHostFromHostResourceForceCallback<PPB_VideoDecoder_API> enter( 268 decoder, callback_factory_, 269 &PPB_VideoDecoder_Proxy::SendMsgResetACKToPlugin, decoder); 270 if (enter.succeeded()) 271 enter.SetResult(enter.object()->Reset(enter.callback())); 272 } 273 274 void PPB_VideoDecoder_Proxy::OnMsgDestroy(const HostResource& decoder) { 275 EnterHostFromHostResource<PPB_VideoDecoder_API> enter(decoder); 276 if (enter.succeeded()) 277 enter.object()->Destroy(); 278 } 279 280 void PPB_VideoDecoder_Proxy::SendMsgEndOfBitstreamACKToPlugin( 281 int32_t result, const HostResource& decoder, int32 id) { 282 dispatcher()->Send(new PpapiMsg_PPBVideoDecoder_EndOfBitstreamACK( 283 API_ID_PPB_VIDEO_DECODER_DEV, decoder, id, result)); 284 } 285 286 void PPB_VideoDecoder_Proxy::SendMsgFlushACKToPlugin( 287 int32_t result, const HostResource& decoder) { 288 dispatcher()->Send(new PpapiMsg_PPBVideoDecoder_FlushACK( 289 API_ID_PPB_VIDEO_DECODER_DEV, decoder, result)); 290 } 291 292 void PPB_VideoDecoder_Proxy::SendMsgResetACKToPlugin( 293 int32_t result, const HostResource& decoder) { 294 dispatcher()->Send(new PpapiMsg_PPBVideoDecoder_ResetACK( 295 API_ID_PPB_VIDEO_DECODER_DEV, decoder, result)); 296 } 297 298 void PPB_VideoDecoder_Proxy::OnMsgEndOfBitstreamACK( 299 const HostResource& decoder, int32_t id, int32_t result) { 300 EnterPluginFromHostResource<PPB_VideoDecoder_API> enter(decoder); 301 if (enter.succeeded()) 302 static_cast<VideoDecoder*>(enter.object())->EndOfBitstreamACK(id, result); 303 } 304 305 void PPB_VideoDecoder_Proxy::OnMsgFlushACK( 306 const HostResource& decoder, int32_t result) { 307 EnterPluginFromHostResource<PPB_VideoDecoder_API> enter(decoder); 308 if (enter.succeeded()) 309 static_cast<VideoDecoder*>(enter.object())->FlushACK(result); 310 } 311 312 void PPB_VideoDecoder_Proxy::OnMsgResetACK( 313 const HostResource& decoder, int32_t result) { 314 EnterPluginFromHostResource<PPB_VideoDecoder_API> enter(decoder); 315 if (enter.succeeded()) 316 static_cast<VideoDecoder*>(enter.object())->ResetACK(result); 317 } 318 319 } // namespace proxy 320 } // namespace ppapi 321