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

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/proxy/video_decoder_constants.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 media::VideoCodecProfile PepperToMediaVideoProfile(PP_VideoProfile profile) {
35 switch (profile) {
36 case PP_VIDEOPROFILE_H264BASELINE:
37 return media::H264PROFILE_BASELINE;
38 case PP_VIDEOPROFILE_H264MAIN:
39 return media::H264PROFILE_MAIN;
40 case PP_VIDEOPROFILE_H264EXTENDED:
41 return media::H264PROFILE_EXTENDED;
42 case PP_VIDEOPROFILE_H264HIGH:
43 return media::H264PROFILE_HIGH;
44 case PP_VIDEOPROFILE_H264HIGH10PROFILE:
45 return media::H264PROFILE_HIGH10PROFILE;
46 case PP_VIDEOPROFILE_H264HIGH422PROFILE:
47 return media::H264PROFILE_HIGH422PROFILE;
48 case PP_VIDEOPROFILE_H264HIGH444PREDICTIVEPROFILE:
49 return media::H264PROFILE_HIGH444PREDICTIVEPROFILE;
50 case PP_VIDEOPROFILE_H264SCALABLEBASELINE:
51 return media::H264PROFILE_SCALABLEBASELINE;
52 case PP_VIDEOPROFILE_H264SCALABLEHIGH:
53 return media::H264PROFILE_SCALABLEHIGH;
54 case PP_VIDEOPROFILE_H264STEREOHIGH:
55 return media::H264PROFILE_STEREOHIGH;
56 case PP_VIDEOPROFILE_H264MULTIVIEWHIGH:
57 return media::H264PROFILE_MULTIVIEWHIGH;
58 case PP_VIDEOPROFILE_VP8MAIN:
59 return media::VP8PROFILE_MAIN;
60 // No default case, to catch unhandled PP_VideoProfile values.
61 }
62
63 return media::VIDEO_CODEC_PROFILE_UNKNOWN;
64 }
65
66 } // namespace
67
68 PepperVideoDecoderHost::PendingDecode::PendingDecode(
69 uint32_t shm_id,
70 const ppapi::host::ReplyMessageContext& reply_context)
71 : shm_id(shm_id), reply_context(reply_context) {
72 }
73
74 PepperVideoDecoderHost::PendingDecode::~PendingDecode() {
75 }
76
77 PepperVideoDecoderHost::PepperVideoDecoderHost(RendererPpapiHost* host,
78 PP_Instance instance,
79 PP_Resource resource)
80 : ResourceHost(host->GetPpapiHost(), instance, resource),
81 renderer_ppapi_host_(host),
82 num_decodes_(0),
83 initialized_(false) {
84 }
85
86 PepperVideoDecoderHost::~PepperVideoDecoderHost() {
87 if (decoder_)
88 decoder_.release()->Destroy();
89 }
90
91 int32_t PepperVideoDecoderHost::OnResourceMessageReceived(
92 const IPC::Message& msg,
93 ppapi::host::HostMessageContext* context) {
94 PPAPI_BEGIN_MESSAGE_MAP(PepperVideoDecoderHost, msg)
95 PPAPI_DISPATCH_HOST_RESOURCE_CALL(PpapiHostMsg_VideoDecoder_Initialize,
96 OnHostMsgInitialize)
97 PPAPI_DISPATCH_HOST_RESOURCE_CALL(PpapiHostMsg_VideoDecoder_DecodeBuffer,
98 OnHostMsgDecodeBuffer)
99 PPAPI_DISPATCH_HOST_RESOURCE_CALL(PpapiHostMsg_VideoDecoder_Decode,
100 OnHostMsgDecode)
101 PPAPI_DISPATCH_HOST_RESOURCE_CALL(PpapiHostMsg_VideoDecoder_AssignTextures,
102 OnHostMsgAssignTextures)
103 PPAPI_DISPATCH_HOST_RESOURCE_CALL(PpapiHostMsg_VideoDecoder_RecyclePicture,
104 OnHostMsgRecyclePicture)
105 PPAPI_DISPATCH_HOST_RESOURCE_CALL_0(PpapiHostMsg_VideoDecoder_Flush,
106 OnHostMsgFlush)
107 PPAPI_DISPATCH_HOST_RESOURCE_CALL_0(PpapiHostMsg_VideoDecoder_Reset,
108 OnHostMsgReset)
109 PPAPI_END_MESSAGE_MAP()
110 return PP_ERROR_FAILED;
111 }
112
113 int32_t PepperVideoDecoderHost::OnHostMsgInitialize(
114 ppapi::host::HostMessageContext* context,
115 const ppapi::HostResource& graphics_context,
116 PP_VideoProfile profile,
117 bool allow_software_fallback) {
118 if (initialized_)
119 return PP_ERROR_FAILED;
120
121 EnterResourceNoLock<PPB_Graphics3D_API> enter_graphics(
122 graphics_context.host_resource(), true);
123 if (enter_graphics.failed())
124 return PP_ERROR_FAILED;
125 graphics3d_ = static_cast<PPB_Graphics3D_Impl*>(enter_graphics.object());
126
127 int command_buffer_route_id = graphics3d_->GetCommandBufferRouteId();
128 if (!command_buffer_route_id)
129 return PP_ERROR_FAILED;
130
131 media::VideoCodecProfile media_profile = PepperToMediaVideoProfile(profile);
132
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
138 if (channel) {
piman 2014/05/22 20:43:19 either DCHECK or if, but not both. I think the DC
bbudge 2014/05/23 12:24:35 Done.
139 decoder_ = channel->CreateVideoDecoder(command_buffer_route_id);
140 if (decoder_ && decoder_->Initialize(media_profile, this)) {
141 initialized_ = true;
142 return PP_OK;
143 }
144 decoder_.reset();
145 }
146
147 // TODO(bbudge) Implement software fallback.
148 return PP_ERROR_NOTSUPPORTED;
149 }
150
151 int32_t PepperVideoDecoderHost::OnHostMsgDecodeBuffer(
152 ppapi::host::HostMessageContext* context,
153 const std::vector<uint8_t>& buffer,
154 uint32_t pending_shm_id) {
155 if (!initialized_)
156 return PP_ERROR_FAILED;
157
158 uint32_t buffer_size = static_cast<uint32_t>(buffer.size());
159 // Make the buffers larger since we hope to reuse them.
160 uint32_t shm_size =
161 std::max(buffer_size, ppapi::proxy::kMinimumBitstreamBufferSize);
162 if (shm_size > ppapi::proxy::kMaximumBitstreamBufferSize)
163 return PP_ERROR_FAILED;
164
165 if (pending_shm_id >= ppapi::proxy::kMaximumPendingDecodes)
166 return PP_ERROR_FAILED;
167 // The shm_id must be inside or at the end of shm_buffers_.
168 if (pending_shm_id > shm_buffers_.size())
169 return PP_ERROR_FAILED;
170 // Reject an attempt to reallocate a busy shm buffer.
171 if (pending_shm_id < shm_buffers_.size() && shm_buffer_busy_[pending_shm_id])
172 return PP_ERROR_FAILED;
173
174 content::RenderThread* render_thread = content::RenderThread::Get();
175 scoped_ptr<base::SharedMemory> shm(
176 render_thread->HostAllocateSharedMemoryBuffer(shm_size).Pass());
177 if (!shm || !shm->Map(shm_size))
178 return PP_ERROR_FAILED;
179
180 memcpy(shm->memory(), &buffer.front(), buffer.size());
181
182 base::SharedMemoryHandle shm_handle = shm->handle();
183 if (pending_shm_id == shm_buffers_.size()) {
184 shm_buffers_.push_back(shm.release());
185 shm_buffer_busy_.push_back(false);
186 } else {
187 // Fill in the new resized buffer. Delete it manually since ScopedVector
188 // won't delete the existing element if we just assign it.
189 delete shm_buffers_[pending_shm_id];
190 shm_buffers_[pending_shm_id] = shm.release();
191 }
192
193 #if defined(OS_WIN)
194 base::PlatformFile platform_file = shm_handle;
195 #elif defined(OS_POSIX)
196 base::PlatformFile platform_file = shm_handle.fd;
197 #else
198 #error Not implemented.
199 #endif
200 SerializedHandle handle(
201 renderer_ppapi_host_->ShareHandleWithRemote(
202 platform_file, false), shm_size);
203 host()->SendUnsolicitedReplyWithHandles(
204 pp_resource(),
205 PpapiPluginMsg_VideoDecoder_CreatedShm(shm_size),
206 std::vector<SerializedHandle>(1, handle));
207
208 DoDecode(context, pending_shm_id, buffer_size);
209 return PP_OK_COMPLETIONPENDING;
210 }
211
212 int32_t PepperVideoDecoderHost::OnHostMsgDecode(
213 ppapi::host::HostMessageContext* context,
214 uint32_t shm_id,
215 uint32_t size) {
216 if (!initialized_)
217 return PP_ERROR_FAILED;
218 DCHECK(decoder_);
219 // |shm_id| is just an index into shm_buffers_. Make sure it's in range.
220 if (static_cast<size_t>(shm_id) >= shm_buffers_.size())
221 return PP_ERROR_FAILED;
222 // Reject an attempt to pass a busy buffer to the decoder again.
223 if (shm_buffer_busy_[shm_id])
224 return PP_ERROR_FAILED;
225
226 if (flush_reply_context_.is_valid() || reset_reply_context_.is_valid())
227 return PP_ERROR_FAILED;
228
229 DoDecode(context, shm_id, size);
230 return PP_OK_COMPLETIONPENDING;
231 }
232
233 int32_t PepperVideoDecoderHost::OnHostMsgAssignTextures(
234 ppapi::host::HostMessageContext* context,
235 const PP_Size& size,
236 const std::vector<uint32_t>& texture_ids) {
237 if (!initialized_)
238 return PP_ERROR_FAILED;
239 DCHECK(decoder_);
240
241 std::vector<media::PictureBuffer> picture_buffers;
242 for (uint32 i = 0; i < texture_ids.size(); i++) {
243 media::PictureBuffer buffer(
244 texture_ids[i], // Use the texture_id to identify the buffer.
245 gfx::Size(size.width, size.height),
246 texture_ids[i]);
247 picture_buffers.push_back(buffer);
248 }
249 decoder_->AssignPictureBuffers(picture_buffers);
250 return PP_OK;
251 }
252
253 int32_t PepperVideoDecoderHost::OnHostMsgRecyclePicture(
254 ppapi::host::HostMessageContext* context,
255 uint32_t texture_id) {
256 if (!initialized_)
257 return PP_ERROR_FAILED;
258 DCHECK(decoder_);
259 if (reset_reply_context_.is_valid())
260 return PP_ERROR_FAILED;
261
262 decoder_->ReusePictureBuffer(texture_id);
263
264 return PP_OK;
265 }
266
267 int32_t PepperVideoDecoderHost::OnHostMsgFlush(
268 ppapi::host::HostMessageContext* context) {
269 if (!initialized_)
270 return PP_ERROR_FAILED;
271 DCHECK(decoder_);
272 if (flush_reply_context_.is_valid() || reset_reply_context_.is_valid())
273 return PP_ERROR_FAILED;
274
275 flush_reply_context_ = context->MakeReplyMessageContext();
276 decoder_->Flush();
277
278 return PP_OK_COMPLETIONPENDING;
279 }
280
281 int32_t PepperVideoDecoderHost::OnHostMsgReset(
282 ppapi::host::HostMessageContext* context) {
283 if (!initialized_)
284 return PP_ERROR_FAILED;
285 DCHECK(decoder_);
286 if (flush_reply_context_.is_valid() || reset_reply_context_.is_valid())
287 return PP_ERROR_FAILED;
288
289 reset_reply_context_ = context->MakeReplyMessageContext();
290 decoder_->Reset();
291
292 return PP_OK_COMPLETIONPENDING;
293 }
294
295 void PepperVideoDecoderHost::ProvidePictureBuffers(
296 uint32 requested_num_of_buffers,
297 const gfx::Size& dimensions,
298 uint32 texture_target) {
299 RequestTextures(requested_num_of_buffers, dimensions, texture_target);
300 }
301
302 void PepperVideoDecoderHost::DoDecode(
303 ppapi::host::HostMessageContext* context,
304 uint32_t shm_id,
305 uint32_t size) {
306 int32_t uid = num_decodes_++;
307 pending_decodes_.insert(std::make_pair(
308 uid, PendingDecode(shm_id, context->MakeReplyMessageContext())));
309
310 shm_buffer_busy_[shm_id] = true;
311 decoder_->Decode(media::BitstreamBuffer(
312 uid, shm_buffers_[shm_id]->handle(), size));
313 }
314
315 void PepperVideoDecoderHost::RequestTextures(uint32 requested_num_of_buffers,
316 const gfx::Size& dimensions,
317 uint32 texture_target) {
318 DCHECK(RenderThreadImpl::current());
319 host()->SendUnsolicitedReply(
320 pp_resource(),
321 PpapiPluginMsg_VideoDecoder_RequestTextures(
322 requested_num_of_buffers,
323 PP_MakeSize(dimensions.width(), dimensions.height()),
324 texture_target));
325 }
326
327 void PepperVideoDecoderHost::PictureReady(const media::Picture& picture) {
328 DCHECK(RenderThreadImpl::current());
329 host()->SendUnsolicitedReply(
330 pp_resource(),
331 PpapiPluginMsg_VideoDecoder_PictureReady(picture.bitstream_buffer_id(),
332 picture.picture_buffer_id()));
333 }
334
335 void PepperVideoDecoderHost::DismissPictureBuffer(int32 picture_buffer_id) {
336 DCHECK(RenderThreadImpl::current());
337 host()->SendUnsolicitedReply(
338 pp_resource(),
339 PpapiPluginMsg_VideoDecoder_DismissPicture(picture_buffer_id));
340 }
341
342 void PepperVideoDecoderHost::NotifyError(
343 media::VideoDecodeAccelerator::Error error) {
344 DCHECK(RenderThreadImpl::current());
345 int32_t pp_error = PP_ERROR_FAILED;
346 switch (error) {
347 case media::VideoDecodeAccelerator::UNREADABLE_INPUT:
348 pp_error = PP_ERROR_MALFORMED_INPUT;
349 break;
350 case media::VideoDecodeAccelerator::ILLEGAL_STATE:
351 case media::VideoDecodeAccelerator::INVALID_ARGUMENT:
352 case media::VideoDecodeAccelerator::PLATFORM_FAILURE:
353 pp_error = PP_ERROR_RESOURCE_FAILED;
354 break;
355 default:
356 NOTREACHED();
357 break;
358 }
359 host()->SendUnsolicitedReply(
360 pp_resource(), PpapiPluginMsg_VideoDecoder_NotifyError(pp_error));
361 }
362
363 void PepperVideoDecoderHost::NotifyResetDone() {
364 DCHECK(RenderThreadImpl::current());
365 host()->SendReply(reset_reply_context_,
366 PpapiPluginMsg_VideoDecoder_ResetReply());
367 reset_reply_context_ = ppapi::host::ReplyMessageContext();
368 }
369
370 void PepperVideoDecoderHost::NotifyEndOfBitstreamBuffer(
371 int32 bitstream_buffer_id) {
372 DCHECK(RenderThreadImpl::current());
373 PendingDecodeMap::iterator it = pending_decodes_.find(bitstream_buffer_id);
374 if (it == pending_decodes_.end()) {
375 NOTREACHED();
376 return;
377 }
378 const PendingDecode& pending_decode = it->second;
379 host()->SendReply(
380 pending_decode.reply_context,
381 PpapiPluginMsg_VideoDecoder_DecodeReply(pending_decode.shm_id));
382 shm_buffer_busy_[pending_decode.shm_id] = false;
383 pending_decodes_.erase(it);
384 }
385
386 void PepperVideoDecoderHost::NotifyFlushDone() {
387 DCHECK(RenderThreadImpl::current());
388 host()->SendReply(flush_reply_context_,
389 PpapiPluginMsg_VideoDecoder_FlushReply());
390 flush_reply_context_ = ppapi::host::ReplyMessageContext();
391 }
392
393 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698