OLD | NEW |
---|---|
(Empty) | |
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 "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/ppb_graphics_3d_impl.h" | |
13 #include "content/renderer/render_thread_impl.h" | |
14 #include "content/renderer/render_view_impl.h" | |
15 #include "gpu/command_buffer/client/gles2_implementation.h" | |
16 #include "media/video/picture.h" | |
17 #include "media/video/video_decode_accelerator.h" | |
18 #include "ppapi/c/pp_completion_callback.h" | |
19 #include "ppapi/c/pp_errors.h" | |
20 #include "ppapi/host/dispatch_host_message.h" | |
21 #include "ppapi/host/ppapi_host.h" | |
22 #include "ppapi/proxy/ppapi_messages.h" | |
23 #include "ppapi/thunk/enter.h" | |
24 #include "ppapi/thunk/ppb_graphics_3d_api.h" | |
25 | |
26 using ppapi::proxy::SerializedHandle; | |
27 using ppapi::thunk::EnterResourceNoLock; | |
28 using ppapi::thunk::PPB_Graphics3D_API; | |
29 | |
30 namespace content { | |
31 | |
32 namespace { | |
33 | |
34 #define COMPILE_ASSERT_MATCHING_ENUM(media_name, np_name) \ | |
35 COMPILE_ASSERT( \ | |
36 static_cast<int>(media::media_name) == static_cast<int>(np_name), \ | |
37 mismatching_enums) | |
38 | |
39 COMPILE_ASSERT_MATCHING_ENUM(H264PROFILE_BASELINE, | |
40 PP_VIDEOPROFILE_H264BASELINE); | |
41 COMPILE_ASSERT_MATCHING_ENUM(H264PROFILE_MAIN, PP_VIDEOPROFILE_H264MAIN); | |
42 COMPILE_ASSERT_MATCHING_ENUM(H264PROFILE_EXTENDED, | |
43 PP_VIDEOPROFILE_H264EXTENDED); | |
44 COMPILE_ASSERT_MATCHING_ENUM(H264PROFILE_HIGH, PP_VIDEOPROFILE_H264HIGH); | |
45 COMPILE_ASSERT_MATCHING_ENUM(H264PROFILE_HIGH10PROFILE, | |
46 PP_VIDEOPROFILE_H264HIGH10PROFILE); | |
47 COMPILE_ASSERT_MATCHING_ENUM(H264PROFILE_HIGH422PROFILE, | |
48 PP_VIDEOPROFILE_H264HIGH422PROFILE); | |
49 COMPILE_ASSERT_MATCHING_ENUM(H264PROFILE_HIGH444PREDICTIVEPROFILE, | |
50 PP_VIDEOPROFILE_H264HIGH444PREDICTIVEPROFILE); | |
51 COMPILE_ASSERT_MATCHING_ENUM(H264PROFILE_SCALABLEBASELINE, | |
52 PP_VIDEOPROFILE_H264SCALABLEBASELINE); | |
53 COMPILE_ASSERT_MATCHING_ENUM(H264PROFILE_SCALABLEHIGH, | |
54 PP_VIDEOPROFILE_H264SCALABLEHIGH); | |
55 COMPILE_ASSERT_MATCHING_ENUM(H264PROFILE_STEREOHIGH, | |
56 PP_VIDEOPROFILE_H264STEREOHIGH); | |
57 COMPILE_ASSERT_MATCHING_ENUM(H264PROFILE_MULTIVIEWHIGH, | |
58 PP_VIDEOPROFILE_H264MULTIVIEWHIGH); | |
59 COMPILE_ASSERT_MATCHING_ENUM(VP8PROFILE_MAIN, PP_VIDEOPROFILE_VP8MAIN); | |
60 | |
61 } // namespace | |
62 | |
63 PepperVideoDecoderHost::PepperVideoDecoderHost(RendererPpapiHost* host, | |
64 PP_Instance instance, | |
65 PP_Resource resource) | |
66 : ResourceHost(host->GetPpapiHost(), instance, resource), | |
67 renderer_ppapi_host_(host), | |
68 initialized_(false), | |
69 weak_factory_(this) { | |
70 } | |
71 | |
72 PepperVideoDecoderHost::~PepperVideoDecoderHost() { | |
73 if (decoder_) { | |
74 decoder_->Destroy(); | |
75 decoder_.reset(); | |
76 } | |
77 } | |
78 | |
79 int32_t PepperVideoDecoderHost::OnResourceMessageReceived( | |
80 const IPC::Message& msg, | |
81 ppapi::host::HostMessageContext* context) { | |
82 IPC_BEGIN_MESSAGE_MAP(PepperVideoDecoderHost, msg) | |
83 PPAPI_DISPATCH_HOST_RESOURCE_CALL(PpapiHostMsg_VideoDecoder_Initialize, | |
Tom Sepez
2014/05/08 20:35:07
nit: it's common to indent these two spaces betwee
bbudge
2014/05/14 16:40:41
We're trying to use clang-format on Pepper code. I
| |
84 OnHostMsgInitialize) | |
85 PPAPI_DISPATCH_HOST_RESOURCE_CALL(PpapiHostMsg_VideoDecoder_GetShm, | |
86 OnHostMsgGetShm) | |
87 PPAPI_DISPATCH_HOST_RESOURCE_CALL(PpapiHostMsg_VideoDecoder_AssignTextures, | |
88 OnHostMsgAssignTextures) | |
89 PPAPI_DISPATCH_HOST_RESOURCE_CALL(PpapiHostMsg_VideoDecoder_Decode, | |
90 OnHostMsgDecode) | |
91 PPAPI_DISPATCH_HOST_RESOURCE_CALL(PpapiHostMsg_VideoDecoder_RecyclePicture, | |
92 OnHostMsgRecyclePicture) | |
93 PPAPI_DISPATCH_HOST_RESOURCE_CALL_0(PpapiHostMsg_VideoDecoder_Flush, | |
94 OnHostMsgFlush) | |
95 PPAPI_DISPATCH_HOST_RESOURCE_CALL_0(PpapiHostMsg_VideoDecoder_Reset, | |
96 OnHostMsgReset) | |
97 IPC_END_MESSAGE_MAP() | |
98 return PP_ERROR_FAILED; | |
99 } | |
100 | |
101 int32_t PepperVideoDecoderHost::OnHostMsgInitialize( | |
102 ppapi::host::HostMessageContext* context, | |
103 ppapi::HostResource graphics_context, | |
104 PP_VideoProfile profile, | |
105 bool allow_software_fallback) { | |
106 if (initialized_) | |
107 return PP_ERROR_FAILED; | |
108 if (profile < 0 || profile > PP_VIDEOPROFILE_MAX) | |
dmichael (off chromium)
2014/05/08 20:27:00
Should that be >= PP_VIDEOPROFILE_MAX?
It looks l
bbudge
2014/05/14 16:40:41
There should be no more VP9 in the API. It isn't s
| |
109 return PP_ERROR_BADARGUMENT; | |
110 | |
111 EnterResourceNoLock<PPB_Graphics3D_API> enter( | |
112 graphics_context.host_resource(), true); | |
113 if (enter.failed()) | |
114 return PP_ERROR_BADRESOURCE; | |
115 PPB_Graphics3D_Impl* graphics3d_impl = | |
116 static_cast<PPB_Graphics3D_Impl*>(enter.object()); | |
117 int command_buffer_route_id = graphics3d_impl->GetCommandBufferRouteId(); | |
118 if (!command_buffer_route_id) | |
119 return PP_ERROR_FAILED; | |
120 | |
121 media::VideoCodecProfile media_profile = | |
122 static_cast<media::VideoCodecProfile>(profile); | |
123 | |
124 // This is not synchronous, but subsequent IPC messages will be buffered, so | |
125 // it is okay to immediately send IPC messages through the returned channel. | |
126 GpuChannelHost* channel = graphics3d_impl->channel(); | |
127 DCHECK(channel); | |
128 | |
129 if (channel) { | |
130 decoder_ = channel->CreateVideoDecoder(command_buffer_route_id); | |
131 if (decoder_ && decoder_->Initialize(media_profile, this)) { | |
132 initialized_ = true; | |
133 return PP_OK; | |
134 } | |
135 decoder_.reset(); | |
136 } | |
137 | |
138 // TODO(bbudge) Implement software fallback. | |
139 return PP_ERROR_NOTSUPPORTED; | |
140 } | |
141 | |
142 int32_t PepperVideoDecoderHost::OnHostMsgGetShm( | |
143 ppapi::host::HostMessageContext* context, | |
144 uint32_t size) { | |
145 if (!initialized_) | |
146 return PP_ERROR_FAILED; | |
147 | |
148 content::RenderThread* render_thread = content::RenderThread::Get(); | |
149 scoped_ptr<base::SharedMemory> shm( | |
150 render_thread->HostAllocateSharedMemoryBuffer(size).Pass()); | |
151 if (!shm) | |
152 return PP_ERROR_FAILED; | |
153 if (!shm->Map(size)) | |
154 return PP_ERROR_FAILED; | |
155 | |
156 base::SharedMemoryHandle shm_handle = shm->handle(); | |
157 shm_buffers_.push_back(shm.release()); | |
158 | |
159 base::PlatformFile platform_file = | |
160 #if defined(OS_WIN) | |
161 shm_handle; | |
162 #elif defined(OS_POSIX) | |
163 shm_handle.fd; | |
164 #else | |
165 #error Not implemented. | |
166 #endif | |
167 SerializedHandle handle( | |
168 renderer_ppapi_host_->ShareHandleWithRemote(platform_file, false), size); | |
169 ppapi::host::ReplyMessageContext reply_context = | |
170 context->MakeReplyMessageContext(); | |
171 reply_context.params.AppendHandle(handle); | |
172 host()->SendReply(reply_context, | |
173 PpapiPluginMsg_VideoDecoder_GetShmReply(size)); | |
174 return PP_OK_COMPLETIONPENDING; | |
175 } | |
176 | |
177 int32_t PepperVideoDecoderHost::OnHostMsgAssignTextures( | |
178 ppapi::host::HostMessageContext* context, | |
179 PP_Size size, | |
180 const std::vector<uint32_t>& texture_ids) { | |
181 if (!initialized_) | |
182 return PP_ERROR_FAILED; | |
183 | |
184 DCHECK(decoder_); | |
185 if (decoder_) { | |
dmichael (off chromium)
2014/05/08 20:27:00
nit: What's inside the if block is actually the co
bbudge
2014/05/14 16:40:41
Much better. Done.
| |
186 std::vector<media::PictureBuffer> picture_buffers; | |
187 for (uint32 i = 0; i < texture_ids.size(); i++) { | |
188 media::PictureBuffer buffer( | |
189 texture_ids[i], // Use the texture_id to identify the buffer. | |
190 gfx::Size(size.width, size.height), | |
191 texture_ids[i]); | |
192 picture_buffers.push_back(buffer); | |
193 } | |
194 decoder_->AssignPictureBuffers(picture_buffers); | |
195 } | |
196 return PP_OK; | |
197 } | |
198 | |
199 int32_t PepperVideoDecoderHost::OnHostMsgDecode( | |
200 ppapi::host::HostMessageContext* context, | |
201 uint32_t shm_id, | |
202 uint32_t size) { | |
203 if (!initialized_) | |
204 return PP_ERROR_FAILED; | |
205 // |shm_id| is just an index into shm_buffers_. Make sure it's in range. | |
206 if (static_cast<size_t>(shm_id) >= shm_buffers_.size()) | |
207 return PP_ERROR_FAILED; | |
208 | |
209 pending_decodes_.insert( | |
210 std::make_pair(shm_id, context->MakeReplyMessageContext())); | |
211 | |
212 base::SharedMemory* shm = shm_buffers_[shm_id]; | |
213 DCHECK(decoder_); | |
214 if (decoder_) | |
215 decoder_->Decode(media::BitstreamBuffer(shm_id, shm->handle(), size)); | |
216 | |
217 return PP_OK_COMPLETIONPENDING; | |
218 } | |
219 | |
220 int32_t PepperVideoDecoderHost::OnHostMsgRecyclePicture( | |
221 ppapi::host::HostMessageContext* context, | |
222 uint32_t texture_id) { | |
223 if (!initialized_) | |
224 return PP_ERROR_FAILED; | |
225 DCHECK(decoder_); | |
226 if (decoder_) | |
227 decoder_->ReusePictureBuffer(texture_id); | |
228 | |
229 return PP_OK; | |
230 } | |
231 | |
232 int32_t PepperVideoDecoderHost::OnHostMsgFlush( | |
233 ppapi::host::HostMessageContext* context) { | |
234 if (!initialized_) | |
235 return PP_ERROR_FAILED; | |
236 | |
237 flush_reply_context_ = context->MakeReplyMessageContext(); | |
238 DCHECK(decoder_); | |
239 if (decoder_) | |
240 decoder_->Flush(); | |
241 | |
242 return PP_OK_COMPLETIONPENDING; | |
243 } | |
244 | |
245 int32_t PepperVideoDecoderHost::OnHostMsgReset( | |
246 ppapi::host::HostMessageContext* context) { | |
247 if (!initialized_) | |
248 return PP_ERROR_FAILED; | |
249 | |
250 reset_reply_context_ = context->MakeReplyMessageContext(); | |
251 DCHECK(decoder_); | |
252 if (decoder_) | |
253 decoder_->Reset(); | |
254 | |
255 return PP_OK_COMPLETIONPENDING; | |
256 } | |
257 | |
258 void PepperVideoDecoderHost::ProvidePictureBuffers( | |
259 uint32 requested_num_of_buffers, | |
260 const gfx::Size& dimensions, | |
261 uint32 texture_target) { | |
262 RequestTextures(requested_num_of_buffers, | |
263 dimensions, | |
264 texture_target, | |
265 std::vector<gpu::Mailbox>()); | |
266 } | |
267 | |
268 void PepperVideoDecoderHost::RequestTextures( | |
269 uint32 requested_num_of_buffers, | |
270 const gfx::Size& dimensions, | |
271 uint32 texture_target, | |
272 const std::vector<gpu::Mailbox>& mailboxes) { | |
dmichael (off chromium)
2014/05/08 20:27:00
I don't see any case where mailboxes will be anyth
bbudge
2014/05/14 16:40:41
Removed these for now.
| |
273 DCHECK(RenderThreadImpl::current()); | |
274 host()->SendUnsolicitedReply( | |
275 pp_resource(), | |
276 PpapiPluginMsg_VideoDecoder_RequestTextures( | |
277 requested_num_of_buffers, | |
278 PP_MakeSize(dimensions.width(), dimensions.height()), | |
279 texture_target, | |
280 mailboxes)); | |
281 } | |
282 | |
283 void PepperVideoDecoderHost::PictureReady(const media::Picture& picture) { | |
284 DCHECK(RenderThreadImpl::current()); | |
285 host()->SendUnsolicitedReply( | |
286 pp_resource(), | |
287 PpapiPluginMsg_VideoDecoder_PictureReady(picture.bitstream_buffer_id(), | |
288 picture.picture_buffer_id())); | |
289 } | |
290 | |
291 void PepperVideoDecoderHost::DismissPictureBuffer(int32 picture_buffer_id) { | |
292 DCHECK(RenderThreadImpl::current()); | |
293 host()->SendUnsolicitedReply( | |
294 pp_resource(), | |
295 PpapiPluginMsg_VideoDecoder_DismissPicture(picture_buffer_id)); | |
296 } | |
297 | |
298 void PepperVideoDecoderHost::NotifyError( | |
299 media::VideoDecodeAccelerator::Error error) { | |
300 DCHECK(RenderThreadImpl::current()); | |
301 int32_t pp_error = PP_ERROR_FAILED; | |
302 switch (error) { | |
303 case media::VideoDecodeAccelerator::UNREADABLE_INPUT: | |
304 pp_error = PP_ERROR_UNREADABLE_INPUT; | |
305 break; | |
306 case media::VideoDecodeAccelerator::ILLEGAL_STATE: | |
307 case media::VideoDecodeAccelerator::INVALID_ARGUMENT: | |
308 case media::VideoDecodeAccelerator::PLATFORM_FAILURE: | |
309 pp_error = PP_ERROR_PLATFORM_FAILED; | |
310 break; | |
311 default: | |
312 NOTREACHED(); | |
313 break; | |
314 } | |
315 host()->SendUnsolicitedReply( | |
316 pp_resource(), PpapiPluginMsg_VideoDecoder_NotifyError(pp_error)); | |
317 } | |
318 | |
319 void PepperVideoDecoderHost::NotifyResetDone() { | |
320 DCHECK(RenderThreadImpl::current()); | |
321 host()->SendReply(reset_reply_context_, | |
322 PpapiPluginMsg_VideoDecoder_ResetReply()); | |
323 reset_reply_context_ = ppapi::host::ReplyMessageContext(); | |
324 } | |
325 | |
326 void PepperVideoDecoderHost::NotifyEndOfBitstreamBuffer( | |
327 int32 bitstream_buffer_id) { | |
328 DCHECK(RenderThreadImpl::current()); | |
329 uint32_t shm_id = static_cast<uint32_t>(bitstream_buffer_id); | |
330 ReplyMap::iterator it = pending_decodes_.find(shm_id); | |
331 DCHECK(it != pending_decodes_.end()); | |
Tom Sepez
2014/05/08 20:35:07
Can this happen for real? Does bitstream_buffer_i
bbudge
2014/05/14 16:40:41
This is from the decoder which is trusted. A futur
| |
332 host()->SendReply(it->second, | |
333 PpapiPluginMsg_VideoDecoder_DecodeReply(shm_id)); | |
334 | |
335 pending_decodes_.erase(it); | |
336 } | |
337 | |
338 void PepperVideoDecoderHost::NotifyFlushDone() { | |
339 DCHECK(RenderThreadImpl::current()); | |
340 host()->SendReply(flush_reply_context_, | |
341 PpapiPluginMsg_VideoDecoder_FlushReply()); | |
342 flush_reply_context_ = ppapi::host::ReplyMessageContext(); | |
343 } | |
344 | |
345 } // namespace content | |
OLD | NEW |