OLD | NEW |
---|---|
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 | |
OLD | NEW |