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