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

Side by Side Diff: content/renderer/pepper/pepper_video_decoder_host.cc

Issue 311853005: Implement software fallback for PPB_VideoDecoder. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: 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
1 // Copyright (c) 2014 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include <GLES2/gl2.h>
6 #include <GLES2/gl2ext.h>
7 #include <GLES2/gl2extchromium.h>
8
5 #include "content/renderer/pepper/pepper_video_decoder_host.h" 9 #include "content/renderer/pepper/pepper_video_decoder_host.h"
6 10
7 #include "base/bind.h" 11 #include "base/bind.h"
8 #include "base/memory/shared_memory.h" 12 #include "base/memory/shared_memory.h"
9 #include "content/common/gpu/client/gpu_channel_host.h" 13 #include "content/common/gpu/client/gpu_channel_host.h"
10 #include "content/public/renderer/render_thread.h" 14 #include "content/public/renderer/render_thread.h"
11 #include "content/public/renderer/renderer_ppapi_host.h" 15 #include "content/public/renderer/renderer_ppapi_host.h"
12 #include "content/renderer/pepper/ppb_graphics_3d_impl.h" 16 #include "content/renderer/pepper/ppb_graphics_3d_impl.h"
13 #include "content/renderer/render_thread_impl.h" 17 #include "content/renderer/render_thread_impl.h"
14 #include "content/renderer/render_view_impl.h" 18 #include "content/renderer/render_view_impl.h"
19 #include "gpu/command_buffer/client/gles2_implementation.h"
20 #include "media/base/decoder_buffer.h"
21 #include "media/filters/ffmpeg_video_decoder.h"
15 #include "media/video/picture.h" 22 #include "media/video/picture.h"
16 #include "media/video/video_decode_accelerator.h" 23 #include "media/video/video_decode_accelerator.h"
17 #include "ppapi/c/pp_completion_callback.h" 24 #include "ppapi/c/pp_completion_callback.h"
18 #include "ppapi/c/pp_errors.h" 25 #include "ppapi/c/pp_errors.h"
19 #include "ppapi/host/dispatch_host_message.h" 26 #include "ppapi/host/dispatch_host_message.h"
20 #include "ppapi/host/ppapi_host.h" 27 #include "ppapi/host/ppapi_host.h"
21 #include "ppapi/proxy/ppapi_messages.h" 28 #include "ppapi/proxy/ppapi_messages.h"
22 #include "ppapi/proxy/video_decoder_constants.h" 29 #include "ppapi/proxy/video_decoder_constants.h"
23 #include "ppapi/thunk/enter.h" 30 #include "ppapi/thunk/enter.h"
24 #include "ppapi/thunk/ppb_graphics_3d_api.h" 31 #include "ppapi/thunk/ppb_graphics_3d_api.h"
32 #include "third_party/libyuv/include/libyuv.h"
33 #include "webkit/common/gpu/context_provider_web_context.h"
25 34
26 using ppapi::proxy::SerializedHandle; 35 using ppapi::proxy::SerializedHandle;
27 using ppapi::thunk::EnterResourceNoLock; 36 using ppapi::thunk::EnterResourceNoLock;
28 using ppapi::thunk::PPB_Graphics3D_API; 37 using ppapi::thunk::PPB_Graphics3D_API;
29 38
30 namespace content { 39 namespace content {
31 40
32 namespace { 41 namespace {
33 42
34 media::VideoCodecProfile PepperToMediaVideoProfile(PP_VideoProfile profile) { 43 media::VideoCodecProfile PepperToMediaVideoProfile(PP_VideoProfile profile) {
(...skipping 23 matching lines...) Expand all
58 case PP_VIDEOPROFILE_VP8MAIN: 67 case PP_VIDEOPROFILE_VP8MAIN:
59 return media::VP8PROFILE_MAIN; 68 return media::VP8PROFILE_MAIN;
60 // No default case, to catch unhandled PP_VideoProfile values. 69 // No default case, to catch unhandled PP_VideoProfile values.
61 } 70 }
62 71
63 return media::VIDEO_CODEC_PROFILE_UNKNOWN; 72 return media::VIDEO_CODEC_PROFILE_UNKNOWN;
64 } 73 }
65 74
66 } // namespace 75 } // namespace
67 76
77 // This wrapper class calls methods on a media::VideoDecoder on the media thread
78 // and relays results back to the host on the main thread. It should be created,
79 // used, and destroyed on the main (render) thread.
80 class SoftwareDecoder {
81 public:
82 explicit SoftwareDecoder(PepperVideoDecoderHost* host);
83
84 void Initialize(media::VideoCodecProfile profile);
85 void Decode(uint32_t decode_id,
86 const scoped_refptr<media::DecoderBuffer>& buffer);
87 void AssignTextures(const std::vector<uint32_t>& texture_ids);
88 void RecycleTexture(uint32_t texture_id);
89 void Flush();
90 void Reset();
91 void Destroy();
92
93 protected:
94 // Do not delete directly; use Destroy() or own it with a scoped_ptr, which
95 // will Destroy() it properly by default.
96 ~SoftwareDecoder();
97
98 private:
99 struct PendingDecode {
100 PendingDecode(uint32_t decode_id,
101 const scoped_refptr<media::DecoderBuffer>& buffer);
102 ~PendingDecode();
103
104 uint32_t decode_id;
105 scoped_refptr<media::DecoderBuffer> buffer;
106 };
107
108 struct PendingFrame {
109 PendingFrame(uint32_t decode_id, const gfx::Size& size);
110 ~PendingFrame();
111
112 uint32_t decode_id;
113 gfx::Size size;
114 std::vector<uint8_t> pixels;
115 };
116
117 void InitializeOnMediaThread(media::VideoDecoderConfig config);
118 void PipelineStatusOnMediaThread(media::PipelineStatus status);
119 void PipelineStatusOnMainThread(media::PipelineStatus status);
120
121 void ReceiveBufferOnMediaThread(uint32_t decode_id,
122 scoped_refptr<media::DecoderBuffer> buffer);
123 void DecodeOnMediaThread();
124 void ConvertFrameOnMediaThread(uint32_t decode_id,
125 media::VideoDecoder::Status status,
126 const scoped_refptr<media::VideoFrame>& frame);
127 void ReceiveFrameOnMainThread(media::VideoDecoder::Status status,
128 scoped_ptr<PendingFrame> frame);
129 void SendPicturesOnMainThread();
130
131 void DoResetOnMediaThread();
132 void ResetCompleteOnMediaThread();
133 void ResetCompleteOnMainThread();
134
135 void DestroyOnMediaThread();
136 void DestroyOnMainThread();
137
138 void DismissTexture(uint32_t texture_id);
139 void DeleteTexture(uint32_t texture_id);
140 void FlushCommandBuffer();
141
142 // These members are accessed only on the main thread.
143
144 PepperVideoDecoderHost* host_;
145 scoped_refptr<base::MessageLoopProxy> media_message_loop_;
146 scoped_refptr<webkit::gpu::ContextProviderWebContext> context_provider_;
147 // The current decoded frame size.
148 gfx::Size texture_size_;
149 // Map that takes the plugin's GL texture id to the renderer's GL texture id.
150 typedef base::hash_map<uint32_t, uint32_t> TextureIdMap;
151 TextureIdMap texture_id_map_;
152 // Available textures (these are plugin ids.)
153 std::vector<uint32_t> available_textures_;
154 // Track textures that are no longer needed (these are plugin ids.)
155 typedef base::hash_set<uint32_t> TextureIdSet;
156 TextureIdSet textures_to_dismiss_;
157 // Mailboxes for pending texture requests, to write to plugin's textures.
158 std::vector<gpu::Mailbox> pending_texture_mailboxes_;
159 // Queue of pending decoded frames. These have been converted to RGB, and
160 // await upload to a GL texture.
161 typedef std::queue<PendingFrame*> PendingFrameQueue;
162 PendingFrameQueue pending_frames_;
163 uint32_t num_pending_decodes_;
164 bool flushing_;
165 bool resetting_;
dmichael (off chromium) 2014/06/03 22:27:47 suggestion: Might be clearer to use a 3-state enum
bbudge 2014/06/04 14:10:12 UNITIALIZED, DECODING, FLUSHING, RESETTING. Done.
166
167 // These members are accessed only on the media thread.
168
169 scoped_ptr<media::VideoDecoder> decoder_;
170 scoped_refptr<base::MessageLoopProxy> main_message_loop_;
171 // Queue of decodes waiting for the decoder.
172 typedef std::queue<PendingDecode> PendingDecodeQueue;
173 PendingDecodeQueue pending_decodes_;
dmichael (off chromium) 2014/06/03 22:27:47 This is a bit hard to follow with the mix of opera
bbudge 2014/06/04 14:10:12 I moved SoftwareDecoder to its own files (video_de
dmichael (off chromium) 2014/06/04 15:47:29 Do you mean you don't want to inherit SupportsWeak
bbudge 2014/06/04 20:52:46 Delegate now references VideoDecoderProxy (formerl
dmichael (off chromium) 2014/06/04 21:03:07 FYI, base::Callbacks have no restriction on the nu
174
175 DISALLOW_COPY_AND_ASSIGN(SoftwareDecoder);
176 };
177
178 SoftwareDecoder::PendingDecode::PendingDecode(
179 uint32_t decode_id,
180 const scoped_refptr<media::DecoderBuffer>& buffer)
181 : decode_id(decode_id), buffer(buffer) {
182 }
183
184 SoftwareDecoder::PendingDecode::~PendingDecode() {
185 }
186
187 SoftwareDecoder::PendingFrame::PendingFrame(uint32_t decode_id,
188 const gfx::Size& size)
189 : decode_id(decode_id),
190 size(size),
191 pixels(size.width() * size.height() * 4) {
192 }
193
194 SoftwareDecoder::PendingFrame::~PendingFrame() {
195 }
196
197 SoftwareDecoder::SoftwareDecoder(PepperVideoDecoderHost* host)
198 : host_(host),
199 media_message_loop_(
200 RenderThreadImpl::current()->GetMediaThreadMessageLoopProxy()),
201 context_provider_(
202 RenderThreadImpl::current()->SharedMainThreadContextProvider()),
203 num_pending_decodes_(0),
204 flushing_(false),
205 resetting_(false),
206 main_message_loop_(base::MessageLoopProxy::current()) {
207 DCHECK(host_);
208 DCHECK(main_message_loop_);
209 DCHECK(media_message_loop_);
210 DCHECK(context_provider_);
211 }
212
213 SoftwareDecoder::~SoftwareDecoder() {
214 DCHECK(RenderThreadImpl::current());
215 DCHECK(!host_);
216 // Delete any remaining video frames.
217 while (!pending_frames_.empty()) {
218 delete pending_frames_.front();
219 pending_frames_.pop();
220 }
221 // Delete any remaining textures.
222 TextureIdMap::iterator it = texture_id_map_.begin();
223 for (; it != texture_id_map_.end(); ++it)
224 DeleteTexture(it->second);
225
226 FlushCommandBuffer();
227 }
228
229 void SoftwareDecoder::Initialize(media::VideoCodecProfile profile) {
230 DCHECK(RenderThreadImpl::current());
231 DCHECK(!decoder_);
232 media::VideoCodec codec = media::kUnknownVideoCodec;
233 if (profile <= media::H264PROFILE_MAX)
234 codec = media::kCodecH264;
235 else if (profile <= media::VP8PROFILE_MAX)
236 codec = media::kCodecVP8;
237 DCHECK_NE(codec, media::kUnknownVideoCodec);
238
239 media::VideoDecoderConfig config(
240 codec,
241 profile,
242 media::VideoFrame::YV12,
243 gfx::Size(32, 24), // Small sizes that won't fail.
244 gfx::Rect(32, 24),
245 gfx::Size(32, 24),
246 NULL /* extra_data */,
247 0 /* extra_data_size */,
248 false /* decryption */);
249
250 decoder_.reset(new media::FFmpegVideoDecoder(media_message_loop_));
251
252 media_message_loop_->PostTask(
253 FROM_HERE,
254 base::Bind(&SoftwareDecoder::InitializeOnMediaThread,
255 base::Unretained(this),
256 config));
257 }
258
259 void SoftwareDecoder::Decode(
260 uint32_t decode_id,
261 const scoped_refptr<media::DecoderBuffer>& buffer) {
262 DCHECK(RenderThreadImpl::current());
263 DCHECK(decoder_);
264 DCHECK(!resetting_ && !flushing_);
265
266 num_pending_decodes_++;
267
268 media_message_loop_->PostTask(
269 FROM_HERE,
270 base::Bind(&SoftwareDecoder::ReceiveBufferOnMediaThread,
271 base::Unretained(this),
272 decode_id,
273 buffer));
274 }
275
276 void SoftwareDecoder::AssignTextures(const std::vector<uint32_t>& texture_ids) {
277 DCHECK(RenderThreadImpl::current());
278 DCHECK(decoder_);
279 DCHECK(texture_ids.size());
280 DCHECK_EQ(texture_ids.size(), pending_texture_mailboxes_.size());
281 uint32_t num_textures = static_cast<GLuint>(texture_ids.size());
282 std::vector<uint32_t> local_texture_ids(num_textures);
283 gpu::gles2::GLES2Interface* gles2 = context_provider_->ContextGL();
284 gles2->GenTextures(num_textures, &local_texture_ids.front());
285 for (uint32_t i = 0; i < num_textures; i++) {
286 gles2->ActiveTexture(GL_TEXTURE0);
287 gles2->BindTexture(GL_TEXTURE_2D, local_texture_ids[i]);
288 gles2->ConsumeTextureCHROMIUM(GL_TEXTURE_2D,
289 pending_texture_mailboxes_[i].name);
290 // Map the plugin texture id to the local texture id.
291 texture_id_map_.insert(
292 std::make_pair(texture_ids[i], local_texture_ids[i]));
293 }
294 pending_texture_mailboxes_.clear();
295 available_textures_.insert(
296 available_textures_.end(), texture_ids.begin(), texture_ids.end());
297 SendPicturesOnMainThread();
298 }
299
300 void SoftwareDecoder::RecycleTexture(uint32_t texture_id) {
301 DCHECK(RenderThreadImpl::current());
302 DCHECK(decoder_);
303 if (textures_to_dismiss_.find(texture_id) != textures_to_dismiss_.end()) {
304 DismissTexture(texture_id);
305 } else if (texture_id_map_.find(texture_id) != texture_id_map_.end()) {
306 available_textures_.push_back(texture_id);
307 SendPicturesOnMainThread();
308 } else {
309 NOTREACHED();
310 }
311 }
312
313 void SoftwareDecoder::Flush() {
314 DCHECK(RenderThreadImpl::current());
315 DCHECK(decoder_);
316 DCHECK(!resetting_ && !flushing_);
317 flushing_ = true;
318 }
319
320 void SoftwareDecoder::Reset() {
321 DCHECK(RenderThreadImpl::current());
322 DCHECK(decoder_);
323 DCHECK(!resetting_ && !flushing_);
324 resetting_ = true;
325 media_message_loop_->PostTask(
326 FROM_HERE,
327 base::Bind(&SoftwareDecoder::DoResetOnMediaThread,
328 base::Unretained(this)));
329 }
330
331 void SoftwareDecoder::Destroy() {
332 DCHECK(RenderThreadImpl::current());
333 DCHECK(decoder_);
334 DCHECK(host_);
335 host_ = NULL;
336 media_message_loop_->PostTask(
337 FROM_HERE,
338 base::Bind(&SoftwareDecoder::DestroyOnMediaThread,
339 base::Unretained(this)));
340 }
341
342 void SoftwareDecoder::InitializeOnMediaThread(
343 media::VideoDecoderConfig config) {
344 DCHECK(decoder_);
345 decoder_->Initialize(config,
346 true /* low_delay */,
347 base::Bind(&SoftwareDecoder::PipelineStatusOnMediaThread,
348 base::Unretained(this)));
349 }
350
351 void SoftwareDecoder::PipelineStatusOnMediaThread(
352 media::PipelineStatus status) {
353 if (!host_)
354 return;
355 main_message_loop_->PostTask(
356 FROM_HERE,
357 base::Bind(&SoftwareDecoder::PipelineStatusOnMainThread,
358 base::Unretained(this),
359 status));
360 }
361
362 void SoftwareDecoder::PipelineStatusOnMainThread(media::PipelineStatus status) {
363 if (!host_)
364 return;
365 int32_t result;
366 switch (status) {
367 case media::PIPELINE_OK:
368 result = PP_OK;
369 break;
370 case media::DECODER_ERROR_NOT_SUPPORTED:
371 result = PP_ERROR_NOTSUPPORTED;
372 break;
373 default:
374 result = PP_ERROR_FAILED;
375 break;
376 }
377 host_->OnInitializeComplete(result);
378 }
379
380 void SoftwareDecoder::ReceiveBufferOnMediaThread(
381 uint32_t decode_id,
382 scoped_refptr<media::DecoderBuffer> buffer) {
383 bool decoder_busy = !pending_decodes_.empty();
384 pending_decodes_.push(PendingDecode(decode_id, buffer));
385 if (!decoder_busy)
386 DecodeOnMediaThread();
387 }
388
389 void SoftwareDecoder::DecodeOnMediaThread() {
390 DCHECK(!pending_decodes_.empty());
391 PendingDecode& next_decode = pending_decodes_.front();
392 decoder_->Decode(next_decode.buffer,
393 base::Bind(&SoftwareDecoder::ConvertFrameOnMediaThread,
394 base::Unretained(this),
395 next_decode.decode_id));
396 pending_decodes_.pop();
397 }
398
399 void SoftwareDecoder::ConvertFrameOnMediaThread(
400 uint32_t decode_id,
401 media::VideoDecoder::Status status,
402 const scoped_refptr<media::VideoFrame>& frame) {
403 if (!host_)
404 return;
405 scoped_ptr<PendingFrame> pending_frame(
406 new PendingFrame(decode_id, gfx::Size()));
407 if (frame) {
408 pending_frame->size = frame->coded_size();
409 pending_frame->pixels.resize(frame->coded_size().width() *
410 frame->coded_size().height() * 4);
411 // Convert the decoded frame to ARGB pixels.
412 libyuv::I420ToARGB(frame->data(media::VideoFrame::kYPlane),
413 frame->stride(media::VideoFrame::kYPlane),
414 frame->data(media::VideoFrame::kUPlane),
415 frame->stride(media::VideoFrame::kUPlane),
416 frame->data(media::VideoFrame::kVPlane),
417 frame->stride(media::VideoFrame::kVPlane),
418 &pending_frame->pixels.front(),
419 frame->coded_size().width() * 4,
420 frame->coded_size().width(),
421 frame->coded_size().height());
422 }
423
424 main_message_loop_->PostTask(
425 FROM_HERE,
426 base::Bind(&SoftwareDecoder::ReceiveFrameOnMainThread,
427 base::Unretained(this),
428 status,
429 base::Passed(&pending_frame)));
430
431 if (!pending_decodes_.empty())
432 DecodeOnMediaThread();
433 }
434
435 void SoftwareDecoder::ReceiveFrameOnMainThread(
436 media::VideoDecoder::Status status,
437 scoped_ptr<PendingFrame> frame) {
438 DCHECK(RenderThreadImpl::current());
439 if (!host_)
440 return;
441
442 num_pending_decodes_--;
443
444 if (frame->pixels.size()) {
445 if (texture_size_ != frame->size) {
446 // If the size has changed, all current textures must be dismissed. Add
447 // all textures to |textures_to_dismiss_| and dismiss any that aren't in
448 // use by the plugin. We dismiss the rest as they are recycled.
449 for (TextureIdMap::const_iterator it = texture_id_map_.begin();
450 it != texture_id_map_.end();
451 ++it) {
452 textures_to_dismiss_.insert(it->second);
453 }
454 for (std::vector<uint32_t>::const_iterator it =
455 available_textures_.begin();
456 it != available_textures_.end();
457 ++it) {
458 DismissTexture(*it);
459 }
460 available_textures_.clear();
461 FlushCommandBuffer();
462
463 DCHECK(pending_texture_mailboxes_.empty());
464 const uint32_t num_textures = 8;
465 for (uint32_t i = 0; i < num_textures; i++)
466 pending_texture_mailboxes_.push_back(gpu::Mailbox::Generate());
467
468 host_->RequestTextures(
469 num_textures, frame->size, GL_TEXTURE_2D, pending_texture_mailboxes_);
470 texture_size_ = frame->size;
471 }
472
473 pending_frames_.push(frame.release());
474 SendPicturesOnMainThread();
475 } else {
476 host_->NotifyEndOfBitstreamBuffer(frame->decode_id);
477 }
478
479 switch (status) {
480 case media::VideoDecoder::kOk:
481 case media::VideoDecoder::kAborted:
482 break;
483 case media::VideoDecoder::kNotEnoughData:
igorc 2014/06/03 20:26:32 This is not an error in H264 case when we feed ind
bbudge 2014/06/03 20:59:20 Do you mean that we should silently ignore this er
bbudge 2014/06/04 14:10:12 Changed to not call NotifyError on kNotEnoughData.
484 host_->NotifyError(PP_ERROR_MALFORMED_INPUT);
485 break;
486 case media::VideoDecoder::kDecodeError:
487 case media::VideoDecoder::kDecryptError:
488 host_->NotifyError(PP_ERROR_RESOURCE_FAILED);
489 break;
490 // No default case, to catch unhandled status values.
491 }
492 }
493
494 void SoftwareDecoder::SendPicturesOnMainThread() {
495 DCHECK(RenderThreadImpl::current());
496 if (!host_)
497 return;
498 while (!pending_frames_.empty() && !available_textures_.empty()) {
499 scoped_ptr<PendingFrame> frame(pending_frames_.front());
500 pending_frames_.pop();
501
502 uint32_t texture_id = available_textures_.back();
503 available_textures_.pop_back();
504
505 uint32_t local_texture_id = texture_id_map_[texture_id];
506 gpu::gles2::GLES2Interface* gles2 = context_provider_->ContextGL();
507 gles2->ActiveTexture(GL_TEXTURE0);
508 gles2->BindTexture(GL_TEXTURE_2D, local_texture_id);
509 gles2->TexImage2D(GL_TEXTURE_2D,
510 0,
511 GL_RGBA,
512 texture_size_.width(),
513 texture_size_.height(),
514 0,
515 GL_RGBA,
516 GL_UNSIGNED_BYTE,
517 &frame->pixels.front());
518
519 host_->NotifyEndOfBitstreamBuffer(frame->decode_id);
520 host_->PictureReady(media::Picture(texture_id, frame->decode_id));
521 }
522
523 FlushCommandBuffer();
524
525 if (flushing_ && !num_pending_decodes_ && pending_frames_.empty()) {
526 flushing_ = false;
527 host_->NotifyFlushDone();
528 }
529 }
530
531 void SoftwareDecoder::DoResetOnMediaThread() {
532 decoder_->Reset(base::Bind(&SoftwareDecoder::ResetCompleteOnMediaThread,
533 base::Unretained(this)));
534 }
535
536 void SoftwareDecoder::ResetCompleteOnMediaThread() {
537 // Cancel all remaining decodes, and notify the host so it can free the shm
538 // buffers. We'll clear pending frames on the main thread.
539 while (!pending_decodes_.empty()) {
540 PendingDecode& next_decode = pending_decodes_.front();
541 scoped_ptr<PendingFrame> pending_frame(
542 new PendingFrame(next_decode.decode_id, gfx::Size()));
543 main_message_loop_->PostTask(
544 FROM_HERE,
545 base::Bind(&SoftwareDecoder::ReceiveFrameOnMainThread,
546 base::Unretained(this),
547 media::VideoDecoder::kAborted,
548 base::Passed(&pending_frame)));
549 pending_decodes_.pop();
550 }
551 main_message_loop_->PostTask(
552 FROM_HERE,
553 base::Bind(&SoftwareDecoder::ResetCompleteOnMainThread,
554 base::Unretained(this)));
555 }
556
557 void SoftwareDecoder::ResetCompleteOnMainThread() {
558 if (!host_)
559 return;
560 while (!pending_frames_.empty()) {
561 scoped_ptr<PendingFrame> frame(pending_frames_.front());
562 host_->NotifyEndOfBitstreamBuffer(frame->decode_id);
563 pending_frames_.pop();
564 }
565
566 resetting_ = false;
567 host_->NotifyResetDone();
568 }
569
570 void SoftwareDecoder::DestroyOnMediaThread() {
571 DCHECK(decoder_);
572 decoder_->Stop();
573 // All callbacks have been called on the media thread, and thus all tasks
574 // posted for the main thread. This is our last task for the main thread.
575 main_message_loop_->PostTask(FROM_HERE,
576 base::Bind(&SoftwareDecoder::DestroyOnMainThread,
577 base::Unretained(this)));
578 }
579
580 void SoftwareDecoder::DestroyOnMainThread() {
581 DCHECK(RenderThreadImpl::current());
582 DCHECK(!host_);
583 delete this;
584 }
585
586 void SoftwareDecoder::DismissTexture(uint32_t texture_id) {
587 DCHECK(host_);
588 textures_to_dismiss_.erase(texture_id);
589 DCHECK(texture_id_map_.find(texture_id) != texture_id_map_.end());
590 DeleteTexture(texture_id_map_[texture_id]);
591 texture_id_map_.erase(texture_id);
592 host_->DismissPictureBuffer(texture_id);
593 }
594
595 void SoftwareDecoder::DeleteTexture(uint32_t texture_id) {
596 gpu::gles2::GLES2Interface* gles2 = context_provider_->ContextGL();
597 gles2->DeleteTextures(1, &texture_id);
598 }
599
600 void SoftwareDecoder::FlushCommandBuffer() {
601 DCHECK(RenderThreadImpl::current());
602 context_provider_->ContextGL()->Flush();
603 }
604
dmichael (off chromium) 2014/06/03 22:27:46 I think this class should be in its own file.
bbudge 2014/06/04 14:10:12 Done.
68 PepperVideoDecoderHost::PendingDecode::PendingDecode( 605 PepperVideoDecoderHost::PendingDecode::PendingDecode(
69 uint32_t shm_id, 606 uint32_t shm_id,
70 const ppapi::host::ReplyMessageContext& reply_context) 607 const ppapi::host::ReplyMessageContext& reply_context)
71 : shm_id(shm_id), reply_context(reply_context) { 608 : shm_id(shm_id), reply_context(reply_context) {
72 } 609 }
73 610
74 PepperVideoDecoderHost::PendingDecode::~PendingDecode() { 611 PepperVideoDecoderHost::PendingDecode::~PendingDecode() {
75 } 612 }
76 613
77 PepperVideoDecoderHost::PepperVideoDecoderHost(RendererPpapiHost* host, 614 PepperVideoDecoderHost::PepperVideoDecoderHost(RendererPpapiHost* host,
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after
112 const ppapi::HostResource& graphics_context, 649 const ppapi::HostResource& graphics_context,
113 PP_VideoProfile profile, 650 PP_VideoProfile profile,
114 bool allow_software_fallback) { 651 bool allow_software_fallback) {
115 if (initialized_) 652 if (initialized_)
116 return PP_ERROR_FAILED; 653 return PP_ERROR_FAILED;
117 654
118 EnterResourceNoLock<PPB_Graphics3D_API> enter_graphics( 655 EnterResourceNoLock<PPB_Graphics3D_API> enter_graphics(
119 graphics_context.host_resource(), true); 656 graphics_context.host_resource(), true);
120 if (enter_graphics.failed()) 657 if (enter_graphics.failed())
121 return PP_ERROR_FAILED; 658 return PP_ERROR_FAILED;
122 graphics3d_ = static_cast<PPB_Graphics3D_Impl*>(enter_graphics.object()); 659 PPB_Graphics3D_Impl* graphics3d =
660 static_cast<PPB_Graphics3D_Impl*>(enter_graphics.object());
123 661
124 int command_buffer_route_id = graphics3d_->GetCommandBufferRouteId(); 662 int command_buffer_route_id = graphics3d->GetCommandBufferRouteId();
125 if (!command_buffer_route_id) 663 if (!command_buffer_route_id)
126 return PP_ERROR_FAILED; 664 return PP_ERROR_FAILED;
127 665
128 media::VideoCodecProfile media_profile = PepperToMediaVideoProfile(profile); 666 media::VideoCodecProfile media_profile = PepperToMediaVideoProfile(profile);
129 667
130 // This is not synchronous, but subsequent IPC messages will be buffered, so 668 // 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. 669 // it is okay to immediately send IPC messages through the returned channel.
132 GpuChannelHost* channel = graphics3d_->channel(); 670 GpuChannelHost* channel = graphics3d->channel();
133 DCHECK(channel); 671 DCHECK(channel);
134 decoder_ = channel->CreateVideoDecoder(command_buffer_route_id); 672 decoder_ = channel->CreateVideoDecoder(command_buffer_route_id);
135 if (decoder_ && decoder_->Initialize(media_profile, this)) { 673 if (decoder_ && decoder_->Initialize(media_profile, this)) {
136 initialized_ = true; 674 initialized_ = true;
137 return PP_OK; 675 return PP_OK;
138 } 676 }
139 decoder_.reset(); 677 decoder_.reset();
140 678
141 // TODO(bbudge) Implement software fallback. 679 if (!allow_software_fallback)
142 return PP_ERROR_NOTSUPPORTED; 680 return PP_ERROR_NOTSUPPORTED;
681
682 software_decoder_.reset(new SoftwareDecoder(this));
683 initialize_reply_context_ = context->MakeReplyMessageContext();
684 software_decoder_->Initialize(media_profile);
685
686 return PP_OK_COMPLETIONPENDING;
143 } 687 }
144 688
145 int32_t PepperVideoDecoderHost::OnHostMsgGetShm( 689 int32_t PepperVideoDecoderHost::OnHostMsgGetShm(
146 ppapi::host::HostMessageContext* context, 690 ppapi::host::HostMessageContext* context,
147 uint32_t shm_id, 691 uint32_t shm_id,
148 uint32_t shm_size) { 692 uint32_t shm_size) {
149 if (!initialized_) 693 if (!initialized_)
150 return PP_ERROR_FAILED; 694 return PP_ERROR_FAILED;
151 695
152 // Make the buffers larger since we hope to reuse them. 696 // Make the buffers larger since we hope to reuse them.
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after
201 return PP_OK_COMPLETIONPENDING; 745 return PP_OK_COMPLETIONPENDING;
202 } 746 }
203 747
204 int32_t PepperVideoDecoderHost::OnHostMsgDecode( 748 int32_t PepperVideoDecoderHost::OnHostMsgDecode(
205 ppapi::host::HostMessageContext* context, 749 ppapi::host::HostMessageContext* context,
206 uint32_t shm_id, 750 uint32_t shm_id,
207 uint32_t size, 751 uint32_t size,
208 int32_t decode_id) { 752 int32_t decode_id) {
209 if (!initialized_) 753 if (!initialized_)
210 return PP_ERROR_FAILED; 754 return PP_ERROR_FAILED;
211 DCHECK(decoder_); 755 DCHECK(decoder_ || software_decoder_);
212 // |shm_id| is just an index into shm_buffers_. Make sure it's in range. 756 // |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()) 757 if (static_cast<size_t>(shm_id) >= shm_buffers_.size())
214 return PP_ERROR_FAILED; 758 return PP_ERROR_FAILED;
215 // Reject an attempt to pass a busy buffer to the decoder again. 759 // Reject an attempt to pass a busy buffer to the decoder again.
216 if (shm_buffer_busy_[shm_id]) 760 if (shm_buffer_busy_[shm_id])
217 return PP_ERROR_FAILED; 761 return PP_ERROR_FAILED;
218 // Reject non-unique decode_id values. 762 // Reject non-unique decode_id values.
219 if (pending_decodes_.find(decode_id) != pending_decodes_.end()) 763 if (pending_decodes_.find(decode_id) != pending_decodes_.end())
220 return PP_ERROR_FAILED; 764 return PP_ERROR_FAILED;
221 765
222 if (flush_reply_context_.is_valid() || reset_reply_context_.is_valid()) 766 if (flush_reply_context_.is_valid() || reset_reply_context_.is_valid())
223 return PP_ERROR_FAILED; 767 return PP_ERROR_FAILED;
224 768
225 pending_decodes_.insert(std::make_pair( 769 pending_decodes_.insert(std::make_pair(
226 decode_id, PendingDecode(shm_id, context->MakeReplyMessageContext()))); 770 decode_id, PendingDecode(shm_id, context->MakeReplyMessageContext())));
227 771
228 shm_buffer_busy_[shm_id] = true; 772 shm_buffer_busy_[shm_id] = true;
229 decoder_->Decode( 773 base::SharedMemory* shm = shm_buffers_[shm_id];
230 media::BitstreamBuffer(decode_id, shm_buffers_[shm_id]->handle(), size)); 774 if (decoder_) {
775 decoder_->Decode(media::BitstreamBuffer(decode_id, shm->handle(), size));
776 } else {
777 software_decoder_->Decode(decode_id,
778 media::DecoderBuffer::CopyFrom(
779 static_cast<uint8_t*>(shm->memory()), size));
780 }
231 781
232 return PP_OK_COMPLETIONPENDING; 782 return PP_OK_COMPLETIONPENDING;
233 } 783 }
234 784
235 int32_t PepperVideoDecoderHost::OnHostMsgAssignTextures( 785 int32_t PepperVideoDecoderHost::OnHostMsgAssignTextures(
236 ppapi::host::HostMessageContext* context, 786 ppapi::host::HostMessageContext* context,
237 const PP_Size& size, 787 const PP_Size& size,
238 const std::vector<uint32_t>& texture_ids) { 788 const std::vector<uint32_t>& texture_ids) {
239 if (!initialized_) 789 if (!initialized_)
240 return PP_ERROR_FAILED; 790 return PP_ERROR_FAILED;
241 DCHECK(decoder_); 791 DCHECK(decoder_ || software_decoder_);
242 792
243 std::vector<media::PictureBuffer> picture_buffers; 793 if (decoder_) {
244 for (uint32 i = 0; i < texture_ids.size(); i++) { 794 std::vector<media::PictureBuffer> picture_buffers;
245 media::PictureBuffer buffer( 795 for (uint32 i = 0; i < texture_ids.size(); i++) {
246 texture_ids[i], // Use the texture_id to identify the buffer. 796 media::PictureBuffer buffer(
247 gfx::Size(size.width, size.height), 797 texture_ids[i], // Use the texture_id to identify the buffer.
248 texture_ids[i]); 798 gfx::Size(size.width, size.height),
249 picture_buffers.push_back(buffer); 799 texture_ids[i]);
800 picture_buffers.push_back(buffer);
801 }
802 decoder_->AssignPictureBuffers(picture_buffers);
803 } else {
804 software_decoder_->AssignTextures(texture_ids);
250 } 805 }
251 decoder_->AssignPictureBuffers(picture_buffers);
252 return PP_OK; 806 return PP_OK;
253 } 807 }
254 808
255 int32_t PepperVideoDecoderHost::OnHostMsgRecyclePicture( 809 int32_t PepperVideoDecoderHost::OnHostMsgRecyclePicture(
256 ppapi::host::HostMessageContext* context, 810 ppapi::host::HostMessageContext* context,
257 uint32_t texture_id) { 811 uint32_t texture_id) {
258 if (!initialized_) 812 if (!initialized_)
259 return PP_ERROR_FAILED; 813 return PP_ERROR_FAILED;
260 DCHECK(decoder_); 814 DCHECK(decoder_ || software_decoder_);
261 if (reset_reply_context_.is_valid()) 815 if (reset_reply_context_.is_valid())
262 return PP_ERROR_FAILED; 816 return PP_ERROR_FAILED;
263 817 if (decoder_) {
264 decoder_->ReusePictureBuffer(texture_id); 818 decoder_->ReusePictureBuffer(texture_id);
819 } else {
820 software_decoder_->RecycleTexture(texture_id);
821 }
265 822
266 return PP_OK; 823 return PP_OK;
267 } 824 }
268 825
269 int32_t PepperVideoDecoderHost::OnHostMsgFlush( 826 int32_t PepperVideoDecoderHost::OnHostMsgFlush(
270 ppapi::host::HostMessageContext* context) { 827 ppapi::host::HostMessageContext* context) {
271 if (!initialized_) 828 if (!initialized_)
272 return PP_ERROR_FAILED; 829 return PP_ERROR_FAILED;
273 DCHECK(decoder_); 830 DCHECK(decoder_ || software_decoder_);
274 if (flush_reply_context_.is_valid() || reset_reply_context_.is_valid()) 831 if (flush_reply_context_.is_valid() || reset_reply_context_.is_valid())
275 return PP_ERROR_FAILED; 832 return PP_ERROR_FAILED;
276 833
277 flush_reply_context_ = context->MakeReplyMessageContext(); 834 flush_reply_context_ = context->MakeReplyMessageContext();
278 decoder_->Flush(); 835 if (decoder_)
836 decoder_->Flush();
837 else
838 software_decoder_->Flush();
279 839
280 return PP_OK_COMPLETIONPENDING; 840 return PP_OK_COMPLETIONPENDING;
281 } 841 }
282 842
283 int32_t PepperVideoDecoderHost::OnHostMsgReset( 843 int32_t PepperVideoDecoderHost::OnHostMsgReset(
284 ppapi::host::HostMessageContext* context) { 844 ppapi::host::HostMessageContext* context) {
285 if (!initialized_) 845 if (!initialized_)
286 return PP_ERROR_FAILED; 846 return PP_ERROR_FAILED;
287 DCHECK(decoder_); 847 DCHECK(decoder_ || software_decoder_);
288 if (flush_reply_context_.is_valid() || reset_reply_context_.is_valid()) 848 if (flush_reply_context_.is_valid() || reset_reply_context_.is_valid())
289 return PP_ERROR_FAILED; 849 return PP_ERROR_FAILED;
290 850
291 reset_reply_context_ = context->MakeReplyMessageContext(); 851 reset_reply_context_ = context->MakeReplyMessageContext();
292 decoder_->Reset(); 852 if (decoder_)
853 decoder_->Reset();
854 else
855 software_decoder_->Reset();
293 856
294 return PP_OK_COMPLETIONPENDING; 857 return PP_OK_COMPLETIONPENDING;
295 } 858 }
296 859
297 void PepperVideoDecoderHost::ProvidePictureBuffers( 860 void PepperVideoDecoderHost::ProvidePictureBuffers(
298 uint32 requested_num_of_buffers, 861 uint32 requested_num_of_buffers,
299 const gfx::Size& dimensions, 862 const gfx::Size& dimensions,
300 uint32 texture_target) { 863 uint32 texture_target) {
301 DCHECK(RenderThreadImpl::current()); 864 RequestTextures(requested_num_of_buffers,
302 host()->SendUnsolicitedReply( 865 dimensions,
303 pp_resource(), 866 texture_target,
304 PpapiPluginMsg_VideoDecoder_RequestTextures( 867 std::vector<gpu::Mailbox>());
305 requested_num_of_buffers,
306 PP_MakeSize(dimensions.width(), dimensions.height()),
307 texture_target));
308 } 868 }
309 869
310 void PepperVideoDecoderHost::PictureReady(const media::Picture& picture) { 870 void PepperVideoDecoderHost::PictureReady(const media::Picture& picture) {
311 DCHECK(RenderThreadImpl::current());
312 host()->SendUnsolicitedReply( 871 host()->SendUnsolicitedReply(
313 pp_resource(), 872 pp_resource(),
314 PpapiPluginMsg_VideoDecoder_PictureReady(picture.bitstream_buffer_id(), 873 PpapiPluginMsg_VideoDecoder_PictureReady(picture.bitstream_buffer_id(),
315 picture.picture_buffer_id())); 874 picture.picture_buffer_id()));
316 } 875 }
317 876
318 void PepperVideoDecoderHost::DismissPictureBuffer(int32 picture_buffer_id) { 877 void PepperVideoDecoderHost::DismissPictureBuffer(int32 picture_buffer_id) {
319 DCHECK(RenderThreadImpl::current());
320 host()->SendUnsolicitedReply( 878 host()->SendUnsolicitedReply(
321 pp_resource(), 879 pp_resource(),
322 PpapiPluginMsg_VideoDecoder_DismissPicture(picture_buffer_id)); 880 PpapiPluginMsg_VideoDecoder_DismissPicture(picture_buffer_id));
323 } 881 }
324 882
883 void PepperVideoDecoderHost::NotifyEndOfBitstreamBuffer(
884 int32 bitstream_buffer_id) {
885 PendingDecodeMap::iterator it = pending_decodes_.find(bitstream_buffer_id);
886 if (it == pending_decodes_.end()) {
887 NOTREACHED();
888 return;
889 }
890 const PendingDecode& pending_decode = it->second;
891 host()->SendReply(
892 pending_decode.reply_context,
893 PpapiPluginMsg_VideoDecoder_DecodeReply(pending_decode.shm_id));
894 shm_buffer_busy_[pending_decode.shm_id] = false;
895 pending_decodes_.erase(it);
896 }
897
898 void PepperVideoDecoderHost::NotifyFlushDone() {
899 host()->SendReply(flush_reply_context_,
900 PpapiPluginMsg_VideoDecoder_FlushReply());
901 flush_reply_context_ = ppapi::host::ReplyMessageContext();
902 }
903
904 void PepperVideoDecoderHost::NotifyResetDone() {
905 host()->SendReply(reset_reply_context_,
906 PpapiPluginMsg_VideoDecoder_ResetReply());
907 reset_reply_context_ = ppapi::host::ReplyMessageContext();
908 }
909
325 void PepperVideoDecoderHost::NotifyError( 910 void PepperVideoDecoderHost::NotifyError(
326 media::VideoDecodeAccelerator::Error error) { 911 media::VideoDecodeAccelerator::Error error) {
327 DCHECK(RenderThreadImpl::current());
328 int32_t pp_error = PP_ERROR_FAILED; 912 int32_t pp_error = PP_ERROR_FAILED;
329 switch (error) { 913 switch (error) {
330 case media::VideoDecodeAccelerator::UNREADABLE_INPUT: 914 case media::VideoDecodeAccelerator::UNREADABLE_INPUT:
331 pp_error = PP_ERROR_MALFORMED_INPUT; 915 pp_error = PP_ERROR_MALFORMED_INPUT;
332 break; 916 break;
333 case media::VideoDecodeAccelerator::ILLEGAL_STATE: 917 case media::VideoDecodeAccelerator::ILLEGAL_STATE:
334 case media::VideoDecodeAccelerator::INVALID_ARGUMENT: 918 case media::VideoDecodeAccelerator::INVALID_ARGUMENT:
335 case media::VideoDecodeAccelerator::PLATFORM_FAILURE: 919 case media::VideoDecodeAccelerator::PLATFORM_FAILURE:
336 case media::VideoDecodeAccelerator::LARGEST_ERROR_ENUM: 920 case media::VideoDecodeAccelerator::LARGEST_ERROR_ENUM:
337 pp_error = PP_ERROR_RESOURCE_FAILED; 921 pp_error = PP_ERROR_RESOURCE_FAILED;
338 break; 922 break;
339 // No default case, to catch unhandled enum values. 923 // No default case, to catch unhandled enum values.
340 } 924 }
925 NotifyError(pp_error);
926 }
927
928 void PepperVideoDecoderHost::OnInitializeComplete(int32_t result) {
929 if (!initialized_) {
930 initialized_ = true;
931 initialize_reply_context_.params.set_result(result);
932 host()->SendReply(initialize_reply_context_,
933 PpapiPluginMsg_VideoDecoder_InitializeReply());
934 }
935 }
936
937 void PepperVideoDecoderHost::RequestTextures(
938 uint32 requested_num_of_buffers,
939 const gfx::Size& dimensions,
940 uint32 texture_target,
941 const std::vector<gpu::Mailbox>& mailboxes) {
942 DCHECK(RenderThreadImpl::current());
943 host()->SendUnsolicitedReply(
944 pp_resource(),
945 PpapiPluginMsg_VideoDecoder_RequestTextures(
946 requested_num_of_buffers,
947 PP_MakeSize(dimensions.width(), dimensions.height()),
948 texture_target,
949 mailboxes));
950 }
951
952 void PepperVideoDecoderHost::NotifyError(int32_t pp_error) {
341 host()->SendUnsolicitedReply( 953 host()->SendUnsolicitedReply(
342 pp_resource(), PpapiPluginMsg_VideoDecoder_NotifyError(pp_error)); 954 pp_resource(), PpapiPluginMsg_VideoDecoder_NotifyError(pp_error));
343 } 955 }
344 956
345 void PepperVideoDecoderHost::NotifyResetDone() { 957 } // namespace content
346 DCHECK(RenderThreadImpl::current()); 958
347 host()->SendReply(reset_reply_context_, 959 namespace base {
348 PpapiPluginMsg_VideoDecoder_ResetReply()); 960
349 reset_reply_context_ = ppapi::host::ReplyMessageContext(); 961 void DefaultDeleter<content::SoftwareDecoder>::operator()(
962 void* software_decoder) const {
963 static_cast<content::SoftwareDecoder*>(software_decoder)->Destroy();
350 } 964 }
351 965
352 void PepperVideoDecoderHost::NotifyEndOfBitstreamBuffer( 966 } // namespace base
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

Powered by Google App Engine
This is Rietveld 408576698