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

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. 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 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_VP8MAIN:
58 return media::VP8PROFILE_MAIN;
59 // No default case, to catch unhandled PP_VideoProfile values.
dmichael (off chromium) 2014/05/20 22:40:38 I think the previous indent was right. Did clang-f
bbudge 2014/05/22 18:34:55 I think I "fixed" this when I fixed the indent in
60 }
61
62 return media::VIDEO_CODEC_PROFILE_UNKNOWN;
63 }
64
65 // These constants should be kept in sync with VideoDecoderResource.
dmichael (off chromium) 2014/05/20 22:40:38 Your header currently includes video_decoder_resou
bbudge 2014/05/22 18:34:55 Added a .h file, ppapi/proxy/video_decoder_constan
66 // Maximum number of concurrent decodes which can be pending.
67 const uint32_t kMaximumPendingDecodes = 8;
68 // Maximum size of shared-memory buffers we allocate (4 MB). This should be
69 // enough for even 4K video at reasonable compression levels.
70 const uint32_t kMaximumBitstreamBufferSize = 4 << 20;
71
72 } // namespace
73
74 PepperVideoDecoderHost::PendingDecode::PendingDecode(
75 uint32_t shm_id,
76 const ppapi::host::ReplyMessageContext& reply_context)
77 : shm_id(shm_id), reply_context(reply_context) {
78 }
79
80 PepperVideoDecoderHost::PendingDecode::~PendingDecode() {
81 }
82
83 PepperVideoDecoderHost::PepperVideoDecoderHost(RendererPpapiHost* host,
84 PP_Instance instance,
85 PP_Resource resource)
86 : ResourceHost(host->GetPpapiHost(), instance, resource),
87 renderer_ppapi_host_(host),
88 next_decode_id_(0),
89 initialized_(false) {
90 }
91
92 PepperVideoDecoderHost::~PepperVideoDecoderHost() {
93 if (decoder_) {
94 decoder_->Destroy();
95 // The decoder will delete itself.
96 ignore_result(decoder_.release());
dmichael (off chromium) 2014/05/20 22:40:38 Yuck. Seems like the destructor for that class oug
bbudge 2014/05/22 18:34:55 I looked for existing usages of Destroy. Seems lik
dmichael (off chromium) 2014/05/23 22:44:47 Sure... being consistent makes sense. I still th
97 }
98 }
99
100 int32_t PepperVideoDecoderHost::OnResourceMessageReceived(
101 const IPC::Message& msg,
102 ppapi::host::HostMessageContext* context) {
103 PPAPI_BEGIN_MESSAGE_MAP(PepperVideoDecoderHost, msg)
104 PPAPI_DISPATCH_HOST_RESOURCE_CALL(PpapiHostMsg_VideoDecoder_Initialize,
105 OnHostMsgInitialize)
106 PPAPI_DISPATCH_HOST_RESOURCE_CALL(PpapiHostMsg_VideoDecoder_GetShm,
107 OnHostMsgGetShm)
108 PPAPI_DISPATCH_HOST_RESOURCE_CALL(PpapiHostMsg_VideoDecoder_AssignTextures,
109 OnHostMsgAssignTextures)
110 PPAPI_DISPATCH_HOST_RESOURCE_CALL(PpapiHostMsg_VideoDecoder_Decode,
111 OnHostMsgDecode)
112 PPAPI_DISPATCH_HOST_RESOURCE_CALL(PpapiHostMsg_VideoDecoder_RecyclePicture,
113 OnHostMsgRecyclePicture)
114 PPAPI_DISPATCH_HOST_RESOURCE_CALL_0(PpapiHostMsg_VideoDecoder_Flush,
115 OnHostMsgFlush)
116 PPAPI_DISPATCH_HOST_RESOURCE_CALL_0(PpapiHostMsg_VideoDecoder_Reset,
117 OnHostMsgReset)
118 PPAPI_END_MESSAGE_MAP()
119 return PP_ERROR_FAILED;
120 }
121
122 int32_t PepperVideoDecoderHost::OnHostMsgInitialize(
123 ppapi::host::HostMessageContext* context,
124 const ppapi::HostResource& graphics_context,
125 PP_VideoProfile profile,
126 bool allow_software_fallback) {
127 if (initialized_)
128 return PP_ERROR_FAILED;
129
130 EnterResourceNoLock<PPB_Graphics3D_API> enter_graphics(
131 graphics_context.host_resource(), true);
132 if (enter_graphics.failed())
133 return PP_ERROR_FAILED;
134 graphics3d_ = static_cast<PPB_Graphics3D_Impl*>(enter_graphics.object());
135
136 int command_buffer_route_id = graphics3d_->GetCommandBufferRouteId();
137 if (!command_buffer_route_id)
138 return PP_ERROR_FAILED;
139
140 media::VideoCodecProfile media_profile = PepperToMediaVideoProfile(profile);
141
142 // This is not synchronous, but subsequent IPC messages will be buffered, so
143 // it is okay to immediately send IPC messages through the returned channel.
144 GpuChannelHost* channel = graphics3d_->channel();
145 DCHECK(channel);
146
147 if (channel) {
148 decoder_ = channel->CreateVideoDecoder(command_buffer_route_id);
149 if (decoder_ && decoder_->Initialize(media_profile, this)) {
150 initialized_ = true;
151 return PP_OK;
152 }
153 decoder_.reset();
154 }
155
156 // TODO(bbudge) Implement software fallback.
157 return PP_ERROR_NOTSUPPORTED;
158 }
159
160 int32_t PepperVideoDecoderHost::OnHostMsgGetShm(
161 ppapi::host::HostMessageContext* context,
162 uint32_t size,
163 uint32_t pending_shm_id) {
164 if (!initialized_)
165 return PP_ERROR_FAILED;
166 if (size > kMaximumBitstreamBufferSize)
167 return PP_ERROR_FAILED;
168 if (pending_shm_id >= kMaximumPendingDecodes)
169 return PP_ERROR_FAILED;
170 // The shm_id must be inside or at the end of shm_buffers_.
171 if (pending_shm_id > shm_buffers_.size())
172 return PP_ERROR_FAILED;
173
174 // Is this is a request to reallocate (grow) a buffer?
175 if (pending_shm_id < shm_buffers_.size()) {
176 // Reject an attempt to reallocate a busy shm buffer.
177 if (shm_buffer_busy_[pending_shm_id])
dmichael (off chromium) 2014/05/20 22:40:38 Could you instead just say: if (pending_decodes_.c
bbudge 2014/05/22 18:34:55 It requires iterating through the map. The key her
178 return PP_ERROR_FAILED;
179 // The buffer isn't in use. Delete it early to make allocation of a new,
180 // larger one more likely to succeed. Delete it manually since ScopedVector
181 // doesn't do the right thing.
dmichael (off chromium) 2014/05/20 22:40:38 nit: maybe better to say "won't delete the existin
bbudge 2014/05/22 18:34:55 Done.
182 delete shm_buffers_[pending_shm_id];
183 shm_buffers_[pending_shm_id] = NULL;
184 }
185
186 content::RenderThread* render_thread = content::RenderThread::Get();
187 scoped_ptr<base::SharedMemory> shm(
188 render_thread->HostAllocateSharedMemoryBuffer(size).Pass());
189 if (!shm)
190 return PP_ERROR_FAILED;
191 if (!shm->Map(size))
192 return PP_ERROR_FAILED;
193
194 base::SharedMemoryHandle shm_handle = shm->handle();
195 if (pending_shm_id == shm_buffers_.size()) {
196 shm_buffers_.push_back(shm.release());
197 shm_buffer_busy_.push_back(0);
198 } else {
199 // Fill in the new resized buffer.
200 shm_buffers_[pending_shm_id] = shm.release();
201 }
202
203 #if defined(OS_WIN)
204 base::PlatformFile platform_file = shm_handle;
205 #elif defined(OS_POSIX)
206 base::PlatformFile platform_file = shm_handle.fd;
207 #else
208 #error Not implemented.
209 #endif
210 SerializedHandle handle(
211 renderer_ppapi_host_->ShareHandleWithRemote(platform_file, false), size);
212 ppapi::host::ReplyMessageContext reply_context =
213 context->MakeReplyMessageContext();
214 reply_context.params.AppendHandle(handle);
215 host()->SendReply(reply_context,
216 PpapiPluginMsg_VideoDecoder_GetShmReply(size));
217 return PP_OK_COMPLETIONPENDING;
218 }
219
220 int32_t PepperVideoDecoderHost::OnHostMsgAssignTextures(
221 ppapi::host::HostMessageContext* context,
222 const PP_Size& size,
223 const std::vector<uint32_t>& texture_ids) {
224 if (!initialized_)
225 return PP_ERROR_FAILED;
226 DCHECK(decoder_);
227
228 std::vector<media::PictureBuffer> picture_buffers;
229 for (uint32 i = 0; i < texture_ids.size(); i++) {
230 media::PictureBuffer buffer(
231 texture_ids[i], // Use the texture_id to identify the buffer.
232 gfx::Size(size.width, size.height),
233 texture_ids[i]);
234 picture_buffers.push_back(buffer);
235 }
236 decoder_->AssignPictureBuffers(picture_buffers);
237 return PP_OK;
238 }
239
240 int32_t PepperVideoDecoderHost::OnHostMsgDecode(
241 ppapi::host::HostMessageContext* context,
242 uint32_t shm_id,
243 uint32_t size) {
244 if (!initialized_)
245 return PP_ERROR_FAILED;
246 DCHECK(decoder_);
247 // |shm_id| is just an index into shm_buffers_. Make sure it's in range.
248 if (static_cast<size_t>(shm_id) >= shm_buffers_.size())
249 return PP_ERROR_FAILED;
250 // Reject an attempt to pass a busy buffer to the decoder again.
251 if (shm_buffer_busy_[shm_id])
dmichael (off chromium) 2014/05/20 22:40:38 same as above, I think you could just look in the
bbudge 2014/05/22 18:34:55 See comments above.
252 return PP_ERROR_FAILED;
253
254 if (flush_reply_context_.is_valid() || reset_reply_context_.is_valid())
255 return PP_ERROR_FAILED;
256
257 uint32_t uid = next_decode_id_++;
258 pending_decodes_.insert(std::make_pair(
259 uid, PendingDecode(shm_id, context->MakeReplyMessageContext())));
260
261 shm_buffer_busy_[shm_id] = true;
262 decoder_->Decode(media::BitstreamBuffer(
263 uid, shm_buffers_[shm_id]->handle(), size));
264
265 return PP_OK_COMPLETIONPENDING;
266 }
267
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_);
274 if (reset_reply_context_.is_valid())
275 return PP_ERROR_FAILED;
276
277 decoder_->ReusePictureBuffer(texture_id);
278
279 return PP_OK;
280 }
281
282 int32_t PepperVideoDecoderHost::OnHostMsgFlush(
283 ppapi::host::HostMessageContext* context) {
284 if (!initialized_)
285 return PP_ERROR_FAILED;
286 DCHECK(decoder_);
287 if (flush_reply_context_.is_valid() || reset_reply_context_.is_valid())
288 return PP_ERROR_FAILED;
289
290 flush_reply_context_ = context->MakeReplyMessageContext();
291 decoder_->Flush();
292
293 return PP_OK_COMPLETIONPENDING;
294 }
295
296 int32_t PepperVideoDecoderHost::OnHostMsgReset(
297 ppapi::host::HostMessageContext* context) {
298 if (!initialized_)
299 return PP_ERROR_FAILED;
300 DCHECK(decoder_);
301 if (flush_reply_context_.is_valid() || reset_reply_context_.is_valid())
302 return PP_ERROR_FAILED;
303
304 reset_reply_context_ = context->MakeReplyMessageContext();
305 decoder_->Reset();
306
307 return PP_OK_COMPLETIONPENDING;
308 }
309
310 void PepperVideoDecoderHost::ProvidePictureBuffers(
311 uint32 requested_num_of_buffers,
312 const gfx::Size& dimensions,
313 uint32 texture_target) {
314 RequestTextures(requested_num_of_buffers, dimensions, texture_target);
315 }
316
317 void PepperVideoDecoderHost::RequestTextures(uint32 requested_num_of_buffers,
318 const gfx::Size& dimensions,
319 uint32 texture_target) {
320 DCHECK(RenderThreadImpl::current());
321 host()->SendUnsolicitedReply(
322 pp_resource(),
323 PpapiPluginMsg_VideoDecoder_RequestTextures(
324 requested_num_of_buffers,
325 PP_MakeSize(dimensions.width(), dimensions.height()),
326 texture_target));
327 }
328
329 void PepperVideoDecoderHost::PictureReady(const media::Picture& picture) {
330 DCHECK(RenderThreadImpl::current());
331 host()->SendUnsolicitedReply(
332 pp_resource(),
333 PpapiPluginMsg_VideoDecoder_PictureReady(picture.bitstream_buffer_id(),
334 picture.picture_buffer_id()));
335 }
336
337 void PepperVideoDecoderHost::DismissPictureBuffer(int32 picture_buffer_id) {
338 DCHECK(RenderThreadImpl::current());
339 host()->SendUnsolicitedReply(
340 pp_resource(),
341 PpapiPluginMsg_VideoDecoder_DismissPicture(picture_buffer_id));
342 }
343
344 void PepperVideoDecoderHost::NotifyError(
345 media::VideoDecodeAccelerator::Error error) {
346 DCHECK(RenderThreadImpl::current());
347 int32_t pp_error = PP_ERROR_FAILED;
348 switch (error) {
349 case media::VideoDecodeAccelerator::UNREADABLE_INPUT:
350 pp_error = PP_ERROR_MALFORMED_INPUT;
351 break;
352 case media::VideoDecodeAccelerator::ILLEGAL_STATE:
353 case media::VideoDecodeAccelerator::INVALID_ARGUMENT:
354 case media::VideoDecodeAccelerator::PLATFORM_FAILURE:
355 pp_error = PP_ERROR_RESOURCE_FAILED;
356 break;
357 default:
358 NOTREACHED();
359 break;
360 }
361 host()->SendUnsolicitedReply(
362 pp_resource(), PpapiPluginMsg_VideoDecoder_NotifyError(pp_error));
363 }
364
365 void PepperVideoDecoderHost::NotifyResetDone() {
366 DCHECK(RenderThreadImpl::current());
367 host()->SendReply(reset_reply_context_,
368 PpapiPluginMsg_VideoDecoder_ResetReply());
369 reset_reply_context_ = ppapi::host::ReplyMessageContext();
370 }
371
372 void PepperVideoDecoderHost::NotifyEndOfBitstreamBuffer(
373 int32 bitstream_buffer_id) {
374 DCHECK(RenderThreadImpl::current());
375 uint32_t uid = static_cast<uint32_t>(bitstream_buffer_id);
dmichael (off chromium) 2014/05/20 22:40:38 If the decode API forces you to use int32, you mig
bbudge 2014/05/22 18:34:55 Changed uid type to int32.
376 PendingDecodeMap::iterator it = pending_decodes_.find(uid);
377 if (it == pending_decodes_.end()) {
378 NOTREACHED();
379 return;
380 }
381 const PendingDecode& pending_decode = it->second;
382 host()->SendReply(
383 pending_decode.reply_context,
384 PpapiPluginMsg_VideoDecoder_DecodeReply(pending_decode.shm_id));
385 shm_buffer_busy_[pending_decode.shm_id] = false;
386 pending_decodes_.erase(it);
387 }
388
389 void PepperVideoDecoderHost::NotifyFlushDone() {
390 DCHECK(RenderThreadImpl::current());
391 host()->SendReply(flush_reply_context_,
392 PpapiPluginMsg_VideoDecoder_FlushReply());
393 flush_reply_context_ = ppapi::host::ReplyMessageContext();
394 }
395
396 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698