Fix some potential after free errors on TestCompletionCallback
[chromium-blink-merge.git] / media / filters / gpu_video_decoder.cc
blob3679a5acc00070115b260953644e79979462014c
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.
5 #include "media/filters/gpu_video_decoder.h"
7 #include "base/bind.h"
8 #include "base/callback_helpers.h"
9 #include "base/cpu.h"
10 #include "base/message_loop.h"
11 #include "base/stl_util.h"
12 #include "base/task_runner_util.h"
13 #include "media/base/bind_to_loop.h"
14 #include "media/base/decoder_buffer.h"
15 #include "media/base/demuxer_stream.h"
16 #include "media/base/pipeline.h"
17 #include "media/base/pipeline_status.h"
18 #include "media/base/video_decoder_config.h"
20 namespace media {
22 // Proxies calls to a VideoDecodeAccelerator::Client from the calling thread to
23 // the client's thread.
25 // TODO(scherkus): VDAClientProxy should hold onto GpuVideoDecoder::Factories
26 // and take care of some of the work that GpuVideoDecoder does to minimize
27 // thread hopping. See following for discussion:
29 // https://codereview.chromium.org/12989009/diff/27035/media/filters/gpu_video_decoder.cc#newcode23
30 class VDAClientProxy
31 : public base::RefCountedThreadSafe<VDAClientProxy>,
32 public VideoDecodeAccelerator::Client {
33 public:
34 explicit VDAClientProxy(VideoDecodeAccelerator::Client* client);
36 // Detaches the proxy. |weak_client_| will no longer be called and can be
37 // safely deleted. Any pending/future calls will be discarded.
39 // Must be called on |client_loop_|.
40 void Detach();
42 // VideoDecodeAccelerator::Client implementation.
43 virtual void NotifyInitializeDone() OVERRIDE;
44 virtual void ProvidePictureBuffers(uint32 count,
45 const gfx::Size& size,
46 uint32 texture_target) OVERRIDE;
47 virtual void DismissPictureBuffer(int32 id) OVERRIDE;
48 virtual void PictureReady(const media::Picture& picture) OVERRIDE;
49 virtual void NotifyEndOfBitstreamBuffer(int32 id) OVERRIDE;
50 virtual void NotifyFlushDone() OVERRIDE;
51 virtual void NotifyResetDone() OVERRIDE;
52 virtual void NotifyError(media::VideoDecodeAccelerator::Error error) OVERRIDE;
54 private:
55 friend class base::RefCountedThreadSafe<VDAClientProxy>;
56 virtual ~VDAClientProxy();
58 scoped_refptr<base::MessageLoopProxy> client_loop_;
60 // Weak pointers are used to invalidate tasks posted to |client_loop_| after
61 // Detach() has been called.
62 base::WeakPtrFactory<VideoDecodeAccelerator::Client> weak_client_factory_;
63 base::WeakPtr<VideoDecodeAccelerator::Client> weak_client_;
65 DISALLOW_COPY_AND_ASSIGN(VDAClientProxy);
68 VDAClientProxy::VDAClientProxy(VideoDecodeAccelerator::Client* client)
69 : client_loop_(base::MessageLoopProxy::current()),
70 weak_client_factory_(client),
71 weak_client_(weak_client_factory_.GetWeakPtr()) {
72 DCHECK(weak_client_.get());
75 VDAClientProxy::~VDAClientProxy() {}
77 void VDAClientProxy::Detach() {
78 DCHECK(client_loop_->BelongsToCurrentThread());
79 DCHECK(weak_client_.get()) << "Detach() already called";
80 weak_client_factory_.InvalidateWeakPtrs();
83 void VDAClientProxy::NotifyInitializeDone() {
84 client_loop_->PostTask(FROM_HERE, base::Bind(
85 &VideoDecodeAccelerator::Client::NotifyInitializeDone, weak_client_));
88 void VDAClientProxy::ProvidePictureBuffers(uint32 count,
89 const gfx::Size& size,
90 uint32 texture_target) {
91 client_loop_->PostTask(FROM_HERE, base::Bind(
92 &VideoDecodeAccelerator::Client::ProvidePictureBuffers, weak_client_,
93 count, size, texture_target));
96 void VDAClientProxy::DismissPictureBuffer(int32 id) {
97 client_loop_->PostTask(FROM_HERE, base::Bind(
98 &VideoDecodeAccelerator::Client::DismissPictureBuffer, weak_client_, id));
101 void VDAClientProxy::PictureReady(const media::Picture& picture) {
102 client_loop_->PostTask(FROM_HERE, base::Bind(
103 &VideoDecodeAccelerator::Client::PictureReady, weak_client_, picture));
106 void VDAClientProxy::NotifyEndOfBitstreamBuffer(int32 id) {
107 client_loop_->PostTask(FROM_HERE, base::Bind(
108 &VideoDecodeAccelerator::Client::NotifyEndOfBitstreamBuffer, weak_client_,
109 id));
112 void VDAClientProxy::NotifyFlushDone() {
113 client_loop_->PostTask(FROM_HERE, base::Bind(
114 &VideoDecodeAccelerator::Client::NotifyFlushDone, weak_client_));
117 void VDAClientProxy::NotifyResetDone() {
118 client_loop_->PostTask(FROM_HERE, base::Bind(
119 &VideoDecodeAccelerator::Client::NotifyResetDone, weak_client_));
122 void VDAClientProxy::NotifyError(media::VideoDecodeAccelerator::Error error) {
123 client_loop_->PostTask(FROM_HERE, base::Bind(
124 &VideoDecodeAccelerator::Client::NotifyError, weak_client_, error));
128 // Maximum number of concurrent VDA::Decode() operations GVD will maintain.
129 // Higher values allow better pipelining in the GPU, but also require more
130 // resources.
131 enum { kMaxInFlightDecodes = 4 };
133 GpuVideoDecoder::Factories::~Factories() {}
135 // Size of shared-memory segments we allocate. Since we reuse them we let them
136 // be on the beefy side.
137 static const size_t kSharedMemorySegmentBytes = 100 << 10;
139 GpuVideoDecoder::SHMBuffer::SHMBuffer(base::SharedMemory* m, size_t s)
140 : shm(m), size(s) {
143 GpuVideoDecoder::SHMBuffer::~SHMBuffer() {}
145 GpuVideoDecoder::BufferPair::BufferPair(
146 SHMBuffer* s, const scoped_refptr<DecoderBuffer>& b)
147 : shm_buffer(s), buffer(b) {
150 GpuVideoDecoder::BufferPair::~BufferPair() {}
152 GpuVideoDecoder::BufferData::BufferData(
153 int32 bbid, base::TimeDelta ts, const gfx::Rect& vr, const gfx::Size& ns)
154 : bitstream_buffer_id(bbid), timestamp(ts), visible_rect(vr),
155 natural_size(ns) {
158 GpuVideoDecoder::BufferData::~BufferData() {}
160 GpuVideoDecoder::GpuVideoDecoder(
161 const scoped_refptr<base::MessageLoopProxy>& message_loop,
162 const scoped_refptr<Factories>& factories)
163 : demuxer_stream_(NULL),
164 needs_bitstream_conversion_(false),
165 gvd_loop_proxy_(message_loop),
166 weak_factory_(this),
167 vda_loop_proxy_(factories->GetMessageLoop()),
168 factories_(factories),
169 state_(kNormal),
170 demuxer_read_in_progress_(false),
171 decoder_texture_target_(0),
172 next_picture_buffer_id_(0),
173 next_bitstream_buffer_id_(0),
174 available_pictures_(0) {
175 DCHECK(factories_.get());
178 void GpuVideoDecoder::Reset(const base::Closure& closure) {
179 DCHECK(gvd_loop_proxy_->BelongsToCurrentThread());
181 if (state_ == kDrainingDecoder && !factories_->IsAborted()) {
182 gvd_loop_proxy_->PostTask(FROM_HERE, base::Bind(
183 &GpuVideoDecoder::Reset, weak_this_, closure));
184 // NOTE: if we're deferring Reset() until a Flush() completes, return
185 // queued pictures to the VDA so they can be used to finish that Flush().
186 if (pending_read_cb_.is_null())
187 ready_video_frames_.clear();
188 return;
191 // Throw away any already-decoded, not-yet-delivered frames.
192 ready_video_frames_.clear();
194 if (!vda_) {
195 gvd_loop_proxy_->PostTask(FROM_HERE, closure);
196 return;
199 if (!pending_read_cb_.is_null())
200 EnqueueFrameAndTriggerFrameDelivery(VideoFrame::CreateEmptyFrame());
202 DCHECK(pending_reset_cb_.is_null());
203 pending_reset_cb_ = BindToCurrentLoop(closure);
205 vda_loop_proxy_->PostTask(FROM_HERE, base::Bind(
206 &VideoDecodeAccelerator::Reset, weak_vda_));
209 void GpuVideoDecoder::Stop(const base::Closure& closure) {
210 DCHECK(gvd_loop_proxy_->BelongsToCurrentThread());
211 if (vda_)
212 DestroyVDA();
213 if (!pending_read_cb_.is_null())
214 EnqueueFrameAndTriggerFrameDelivery(VideoFrame::CreateEmptyFrame());
215 if (!pending_reset_cb_.is_null())
216 base::ResetAndReturn(&pending_reset_cb_).Run();
217 demuxer_stream_ = NULL;
218 BindToCurrentLoop(closure).Run();
221 static bool IsCodedSizeSupported(const gfx::Size& coded_size) {
222 // Only non-Windows, Ivy Bridge+ platforms can support more than 1920x1080.
223 // We test against 1088 to account for 16x16 macroblocks.
224 if (coded_size.width() <= 1920 && coded_size.height() <= 1088)
225 return true;
227 base::CPU cpu;
228 bool hw_large_video_support =
229 (cpu.vendor_name() == "GenuineIntel") && cpu.model() >= 58;
230 bool os_large_video_support = true;
231 #if defined(OS_WIN)
232 os_large_video_support = false;
233 #endif
234 return os_large_video_support && hw_large_video_support;
237 void GpuVideoDecoder::Initialize(DemuxerStream* stream,
238 const PipelineStatusCB& orig_status_cb,
239 const StatisticsCB& statistics_cb) {
240 DCHECK(gvd_loop_proxy_->BelongsToCurrentThread());
241 DCHECK(stream);
243 weak_this_ = weak_factory_.GetWeakPtr();
245 PipelineStatusCB status_cb = CreateUMAReportingPipelineCB(
246 "Media.GpuVideoDecoderInitializeStatus",
247 BindToCurrentLoop(orig_status_cb));
249 if (demuxer_stream_) {
250 // TODO(xhwang): Make GpuVideoDecoder reinitializable.
251 // See http://crbug.com/233608
252 DVLOG(1) << "GpuVideoDecoder reinitialization not supported.";
253 status_cb.Run(DECODER_ERROR_NOT_SUPPORTED);
254 return;
257 const VideoDecoderConfig& config = stream->video_decoder_config();
258 DCHECK(config.IsValidConfig());
259 DCHECK(!config.is_encrypted());
261 if (!IsCodedSizeSupported(config.coded_size())) {
262 status_cb.Run(DECODER_ERROR_NOT_SUPPORTED);
263 return;
266 client_proxy_ = new VDAClientProxy(this);
267 VideoDecodeAccelerator* vda = factories_->CreateVideoDecodeAccelerator(
268 config.profile(), client_proxy_.get());
269 if (!vda) {
270 status_cb.Run(DECODER_ERROR_NOT_SUPPORTED);
271 return;
274 demuxer_stream_ = stream;
275 statistics_cb_ = statistics_cb;
276 needs_bitstream_conversion_ = (config.codec() == kCodecH264);
278 DVLOG(1) << "GpuVideoDecoder::Initialize() succeeded.";
279 PostTaskAndReplyWithResult(
280 vda_loop_proxy_.get(),
281 FROM_HERE,
282 base::Bind(&VideoDecodeAccelerator::AsWeakPtr, base::Unretained(vda)),
283 base::Bind(&GpuVideoDecoder::SetVDA, weak_this_, status_cb, vda));
286 void GpuVideoDecoder::SetVDA(
287 const PipelineStatusCB& status_cb,
288 VideoDecodeAccelerator* vda,
289 base::WeakPtr<VideoDecodeAccelerator> weak_vda) {
290 DCHECK(gvd_loop_proxy_->BelongsToCurrentThread());
291 DCHECK(!vda_.get());
292 vda_.reset(vda);
293 weak_vda_ = weak_vda;
294 status_cb.Run(PIPELINE_OK);
297 void GpuVideoDecoder::DestroyTextures() {
298 std::map<int32, PictureBuffer>::iterator it;
300 for (it = assigned_picture_buffers_.begin();
301 it != assigned_picture_buffers_.end(); ++it) {
302 factories_->DeleteTexture(it->second.texture_id());
304 assigned_picture_buffers_.clear();
306 for (it = dismissed_picture_buffers_.begin();
307 it != dismissed_picture_buffers_.end(); ++it) {
308 factories_->DeleteTexture(it->second.texture_id());
310 dismissed_picture_buffers_.clear();
313 static void DestroyVDAWithClientProxy(
314 const scoped_refptr<VDAClientProxy>& client_proxy,
315 base::WeakPtr<VideoDecodeAccelerator> weak_vda) {
316 if (weak_vda.get()) {
317 weak_vda->Destroy();
318 DCHECK(!weak_vda.get()); // Check VDA::Destroy() contract.
322 void GpuVideoDecoder::DestroyVDA() {
323 DCHECK(gvd_loop_proxy_->BelongsToCurrentThread());
325 // |client_proxy| must stay alive until |weak_vda_| has been destroyed.
326 vda_loop_proxy_->PostTask(FROM_HERE, base::Bind(
327 &DestroyVDAWithClientProxy, client_proxy_, weak_vda_));
329 VideoDecodeAccelerator* vda ALLOW_UNUSED = vda_.release();
330 client_proxy_->Detach();
331 client_proxy_ = NULL;
333 DestroyTextures();
336 void GpuVideoDecoder::Read(const ReadCB& read_cb) {
337 DCHECK(gvd_loop_proxy_->BelongsToCurrentThread());
338 DCHECK(pending_reset_cb_.is_null());
339 DCHECK(pending_read_cb_.is_null());
340 pending_read_cb_ = BindToCurrentLoop(read_cb);
342 if (state_ == kError) {
343 base::ResetAndReturn(&pending_read_cb_).Run(kDecodeError, NULL);
344 return;
347 // TODO(xhwang): It's odd that we return kOk after VDA has been released.
348 // Fix this and simplify cases.
349 if (!vda_) {
350 base::ResetAndReturn(&pending_read_cb_).Run(
351 kOk, VideoFrame::CreateEmptyFrame());
352 return;
355 if (!ready_video_frames_.empty()) {
356 EnqueueFrameAndTriggerFrameDelivery(NULL);
357 return;
360 switch (state_) {
361 case kDecoderDrained:
362 state_ = kNormal;
363 // Fall-through.
364 case kNormal:
365 EnsureDemuxOrDecode();
366 break;
367 case kDrainingDecoder:
368 // Do nothing. Will be satisfied either by a PictureReady or
369 // NotifyFlushDone below.
370 break;
371 case kError:
372 NOTREACHED();
373 break;
377 bool GpuVideoDecoder::CanMoreDecodeWorkBeDone() {
378 return bitstream_buffers_in_decoder_.size() < kMaxInFlightDecodes;
381 void GpuVideoDecoder::RequestBufferDecode(
382 DemuxerStream::Status status,
383 const scoped_refptr<DecoderBuffer>& buffer) {
384 DCHECK(gvd_loop_proxy_->BelongsToCurrentThread());
385 DCHECK_EQ(status != DemuxerStream::kOk, !buffer.get()) << status;
387 demuxer_read_in_progress_ = false;
389 if (status == DemuxerStream::kAborted) {
390 if (pending_read_cb_.is_null())
391 return;
392 base::ResetAndReturn(&pending_read_cb_).Run(kOk, NULL);
393 return;
396 // VideoFrameStream ensures no kConfigChanged is passed to VideoDecoders.
397 DCHECK_EQ(status, DemuxerStream::kOk) << status;
399 if (!vda_) {
400 EnqueueFrameAndTriggerFrameDelivery(VideoFrame::CreateEmptyFrame());
401 return;
404 if (buffer->IsEndOfStream()) {
405 if (state_ == kNormal) {
406 state_ = kDrainingDecoder;
407 vda_loop_proxy_->PostTask(FROM_HERE, base::Bind(
408 &VideoDecodeAccelerator::Flush, weak_vda_));
410 return;
413 if (!pending_reset_cb_.is_null())
414 return;
416 size_t size = buffer->GetDataSize();
417 SHMBuffer* shm_buffer = GetSHM(size);
418 if (!shm_buffer)
419 return;
421 memcpy(shm_buffer->shm->memory(), buffer->GetData(), size);
422 BitstreamBuffer bitstream_buffer(
423 next_bitstream_buffer_id_, shm_buffer->shm->handle(), size);
424 // Mask against 30 bits, to avoid (undefined) wraparound on signed integer.
425 next_bitstream_buffer_id_ = (next_bitstream_buffer_id_ + 1) & 0x3FFFFFFF;
426 bool inserted = bitstream_buffers_in_decoder_.insert(std::make_pair(
427 bitstream_buffer.id(), BufferPair(shm_buffer, buffer))).second;
428 DCHECK(inserted);
429 RecordBufferData(bitstream_buffer, *buffer.get());
431 vda_loop_proxy_->PostTask(FROM_HERE, base::Bind(
432 &VideoDecodeAccelerator::Decode, weak_vda_, bitstream_buffer));
434 if (CanMoreDecodeWorkBeDone()) {
435 // Force post here to prevent reentrancy into DemuxerStream.
436 gvd_loop_proxy_->PostTask(FROM_HERE, base::Bind(
437 &GpuVideoDecoder::EnsureDemuxOrDecode, weak_this_));
441 void GpuVideoDecoder::RecordBufferData(
442 const BitstreamBuffer& bitstream_buffer, const DecoderBuffer& buffer) {
443 input_buffer_data_.push_front(BufferData(
444 bitstream_buffer.id(), buffer.GetTimestamp(),
445 demuxer_stream_->video_decoder_config().visible_rect(),
446 demuxer_stream_->video_decoder_config().natural_size()));
447 // Why this value? Because why not. avformat.h:MAX_REORDER_DELAY is 16, but
448 // that's too small for some pathological B-frame test videos. The cost of
449 // using too-high a value is low (192 bits per extra slot).
450 static const size_t kMaxInputBufferDataSize = 128;
451 // Pop from the back of the list, because that's the oldest and least likely
452 // to be useful in the future data.
453 if (input_buffer_data_.size() > kMaxInputBufferDataSize)
454 input_buffer_data_.pop_back();
457 void GpuVideoDecoder::GetBufferData(int32 id, base::TimeDelta* timestamp,
458 gfx::Rect* visible_rect,
459 gfx::Size* natural_size) {
460 for (std::list<BufferData>::const_iterator it =
461 input_buffer_data_.begin(); it != input_buffer_data_.end();
462 ++it) {
463 if (it->bitstream_buffer_id != id)
464 continue;
465 *timestamp = it->timestamp;
466 *visible_rect = it->visible_rect;
467 *natural_size = it->natural_size;
468 return;
470 NOTREACHED() << "Missing bitstreambuffer id: " << id;
473 bool GpuVideoDecoder::HasAlpha() const {
474 DCHECK(gvd_loop_proxy_->BelongsToCurrentThread());
475 return true;
478 bool GpuVideoDecoder::NeedsBitstreamConversion() const {
479 DCHECK(gvd_loop_proxy_->BelongsToCurrentThread());
480 return needs_bitstream_conversion_;
483 bool GpuVideoDecoder::HasOutputFrameAvailable() const {
484 DCHECK(gvd_loop_proxy_->BelongsToCurrentThread());
485 return available_pictures_ > 0;
488 void GpuVideoDecoder::NotifyInitializeDone() {
489 NOTREACHED() << "GpuVideoDecodeAcceleratorHost::Initialize is synchronous!";
492 void GpuVideoDecoder::ProvidePictureBuffers(uint32 count,
493 const gfx::Size& size,
494 uint32 texture_target) {
495 DCHECK(gvd_loop_proxy_->BelongsToCurrentThread());
497 std::vector<uint32> texture_ids;
498 std::vector<gpu::Mailbox> texture_mailboxes;
499 decoder_texture_target_ = texture_target;
500 // Discards the sync point returned here since PictureReady will imply that
501 // the produce has already happened, and the texture is ready for use.
502 if (!factories_->CreateTextures(count,
503 size,
504 &texture_ids,
505 &texture_mailboxes,
506 decoder_texture_target_)) {
507 NotifyError(VideoDecodeAccelerator::PLATFORM_FAILURE);
508 return;
510 DCHECK_EQ(count, texture_ids.size());
511 DCHECK_EQ(count, texture_mailboxes.size());
513 if (!vda_)
514 return;
516 std::vector<PictureBuffer> picture_buffers;
517 for (size_t i = 0; i < texture_ids.size(); ++i) {
518 picture_buffers.push_back(PictureBuffer(
519 next_picture_buffer_id_++, size, texture_ids[i], texture_mailboxes[i]));
520 bool inserted = assigned_picture_buffers_.insert(std::make_pair(
521 picture_buffers.back().id(), picture_buffers.back())).second;
522 DCHECK(inserted);
525 available_pictures_ += count;
527 vda_loop_proxy_->PostTask(FROM_HERE, base::Bind(
528 &VideoDecodeAccelerator::AssignPictureBuffers, weak_vda_,
529 picture_buffers));
532 void GpuVideoDecoder::DismissPictureBuffer(int32 id) {
533 DCHECK(gvd_loop_proxy_->BelongsToCurrentThread());
535 std::map<int32, PictureBuffer>::iterator it =
536 assigned_picture_buffers_.find(id);
537 if (it == assigned_picture_buffers_.end()) {
538 NOTREACHED() << "Missing picture buffer: " << id;
539 return;
542 PictureBuffer buffer_to_dismiss = it->second;
543 assigned_picture_buffers_.erase(it);
545 std::set<int32>::iterator at_display_it =
546 picture_buffers_at_display_.find(id);
548 if (at_display_it == picture_buffers_at_display_.end()) {
549 // We can delete the texture immediately as it's not being displayed.
550 factories_->DeleteTexture(buffer_to_dismiss.texture_id());
551 CHECK_GT(available_pictures_, 0);
552 --available_pictures_;
553 } else {
554 // Texture in display. Postpone deletion until after it's returned to us.
555 bool inserted = dismissed_picture_buffers_.insert(std::make_pair(
556 id, buffer_to_dismiss)).second;
557 DCHECK(inserted);
561 void GpuVideoDecoder::PictureReady(const media::Picture& picture) {
562 DCHECK(gvd_loop_proxy_->BelongsToCurrentThread());
564 std::map<int32, PictureBuffer>::iterator it =
565 assigned_picture_buffers_.find(picture.picture_buffer_id());
566 if (it == assigned_picture_buffers_.end()) {
567 NOTREACHED() << "Missing picture buffer: " << picture.picture_buffer_id();
568 NotifyError(VideoDecodeAccelerator::PLATFORM_FAILURE);
569 return;
571 const PictureBuffer& pb = it->second;
573 // Update frame's timestamp.
574 base::TimeDelta timestamp;
575 gfx::Rect visible_rect;
576 gfx::Size natural_size;
577 GetBufferData(picture.bitstream_buffer_id(), &timestamp, &visible_rect,
578 &natural_size);
579 DCHECK(decoder_texture_target_);
581 scoped_refptr<VideoFrame> frame(
582 VideoFrame::WrapNativeTexture(
583 new VideoFrame::MailboxHolder(
584 pb.texture_mailbox(),
585 0, // sync_point
586 BindToCurrentLoop(base::Bind(
587 &GpuVideoDecoder::ReusePictureBuffer, weak_this_,
588 picture.picture_buffer_id()))),
589 decoder_texture_target_,
590 pb.size(), visible_rect,
591 natural_size, timestamp,
592 base::Bind(&Factories::ReadPixels, factories_, pb.texture_id(),
593 decoder_texture_target_,
594 gfx::Size(visible_rect.width(), visible_rect.height())),
595 base::Closure()));
596 CHECK_GT(available_pictures_, 0);
597 --available_pictures_;
598 bool inserted =
599 picture_buffers_at_display_.insert(picture.picture_buffer_id()).second;
600 DCHECK(inserted);
602 EnqueueFrameAndTriggerFrameDelivery(frame);
605 void GpuVideoDecoder::EnqueueFrameAndTriggerFrameDelivery(
606 const scoped_refptr<VideoFrame>& frame) {
607 DCHECK(gvd_loop_proxy_->BelongsToCurrentThread());
609 // During a pending vda->Reset(), we don't accumulate frames. Drop it on the
610 // floor and return.
611 if (!pending_reset_cb_.is_null())
612 return;
614 if (frame.get())
615 ready_video_frames_.push_back(frame);
616 else
617 DCHECK(!ready_video_frames_.empty());
619 if (pending_read_cb_.is_null())
620 return;
622 base::ResetAndReturn(&pending_read_cb_).Run(kOk, ready_video_frames_.front());
623 ready_video_frames_.pop_front();
626 void GpuVideoDecoder::ReusePictureBuffer(int64 picture_buffer_id,
627 uint32 sync_point) {
628 DCHECK(gvd_loop_proxy_->BelongsToCurrentThread());
630 if (!vda_)
631 return;
633 CHECK(!picture_buffers_at_display_.empty());
635 size_t num_erased = picture_buffers_at_display_.erase(picture_buffer_id);
636 DCHECK(num_erased);
638 std::map<int32, PictureBuffer>::iterator it =
639 assigned_picture_buffers_.find(picture_buffer_id);
641 if (it == assigned_picture_buffers_.end()) {
642 // This picture was dismissed while in display, so we postponed deletion.
643 it = dismissed_picture_buffers_.find(picture_buffer_id);
644 DCHECK(it != dismissed_picture_buffers_.end());
645 factories_->DeleteTexture(it->second.texture_id());
646 dismissed_picture_buffers_.erase(it);
647 return;
650 factories_->WaitSyncPoint(sync_point);
652 ++available_pictures_;
654 vda_loop_proxy_->PostTask(FROM_HERE, base::Bind(
655 &VideoDecodeAccelerator::ReusePictureBuffer, weak_vda_,
656 picture_buffer_id));
659 GpuVideoDecoder::SHMBuffer* GpuVideoDecoder::GetSHM(size_t min_size) {
660 DCHECK(gvd_loop_proxy_->BelongsToCurrentThread());
661 if (available_shm_segments_.empty() ||
662 available_shm_segments_.back()->size < min_size) {
663 size_t size_to_allocate = std::max(min_size, kSharedMemorySegmentBytes);
664 base::SharedMemory* shm = factories_->CreateSharedMemory(size_to_allocate);
665 // CreateSharedMemory() can return NULL during Shutdown.
666 if (!shm)
667 return NULL;
668 return new SHMBuffer(shm, size_to_allocate);
670 SHMBuffer* ret = available_shm_segments_.back();
671 available_shm_segments_.pop_back();
672 return ret;
675 void GpuVideoDecoder::PutSHM(SHMBuffer* shm_buffer) {
676 DCHECK(gvd_loop_proxy_->BelongsToCurrentThread());
677 available_shm_segments_.push_back(shm_buffer);
680 void GpuVideoDecoder::NotifyEndOfBitstreamBuffer(int32 id) {
681 DCHECK(gvd_loop_proxy_->BelongsToCurrentThread());
683 std::map<int32, BufferPair>::iterator it =
684 bitstream_buffers_in_decoder_.find(id);
685 if (it == bitstream_buffers_in_decoder_.end()) {
686 NotifyError(VideoDecodeAccelerator::PLATFORM_FAILURE);
687 NOTREACHED() << "Missing bitstream buffer: " << id;
688 return;
691 PutSHM(it->second.shm_buffer);
692 const scoped_refptr<DecoderBuffer>& buffer = it->second.buffer;
693 if (buffer->GetDataSize()) {
694 PipelineStatistics statistics;
695 statistics.video_bytes_decoded = buffer->GetDataSize();
696 statistics_cb_.Run(statistics);
698 bitstream_buffers_in_decoder_.erase(it);
700 if (pending_reset_cb_.is_null() && state_ != kDrainingDecoder &&
701 CanMoreDecodeWorkBeDone()) {
702 EnsureDemuxOrDecode();
706 GpuVideoDecoder::~GpuVideoDecoder() {
707 DCHECK(!vda_.get()); // Stop should have been already called.
708 DCHECK(pending_read_cb_.is_null());
709 for (size_t i = 0; i < available_shm_segments_.size(); ++i) {
710 available_shm_segments_[i]->shm->Close();
711 delete available_shm_segments_[i];
713 available_shm_segments_.clear();
714 for (std::map<int32, BufferPair>::iterator it =
715 bitstream_buffers_in_decoder_.begin();
716 it != bitstream_buffers_in_decoder_.end(); ++it) {
717 it->second.shm_buffer->shm->Close();
719 bitstream_buffers_in_decoder_.clear();
721 DestroyTextures();
724 void GpuVideoDecoder::EnsureDemuxOrDecode() {
725 DCHECK(gvd_loop_proxy_->BelongsToCurrentThread());
727 // The second condition can happen during the tear-down process.
728 // GpuVideoDecoder::Stop() returns the |pending_read_cb_| immediately without
729 // waiting for the demuxer read to be returned. Therefore, this function could
730 // be called even after the decoder has been stopped.
731 if (demuxer_read_in_progress_ || !demuxer_stream_)
732 return;
734 demuxer_read_in_progress_ = true;
735 demuxer_stream_->Read(base::Bind(
736 &GpuVideoDecoder::RequestBufferDecode, weak_this_));
739 void GpuVideoDecoder::NotifyFlushDone() {
740 DCHECK(gvd_loop_proxy_->BelongsToCurrentThread());
741 DCHECK_EQ(state_, kDrainingDecoder);
742 state_ = kDecoderDrained;
743 EnqueueFrameAndTriggerFrameDelivery(VideoFrame::CreateEmptyFrame());
746 void GpuVideoDecoder::NotifyResetDone() {
747 DCHECK(gvd_loop_proxy_->BelongsToCurrentThread());
748 DCHECK(ready_video_frames_.empty());
750 // This needs to happen after the Reset() on vda_ is done to ensure pictures
751 // delivered during the reset can find their time data.
752 input_buffer_data_.clear();
754 if (!pending_reset_cb_.is_null())
755 base::ResetAndReturn(&pending_reset_cb_).Run();
757 if (!pending_read_cb_.is_null())
758 EnqueueFrameAndTriggerFrameDelivery(VideoFrame::CreateEmptyFrame());
761 void GpuVideoDecoder::NotifyError(media::VideoDecodeAccelerator::Error error) {
762 DCHECK(gvd_loop_proxy_->BelongsToCurrentThread());
763 if (!vda_)
764 return;
766 DLOG(ERROR) << "VDA Error: " << error;
767 DestroyVDA();
769 state_ = kError;
771 if (!pending_read_cb_.is_null()) {
772 base::ResetAndReturn(&pending_read_cb_).Run(kDecodeError, NULL);
773 return;
777 } // namespace media