| Index: media/filters/gpu_video_decoder.cc
|
| diff --git a/media/filters/gpu_video_decoder.cc b/media/filters/gpu_video_decoder.cc
|
| index 8cf51ad101a76c7a78aaec78ca20b916dd43b8a5..fcb837d005fd167089447a6dc070505b01945709 100644
|
| --- a/media/filters/gpu_video_decoder.cc
|
| +++ b/media/filters/gpu_video_decoder.cc
|
| @@ -4,6 +4,8 @@
|
|
|
| #include "media/filters/gpu_video_decoder.h"
|
|
|
| +#include <algorithm>
|
| +
|
| #include "base/bind.h"
|
| #include "base/callback_helpers.h"
|
| #include "base/cpu.h"
|
| @@ -12,7 +14,6 @@
|
| #include "base/task_runner_util.h"
|
| #include "media/base/bind_to_loop.h"
|
| #include "media/base/decoder_buffer.h"
|
| -#include "media/base/demuxer_stream.h"
|
| #include "media/base/pipeline.h"
|
| #include "media/base/pipeline_status.h"
|
| #include "media/base/video_decoder_config.h"
|
| @@ -160,14 +161,12 @@ GpuVideoDecoder::BufferData::~BufferData() {}
|
| GpuVideoDecoder::GpuVideoDecoder(
|
| const scoped_refptr<base::MessageLoopProxy>& message_loop,
|
| const scoped_refptr<Factories>& factories)
|
| - : demuxer_stream_(NULL),
|
| - needs_bitstream_conversion_(false),
|
| + : needs_bitstream_conversion_(false),
|
| gvd_loop_proxy_(message_loop),
|
| weak_factory_(this),
|
| vda_loop_proxy_(factories->GetMessageLoop()),
|
| factories_(factories),
|
| state_(kNormal),
|
| - demuxer_read_in_progress_(false),
|
| decoder_texture_target_(0),
|
| next_picture_buffer_id_(0),
|
| next_bitstream_buffer_id_(0),
|
| @@ -176,6 +175,7 @@ GpuVideoDecoder::GpuVideoDecoder(
|
| }
|
|
|
| void GpuVideoDecoder::Reset(const base::Closure& closure) {
|
| + DVLOG(3) << "Reset()";
|
| DCHECK(gvd_loop_proxy_->BelongsToCurrentThread());
|
|
|
| if (state_ == kDrainingDecoder && !factories_->IsAborted()) {
|
| @@ -214,7 +214,6 @@ void GpuVideoDecoder::Stop(const base::Closure& closure) {
|
| EnqueueFrameAndTriggerFrameDelivery(VideoFrame::CreateEmptyFrame());
|
| if (!pending_reset_cb_.is_null())
|
| base::ResetAndReturn(&pending_reset_cb_).Run();
|
| - demuxer_stream_ = NULL;
|
| BindToCurrentLoop(closure).Run();
|
| }
|
|
|
| @@ -234,11 +233,13 @@ static bool IsCodedSizeSupported(const gfx::Size& coded_size) {
|
| return os_large_video_support && hw_large_video_support;
|
| }
|
|
|
| -void GpuVideoDecoder::Initialize(DemuxerStream* stream,
|
| +void GpuVideoDecoder::Initialize(const VideoDecoderConfig& config,
|
| const PipelineStatusCB& orig_status_cb,
|
| const StatisticsCB& statistics_cb) {
|
| + DVLOG(3) << "Initialize()";
|
| DCHECK(gvd_loop_proxy_->BelongsToCurrentThread());
|
| - DCHECK(stream);
|
| + DCHECK(config.IsValidConfig());
|
| + DCHECK(!config.is_encrypted());
|
|
|
| weak_this_ = weak_factory_.GetWeakPtr();
|
|
|
| @@ -246,7 +247,7 @@ void GpuVideoDecoder::Initialize(DemuxerStream* stream,
|
| "Media.GpuVideoDecoderInitializeStatus",
|
| BindToCurrentLoop(orig_status_cb));
|
|
|
| - if (demuxer_stream_) {
|
| + if (config_.IsValidConfig()) {
|
| // TODO(xhwang): Make GpuVideoDecoder reinitializable.
|
| // See http://crbug.com/233608
|
| DVLOG(1) << "GpuVideoDecoder reinitialization not supported.";
|
| @@ -254,10 +255,6 @@ void GpuVideoDecoder::Initialize(DemuxerStream* stream,
|
| return;
|
| }
|
|
|
| - const VideoDecoderConfig& config = stream->video_decoder_config();
|
| - DCHECK(config.IsValidConfig());
|
| - DCHECK(!config.is_encrypted());
|
| -
|
| if (!IsCodedSizeSupported(config.coded_size())) {
|
| status_cb.Run(DECODER_ERROR_NOT_SUPPORTED);
|
| return;
|
| @@ -271,11 +268,11 @@ void GpuVideoDecoder::Initialize(DemuxerStream* stream,
|
| return;
|
| }
|
|
|
| - demuxer_stream_ = stream;
|
| + config_ = config;
|
| statistics_cb_ = statistics_cb;
|
| needs_bitstream_conversion_ = (config.codec() == kCodecH264);
|
|
|
| - DVLOG(1) << "GpuVideoDecoder::Initialize() succeeded.";
|
| + DVLOG(3) << "GpuVideoDecoder::Initialize() succeeded.";
|
| PostTaskAndReplyWithResult(
|
| vda_loop_proxy_.get(),
|
| FROM_HERE,
|
| @@ -333,72 +330,37 @@ void GpuVideoDecoder::DestroyVDA() {
|
| DestroyTextures();
|
| }
|
|
|
| -void GpuVideoDecoder::Read(const ReadCB& read_cb) {
|
| +void GpuVideoDecoder::Decode(const scoped_refptr<DecoderBuffer>& buffer,
|
| + const ReadCB& read_cb) {
|
| DCHECK(gvd_loop_proxy_->BelongsToCurrentThread());
|
| DCHECK(pending_reset_cb_.is_null());
|
| DCHECK(pending_read_cb_.is_null());
|
| +
|
| pending_read_cb_ = BindToCurrentLoop(read_cb);
|
|
|
| - if (state_ == kError) {
|
| + if (state_ == kError || !vda_) {
|
| base::ResetAndReturn(&pending_read_cb_).Run(kDecodeError, NULL);
|
| return;
|
| }
|
|
|
| - // TODO(xhwang): It's odd that we return kOk after VDA has been released.
|
| - // Fix this and simplify cases.
|
| - if (!vda_) {
|
| - base::ResetAndReturn(&pending_read_cb_).Run(
|
| - kOk, VideoFrame::CreateEmptyFrame());
|
| - return;
|
| - }
|
| -
|
| - if (!ready_video_frames_.empty()) {
|
| - EnqueueFrameAndTriggerFrameDelivery(NULL);
|
| - return;
|
| - }
|
| -
|
| switch (state_) {
|
| case kDecoderDrained:
|
| + if (!ready_video_frames_.empty()) {
|
| + EnqueueFrameAndTriggerFrameDelivery(NULL);
|
| + return;
|
| + }
|
| state_ = kNormal;
|
| // Fall-through.
|
| case kNormal:
|
| - EnsureDemuxOrDecode();
|
| break;
|
| case kDrainingDecoder:
|
| + DCHECK(buffer->IsEndOfStream());
|
| // Do nothing. Will be satisfied either by a PictureReady or
|
| // NotifyFlushDone below.
|
| - break;
|
| + return;
|
| case kError:
|
| NOTREACHED();
|
| - break;
|
| - }
|
| -}
|
| -
|
| -bool GpuVideoDecoder::CanMoreDecodeWorkBeDone() {
|
| - return bitstream_buffers_in_decoder_.size() < kMaxInFlightDecodes;
|
| -}
|
| -
|
| -void GpuVideoDecoder::RequestBufferDecode(
|
| - DemuxerStream::Status status,
|
| - const scoped_refptr<DecoderBuffer>& buffer) {
|
| - DCHECK(gvd_loop_proxy_->BelongsToCurrentThread());
|
| - DCHECK_EQ(status != DemuxerStream::kOk, !buffer.get()) << status;
|
| -
|
| - demuxer_read_in_progress_ = false;
|
| -
|
| - if (status == DemuxerStream::kAborted) {
|
| - if (pending_read_cb_.is_null())
|
| return;
|
| - base::ResetAndReturn(&pending_read_cb_).Run(kOk, NULL);
|
| - return;
|
| - }
|
| -
|
| - // VideoFrameStream ensures no kConfigChanged is passed to VideoDecoders.
|
| - DCHECK_EQ(status, DemuxerStream::kOk) << status;
|
| -
|
| - if (!vda_) {
|
| - EnqueueFrameAndTriggerFrameDelivery(VideoFrame::CreateEmptyFrame());
|
| - return;
|
| }
|
|
|
| if (buffer->IsEndOfStream()) {
|
| @@ -410,13 +372,12 @@ void GpuVideoDecoder::RequestBufferDecode(
|
| return;
|
| }
|
|
|
| - if (!pending_reset_cb_.is_null())
|
| - return;
|
| -
|
| size_t size = buffer->GetDataSize();
|
| SHMBuffer* shm_buffer = GetSHM(size);
|
| - if (!shm_buffer)
|
| + if (!shm_buffer) {
|
| + base::ResetAndReturn(&pending_read_cb_).Run(kDecodeError, NULL);
|
| return;
|
| + }
|
|
|
| memcpy(shm_buffer->shm->memory(), buffer->GetData(), size);
|
| BitstreamBuffer bitstream_buffer(
|
| @@ -431,19 +392,25 @@ void GpuVideoDecoder::RequestBufferDecode(
|
| vda_loop_proxy_->PostTask(FROM_HERE, base::Bind(
|
| &VideoDecodeAccelerator::Decode, weak_vda_, bitstream_buffer));
|
|
|
| - if (CanMoreDecodeWorkBeDone()) {
|
| - // Force post here to prevent reentrancy into DemuxerStream.
|
| - gvd_loop_proxy_->PostTask(FROM_HERE, base::Bind(
|
| - &GpuVideoDecoder::EnsureDemuxOrDecode, weak_this_));
|
| + if (!ready_video_frames_.empty()) {
|
| + EnqueueFrameAndTriggerFrameDelivery(NULL);
|
| + return;
|
| }
|
| +
|
| + if (CanMoreDecodeWorkBeDone())
|
| + base::ResetAndReturn(&pending_read_cb_).Run(kNotEnoughData, NULL);
|
| +}
|
| +
|
| +bool GpuVideoDecoder::CanMoreDecodeWorkBeDone() {
|
| + return bitstream_buffers_in_decoder_.size() < kMaxInFlightDecodes;
|
| }
|
|
|
| -void GpuVideoDecoder::RecordBufferData(
|
| - const BitstreamBuffer& bitstream_buffer, const DecoderBuffer& buffer) {
|
| - input_buffer_data_.push_front(BufferData(
|
| - bitstream_buffer.id(), buffer.GetTimestamp(),
|
| - demuxer_stream_->video_decoder_config().visible_rect(),
|
| - demuxer_stream_->video_decoder_config().natural_size()));
|
| +void GpuVideoDecoder::RecordBufferData(const BitstreamBuffer& bitstream_buffer,
|
| + const DecoderBuffer& buffer) {
|
| + input_buffer_data_.push_front(BufferData(bitstream_buffer.id(),
|
| + buffer.GetTimestamp(),
|
| + config_.visible_rect(),
|
| + config_.natural_size()));
|
| // Why this value? Because why not. avformat.h:MAX_REORDER_DELAY is 16, but
|
| // that's too small for some pathological B-frame test videos. The cost of
|
| // using too-high a value is low (192 bits per extra slot).
|
| @@ -492,6 +459,8 @@ void GpuVideoDecoder::NotifyInitializeDone() {
|
| void GpuVideoDecoder::ProvidePictureBuffers(uint32 count,
|
| const gfx::Size& size,
|
| uint32 texture_target) {
|
| + DVLOG(3) << "ProvidePictureBuffers(" << count << ", "
|
| + << size.width() << "x" << size.height() << ")";
|
| DCHECK(gvd_loop_proxy_->BelongsToCurrentThread());
|
|
|
| std::vector<uint32> texture_ids;
|
| @@ -530,6 +499,7 @@ void GpuVideoDecoder::ProvidePictureBuffers(uint32 count,
|
| }
|
|
|
| void GpuVideoDecoder::DismissPictureBuffer(int32 id) {
|
| + DVLOG(3) << "DismissPictureBuffer(" << id << ")";
|
| DCHECK(gvd_loop_proxy_->BelongsToCurrentThread());
|
|
|
| std::map<int32, PictureBuffer>::iterator it =
|
| @@ -559,6 +529,7 @@ void GpuVideoDecoder::DismissPictureBuffer(int32 id) {
|
| }
|
|
|
| void GpuVideoDecoder::PictureReady(const media::Picture& picture) {
|
| + DVLOG(3) << "PictureReady()";
|
| DCHECK(gvd_loop_proxy_->BelongsToCurrentThread());
|
|
|
| std::map<int32, PictureBuffer>::iterator it =
|
| @@ -625,6 +596,7 @@ void GpuVideoDecoder::EnqueueFrameAndTriggerFrameDelivery(
|
|
|
| void GpuVideoDecoder::ReusePictureBuffer(int64 picture_buffer_id,
|
| uint32 sync_point) {
|
| + DVLOG(3) << "ReusePictureBuffer(" << picture_buffer_id << ")";
|
| DCHECK(gvd_loop_proxy_->BelongsToCurrentThread());
|
|
|
| if (!vda_)
|
| @@ -648,7 +620,6 @@ void GpuVideoDecoder::ReusePictureBuffer(int64 picture_buffer_id,
|
| }
|
|
|
| factories_->WaitSyncPoint(sync_point);
|
| -
|
| ++available_pictures_;
|
|
|
| vda_loop_proxy_->PostTask(FROM_HERE, base::Bind(
|
| @@ -678,6 +649,7 @@ void GpuVideoDecoder::PutSHM(SHMBuffer* shm_buffer) {
|
| }
|
|
|
| void GpuVideoDecoder::NotifyEndOfBitstreamBuffer(int32 id) {
|
| + DVLOG(3) << "NotifyEndOfBitstreamBuffer(" << id << ")";
|
| DCHECK(gvd_loop_proxy_->BelongsToCurrentThread());
|
|
|
| std::map<int32, BufferPair>::iterator it =
|
| @@ -698,8 +670,8 @@ void GpuVideoDecoder::NotifyEndOfBitstreamBuffer(int32 id) {
|
| bitstream_buffers_in_decoder_.erase(it);
|
|
|
| if (pending_reset_cb_.is_null() && state_ != kDrainingDecoder &&
|
| - CanMoreDecodeWorkBeDone()) {
|
| - EnsureDemuxOrDecode();
|
| + CanMoreDecodeWorkBeDone() && !pending_read_cb_.is_null()) {
|
| + base::ResetAndReturn(&pending_read_cb_).Run(kNotEnoughData, NULL);
|
| }
|
| }
|
|
|
| @@ -721,22 +693,8 @@ GpuVideoDecoder::~GpuVideoDecoder() {
|
| DestroyTextures();
|
| }
|
|
|
| -void GpuVideoDecoder::EnsureDemuxOrDecode() {
|
| - DCHECK(gvd_loop_proxy_->BelongsToCurrentThread());
|
| -
|
| - // The second condition can happen during the tear-down process.
|
| - // GpuVideoDecoder::Stop() returns the |pending_read_cb_| immediately without
|
| - // waiting for the demuxer read to be returned. Therefore, this function could
|
| - // be called even after the decoder has been stopped.
|
| - if (demuxer_read_in_progress_ || !demuxer_stream_)
|
| - return;
|
| -
|
| - demuxer_read_in_progress_ = true;
|
| - demuxer_stream_->Read(base::Bind(
|
| - &GpuVideoDecoder::RequestBufferDecode, weak_this_));
|
| -}
|
| -
|
| void GpuVideoDecoder::NotifyFlushDone() {
|
| + DVLOG(3) << "NotifyFlushDone()";
|
| DCHECK(gvd_loop_proxy_->BelongsToCurrentThread());
|
| DCHECK_EQ(state_, kDrainingDecoder);
|
| state_ = kDecoderDrained;
|
| @@ -744,6 +702,7 @@ void GpuVideoDecoder::NotifyFlushDone() {
|
| }
|
|
|
| void GpuVideoDecoder::NotifyResetDone() {
|
| + DVLOG(3) << "NotifyResetDone()";
|
| DCHECK(gvd_loop_proxy_->BelongsToCurrentThread());
|
| DCHECK(ready_video_frames_.empty());
|
|
|
|
|