Index: media/filters/gpu_video_decoder.cc |
diff --git a/media/filters/gpu_video_decoder.cc b/media/filters/gpu_video_decoder.cc |
index 8ea4fc68e179e7e819630686061479fb6eced39f..a76a714b399a39211895dcf2f9372e9555f8de92 100644 |
--- a/media/filters/gpu_video_decoder.cc |
+++ b/media/filters/gpu_video_decoder.cc |
@@ -12,7 +12,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,19 +159,18 @@ 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), |
available_pictures_(-1) { |
DCHECK(factories_); |
+ DCHECK(!config_.IsValidConfig()); |
} |
void GpuVideoDecoder::Reset(const base::Closure& closure) { |
@@ -214,7 +212,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 +231,12 @@ 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) { |
DCHECK(gvd_loop_proxy_->BelongsToCurrentThread()); |
- DCHECK(stream); |
+ DCHECK(config.IsValidConfig()); |
+ DCHECK(!config.is_encrypted()); |
weak_this_ = weak_factory_.GetWeakPtr(); |
@@ -246,7 +244,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 +252,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,7 +265,6 @@ void GpuVideoDecoder::Initialize(DemuxerStream* stream, |
return; |
} |
- demuxer_stream_ = stream; |
statistics_cb_ = statistics_cb; |
needs_bitstream_conversion_ = (config.codec() == kCodecH264); |
@@ -295,8 +288,9 @@ void GpuVideoDecoder::SetVDA( |
void GpuVideoDecoder::DestroyTextures() { |
for (std::map<int32, PictureBuffer>::iterator it = |
- picture_buffers_in_decoder_.begin(); |
- it != picture_buffers_in_decoder_.end(); ++it) { |
+ picture_buffers_in_decoder_.begin(); |
+ it != picture_buffers_in_decoder_.end(); |
+ ++it) { |
factories_->DeleteTexture(it->second.texture_id()); |
} |
picture_buffers_in_decoder_.clear(); |
@@ -325,10 +319,12 @@ 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) { |
@@ -336,19 +332,50 @@ void GpuVideoDecoder::Read(const ReadCB& read_cb) { |
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()); |
+ kDecodeError, VideoFrame::CreateEmptyFrame()); |
return; |
} |
- if (!ready_video_frames_.empty()) { |
+ if (!ready_video_frames_.empty()) |
EnqueueFrameAndTriggerFrameDelivery(NULL); |
- return; |
+ |
+ if (buffer->IsEndOfStream()) { |
+ if (state_ == kNormal) { |
+ state_ = kDrainingDecoder; |
+ vda_loop_proxy_->PostTask(FROM_HERE, base::Bind( |
+ &VideoDecodeAccelerator::Flush, weak_vda_)); |
+ } |
+ } else { |
+ size_t size = buffer->GetDataSize(); |
+ SHMBuffer* shm_buffer = GetSHM(size); |
+ if (!shm_buffer) { |
+ state_ = kError; |
+ return; |
+ } |
+ |
+ memcpy(shm_buffer->shm->memory(), buffer->GetData(), size); |
+ BitstreamBuffer bitstream_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); |
+ RecordBufferData(bitstream_buffer, *buffer); |
+ |
+ vda_loop_proxy_->PostTask( |
+ FROM_HERE, |
+ base::Bind( |
+ &VideoDecodeAccelerator::Decode, weak_vda_, bitstream_buffer)); |
+ } |
+ |
+ if (CanMoreDecodeWorkBeDone()) { |
+ base::ResetAndReturn(&pending_read_cb_).Run(kNotEnoughData, NULL); |
} |
+/* |
switch (state_) { |
case kDecoderDrained: |
state_ = kNormal; |
@@ -364,78 +391,19 @@ void GpuVideoDecoder::Read(const ReadCB& read_cb) { |
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) << 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()) { |
- if (state_ == kNormal) { |
- state_ = kDrainingDecoder; |
- vda_loop_proxy_->PostTask(FROM_HERE, base::Bind( |
- &VideoDecodeAccelerator::Flush, weak_vda_)); |
- } |
- return; |
- } |
- |
- if (!pending_reset_cb_.is_null()) |
- return; |
- |
- size_t size = buffer->GetDataSize(); |
- SHMBuffer* shm_buffer = GetSHM(size); |
- if (!shm_buffer) |
- return; |
- |
- memcpy(shm_buffer->shm->memory(), buffer->GetData(), size); |
- BitstreamBuffer bitstream_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); |
- RecordBufferData(bitstream_buffer, *buffer); |
- |
- 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_)); |
- } |
-} |
- |
-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). |
@@ -449,8 +417,8 @@ void GpuVideoDecoder::RecordBufferData( |
void GpuVideoDecoder::GetBufferData(int32 id, base::TimeDelta* timestamp, |
gfx::Rect* visible_rect, |
gfx::Size* natural_size) { |
- for (std::list<BufferData>::const_iterator it = |
- input_buffer_data_.begin(); it != input_buffer_data_.end(); |
+ for (std::list<BufferData>::const_iterator it = input_buffer_data_.begin(); |
+ it != input_buffer_data_.end(); |
++it) { |
if (it->bitstream_buffer_id != id) |
continue; |
@@ -659,21 +627,6 @@ 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() { |
DCHECK(gvd_loop_proxy_->BelongsToCurrentThread()); |
DCHECK_EQ(state_, kDrainingDecoder); |