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"
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/ppb_graphics_3d_impl.h"
13 #include "content/renderer/pepper/video_decoder_shim.h"
14 #include "media/video/video_decode_accelerator.h"
15 #include "ppapi/c/pp_completion_callback.h"
16 #include "ppapi/c/pp_errors.h"
17 #include "ppapi/host/dispatch_host_message.h"
18 #include "ppapi/host/ppapi_host.h"
19 #include "ppapi/proxy/ppapi_messages.h"
20 #include "ppapi/proxy/video_decoder_constants.h"
21 #include "ppapi/thunk/enter.h"
22 #include "ppapi/thunk/ppb_graphics_3d_api.h"
24 using ppapi::proxy::SerializedHandle
;
25 using ppapi::thunk::EnterResourceNoLock
;
26 using ppapi::thunk::PPB_Graphics3D_API
;
32 media::VideoCodecProfile
PepperToMediaVideoProfile(PP_VideoProfile profile
) {
34 case PP_VIDEOPROFILE_H264BASELINE
:
35 return media::H264PROFILE_BASELINE
;
36 case PP_VIDEOPROFILE_H264MAIN
:
37 return media::H264PROFILE_MAIN
;
38 case PP_VIDEOPROFILE_H264EXTENDED
:
39 return media::H264PROFILE_EXTENDED
;
40 case PP_VIDEOPROFILE_H264HIGH
:
41 return media::H264PROFILE_HIGH
;
42 case PP_VIDEOPROFILE_H264HIGH10PROFILE
:
43 return media::H264PROFILE_HIGH10PROFILE
;
44 case PP_VIDEOPROFILE_H264HIGH422PROFILE
:
45 return media::H264PROFILE_HIGH422PROFILE
;
46 case PP_VIDEOPROFILE_H264HIGH444PREDICTIVEPROFILE
:
47 return media::H264PROFILE_HIGH444PREDICTIVEPROFILE
;
48 case PP_VIDEOPROFILE_H264SCALABLEBASELINE
:
49 return media::H264PROFILE_SCALABLEBASELINE
;
50 case PP_VIDEOPROFILE_H264SCALABLEHIGH
:
51 return media::H264PROFILE_SCALABLEHIGH
;
52 case PP_VIDEOPROFILE_H264STEREOHIGH
:
53 return media::H264PROFILE_STEREOHIGH
;
54 case PP_VIDEOPROFILE_H264MULTIVIEWHIGH
:
55 return media::H264PROFILE_MULTIVIEWHIGH
;
56 case PP_VIDEOPROFILE_VP8_ANY
:
57 return media::VP8PROFILE_ANY
;
58 case PP_VIDEOPROFILE_VP9_ANY
:
59 return media::VP9PROFILE_ANY
;
60 // No default case, to catch unhandled PP_VideoProfile values.
63 return media::VIDEO_CODEC_PROFILE_UNKNOWN
;
68 PepperVideoDecoderHost::PendingDecode::PendingDecode(
70 const ppapi::host::ReplyMessageContext
& reply_context
)
71 : shm_id(shm_id
), reply_context(reply_context
) {
74 PepperVideoDecoderHost::PendingDecode::~PendingDecode() {
77 PepperVideoDecoderHost::PepperVideoDecoderHost(RendererPpapiHost
* host
,
80 : ResourceHost(host
->GetPpapiHost(), instance
, resource
),
81 renderer_ppapi_host_(host
),
85 PepperVideoDecoderHost::~PepperVideoDecoderHost() {
88 int32_t PepperVideoDecoderHost::OnResourceMessageReceived(
89 const IPC::Message
& msg
,
90 ppapi::host::HostMessageContext
* context
) {
91 PPAPI_BEGIN_MESSAGE_MAP(PepperVideoDecoderHost
, msg
)
92 PPAPI_DISPATCH_HOST_RESOURCE_CALL(PpapiHostMsg_VideoDecoder_Initialize
,
94 PPAPI_DISPATCH_HOST_RESOURCE_CALL(PpapiHostMsg_VideoDecoder_GetShm
,
96 PPAPI_DISPATCH_HOST_RESOURCE_CALL(PpapiHostMsg_VideoDecoder_Decode
,
98 PPAPI_DISPATCH_HOST_RESOURCE_CALL(PpapiHostMsg_VideoDecoder_AssignTextures
,
99 OnHostMsgAssignTextures
)
100 PPAPI_DISPATCH_HOST_RESOURCE_CALL(PpapiHostMsg_VideoDecoder_RecyclePicture
,
101 OnHostMsgRecyclePicture
)
102 PPAPI_DISPATCH_HOST_RESOURCE_CALL_0(PpapiHostMsg_VideoDecoder_Flush
,
104 PPAPI_DISPATCH_HOST_RESOURCE_CALL_0(PpapiHostMsg_VideoDecoder_Reset
,
106 PPAPI_END_MESSAGE_MAP()
107 return PP_ERROR_FAILED
;
110 int32_t PepperVideoDecoderHost::OnHostMsgInitialize(
111 ppapi::host::HostMessageContext
* context
,
112 const ppapi::HostResource
& graphics_context
,
113 PP_VideoProfile profile
,
114 PP_HardwareAcceleration acceleration
) {
116 return PP_ERROR_FAILED
;
118 EnterResourceNoLock
<PPB_Graphics3D_API
> enter_graphics(
119 graphics_context
.host_resource(), true);
120 if (enter_graphics
.failed())
121 return PP_ERROR_FAILED
;
122 PPB_Graphics3D_Impl
* graphics3d
=
123 static_cast<PPB_Graphics3D_Impl
*>(enter_graphics
.object());
125 int command_buffer_route_id
= graphics3d
->GetCommandBufferRouteId();
126 if (!command_buffer_route_id
)
127 return PP_ERROR_FAILED
;
129 media::VideoCodecProfile media_profile
= PepperToMediaVideoProfile(profile
);
131 if (acceleration
!= PP_HARDWAREACCELERATION_NONE
) {
132 // This is not synchronous, but subsequent IPC messages will be buffered, so
133 // it is okay to immediately send IPC messages through the returned channel.
134 GpuChannelHost
* channel
= graphics3d
->channel();
136 decoder_
= channel
->CreateVideoDecoder(command_buffer_route_id
);
137 if (decoder_
&& decoder_
->Initialize(media_profile
, this)) {
142 if (acceleration
== PP_HARDWAREACCELERATION_ONLY
)
143 return PP_ERROR_NOTSUPPORTED
;
146 #if defined(OS_ANDROID)
147 return PP_ERROR_NOTSUPPORTED
;
149 decoder_
.reset(new VideoDecoderShim(this));
150 initialize_reply_context_
= context
->MakeReplyMessageContext();
151 decoder_
->Initialize(media_profile
, this);
153 return PP_OK_COMPLETIONPENDING
;
157 int32_t PepperVideoDecoderHost::OnHostMsgGetShm(
158 ppapi::host::HostMessageContext
* context
,
162 return PP_ERROR_FAILED
;
164 // Make the buffers larger since we hope to reuse them.
167 static_cast<uint32_t>(ppapi::proxy::kMinimumBitstreamBufferSize
));
168 if (shm_size
> ppapi::proxy::kMaximumBitstreamBufferSize
)
169 return PP_ERROR_FAILED
;
171 if (shm_id
>= ppapi::proxy::kMaximumPendingDecodes
)
172 return PP_ERROR_FAILED
;
173 // The shm_id must be inside or at the end of shm_buffers_.
174 if (shm_id
> shm_buffers_
.size())
175 return PP_ERROR_FAILED
;
176 // Reject an attempt to reallocate a busy shm buffer.
177 if (shm_id
< shm_buffers_
.size() && shm_buffer_busy_
[shm_id
])
178 return PP_ERROR_FAILED
;
180 content::RenderThread
* render_thread
= content::RenderThread::Get();
181 scoped_ptr
<base::SharedMemory
> shm(
182 render_thread
->HostAllocateSharedMemoryBuffer(shm_size
).Pass());
183 if (!shm
|| !shm
->Map(shm_size
))
184 return PP_ERROR_FAILED
;
186 base::SharedMemoryHandle shm_handle
= shm
->handle();
187 if (shm_id
== shm_buffers_
.size()) {
188 shm_buffers_
.push_back(shm
.release());
189 shm_buffer_busy_
.push_back(false);
191 // Remove the old buffer. Delete manually since ScopedVector won't delete
192 // the existing element if we just assign over it.
193 delete shm_buffers_
[shm_id
];
194 shm_buffers_
[shm_id
] = shm
.release();
198 base::PlatformFile platform_file
= shm_handle
;
199 #elif defined(OS_POSIX)
200 base::PlatformFile platform_file
= shm_handle
.fd
;
202 #error Not implemented.
204 SerializedHandle
handle(
205 renderer_ppapi_host_
->ShareHandleWithRemote(platform_file
, false),
207 ppapi::host::ReplyMessageContext reply_context
=
208 context
->MakeReplyMessageContext();
209 reply_context
.params
.AppendHandle(handle
);
210 host()->SendReply(reply_context
,
211 PpapiPluginMsg_VideoDecoder_GetShmReply(shm_size
));
213 return PP_OK_COMPLETIONPENDING
;
216 int32_t PepperVideoDecoderHost::OnHostMsgDecode(
217 ppapi::host::HostMessageContext
* context
,
222 return PP_ERROR_FAILED
;
224 // |shm_id| is just an index into shm_buffers_. Make sure it's in range.
225 if (static_cast<size_t>(shm_id
) >= shm_buffers_
.size())
226 return PP_ERROR_FAILED
;
227 // Reject an attempt to pass a busy buffer to the decoder again.
228 if (shm_buffer_busy_
[shm_id
])
229 return PP_ERROR_FAILED
;
230 // Reject non-unique decode_id values.
231 if (pending_decodes_
.find(decode_id
) != pending_decodes_
.end())
232 return PP_ERROR_FAILED
;
234 if (flush_reply_context_
.is_valid() || reset_reply_context_
.is_valid())
235 return PP_ERROR_FAILED
;
237 pending_decodes_
.insert(std::make_pair(
238 decode_id
, PendingDecode(shm_id
, context
->MakeReplyMessageContext())));
240 shm_buffer_busy_
[shm_id
] = true;
242 media::BitstreamBuffer(decode_id
, shm_buffers_
[shm_id
]->handle(), size
));
244 return PP_OK_COMPLETIONPENDING
;
247 int32_t PepperVideoDecoderHost::OnHostMsgAssignTextures(
248 ppapi::host::HostMessageContext
* context
,
250 const std::vector
<uint32_t>& texture_ids
) {
252 return PP_ERROR_FAILED
;
255 std::vector
<media::PictureBuffer
> picture_buffers
;
256 for (uint32 i
= 0; i
< texture_ids
.size(); i
++) {
257 media::PictureBuffer
buffer(
258 texture_ids
[i
], // Use the texture_id to identify the buffer.
259 gfx::Size(size
.width
, size
.height
),
261 picture_buffers
.push_back(buffer
);
263 decoder_
->AssignPictureBuffers(picture_buffers
);
267 int32_t PepperVideoDecoderHost::OnHostMsgRecyclePicture(
268 ppapi::host::HostMessageContext
* context
,
269 uint32_t texture_id
) {
271 return PP_ERROR_FAILED
;
274 decoder_
->ReusePictureBuffer(texture_id
);
278 int32_t PepperVideoDecoderHost::OnHostMsgFlush(
279 ppapi::host::HostMessageContext
* context
) {
281 return PP_ERROR_FAILED
;
283 if (flush_reply_context_
.is_valid() || reset_reply_context_
.is_valid())
284 return PP_ERROR_FAILED
;
286 flush_reply_context_
= context
->MakeReplyMessageContext();
289 return PP_OK_COMPLETIONPENDING
;
292 int32_t PepperVideoDecoderHost::OnHostMsgReset(
293 ppapi::host::HostMessageContext
* context
) {
295 return PP_ERROR_FAILED
;
297 if (flush_reply_context_
.is_valid() || reset_reply_context_
.is_valid())
298 return PP_ERROR_FAILED
;
300 reset_reply_context_
= context
->MakeReplyMessageContext();
303 return PP_OK_COMPLETIONPENDING
;
306 void PepperVideoDecoderHost::ProvidePictureBuffers(
307 uint32 requested_num_of_buffers
,
308 const gfx::Size
& dimensions
,
309 uint32 texture_target
) {
310 RequestTextures(requested_num_of_buffers
,
313 std::vector
<gpu::Mailbox
>());
316 void PepperVideoDecoderHost::PictureReady(const media::Picture
& picture
) {
317 // So far picture.visible_rect is not used. If used, visible_rect should
318 // be validated since it comes from GPU process and may not be trustworthy.
319 host()->SendUnsolicitedReply(
321 PpapiPluginMsg_VideoDecoder_PictureReady(picture
.bitstream_buffer_id(),
322 picture
.picture_buffer_id()));
325 void PepperVideoDecoderHost::DismissPictureBuffer(int32 picture_buffer_id
) {
326 host()->SendUnsolicitedReply(
328 PpapiPluginMsg_VideoDecoder_DismissPicture(picture_buffer_id
));
331 void PepperVideoDecoderHost::NotifyEndOfBitstreamBuffer(
332 int32 bitstream_buffer_id
) {
333 PendingDecodeMap::iterator it
= pending_decodes_
.find(bitstream_buffer_id
);
334 if (it
== pending_decodes_
.end()) {
338 const PendingDecode
& pending_decode
= it
->second
;
340 pending_decode
.reply_context
,
341 PpapiPluginMsg_VideoDecoder_DecodeReply(pending_decode
.shm_id
));
342 shm_buffer_busy_
[pending_decode
.shm_id
] = false;
343 pending_decodes_
.erase(it
);
346 void PepperVideoDecoderHost::NotifyFlushDone() {
347 DCHECK(pending_decodes_
.empty());
348 host()->SendReply(flush_reply_context_
,
349 PpapiPluginMsg_VideoDecoder_FlushReply());
350 flush_reply_context_
= ppapi::host::ReplyMessageContext();
353 void PepperVideoDecoderHost::NotifyResetDone() {
354 DCHECK(pending_decodes_
.empty());
355 host()->SendReply(reset_reply_context_
,
356 PpapiPluginMsg_VideoDecoder_ResetReply());
357 reset_reply_context_
= ppapi::host::ReplyMessageContext();
360 void PepperVideoDecoderHost::NotifyError(
361 media::VideoDecodeAccelerator::Error error
) {
362 int32_t pp_error
= PP_ERROR_FAILED
;
364 case media::VideoDecodeAccelerator::UNREADABLE_INPUT
:
365 pp_error
= PP_ERROR_MALFORMED_INPUT
;
367 case media::VideoDecodeAccelerator::ILLEGAL_STATE
:
368 case media::VideoDecodeAccelerator::INVALID_ARGUMENT
:
369 case media::VideoDecodeAccelerator::PLATFORM_FAILURE
:
370 case media::VideoDecodeAccelerator::LARGEST_ERROR_ENUM
:
371 pp_error
= PP_ERROR_RESOURCE_FAILED
;
373 // No default case, to catch unhandled enum values.
375 host()->SendUnsolicitedReply(
376 pp_resource(), PpapiPluginMsg_VideoDecoder_NotifyError(pp_error
));
379 void PepperVideoDecoderHost::OnInitializeComplete(int32_t result
) {
383 initialize_reply_context_
.params
.set_result(result
);
384 host()->SendReply(initialize_reply_context_
,
385 PpapiPluginMsg_VideoDecoder_InitializeReply());
389 const uint8_t* PepperVideoDecoderHost::DecodeIdToAddress(uint32_t decode_id
) {
390 PendingDecodeMap::const_iterator it
= pending_decodes_
.find(decode_id
);
391 DCHECK(it
!= pending_decodes_
.end());
392 uint32_t shm_id
= it
->second
.shm_id
;
393 return static_cast<uint8_t*>(shm_buffers_
[shm_id
]->memory());
396 void PepperVideoDecoderHost::RequestTextures(
397 uint32 requested_num_of_buffers
,
398 const gfx::Size
& dimensions
,
399 uint32 texture_target
,
400 const std::vector
<gpu::Mailbox
>& mailboxes
) {
401 host()->SendUnsolicitedReply(
403 PpapiPluginMsg_VideoDecoder_RequestTextures(
404 requested_num_of_buffers
,
405 PP_MakeSize(dimensions
.width(), dimensions
.height()),
410 } // namespace content