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