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