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