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

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: Fix compile (missing return in new fn). 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
« no previous file with comments | « ppapi/proxy/video_decoder_resource.h ('k') | ppapi/proxy/video_decoder_resource_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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_,
yzshen1 2014/05/14 22:58:16 I think '_' suffix has quite specific meaning in o
bbudge 2014/05/15 00:24:54 That's a good convention. Done.
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();
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(
yzshen1 2014/05/14 22:58:16 I think it is good to add indent in this case.
bbudge 2014/05/15 00:24:54 You're the second reviewer to point this out so I'
239 PpapiPluginMsg_VideoDecoder_RequestTextures, OnPluginMsgRequestTextures)
240 PPAPI_DISPATCH_PLUGIN_RESOURCE_CALL(PpapiPluginMsg_VideoDecoder_PictureReady,
241 OnPluginMsgPictureReady)
242 PPAPI_DISPATCH_PLUGIN_RESOURCE_CALL(
243 PpapiPluginMsg_VideoDecoder_DismissPicture, OnPluginMsgDismissPicture)
244 PPAPI_DISPATCH_PLUGIN_RESOURCE_CALL(PpapiPluginMsg_VideoDecoder_NotifyError,
245 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 const 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 scoped_ptr<ShmBuffer> shm_buffer(
366 new ShmBuffer(new base::SharedMemory(shm_handle, false /* read_only */),
367 size,
368 shm_id));
369 if (!shm_buffer->addr) {
370 RunDecodeCallback(PP_ERROR_FAILED);
371 return;
372 }
373 shm_buffers_.push_back(shm_buffer.release());
374 SendDecodeMessage(shm_id);
375 RunDecodeCallback(PP_OK);
376 }
377 }
378
379 void VideoDecoderResource::OnPluginMsgDecodeComplete(
380 const ResourceMessageReplyParams& params,
381 uint32_t shm_id) {
382 pending_decode_count_--;
383 // Return the shm buffer to the available list.
384 if (shm_id < shm_buffers_.size())
385 available_shm_buffers_.push_back(shm_buffers_[shm_id]);
386 else
387 NOTREACHED();
388
389 // If a Decode is pending, and we're not waiting for a shm buffer, attempt
390 // the Decode again.
391 if (decode_callback_ && !get_shm_buffer_pending_) {
392 int32_t result =
393 TryDecode(decode_id_, decode_size_, decode_buffer_, decode_callback_);
394 if (result == PP_OK)
395 RunDecodeCallback(PP_OK);
396 }
397 }
398
399 void VideoDecoderResource::OnPluginMsgFlushComplete(
400 const ResourceMessageReplyParams& params) {
401 if (get_picture_callback_) {
402 scoped_refptr<TrackedCallback> callback;
403 callback.swap(get_picture_callback_);
404 callback->Abort();
405 }
406
407 scoped_refptr<TrackedCallback> callback;
408 callback.swap(flush_callback_);
409 callback->Run(params.result());
410 }
411
412 void VideoDecoderResource::OnPluginMsgResetComplete(
413 const ResourceMessageReplyParams& params) {
414 scoped_refptr<TrackedCallback> callback;
415 callback.swap(reset_callback_);
416 callback->Run(params.result());
417 }
418
419 int32_t VideoDecoderResource::TryDecode(
420 uint32_t decode_id,
421 uint32_t size,
422 const void* buffer,
423 scoped_refptr<TrackedCallback> callback) {
424 decode_id_ = decode_id;
425 decode_size_ = size;
426 decode_buffer_ = buffer;
427 if (available_shm_buffers_.empty() ||
428 available_shm_buffers_.back()->size < size) {
429 decode_callback_ = callback;
430
431 if (pending_decode_count_ < kMaximumPendingDecodes) {
432 get_shm_buffer_pending_ = true;
433 uint32_t alloc_size = std::max(size, kMinimumBitstreamBufferSize);
434 Call<PpapiPluginMsg_VideoDecoder_GetShmReply>(
435 RENDERER,
436 PpapiHostMsg_VideoDecoder_GetShm(alloc_size),
437 base::Bind(&VideoDecoderResource::OnPluginMsgGetShmComplete, this));
438 }
439
440 return PP_OK_COMPLETIONPENDING;
441 }
442
443 ShmBuffer* shm_buffer = available_shm_buffers_.back();
444 available_shm_buffers_.pop_back();
445 SendDecodeMessage(shm_buffer->shm_id);
446 return PP_OK;
447 }
448
449 void VideoDecoderResource::SendDecodeMessage(uint32_t shm_id) {
450 DCHECK(shm_id < shm_buffers_.size());
451 ShmBuffer* shm_buffer = shm_buffers_[shm_id];
452 memcpy(shm_buffer->addr, decode_buffer_, decode_size_);
453 pending_decode_count_++;
454
455 Call<PpapiPluginMsg_VideoDecoder_DecodeReply>(
456 RENDERER,
457 PpapiHostMsg_VideoDecoder_Decode(shm_id, decode_id_, decode_size_),
458 base::Bind(&VideoDecoderResource::OnPluginMsgDecodeComplete, this));
459 }
460
461 void VideoDecoderResource::RunDecodeCallback(int32_t result) {
462 scoped_refptr<TrackedCallback> callback;
463 callback.swap(decode_callback_);
464 callback->Run(result);
465 }
466
467 void VideoDecoderResource::DeleteGLTexture(uint32_t id) {
468 if (gles2_impl_) {
469 gles2_impl_->DeleteTextures(1, &id);
470 gles2_impl_->Flush();
471 }
472 }
473
474 void VideoDecoderResource::WriteNextPicture(PP_VideoPicture* pp_picture) {
475 DCHECK(!received_pictures_.empty());
476 Picture& picture = received_pictures_.front();
477 uint32_t texture_id = picture.texture_id;
478 TextureMap::iterator it = textures_.find(texture_id);
479 DCHECK(it != textures_.end());
480 pp_picture->decode_id = picture.decode_id;
481 pp_picture->texture_id = texture_id;
482 pp_picture->texture_target = it->second.texture_target;
483 pp_picture->texture_size = it->second.size;
484 received_pictures_.pop();
485 }
486
487 } // namespace proxy
488 } // namespace ppapi
OLDNEW
« no previous file with comments | « ppapi/proxy/video_decoder_resource.h ('k') | ppapi/proxy/video_decoder_resource_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698