Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 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" | |
| 10 #include "gpu/command_buffer/common/mailbox.h" | |
| 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/shared_impl/ppapi_globals.h" | |
| 18 #include "ppapi/shared_impl/ppb_graphics_3d_shared.h" | |
| 19 #include "ppapi/shared_impl/proxy_lock.h" | |
| 20 #include "ppapi/shared_impl/resource_tracker.h" | |
| 21 #include "ppapi/thunk/enter.h" | |
| 22 | |
| 23 using ppapi::thunk::EnterResourceNoLock; | |
| 24 using ppapi::thunk::PPB_Graphics3D_API; | |
| 25 using ppapi::thunk::PPB_VideoDecoder_API; | |
| 26 | |
| 27 namespace { | |
| 28 | |
| 29 // Maximum number of concurrent decodes which can be pending. | |
| 30 const uint32_t kMaximumPendingDecodes = 8; | |
| 31 | |
| 32 // Minimum size of shared-memory buffers we allocate. Make them large since | |
| 33 // we try to reuse them. | |
| 34 const uint32_t kMinimumBitstreamBufferSize = 100 << 10; | |
| 35 | |
| 36 } // namespace | |
| 37 | |
| 38 namespace ppapi { | |
| 39 namespace proxy { | |
| 40 | |
| 41 VideoDecoderResource::ShmBuffer::ShmBuffer(base::SharedMemory* shm, | |
| 42 uint32_t size, | |
| 43 uint32_t shm_id) | |
| 44 : shm_(shm), size_(size), addr_(NULL), shm_id_(shm_id) { | |
| 45 if (shm_->Map(size_)) | |
| 46 addr_ = shm_->memory(); | |
| 47 DCHECK(addr_); | |
|
Tom Sepez
2014/05/08 20:35:07
might want to handle error cases here. I'd suspec
bbudge
2014/05/14 19:35:04
Added a check that Map succeeded below, when we cr
| |
| 48 } | |
| 49 | |
| 50 VideoDecoderResource::ShmBuffer::~ShmBuffer() { | |
| 51 shm_->Unmap(); | |
|
piman
2014/05/08 04:26:04
nit: that's implicit with the destruction.
bbudge
2014/05/14 16:40:41
Done.
| |
| 52 addr_ = NULL; | |
| 53 } | |
| 54 | |
| 55 VideoDecoderResource::Texture::Texture(uint32_t texture_target, | |
| 56 const PP_Size& size) | |
| 57 : texture_target_(texture_target), size_(size) { | |
| 58 } | |
| 59 | |
| 60 VideoDecoderResource::Texture::~Texture() { | |
| 61 } | |
| 62 | |
| 63 VideoDecoderResource::Picture::Picture(int32_t decode_id, uint32_t texture_id) | |
| 64 : decode_id_(decode_id), texture_id_(texture_id) { | |
| 65 } | |
| 66 | |
| 67 VideoDecoderResource::Picture::~Picture() { | |
| 68 } | |
| 69 | |
| 70 VideoDecoderResource::VideoDecoderResource(Connection connection, | |
| 71 PP_Instance instance) | |
| 72 : PluginResource(connection, instance), | |
| 73 decode_id_(0), | |
| 74 decode_size_(0), | |
| 75 decode_buffer_(NULL), | |
| 76 pending_decode_count_(0), | |
| 77 get_shm_buffer_pending_(false), | |
| 78 get_picture_(NULL), | |
| 79 gles2_impl_(NULL), | |
| 80 initialized_(false), | |
| 81 // Set |decoder_last_error_| to PP_OK after successful initialization. | |
| 82 // This makes error checking a little more concise, since we can check | |
| 83 // that the decoder is initialized and hasn't returned an error in one | |
| 84 // comparison. | |
| 85 decoder_last_error_(PP_ERROR_FAILED) { | |
| 86 SendCreate(RENDERER, PpapiHostMsg_VideoDecoder_Create()); | |
| 87 } | |
| 88 | |
| 89 VideoDecoderResource::~VideoDecoderResource() { | |
| 90 FlushCommandBuffer(); | |
| 91 | |
| 92 // Destroy any textures which haven't been dismissed. | |
| 93 TextureMap::iterator it = textures_.begin(); | |
| 94 for (; it != textures_.end(); ++it) | |
| 95 DeleteGLTexture(it->first); | |
| 96 // Release our ref on the graphics resource. | |
| 97 graphics3d_ = NULL; | |
| 98 gles2_impl_ = NULL; | |
| 99 } | |
| 100 | |
| 101 PPB_VideoDecoder_API* VideoDecoderResource::AsPPB_VideoDecoder_API() { | |
| 102 return this; | |
| 103 } | |
| 104 | |
| 105 int32_t VideoDecoderResource::Initialize( | |
| 106 PP_Resource graphics_context, | |
| 107 PP_VideoProfile profile, | |
| 108 PP_Bool allow_software_fallback, | |
| 109 scoped_refptr<TrackedCallback> callback) { | |
| 110 if (initialized_) | |
| 111 return PP_ERROR_FAILED; | |
| 112 if (initialize_callback_) | |
| 113 return PP_ERROR_INPROGRESS; | |
| 114 if (!graphics_context) | |
| 115 return PP_ERROR_BADRESOURCE; | |
| 116 EnterResourceNoLock<PPB_Graphics3D_API> enter_context(graphics_context, true); | |
| 117 if (enter_context.failed()) | |
| 118 return PP_ERROR_BADRESOURCE; | |
| 119 | |
| 120 initialize_callback_ = callback; | |
| 121 | |
| 122 // Take a reference to keep the graphics resource alive for the lifetime of | |
| 123 // this resource. | |
| 124 graphics3d_ = static_cast<PPB_Graphics3D_Shared*>(enter_context.object()); | |
| 125 gles2_impl_ = graphics3d_->gles2_impl(); | |
| 126 | |
| 127 Call<PpapiPluginMsg_VideoDecoder_InitializeReply>( | |
| 128 RENDERER, | |
| 129 PpapiHostMsg_VideoDecoder_Initialize(graphics3d_->host_resource(), | |
| 130 profile, | |
| 131 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 | |
| 148 return TryDecode(decode_id, size, buffer, callback); | |
| 149 } | |
| 150 | |
| 151 int32_t VideoDecoderResource::GetPicture( | |
| 152 PP_VideoPicture* picture, | |
| 153 scoped_refptr<TrackedCallback> callback) { | |
| 154 if (decoder_last_error_) | |
| 155 return decoder_last_error_; | |
| 156 if (reset_callback_) | |
| 157 return PP_ERROR_FAILED; | |
| 158 if (get_picture_callback_) | |
| 159 return PP_ERROR_INPROGRESS; | |
| 160 | |
| 161 // If the next picture is ready, return it synchronously. | |
| 162 if (!received_pictures_.empty()) { | |
| 163 WriteNextPicture(picture); | |
| 164 return PP_OK; | |
| 165 } | |
| 166 | |
| 167 get_picture_callback_ = callback; | |
| 168 get_picture_ = picture; | |
| 169 return PP_OK_COMPLETIONPENDING; | |
| 170 } | |
| 171 | |
| 172 void VideoDecoderResource::RecyclePicture(const PP_VideoPicture* picture) { | |
| 173 if (decoder_last_error_) | |
| 174 return; | |
| 175 if (reset_callback_) | |
| 176 return; | |
| 177 | |
| 178 Post(RENDERER, PpapiHostMsg_VideoDecoder_RecyclePicture(picture->texture_id)); | |
| 179 } | |
| 180 | |
| 181 int32_t VideoDecoderResource::Flush(scoped_refptr<TrackedCallback> callback) { | |
| 182 if (decoder_last_error_) | |
| 183 return decoder_last_error_; | |
| 184 if (reset_callback_) | |
| 185 return PP_ERROR_FAILED; | |
| 186 if (flush_callback_) | |
| 187 return PP_ERROR_INPROGRESS; | |
| 188 flush_callback_ = callback; | |
| 189 | |
| 190 FlushCommandBuffer(); | |
| 191 Call<PpapiPluginMsg_VideoDecoder_FlushReply>( | |
| 192 RENDERER, | |
| 193 PpapiHostMsg_VideoDecoder_Flush(), | |
| 194 base::Bind(&VideoDecoderResource::OnPluginMsgFlushComplete, this)); | |
| 195 | |
| 196 return PP_OK_COMPLETIONPENDING; | |
| 197 } | |
| 198 | |
| 199 int32_t VideoDecoderResource::Reset(scoped_refptr<TrackedCallback> callback) { | |
| 200 if (decoder_last_error_) | |
| 201 return decoder_last_error_; | |
| 202 if (flush_callback_) | |
| 203 return PP_ERROR_FAILED; | |
| 204 if (reset_callback_) | |
| 205 return PP_ERROR_INPROGRESS; | |
| 206 reset_callback_ = callback; | |
| 207 | |
| 208 // Cause any pending Decode or GetPicture callbacks to abort immediately. | |
| 209 // Reentrancy isn't a problem, since all calls fail until Reset completes. | |
| 210 if (TrackedCallback::IsPending(decode_callback_)) | |
| 211 decode_callback_->Abort(); | |
| 212 decode_callback_ = NULL; | |
| 213 if (TrackedCallback::IsPending(get_picture_callback_)) | |
| 214 get_picture_callback_->Abort(); | |
| 215 get_picture_callback_ = NULL; | |
| 216 FlushCommandBuffer(); | |
| 217 Call<PpapiPluginMsg_VideoDecoder_ResetReply>( | |
| 218 RENDERER, | |
| 219 PpapiHostMsg_VideoDecoder_Reset(), | |
| 220 base::Bind(&VideoDecoderResource::OnPluginMsgResetComplete, this)); | |
| 221 | |
| 222 return PP_OK_COMPLETIONPENDING; | |
| 223 } | |
| 224 | |
| 225 void VideoDecoderResource::OnReplyReceived( | |
| 226 const ResourceMessageReplyParams& params, | |
| 227 const IPC::Message& msg) { | |
| 228 IPC_BEGIN_MESSAGE_MAP(VideoDecoderResource, msg) | |
| 229 PPAPI_DISPATCH_PLUGIN_RESOURCE_CALL( | |
| 230 PpapiPluginMsg_VideoDecoder_RequestTextures, OnPluginMsgRequestTextures) | |
| 231 PPAPI_DISPATCH_PLUGIN_RESOURCE_CALL(PpapiPluginMsg_VideoDecoder_PictureReady, | |
| 232 OnPluginMsgPictureReady) | |
| 233 PPAPI_DISPATCH_PLUGIN_RESOURCE_CALL( | |
| 234 PpapiPluginMsg_VideoDecoder_DismissPicture, OnPluginMsgDismissPicture) | |
| 235 PPAPI_DISPATCH_PLUGIN_RESOURCE_CALL(PpapiPluginMsg_VideoDecoder_NotifyError, | |
| 236 OnPluginMsgNotifyError) | |
| 237 PPAPI_DISPATCH_PLUGIN_RESOURCE_CALL_UNHANDLED( | |
| 238 PluginResource::OnReplyReceived(params, msg)) | |
| 239 IPC_END_MESSAGE_MAP() | |
| 240 } | |
| 241 | |
| 242 void VideoDecoderResource::OnPluginMsgRequestTextures( | |
| 243 const ResourceMessageReplyParams& params, | |
| 244 uint32_t num_textures, | |
| 245 PP_Size size, | |
| 246 uint32_t texture_target, | |
| 247 const std::vector<gpu::Mailbox>& mailboxes) { | |
|
Tom Sepez
2014/05/08 20:35:07
Are the mailboxes are supplied by a trusted proces
bbudge
2014/05/14 16:40:41
They are generated by the renderer process. I am r
| |
| 248 std::vector<uint32_t> texture_ids; | |
| 249 for (uint32_t i = 0; i < num_textures; ++i) { | |
| 250 GLuint texture_id; | |
| 251 gles2_impl_->GenTextures(1, &texture_id); | |
|
piman
2014/05/08 04:26:04
It's really better to GenTextures(num_textures, ar
bbudge
2014/05/14 16:40:41
Done.
| |
| 252 | |
| 253 gles2_impl_->ActiveTexture(GL_TEXTURE0); | |
|
bbudge
2014/05/14 19:35:04
piman: Can I move this out of the loop, to after G
| |
| 254 gles2_impl_->BindTexture(texture_target, texture_id); | |
|
piman
2014/05/08 04:26:04
So, these 2 calls modify GL state.
Since this come
bbudge
2014/05/14 16:40:41
I've changed the resource to create its own Graphi
| |
| 255 gles2_impl_->TexParameteri( | |
| 256 texture_target, GL_TEXTURE_MIN_FILTER, GL_NEAREST); | |
| 257 gles2_impl_->TexParameteri( | |
| 258 texture_target, GL_TEXTURE_MAG_FILTER, GL_NEAREST); | |
| 259 gles2_impl_->TexParameterf( | |
| 260 texture_target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); | |
| 261 gles2_impl_->TexParameterf( | |
| 262 texture_target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); | |
| 263 | |
| 264 if (texture_target == GL_TEXTURE_2D) { | |
| 265 gles2_impl_->TexImage2D(texture_target, | |
| 266 0, | |
| 267 GL_RGBA, | |
| 268 size.width, | |
| 269 size.height, | |
| 270 0, | |
| 271 GL_RGBA, | |
| 272 GL_UNSIGNED_BYTE, | |
| 273 NULL); | |
| 274 } | |
| 275 | |
| 276 if (!mailboxes.empty()) | |
|
piman
2014/05/08 04:26:04
We should check somewhere that mailbox.size() == n
bbudge
2014/05/14 16:40:41
Will do in future CL (mailboxes removed for now)
| |
| 277 gles2_impl_->ProduceTextureCHROMIUM(GL_TEXTURE_2D, mailboxes[i].name); | |
| 278 | |
| 279 textures_.insert(std::make_pair(texture_id, Texture(texture_target, size))); | |
| 280 texture_ids.push_back(texture_id); | |
| 281 } | |
| 282 | |
| 283 FlushCommandBuffer(); | |
| 284 | |
| 285 Post(RENDERER, PpapiHostMsg_VideoDecoder_AssignTextures(size, texture_ids)); | |
| 286 } | |
| 287 | |
| 288 void VideoDecoderResource::OnPluginMsgPictureReady( | |
| 289 const ResourceMessageReplyParams& params, | |
| 290 int32_t shm_id, | |
| 291 uint32_t texture_id) { | |
| 292 // This value is inserted in OnPluginMsgDecodeComplete. | |
| 293 uint32_t decode_id = decode_ids_[shm_id]; | |
| 294 received_pictures_.push(Picture(decode_id, texture_id)); | |
| 295 // Get ready to accept another call to GetPicture in the callback. | |
| 296 scoped_refptr<TrackedCallback> callback; | |
| 297 callback.swap(get_picture_callback_); | |
| 298 PP_VideoPicture* picture = get_picture_; | |
| 299 get_picture_ = NULL; | |
| 300 if (TrackedCallback::IsPending(callback)) { | |
| 301 WriteNextPicture(picture); | |
| 302 callback->Run(PP_OK); | |
| 303 } | |
| 304 } | |
| 305 | |
| 306 void VideoDecoderResource::OnPluginMsgDismissPicture( | |
| 307 const ResourceMessageReplyParams& params, | |
| 308 uint32_t texture_id) { | |
| 309 DeleteGLTexture(texture_id); | |
| 310 textures_.erase(texture_id); | |
| 311 } | |
| 312 | |
| 313 void VideoDecoderResource::OnPluginMsgNotifyError( | |
| 314 const ResourceMessageReplyParams& params, | |
| 315 int32_t error) { | |
| 316 decoder_last_error_ = error; | |
| 317 // Cause any pending Decode or GetPicture callbacks to run immediately. | |
| 318 // Reentrancy isn't a problem, since the resource is unusable now. | |
| 319 if (TrackedCallback::IsPending(decode_callback_)) | |
| 320 decode_callback_->Run(decoder_last_error_); | |
| 321 decode_callback_ = NULL; | |
| 322 if (TrackedCallback::IsPending(get_picture_callback_)) | |
| 323 get_picture_callback_->Run(decoder_last_error_); | |
| 324 get_picture_callback_ = NULL; | |
| 325 } | |
| 326 | |
| 327 void VideoDecoderResource::OnPluginMsgInitializeComplete( | |
| 328 const ResourceMessageReplyParams& params) { | |
| 329 decoder_last_error_ = params.result(); | |
| 330 if (decoder_last_error_ == PP_OK) | |
| 331 initialized_ = true; | |
| 332 scoped_refptr<TrackedCallback> callback; | |
| 333 callback.swap(initialize_callback_); | |
| 334 callback->Run(decoder_last_error_); | |
| 335 } | |
| 336 | |
| 337 void VideoDecoderResource::OnPluginMsgGetShmComplete( | |
| 338 const ResourceMessageReplyParams& params, | |
| 339 uint32_t size) { | |
| 340 get_shm_buffer_pending_ = false; | |
| 341 int32_t result = params.result(); | |
| 342 if (result == PP_OK) { | |
| 343 base::SharedMemoryHandle shm_handle = base::SharedMemory::NULLHandle(); | |
| 344 if (!params.TakeSharedMemoryHandleAtIndex(0, &shm_handle)) { | |
| 345 RunDecodeCallback(PP_ERROR_FAILED); | |
| 346 return; | |
| 347 } | |
| 348 uint32_t shm_id = static_cast<uint32_t>(shm_buffers_.size()); | |
| 349 ShmBuffer* shm_buffer = | |
| 350 new ShmBuffer(new base::SharedMemory(shm_handle, false /* read_only */), | |
| 351 size, | |
| 352 shm_id); | |
| 353 shm_buffers_.push_back(shm_buffer); | |
| 354 SendDecodeMessage(shm_id); | |
| 355 RunDecodeCallback(PP_OK); | |
| 356 } | |
| 357 } | |
| 358 | |
| 359 void VideoDecoderResource::OnPluginMsgDecodeComplete( | |
| 360 uint32_t decode_id, | |
| 361 const ResourceMessageReplyParams& params, | |
| 362 uint32_t shm_id) { | |
|
piman
2014/05/08 04:26:04
It makes me a bit uncomfortable to have the shm_id
bbudge
2014/05/14 16:40:41
I must pass the shm_id round trip to identify busy
bbudge
2014/05/14 19:35:04
Just to reiterate, shm_id is the only Id I can cou
| |
| 363 pending_decode_count_--; | |
| 364 available_shm_buffers_.push_back(shm_buffers_[shm_id]); | |
| 365 // Save the user id associated with the Decode now, in case it generates a | |
| 366 // call to OnPluginMsgPictureReady. | |
| 367 decode_ids_[shm_id] = decode_id; | |
|
piman
2014/05/08 04:26:04
Is this ok, to use the shm_id (which is just an in
bbudge
2014/05/14 16:40:41
The decode_id is provided by the plugin, which may
| |
| 368 // If a Decode is pending, and we're not waiting for a shm buffer, attempt | |
| 369 // the Decode again. | |
| 370 if (decode_callback_ && !get_shm_buffer_pending_) { | |
| 371 int32_t result = | |
| 372 TryDecode(decode_id_, decode_size_, decode_buffer_, decode_callback_); | |
| 373 if (result == PP_OK) | |
| 374 RunDecodeCallback(PP_OK); | |
| 375 } | |
| 376 } | |
| 377 | |
| 378 void VideoDecoderResource::OnPluginMsgFlushComplete( | |
| 379 const ResourceMessageReplyParams& params) { | |
| 380 if (get_picture_callback_) { | |
| 381 scoped_refptr<TrackedCallback> callback; | |
| 382 callback.swap(get_picture_callback_); | |
| 383 callback->Abort(); | |
| 384 } | |
| 385 | |
| 386 scoped_refptr<TrackedCallback> callback; | |
| 387 callback.swap(flush_callback_); | |
| 388 callback->Run(params.result()); | |
| 389 } | |
| 390 | |
| 391 void VideoDecoderResource::OnPluginMsgResetComplete( | |
| 392 const ResourceMessageReplyParams& params) { | |
| 393 scoped_refptr<TrackedCallback> callback; | |
| 394 callback.swap(reset_callback_); | |
| 395 callback->Run(params.result()); | |
| 396 } | |
| 397 | |
| 398 int32_t VideoDecoderResource::TryDecode( | |
| 399 uint32_t decode_id, | |
| 400 uint32_t size, | |
| 401 const void* buffer, | |
| 402 scoped_refptr<TrackedCallback> callback) { | |
| 403 decode_id_ = decode_id; | |
| 404 decode_size_ = size; | |
| 405 decode_buffer_ = buffer; | |
| 406 if (available_shm_buffers_.empty() || | |
| 407 available_shm_buffers_.back()->size_ < size) { | |
| 408 decode_callback_ = callback; | |
| 409 | |
| 410 if (pending_decode_count_ < kMaximumPendingDecodes) { | |
| 411 get_shm_buffer_pending_ = true; | |
| 412 uint32_t alloc_size = std::max(size, kMinimumBitstreamBufferSize); | |
| 413 Call<PpapiPluginMsg_VideoDecoder_GetShmReply>( | |
| 414 RENDERER, | |
|
piman
2014/05/08 04:26:04
Why not allocate the shm by going to the browser?
bbudge
2014/05/14 19:35:04
This was simpler, and the patch is already large.
piman
2014/05/15 04:02:53
I disagree... the API is too subtle. See the comme
| |
| 415 PpapiHostMsg_VideoDecoder_GetShm(alloc_size), | |
| 416 base::Bind(&VideoDecoderResource::OnPluginMsgGetShmComplete, this)); | |
| 417 } | |
| 418 | |
| 419 return PP_OK_COMPLETIONPENDING; | |
| 420 } | |
| 421 | |
| 422 ShmBuffer* shm_buffer = available_shm_buffers_.back(); | |
| 423 available_shm_buffers_.pop_back(); | |
| 424 SendDecodeMessage(shm_buffer->shm_id_); | |
| 425 return PP_OK; | |
| 426 } | |
| 427 | |
| 428 void VideoDecoderResource::SendDecodeMessage(uint32_t shm_id) { | |
| 429 ShmBuffer* shm_buffer = shm_buffers_[shm_id]; | |
| 430 memcpy(shm_buffer->addr_, decode_buffer_, decode_size_); | |
| 431 pending_decode_count_++; | |
| 432 | |
| 433 FlushCommandBuffer(); | |
| 434 Call<PpapiPluginMsg_VideoDecoder_DecodeReply>( | |
| 435 RENDERER, | |
| 436 PpapiHostMsg_VideoDecoder_Decode(shm_id, decode_size_), | |
| 437 base::Bind( | |
| 438 &VideoDecoderResource::OnPluginMsgDecodeComplete, this, decode_id_)); | |
| 439 } | |
| 440 | |
| 441 void VideoDecoderResource::RunDecodeCallback(int32_t result) { | |
| 442 scoped_refptr<TrackedCallback> callback; | |
| 443 callback.swap(decode_callback_); | |
| 444 callback->Run(result); | |
| 445 } | |
| 446 | |
| 447 void VideoDecoderResource::FlushCommandBuffer() { | |
| 448 if (gles2_impl_) | |
| 449 gles2_impl_->Flush(); | |
| 450 } | |
| 451 | |
| 452 void VideoDecoderResource::DeleteGLTexture(uint32_t id) { | |
| 453 gles2_impl_->DeleteTextures(1, &id); | |
| 454 } | |
| 455 | |
| 456 void VideoDecoderResource::WriteNextPicture(PP_VideoPicture* pp_picture) { | |
| 457 DCHECK(!received_pictures_.empty()); | |
| 458 Picture& picture = received_pictures_.front(); | |
| 459 uint32_t texture_id = picture.texture_id_; | |
| 460 TextureMap::iterator it = textures_.find(texture_id); | |
| 461 DCHECK(it != textures_.end()); | |
| 462 pp_picture->decode_id = picture.decode_id_; | |
| 463 pp_picture->texture_id = texture_id; | |
| 464 pp_picture->texture_target = it->second.texture_target_; | |
| 465 pp_picture->texture_size = it->second.size_; | |
| 466 received_pictures_.pop(); | |
| 467 } | |
| 468 | |
| 469 } // namespace proxy | |
| 470 } // namespace ppapi | |
| OLD | NEW |