[M108 Aura Migration][NaCl][PPFwk] Add error logs + SVACE/DLOG/Static analysis fix
[platform/framework/web/chromium-efl.git] / content / renderer / pepper / pepper_video_decoder_host.cc
1 // Copyright 2014 The Chromium Authors
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 "content/renderer/pepper/pepper_video_decoder_host.h"
6
7 #include <stddef.h>
8
9 #include "base/bind.h"
10 #include "base/memory/ptr_util.h"
11 #include "base/memory/unsafe_shared_memory_region.h"
12 #include "base/ranges/algorithm.h"
13 #include "build/build_config.h"
14 #include "content/common/pepper_file_util.h"
15 #include "content/public/common/content_client.h"
16 #include "content/public/renderer/content_renderer_client.h"
17 #include "content/public/renderer/ppapi_gfx_conversion.h"
18 #include "content/public/renderer/render_thread.h"
19 #include "content/public/renderer/renderer_ppapi_host.h"
20 #include "content/renderer/pepper/ppb_graphics_3d_impl.h"
21 #include "content/renderer/pepper/video_decoder_shim.h"
22 #include "gpu/ipc/client/command_buffer_proxy_impl.h"
23 #include "media/base/limits.h"
24 #include "media/base/media_util.h"
25 #include "media/gpu/ipc/client/gpu_video_decode_accelerator_host.h"
26 #include "media/video/video_decode_accelerator.h"
27 #include "ppapi/c/pp_completion_callback.h"
28 #include "ppapi/c/pp_errors.h"
29 #include "ppapi/host/dispatch_host_message.h"
30 #include "ppapi/host/ppapi_host.h"
31 #include "ppapi/proxy/ppapi_messages.h"
32 #include "ppapi/proxy/video_decoder_constants.h"
33 #include "ppapi/thunk/enter.h"
34 #include "ppapi/thunk/ppb_graphics_3d_api.h"
35
36 using ppapi::proxy::SerializedHandle;
37 using ppapi::thunk::EnterResourceNoLock;
38 using ppapi::thunk::PPB_Graphics3D_API;
39
40 namespace content {
41
42 namespace {
43
44 media::VideoCodecProfile PepperToMediaVideoProfile(PP_VideoProfile profile) {
45   switch (profile) {
46     case PP_VIDEOPROFILE_H264BASELINE:
47       return media::H264PROFILE_BASELINE;
48     case PP_VIDEOPROFILE_H264MAIN:
49       return media::H264PROFILE_MAIN;
50     case PP_VIDEOPROFILE_H264EXTENDED:
51       return media::H264PROFILE_EXTENDED;
52     case PP_VIDEOPROFILE_H264HIGH:
53       return media::H264PROFILE_HIGH;
54     case PP_VIDEOPROFILE_H264HIGH10PROFILE:
55       return media::H264PROFILE_HIGH10PROFILE;
56     case PP_VIDEOPROFILE_H264HIGH422PROFILE:
57       return media::H264PROFILE_HIGH422PROFILE;
58     case PP_VIDEOPROFILE_H264HIGH444PREDICTIVEPROFILE:
59       return media::H264PROFILE_HIGH444PREDICTIVEPROFILE;
60     case PP_VIDEOPROFILE_H264SCALABLEBASELINE:
61       return media::H264PROFILE_SCALABLEBASELINE;
62     case PP_VIDEOPROFILE_H264SCALABLEHIGH:
63       return media::H264PROFILE_SCALABLEHIGH;
64     case PP_VIDEOPROFILE_H264STEREOHIGH:
65       return media::H264PROFILE_STEREOHIGH;
66     case PP_VIDEOPROFILE_H264MULTIVIEWHIGH:
67       return media::H264PROFILE_MULTIVIEWHIGH;
68     case PP_VIDEOPROFILE_VP8_ANY:
69       return media::VP8PROFILE_ANY;
70     case PP_VIDEOPROFILE_VP9_ANY:
71       return media::VP9PROFILE_PROFILE0;
72     // No default case, to catch unhandled PP_VideoProfile values.
73   }
74
75   return media::VIDEO_CODEC_PROFILE_UNKNOWN;
76 }
77
78 }  // namespace
79
80 PepperVideoDecoderHost::PendingDecode::PendingDecode(
81     int32_t decode_id,
82     uint32_t shm_id,
83     uint32_t size,
84     const ppapi::host::ReplyMessageContext& reply_context)
85     : decode_id(decode_id),
86       shm_id(shm_id),
87       size(size),
88       reply_context(reply_context) {}
89
90 PepperVideoDecoderHost::PendingDecode::~PendingDecode() {}
91
92 PepperVideoDecoderHost::MappedBuffer::MappedBuffer(
93     base::UnsafeSharedMemoryRegion region,
94     base::WritableSharedMemoryMapping mapping)
95     : region(std::move(region)), mapping(std::move(mapping)) {}
96
97 PepperVideoDecoderHost::MappedBuffer::~MappedBuffer() {}
98
99 PepperVideoDecoderHost::MappedBuffer::MappedBuffer(MappedBuffer&&) = default;
100 PepperVideoDecoderHost::MappedBuffer& PepperVideoDecoderHost::MappedBuffer::
101 operator=(MappedBuffer&&) = default;
102
103 PepperVideoDecoderHost::PepperVideoDecoderHost(RendererPpapiHost* host,
104                                                PP_Instance instance,
105                                                PP_Resource resource)
106     : ResourceHost(host->GetPpapiHost(), instance, resource),
107       renderer_ppapi_host_(host) {}
108
109 PepperVideoDecoderHost::~PepperVideoDecoderHost() {}
110
111 int32_t PepperVideoDecoderHost::OnResourceMessageReceived(
112     const IPC::Message& msg,
113     ppapi::host::HostMessageContext* context) {
114   PPAPI_BEGIN_MESSAGE_MAP(PepperVideoDecoderHost, msg)
115     PPAPI_DISPATCH_HOST_RESOURCE_CALL(PpapiHostMsg_VideoDecoder_Initialize,
116                                       OnHostMsgInitialize)
117     PPAPI_DISPATCH_HOST_RESOURCE_CALL(PpapiHostMsg_VideoDecoder_GetShm,
118                                       OnHostMsgGetShm)
119     PPAPI_DISPATCH_HOST_RESOURCE_CALL(PpapiHostMsg_VideoDecoder_Decode,
120                                       OnHostMsgDecode)
121     PPAPI_DISPATCH_HOST_RESOURCE_CALL(PpapiHostMsg_VideoDecoder_AssignTextures,
122                                       OnHostMsgAssignTextures)
123     PPAPI_DISPATCH_HOST_RESOURCE_CALL(PpapiHostMsg_VideoDecoder_RecyclePicture,
124                                       OnHostMsgRecyclePicture)
125     PPAPI_DISPATCH_HOST_RESOURCE_CALL_0(PpapiHostMsg_VideoDecoder_Flush,
126                                         OnHostMsgFlush)
127     PPAPI_DISPATCH_HOST_RESOURCE_CALL_0(PpapiHostMsg_VideoDecoder_Reset,
128                                         OnHostMsgReset)
129   PPAPI_END_MESSAGE_MAP()
130   return PP_ERROR_FAILED;
131 }
132
133 int32_t PepperVideoDecoderHost::OnHostMsgInitialize(
134     ppapi::host::HostMessageContext* context,
135     const ppapi::HostResource& graphics_context,
136     PP_VideoProfile profile,
137     PP_HardwareAcceleration acceleration,
138     uint32_t min_picture_count) {
139   if (initialized_)
140     return PP_ERROR_FAILED;
141   if (min_picture_count > ppapi::proxy::kMaximumPictureCount)
142     return PP_ERROR_BADARGUMENT;
143
144   EnterResourceNoLock<PPB_Graphics3D_API> enter_graphics(
145       graphics_context.host_resource(), true);
146   if (enter_graphics.failed())
147     return PP_ERROR_FAILED;
148   PPB_Graphics3D_Impl* graphics3d =
149       static_cast<PPB_Graphics3D_Impl*>(enter_graphics.object());
150
151   gpu::CommandBufferProxyImpl* command_buffer =
152       graphics3d->GetCommandBufferProxy();
153   if (!command_buffer)
154     return PP_ERROR_FAILED;
155
156   profile_ = PepperToMediaVideoProfile(profile);
157   software_fallback_allowed_ = (acceleration != PP_HARDWAREACCELERATION_ONLY);
158
159   min_picture_count_ = min_picture_count;
160
161   if (acceleration != PP_HARDWAREACCELERATION_NONE) {
162     // This is not synchronous, but subsequent IPC messages will be buffered, so
163     // it is okay to immediately send IPC messages.
164     if (command_buffer->channel()) {
165       decoder_ = base::WrapUnique<media::VideoDecodeAccelerator>(
166           new media::GpuVideoDecodeAcceleratorHost(command_buffer));
167       media::VideoDecodeAccelerator::Config vda_config(profile_);
168       vda_config.supported_output_formats.assign(
169           {media::PIXEL_FORMAT_XRGB, media::PIXEL_FORMAT_ARGB});
170       if (decoder_->Initialize(vda_config, this)) {
171         initialized_ = true;
172         return PP_OK;
173       }
174     }
175     decoder_.reset();
176     if (acceleration == PP_HARDWAREACCELERATION_ONLY)
177       return PP_ERROR_NOTSUPPORTED;
178   }
179
180 #if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_TIZEN)
181   return PP_ERROR_NOTSUPPORTED;
182 #else
183   if (!TryFallbackToSoftwareDecoder())
184     return PP_ERROR_FAILED;
185
186   initialized_ = true;
187   return PP_OK;
188 #endif
189 }
190
191 int32_t PepperVideoDecoderHost::OnHostMsgGetShm(
192     ppapi::host::HostMessageContext* context,
193     uint32_t shm_id,
194     uint32_t shm_size) {
195   if (!initialized_)
196     return PP_ERROR_FAILED;
197
198   // Make the buffers larger since we hope to reuse them.
199   shm_size = std::max(
200       shm_size,
201       static_cast<uint32_t>(ppapi::proxy::kMinimumBitstreamBufferSize));
202   if (shm_size > ppapi::proxy::kMaximumBitstreamBufferSize)
203     return PP_ERROR_FAILED;
204
205   if (shm_id >= ppapi::proxy::kMaximumPendingDecodes)
206     return PP_ERROR_FAILED;
207   // The shm_id must be inside or at the end of shm_buffers_.
208   if (shm_id > shm_buffers_.size())
209     return PP_ERROR_FAILED;
210   // Reject an attempt to reallocate a busy shm buffer.
211   if (shm_id < shm_buffers_.size() && shm_buffers_[shm_id].busy)
212     return PP_ERROR_FAILED;
213
214   auto shm = base::UnsafeSharedMemoryRegion::Create(shm_size);
215   auto mapping = shm.Map();
216   if (!shm.IsValid() || !mapping.IsValid())
217     return PP_ERROR_FAILED;
218
219   SerializedHandle handle(
220       base::UnsafeSharedMemoryRegion::TakeHandleForSerialization(
221           renderer_ppapi_host_->ShareUnsafeSharedMemoryRegionWithRemote(shm)));
222   if (shm_id == shm_buffers_.size()) {
223     shm_buffers_.emplace_back(std::move(shm), std::move(mapping));
224   } else {
225     // Note by the check above this buffer cannot be busy.
226     shm_buffers_[shm_id] = MappedBuffer(std::move(shm), std::move(mapping));
227   }
228
229   ppapi::host::ReplyMessageContext reply_context =
230       context->MakeReplyMessageContext();
231   reply_context.params.AppendHandle(std::move(handle));
232   host()->SendReply(reply_context,
233                     PpapiPluginMsg_VideoDecoder_GetShmReply(shm_size));
234
235   return PP_OK_COMPLETIONPENDING;
236 }
237
238 int32_t PepperVideoDecoderHost::OnHostMsgDecode(
239     ppapi::host::HostMessageContext* context,
240     uint32_t shm_id,
241     uint32_t size,
242     int32_t decode_id) {
243   if (!initialized_)
244     return PP_ERROR_FAILED;
245   DCHECK(decoder_);
246   // |shm_id| is just an index into shm_buffers_. Make sure it's in range.
247   if (static_cast<size_t>(shm_id) >= shm_buffers_.size())
248     return PP_ERROR_FAILED;
249   // Reject an attempt to pass a busy buffer to the decoder again.
250   if (shm_buffers_[shm_id].busy)
251     return PP_ERROR_FAILED;
252   // Reject non-unique decode_id values.
253   if (GetPendingDecodeById(decode_id) != pending_decodes_.end())
254     return PP_ERROR_FAILED;
255
256   if (flush_reply_context_.is_valid() || reset_reply_context_.is_valid())
257     return PP_ERROR_FAILED;
258
259   pending_decodes_.push_back(PendingDecode(decode_id, shm_id, size,
260                                            context->MakeReplyMessageContext()));
261
262   shm_buffers_[shm_id].busy = true;
263   decoder_->Decode(media::BitstreamBuffer(
264       decode_id, shm_buffers_[shm_id].region.Duplicate(), size));
265
266   return PP_OK_COMPLETIONPENDING;
267 }
268
269 int32_t PepperVideoDecoderHost::OnHostMsgAssignTextures(
270     ppapi::host::HostMessageContext* context,
271     const PP_Size& size,
272     const std::vector<uint32_t>& texture_ids,
273     const std::vector<gpu::Mailbox>& mailboxes) {
274   if (!initialized_)
275     return PP_ERROR_FAILED;
276   if (texture_ids.size() != mailboxes.size()) {
277     LOG(ERROR) << "Texture_ids size was invalid";
278     return PP_ERROR_FAILED;
279   }
280   DCHECK(decoder_);
281
282   pending_texture_requests_--;
283   DCHECK_GE(pending_texture_requests_, 0);
284
285   // If |assign_textures_messages_to_dismiss_| is not 0 then decrement it and
286   // dismiss the textures. This is necessary to ensure that after SW decoder
287   // fallback the textures that were requested by the failed HW decoder are not
288   // passed to the SW decoder.
289   if (assign_textures_messages_to_dismiss_ > 0) {
290     assign_textures_messages_to_dismiss_--;
291     PictureBufferMap pictures_pending_dismission;
292     for (auto& texture_id : texture_ids) {
293       host()->SendUnsolicitedReply(
294           pp_resource(),
295           PpapiPluginMsg_VideoDecoder_DismissPicture(texture_id));
296     }
297     picture_buffer_map_.swap(pictures_pending_dismission);
298     return PP_OK;
299   }
300
301   // Verify that the new texture IDs are unique and store them in
302   // |new_textures|.
303   PictureBufferMap new_textures;
304   for (uint32_t i = 0; i < texture_ids.size(); i++) {
305     if (picture_buffer_map_.find(texture_ids[i]) != picture_buffer_map_.end() ||
306         new_textures.find(texture_ids[i]) != new_textures.end()) {
307       // Can't assign the same texture more than once.
308       return PP_ERROR_BADARGUMENT;
309     }
310     new_textures.insert(
311         std::make_pair(texture_ids[i], PictureBufferState::ASSIGNED));
312   }
313
314   picture_buffer_map_.insert(new_textures.begin(), new_textures.end());
315
316   std::vector<media::PictureBuffer> picture_buffers;
317   for (uint32_t i = 0; i < texture_ids.size(); i++) {
318     media::PictureBuffer::TextureIds ids;
319     ids.push_back(texture_ids[i]);
320     media::PictureBuffer buffer(
321         texture_ids[i],  // Use the texture_id to identify the buffer.
322         gfx::Size(size.width, size.height), ids);
323     picture_buffers.push_back(buffer);
324   }
325   texture_mailboxes_ = mailboxes;
326   decoder_->AssignPictureBuffers(picture_buffers);
327   return PP_OK;
328 }
329
330 int32_t PepperVideoDecoderHost::OnHostMsgRecyclePicture(
331     ppapi::host::HostMessageContext* context,
332     uint32_t texture_id) {
333   if (!initialized_)
334     return PP_ERROR_FAILED;
335   DCHECK(decoder_);
336
337   auto it = picture_buffer_map_.find(texture_id);
338   if (it == picture_buffer_map_.end())
339     return PP_ERROR_BADARGUMENT;
340
341   switch (it->second) {
342     case PictureBufferState::ASSIGNED:
343       return PP_ERROR_BADARGUMENT;
344
345     case PictureBufferState::IN_USE:
346       it->second = PictureBufferState::ASSIGNED;
347       decoder_->ReusePictureBuffer(texture_id);
348       break;
349
350     case PictureBufferState::DISMISSED:
351       picture_buffer_map_.erase(it);
352       // The texture was already dismissed by the decoder. Notify the plugin.
353       host()->SendUnsolicitedReply(
354           pp_resource(),
355           PpapiPluginMsg_VideoDecoder_DismissPicture(texture_id));
356       break;
357   }
358
359   return PP_OK;
360 }
361
362 int32_t PepperVideoDecoderHost::OnHostMsgFlush(
363     ppapi::host::HostMessageContext* context) {
364   if (!initialized_)
365     return PP_ERROR_FAILED;
366   DCHECK(decoder_);
367   if (flush_reply_context_.is_valid() || reset_reply_context_.is_valid())
368     return PP_ERROR_FAILED;
369
370   flush_reply_context_ = context->MakeReplyMessageContext();
371   decoder_->Flush();
372
373   return PP_OK_COMPLETIONPENDING;
374 }
375
376 int32_t PepperVideoDecoderHost::OnHostMsgReset(
377     ppapi::host::HostMessageContext* context) {
378   if (!initialized_)
379     return PP_ERROR_FAILED;
380   DCHECK(decoder_);
381   if (flush_reply_context_.is_valid() || reset_reply_context_.is_valid())
382     return PP_ERROR_FAILED;
383
384   reset_reply_context_ = context->MakeReplyMessageContext();
385   decoder_->Reset();
386
387   return PP_OK_COMPLETIONPENDING;
388 }
389
390 void PepperVideoDecoderHost::ProvidePictureBuffers(
391     uint32_t requested_num_of_buffers,
392     media::VideoPixelFormat format,
393     uint32_t textures_per_buffer,
394     const gfx::Size& dimensions,
395     uint32_t texture_target) {
396   DCHECK_EQ(1u, textures_per_buffer);
397   coded_size_ = dimensions;
398   pending_texture_requests_++;
399   host()->SendUnsolicitedReply(
400       pp_resource(), PpapiPluginMsg_VideoDecoder_RequestTextures(
401                          std::max(min_picture_count_, requested_num_of_buffers),
402                          PP_MakeSize(dimensions.width(), dimensions.height()),
403                          texture_target));
404 }
405
406 void PepperVideoDecoderHost::PictureReady(const media::Picture& picture) {
407   auto it = picture_buffer_map_.find(picture.picture_buffer_id());
408   DCHECK(it != picture_buffer_map_.end());
409   // VDA might send the same picture multiple times in VP9 video. However the
410   // Pepper client might not able to handle it. Therefore we just catch it here.
411   // https://crbug.com/755887
412   CHECK(it->second == PictureBufferState::ASSIGNED);
413   it->second = PictureBufferState::IN_USE;
414
415   // Don't bother validating the visible rect, since the plugin process is less
416   // trusted than the gpu process.
417   PP_Rect visible_rect = PP_FromGfxRect(picture.visible_rect());
418   host()->SendUnsolicitedReply(pp_resource(),
419                                PpapiPluginMsg_VideoDecoder_PictureReady(
420                                    picture.bitstream_buffer_id(),
421                                    picture.picture_buffer_id(), visible_rect));
422 }
423
424 void PepperVideoDecoderHost::DismissPictureBuffer(int32_t picture_buffer_id) {
425   auto it = picture_buffer_map_.find(picture_buffer_id);
426   DCHECK(it != picture_buffer_map_.end());
427
428   // If the texture is still used by the plugin keep it until the plugin
429   // recycles it.
430   if (it->second == PictureBufferState::IN_USE) {
431     it->second = PictureBufferState::DISMISSED;
432     return;
433   }
434
435   DCHECK(it->second == PictureBufferState::ASSIGNED);
436   picture_buffer_map_.erase(it);
437   host()->SendUnsolicitedReply(
438       pp_resource(),
439       PpapiPluginMsg_VideoDecoder_DismissPicture(picture_buffer_id));
440 }
441
442 void PepperVideoDecoderHost::NotifyEndOfBitstreamBuffer(
443     int32_t bitstream_buffer_id) {
444   auto it = GetPendingDecodeById(bitstream_buffer_id);
445   if (it == pending_decodes_.end()) {
446     NOTREACHED();
447     return;
448   }
449   host()->SendReply(it->reply_context,
450                     PpapiPluginMsg_VideoDecoder_DecodeReply(it->shm_id));
451   shm_buffers_[it->shm_id].busy = false;
452   pending_decodes_.erase(it);
453 }
454
455 void PepperVideoDecoderHost::NotifyFlushDone() {
456   DCHECK(pending_decodes_.empty());
457   host()->SendReply(flush_reply_context_,
458                     PpapiPluginMsg_VideoDecoder_FlushReply());
459   flush_reply_context_ = ppapi::host::ReplyMessageContext();
460 }
461
462 void PepperVideoDecoderHost::NotifyResetDone() {
463   DCHECK(pending_decodes_.empty());
464   host()->SendReply(reset_reply_context_,
465                     PpapiPluginMsg_VideoDecoder_ResetReply());
466   reset_reply_context_ = ppapi::host::ReplyMessageContext();
467 }
468
469 void PepperVideoDecoderHost::NotifyError(
470     media::VideoDecodeAccelerator::Error error) {
471   int32_t pp_error = PP_ERROR_FAILED;
472   switch (error) {
473     case media::VideoDecodeAccelerator::UNREADABLE_INPUT:
474       pp_error = PP_ERROR_MALFORMED_INPUT;
475       break;
476     case media::VideoDecodeAccelerator::ILLEGAL_STATE:
477     case media::VideoDecodeAccelerator::INVALID_ARGUMENT:
478     case media::VideoDecodeAccelerator::PLATFORM_FAILURE:
479       pp_error = PP_ERROR_RESOURCE_FAILED;
480       break;
481     // No default case, to catch unhandled enum values.
482   }
483
484   // Try to initialize software decoder and use it instead.
485   if (!software_fallback_used_ && software_fallback_allowed_) {
486     VLOG(0)
487         << "Hardware decoder has returned an error. Trying Software decoder.";
488     if (TryFallbackToSoftwareDecoder())
489       return;
490   }
491
492   host()->SendUnsolicitedReply(
493       pp_resource(), PpapiPluginMsg_VideoDecoder_NotifyError(pp_error));
494 }
495
496 const uint8_t* PepperVideoDecoderHost::DecodeIdToAddress(uint32_t decode_id) {
497   PendingDecodeList::const_iterator it = GetPendingDecodeById(decode_id);
498   DCHECK(it != pending_decodes_.end());
499   uint32_t shm_id = it->shm_id;
500   return static_cast<uint8_t*>(shm_buffers_[shm_id].mapping.memory());
501 }
502
503 bool PepperVideoDecoderHost::TryFallbackToSoftwareDecoder() {
504 #if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_TIZEN)
505   return false;
506 #else
507   DCHECK(!software_fallback_used_ && software_fallback_allowed_);
508
509   uint32_t shim_texture_pool_size = media::limits::kMaxVideoFrames + 1;
510   shim_texture_pool_size = std::max(shim_texture_pool_size,
511                                     min_picture_count_);
512   std::unique_ptr<VideoDecoderShim> new_decoder(
513       new VideoDecoderShim(this, shim_texture_pool_size));
514   if (!new_decoder->Initialize(media::VideoDecodeAccelerator::Config(profile_),
515                                this)) {
516     return false;
517   }
518
519   software_fallback_used_ = true;
520   decoder_.reset(new_decoder.release());
521
522   // Dismiss all assigned pictures and mark all pictures in use as DISMISSED.
523   PictureBufferMap pictures_pending_dismission;
524   for (auto& picture : picture_buffer_map_) {
525     if (picture.second == PictureBufferState::ASSIGNED) {
526       host()->SendUnsolicitedReply(
527           pp_resource(),
528           PpapiPluginMsg_VideoDecoder_DismissPicture(picture.first));
529     } else {
530       pictures_pending_dismission.insert(
531           std::make_pair(picture.first, PictureBufferState::DISMISSED));
532     }
533   }
534   picture_buffer_map_.swap(pictures_pending_dismission);
535
536   // Dismiss all outstanding texture requests.
537   DCHECK_EQ(assign_textures_messages_to_dismiss_, 0);
538   assign_textures_messages_to_dismiss_ = pending_texture_requests_;
539
540   // If there was a pending Reset() it can be finished now.
541   if (reset_reply_context_.is_valid()) {
542     while (!pending_decodes_.empty()) {
543       const PendingDecode& decode = pending_decodes_.front();
544       host()->SendReply(decode.reply_context,
545                         PpapiPluginMsg_VideoDecoder_DecodeReply(decode.shm_id));
546       DCHECK(shm_buffers_[decode.shm_id].busy);
547       shm_buffers_[decode.shm_id].busy = false;
548       pending_decodes_.pop_front();
549     }
550     NotifyResetDone();
551   }
552
553   // Resubmit all pending decodes.
554   for (const PendingDecode& decode : pending_decodes_) {
555     DCHECK(shm_buffers_[decode.shm_id].busy);
556     decoder_->Decode(media::BitstreamBuffer(
557         decode.decode_id, shm_buffers_[decode.shm_id].region.Duplicate(),
558         decode.size));
559   }
560
561   // Flush the new decoder if Flush() was pending.
562   if (flush_reply_context_.is_valid())
563     decoder_->Flush();
564
565   return true;
566 #endif
567 }
568
569 PepperVideoDecoderHost::PendingDecodeList::iterator
570 PepperVideoDecoderHost::GetPendingDecodeById(int32_t decode_id) {
571   return base::ranges::find(pending_decodes_, decode_id,
572                             &PendingDecode::decode_id);
573 }
574
575 }  // namespace content