[email protected] | dfb0d06f3 | 2014-05-30 22:45:56 | [diff] [blame] | 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/video_decoder_resource.h" |
| 6 | |
| 7 | #include "base/bind.h" |
| 8 | #include "gpu/command_buffer/client/gles2_cmd_helper.h" |
| 9 | #include "gpu/command_buffer/client/gles2_implementation.h" |
[email protected] | 0ff052d | 2014-06-13 15:00:14 | [diff] [blame] | 10 | #include "gpu/command_buffer/common/mailbox.h" |
[email protected] | dfb0d06f3 | 2014-05-30 22:45:56 | [diff] [blame] | 11 | #include "ipc/ipc_message.h" |
| 12 | #include "ppapi/c/pp_errors.h" |
| 13 | #include "ppapi/c/ppb_opengles2.h" |
| 14 | #include "ppapi/proxy/plugin_dispatcher.h" |
| 15 | #include "ppapi/proxy/ppapi_messages.h" |
| 16 | #include "ppapi/proxy/ppb_graphics_3d_proxy.h" |
| 17 | #include "ppapi/proxy/serialized_handle.h" |
| 18 | #include "ppapi/proxy/video_decoder_constants.h" |
| 19 | #include "ppapi/shared_impl/ppapi_globals.h" |
| 20 | #include "ppapi/shared_impl/ppb_graphics_3d_shared.h" |
| 21 | #include "ppapi/shared_impl/proxy_lock.h" |
| 22 | #include "ppapi/shared_impl/resource_tracker.h" |
| 23 | #include "ppapi/thunk/enter.h" |
| 24 | |
| 25 | using ppapi::thunk::EnterResourceNoLock; |
| 26 | using ppapi::thunk::PPB_Graphics3D_API; |
| 27 | using ppapi::thunk::PPB_VideoDecoder_API; |
| 28 | |
| 29 | namespace ppapi { |
| 30 | namespace proxy { |
| 31 | |
| 32 | VideoDecoderResource::ShmBuffer::ShmBuffer( |
| 33 | scoped_ptr<base::SharedMemory> shm_ptr, |
| 34 | uint32_t size, |
| 35 | uint32_t shm_id) |
| 36 | : shm(shm_ptr.Pass()), addr(NULL), shm_id(shm_id) { |
| 37 | if (shm->Map(size)) |
| 38 | addr = shm->memory(); |
| 39 | } |
| 40 | |
| 41 | VideoDecoderResource::ShmBuffer::~ShmBuffer() { |
| 42 | } |
| 43 | |
| 44 | VideoDecoderResource::Texture::Texture(uint32_t texture_target, |
| 45 | const PP_Size& size) |
| 46 | : texture_target(texture_target), size(size) { |
| 47 | } |
| 48 | |
| 49 | VideoDecoderResource::Texture::~Texture() { |
| 50 | } |
| 51 | |
Bill Budge | 2d4bf3a | 2014-11-06 22:31:21 | [diff] [blame] | 52 | VideoDecoderResource::Picture::Picture(int32_t decode_id, |
| 53 | uint32_t texture_id, |
| 54 | const PP_Rect& visible_rect) |
| 55 | : decode_id(decode_id), texture_id(texture_id), visible_rect(visible_rect) { |
[email protected] | dfb0d06f3 | 2014-05-30 22:45:56 | [diff] [blame] | 56 | } |
| 57 | |
| 58 | VideoDecoderResource::Picture::~Picture() { |
| 59 | } |
| 60 | |
| 61 | VideoDecoderResource::VideoDecoderResource(Connection connection, |
| 62 | PP_Instance instance) |
| 63 | : PluginResource(connection, instance), |
| 64 | num_decodes_(0), |
lpique | 9dd55e54 | 2015-08-20 01:06:53 | [diff] [blame^] | 65 | min_picture_count_(0), |
[email protected] | dfb0d06f3 | 2014-05-30 22:45:56 | [diff] [blame] | 66 | get_picture_(NULL), |
Bill Budge | 2d4bf3a | 2014-11-06 22:31:21 | [diff] [blame] | 67 | get_picture_0_1_(NULL), |
[email protected] | dfb0d06f3 | 2014-05-30 22:45:56 | [diff] [blame] | 68 | gles2_impl_(NULL), |
| 69 | initialized_(false), |
| 70 | testing_(false), |
| 71 | // Set |decoder_last_error_| to PP_OK after successful initialization. |
| 72 | // This makes error checking a little more concise, since we can check |
| 73 | // that the decoder has been initialized and hasn't returned an error by |
| 74 | // just testing |decoder_last_error_|. |
| 75 | decoder_last_error_(PP_ERROR_FAILED) { |
| 76 | // Clear the decode_ids_ array. |
tsepez | e9faf30 | 2015-03-21 07:48:29 | [diff] [blame] | 77 | memset(decode_ids_, 0, sizeof(decode_ids_)); |
[email protected] | dfb0d06f3 | 2014-05-30 22:45:56 | [diff] [blame] | 78 | SendCreate(RENDERER, PpapiHostMsg_VideoDecoder_Create()); |
| 79 | } |
| 80 | |
| 81 | VideoDecoderResource::~VideoDecoderResource() { |
| 82 | // Destroy any textures which haven't been dismissed. |
| 83 | TextureMap::iterator it = textures_.begin(); |
| 84 | for (; it != textures_.end(); ++it) |
| 85 | DeleteGLTexture(it->first); |
| 86 | } |
| 87 | |
| 88 | PPB_VideoDecoder_API* VideoDecoderResource::AsPPB_VideoDecoder_API() { |
| 89 | return this; |
| 90 | } |
| 91 | |
bbudge | 4d6acaf | 2014-08-23 22:17:45 | [diff] [blame] | 92 | int32_t VideoDecoderResource::Initialize0_1( |
[email protected] | dfb0d06f3 | 2014-05-30 22:45:56 | [diff] [blame] | 93 | PP_Resource graphics_context, |
| 94 | PP_VideoProfile profile, |
| 95 | PP_Bool allow_software_fallback, |
| 96 | scoped_refptr<TrackedCallback> callback) { |
bbudge | 4d6acaf | 2014-08-23 22:17:45 | [diff] [blame] | 97 | return Initialize(graphics_context, |
| 98 | profile, |
| 99 | allow_software_fallback |
| 100 | ? PP_HARDWAREACCELERATION_WITHFALLBACK |
| 101 | : PP_HARDWAREACCELERATION_ONLY, |
lpique | 9dd55e54 | 2015-08-20 01:06:53 | [diff] [blame^] | 102 | 0, |
| 103 | callback); |
| 104 | } |
| 105 | |
| 106 | int32_t VideoDecoderResource::Initialize0_2( |
| 107 | PP_Resource graphics_context, |
| 108 | PP_VideoProfile profile, |
| 109 | PP_HardwareAcceleration acceleration, |
| 110 | scoped_refptr<TrackedCallback> callback) { |
| 111 | return Initialize(graphics_context, |
| 112 | profile, |
| 113 | acceleration, |
| 114 | 0, |
bbudge | 4d6acaf | 2014-08-23 22:17:45 | [diff] [blame] | 115 | callback); |
| 116 | } |
| 117 | |
| 118 | int32_t VideoDecoderResource::Initialize( |
| 119 | PP_Resource graphics_context, |
| 120 | PP_VideoProfile profile, |
| 121 | PP_HardwareAcceleration acceleration, |
lpique | 9dd55e54 | 2015-08-20 01:06:53 | [diff] [blame^] | 122 | uint32_t min_picture_count, |
bbudge | 4d6acaf | 2014-08-23 22:17:45 | [diff] [blame] | 123 | scoped_refptr<TrackedCallback> callback) { |
[email protected] | dfb0d06f3 | 2014-05-30 22:45:56 | [diff] [blame] | 124 | if (initialized_) |
| 125 | return PP_ERROR_FAILED; |
| 126 | if (profile < 0 || profile > PP_VIDEOPROFILE_MAX) |
| 127 | return PP_ERROR_BADARGUMENT; |
lpique | 9dd55e54 | 2015-08-20 01:06:53 | [diff] [blame^] | 128 | if (min_picture_count > kMaximumPictureCount) |
| 129 | return PP_ERROR_BADARGUMENT; |
Daniel Cheng | 6d3ae97 | 2014-08-26 00:27:38 | [diff] [blame] | 130 | if (initialize_callback_.get()) |
[email protected] | dfb0d06f3 | 2014-05-30 22:45:56 | [diff] [blame] | 131 | return PP_ERROR_INPROGRESS; |
| 132 | if (!graphics_context) |
| 133 | return PP_ERROR_BADRESOURCE; |
| 134 | |
lpique | 9dd55e54 | 2015-08-20 01:06:53 | [diff] [blame^] | 135 | min_picture_count_ = min_picture_count; |
| 136 | |
[email protected] | dfb0d06f3 | 2014-05-30 22:45:56 | [diff] [blame] | 137 | HostResource host_resource; |
| 138 | if (!testing_) { |
| 139 | // Create a new Graphics3D resource that can create texture resources to |
| 140 | // share with the plugin. We can't use the plugin's Graphics3D, since we |
| 141 | // create textures on a proxy thread, and would interfere with the plugin. |
| 142 | thunk::EnterResourceCreationNoLock enter_create(pp_instance()); |
| 143 | if (enter_create.failed()) |
| 144 | return PP_ERROR_FAILED; |
| 145 | int32_t attrib_list[] = {PP_GRAPHICS3DATTRIB_NONE}; |
| 146 | graphics3d_ = |
| 147 | ScopedPPResource(ScopedPPResource::PassRef(), |
| 148 | enter_create.functions()->CreateGraphics3D( |
| 149 | pp_instance(), graphics_context, attrib_list)); |
| 150 | EnterResourceNoLock<PPB_Graphics3D_API> enter_graphics(graphics3d_.get(), |
[email protected] | 0ff052d | 2014-06-13 15:00:14 | [diff] [blame] | 151 | false); |
[email protected] | dfb0d06f3 | 2014-05-30 22:45:56 | [diff] [blame] | 152 | if (enter_graphics.failed()) |
| 153 | return PP_ERROR_BADRESOURCE; |
| 154 | |
| 155 | PPB_Graphics3D_Shared* ppb_graphics3d_shared = |
| 156 | static_cast<PPB_Graphics3D_Shared*>(enter_graphics.object()); |
| 157 | gles2_impl_ = ppb_graphics3d_shared->gles2_impl(); |
| 158 | host_resource = ppb_graphics3d_shared->host_resource(); |
| 159 | } |
| 160 | |
| 161 | initialize_callback_ = callback; |
| 162 | |
| 163 | Call<PpapiPluginMsg_VideoDecoder_InitializeReply>( |
| 164 | RENDERER, |
| 165 | PpapiHostMsg_VideoDecoder_Initialize( |
lpique | 9dd55e54 | 2015-08-20 01:06:53 | [diff] [blame^] | 166 | host_resource, profile, acceleration, min_picture_count), |
[email protected] | dfb0d06f3 | 2014-05-30 22:45:56 | [diff] [blame] | 167 | base::Bind(&VideoDecoderResource::OnPluginMsgInitializeComplete, this)); |
| 168 | |
| 169 | return PP_OK_COMPLETIONPENDING; |
| 170 | } |
| 171 | |
| 172 | int32_t VideoDecoderResource::Decode(uint32_t decode_id, |
| 173 | uint32_t size, |
| 174 | const void* buffer, |
| 175 | scoped_refptr<TrackedCallback> callback) { |
| 176 | if (decoder_last_error_) |
| 177 | return decoder_last_error_; |
Daniel Cheng | 6d3ae97 | 2014-08-26 00:27:38 | [diff] [blame] | 178 | if (flush_callback_.get() || reset_callback_.get()) |
[email protected] | dfb0d06f3 | 2014-05-30 22:45:56 | [diff] [blame] | 179 | return PP_ERROR_FAILED; |
Daniel Cheng | 6d3ae97 | 2014-08-26 00:27:38 | [diff] [blame] | 180 | if (decode_callback_.get()) |
[email protected] | dfb0d06f3 | 2014-05-30 22:45:56 | [diff] [blame] | 181 | return PP_ERROR_INPROGRESS; |
| 182 | if (size > kMaximumBitstreamBufferSize) |
| 183 | return PP_ERROR_NOMEMORY; |
| 184 | |
| 185 | // If we allow the plugin to call Decode again, we must have somewhere to |
| 186 | // copy their buffer. |
| 187 | DCHECK(!available_shm_buffers_.empty() || |
| 188 | shm_buffers_.size() < kMaximumPendingDecodes); |
| 189 | |
| 190 | // Count up, wrapping back to 0 before overflowing. |
| 191 | int32_t uid = ++num_decodes_; |
| 192 | if (uid == std::numeric_limits<int32_t>::max()) |
| 193 | num_decodes_ = 0; |
| 194 | |
| 195 | // Save decode_id in a ring buffer. The ring buffer is sized to store |
| 196 | // decode_id for the maximum picture delay. |
| 197 | decode_ids_[uid % kMaximumPictureDelay] = decode_id; |
| 198 | |
| 199 | if (available_shm_buffers_.empty() || |
| 200 | available_shm_buffers_.back()->shm->mapped_size() < size) { |
| 201 | uint32_t shm_id; |
| 202 | if (shm_buffers_.size() < kMaximumPendingDecodes) { |
| 203 | // Signal the host to create a new shm buffer by passing an index outside |
| 204 | // the legal range. |
| 205 | shm_id = static_cast<uint32_t>(shm_buffers_.size()); |
| 206 | } else { |
| 207 | // Signal the host to grow a buffer by passing a legal index. Choose the |
| 208 | // last available shm buffer for simplicity. |
| 209 | shm_id = available_shm_buffers_.back()->shm_id; |
| 210 | available_shm_buffers_.pop_back(); |
| 211 | } |
| 212 | |
| 213 | // Synchronously get shared memory. Use GenericSyncCall so we can get the |
| 214 | // reply params, which contain the handle. |
| 215 | uint32_t shm_size = 0; |
| 216 | IPC::Message reply; |
| 217 | ResourceMessageReplyParams reply_params; |
| 218 | int32_t result = |
| 219 | GenericSyncCall(RENDERER, |
| 220 | PpapiHostMsg_VideoDecoder_GetShm(shm_id, size), |
| 221 | &reply, |
| 222 | &reply_params); |
| 223 | if (result != PP_OK) |
| 224 | return PP_ERROR_FAILED; |
| 225 | if (!UnpackMessage<PpapiPluginMsg_VideoDecoder_GetShmReply>(reply, |
| 226 | &shm_size)) |
| 227 | return PP_ERROR_FAILED; |
| 228 | base::SharedMemoryHandle shm_handle = base::SharedMemory::NULLHandle(); |
| 229 | if (!reply_params.TakeSharedMemoryHandleAtIndex(0, &shm_handle)) |
| 230 | return PP_ERROR_NOMEMORY; |
| 231 | scoped_ptr<base::SharedMemory> shm( |
| 232 | new base::SharedMemory(shm_handle, false /* read_only */)); |
| 233 | scoped_ptr<ShmBuffer> shm_buffer( |
| 234 | new ShmBuffer(shm.Pass(), shm_size, shm_id)); |
| 235 | if (!shm_buffer->addr) |
| 236 | return PP_ERROR_NOMEMORY; |
| 237 | |
| 238 | available_shm_buffers_.push_back(shm_buffer.get()); |
| 239 | if (shm_buffers_.size() < kMaximumPendingDecodes) { |
| 240 | shm_buffers_.push_back(shm_buffer.release()); |
| 241 | } else { |
| 242 | // Delete manually since ScopedVector won't delete the existing element if |
| 243 | // we just assign it. |
| 244 | delete shm_buffers_[shm_id]; |
| 245 | shm_buffers_[shm_id] = shm_buffer.release(); |
| 246 | } |
| 247 | } |
| 248 | |
| 249 | // At this point we should have shared memory to hold the plugin's buffer. |
| 250 | DCHECK(!available_shm_buffers_.empty() && |
| 251 | available_shm_buffers_.back()->shm->mapped_size() >= size); |
| 252 | |
| 253 | ShmBuffer* shm_buffer = available_shm_buffers_.back(); |
| 254 | available_shm_buffers_.pop_back(); |
| 255 | memcpy(shm_buffer->addr, buffer, size); |
| 256 | |
| 257 | Call<PpapiPluginMsg_VideoDecoder_DecodeReply>( |
| 258 | RENDERER, |
| 259 | PpapiHostMsg_VideoDecoder_Decode(shm_buffer->shm_id, size, uid), |
| 260 | base::Bind(&VideoDecoderResource::OnPluginMsgDecodeComplete, this)); |
| 261 | |
| 262 | // If we have another free buffer, or we can still create new buffers, let |
| 263 | // the plugin call Decode again. |
| 264 | if (!available_shm_buffers_.empty() || |
| 265 | shm_buffers_.size() < kMaximumPendingDecodes) |
| 266 | return PP_OK; |
| 267 | |
| 268 | // All buffers are busy and we can't create more. Delay completion until a |
| 269 | // buffer is available. |
| 270 | decode_callback_ = callback; |
| 271 | return PP_OK_COMPLETIONPENDING; |
| 272 | } |
| 273 | |
Bill Budge | 2d4bf3a | 2014-11-06 22:31:21 | [diff] [blame] | 274 | int32_t VideoDecoderResource::GetPicture0_1( |
| 275 | PP_VideoPicture_0_1* picture, |
| 276 | scoped_refptr<TrackedCallback> callback) { |
| 277 | get_picture_0_1_ = picture; |
| 278 | return GetPicture(NULL, callback); |
| 279 | } |
| 280 | |
[email protected] | dfb0d06f3 | 2014-05-30 22:45:56 | [diff] [blame] | 281 | int32_t VideoDecoderResource::GetPicture( |
| 282 | PP_VideoPicture* picture, |
| 283 | scoped_refptr<TrackedCallback> callback) { |
| 284 | if (decoder_last_error_) |
| 285 | return decoder_last_error_; |
Daniel Cheng | 6d3ae97 | 2014-08-26 00:27:38 | [diff] [blame] | 286 | if (reset_callback_.get()) |
[email protected] | dfb0d06f3 | 2014-05-30 22:45:56 | [diff] [blame] | 287 | return PP_ERROR_FAILED; |
Daniel Cheng | 6d3ae97 | 2014-08-26 00:27:38 | [diff] [blame] | 288 | if (get_picture_callback_.get()) |
[email protected] | dfb0d06f3 | 2014-05-30 22:45:56 | [diff] [blame] | 289 | return PP_ERROR_INPROGRESS; |
| 290 | |
Bill Budge | 2d4bf3a | 2014-11-06 22:31:21 | [diff] [blame] | 291 | get_picture_ = picture; |
| 292 | |
[email protected] | dfb0d06f3 | 2014-05-30 22:45:56 | [diff] [blame] | 293 | // If the next picture is ready, return it synchronously. |
| 294 | if (!received_pictures_.empty()) { |
Bill Budge | 2d4bf3a | 2014-11-06 22:31:21 | [diff] [blame] | 295 | WriteNextPicture(); |
[email protected] | dfb0d06f3 | 2014-05-30 22:45:56 | [diff] [blame] | 296 | return PP_OK; |
| 297 | } |
| 298 | |
| 299 | get_picture_callback_ = callback; |
Bill Budge | 2d4bf3a | 2014-11-06 22:31:21 | [diff] [blame] | 300 | |
[email protected] | dfb0d06f3 | 2014-05-30 22:45:56 | [diff] [blame] | 301 | return PP_OK_COMPLETIONPENDING; |
| 302 | } |
| 303 | |
| 304 | void VideoDecoderResource::RecyclePicture(const PP_VideoPicture* picture) { |
| 305 | if (decoder_last_error_) |
| 306 | return; |
[email protected] | dfb0d06f3 | 2014-05-30 22:45:56 | [diff] [blame] | 307 | |
| 308 | Post(RENDERER, PpapiHostMsg_VideoDecoder_RecyclePicture(picture->texture_id)); |
| 309 | } |
| 310 | |
| 311 | int32_t VideoDecoderResource::Flush(scoped_refptr<TrackedCallback> callback) { |
| 312 | if (decoder_last_error_) |
| 313 | return decoder_last_error_; |
Daniel Cheng | 6d3ae97 | 2014-08-26 00:27:38 | [diff] [blame] | 314 | if (reset_callback_.get()) |
[email protected] | dfb0d06f3 | 2014-05-30 22:45:56 | [diff] [blame] | 315 | return PP_ERROR_FAILED; |
Daniel Cheng | 6d3ae97 | 2014-08-26 00:27:38 | [diff] [blame] | 316 | if (flush_callback_.get()) |
[email protected] | dfb0d06f3 | 2014-05-30 22:45:56 | [diff] [blame] | 317 | return PP_ERROR_INPROGRESS; |
| 318 | flush_callback_ = callback; |
| 319 | |
| 320 | Call<PpapiPluginMsg_VideoDecoder_FlushReply>( |
| 321 | RENDERER, |
| 322 | PpapiHostMsg_VideoDecoder_Flush(), |
| 323 | base::Bind(&VideoDecoderResource::OnPluginMsgFlushComplete, this)); |
| 324 | |
| 325 | return PP_OK_COMPLETIONPENDING; |
| 326 | } |
| 327 | |
| 328 | int32_t VideoDecoderResource::Reset(scoped_refptr<TrackedCallback> callback) { |
| 329 | if (decoder_last_error_) |
| 330 | return decoder_last_error_; |
Daniel Cheng | 6d3ae97 | 2014-08-26 00:27:38 | [diff] [blame] | 331 | if (flush_callback_.get()) |
[email protected] | dfb0d06f3 | 2014-05-30 22:45:56 | [diff] [blame] | 332 | return PP_ERROR_FAILED; |
Daniel Cheng | 6d3ae97 | 2014-08-26 00:27:38 | [diff] [blame] | 333 | if (reset_callback_.get()) |
[email protected] | dfb0d06f3 | 2014-05-30 22:45:56 | [diff] [blame] | 334 | return PP_ERROR_INPROGRESS; |
| 335 | reset_callback_ = callback; |
| 336 | |
| 337 | // Cause any pending Decode or GetPicture callbacks to abort after we return, |
| 338 | // to avoid reentering the plugin. |
| 339 | if (TrackedCallback::IsPending(decode_callback_)) |
| 340 | decode_callback_->PostAbort(); |
| 341 | decode_callback_ = NULL; |
| 342 | if (TrackedCallback::IsPending(get_picture_callback_)) |
| 343 | get_picture_callback_->PostAbort(); |
| 344 | get_picture_callback_ = NULL; |
| 345 | Call<PpapiPluginMsg_VideoDecoder_ResetReply>( |
| 346 | RENDERER, |
| 347 | PpapiHostMsg_VideoDecoder_Reset(), |
| 348 | base::Bind(&VideoDecoderResource::OnPluginMsgResetComplete, this)); |
| 349 | |
| 350 | return PP_OK_COMPLETIONPENDING; |
| 351 | } |
| 352 | |
| 353 | void VideoDecoderResource::OnReplyReceived( |
| 354 | const ResourceMessageReplyParams& params, |
| 355 | const IPC::Message& msg) { |
| 356 | PPAPI_BEGIN_MESSAGE_MAP(VideoDecoderResource, msg) |
| 357 | PPAPI_DISPATCH_PLUGIN_RESOURCE_CALL( |
| 358 | PpapiPluginMsg_VideoDecoder_RequestTextures, OnPluginMsgRequestTextures) |
| 359 | PPAPI_DISPATCH_PLUGIN_RESOURCE_CALL( |
| 360 | PpapiPluginMsg_VideoDecoder_PictureReady, OnPluginMsgPictureReady) |
| 361 | PPAPI_DISPATCH_PLUGIN_RESOURCE_CALL( |
| 362 | PpapiPluginMsg_VideoDecoder_DismissPicture, OnPluginMsgDismissPicture) |
| 363 | PPAPI_DISPATCH_PLUGIN_RESOURCE_CALL( |
| 364 | PpapiPluginMsg_VideoDecoder_NotifyError, OnPluginMsgNotifyError) |
| 365 | PPAPI_DISPATCH_PLUGIN_RESOURCE_CALL_UNHANDLED( |
| 366 | PluginResource::OnReplyReceived(params, msg)) |
| 367 | PPAPI_END_MESSAGE_MAP() |
| 368 | } |
| 369 | |
| 370 | void VideoDecoderResource::SetForTest() { |
| 371 | testing_ = true; |
| 372 | } |
| 373 | |
| 374 | void VideoDecoderResource::OnPluginMsgRequestTextures( |
| 375 | const ResourceMessageReplyParams& params, |
| 376 | uint32_t num_textures, |
| 377 | const PP_Size& size, |
[email protected] | 0ff052d | 2014-06-13 15:00:14 | [diff] [blame] | 378 | uint32_t texture_target, |
| 379 | const std::vector<gpu::Mailbox>& mailboxes) { |
[email protected] | dfb0d06f3 | 2014-05-30 22:45:56 | [diff] [blame] | 380 | DCHECK(num_textures); |
lpique | 9dd55e54 | 2015-08-20 01:06:53 | [diff] [blame^] | 381 | DCHECK(num_textures >= min_picture_count_); |
[email protected] | 0ff052d | 2014-06-13 15:00:14 | [diff] [blame] | 382 | DCHECK(mailboxes.empty() || mailboxes.size() == num_textures); |
[email protected] | dfb0d06f3 | 2014-05-30 22:45:56 | [diff] [blame] | 383 | std::vector<uint32_t> texture_ids(num_textures); |
| 384 | if (gles2_impl_) { |
| 385 | gles2_impl_->GenTextures(num_textures, &texture_ids.front()); |
| 386 | for (uint32_t i = 0; i < num_textures; ++i) { |
| 387 | gles2_impl_->ActiveTexture(GL_TEXTURE0); |
| 388 | gles2_impl_->BindTexture(texture_target, texture_ids[i]); |
| 389 | gles2_impl_->TexParameteri( |
CodeByThePound | de2d8397 | 2015-04-30 20:41:47 | [diff] [blame] | 390 | texture_target, GL_TEXTURE_MIN_FILTER, GL_LINEAR); |
[email protected] | dfb0d06f3 | 2014-05-30 22:45:56 | [diff] [blame] | 391 | gles2_impl_->TexParameteri( |
CodeByThePound | de2d8397 | 2015-04-30 20:41:47 | [diff] [blame] | 392 | texture_target, GL_TEXTURE_MAG_FILTER, GL_LINEAR); |
[email protected] | dfb0d06f3 | 2014-05-30 22:45:56 | [diff] [blame] | 393 | gles2_impl_->TexParameterf( |
| 394 | texture_target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); |
| 395 | gles2_impl_->TexParameterf( |
| 396 | texture_target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); |
| 397 | |
| 398 | if (texture_target == GL_TEXTURE_2D) { |
| 399 | gles2_impl_->TexImage2D(texture_target, |
| 400 | 0, |
| 401 | GL_RGBA, |
| 402 | size.width, |
| 403 | size.height, |
| 404 | 0, |
| 405 | GL_RGBA, |
| 406 | GL_UNSIGNED_BYTE, |
| 407 | NULL); |
| 408 | } |
[email protected] | 0ff052d | 2014-06-13 15:00:14 | [diff] [blame] | 409 | if (!mailboxes.empty()) { |
| 410 | gles2_impl_->ProduceTextureCHROMIUM( |
| 411 | GL_TEXTURE_2D, reinterpret_cast<const GLbyte*>(mailboxes[i].name)); |
| 412 | } |
[email protected] | dfb0d06f3 | 2014-05-30 22:45:56 | [diff] [blame] | 413 | |
| 414 | textures_.insert( |
| 415 | std::make_pair(texture_ids[i], Texture(texture_target, size))); |
| 416 | } |
| 417 | gles2_impl_->Flush(); |
| 418 | } else { |
| 419 | DCHECK(testing_); |
| 420 | // Create some fake texture ids so we can test picture handling. |
| 421 | for (uint32_t i = 0; i < num_textures; ++i) { |
| 422 | texture_ids[i] = i + 1; |
| 423 | textures_.insert( |
| 424 | std::make_pair(texture_ids[i], Texture(texture_target, size))); |
| 425 | } |
| 426 | } |
| 427 | |
| 428 | Post(RENDERER, PpapiHostMsg_VideoDecoder_AssignTextures(size, texture_ids)); |
| 429 | } |
| 430 | |
| 431 | void VideoDecoderResource::OnPluginMsgPictureReady( |
| 432 | const ResourceMessageReplyParams& params, |
| 433 | int32_t decode_id, |
Bill Budge | 2d4bf3a | 2014-11-06 22:31:21 | [diff] [blame] | 434 | uint32_t texture_id, |
| 435 | const PP_Rect& visible_rect) { |
| 436 | received_pictures_.push(Picture(decode_id, texture_id, visible_rect)); |
[email protected] | dfb0d06f3 | 2014-05-30 22:45:56 | [diff] [blame] | 437 | |
| 438 | if (TrackedCallback::IsPending(get_picture_callback_)) { |
| 439 | // The plugin may call GetPicture in its callback. |
| 440 | scoped_refptr<TrackedCallback> callback; |
| 441 | callback.swap(get_picture_callback_); |
Bill Budge | 2d4bf3a | 2014-11-06 22:31:21 | [diff] [blame] | 442 | WriteNextPicture(); |
[email protected] | dfb0d06f3 | 2014-05-30 22:45:56 | [diff] [blame] | 443 | callback->Run(PP_OK); |
| 444 | } |
| 445 | } |
| 446 | |
| 447 | void VideoDecoderResource::OnPluginMsgDismissPicture( |
| 448 | const ResourceMessageReplyParams& params, |
| 449 | uint32_t texture_id) { |
| 450 | DeleteGLTexture(texture_id); |
| 451 | textures_.erase(texture_id); |
| 452 | } |
| 453 | |
| 454 | void VideoDecoderResource::OnPluginMsgNotifyError( |
| 455 | const ResourceMessageReplyParams& params, |
| 456 | int32_t error) { |
| 457 | decoder_last_error_ = error; |
| 458 | // Cause any pending callbacks to run immediately. Reentrancy isn't a problem, |
| 459 | // since the plugin wasn't calling us. |
| 460 | RunCallbackWithError(&initialize_callback_); |
| 461 | RunCallbackWithError(&decode_callback_); |
| 462 | RunCallbackWithError(&get_picture_callback_); |
| 463 | RunCallbackWithError(&flush_callback_); |
| 464 | RunCallbackWithError(&reset_callback_); |
| 465 | } |
| 466 | |
| 467 | void VideoDecoderResource::OnPluginMsgInitializeComplete( |
| 468 | const ResourceMessageReplyParams& params) { |
| 469 | decoder_last_error_ = params.result(); |
| 470 | if (decoder_last_error_ == PP_OK) |
| 471 | initialized_ = true; |
| 472 | |
| 473 | // Let the plugin call Initialize again from its callback in case of failure. |
| 474 | scoped_refptr<TrackedCallback> callback; |
| 475 | callback.swap(initialize_callback_); |
| 476 | callback->Run(decoder_last_error_); |
| 477 | } |
| 478 | |
| 479 | void VideoDecoderResource::OnPluginMsgDecodeComplete( |
| 480 | const ResourceMessageReplyParams& params, |
| 481 | uint32_t shm_id) { |
| 482 | if (shm_id >= shm_buffers_.size()) { |
| 483 | NOTREACHED(); |
| 484 | return; |
| 485 | } |
| 486 | // Make the shm buffer available. |
| 487 | available_shm_buffers_.push_back(shm_buffers_[shm_id]); |
| 488 | // If the plugin is waiting, let it call Decode again. |
Daniel Cheng | 6d3ae97 | 2014-08-26 00:27:38 | [diff] [blame] | 489 | if (decode_callback_.get()) { |
[email protected] | dfb0d06f3 | 2014-05-30 22:45:56 | [diff] [blame] | 490 | scoped_refptr<TrackedCallback> callback; |
| 491 | callback.swap(decode_callback_); |
| 492 | callback->Run(PP_OK); |
| 493 | } |
| 494 | } |
| 495 | |
| 496 | void VideoDecoderResource::OnPluginMsgFlushComplete( |
| 497 | const ResourceMessageReplyParams& params) { |
| 498 | // All shm buffers should have been made available by now. |
| 499 | DCHECK_EQ(shm_buffers_.size(), available_shm_buffers_.size()); |
| 500 | |
Daniel Cheng | 6d3ae97 | 2014-08-26 00:27:38 | [diff] [blame] | 501 | if (get_picture_callback_.get()) { |
[email protected] | dfb0d06f3 | 2014-05-30 22:45:56 | [diff] [blame] | 502 | scoped_refptr<TrackedCallback> callback; |
| 503 | callback.swap(get_picture_callback_); |
| 504 | callback->Abort(); |
| 505 | } |
| 506 | |
| 507 | scoped_refptr<TrackedCallback> callback; |
| 508 | callback.swap(flush_callback_); |
| 509 | callback->Run(params.result()); |
| 510 | } |
| 511 | |
| 512 | void VideoDecoderResource::OnPluginMsgResetComplete( |
| 513 | const ResourceMessageReplyParams& params) { |
| 514 | // All shm buffers should have been made available by now. |
| 515 | DCHECK_EQ(shm_buffers_.size(), available_shm_buffers_.size()); |
[email protected] | 7ee85d6 | 2014-07-16 20:24:01 | [diff] [blame] | 516 | // Recycle any pictures which haven't been passed to the plugin. |
| 517 | while (!received_pictures_.empty()) { |
| 518 | Post(RENDERER, PpapiHostMsg_VideoDecoder_RecyclePicture( |
| 519 | received_pictures_.front().texture_id)); |
[email protected] | e9fc71c1 | 2014-06-16 22:01:20 | [diff] [blame] | 520 | received_pictures_.pop(); |
[email protected] | 7ee85d6 | 2014-07-16 20:24:01 | [diff] [blame] | 521 | } |
[email protected] | e9fc71c1 | 2014-06-16 22:01:20 | [diff] [blame] | 522 | |
[email protected] | dfb0d06f3 | 2014-05-30 22:45:56 | [diff] [blame] | 523 | scoped_refptr<TrackedCallback> callback; |
| 524 | callback.swap(reset_callback_); |
| 525 | callback->Run(params.result()); |
| 526 | } |
| 527 | |
| 528 | void VideoDecoderResource::RunCallbackWithError( |
| 529 | scoped_refptr<TrackedCallback>* callback) { |
| 530 | if (TrackedCallback::IsPending(*callback)) { |
| 531 | scoped_refptr<TrackedCallback> temp; |
| 532 | callback->swap(temp); |
| 533 | temp->Run(decoder_last_error_); |
| 534 | } |
| 535 | } |
| 536 | |
| 537 | void VideoDecoderResource::DeleteGLTexture(uint32_t id) { |
| 538 | if (gles2_impl_) { |
| 539 | gles2_impl_->DeleteTextures(1, &id); |
| 540 | gles2_impl_->Flush(); |
| 541 | } |
| 542 | } |
| 543 | |
Bill Budge | 2d4bf3a | 2014-11-06 22:31:21 | [diff] [blame] | 544 | void VideoDecoderResource::WriteNextPicture() { |
[email protected] | dfb0d06f3 | 2014-05-30 22:45:56 | [diff] [blame] | 545 | DCHECK(!received_pictures_.empty()); |
| 546 | Picture& picture = received_pictures_.front(); |
Bill Budge | 2d4bf3a | 2014-11-06 22:31:21 | [diff] [blame] | 547 | |
[email protected] | dfb0d06f3 | 2014-05-30 22:45:56 | [diff] [blame] | 548 | // Internally, we identify decodes by a unique id, which the host returns |
| 549 | // to us in the picture. Use this to get the plugin's decode_id. |
Bill Budge | 2d4bf3a | 2014-11-06 22:31:21 | [diff] [blame] | 550 | uint32_t decode_id = decode_ids_[picture.decode_id % kMaximumPictureDelay]; |
| 551 | uint32_t texture_id = picture.texture_id; |
| 552 | uint32_t texture_target = 0; |
| 553 | PP_Size texture_size = PP_MakeSize(0, 0); |
[email protected] | dfb0d06f3 | 2014-05-30 22:45:56 | [diff] [blame] | 554 | TextureMap::iterator it = textures_.find(picture.texture_id); |
| 555 | if (it != textures_.end()) { |
Bill Budge | 2d4bf3a | 2014-11-06 22:31:21 | [diff] [blame] | 556 | texture_target = it->second.texture_target; |
| 557 | texture_size = it->second.size; |
[email protected] | dfb0d06f3 | 2014-05-30 22:45:56 | [diff] [blame] | 558 | } else { |
| 559 | NOTREACHED(); |
| 560 | } |
Bill Budge | 2d4bf3a | 2014-11-06 22:31:21 | [diff] [blame] | 561 | |
| 562 | if (get_picture_) { |
| 563 | DCHECK(!get_picture_0_1_); |
| 564 | get_picture_->decode_id = decode_id; |
| 565 | get_picture_->texture_id = texture_id; |
| 566 | get_picture_->texture_target = texture_target; |
| 567 | get_picture_->texture_size = texture_size; |
| 568 | get_picture_->visible_rect = picture.visible_rect; |
| 569 | get_picture_ = NULL; |
| 570 | } else { |
| 571 | DCHECK(get_picture_0_1_); |
| 572 | get_picture_0_1_->decode_id = decode_id; |
| 573 | get_picture_0_1_->texture_id = texture_id; |
| 574 | get_picture_0_1_->texture_target = texture_target; |
| 575 | get_picture_0_1_->texture_size = texture_size; |
| 576 | get_picture_0_1_ = NULL; |
| 577 | } |
| 578 | |
[email protected] | dfb0d06f3 | 2014-05-30 22:45:56 | [diff] [blame] | 579 | received_pictures_.pop(); |
| 580 | } |
| 581 | |
| 582 | } // namespace proxy |
| 583 | } // namespace ppapi |