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"
8 #include "base/callback_helpers.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"
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
31 : public base::RefCountedThreadSafe
<VDAClientProxy
>,
32 public VideoDecodeAccelerator::Client
{
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_|.
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
;
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_
,
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
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
)
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
),
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
),
167 vda_loop_proxy_(factories
->GetMessageLoop()),
168 factories_(factories
),
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();
191 // Throw away any already-decoded, not-yet-delivered frames.
192 ready_video_frames_
.clear();
195 gvd_loop_proxy_
->PostTask(FROM_HERE
, closure
);
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());
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)
228 bool hw_large_video_support
=
229 (cpu
.vendor_name() == "GenuineIntel") && cpu
.model() >= 58;
230 bool os_large_video_support
= true;
232 os_large_video_support
= false;
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());
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
);
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
);
266 client_proxy_
= new VDAClientProxy(this);
267 VideoDecodeAccelerator
* vda
= factories_
->CreateVideoDecodeAccelerator(
268 config
.profile(), client_proxy_
.get());
270 status_cb
.Run(DECODER_ERROR_NOT_SUPPORTED
);
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(),
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());
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()) {
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
;
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
);
347 // TODO(xhwang): It's odd that we return kOk after VDA has been released.
348 // Fix this and simplify cases.
350 base::ResetAndReturn(&pending_read_cb_
).Run(
351 kOk
, VideoFrame::CreateEmptyFrame());
355 if (!ready_video_frames_
.empty()) {
356 EnqueueFrameAndTriggerFrameDelivery(NULL
);
361 case kDecoderDrained
:
365 EnsureDemuxOrDecode();
367 case kDrainingDecoder
:
368 // Do nothing. Will be satisfied either by a PictureReady or
369 // NotifyFlushDone below.
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())
392 base::ResetAndReturn(&pending_read_cb_
).Run(kOk
, NULL
);
396 // VideoFrameStream ensures no kConfigChanged is passed to VideoDecoders.
397 DCHECK_EQ(status
, DemuxerStream::kOk
) << status
;
400 EnqueueFrameAndTriggerFrameDelivery(VideoFrame::CreateEmptyFrame());
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_
));
413 if (!pending_reset_cb_
.is_null())
416 size_t size
= buffer
->GetDataSize();
417 SHMBuffer
* shm_buffer
= GetSHM(size
);
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
;
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();
463 if (it
->bitstream_buffer_id
!= id
)
465 *timestamp
= it
->timestamp
;
466 *visible_rect
= it
->visible_rect
;
467 *natural_size
= it
->natural_size
;
470 NOTREACHED() << "Missing bitstreambuffer id: " << id
;
473 bool GpuVideoDecoder::HasAlpha() const {
474 DCHECK(gvd_loop_proxy_
->BelongsToCurrentThread());
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
,
506 decoder_texture_target_
)) {
507 NotifyError(VideoDecodeAccelerator::PLATFORM_FAILURE
);
510 DCHECK_EQ(count
, texture_ids
.size());
511 DCHECK_EQ(count
, texture_mailboxes
.size());
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
;
525 available_pictures_
+= count
;
527 vda_loop_proxy_
->PostTask(FROM_HERE
, base::Bind(
528 &VideoDecodeAccelerator::AssignPictureBuffers
, weak_vda_
,
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
;
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_
;
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
;
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
);
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(), ×tamp
, &visible_rect
,
579 DCHECK(decoder_texture_target_
);
581 scoped_refptr
<VideoFrame
> frame(
582 VideoFrame::WrapNativeTexture(
583 new VideoFrame::MailboxHolder(
584 pb
.texture_mailbox(),
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())),
596 CHECK_GT(available_pictures_
, 0);
597 --available_pictures_
;
599 picture_buffers_at_display_
.insert(picture
.picture_buffer_id()).second
;
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
611 if (!pending_reset_cb_
.is_null())
615 ready_video_frames_
.push_back(frame
);
617 DCHECK(!ready_video_frames_
.empty());
619 if (pending_read_cb_
.is_null())
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
,
628 DCHECK(gvd_loop_proxy_
->BelongsToCurrentThread());
633 CHECK(!picture_buffers_at_display_
.empty());
635 size_t num_erased
= picture_buffers_at_display_
.erase(picture_buffer_id
);
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
);
650 factories_
->WaitSyncPoint(sync_point
);
652 ++available_pictures_
;
654 vda_loop_proxy_
->PostTask(FROM_HERE
, base::Bind(
655 &VideoDecodeAccelerator::ReusePictureBuffer
, weak_vda_
,
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.
668 return new SHMBuffer(shm
, size_to_allocate
);
670 SHMBuffer
* ret
= available_shm_segments_
.back();
671 available_shm_segments_
.pop_back();
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
;
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();
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_
)
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());
766 DLOG(ERROR
) << "VDA Error: " << error
;
771 if (!pending_read_cb_
.is_null()) {
772 base::ResetAndReturn(&pending_read_cb_
).Run(kDecodeError
, NULL
);