Chromium Code Reviews| Index: media/filters/gpu_video_decoder.cc |
| diff --git a/media/filters/gpu_video_decoder.cc b/media/filters/gpu_video_decoder.cc |
| index 6842e4d7c59a4797c6c373f5916ad1c30feb357a..39d4ac76c494cca1cd563ff709e06854e9f0489f 100644 |
| --- a/media/filters/gpu_video_decoder.cc |
| +++ b/media/filters/gpu_video_decoder.cc |
| @@ -41,12 +41,14 @@ GpuVideoDecoder::SHMBuffer::SHMBuffer(base::SharedMemory* m, size_t s) |
| GpuVideoDecoder::SHMBuffer::~SHMBuffer() {} |
| -GpuVideoDecoder::BufferPair::BufferPair( |
| - SHMBuffer* s, const scoped_refptr<DecoderBuffer>& b) |
| - : shm_buffer(s), buffer(b) { |
| +GpuVideoDecoder::PendingDecoderBuffer::PendingDecoderBuffer( |
| + SHMBuffer* s, |
| + const scoped_refptr<DecoderBuffer>& b, |
| + const DecodeCB& done_cb) |
| + : shm_buffer(s), buffer(b), done_cb(done_cb) { |
| } |
| -GpuVideoDecoder::BufferPair::~BufferPair() {} |
| +GpuVideoDecoder::PendingDecoderBuffer::~PendingDecoderBuffer() {} |
| GpuVideoDecoder::BufferData::BufferData( |
| int32 bbid, base::TimeDelta ts, const gfx::Rect& vr, const gfx::Size& ns) |
| @@ -80,24 +82,14 @@ void GpuVideoDecoder::Reset(const base::Closure& closure) { |
| FROM_HERE, |
| base::Bind( |
| &GpuVideoDecoder::Reset, weak_factory_.GetWeakPtr(), closure)); |
| - // NOTE: if we're deferring Reset() until a Flush() completes, return |
| - // queued pictures to the VDA so they can be used to finish that Flush(). |
| - if (pending_decode_cb_.is_null()) |
| - ready_video_frames_.clear(); |
| return; |
| } |
| - // Throw away any already-decoded, not-yet-delivered frames. |
| - ready_video_frames_.clear(); |
| - |
| if (!vda_) { |
| base::MessageLoop::current()->PostTask(FROM_HERE, closure); |
| return; |
| } |
| - if (!pending_decode_cb_.is_null()) |
| - EnqueueFrameAndTriggerFrameDelivery(VideoFrame::CreateEOSFrame()); |
| - |
| DCHECK(pending_reset_cb_.is_null()); |
| pending_reset_cb_ = BindToCurrentLoop(closure); |
| @@ -108,8 +100,7 @@ void GpuVideoDecoder::Stop() { |
| DCheckGpuVideoAcceleratorFactoriesTaskRunnerIsCurrent(); |
| if (vda_) |
| DestroyVDA(); |
| - if (!pending_decode_cb_.is_null()) |
| - EnqueueFrameAndTriggerFrameDelivery(VideoFrame::CreateEOSFrame()); |
| + DCHECK(bitstream_buffers_in_decoder_.empty()); |
| if (!pending_reset_cb_.is_null()) |
| base::ResetAndReturn(&pending_reset_cb_).Run(); |
| } |
| @@ -143,7 +134,8 @@ static void ReportGpuVideoDecoderInitializeStatusToUMAAndRunCB( |
| void GpuVideoDecoder::Initialize(const VideoDecoderConfig& config, |
| bool live_mode, |
| - const PipelineStatusCB& orig_status_cb) { |
| + const PipelineStatusCB& orig_status_cb, |
| + const OutputCB& output_cb) { |
| DVLOG(3) << "Initialize()"; |
| DCheckGpuVideoAcceleratorFactoriesTaskRunnerIsCurrent(); |
| DCHECK(config.IsValidConfig()); |
| @@ -172,6 +164,7 @@ void GpuVideoDecoder::Initialize(const VideoDecoderConfig& config, |
| config_ = config; |
| needs_bitstream_conversion_ = (config.codec() == kCodecH264); |
| + output_cb_ = output_cb; |
|
xhwang
2014/06/05 21:53:51
In some decoders we BindToCurrentLoop, in some we
Sergey Ulanov
2014/06/06 22:49:41
I think all VDA implementations should call the ca
|
| if (previously_initialized) { |
| // Reinitialization with a different config (but same codec and profile). |
| @@ -223,52 +216,39 @@ void GpuVideoDecoder::Decode(const scoped_refptr<DecoderBuffer>& buffer, |
| const DecodeCB& decode_cb) { |
| DCheckGpuVideoAcceleratorFactoriesTaskRunnerIsCurrent(); |
| DCHECK(pending_reset_cb_.is_null()); |
| - DCHECK(pending_decode_cb_.is_null()); |
| - pending_decode_cb_ = BindToCurrentLoop(decode_cb); |
| + DecodeCB bound_decode_cb = BindToCurrentLoop(decode_cb); |
| if (state_ == kError || !vda_) { |
| - base::ResetAndReturn(&pending_decode_cb_).Run(kDecodeError, NULL); |
| + bound_decode_cb.Run(kDecodeError); |
| return; |
| } |
| switch (state_) { |
| case kDecoderDrained: |
| - if (!ready_video_frames_.empty()) { |
| - EnqueueFrameAndTriggerFrameDelivery(NULL); |
| - return; |
| - } |
| state_ = kNormal; |
| // Fall-through. |
| case kNormal: |
| break; |
| case kDrainingDecoder: |
| - DCHECK(buffer->end_of_stream()); |
| - // Do nothing. Will be satisfied either by a PictureReady or |
| - // NotifyFlushDone below. |
| - return; |
| case kError: |
| NOTREACHED(); |
| return; |
| } |
| + DCHECK_EQ(state_, kNormal); |
| + |
| if (buffer->end_of_stream()) { |
| - if (state_ == kNormal) { |
| - state_ = kDrainingDecoder; |
| - vda_->Flush(); |
| - // If we have ready frames, go ahead and process them to ensure that the |
| - // Flush operation does not block in the VDA due to lack of picture |
| - // buffers. |
| - if (!ready_video_frames_.empty()) |
| - EnqueueFrameAndTriggerFrameDelivery(NULL); |
| - } |
| + state_ = kDrainingDecoder; |
| + eos_decode_cb_ = bound_decode_cb; |
| + vda_->Flush(); |
| return; |
| } |
| size_t size = buffer->data_size(); |
| SHMBuffer* shm_buffer = GetSHM(size); |
| if (!shm_buffer) { |
| - base::ResetAndReturn(&pending_decode_cb_).Run(kDecodeError, NULL); |
| + bound_decode_cb.Run(kDecodeError); |
| return; |
| } |
| @@ -277,24 +257,16 @@ void GpuVideoDecoder::Decode(const scoped_refptr<DecoderBuffer>& buffer, |
| next_bitstream_buffer_id_, shm_buffer->shm->handle(), size); |
| // Mask against 30 bits, to avoid (undefined) wraparound on signed integer. |
| next_bitstream_buffer_id_ = (next_bitstream_buffer_id_ + 1) & 0x3FFFFFFF; |
| - bool inserted = bitstream_buffers_in_decoder_.insert(std::make_pair( |
| - bitstream_buffer.id(), BufferPair(shm_buffer, buffer))).second; |
| - DCHECK(inserted); |
| + DCHECK(bitstream_buffers_in_decoder_.find(bitstream_buffer.id()) == |
| + bitstream_buffers_in_decoder_.end()); |
|
xhwang
2014/06/05 21:53:51
nit: You can use ContainsKey():
https://code.googl
Sergey Ulanov
2014/06/06 22:49:41
Done.
|
| + bitstream_buffers_in_decoder_.insert( |
| + std::make_pair(bitstream_buffer.id(), |
| + PendingDecoderBuffer(shm_buffer, buffer, decode_cb))); |
| + DCHECK_LE(static_cast<int>(bitstream_buffers_in_decoder_.size()), |
| + kMaxInFlightDecodes); |
| RecordBufferData(bitstream_buffer, *buffer.get()); |
| vda_->Decode(bitstream_buffer); |
| - |
| - if (!ready_video_frames_.empty()) { |
| - EnqueueFrameAndTriggerFrameDelivery(NULL); |
| - return; |
| - } |
| - |
| - if (CanMoreDecodeWorkBeDone()) |
| - base::ResetAndReturn(&pending_decode_cb_).Run(kNotEnoughData, NULL); |
| -} |
| - |
| -bool GpuVideoDecoder::CanMoreDecodeWorkBeDone() { |
| - return bitstream_buffers_in_decoder_.size() < kMaxInFlightDecodes; |
| } |
| void GpuVideoDecoder::RecordBufferData(const BitstreamBuffer& bitstream_buffer, |
| @@ -338,7 +310,11 @@ bool GpuVideoDecoder::CanReadWithoutStalling() const { |
| DCheckGpuVideoAcceleratorFactoriesTaskRunnerIsCurrent(); |
| return |
| next_picture_buffer_id_ == 0 || // Decode() will ProvidePictureBuffers(). |
| - available_pictures_ > 0 || !ready_video_frames_.empty(); |
| + available_pictures_ > 0; |
| +} |
| + |
| +int GpuVideoDecoder::GetMaxDecodeRequests() const { |
| + return kMaxInFlightDecodes; |
| } |
| void GpuVideoDecoder::ProvidePictureBuffers(uint32 count, |
| @@ -471,10 +447,10 @@ void GpuVideoDecoder::PictureReady(const media::Picture& picture) { |
| pb.texture_id())).second; |
| DCHECK(inserted); |
| - EnqueueFrameAndTriggerFrameDelivery(frame); |
| + DeliverFrame(frame); |
| } |
| -void GpuVideoDecoder::EnqueueFrameAndTriggerFrameDelivery( |
| +void GpuVideoDecoder::DeliverFrame( |
| const scoped_refptr<VideoFrame>& frame) { |
| DCheckGpuVideoAcceleratorFactoriesTaskRunnerIsCurrent(); |
| @@ -483,17 +459,7 @@ void GpuVideoDecoder::EnqueueFrameAndTriggerFrameDelivery( |
| if (!pending_reset_cb_.is_null()) |
| return; |
| - if (frame.get()) |
| - ready_video_frames_.push_back(frame); |
| - else |
| - DCHECK(!ready_video_frames_.empty()); |
| - |
| - if (pending_decode_cb_.is_null()) |
| - return; |
| - |
| - base::ResetAndReturn(&pending_decode_cb_) |
| - .Run(kOk, ready_video_frames_.front()); |
| - ready_video_frames_.pop_front(); |
| + output_cb_.Run(frame); |
| } |
| // static |
| @@ -566,7 +532,7 @@ void GpuVideoDecoder::NotifyEndOfBitstreamBuffer(int32 id) { |
| DVLOG(3) << "NotifyEndOfBitstreamBuffer(" << id << ")"; |
| DCheckGpuVideoAcceleratorFactoriesTaskRunnerIsCurrent(); |
| - std::map<int32, BufferPair>::iterator it = |
| + std::map<int32, PendingDecoderBuffer>::iterator it = |
| bitstream_buffers_in_decoder_.find(id); |
| if (it == bitstream_buffers_in_decoder_.end()) { |
| NotifyError(VideoDecodeAccelerator::PLATFORM_FAILURE); |
| @@ -575,25 +541,21 @@ void GpuVideoDecoder::NotifyEndOfBitstreamBuffer(int32 id) { |
| } |
| PutSHM(it->second.shm_buffer); |
| + it->second.done_cb.Run(state_ == kError ? kDecodeError : kOk); |
| bitstream_buffers_in_decoder_.erase(it); |
| - |
| - if (pending_reset_cb_.is_null() && state_ != kDrainingDecoder && |
| - CanMoreDecodeWorkBeDone() && !pending_decode_cb_.is_null()) { |
| - base::ResetAndReturn(&pending_decode_cb_).Run(kNotEnoughData, NULL); |
| - } |
| } |
| GpuVideoDecoder::~GpuVideoDecoder() { |
| DCheckGpuVideoAcceleratorFactoriesTaskRunnerIsCurrent(); |
| // Stop should have been already called. |
| DCHECK(!vda_.get() && assigned_picture_buffers_.empty()); |
| - DCHECK(pending_decode_cb_.is_null()); |
| + DCHECK(bitstream_buffers_in_decoder_.empty()); |
| for (size_t i = 0; i < available_shm_segments_.size(); ++i) { |
| available_shm_segments_[i]->shm->Close(); |
| delete available_shm_segments_[i]; |
| } |
| available_shm_segments_.clear(); |
| - for (std::map<int32, BufferPair>::iterator it = |
| + for (std::map<int32, PendingDecoderBuffer>::iterator it = |
| bitstream_buffers_in_decoder_.begin(); |
| it != bitstream_buffers_in_decoder_.end(); ++it) { |
| it->second.shm_buffer->shm->Close(); |
| @@ -606,13 +568,14 @@ void GpuVideoDecoder::NotifyFlushDone() { |
| DCheckGpuVideoAcceleratorFactoriesTaskRunnerIsCurrent(); |
| DCHECK_EQ(state_, kDrainingDecoder); |
| state_ = kDecoderDrained; |
| - EnqueueFrameAndTriggerFrameDelivery(VideoFrame::CreateEOSFrame()); |
| + DeliverFrame(VideoFrame::CreateEOSFrame()); |
| + base::ResetAndReturn(&eos_decode_cb_).Run(kOk); |
| } |
| void GpuVideoDecoder::NotifyResetDone() { |
| DVLOG(3) << "NotifyResetDone()"; |
| DCheckGpuVideoAcceleratorFactoriesTaskRunnerIsCurrent(); |
| - DCHECK(ready_video_frames_.empty()); |
| + DCHECK(bitstream_buffers_in_decoder_.empty()); |
| // This needs to happen after the Reset() on vda_ is done to ensure pictures |
| // delivered during the reset can find their time data. |
| @@ -620,9 +583,6 @@ void GpuVideoDecoder::NotifyResetDone() { |
| if (!pending_reset_cb_.is_null()) |
| base::ResetAndReturn(&pending_reset_cb_).Run(); |
| - |
| - if (!pending_decode_cb_.is_null()) |
| - EnqueueFrameAndTriggerFrameDelivery(VideoFrame::CreateEOSFrame()); |
| } |
| void GpuVideoDecoder::NotifyError(media::VideoDecodeAccelerator::Error error) { |
| @@ -630,15 +590,10 @@ void GpuVideoDecoder::NotifyError(media::VideoDecodeAccelerator::Error error) { |
| if (!vda_) |
| return; |
| - DLOG(ERROR) << "VDA Error: " << error; |
| - DestroyVDA(); |
| - |
| state_ = kError; |
| - if (!pending_decode_cb_.is_null()) { |
| - base::ResetAndReturn(&pending_decode_cb_).Run(kDecodeError, NULL); |
| - return; |
| - } |
| + DLOG(ERROR) << "VDA Error: " << error; |
| + DestroyVDA(); |
| } |
| void GpuVideoDecoder::DCheckGpuVideoAcceleratorFactoriesTaskRunnerIsCurrent() |