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

Side by Side Diff: ppapi/proxy/video_decoder_resource.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) 2012 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 "ppapi/proxy/video_decoder_resource.h"
6
7 #include "base/bind.h"
8 #include "gpu/command_buffer/client/gles2_cmd_helper.h"
9 #include "gpu/command_buffer/client/gles2_implementation.h"
10 #include "ipc/ipc_message.h"
11 #include "ppapi/c/pp_errors.h"
12 #include "ppapi/c/ppb_opengles2.h"
13 #include "ppapi/proxy/plugin_dispatcher.h"
14 #include "ppapi/proxy/ppapi_messages.h"
15 #include "ppapi/proxy/ppb_graphics_3d_proxy.h"
16 #include "ppapi/shared_impl/ppapi_globals.h"
17 #include "ppapi/shared_impl/ppb_graphics_3d_shared.h"
18 #include "ppapi/shared_impl/proxy_lock.h"
19 #include "ppapi/shared_impl/resource_tracker.h"
20 #include "ppapi/shared_impl/scoped_pp_resource.h"
21 #include "ppapi/thunk/enter.h"
22
23 using ppapi::thunk::EnterResourceNoLock;
24 using ppapi::thunk::PPB_Graphics3D_API;
25 using ppapi::thunk::PPB_VideoDecoder_API;
26
27 namespace {
28
29 // Maximum number of concurrent decodes which can be pending.
30 const uint32_t kMaximumPendingDecodes = 8;
31
32 // Minimum size of shared-memory buffers we allocate. Make them large since
33 // we try to reuse them.
34 const uint32_t kMinimumBitstreamBufferSize = 100 << 10;
35
36 } // namespace
37
38 namespace ppapi {
39 namespace proxy {
40
41 VideoDecoderResource::ShmBuffer::ShmBuffer(base::SharedMemory* shm,
42 uint32_t size,
43 uint32_t shm_id)
44 : shm_(shm), size_(size), addr_(NULL), shm_id_(shm_id) {
45 if (shm_->Map(size_))
46 addr_ = shm_->memory();
47 DCHECK(addr_);
48 }
49
50 VideoDecoderResource::ShmBuffer::~ShmBuffer() {
51 }
52
53 VideoDecoderResource::Texture::Texture(uint32_t texture_target,
54 const PP_Size& size)
55 : texture_target_(texture_target), size_(size) {
56 }
57
58 VideoDecoderResource::Texture::~Texture() {
59 }
60
61 VideoDecoderResource::Picture::Picture(int32_t decode_id, uint32_t texture_id)
62 : decode_id_(decode_id), texture_id_(texture_id) {
63 }
64
65 VideoDecoderResource::Picture::~Picture() {
66 }
67
68 VideoDecoderResource::VideoDecoderResource(Connection connection,
69 PP_Instance instance)
70 : PluginResource(connection, instance),
71 decode_id_(0),
72 decode_size_(0),
73 decode_buffer_(NULL),
74 pending_decode_count_(0),
75 get_shm_buffer_pending_(false),
76 get_picture_(NULL),
77 gles2_impl_(NULL),
78 initialized_(false),
79 testing_(false),
80 // Set |decoder_last_error_| to PP_OK after successful initialization.
81 // This makes error checking a little more concise, since we can check
82 // that the decoder has been initialized and hasn't returned an error by
83 // just testing |decoder_last_error_|.
84 decoder_last_error_(PP_ERROR_FAILED) {
85 SendCreate(RENDERER, PpapiHostMsg_VideoDecoder_Create());
86 }
87
88 VideoDecoderResource::~VideoDecoderResource() {
89 // Destroy any textures which haven't been dismissed.
90 TextureMap::iterator it = textures_.begin();
91 for (; it != textures_.end(); ++it)
92 DeleteGLTexture(it->first);
93 }
94
95 PPB_VideoDecoder_API* VideoDecoderResource::AsPPB_VideoDecoder_API() {
96 return this;
97 }
98
99 int32_t VideoDecoderResource::Initialize(
100 PP_Resource graphics_context,
101 PP_VideoProfile profile,
102 PP_Bool allow_software_fallback,
103 scoped_refptr<TrackedCallback> callback) {
104 if (initialized_)
105 return PP_ERROR_FAILED;
106 if (profile < 0 || profile > PP_VIDEOPROFILE_MAX)
107 return PP_ERROR_BADARGUMENT;
108 if (initialize_callback_)
109 return PP_ERROR_INPROGRESS;
110 if (!graphics_context)
111 return PP_ERROR_BADRESOURCE;
112
113 // Create a new Graphics3D resource that can create texture resources to share
114 // with the plugin. We can't use the plugin's Graphics3D, since we create
115 // textures on a proxy thread, which would interfere with the plugin.
116 thunk::EnterResourceCreationNoLock enter_create(pp_instance());
117 if (enter_create.failed())
118 return PP_ERROR_FAILED;
119 int32_t attrib_list[] = {PP_GRAPHICS3DATTRIB_NONE};
120 HostResource host_resource;
121 if (!testing_) {
122 ScopedPPResource graphics3d(
123 ScopedPPResource::PassRef(),
124 enter_create.functions()->CreateGraphics3D(
125 pp_instance(), graphics_context, attrib_list));
126 EnterResourceNoLock<PPB_Graphics3D_API> enter_graphics(graphics3d.get(),
127 true);
128 if (enter_graphics.failed())
129 return PP_ERROR_BADRESOURCE;
130
131 graphics3d_ = static_cast<PPB_Graphics3D_Shared*>(enter_graphics.object());
132 gles2_impl_ = graphics3d_->gles2_impl();
133 host_resource = graphics3d_->host_resource();
134 graphics3d.Release();
yzshen1 2014/05/14 18:08:23 Is this leak intentional?
bbudge 2014/05/14 19:35:04 Won't graphics3d_ (scoped_refptr) hold onto it?
yzshen1 2014/05/14 22:58:16 - When assigning a value to scoped_refptr, it adds
135 }
136
137 initialize_callback_ = callback;
138
139 Call<PpapiPluginMsg_VideoDecoder_InitializeReply>(
140 RENDERER,
141 PpapiHostMsg_VideoDecoder_Initialize(
142 host_resource, profile, PP_ToBool(allow_software_fallback)),
143 base::Bind(&VideoDecoderResource::OnPluginMsgInitializeComplete, this));
144
145 return PP_OK_COMPLETIONPENDING;
146 }
147
148 int32_t VideoDecoderResource::Decode(uint32_t decode_id,
149 uint32_t size,
150 const void* buffer,
151 scoped_refptr<TrackedCallback> callback) {
152 if (decoder_last_error_)
153 return decoder_last_error_;
154 if (flush_callback_ || reset_callback_)
155 return PP_ERROR_FAILED;
156 if (decode_callback_)
157 return PP_ERROR_INPROGRESS;
158
159 return TryDecode(decode_id, size, buffer, callback);
160 }
161
162 int32_t VideoDecoderResource::GetPicture(
163 PP_VideoPicture* picture,
164 scoped_refptr<TrackedCallback> callback) {
165 if (decoder_last_error_)
166 return decoder_last_error_;
167 if (reset_callback_)
168 return PP_ERROR_FAILED;
169 if (get_picture_callback_)
170 return PP_ERROR_INPROGRESS;
171
172 // If the next picture is ready, return it synchronously.
173 if (!received_pictures_.empty()) {
174 WriteNextPicture(picture);
175 return PP_OK;
176 }
177
178 get_picture_callback_ = callback;
179 get_picture_ = picture;
180 return PP_OK_COMPLETIONPENDING;
181 }
182
183 void VideoDecoderResource::RecyclePicture(const PP_VideoPicture* picture) {
184 if (decoder_last_error_)
185 return;
186 if (reset_callback_)
187 return;
188
189 Post(RENDERER, PpapiHostMsg_VideoDecoder_RecyclePicture(picture->texture_id));
190 }
191
192 int32_t VideoDecoderResource::Flush(scoped_refptr<TrackedCallback> callback) {
193 if (decoder_last_error_)
194 return decoder_last_error_;
195 if (reset_callback_)
196 return PP_ERROR_FAILED;
197 if (flush_callback_)
198 return PP_ERROR_INPROGRESS;
199 flush_callback_ = callback;
200
201 Call<PpapiPluginMsg_VideoDecoder_FlushReply>(
202 RENDERER,
203 PpapiHostMsg_VideoDecoder_Flush(),
204 base::Bind(&VideoDecoderResource::OnPluginMsgFlushComplete, this));
205
206 return PP_OK_COMPLETIONPENDING;
207 }
208
209 int32_t VideoDecoderResource::Reset(scoped_refptr<TrackedCallback> callback) {
210 if (decoder_last_error_)
211 return decoder_last_error_;
212 if (flush_callback_)
213 return PP_ERROR_FAILED;
214 if (reset_callback_)
215 return PP_ERROR_INPROGRESS;
216 reset_callback_ = callback;
217
218 // Cause any pending Decode or GetPicture callbacks to abort immediately.
219 // Reentrancy isn't a problem, since all calls fail until Reset completes.
220 if (TrackedCallback::IsPending(decode_callback_))
221 decode_callback_->Abort();
222 decode_callback_ = NULL;
223 if (TrackedCallback::IsPending(get_picture_callback_))
224 get_picture_callback_->Abort();
225 get_picture_callback_ = NULL;
226 Call<PpapiPluginMsg_VideoDecoder_ResetReply>(
227 RENDERER,
228 PpapiHostMsg_VideoDecoder_Reset(),
229 base::Bind(&VideoDecoderResource::OnPluginMsgResetComplete, this));
230
231 return PP_OK_COMPLETIONPENDING;
232 }
233
234 void VideoDecoderResource::OnReplyReceived(
235 const ResourceMessageReplyParams& params,
236 const IPC::Message& msg) {
237 PPAPI_BEGIN_MESSAGE_MAP(VideoDecoderResource, msg)
238 PPAPI_DISPATCH_PLUGIN_RESOURCE_CALL(
239 PpapiPluginMsg_VideoDecoder_RequestTextures, OnPluginMsgRequestTextures)
240 PPAPI_DISPATCH_PLUGIN_RESOURCE_CALL(
241 PpapiPluginMsg_VideoDecoder_PictureReady, OnPluginMsgPictureReady)
242 PPAPI_DISPATCH_PLUGIN_RESOURCE_CALL(
243 PpapiPluginMsg_VideoDecoder_DismissPicture, OnPluginMsgDismissPicture)
244 PPAPI_DISPATCH_PLUGIN_RESOURCE_CALL(
245 PpapiPluginMsg_VideoDecoder_NotifyError, OnPluginMsgNotifyError)
246 PPAPI_DISPATCH_PLUGIN_RESOURCE_CALL_UNHANDLED(
247 PluginResource::OnReplyReceived(params, msg))
248 PPAPI_END_MESSAGE_MAP()
249 }
250
251 void VideoDecoderResource::SetForTest() {
252 testing_ = true;
253 }
254
255 void VideoDecoderResource::OnPluginMsgRequestTextures(
256 const ResourceMessageReplyParams& params,
257 uint32_t num_textures,
258 PP_Size size,
259 uint32_t texture_target) {
260 DCHECK(num_textures);
261 std::vector<uint32_t> texture_ids(num_textures);
262 if (gles2_impl_) {
263 gles2_impl_->GenTextures(num_textures, &texture_ids.front());
264 for (uint32_t i = 0; i < num_textures; ++i) {
265 gles2_impl_->ActiveTexture(GL_TEXTURE0);
266 gles2_impl_->BindTexture(texture_target, texture_ids[i]);
267 gles2_impl_->TexParameteri(
268 texture_target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
269 gles2_impl_->TexParameteri(
270 texture_target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
271 gles2_impl_->TexParameterf(
272 texture_target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
273 gles2_impl_->TexParameterf(
274 texture_target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
275
276 if (texture_target == GL_TEXTURE_2D) {
277 gles2_impl_->TexImage2D(texture_target,
278 0,
279 GL_RGBA,
280 size.width,
281 size.height,
282 0,
283 GL_RGBA,
284 GL_UNSIGNED_BYTE,
285 NULL);
286 }
287
288 textures_.insert(
289 std::make_pair(texture_ids[i], Texture(texture_target, size)));
290 }
291 gles2_impl_->Flush();
292 } else if (testing_) {
293 // Create some fake texture ids so we can test picture handling.
294 for (uint32_t i = 0; i < num_textures; ++i) {
295 texture_ids[i] = i + 1;
296 textures_.insert(
297 std::make_pair(texture_ids[i], Texture(texture_target, size)));
298 }
299 }
300
301 Post(RENDERER, PpapiHostMsg_VideoDecoder_AssignTextures(size, texture_ids));
302 }
303
304 void VideoDecoderResource::OnPluginMsgPictureReady(
305 const ResourceMessageReplyParams& params,
306 uint32_t decode_id,
307 uint32_t texture_id) {
308 received_pictures_.push(Picture(decode_id, texture_id));
309 // Prepare to accept another call to GetPicture in the callback.
310 scoped_refptr<TrackedCallback> callback;
311 callback.swap(get_picture_callback_);
312 PP_VideoPicture* picture = get_picture_;
313 get_picture_ = NULL;
314 if (TrackedCallback::IsPending(callback)) {
315 WriteNextPicture(picture);
316 callback->Run(PP_OK);
317 }
318 }
319
320 void VideoDecoderResource::OnPluginMsgDismissPicture(
321 const ResourceMessageReplyParams& params,
322 uint32_t texture_id) {
323 DeleteGLTexture(texture_id);
324 textures_.erase(texture_id);
325 }
326
327 void VideoDecoderResource::OnPluginMsgNotifyError(
328 const ResourceMessageReplyParams& params,
329 int32_t error) {
330 decoder_last_error_ = error;
331 // Cause any pending Decode or GetPicture callbacks to run immediately.
332 // Reentrancy isn't a problem, since the resource is unusable now.
333 if (TrackedCallback::IsPending(decode_callback_))
334 decode_callback_->Run(decoder_last_error_);
335 decode_callback_ = NULL;
336 if (TrackedCallback::IsPending(get_picture_callback_))
337 get_picture_callback_->Run(decoder_last_error_);
338 get_picture_callback_ = NULL;
339 }
340
341 void VideoDecoderResource::OnPluginMsgInitializeComplete(
342 const ResourceMessageReplyParams& params) {
343 decoder_last_error_ = params.result();
344 if (decoder_last_error_ == PP_OK)
345 initialized_ = true;
346
347 // Let the plugin call Initialize again from its callback in case of failure.
348 scoped_refptr<TrackedCallback> callback;
349 callback.swap(initialize_callback_);
350 callback->Run(decoder_last_error_);
351 }
352
353 void VideoDecoderResource::OnPluginMsgGetShmComplete(
354 const ResourceMessageReplyParams& params,
355 uint32_t size) {
356 get_shm_buffer_pending_ = false;
357 int32_t result = params.result();
358 if (result == PP_OK) {
359 base::SharedMemoryHandle shm_handle = base::SharedMemory::NULLHandle();
360 if (!params.TakeSharedMemoryHandleAtIndex(0, &shm_handle)) {
361 RunDecodeCallback(PP_ERROR_FAILED);
362 return;
363 }
364 uint32_t shm_id = static_cast<uint32_t>(shm_buffers_.size());
365 ShmBuffer* shm_buffer =
366 new ShmBuffer(new base::SharedMemory(shm_handle, false /* read_only */),
367 size,
368 shm_id);
369 shm_buffers_.push_back(shm_buffer);
370 SendDecodeMessage(shm_id);
371 RunDecodeCallback(PP_OK);
372 }
373 }
374
375 void VideoDecoderResource::OnPluginMsgDecodeComplete(
376 const ResourceMessageReplyParams& params,
377 uint32_t shm_id) {
378 pending_decode_count_--;
379 available_shm_buffers_.push_back(shm_buffers_[shm_id]);
380 // If a Decode is pending, and we're not waiting for a shm buffer, attempt
381 // the Decode again.
382 if (decode_callback_ && !get_shm_buffer_pending_) {
383 int32_t result =
384 TryDecode(decode_id_, decode_size_, decode_buffer_, decode_callback_);
385 if (result == PP_OK)
386 RunDecodeCallback(PP_OK);
387 }
388 }
389
390 void VideoDecoderResource::OnPluginMsgFlushComplete(
391 const ResourceMessageReplyParams& params) {
392 if (get_picture_callback_) {
393 scoped_refptr<TrackedCallback> callback;
394 callback.swap(get_picture_callback_);
395 callback->Abort();
396 }
397
398 scoped_refptr<TrackedCallback> callback;
399 callback.swap(flush_callback_);
400 callback->Run(params.result());
401 }
402
403 void VideoDecoderResource::OnPluginMsgResetComplete(
404 const ResourceMessageReplyParams& params) {
405 scoped_refptr<TrackedCallback> callback;
406 callback.swap(reset_callback_);
407 callback->Run(params.result());
408 }
409
410 int32_t VideoDecoderResource::TryDecode(
411 uint32_t decode_id,
412 uint32_t size,
413 const void* buffer,
414 scoped_refptr<TrackedCallback> callback) {
415 decode_id_ = decode_id;
416 decode_size_ = size;
417 decode_buffer_ = buffer;
418 if (available_shm_buffers_.empty() ||
419 available_shm_buffers_.back()->size_ < size) {
420 decode_callback_ = callback;
421
422 if (pending_decode_count_ < kMaximumPendingDecodes) {
423 get_shm_buffer_pending_ = true;
424 uint32_t alloc_size = std::max(size, kMinimumBitstreamBufferSize);
425 Call<PpapiPluginMsg_VideoDecoder_GetShmReply>(
426 RENDERER,
427 PpapiHostMsg_VideoDecoder_GetShm(alloc_size),
428 base::Bind(&VideoDecoderResource::OnPluginMsgGetShmComplete, this));
429 }
430
431 return PP_OK_COMPLETIONPENDING;
432 }
433
434 ShmBuffer* shm_buffer = available_shm_buffers_.back();
435 available_shm_buffers_.pop_back();
436 SendDecodeMessage(shm_buffer->shm_id_);
437 return PP_OK;
438 }
439
440 void VideoDecoderResource::SendDecodeMessage(uint32_t shm_id) {
441 ShmBuffer* shm_buffer = shm_buffers_[shm_id];
442 memcpy(shm_buffer->addr_, decode_buffer_, decode_size_);
443 pending_decode_count_++;
444
445 Call<PpapiPluginMsg_VideoDecoder_DecodeReply>(
446 RENDERER,
447 PpapiHostMsg_VideoDecoder_Decode(shm_id, decode_id_, decode_size_),
448 base::Bind(&VideoDecoderResource::OnPluginMsgDecodeComplete, this));
449 }
450
451 void VideoDecoderResource::RunDecodeCallback(int32_t result) {
452 scoped_refptr<TrackedCallback> callback;
453 callback.swap(decode_callback_);
454 callback->Run(result);
455 }
456
457 void VideoDecoderResource::DeleteGLTexture(uint32_t id) {
458 if (gles2_impl_) {
459 gles2_impl_->DeleteTextures(1, &id);
460 gles2_impl_->Flush();
461 }
462 }
463
464 void VideoDecoderResource::WriteNextPicture(PP_VideoPicture* pp_picture) {
465 DCHECK(!received_pictures_.empty());
466 Picture& picture = received_pictures_.front();
467 uint32_t texture_id = picture.texture_id_;
468 TextureMap::iterator it = textures_.find(texture_id);
469 DCHECK(it != textures_.end());
470 pp_picture->decode_id = picture.decode_id_;
471 pp_picture->texture_id = texture_id;
472 pp_picture->texture_target = it->second.texture_target_;
473 pp_picture->texture_size = it->second.size_;
474 received_pictures_.pop();
475 }
476
477 } // namespace proxy
478 } // namespace ppapi
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698