Refactor WebsiteSettings to operate on a SecurityInfo
[chromium-blink-merge.git] / content / renderer / pepper / pepper_video_decoder_host.cc
blobc6c5f739901277140abec689a026c4d03750cef0
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.
5 #include "content/renderer/pepper/pepper_video_decoder_host.h"
7 #include "base/bind.h"
8 #include "base/memory/shared_memory.h"
9 #include "content/common/gpu/client/command_buffer_proxy_impl.h"
10 #include "content/common/pepper_file_util.h"
11 #include "content/public/common/content_client.h"
12 #include "content/public/renderer/content_renderer_client.h"
13 #include "content/public/renderer/render_thread.h"
14 #include "content/public/renderer/renderer_ppapi_host.h"
15 #include "content/renderer/pepper/gfx_conversion.h"
16 #include "content/renderer/pepper/ppb_graphics_3d_impl.h"
17 #include "content/renderer/pepper/video_decoder_shim.h"
18 #include "media/base/limits.h"
19 #include "media/video/video_decode_accelerator.h"
20 #include "ppapi/c/pp_completion_callback.h"
21 #include "ppapi/c/pp_errors.h"
22 #include "ppapi/host/dispatch_host_message.h"
23 #include "ppapi/host/ppapi_host.h"
24 #include "ppapi/proxy/ppapi_messages.h"
25 #include "ppapi/proxy/video_decoder_constants.h"
26 #include "ppapi/thunk/enter.h"
27 #include "ppapi/thunk/ppb_graphics_3d_api.h"
29 using ppapi::proxy::SerializedHandle;
30 using ppapi::thunk::EnterResourceNoLock;
31 using ppapi::thunk::PPB_Graphics3D_API;
33 namespace content {
35 namespace {
37 media::VideoCodecProfile PepperToMediaVideoProfile(PP_VideoProfile profile) {
38 switch (profile) {
39 case PP_VIDEOPROFILE_H264BASELINE:
40 return media::H264PROFILE_BASELINE;
41 case PP_VIDEOPROFILE_H264MAIN:
42 return media::H264PROFILE_MAIN;
43 case PP_VIDEOPROFILE_H264EXTENDED:
44 return media::H264PROFILE_EXTENDED;
45 case PP_VIDEOPROFILE_H264HIGH:
46 return media::H264PROFILE_HIGH;
47 case PP_VIDEOPROFILE_H264HIGH10PROFILE:
48 return media::H264PROFILE_HIGH10PROFILE;
49 case PP_VIDEOPROFILE_H264HIGH422PROFILE:
50 return media::H264PROFILE_HIGH422PROFILE;
51 case PP_VIDEOPROFILE_H264HIGH444PREDICTIVEPROFILE:
52 return media::H264PROFILE_HIGH444PREDICTIVEPROFILE;
53 case PP_VIDEOPROFILE_H264SCALABLEBASELINE:
54 return media::H264PROFILE_SCALABLEBASELINE;
55 case PP_VIDEOPROFILE_H264SCALABLEHIGH:
56 return media::H264PROFILE_SCALABLEHIGH;
57 case PP_VIDEOPROFILE_H264STEREOHIGH:
58 return media::H264PROFILE_STEREOHIGH;
59 case PP_VIDEOPROFILE_H264MULTIVIEWHIGH:
60 return media::H264PROFILE_MULTIVIEWHIGH;
61 case PP_VIDEOPROFILE_VP8_ANY:
62 return media::VP8PROFILE_ANY;
63 case PP_VIDEOPROFILE_VP9_ANY:
64 return media::VP9PROFILE_ANY;
65 // No default case, to catch unhandled PP_VideoProfile values.
68 return media::VIDEO_CODEC_PROFILE_UNKNOWN;
71 } // namespace
73 PepperVideoDecoderHost::PendingDecode::PendingDecode(
74 int32_t decode_id,
75 uint32_t shm_id,
76 uint32_t size,
77 const ppapi::host::ReplyMessageContext& reply_context)
78 : decode_id(decode_id),
79 shm_id(shm_id),
80 size(size),
81 reply_context(reply_context) {}
83 PepperVideoDecoderHost::PendingDecode::~PendingDecode() {}
85 PepperVideoDecoderHost::PepperVideoDecoderHost(RendererPpapiHost* host,
86 PP_Instance instance,
87 PP_Resource resource)
88 : ResourceHost(host->GetPpapiHost(), instance, resource),
89 renderer_ppapi_host_(host) {}
91 PepperVideoDecoderHost::~PepperVideoDecoderHost() {}
93 int32_t PepperVideoDecoderHost::OnResourceMessageReceived(
94 const IPC::Message& msg,
95 ppapi::host::HostMessageContext* context) {
96 PPAPI_BEGIN_MESSAGE_MAP(PepperVideoDecoderHost, msg)
97 PPAPI_DISPATCH_HOST_RESOURCE_CALL(PpapiHostMsg_VideoDecoder_Initialize,
98 OnHostMsgInitialize)
99 PPAPI_DISPATCH_HOST_RESOURCE_CALL(PpapiHostMsg_VideoDecoder_GetShm,
100 OnHostMsgGetShm)
101 PPAPI_DISPATCH_HOST_RESOURCE_CALL(PpapiHostMsg_VideoDecoder_Decode,
102 OnHostMsgDecode)
103 PPAPI_DISPATCH_HOST_RESOURCE_CALL(PpapiHostMsg_VideoDecoder_AssignTextures,
104 OnHostMsgAssignTextures)
105 PPAPI_DISPATCH_HOST_RESOURCE_CALL(PpapiHostMsg_VideoDecoder_RecyclePicture,
106 OnHostMsgRecyclePicture)
107 PPAPI_DISPATCH_HOST_RESOURCE_CALL_0(PpapiHostMsg_VideoDecoder_Flush,
108 OnHostMsgFlush)
109 PPAPI_DISPATCH_HOST_RESOURCE_CALL_0(PpapiHostMsg_VideoDecoder_Reset,
110 OnHostMsgReset)
111 PPAPI_END_MESSAGE_MAP()
112 return PP_ERROR_FAILED;
115 int32_t PepperVideoDecoderHost::OnHostMsgInitialize(
116 ppapi::host::HostMessageContext* context,
117 const ppapi::HostResource& graphics_context,
118 PP_VideoProfile profile,
119 PP_HardwareAcceleration acceleration,
120 uint32_t min_picture_count) {
121 if (initialized_)
122 return PP_ERROR_FAILED;
123 if (min_picture_count > ppapi::proxy::kMaximumPictureCount)
124 return PP_ERROR_BADARGUMENT;
126 EnterResourceNoLock<PPB_Graphics3D_API> enter_graphics(
127 graphics_context.host_resource(), true);
128 if (enter_graphics.failed())
129 return PP_ERROR_FAILED;
130 PPB_Graphics3D_Impl* graphics3d =
131 static_cast<PPB_Graphics3D_Impl*>(enter_graphics.object());
133 CommandBufferProxyImpl* command_buffer = graphics3d->GetCommandBufferProxy();
134 if (!command_buffer)
135 return PP_ERROR_FAILED;
137 profile_ = PepperToMediaVideoProfile(profile);
138 software_fallback_allowed_ = (acceleration != PP_HARDWAREACCELERATION_ONLY);
140 // Check for Dev API use
141 // TODO(lpique): remove check when PPB_VideoDecoder_1_1 reaches beta/stable.
142 // https://crbug.com/520323
143 if (min_picture_count != 0) {
144 ContentRendererClient* client = GetContentClient()->renderer();
145 bool allowed = client->IsPluginAllowedToUseDevChannelAPIs();
146 if (!allowed)
147 return PP_ERROR_NOTSUPPORTED;
149 min_picture_count_ = min_picture_count;
151 if (acceleration != PP_HARDWAREACCELERATION_NONE) {
152 // This is not synchronous, but subsequent IPC messages will be buffered, so
153 // it is okay to immediately send IPC messages.
154 decoder_ = command_buffer->CreateVideoDecoder();
155 if (decoder_ && decoder_->Initialize(profile_, this)) {
156 initialized_ = true;
157 return PP_OK;
159 decoder_.reset();
160 if (acceleration == PP_HARDWAREACCELERATION_ONLY)
161 return PP_ERROR_NOTSUPPORTED;
164 #if defined(OS_ANDROID)
165 return PP_ERROR_NOTSUPPORTED;
166 #else
167 if (!TryFallbackToSoftwareDecoder())
168 return PP_ERROR_FAILED;
170 initialized_ = true;
171 return PP_OK;
172 #endif
175 int32_t PepperVideoDecoderHost::OnHostMsgGetShm(
176 ppapi::host::HostMessageContext* context,
177 uint32_t shm_id,
178 uint32_t shm_size) {
179 if (!initialized_)
180 return PP_ERROR_FAILED;
182 // Make the buffers larger since we hope to reuse them.
183 shm_size = std::max(
184 shm_size,
185 static_cast<uint32_t>(ppapi::proxy::kMinimumBitstreamBufferSize));
186 if (shm_size > ppapi::proxy::kMaximumBitstreamBufferSize)
187 return PP_ERROR_FAILED;
189 if (shm_id >= ppapi::proxy::kMaximumPendingDecodes)
190 return PP_ERROR_FAILED;
191 // The shm_id must be inside or at the end of shm_buffers_.
192 if (shm_id > shm_buffers_.size())
193 return PP_ERROR_FAILED;
194 // Reject an attempt to reallocate a busy shm buffer.
195 if (shm_id < shm_buffers_.size() && shm_buffer_busy_[shm_id])
196 return PP_ERROR_FAILED;
198 content::RenderThread* render_thread = content::RenderThread::Get();
199 scoped_ptr<base::SharedMemory> shm(
200 render_thread->HostAllocateSharedMemoryBuffer(shm_size).Pass());
201 if (!shm || !shm->Map(shm_size))
202 return PP_ERROR_FAILED;
204 base::SharedMemoryHandle shm_handle = shm->handle();
205 if (shm_id == shm_buffers_.size()) {
206 shm_buffers_.push_back(shm.release());
207 shm_buffer_busy_.push_back(false);
208 } else {
209 // Remove the old buffer. Delete manually since ScopedVector won't delete
210 // the existing element if we just assign over it.
211 delete shm_buffers_[shm_id];
212 shm_buffers_[shm_id] = shm.release();
215 SerializedHandle handle(
216 renderer_ppapi_host_->ShareSharedMemoryHandleWithRemote(shm_handle),
217 shm_size);
218 ppapi::host::ReplyMessageContext reply_context =
219 context->MakeReplyMessageContext();
220 reply_context.params.AppendHandle(handle);
221 host()->SendReply(reply_context,
222 PpapiPluginMsg_VideoDecoder_GetShmReply(shm_size));
224 return PP_OK_COMPLETIONPENDING;
227 int32_t PepperVideoDecoderHost::OnHostMsgDecode(
228 ppapi::host::HostMessageContext* context,
229 uint32_t shm_id,
230 uint32_t size,
231 int32_t decode_id) {
232 if (!initialized_)
233 return PP_ERROR_FAILED;
234 DCHECK(decoder_);
235 // |shm_id| is just an index into shm_buffers_. Make sure it's in range.
236 if (static_cast<size_t>(shm_id) >= shm_buffers_.size())
237 return PP_ERROR_FAILED;
238 // Reject an attempt to pass a busy buffer to the decoder again.
239 if (shm_buffer_busy_[shm_id])
240 return PP_ERROR_FAILED;
241 // Reject non-unique decode_id values.
242 if (GetPendingDecodeById(decode_id) != pending_decodes_.end())
243 return PP_ERROR_FAILED;
245 if (flush_reply_context_.is_valid() || reset_reply_context_.is_valid())
246 return PP_ERROR_FAILED;
248 pending_decodes_.push_back(PendingDecode(decode_id, shm_id, size,
249 context->MakeReplyMessageContext()));
251 shm_buffer_busy_[shm_id] = true;
252 decoder_->Decode(
253 media::BitstreamBuffer(decode_id, shm_buffers_[shm_id]->handle(), size));
255 return PP_OK_COMPLETIONPENDING;
258 int32_t PepperVideoDecoderHost::OnHostMsgAssignTextures(
259 ppapi::host::HostMessageContext* context,
260 const PP_Size& size,
261 const std::vector<uint32_t>& texture_ids) {
262 if (!initialized_)
263 return PP_ERROR_FAILED;
264 DCHECK(decoder_);
266 // Verify that the new texture IDs are unique and store them in
267 // |new_textures|.
268 PictureBufferMap new_textures;
269 for (uint32_t i = 0; i < texture_ids.size(); i++) {
270 if (picture_buffer_map_.find(texture_ids[i]) != picture_buffer_map_.end() ||
271 new_textures.find(texture_ids[i]) != new_textures.end()) {
272 // Can't assign the same texture more than once.
273 return PP_ERROR_BADARGUMENT;
275 new_textures.insert(
276 std::make_pair(texture_ids[i], PictureBufferState::ASSIGNED));
279 picture_buffer_map_.insert(new_textures.begin(), new_textures.end());
281 std::vector<media::PictureBuffer> picture_buffers;
282 for (uint32_t i = 0; i < texture_ids.size(); i++) {
283 media::PictureBuffer buffer(
284 texture_ids[i], // Use the texture_id to identify the buffer.
285 gfx::Size(size.width, size.height),
286 texture_ids[i]);
287 picture_buffers.push_back(buffer);
289 decoder_->AssignPictureBuffers(picture_buffers);
290 return PP_OK;
293 int32_t PepperVideoDecoderHost::OnHostMsgRecyclePicture(
294 ppapi::host::HostMessageContext* context,
295 uint32_t texture_id) {
296 if (!initialized_)
297 return PP_ERROR_FAILED;
298 DCHECK(decoder_);
300 PictureBufferMap::iterator it = picture_buffer_map_.find(texture_id);
301 if (it == picture_buffer_map_.end())
302 return PP_ERROR_BADARGUMENT;
304 switch (it->second) {
305 case PictureBufferState::ASSIGNED:
306 return PP_ERROR_BADARGUMENT;
308 case PictureBufferState::IN_USE:
309 it->second = PictureBufferState::ASSIGNED;
310 decoder_->ReusePictureBuffer(texture_id);
311 break;
313 case PictureBufferState::DISMISSED:
314 picture_buffer_map_.erase(it);
315 // The texture was already dismissed by the decoder. Notify the plugin.
316 host()->SendUnsolicitedReply(
317 pp_resource(),
318 PpapiPluginMsg_VideoDecoder_DismissPicture(texture_id));
319 break;
322 return PP_OK;
325 int32_t PepperVideoDecoderHost::OnHostMsgFlush(
326 ppapi::host::HostMessageContext* context) {
327 if (!initialized_)
328 return PP_ERROR_FAILED;
329 DCHECK(decoder_);
330 if (flush_reply_context_.is_valid() || reset_reply_context_.is_valid())
331 return PP_ERROR_FAILED;
333 flush_reply_context_ = context->MakeReplyMessageContext();
334 decoder_->Flush();
336 return PP_OK_COMPLETIONPENDING;
339 int32_t PepperVideoDecoderHost::OnHostMsgReset(
340 ppapi::host::HostMessageContext* context) {
341 if (!initialized_)
342 return PP_ERROR_FAILED;
343 DCHECK(decoder_);
344 if (flush_reply_context_.is_valid() || reset_reply_context_.is_valid())
345 return PP_ERROR_FAILED;
347 reset_reply_context_ = context->MakeReplyMessageContext();
348 decoder_->Reset();
350 return PP_OK_COMPLETIONPENDING;
353 void PepperVideoDecoderHost::ProvidePictureBuffers(
354 uint32 requested_num_of_buffers,
355 const gfx::Size& dimensions,
356 uint32 texture_target) {
357 RequestTextures(std::max(min_picture_count_, requested_num_of_buffers),
358 dimensions,
359 texture_target,
360 std::vector<gpu::Mailbox>());
363 void PepperVideoDecoderHost::PictureReady(const media::Picture& picture) {
364 PictureBufferMap::iterator it =
365 picture_buffer_map_.find(picture.picture_buffer_id());
366 DCHECK(it != picture_buffer_map_.end());
367 DCHECK(it->second == PictureBufferState::ASSIGNED);
368 it->second = PictureBufferState::IN_USE;
370 // Don't bother validating the visible rect, since the plugin process is less
371 // trusted than the gpu process.
372 PP_Rect visible_rect = PP_FromGfxRect(picture.visible_rect());
373 host()->SendUnsolicitedReply(pp_resource(),
374 PpapiPluginMsg_VideoDecoder_PictureReady(
375 picture.bitstream_buffer_id(),
376 picture.picture_buffer_id(), visible_rect));
379 void PepperVideoDecoderHost::DismissPictureBuffer(int32 picture_buffer_id) {
380 PictureBufferMap::iterator it = picture_buffer_map_.find(picture_buffer_id);
381 DCHECK(it != picture_buffer_map_.end());
383 // If the texture is still used by the plugin keep it until the plugin
384 // recycles it.
385 if (it->second == PictureBufferState::IN_USE) {
386 it->second = PictureBufferState::DISMISSED;
387 return;
390 DCHECK(it->second == PictureBufferState::ASSIGNED);
391 picture_buffer_map_.erase(it);
392 host()->SendUnsolicitedReply(
393 pp_resource(),
394 PpapiPluginMsg_VideoDecoder_DismissPicture(picture_buffer_id));
397 void PepperVideoDecoderHost::NotifyEndOfBitstreamBuffer(
398 int32 bitstream_buffer_id) {
399 PendingDecodeList::iterator it = GetPendingDecodeById(bitstream_buffer_id);
400 if (it == pending_decodes_.end()) {
401 NOTREACHED();
402 return;
404 host()->SendReply(it->reply_context,
405 PpapiPluginMsg_VideoDecoder_DecodeReply(it->shm_id));
406 shm_buffer_busy_[it->shm_id] = false;
407 pending_decodes_.erase(it);
410 void PepperVideoDecoderHost::NotifyFlushDone() {
411 DCHECK(pending_decodes_.empty());
412 host()->SendReply(flush_reply_context_,
413 PpapiPluginMsg_VideoDecoder_FlushReply());
414 flush_reply_context_ = ppapi::host::ReplyMessageContext();
417 void PepperVideoDecoderHost::NotifyResetDone() {
418 DCHECK(pending_decodes_.empty());
419 host()->SendReply(reset_reply_context_,
420 PpapiPluginMsg_VideoDecoder_ResetReply());
421 reset_reply_context_ = ppapi::host::ReplyMessageContext();
424 void PepperVideoDecoderHost::NotifyError(
425 media::VideoDecodeAccelerator::Error error) {
426 int32_t pp_error = PP_ERROR_FAILED;
427 switch (error) {
428 case media::VideoDecodeAccelerator::UNREADABLE_INPUT:
429 pp_error = PP_ERROR_MALFORMED_INPUT;
430 break;
431 case media::VideoDecodeAccelerator::ILLEGAL_STATE:
432 case media::VideoDecodeAccelerator::INVALID_ARGUMENT:
433 case media::VideoDecodeAccelerator::PLATFORM_FAILURE:
434 case media::VideoDecodeAccelerator::LARGEST_ERROR_ENUM:
435 pp_error = PP_ERROR_RESOURCE_FAILED;
436 break;
437 // No default case, to catch unhandled enum values.
440 // Try to initialize software decoder and use it instead.
441 if (!software_fallback_used_ && software_fallback_allowed_) {
442 VLOG(0)
443 << "Hardware decoder has returned an error. Trying Software decoder.";
444 if (TryFallbackToSoftwareDecoder())
445 return;
448 host()->SendUnsolicitedReply(
449 pp_resource(), PpapiPluginMsg_VideoDecoder_NotifyError(pp_error));
452 const uint8_t* PepperVideoDecoderHost::DecodeIdToAddress(uint32_t decode_id) {
453 PendingDecodeList::const_iterator it = GetPendingDecodeById(decode_id);
454 DCHECK(it != pending_decodes_.end());
455 uint32_t shm_id = it->shm_id;
456 return static_cast<uint8_t*>(shm_buffers_[shm_id]->memory());
459 void PepperVideoDecoderHost::RequestTextures(
460 uint32 requested_num_of_buffers,
461 const gfx::Size& dimensions,
462 uint32 texture_target,
463 const std::vector<gpu::Mailbox>& mailboxes) {
464 host()->SendUnsolicitedReply(
465 pp_resource(),
466 PpapiPluginMsg_VideoDecoder_RequestTextures(
467 requested_num_of_buffers,
468 PP_MakeSize(dimensions.width(), dimensions.height()),
469 texture_target,
470 mailboxes));
473 bool PepperVideoDecoderHost::TryFallbackToSoftwareDecoder() {
474 #if defined(OS_ANDROID)
475 return false;
476 #else
477 DCHECK(!software_fallback_used_ && software_fallback_allowed_);
479 uint32_t shim_texture_pool_size = media::limits::kMaxVideoFrames + 1;
480 shim_texture_pool_size = std::max(shim_texture_pool_size,
481 min_picture_count_);
482 scoped_ptr<VideoDecoderShim> new_decoder(
483 new VideoDecoderShim(this, shim_texture_pool_size));
484 if (!new_decoder->Initialize(profile_, this))
485 return false;
487 software_fallback_used_ = true;
488 decoder_.reset(new_decoder.release());
490 // Dismiss all assigned pictures and mark all pictures in use as DISMISSED.
491 PictureBufferMap pictures_pending_dismission;
492 for (auto& picture : picture_buffer_map_) {
493 if (picture.second == PictureBufferState::ASSIGNED) {
494 host()->SendUnsolicitedReply(
495 pp_resource(),
496 PpapiPluginMsg_VideoDecoder_DismissPicture(picture.first));
497 } else {
498 pictures_pending_dismission.insert(
499 std::make_pair(picture.first, PictureBufferState::DISMISSED));
502 picture_buffer_map_.swap(pictures_pending_dismission);
504 // If there was a pending Reset() it can be finished now.
505 if (reset_reply_context_.is_valid()) {
506 while (!pending_decodes_.empty()) {
507 const PendingDecode& decode = pending_decodes_.front();
508 host()->SendReply(decode.reply_context,
509 PpapiPluginMsg_VideoDecoder_DecodeReply(decode.shm_id));
510 DCHECK(shm_buffer_busy_[decode.shm_id]);
511 shm_buffer_busy_[decode.shm_id] = false;
512 pending_decodes_.pop_front();
514 NotifyResetDone();
517 // Resubmit all pending decodes.
518 for (const PendingDecode& decode : pending_decodes_) {
519 DCHECK(shm_buffer_busy_[decode.shm_id]);
520 decoder_->Decode(media::BitstreamBuffer(
521 decode.decode_id, shm_buffers_[decode.shm_id]->handle(), decode.size));
524 // Flush the new decoder if Flush() was pending.
525 if (flush_reply_context_.is_valid())
526 decoder_->Flush();
528 return true;
529 #endif
532 PepperVideoDecoderHost::PendingDecodeList::iterator
533 PepperVideoDecoderHost::GetPendingDecodeById(int32_t decode_id) {
534 return std::find_if(pending_decodes_.begin(), pending_decodes_.end(),
535 [decode_id](const PendingDecode& item) {
536 return item.decode_id == decode_id;
540 } // namespace content