mesa gn build: suppress -Wstring-conversion warnings
[chromium-blink-merge.git] / content / renderer / pepper / pepper_video_decoder_host.cc
blob02e14f3be5cf9506ea8259970d15084930cc7a0d
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/gpu_channel_host.h"
10 #include "content/public/renderer/render_thread.h"
11 #include "content/public/renderer/renderer_ppapi_host.h"
12 #include "content/renderer/pepper/gfx_conversion.h"
13 #include "content/renderer/pepper/ppb_graphics_3d_impl.h"
14 #include "content/renderer/pepper/video_decoder_shim.h"
15 #include "media/video/video_decode_accelerator.h"
16 #include "ppapi/c/pp_completion_callback.h"
17 #include "ppapi/c/pp_errors.h"
18 #include "ppapi/host/dispatch_host_message.h"
19 #include "ppapi/host/ppapi_host.h"
20 #include "ppapi/proxy/ppapi_messages.h"
21 #include "ppapi/proxy/video_decoder_constants.h"
22 #include "ppapi/thunk/enter.h"
23 #include "ppapi/thunk/ppb_graphics_3d_api.h"
25 using ppapi::proxy::SerializedHandle;
26 using ppapi::thunk::EnterResourceNoLock;
27 using ppapi::thunk::PPB_Graphics3D_API;
29 namespace content {
31 namespace {
33 media::VideoCodecProfile PepperToMediaVideoProfile(PP_VideoProfile profile) {
34 switch (profile) {
35 case PP_VIDEOPROFILE_H264BASELINE:
36 return media::H264PROFILE_BASELINE;
37 case PP_VIDEOPROFILE_H264MAIN:
38 return media::H264PROFILE_MAIN;
39 case PP_VIDEOPROFILE_H264EXTENDED:
40 return media::H264PROFILE_EXTENDED;
41 case PP_VIDEOPROFILE_H264HIGH:
42 return media::H264PROFILE_HIGH;
43 case PP_VIDEOPROFILE_H264HIGH10PROFILE:
44 return media::H264PROFILE_HIGH10PROFILE;
45 case PP_VIDEOPROFILE_H264HIGH422PROFILE:
46 return media::H264PROFILE_HIGH422PROFILE;
47 case PP_VIDEOPROFILE_H264HIGH444PREDICTIVEPROFILE:
48 return media::H264PROFILE_HIGH444PREDICTIVEPROFILE;
49 case PP_VIDEOPROFILE_H264SCALABLEBASELINE:
50 return media::H264PROFILE_SCALABLEBASELINE;
51 case PP_VIDEOPROFILE_H264SCALABLEHIGH:
52 return media::H264PROFILE_SCALABLEHIGH;
53 case PP_VIDEOPROFILE_H264STEREOHIGH:
54 return media::H264PROFILE_STEREOHIGH;
55 case PP_VIDEOPROFILE_H264MULTIVIEWHIGH:
56 return media::H264PROFILE_MULTIVIEWHIGH;
57 case PP_VIDEOPROFILE_VP8_ANY:
58 return media::VP8PROFILE_ANY;
59 case PP_VIDEOPROFILE_VP9_ANY:
60 return media::VP9PROFILE_ANY;
61 // No default case, to catch unhandled PP_VideoProfile values.
64 return media::VIDEO_CODEC_PROFILE_UNKNOWN;
67 } // namespace
69 PepperVideoDecoderHost::PendingDecode::PendingDecode(
70 uint32_t shm_id,
71 const ppapi::host::ReplyMessageContext& reply_context)
72 : shm_id(shm_id), reply_context(reply_context) {
75 PepperVideoDecoderHost::PendingDecode::~PendingDecode() {
78 PepperVideoDecoderHost::PepperVideoDecoderHost(RendererPpapiHost* host,
79 PP_Instance instance,
80 PP_Resource resource)
81 : ResourceHost(host->GetPpapiHost(), instance, resource),
82 renderer_ppapi_host_(host),
83 initialized_(false) {
86 PepperVideoDecoderHost::~PepperVideoDecoderHost() {
89 int32_t PepperVideoDecoderHost::OnResourceMessageReceived(
90 const IPC::Message& msg,
91 ppapi::host::HostMessageContext* context) {
92 PPAPI_BEGIN_MESSAGE_MAP(PepperVideoDecoderHost, msg)
93 PPAPI_DISPATCH_HOST_RESOURCE_CALL(PpapiHostMsg_VideoDecoder_Initialize,
94 OnHostMsgInitialize)
95 PPAPI_DISPATCH_HOST_RESOURCE_CALL(PpapiHostMsg_VideoDecoder_GetShm,
96 OnHostMsgGetShm)
97 PPAPI_DISPATCH_HOST_RESOURCE_CALL(PpapiHostMsg_VideoDecoder_Decode,
98 OnHostMsgDecode)
99 PPAPI_DISPATCH_HOST_RESOURCE_CALL(PpapiHostMsg_VideoDecoder_AssignTextures,
100 OnHostMsgAssignTextures)
101 PPAPI_DISPATCH_HOST_RESOURCE_CALL(PpapiHostMsg_VideoDecoder_RecyclePicture,
102 OnHostMsgRecyclePicture)
103 PPAPI_DISPATCH_HOST_RESOURCE_CALL_0(PpapiHostMsg_VideoDecoder_Flush,
104 OnHostMsgFlush)
105 PPAPI_DISPATCH_HOST_RESOURCE_CALL_0(PpapiHostMsg_VideoDecoder_Reset,
106 OnHostMsgReset)
107 PPAPI_END_MESSAGE_MAP()
108 return PP_ERROR_FAILED;
111 int32_t PepperVideoDecoderHost::OnHostMsgInitialize(
112 ppapi::host::HostMessageContext* context,
113 const ppapi::HostResource& graphics_context,
114 PP_VideoProfile profile,
115 PP_HardwareAcceleration acceleration) {
116 if (initialized_)
117 return PP_ERROR_FAILED;
119 EnterResourceNoLock<PPB_Graphics3D_API> enter_graphics(
120 graphics_context.host_resource(), true);
121 if (enter_graphics.failed())
122 return PP_ERROR_FAILED;
123 PPB_Graphics3D_Impl* graphics3d =
124 static_cast<PPB_Graphics3D_Impl*>(enter_graphics.object());
126 int command_buffer_route_id = graphics3d->GetCommandBufferRouteId();
127 if (!command_buffer_route_id)
128 return PP_ERROR_FAILED;
130 media::VideoCodecProfile media_profile = PepperToMediaVideoProfile(profile);
132 if (acceleration != PP_HARDWAREACCELERATION_NONE) {
133 // This is not synchronous, but subsequent IPC messages will be buffered, so
134 // it is okay to immediately send IPC messages through the returned channel.
135 GpuChannelHost* channel = graphics3d->channel();
136 DCHECK(channel);
137 decoder_ = channel->CreateVideoDecoder(command_buffer_route_id);
138 if (decoder_ && decoder_->Initialize(media_profile, this)) {
139 initialized_ = true;
140 return PP_OK;
142 decoder_.reset();
143 if (acceleration == PP_HARDWAREACCELERATION_ONLY)
144 return PP_ERROR_NOTSUPPORTED;
147 #if defined(OS_ANDROID)
148 return PP_ERROR_NOTSUPPORTED;
149 #else
150 decoder_.reset(new VideoDecoderShim(this));
151 initialize_reply_context_ = context->MakeReplyMessageContext();
152 decoder_->Initialize(media_profile, this);
154 return PP_OK_COMPLETIONPENDING;
155 #endif
158 int32_t PepperVideoDecoderHost::OnHostMsgGetShm(
159 ppapi::host::HostMessageContext* context,
160 uint32_t shm_id,
161 uint32_t shm_size) {
162 if (!initialized_)
163 return PP_ERROR_FAILED;
165 // Make the buffers larger since we hope to reuse them.
166 shm_size = std::max(
167 shm_size,
168 static_cast<uint32_t>(ppapi::proxy::kMinimumBitstreamBufferSize));
169 if (shm_size > ppapi::proxy::kMaximumBitstreamBufferSize)
170 return PP_ERROR_FAILED;
172 if (shm_id >= ppapi::proxy::kMaximumPendingDecodes)
173 return PP_ERROR_FAILED;
174 // The shm_id must be inside or at the end of shm_buffers_.
175 if (shm_id > shm_buffers_.size())
176 return PP_ERROR_FAILED;
177 // Reject an attempt to reallocate a busy shm buffer.
178 if (shm_id < shm_buffers_.size() && shm_buffer_busy_[shm_id])
179 return PP_ERROR_FAILED;
181 content::RenderThread* render_thread = content::RenderThread::Get();
182 scoped_ptr<base::SharedMemory> shm(
183 render_thread->HostAllocateSharedMemoryBuffer(shm_size).Pass());
184 if (!shm || !shm->Map(shm_size))
185 return PP_ERROR_FAILED;
187 base::SharedMemoryHandle shm_handle = shm->handle();
188 if (shm_id == shm_buffers_.size()) {
189 shm_buffers_.push_back(shm.release());
190 shm_buffer_busy_.push_back(false);
191 } else {
192 // Remove the old buffer. Delete manually since ScopedVector won't delete
193 // the existing element if we just assign over it.
194 delete shm_buffers_[shm_id];
195 shm_buffers_[shm_id] = shm.release();
198 #if defined(OS_WIN)
199 base::PlatformFile platform_file = shm_handle;
200 #elif defined(OS_POSIX)
201 base::PlatformFile platform_file = shm_handle.fd;
202 #else
203 #error Not implemented.
204 #endif
205 SerializedHandle handle(
206 renderer_ppapi_host_->ShareHandleWithRemote(platform_file, false),
207 shm_size);
208 ppapi::host::ReplyMessageContext reply_context =
209 context->MakeReplyMessageContext();
210 reply_context.params.AppendHandle(handle);
211 host()->SendReply(reply_context,
212 PpapiPluginMsg_VideoDecoder_GetShmReply(shm_size));
214 return PP_OK_COMPLETIONPENDING;
217 int32_t PepperVideoDecoderHost::OnHostMsgDecode(
218 ppapi::host::HostMessageContext* context,
219 uint32_t shm_id,
220 uint32_t size,
221 int32_t decode_id) {
222 if (!initialized_)
223 return PP_ERROR_FAILED;
224 DCHECK(decoder_);
225 // |shm_id| is just an index into shm_buffers_. Make sure it's in range.
226 if (static_cast<size_t>(shm_id) >= shm_buffers_.size())
227 return PP_ERROR_FAILED;
228 // Reject an attempt to pass a busy buffer to the decoder again.
229 if (shm_buffer_busy_[shm_id])
230 return PP_ERROR_FAILED;
231 // Reject non-unique decode_id values.
232 if (pending_decodes_.find(decode_id) != pending_decodes_.end())
233 return PP_ERROR_FAILED;
235 if (flush_reply_context_.is_valid() || reset_reply_context_.is_valid())
236 return PP_ERROR_FAILED;
238 pending_decodes_.insert(std::make_pair(
239 decode_id, PendingDecode(shm_id, context->MakeReplyMessageContext())));
241 shm_buffer_busy_[shm_id] = true;
242 decoder_->Decode(
243 media::BitstreamBuffer(decode_id, shm_buffers_[shm_id]->handle(), size));
245 return PP_OK_COMPLETIONPENDING;
248 int32_t PepperVideoDecoderHost::OnHostMsgAssignTextures(
249 ppapi::host::HostMessageContext* context,
250 const PP_Size& size,
251 const std::vector<uint32_t>& texture_ids) {
252 if (!initialized_)
253 return PP_ERROR_FAILED;
254 DCHECK(decoder_);
256 std::vector<media::PictureBuffer> picture_buffers;
257 for (uint32 i = 0; i < texture_ids.size(); i++) {
258 media::PictureBuffer buffer(
259 texture_ids[i], // Use the texture_id to identify the buffer.
260 gfx::Size(size.width, size.height),
261 texture_ids[i]);
262 picture_buffers.push_back(buffer);
264 decoder_->AssignPictureBuffers(picture_buffers);
265 return PP_OK;
268 int32_t PepperVideoDecoderHost::OnHostMsgRecyclePicture(
269 ppapi::host::HostMessageContext* context,
270 uint32_t texture_id) {
271 if (!initialized_)
272 return PP_ERROR_FAILED;
273 DCHECK(decoder_);
275 decoder_->ReusePictureBuffer(texture_id);
276 return PP_OK;
279 int32_t PepperVideoDecoderHost::OnHostMsgFlush(
280 ppapi::host::HostMessageContext* context) {
281 if (!initialized_)
282 return PP_ERROR_FAILED;
283 DCHECK(decoder_);
284 if (flush_reply_context_.is_valid() || reset_reply_context_.is_valid())
285 return PP_ERROR_FAILED;
287 flush_reply_context_ = context->MakeReplyMessageContext();
288 decoder_->Flush();
290 return PP_OK_COMPLETIONPENDING;
293 int32_t PepperVideoDecoderHost::OnHostMsgReset(
294 ppapi::host::HostMessageContext* context) {
295 if (!initialized_)
296 return PP_ERROR_FAILED;
297 DCHECK(decoder_);
298 if (flush_reply_context_.is_valid() || reset_reply_context_.is_valid())
299 return PP_ERROR_FAILED;
301 reset_reply_context_ = context->MakeReplyMessageContext();
302 decoder_->Reset();
304 return PP_OK_COMPLETIONPENDING;
307 void PepperVideoDecoderHost::ProvidePictureBuffers(
308 uint32 requested_num_of_buffers,
309 const gfx::Size& dimensions,
310 uint32 texture_target) {
311 RequestTextures(requested_num_of_buffers,
312 dimensions,
313 texture_target,
314 std::vector<gpu::Mailbox>());
317 void PepperVideoDecoderHost::PictureReady(const media::Picture& picture) {
318 // Don't bother validating the visible rect, since the plugin process is less
319 // trusted than the gpu process.
320 PP_Rect visible_rect = PP_FromGfxRect(picture.visible_rect());
321 host()->SendUnsolicitedReply(pp_resource(),
322 PpapiPluginMsg_VideoDecoder_PictureReady(
323 picture.bitstream_buffer_id(),
324 picture.picture_buffer_id(), visible_rect));
327 void PepperVideoDecoderHost::DismissPictureBuffer(int32 picture_buffer_id) {
328 host()->SendUnsolicitedReply(
329 pp_resource(),
330 PpapiPluginMsg_VideoDecoder_DismissPicture(picture_buffer_id));
333 void PepperVideoDecoderHost::NotifyEndOfBitstreamBuffer(
334 int32 bitstream_buffer_id) {
335 PendingDecodeMap::iterator it = pending_decodes_.find(bitstream_buffer_id);
336 if (it == pending_decodes_.end()) {
337 NOTREACHED();
338 return;
340 const PendingDecode& pending_decode = it->second;
341 host()->SendReply(
342 pending_decode.reply_context,
343 PpapiPluginMsg_VideoDecoder_DecodeReply(pending_decode.shm_id));
344 shm_buffer_busy_[pending_decode.shm_id] = false;
345 pending_decodes_.erase(it);
348 void PepperVideoDecoderHost::NotifyFlushDone() {
349 DCHECK(pending_decodes_.empty());
350 host()->SendReply(flush_reply_context_,
351 PpapiPluginMsg_VideoDecoder_FlushReply());
352 flush_reply_context_ = ppapi::host::ReplyMessageContext();
355 void PepperVideoDecoderHost::NotifyResetDone() {
356 DCHECK(pending_decodes_.empty());
357 host()->SendReply(reset_reply_context_,
358 PpapiPluginMsg_VideoDecoder_ResetReply());
359 reset_reply_context_ = ppapi::host::ReplyMessageContext();
362 void PepperVideoDecoderHost::NotifyError(
363 media::VideoDecodeAccelerator::Error error) {
364 int32_t pp_error = PP_ERROR_FAILED;
365 switch (error) {
366 case media::VideoDecodeAccelerator::UNREADABLE_INPUT:
367 pp_error = PP_ERROR_MALFORMED_INPUT;
368 break;
369 case media::VideoDecodeAccelerator::ILLEGAL_STATE:
370 case media::VideoDecodeAccelerator::INVALID_ARGUMENT:
371 case media::VideoDecodeAccelerator::PLATFORM_FAILURE:
372 case media::VideoDecodeAccelerator::LARGEST_ERROR_ENUM:
373 pp_error = PP_ERROR_RESOURCE_FAILED;
374 break;
375 // No default case, to catch unhandled enum values.
377 host()->SendUnsolicitedReply(
378 pp_resource(), PpapiPluginMsg_VideoDecoder_NotifyError(pp_error));
381 void PepperVideoDecoderHost::OnInitializeComplete(int32_t result) {
382 if (!initialized_) {
383 if (result == PP_OK)
384 initialized_ = true;
385 initialize_reply_context_.params.set_result(result);
386 host()->SendReply(initialize_reply_context_,
387 PpapiPluginMsg_VideoDecoder_InitializeReply());
391 const uint8_t* PepperVideoDecoderHost::DecodeIdToAddress(uint32_t decode_id) {
392 PendingDecodeMap::const_iterator it = pending_decodes_.find(decode_id);
393 DCHECK(it != pending_decodes_.end());
394 uint32_t shm_id = it->second.shm_id;
395 return static_cast<uint8_t*>(shm_buffers_[shm_id]->memory());
398 void PepperVideoDecoderHost::RequestTextures(
399 uint32 requested_num_of_buffers,
400 const gfx::Size& dimensions,
401 uint32 texture_target,
402 const std::vector<gpu::Mailbox>& mailboxes) {
403 host()->SendUnsolicitedReply(
404 pp_resource(),
405 PpapiPluginMsg_VideoDecoder_RequestTextures(
406 requested_num_of_buffers,
407 PP_MakeSize(dimensions.width(), dimensions.height()),
408 texture_target,
409 mailboxes));
412 } // namespace content