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

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: Disable some unit tests on Win 64 bit builds. Created 6 years, 6 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 initialized_(false) {
83 }
84
85 PepperVideoDecoderHost::~PepperVideoDecoderHost() {
86 }
87
88 int32_t PepperVideoDecoderHost::OnResourceMessageReceived(
89 const IPC::Message& msg,
90 ppapi::host::HostMessageContext* context) {
91 PPAPI_BEGIN_MESSAGE_MAP(PepperVideoDecoderHost, msg)
92 PPAPI_DISPATCH_HOST_RESOURCE_CALL(PpapiHostMsg_VideoDecoder_Initialize,
93 OnHostMsgInitialize)
94 PPAPI_DISPATCH_HOST_RESOURCE_CALL(PpapiHostMsg_VideoDecoder_GetShm,
95 OnHostMsgGetShm)
96 PPAPI_DISPATCH_HOST_RESOURCE_CALL(PpapiHostMsg_VideoDecoder_Decode,
97 OnHostMsgDecode)
98 PPAPI_DISPATCH_HOST_RESOURCE_CALL(PpapiHostMsg_VideoDecoder_AssignTextures,
99 OnHostMsgAssignTextures)
100 PPAPI_DISPATCH_HOST_RESOURCE_CALL(PpapiHostMsg_VideoDecoder_RecyclePicture,
101 OnHostMsgRecyclePicture)
102 PPAPI_DISPATCH_HOST_RESOURCE_CALL_0(PpapiHostMsg_VideoDecoder_Flush,
103 OnHostMsgFlush)
104 PPAPI_DISPATCH_HOST_RESOURCE_CALL_0(PpapiHostMsg_VideoDecoder_Reset,
105 OnHostMsgReset)
106 PPAPI_END_MESSAGE_MAP()
107 return PP_ERROR_FAILED;
108 }
109
110 int32_t PepperVideoDecoderHost::OnHostMsgInitialize(
111 ppapi::host::HostMessageContext* context,
112 const ppapi::HostResource& graphics_context,
113 PP_VideoProfile profile,
114 bool allow_software_fallback) {
115 if (initialized_)
116 return PP_ERROR_FAILED;
117
118 EnterResourceNoLock<PPB_Graphics3D_API> enter_graphics(
119 graphics_context.host_resource(), true);
120 if (enter_graphics.failed())
121 return PP_ERROR_FAILED;
122 graphics3d_ = static_cast<PPB_Graphics3D_Impl*>(enter_graphics.object());
123
124 int command_buffer_route_id = graphics3d_->GetCommandBufferRouteId();
125 if (!command_buffer_route_id)
126 return PP_ERROR_FAILED;
127
128 media::VideoCodecProfile media_profile = PepperToMediaVideoProfile(profile);
129
130 // This is not synchronous, but subsequent IPC messages will be buffered, so
131 // it is okay to immediately send IPC messages through the returned channel.
132 GpuChannelHost* channel = graphics3d_->channel();
133 DCHECK(channel);
134 decoder_ = channel->CreateVideoDecoder(command_buffer_route_id);
135 if (decoder_ && decoder_->Initialize(media_profile, this)) {
136 initialized_ = true;
137 return PP_OK;
138 }
139 decoder_.reset();
140
141 // TODO(bbudge) Implement software fallback.
142 return PP_ERROR_NOTSUPPORTED;
143 }
144
145 int32_t PepperVideoDecoderHost::OnHostMsgGetShm(
146 ppapi::host::HostMessageContext* context,
147 uint32_t shm_id,
148 uint32_t shm_size) {
149 if (!initialized_)
150 return PP_ERROR_FAILED;
151
152 // Make the buffers larger since we hope to reuse them.
153 shm_size = std::max(
154 shm_size,
155 static_cast<uint32_t>(ppapi::proxy::kMinimumBitstreamBufferSize));
156 if (shm_size > ppapi::proxy::kMaximumBitstreamBufferSize)
157 return PP_ERROR_FAILED;
158
159 if (shm_id >= ppapi::proxy::kMaximumPendingDecodes)
160 return PP_ERROR_FAILED;
161 // The shm_id must be inside or at the end of shm_buffers_.
162 if (shm_id > shm_buffers_.size())
163 return PP_ERROR_FAILED;
164 // Reject an attempt to reallocate a busy shm buffer.
165 if (shm_id < shm_buffers_.size() && shm_buffer_busy_[shm_id])
166 return PP_ERROR_FAILED;
167
168 content::RenderThread* render_thread = content::RenderThread::Get();
169 scoped_ptr<base::SharedMemory> shm(
170 render_thread->HostAllocateSharedMemoryBuffer(shm_size).Pass());
171 if (!shm || !shm->Map(shm_size))
172 return PP_ERROR_FAILED;
173
174 base::SharedMemoryHandle shm_handle = shm->handle();
175 if (shm_id == shm_buffers_.size()) {
176 shm_buffers_.push_back(shm.release());
177 shm_buffer_busy_.push_back(false);
178 } else {
179 // Fill in the new resized buffer. Delete it manually since ScopedVector
180 // won't delete the existing element if we just assign it.
181 delete shm_buffers_[shm_id];
182 shm_buffers_[shm_id] = shm.release();
183 }
184
185 #if defined(OS_WIN)
186 base::PlatformFile platform_file = shm_handle;
187 #elif defined(OS_POSIX)
188 base::PlatformFile platform_file = shm_handle.fd;
189 #else
190 #error Not implemented.
191 #endif
192 SerializedHandle handle(
193 renderer_ppapi_host_->ShareHandleWithRemote(platform_file, false),
194 shm_size);
195 ppapi::host::ReplyMessageContext reply_context =
196 context->MakeReplyMessageContext();
197 reply_context.params.AppendHandle(handle);
198 host()->SendReply(reply_context,
199 PpapiPluginMsg_VideoDecoder_GetShmReply(shm_size));
200
201 return PP_OK_COMPLETIONPENDING;
202 }
203
204 int32_t PepperVideoDecoderHost::OnHostMsgDecode(
205 ppapi::host::HostMessageContext* context,
206 uint32_t shm_id,
207 uint32_t size,
208 int32_t decode_id) {
209 if (!initialized_)
210 return PP_ERROR_FAILED;
211 DCHECK(decoder_);
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 // Reject an attempt to pass a busy buffer to the decoder again.
216 if (shm_buffer_busy_[shm_id])
217 return PP_ERROR_FAILED;
218 // Reject non-unique decode_id values.
219 if (pending_decodes_.find(decode_id) != pending_decodes_.end())
220 return PP_ERROR_FAILED;
221
222 if (flush_reply_context_.is_valid() || reset_reply_context_.is_valid())
223 return PP_ERROR_FAILED;
224
225 pending_decodes_.insert(std::make_pair(
226 decode_id, PendingDecode(shm_id, context->MakeReplyMessageContext())));
227
228 shm_buffer_busy_[shm_id] = true;
229 decoder_->Decode(
230 media::BitstreamBuffer(decode_id, shm_buffers_[shm_id]->handle(), size));
231
232 return PP_OK_COMPLETIONPENDING;
233 }
234
235 int32_t PepperVideoDecoderHost::OnHostMsgAssignTextures(
236 ppapi::host::HostMessageContext* context,
237 const PP_Size& size,
238 const std::vector<uint32_t>& texture_ids) {
239 if (!initialized_)
240 return PP_ERROR_FAILED;
241 DCHECK(decoder_);
242
243 std::vector<media::PictureBuffer> picture_buffers;
244 for (uint32 i = 0; i < texture_ids.size(); i++) {
245 media::PictureBuffer buffer(
246 texture_ids[i], // Use the texture_id to identify the buffer.
247 gfx::Size(size.width, size.height),
248 texture_ids[i]);
249 picture_buffers.push_back(buffer);
250 }
251 decoder_->AssignPictureBuffers(picture_buffers);
252 return PP_OK;
253 }
254
255 int32_t PepperVideoDecoderHost::OnHostMsgRecyclePicture(
256 ppapi::host::HostMessageContext* context,
257 uint32_t texture_id) {
258 if (!initialized_)
259 return PP_ERROR_FAILED;
260 DCHECK(decoder_);
261 if (reset_reply_context_.is_valid())
262 return PP_ERROR_FAILED;
263
264 decoder_->ReusePictureBuffer(texture_id);
265
266 return PP_OK;
267 }
268
269 int32_t PepperVideoDecoderHost::OnHostMsgFlush(
270 ppapi::host::HostMessageContext* context) {
271 if (!initialized_)
272 return PP_ERROR_FAILED;
273 DCHECK(decoder_);
274 if (flush_reply_context_.is_valid() || reset_reply_context_.is_valid())
275 return PP_ERROR_FAILED;
276
277 flush_reply_context_ = context->MakeReplyMessageContext();
278 decoder_->Flush();
279
280 return PP_OK_COMPLETIONPENDING;
281 }
282
283 int32_t PepperVideoDecoderHost::OnHostMsgReset(
284 ppapi::host::HostMessageContext* context) {
285 if (!initialized_)
286 return PP_ERROR_FAILED;
287 DCHECK(decoder_);
288 if (flush_reply_context_.is_valid() || reset_reply_context_.is_valid())
289 return PP_ERROR_FAILED;
290
291 reset_reply_context_ = context->MakeReplyMessageContext();
292 decoder_->Reset();
293
294 return PP_OK_COMPLETIONPENDING;
295 }
296
297 void PepperVideoDecoderHost::ProvidePictureBuffers(
298 uint32 requested_num_of_buffers,
299 const gfx::Size& dimensions,
300 uint32 texture_target) {
301 DCHECK(RenderThreadImpl::current());
302 host()->SendUnsolicitedReply(
303 pp_resource(),
304 PpapiPluginMsg_VideoDecoder_RequestTextures(
305 requested_num_of_buffers,
306 PP_MakeSize(dimensions.width(), dimensions.height()),
307 texture_target));
308 }
309
310 void PepperVideoDecoderHost::PictureReady(const media::Picture& picture) {
311 DCHECK(RenderThreadImpl::current());
312 host()->SendUnsolicitedReply(
313 pp_resource(),
314 PpapiPluginMsg_VideoDecoder_PictureReady(picture.bitstream_buffer_id(),
315 picture.picture_buffer_id()));
316 }
317
318 void PepperVideoDecoderHost::DismissPictureBuffer(int32 picture_buffer_id) {
319 DCHECK(RenderThreadImpl::current());
320 host()->SendUnsolicitedReply(
321 pp_resource(),
322 PpapiPluginMsg_VideoDecoder_DismissPicture(picture_buffer_id));
323 }
324
325 void PepperVideoDecoderHost::NotifyError(
326 media::VideoDecodeAccelerator::Error error) {
327 DCHECK(RenderThreadImpl::current());
328 int32_t pp_error = PP_ERROR_FAILED;
329 switch (error) {
330 case media::VideoDecodeAccelerator::UNREADABLE_INPUT:
331 pp_error = PP_ERROR_MALFORMED_INPUT;
332 break;
333 case media::VideoDecodeAccelerator::ILLEGAL_STATE:
334 case media::VideoDecodeAccelerator::INVALID_ARGUMENT:
335 case media::VideoDecodeAccelerator::PLATFORM_FAILURE:
336 case media::VideoDecodeAccelerator::LARGEST_ERROR_ENUM:
337 pp_error = PP_ERROR_RESOURCE_FAILED;
338 break;
339 // No default case, to catch unhandled enum values.
340 }
341 host()->SendUnsolicitedReply(
342 pp_resource(), PpapiPluginMsg_VideoDecoder_NotifyError(pp_error));
343 }
344
345 void PepperVideoDecoderHost::NotifyResetDone() {
346 DCHECK(RenderThreadImpl::current());
347 host()->SendReply(reset_reply_context_,
348 PpapiPluginMsg_VideoDecoder_ResetReply());
349 reset_reply_context_ = ppapi::host::ReplyMessageContext();
350 }
351
352 void PepperVideoDecoderHost::NotifyEndOfBitstreamBuffer(
353 int32 bitstream_buffer_id) {
354 DCHECK(RenderThreadImpl::current());
355 PendingDecodeMap::iterator it = pending_decodes_.find(bitstream_buffer_id);
356 if (it == pending_decodes_.end()) {
357 NOTREACHED();
358 return;
359 }
360 const PendingDecode& pending_decode = it->second;
361 host()->SendReply(
362 pending_decode.reply_context,
363 PpapiPluginMsg_VideoDecoder_DecodeReply(pending_decode.shm_id));
364 shm_buffer_busy_[pending_decode.shm_id] = false;
365 pending_decodes_.erase(it);
366 }
367
368 void PepperVideoDecoderHost::NotifyFlushDone() {
369 DCHECK(RenderThreadImpl::current());
370 host()->SendReply(flush_reply_context_,
371 PpapiPluginMsg_VideoDecoder_FlushReply());
372 flush_reply_context_ = ppapi::host::ReplyMessageContext();
373 }
374
375 } // namespace content
OLDNEW
« no previous file with comments | « content/renderer/pepper/pepper_video_decoder_host.h ('k') | content/renderer/pepper/plugin_module.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698