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

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: Changed docs for PP_ERROR_PLATFORM_FAILED. 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.
60 }
61
62 return media::VIDEO_CODEC_PROFILE_UNKNOWN;
63 }
64
65 } // namespace
66
67 PepperVideoDecoderHost::PendingDecode::PendingDecode(
68 uint32_t in_shm_id,
69 const ppapi::host::ReplyMessageContext& in_reply_context)
70 : shm_id(in_shm_id), reply_context(in_reply_context) {
71 }
72
73 PepperVideoDecoderHost::PendingDecode::~PendingDecode() {
74 }
75
76 PepperVideoDecoderHost::PepperVideoDecoderHost(RendererPpapiHost* host,
77 PP_Instance instance,
78 PP_Resource resource)
79 : ResourceHost(host->GetPpapiHost(), instance, resource),
80 renderer_ppapi_host_(host),
81 initialized_(false) {
82 }
83
84 PepperVideoDecoderHost::~PepperVideoDecoderHost() {
85 if (decoder_) {
86 decoder_->Destroy();
87 decoder_.reset();
88 }
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_GetShm,
98 OnHostMsgGetShm)
99 PPAPI_DISPATCH_HOST_RESOURCE_CALL(PpapiHostMsg_VideoDecoder_AssignTextures,
100 OnHostMsgAssignTextures)
101 PPAPI_DISPATCH_HOST_RESOURCE_CALL(PpapiHostMsg_VideoDecoder_Decode,
102 OnHostMsgDecode)
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) {
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::OnHostMsgGetShm(
152 ppapi::host::HostMessageContext* context,
153 uint32_t size) {
154 if (!initialized_)
155 return PP_ERROR_FAILED;
156
157 content::RenderThread* render_thread = content::RenderThread::Get();
158 scoped_ptr<base::SharedMemory> shm(
159 render_thread->HostAllocateSharedMemoryBuffer(size).Pass());
160 if (!shm)
161 return PP_ERROR_FAILED;
162 if (!shm->Map(size))
163 return PP_ERROR_FAILED;
164
165 base::SharedMemoryHandle shm_handle = shm->handle();
166 shm_buffers_.push_back(shm.release());
dmichael (off chromium) 2014/05/15 21:18:22 You don't seem to limit the number of buffers poss
bbudge 2014/05/15 22:27:44 Are we concerned about DoS attacks by plugins? It
167
168 #if defined(OS_WIN)
169 base::PlatformFile platform_file = shm_handle;
170 #elif defined(OS_POSIX)
171 base::PlatformFile platform_file = shm_handle.fd;
172 #else
173 #error Not implemented.
174 #endif
175 SerializedHandle handle(
176 renderer_ppapi_host_->ShareHandleWithRemote(platform_file, false), size);
177 ppapi::host::ReplyMessageContext reply_context =
178 context->MakeReplyMessageContext();
179 reply_context.params.AppendHandle(handle);
180 host()->SendReply(reply_context,
181 PpapiPluginMsg_VideoDecoder_GetShmReply(size));
182 return PP_OK_COMPLETIONPENDING;
183 }
184
185 int32_t PepperVideoDecoderHost::OnHostMsgAssignTextures(
186 ppapi::host::HostMessageContext* context,
187 const PP_Size& size,
188 const std::vector<uint32_t>& texture_ids) {
189 if (!initialized_)
190 return PP_ERROR_FAILED;
191 DCHECK(decoder_);
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 DCHECK(decoder_);
213 if (flush_reply_context_.is_valid() || reset_reply_context_.is_valid())
214 return PP_ERROR_FAILED;
215
216 // |shm_id| is just an index into shm_buffers_. Make sure it's in range.
217 if (static_cast<size_t>(shm_id) >= shm_buffers_.size())
218 return PP_ERROR_FAILED;
219
220 pending_decodes_.insert(std::make_pair(
221 decode_id, PendingDecode(shm_id, context->MakeReplyMessageContext())));
222
223 base::SharedMemory* shm = shm_buffers_[shm_id];
224 decoder_->Decode(media::BitstreamBuffer(decode_id, shm->handle(), size));
225
226 return PP_OK_COMPLETIONPENDING;
227 }
228
229 int32_t PepperVideoDecoderHost::OnHostMsgRecyclePicture(
230 ppapi::host::HostMessageContext* context,
231 uint32_t texture_id) {
232 if (!initialized_)
233 return PP_ERROR_FAILED;
234 DCHECK(decoder_);
235 if (reset_reply_context_.is_valid())
236 return PP_ERROR_FAILED;
237
238 decoder_->ReusePictureBuffer(texture_id);
239
240 return PP_OK;
241 }
242
243 int32_t PepperVideoDecoderHost::OnHostMsgFlush(
244 ppapi::host::HostMessageContext* context) {
245 if (!initialized_)
246 return PP_ERROR_FAILED;
247 DCHECK(decoder_);
248 if (flush_reply_context_.is_valid() || reset_reply_context_.is_valid())
249 return PP_ERROR_FAILED;
250
251 flush_reply_context_ = context->MakeReplyMessageContext();
252 decoder_->Flush();
253
254 return PP_OK_COMPLETIONPENDING;
255 }
256
257 int32_t PepperVideoDecoderHost::OnHostMsgReset(
258 ppapi::host::HostMessageContext* context) {
259 if (!initialized_)
260 return PP_ERROR_FAILED;
261 DCHECK(decoder_);
262 if (flush_reply_context_.is_valid() || reset_reply_context_.is_valid())
263 return PP_ERROR_FAILED;
264
265 reset_reply_context_ = context->MakeReplyMessageContext();
266 decoder_->Reset();
267
268 return PP_OK_COMPLETIONPENDING;
269 }
270
271 void PepperVideoDecoderHost::ProvidePictureBuffers(
272 uint32 requested_num_of_buffers,
273 const gfx::Size& dimensions,
274 uint32 texture_target) {
275 RequestTextures(requested_num_of_buffers, dimensions, texture_target);
276 }
277
278 void PepperVideoDecoderHost::RequestTextures(uint32 requested_num_of_buffers,
279 const gfx::Size& dimensions,
280 uint32 texture_target) {
281 DCHECK(RenderThreadImpl::current());
282 host()->SendUnsolicitedReply(
283 pp_resource(),
284 PpapiPluginMsg_VideoDecoder_RequestTextures(
285 requested_num_of_buffers,
286 PP_MakeSize(dimensions.width(), dimensions.height()),
287 texture_target));
288 }
289
290 void PepperVideoDecoderHost::PictureReady(const media::Picture& picture) {
291 DCHECK(RenderThreadImpl::current());
292 host()->SendUnsolicitedReply(
293 pp_resource(),
294 PpapiPluginMsg_VideoDecoder_PictureReady(picture.bitstream_buffer_id(),
295 picture.picture_buffer_id()));
296 }
297
298 void PepperVideoDecoderHost::DismissPictureBuffer(int32 picture_buffer_id) {
299 DCHECK(RenderThreadImpl::current());
300 host()->SendUnsolicitedReply(
301 pp_resource(),
302 PpapiPluginMsg_VideoDecoder_DismissPicture(picture_buffer_id));
303 }
304
305 void PepperVideoDecoderHost::NotifyError(
306 media::VideoDecodeAccelerator::Error error) {
307 DCHECK(RenderThreadImpl::current());
308 int32_t pp_error = PP_ERROR_FAILED;
309 switch (error) {
310 case media::VideoDecodeAccelerator::UNREADABLE_INPUT:
311 pp_error = PP_ERROR_MALFORMED_INPUT;
312 break;
313 case media::VideoDecodeAccelerator::ILLEGAL_STATE:
314 case media::VideoDecodeAccelerator::INVALID_ARGUMENT:
315 case media::VideoDecodeAccelerator::PLATFORM_FAILURE:
316 pp_error = PP_ERROR_PLATFORM_FAILED;
317 break;
318 default:
319 NOTREACHED();
320 break;
321 }
322 host()->SendUnsolicitedReply(
323 pp_resource(), PpapiPluginMsg_VideoDecoder_NotifyError(pp_error));
324 }
325
326 void PepperVideoDecoderHost::NotifyResetDone() {
327 DCHECK(RenderThreadImpl::current());
328 host()->SendReply(reset_reply_context_,
329 PpapiPluginMsg_VideoDecoder_ResetReply());
330 reset_reply_context_ = ppapi::host::ReplyMessageContext();
331 }
332
333 void PepperVideoDecoderHost::NotifyEndOfBitstreamBuffer(
334 int32 bitstream_buffer_id) {
335 DCHECK(RenderThreadImpl::current());
336 uint32_t decode_id = static_cast<uint32_t>(bitstream_buffer_id);
337 PendingDecodeMap::iterator it = pending_decodes_.find(decode_id);
338 if (it == pending_decodes_.end()) {
339 NOTREACHED();
340 return;
341 }
342 const PendingDecode& pending_decode = it->second;
343 host()->SendReply(
344 pending_decode.reply_context,
345 PpapiPluginMsg_VideoDecoder_DecodeReply(pending_decode.shm_id));
346 pending_decodes_.erase(it);
347 }
348
349 void PepperVideoDecoderHost::NotifyFlushDone() {
350 DCHECK(RenderThreadImpl::current());
351 host()->SendReply(flush_reply_context_,
352 PpapiPluginMsg_VideoDecoder_FlushReply());
353 flush_reply_context_ = ppapi::host::ReplyMessageContext();
354 }
355
356 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698