Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(39)

Side by Side Diff: content/renderer/pepper/pepper_video_decoder_host.cc

Issue 270213004: Implement Pepper PPB_VideoDecoder interface. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Rebase, update to PPAPI message map macros. Created 6 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(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 "media/video/picture.h"
16 #include "media/video/video_decode_accelerator.h"
17 #include "ppapi/c/pp_completion_callback.h"
18 #include "ppapi/c/pp_errors.h"
19 #include "ppapi/host/dispatch_host_message.h"
20 #include "ppapi/host/ppapi_host.h"
21 #include "ppapi/proxy/ppapi_messages.h"
22 #include "ppapi/thunk/enter.h"
23 #include "ppapi/thunk/ppb_graphics_3d_api.h"
24
25 using ppapi::proxy::SerializedHandle;
26 using ppapi::thunk::EnterResourceNoLock;
27 using ppapi::thunk::PPB_Graphics3D_API;
28
29 namespace content {
30
31 namespace {
32
33 #define COMPILE_ASSERT_MATCHING_ENUM(media_name, np_name) \
34 COMPILE_ASSERT( \
35 static_cast<int>(media::media_name) == static_cast<int>(np_name), \
36 mismatching_enums)
37
38 COMPILE_ASSERT_MATCHING_ENUM(H264PROFILE_BASELINE,
39 PP_VIDEOPROFILE_H264BASELINE);
40 COMPILE_ASSERT_MATCHING_ENUM(H264PROFILE_MAIN, PP_VIDEOPROFILE_H264MAIN);
41 COMPILE_ASSERT_MATCHING_ENUM(H264PROFILE_EXTENDED,
42 PP_VIDEOPROFILE_H264EXTENDED);
43 COMPILE_ASSERT_MATCHING_ENUM(H264PROFILE_HIGH, PP_VIDEOPROFILE_H264HIGH);
44 COMPILE_ASSERT_MATCHING_ENUM(H264PROFILE_HIGH10PROFILE,
45 PP_VIDEOPROFILE_H264HIGH10PROFILE);
46 COMPILE_ASSERT_MATCHING_ENUM(H264PROFILE_HIGH422PROFILE,
47 PP_VIDEOPROFILE_H264HIGH422PROFILE);
48 COMPILE_ASSERT_MATCHING_ENUM(H264PROFILE_HIGH444PREDICTIVEPROFILE,
49 PP_VIDEOPROFILE_H264HIGH444PREDICTIVEPROFILE);
50 COMPILE_ASSERT_MATCHING_ENUM(H264PROFILE_SCALABLEBASELINE,
51 PP_VIDEOPROFILE_H264SCALABLEBASELINE);
52 COMPILE_ASSERT_MATCHING_ENUM(H264PROFILE_SCALABLEHIGH,
53 PP_VIDEOPROFILE_H264SCALABLEHIGH);
54 COMPILE_ASSERT_MATCHING_ENUM(H264PROFILE_STEREOHIGH,
55 PP_VIDEOPROFILE_H264STEREOHIGH);
56 COMPILE_ASSERT_MATCHING_ENUM(H264PROFILE_MULTIVIEWHIGH,
57 PP_VIDEOPROFILE_H264MULTIVIEWHIGH);
58 COMPILE_ASSERT_MATCHING_ENUM(VP8PROFILE_MAIN, PP_VIDEOPROFILE_VP8MAIN);
59
60 } // namespace
61
62 PepperVideoDecoderHost::PendingDecode::PendingDecode(
63 uint32_t shm_id,
64 const ppapi::host::ReplyMessageContext& reply_context)
65 : shm_id_(shm_id), reply_context_(reply_context) {
66 }
67
68 PepperVideoDecoderHost::PendingDecode::~PendingDecode() {
69 }
70
71 PepperVideoDecoderHost::PepperVideoDecoderHost(RendererPpapiHost* host,
72 PP_Instance instance,
73 PP_Resource resource)
74 : ResourceHost(host->GetPpapiHost(), instance, resource),
75 renderer_ppapi_host_(host),
76 initialized_(false) {
77 }
78
79 PepperVideoDecoderHost::~PepperVideoDecoderHost() {
80 if (decoder_) {
81 decoder_->Destroy();
82 decoder_.reset();
83 }
84 }
85
86 int32_t PepperVideoDecoderHost::OnResourceMessageReceived(
87 const IPC::Message& msg,
88 ppapi::host::HostMessageContext* context) {
89 PPAPI_BEGIN_MESSAGE_MAP(PepperVideoDecoderHost, msg)
90 PPAPI_DISPATCH_HOST_RESOURCE_CALL(PpapiHostMsg_VideoDecoder_Initialize,
91 OnHostMsgInitialize)
92 PPAPI_DISPATCH_HOST_RESOURCE_CALL(PpapiHostMsg_VideoDecoder_GetShm,
93 OnHostMsgGetShm)
94 PPAPI_DISPATCH_HOST_RESOURCE_CALL(PpapiHostMsg_VideoDecoder_AssignTextures,
95 OnHostMsgAssignTextures)
96 PPAPI_DISPATCH_HOST_RESOURCE_CALL(PpapiHostMsg_VideoDecoder_Decode,
97 OnHostMsgDecode)
98 PPAPI_DISPATCH_HOST_RESOURCE_CALL(PpapiHostMsg_VideoDecoder_RecyclePicture,
99 OnHostMsgRecyclePicture)
100 PPAPI_DISPATCH_HOST_RESOURCE_CALL_0(PpapiHostMsg_VideoDecoder_Flush,
101 OnHostMsgFlush)
102 PPAPI_DISPATCH_HOST_RESOURCE_CALL_0(PpapiHostMsg_VideoDecoder_Reset,
103 OnHostMsgReset)
104 PPAPI_END_MESSAGE_MAP()
105 return PP_ERROR_FAILED;
106 }
107
108 int32_t PepperVideoDecoderHost::OnHostMsgInitialize(
109 ppapi::host::HostMessageContext* context,
110 ppapi::HostResource graphics_context,
111 PP_VideoProfile profile,
112 bool allow_software_fallback) {
113 if (initialized_)
114 return PP_ERROR_FAILED;
115
116 EnterResourceNoLock<PPB_Graphics3D_API> enter_graphics(
117 graphics_context.host_resource(), true);
118 if (enter_graphics.failed())
119 return PP_ERROR_FAILED;
yzshen1 2014/05/14 18:08:23 Maybe we could consider PP_ERROR_BADRESOURCE?
bbudge 2014/05/14 19:35:04 It's actually our own Graphics3D, created by the r
yzshen1 2014/05/14 22:58:16 Okay. I see. On 2014/05/14 19:35:04, bbudge wrote:
120 graphics3d_ = static_cast<PPB_Graphics3D_Impl*>(enter_graphics.object());
121
122 int command_buffer_route_id = graphics3d_->GetCommandBufferRouteId();
123 if (!command_buffer_route_id)
124 return PP_ERROR_FAILED;
125
126 media::VideoCodecProfile media_profile =
127 static_cast<media::VideoCodecProfile>(profile);
yzshen1 2014/05/14 18:08:23 If we add new values to PP_VideoProfile but forget
bbudge 2014/05/14 19:35:04 Done.
128
129 // This is not synchronous, but subsequent IPC messages will be buffered, so
130 // it is okay to immediately send IPC messages through the returned channel.
131 GpuChannelHost* channel = graphics3d_->channel();
132 DCHECK(channel);
133
134 if (channel) {
135 decoder_ = channel->CreateVideoDecoder(command_buffer_route_id);
136 if (decoder_ && decoder_->Initialize(media_profile, this)) {
137 initialized_ = true;
138 return PP_OK;
139 }
140 decoder_.reset();
141 }
142
143 // TODO(bbudge) Implement software fallback.
144 return PP_ERROR_NOTSUPPORTED;
145 }
146
147 int32_t PepperVideoDecoderHost::OnHostMsgGetShm(
148 ppapi::host::HostMessageContext* context,
149 uint32_t size) {
150 if (!initialized_)
151 return PP_ERROR_FAILED;
152
153 content::RenderThread* render_thread = content::RenderThread::Get();
154 scoped_ptr<base::SharedMemory> shm(
155 render_thread->HostAllocateSharedMemoryBuffer(size).Pass());
156 if (!shm)
157 return PP_ERROR_FAILED;
158 if (!shm->Map(size))
159 return PP_ERROR_FAILED;
160
161 base::SharedMemoryHandle shm_handle = shm->handle();
162 shm_buffers_.push_back(shm.release());
163
164 base::PlatformFile platform_file =
165 #if defined(OS_WIN)
yzshen1 2014/05/14 18:08:23 I think it is recommended to use #XXX around compl
bbudge 2014/05/14 19:35:04 Done.
166 shm_handle;
167 #elif defined(OS_POSIX)
168 shm_handle.fd;
169 #else
170 #error Not implemented.
171 #endif
172 SerializedHandle handle(
173 renderer_ppapi_host_->ShareHandleWithRemote(platform_file, false), size);
174 ppapi::host::ReplyMessageContext reply_context =
175 context->MakeReplyMessageContext();
176 reply_context.params.AppendHandle(handle);
177 host()->SendReply(reply_context,
178 PpapiPluginMsg_VideoDecoder_GetShmReply(size));
179 return PP_OK_COMPLETIONPENDING;
180 }
181
182 int32_t PepperVideoDecoderHost::OnHostMsgAssignTextures(
183 ppapi::host::HostMessageContext* context,
184 PP_Size size,
185 const std::vector<uint32_t>& texture_ids) {
186 if (!initialized_)
187 return PP_ERROR_FAILED;
188 if (!decoder_) {
yzshen1 2014/05/14 18:08:23 I think as long as |initialized_| is true, |decode
bbudge 2014/05/14 19:35:04 Done.
189 NOTREACHED();
190 return PP_ERROR_FAILED;
191 }
192
193 std::vector<media::PictureBuffer> picture_buffers;
194 for (uint32 i = 0; i < texture_ids.size(); i++) {
195 media::PictureBuffer buffer(
196 texture_ids[i], // Use the texture_id to identify the buffer.
197 gfx::Size(size.width, size.height),
198 texture_ids[i]);
199 picture_buffers.push_back(buffer);
200 }
201 decoder_->AssignPictureBuffers(picture_buffers);
202 return PP_OK;
203 }
204
205 int32_t PepperVideoDecoderHost::OnHostMsgDecode(
206 ppapi::host::HostMessageContext* context,
207 uint32_t shm_id,
208 uint32_t decode_id,
209 uint32_t size) {
210 if (!initialized_)
211 return PP_ERROR_FAILED;
212 // |shm_id| is just an index into shm_buffers_. Make sure it's in range.
213 if (static_cast<size_t>(shm_id) >= shm_buffers_.size())
214 return PP_ERROR_FAILED;
215
216 pending_decodes_.insert(std::make_pair(
yzshen1 2014/05/14 18:08:23 It seems this code allows multiple in-flight Decod
bbudge 2014/05/14 19:35:04 It's true that multiple decodes can be in-flight s
dmichael (off chromium) 2014/05/15 21:18:22 This confused me at first as well. It seems piman
217 decode_id, PendingDecode(shm_id, context->MakeReplyMessageContext())));
218
219 base::SharedMemory* shm = shm_buffers_[shm_id];
220 DCHECK(decoder_);
221 if (decoder_)
222 decoder_->Decode(media::BitstreamBuffer(decode_id, shm->handle(), size));
223
224 return PP_OK_COMPLETIONPENDING;
225 }
226
227 int32_t PepperVideoDecoderHost::OnHostMsgRecyclePicture(
228 ppapi::host::HostMessageContext* context,
229 uint32_t texture_id) {
230 if (!initialized_)
231 return PP_ERROR_FAILED;
232 DCHECK(decoder_);
233 if (decoder_)
234 decoder_->ReusePictureBuffer(texture_id);
235
236 return PP_OK;
237 }
238
239 int32_t PepperVideoDecoderHost::OnHostMsgFlush(
240 ppapi::host::HostMessageContext* context) {
241 if (!initialized_)
242 return PP_ERROR_FAILED;
243
244 flush_reply_context_ = context->MakeReplyMessageContext();
yzshen1 2014/05/14 18:08:23 If there is a pending Flush, this will rewrite the
bbudge 2014/05/14 19:35:04 The IDL is correct. I'll add checks here as well,
245 DCHECK(decoder_);
246 if (decoder_)
247 decoder_->Flush();
248
249 return PP_OK_COMPLETIONPENDING;
250 }
251
252 int32_t PepperVideoDecoderHost::OnHostMsgReset(
253 ppapi::host::HostMessageContext* context) {
254 if (!initialized_)
255 return PP_ERROR_FAILED;
256
257 reset_reply_context_ = context->MakeReplyMessageContext();
yzshen1 2014/05/14 18:08:23 If there is a pending Reset, this will rewrite the
bbudge 2014/05/14 19:35:04 Done.
258 DCHECK(decoder_);
259 if (decoder_)
260 decoder_->Reset();
261
262 return PP_OK_COMPLETIONPENDING;
263 }
264
265 void PepperVideoDecoderHost::ProvidePictureBuffers(
266 uint32 requested_num_of_buffers,
267 const gfx::Size& dimensions,
268 uint32 texture_target) {
269 RequestTextures(requested_num_of_buffers, dimensions, texture_target);
270 }
271
272 void PepperVideoDecoderHost::RequestTextures(uint32 requested_num_of_buffers,
273 const gfx::Size& dimensions,
274 uint32 texture_target) {
275 DCHECK(RenderThreadImpl::current());
276 host()->SendUnsolicitedReply(
277 pp_resource(),
278 PpapiPluginMsg_VideoDecoder_RequestTextures(
279 requested_num_of_buffers,
280 PP_MakeSize(dimensions.width(), dimensions.height()),
281 texture_target));
282 }
283
284 void PepperVideoDecoderHost::PictureReady(const media::Picture& picture) {
285 DCHECK(RenderThreadImpl::current());
286 host()->SendUnsolicitedReply(
287 pp_resource(),
288 PpapiPluginMsg_VideoDecoder_PictureReady(picture.bitstream_buffer_id(),
289 picture.picture_buffer_id()));
290 }
291
292 void PepperVideoDecoderHost::DismissPictureBuffer(int32 picture_buffer_id) {
293 DCHECK(RenderThreadImpl::current());
294 host()->SendUnsolicitedReply(
295 pp_resource(),
296 PpapiPluginMsg_VideoDecoder_DismissPicture(picture_buffer_id));
297 }
298
299 void PepperVideoDecoderHost::NotifyError(
300 media::VideoDecodeAccelerator::Error error) {
301 DCHECK(RenderThreadImpl::current());
302 int32_t pp_error = PP_ERROR_FAILED;
303 switch (error) {
304 case media::VideoDecodeAccelerator::UNREADABLE_INPUT:
305 pp_error = PP_ERROR_UNREADABLE_INPUT;
306 break;
307 case media::VideoDecodeAccelerator::ILLEGAL_STATE:
308 case media::VideoDecodeAccelerator::INVALID_ARGUMENT:
309 case media::VideoDecodeAccelerator::PLATFORM_FAILURE:
310 pp_error = PP_ERROR_PLATFORM_FAILED;
311 break;
312 default:
313 NOTREACHED();
314 break;
315 }
316 host()->SendUnsolicitedReply(
317 pp_resource(), PpapiPluginMsg_VideoDecoder_NotifyError(pp_error));
318 }
319
320 void PepperVideoDecoderHost::NotifyResetDone() {
321 DCHECK(RenderThreadImpl::current());
322 host()->SendReply(reset_reply_context_,
323 PpapiPluginMsg_VideoDecoder_ResetReply());
324 reset_reply_context_ = ppapi::host::ReplyMessageContext();
325 }
326
327 void PepperVideoDecoderHost::NotifyEndOfBitstreamBuffer(
328 int32 bitstream_buffer_id) {
329 DCHECK(RenderThreadImpl::current());
330 uint32_t decode_id = static_cast<uint32_t>(bitstream_buffer_id);
331 PendingDecodeMap::iterator it = pending_decodes_.find(decode_id);
332 if (it == pending_decodes_.end()) {
333 NOTREACHED();
334 return;
335 }
336 const PendingDecode& pending_decode = it->second;
337 host()->SendReply(
338 pending_decode.reply_context_,
339 PpapiPluginMsg_VideoDecoder_DecodeReply(pending_decode.shm_id_));
340 pending_decodes_.erase(it);
341 }
342
343 void PepperVideoDecoderHost::NotifyFlushDone() {
344 DCHECK(RenderThreadImpl::current());
345 host()->SendReply(flush_reply_context_,
346 PpapiPluginMsg_VideoDecoder_FlushReply());
347 flush_reply_context_ = ppapi::host::ReplyMessageContext();
348 }
349
350 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698