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 "ipc/ipc_message.h" | |
| 11 #include "ppapi/c/pp_errors.h" | |
| 12 #include "ppapi/c/ppb_opengles2.h" | |
| 13 #include "ppapi/proxy/plugin_dispatcher.h" | |
| 14 #include "ppapi/proxy/ppapi_messages.h" | |
| 15 #include "ppapi/proxy/ppb_graphics_3d_proxy.h" | |
| 16 #include "ppapi/shared_impl/ppapi_globals.h" | |
| 17 #include "ppapi/shared_impl/ppb_graphics_3d_shared.h" | |
| 18 #include "ppapi/shared_impl/proxy_lock.h" | |
| 19 #include "ppapi/shared_impl/resource_tracker.h" | |
| 20 #include "ppapi/shared_impl/scoped_pp_resource.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_, | |
|
yzshen1
2014/05/14 22:58:16
I think '_' suffix has quite specific meaning in o
bbudge
2014/05/15 00:24:54
That's a good convention. Done.
| |
| 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); | |
| 48 } | |
| 49 | |
| 50 VideoDecoderResource::ShmBuffer::~ShmBuffer() { | |
| 51 } | |
| 52 | |
| 53 VideoDecoderResource::Texture::Texture(uint32_t texture_target_, | |
| 54 const PP_Size& size_) | |
| 55 : texture_target(texture_target_), size(size_) { | |
| 56 } | |
| 57 | |
| 58 VideoDecoderResource::Texture::~Texture() { | |
| 59 } | |
| 60 | |
| 61 VideoDecoderResource::Picture::Picture(int32_t decode_id_, uint32_t texture_id_) | |
| 62 : decode_id(decode_id_), texture_id(texture_id_) { | |
| 63 } | |
| 64 | |
| 65 VideoDecoderResource::Picture::~Picture() { | |
| 66 } | |
| 67 | |
| 68 VideoDecoderResource::VideoDecoderResource(Connection connection, | |
| 69 PP_Instance instance) | |
| 70 : PluginResource(connection, instance), | |
| 71 decode_id_(0), | |
| 72 decode_size_(0), | |
| 73 decode_buffer_(NULL), | |
| 74 pending_decode_count_(0), | |
| 75 get_shm_buffer_pending_(false), | |
| 76 get_picture_(NULL), | |
| 77 gles2_impl_(NULL), | |
| 78 initialized_(false), | |
| 79 testing_(false), | |
| 80 // Set |decoder_last_error_| to PP_OK after successful initialization. | |
| 81 // This makes error checking a little more concise, since we can check | |
| 82 // that the decoder has been initialized and hasn't returned an error by | |
| 83 // just testing |decoder_last_error_|. | |
| 84 decoder_last_error_(PP_ERROR_FAILED) { | |
| 85 SendCreate(RENDERER, PpapiHostMsg_VideoDecoder_Create()); | |
| 86 } | |
| 87 | |
| 88 VideoDecoderResource::~VideoDecoderResource() { | |
| 89 // Destroy any textures which haven't been dismissed. | |
| 90 TextureMap::iterator it = textures_.begin(); | |
| 91 for (; it != textures_.end(); ++it) | |
| 92 DeleteGLTexture(it->first); | |
| 93 } | |
| 94 | |
| 95 PPB_VideoDecoder_API* VideoDecoderResource::AsPPB_VideoDecoder_API() { | |
| 96 return this; | |
| 97 } | |
| 98 | |
| 99 int32_t VideoDecoderResource::Initialize( | |
| 100 PP_Resource graphics_context, | |
| 101 PP_VideoProfile profile, | |
| 102 PP_Bool allow_software_fallback, | |
| 103 scoped_refptr<TrackedCallback> callback) { | |
| 104 if (initialized_) | |
| 105 return PP_ERROR_FAILED; | |
| 106 if (profile < 0 || profile > PP_VIDEOPROFILE_MAX) | |
| 107 return PP_ERROR_BADARGUMENT; | |
| 108 if (initialize_callback_) | |
| 109 return PP_ERROR_INPROGRESS; | |
| 110 if (!graphics_context) | |
| 111 return PP_ERROR_BADRESOURCE; | |
| 112 | |
| 113 // Create a new Graphics3D resource that can create texture resources to share | |
| 114 // with the plugin. We can't use the plugin's Graphics3D, since we create | |
| 115 // textures on a proxy thread, which would interfere with the plugin. | |
| 116 thunk::EnterResourceCreationNoLock enter_create(pp_instance()); | |
| 117 if (enter_create.failed()) | |
| 118 return PP_ERROR_FAILED; | |
| 119 int32_t attrib_list[] = {PP_GRAPHICS3DATTRIB_NONE}; | |
| 120 HostResource host_resource; | |
| 121 if (!testing_) { | |
| 122 ScopedPPResource graphics3d( | |
| 123 ScopedPPResource::PassRef(), | |
| 124 enter_create.functions()->CreateGraphics3D( | |
| 125 pp_instance(), graphics_context, attrib_list)); | |
| 126 EnterResourceNoLock<PPB_Graphics3D_API> enter_graphics(graphics3d.get(), | |
| 127 true); | |
| 128 if (enter_graphics.failed()) | |
| 129 return PP_ERROR_BADRESOURCE; | |
| 130 | |
| 131 graphics3d_ = static_cast<PPB_Graphics3D_Shared*>(enter_graphics.object()); | |
| 132 gles2_impl_ = graphics3d_->gles2_impl(); | |
| 133 host_resource = graphics3d_->host_resource(); | |
| 134 graphics3d.Release(); | |
| 135 } | |
| 136 | |
| 137 initialize_callback_ = callback; | |
| 138 | |
| 139 Call<PpapiPluginMsg_VideoDecoder_InitializeReply>( | |
| 140 RENDERER, | |
| 141 PpapiHostMsg_VideoDecoder_Initialize( | |
| 142 host_resource, profile, PP_ToBool(allow_software_fallback)), | |
| 143 base::Bind(&VideoDecoderResource::OnPluginMsgInitializeComplete, this)); | |
| 144 | |
| 145 return PP_OK_COMPLETIONPENDING; | |
| 146 } | |
| 147 | |
| 148 int32_t VideoDecoderResource::Decode(uint32_t decode_id, | |
| 149 uint32_t size, | |
| 150 const void* buffer, | |
| 151 scoped_refptr<TrackedCallback> callback) { | |
| 152 if (decoder_last_error_) | |
| 153 return decoder_last_error_; | |
| 154 if (flush_callback_ || reset_callback_) | |
| 155 return PP_ERROR_FAILED; | |
| 156 if (decode_callback_) | |
| 157 return PP_ERROR_INPROGRESS; | |
| 158 | |
| 159 return TryDecode(decode_id, size, buffer, callback); | |
| 160 } | |
| 161 | |
| 162 int32_t VideoDecoderResource::GetPicture( | |
| 163 PP_VideoPicture* picture, | |
| 164 scoped_refptr<TrackedCallback> callback) { | |
| 165 if (decoder_last_error_) | |
| 166 return decoder_last_error_; | |
| 167 if (reset_callback_) | |
| 168 return PP_ERROR_FAILED; | |
| 169 if (get_picture_callback_) | |
| 170 return PP_ERROR_INPROGRESS; | |
| 171 | |
| 172 // If the next picture is ready, return it synchronously. | |
| 173 if (!received_pictures_.empty()) { | |
| 174 WriteNextPicture(picture); | |
| 175 return PP_OK; | |
| 176 } | |
| 177 | |
| 178 get_picture_callback_ = callback; | |
| 179 get_picture_ = picture; | |
| 180 return PP_OK_COMPLETIONPENDING; | |
| 181 } | |
| 182 | |
| 183 void VideoDecoderResource::RecyclePicture(const PP_VideoPicture* picture) { | |
| 184 if (decoder_last_error_) | |
| 185 return; | |
| 186 if (reset_callback_) | |
| 187 return; | |
| 188 | |
| 189 Post(RENDERER, PpapiHostMsg_VideoDecoder_RecyclePicture(picture->texture_id)); | |
| 190 } | |
| 191 | |
| 192 int32_t VideoDecoderResource::Flush(scoped_refptr<TrackedCallback> callback) { | |
| 193 if (decoder_last_error_) | |
| 194 return decoder_last_error_; | |
| 195 if (reset_callback_) | |
| 196 return PP_ERROR_FAILED; | |
| 197 if (flush_callback_) | |
| 198 return PP_ERROR_INPROGRESS; | |
| 199 flush_callback_ = callback; | |
| 200 | |
| 201 Call<PpapiPluginMsg_VideoDecoder_FlushReply>( | |
| 202 RENDERER, | |
| 203 PpapiHostMsg_VideoDecoder_Flush(), | |
| 204 base::Bind(&VideoDecoderResource::OnPluginMsgFlushComplete, this)); | |
| 205 | |
| 206 return PP_OK_COMPLETIONPENDING; | |
| 207 } | |
| 208 | |
| 209 int32_t VideoDecoderResource::Reset(scoped_refptr<TrackedCallback> callback) { | |
| 210 if (decoder_last_error_) | |
| 211 return decoder_last_error_; | |
| 212 if (flush_callback_) | |
| 213 return PP_ERROR_FAILED; | |
| 214 if (reset_callback_) | |
| 215 return PP_ERROR_INPROGRESS; | |
| 216 reset_callback_ = callback; | |
| 217 | |
| 218 // Cause any pending Decode or GetPicture callbacks to abort immediately. | |
| 219 // Reentrancy isn't a problem, since all calls fail until Reset completes. | |
| 220 if (TrackedCallback::IsPending(decode_callback_)) | |
| 221 decode_callback_->Abort(); | |
| 222 decode_callback_ = NULL; | |
| 223 if (TrackedCallback::IsPending(get_picture_callback_)) | |
| 224 get_picture_callback_->Abort(); | |
| 225 get_picture_callback_ = NULL; | |
| 226 Call<PpapiPluginMsg_VideoDecoder_ResetReply>( | |
| 227 RENDERER, | |
| 228 PpapiHostMsg_VideoDecoder_Reset(), | |
| 229 base::Bind(&VideoDecoderResource::OnPluginMsgResetComplete, this)); | |
| 230 | |
| 231 return PP_OK_COMPLETIONPENDING; | |
| 232 } | |
| 233 | |
| 234 void VideoDecoderResource::OnReplyReceived( | |
| 235 const ResourceMessageReplyParams& params, | |
| 236 const IPC::Message& msg) { | |
| 237 PPAPI_BEGIN_MESSAGE_MAP(VideoDecoderResource, msg) | |
| 238 PPAPI_DISPATCH_PLUGIN_RESOURCE_CALL( | |
|
yzshen1
2014/05/14 22:58:16
I think it is good to add indent in this case.
bbudge
2014/05/15 00:24:54
You're the second reviewer to point this out so I'
| |
| 239 PpapiPluginMsg_VideoDecoder_RequestTextures, OnPluginMsgRequestTextures) | |
| 240 PPAPI_DISPATCH_PLUGIN_RESOURCE_CALL(PpapiPluginMsg_VideoDecoder_PictureReady, | |
| 241 OnPluginMsgPictureReady) | |
| 242 PPAPI_DISPATCH_PLUGIN_RESOURCE_CALL( | |
| 243 PpapiPluginMsg_VideoDecoder_DismissPicture, OnPluginMsgDismissPicture) | |
| 244 PPAPI_DISPATCH_PLUGIN_RESOURCE_CALL(PpapiPluginMsg_VideoDecoder_NotifyError, | |
| 245 OnPluginMsgNotifyError) | |
| 246 PPAPI_DISPATCH_PLUGIN_RESOURCE_CALL_UNHANDLED( | |
| 247 PluginResource::OnReplyReceived(params, msg)) | |
| 248 PPAPI_END_MESSAGE_MAP() | |
| 249 } | |
| 250 | |
| 251 void VideoDecoderResource::SetForTest() { | |
| 252 testing_ = true; | |
| 253 } | |
| 254 | |
| 255 void VideoDecoderResource::OnPluginMsgRequestTextures( | |
| 256 const ResourceMessageReplyParams& params, | |
| 257 uint32_t num_textures, | |
| 258 const PP_Size& size, | |
| 259 uint32_t texture_target) { | |
| 260 DCHECK(num_textures); | |
| 261 std::vector<uint32_t> texture_ids(num_textures); | |
| 262 if (gles2_impl_) { | |
| 263 gles2_impl_->GenTextures(num_textures, &texture_ids.front()); | |
| 264 for (uint32_t i = 0; i < num_textures; ++i) { | |
| 265 gles2_impl_->ActiveTexture(GL_TEXTURE0); | |
| 266 gles2_impl_->BindTexture(texture_target, texture_ids[i]); | |
| 267 gles2_impl_->TexParameteri( | |
| 268 texture_target, GL_TEXTURE_MIN_FILTER, GL_NEAREST); | |
| 269 gles2_impl_->TexParameteri( | |
| 270 texture_target, GL_TEXTURE_MAG_FILTER, GL_NEAREST); | |
| 271 gles2_impl_->TexParameterf( | |
| 272 texture_target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); | |
| 273 gles2_impl_->TexParameterf( | |
| 274 texture_target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); | |
| 275 | |
| 276 if (texture_target == GL_TEXTURE_2D) { | |
| 277 gles2_impl_->TexImage2D(texture_target, | |
| 278 0, | |
| 279 GL_RGBA, | |
| 280 size.width, | |
| 281 size.height, | |
| 282 0, | |
| 283 GL_RGBA, | |
| 284 GL_UNSIGNED_BYTE, | |
| 285 NULL); | |
| 286 } | |
| 287 | |
| 288 textures_.insert( | |
| 289 std::make_pair(texture_ids[i], Texture(texture_target, size))); | |
| 290 } | |
| 291 gles2_impl_->Flush(); | |
| 292 } else if (testing_) { | |
| 293 // Create some fake texture ids so we can test picture handling. | |
| 294 for (uint32_t i = 0; i < num_textures; ++i) { | |
| 295 texture_ids[i] = i + 1; | |
| 296 textures_.insert( | |
| 297 std::make_pair(texture_ids[i], Texture(texture_target, size))); | |
| 298 } | |
| 299 } | |
| 300 | |
| 301 Post(RENDERER, PpapiHostMsg_VideoDecoder_AssignTextures(size, texture_ids)); | |
| 302 } | |
| 303 | |
| 304 void VideoDecoderResource::OnPluginMsgPictureReady( | |
| 305 const ResourceMessageReplyParams& params, | |
| 306 uint32_t decode_id, | |
| 307 uint32_t texture_id) { | |
| 308 received_pictures_.push(Picture(decode_id, texture_id)); | |
| 309 // Prepare to accept another call to GetPicture in the callback. | |
| 310 scoped_refptr<TrackedCallback> callback; | |
| 311 callback.swap(get_picture_callback_); | |
| 312 PP_VideoPicture* picture = get_picture_; | |
| 313 get_picture_ = NULL; | |
| 314 if (TrackedCallback::IsPending(callback)) { | |
| 315 WriteNextPicture(picture); | |
| 316 callback->Run(PP_OK); | |
| 317 } | |
| 318 } | |
| 319 | |
| 320 void VideoDecoderResource::OnPluginMsgDismissPicture( | |
| 321 const ResourceMessageReplyParams& params, | |
| 322 uint32_t texture_id) { | |
| 323 DeleteGLTexture(texture_id); | |
| 324 textures_.erase(texture_id); | |
| 325 } | |
| 326 | |
| 327 void VideoDecoderResource::OnPluginMsgNotifyError( | |
| 328 const ResourceMessageReplyParams& params, | |
| 329 int32_t error) { | |
| 330 decoder_last_error_ = error; | |
| 331 // Cause any pending Decode or GetPicture callbacks to run immediately. | |
| 332 // Reentrancy isn't a problem, since the resource is unusable now. | |
| 333 if (TrackedCallback::IsPending(decode_callback_)) | |
| 334 decode_callback_->Run(decoder_last_error_); | |
| 335 decode_callback_ = NULL; | |
| 336 if (TrackedCallback::IsPending(get_picture_callback_)) | |
| 337 get_picture_callback_->Run(decoder_last_error_); | |
| 338 get_picture_callback_ = NULL; | |
| 339 } | |
| 340 | |
| 341 void VideoDecoderResource::OnPluginMsgInitializeComplete( | |
| 342 const ResourceMessageReplyParams& params) { | |
| 343 decoder_last_error_ = params.result(); | |
| 344 if (decoder_last_error_ == PP_OK) | |
| 345 initialized_ = true; | |
| 346 | |
| 347 // Let the plugin call Initialize again from its callback in case of failure. | |
| 348 scoped_refptr<TrackedCallback> callback; | |
| 349 callback.swap(initialize_callback_); | |
| 350 callback->Run(decoder_last_error_); | |
| 351 } | |
| 352 | |
| 353 void VideoDecoderResource::OnPluginMsgGetShmComplete( | |
| 354 const ResourceMessageReplyParams& params, | |
| 355 uint32_t size) { | |
| 356 get_shm_buffer_pending_ = false; | |
| 357 int32_t result = params.result(); | |
| 358 if (result == PP_OK) { | |
| 359 base::SharedMemoryHandle shm_handle = base::SharedMemory::NULLHandle(); | |
| 360 if (!params.TakeSharedMemoryHandleAtIndex(0, &shm_handle)) { | |
| 361 RunDecodeCallback(PP_ERROR_FAILED); | |
| 362 return; | |
| 363 } | |
| 364 uint32_t shm_id = static_cast<uint32_t>(shm_buffers_.size()); | |
| 365 scoped_ptr<ShmBuffer> shm_buffer( | |
| 366 new ShmBuffer(new base::SharedMemory(shm_handle, false /* read_only */), | |
| 367 size, | |
| 368 shm_id)); | |
| 369 if (!shm_buffer->addr) { | |
| 370 RunDecodeCallback(PP_ERROR_FAILED); | |
| 371 return; | |
| 372 } | |
| 373 shm_buffers_.push_back(shm_buffer.release()); | |
| 374 SendDecodeMessage(shm_id); | |
| 375 RunDecodeCallback(PP_OK); | |
| 376 } | |
| 377 } | |
| 378 | |
| 379 void VideoDecoderResource::OnPluginMsgDecodeComplete( | |
| 380 const ResourceMessageReplyParams& params, | |
| 381 uint32_t shm_id) { | |
| 382 pending_decode_count_--; | |
| 383 // Return the shm buffer to the available list. | |
| 384 if (shm_id < shm_buffers_.size()) | |
| 385 available_shm_buffers_.push_back(shm_buffers_[shm_id]); | |
| 386 else | |
| 387 NOTREACHED(); | |
| 388 | |
| 389 // If a Decode is pending, and we're not waiting for a shm buffer, attempt | |
| 390 // the Decode again. | |
| 391 if (decode_callback_ && !get_shm_buffer_pending_) { | |
| 392 int32_t result = | |
| 393 TryDecode(decode_id_, decode_size_, decode_buffer_, decode_callback_); | |
| 394 if (result == PP_OK) | |
| 395 RunDecodeCallback(PP_OK); | |
| 396 } | |
| 397 } | |
| 398 | |
| 399 void VideoDecoderResource::OnPluginMsgFlushComplete( | |
| 400 const ResourceMessageReplyParams& params) { | |
| 401 if (get_picture_callback_) { | |
| 402 scoped_refptr<TrackedCallback> callback; | |
| 403 callback.swap(get_picture_callback_); | |
| 404 callback->Abort(); | |
| 405 } | |
| 406 | |
| 407 scoped_refptr<TrackedCallback> callback; | |
| 408 callback.swap(flush_callback_); | |
| 409 callback->Run(params.result()); | |
| 410 } | |
| 411 | |
| 412 void VideoDecoderResource::OnPluginMsgResetComplete( | |
| 413 const ResourceMessageReplyParams& params) { | |
| 414 scoped_refptr<TrackedCallback> callback; | |
| 415 callback.swap(reset_callback_); | |
| 416 callback->Run(params.result()); | |
| 417 } | |
| 418 | |
| 419 int32_t VideoDecoderResource::TryDecode( | |
| 420 uint32_t decode_id, | |
| 421 uint32_t size, | |
| 422 const void* buffer, | |
| 423 scoped_refptr<TrackedCallback> callback) { | |
| 424 decode_id_ = decode_id; | |
| 425 decode_size_ = size; | |
| 426 decode_buffer_ = buffer; | |
| 427 if (available_shm_buffers_.empty() || | |
| 428 available_shm_buffers_.back()->size < size) { | |
| 429 decode_callback_ = callback; | |
| 430 | |
| 431 if (pending_decode_count_ < kMaximumPendingDecodes) { | |
| 432 get_shm_buffer_pending_ = true; | |
| 433 uint32_t alloc_size = std::max(size, kMinimumBitstreamBufferSize); | |
| 434 Call<PpapiPluginMsg_VideoDecoder_GetShmReply>( | |
| 435 RENDERER, | |
| 436 PpapiHostMsg_VideoDecoder_GetShm(alloc_size), | |
| 437 base::Bind(&VideoDecoderResource::OnPluginMsgGetShmComplete, this)); | |
| 438 } | |
| 439 | |
| 440 return PP_OK_COMPLETIONPENDING; | |
| 441 } | |
| 442 | |
| 443 ShmBuffer* shm_buffer = available_shm_buffers_.back(); | |
| 444 available_shm_buffers_.pop_back(); | |
| 445 SendDecodeMessage(shm_buffer->shm_id); | |
| 446 return PP_OK; | |
| 447 } | |
| 448 | |
| 449 void VideoDecoderResource::SendDecodeMessage(uint32_t shm_id) { | |
| 450 DCHECK(shm_id < shm_buffers_.size()); | |
| 451 ShmBuffer* shm_buffer = shm_buffers_[shm_id]; | |
| 452 memcpy(shm_buffer->addr, decode_buffer_, decode_size_); | |
| 453 pending_decode_count_++; | |
| 454 | |
| 455 Call<PpapiPluginMsg_VideoDecoder_DecodeReply>( | |
| 456 RENDERER, | |
| 457 PpapiHostMsg_VideoDecoder_Decode(shm_id, decode_id_, decode_size_), | |
| 458 base::Bind(&VideoDecoderResource::OnPluginMsgDecodeComplete, this)); | |
| 459 } | |
| 460 | |
| 461 void VideoDecoderResource::RunDecodeCallback(int32_t result) { | |
| 462 scoped_refptr<TrackedCallback> callback; | |
| 463 callback.swap(decode_callback_); | |
| 464 callback->Run(result); | |
| 465 } | |
| 466 | |
| 467 void VideoDecoderResource::DeleteGLTexture(uint32_t id) { | |
| 468 if (gles2_impl_) { | |
| 469 gles2_impl_->DeleteTextures(1, &id); | |
| 470 gles2_impl_->Flush(); | |
| 471 } | |
| 472 } | |
| 473 | |
| 474 void VideoDecoderResource::WriteNextPicture(PP_VideoPicture* pp_picture) { | |
| 475 DCHECK(!received_pictures_.empty()); | |
| 476 Picture& picture = received_pictures_.front(); | |
| 477 uint32_t texture_id = picture.texture_id; | |
| 478 TextureMap::iterator it = textures_.find(texture_id); | |
| 479 DCHECK(it != textures_.end()); | |
| 480 pp_picture->decode_id = picture.decode_id; | |
| 481 pp_picture->texture_id = texture_id; | |
| 482 pp_picture->texture_target = it->second.texture_target; | |
| 483 pp_picture->texture_size = it->second.size; | |
| 484 received_pictures_.pop(); | |
| 485 } | |
| 486 | |
| 487 } // namespace proxy | |
| 488 } // namespace ppapi | |
| OLD | NEW |