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