| Index: media/filters/fake_video_decoder.cc
|
| diff --git a/media/filters/fake_video_decoder.cc b/media/filters/fake_video_decoder.cc
|
| index 3da106525302c31a7458249a7cc3c8e3727fd606..fa36219e6ed52050d517ec0dfe9f40723ef78860 100644
|
| --- a/media/filters/fake_video_decoder.cc
|
| +++ b/media/filters/fake_video_decoder.cc
|
| @@ -14,26 +14,29 @@
|
| namespace media {
|
|
|
| FakeVideoDecoder::FakeVideoDecoder(int decoding_delay,
|
| - bool supports_get_decode_output)
|
| - : task_runner_(base::MessageLoopProxy::current()),
|
| - decoding_delay_(decoding_delay),
|
| + bool supports_get_decode_output,
|
| + int max_parallel_decoding_requests)
|
| + : decoding_delay_(decoding_delay),
|
| supports_get_decode_output_(supports_get_decode_output),
|
| - state_(UNINITIALIZED),
|
| + max_parallel_decoding_requests_(max_parallel_decoding_requests),
|
| + state_(STATE_UNINITIALIZED),
|
| + hold_decode_(false),
|
| total_bytes_decoded_(0),
|
| weak_factory_(this) {
|
| DCHECK_GE(decoding_delay, 0);
|
| }
|
|
|
| FakeVideoDecoder::~FakeVideoDecoder() {
|
| - DCHECK_EQ(state_, UNINITIALIZED);
|
| + DCHECK_EQ(state_, STATE_UNINITIALIZED);
|
| }
|
|
|
| void FakeVideoDecoder::Initialize(const VideoDecoderConfig& config,
|
| bool low_delay,
|
| const PipelineStatusCB& status_cb) {
|
| - DCHECK(task_runner_->BelongsToCurrentThread());
|
| + DCHECK(thread_checker_.CalledOnValidThread());
|
| DCHECK(config.IsValidConfig());
|
| - DCHECK(decode_cb_.IsNull()) << "No reinitialization during pending decode.";
|
| + DCHECK(held_decode_callbacks_.empty())
|
| + << "No reinitialization during pending decode.";
|
| DCHECK(reset_cb_.IsNull()) << "No reinitialization during pending reset.";
|
|
|
| current_config_ = config;
|
| @@ -44,74 +47,73 @@ void FakeVideoDecoder::Initialize(const VideoDecoderConfig& config,
|
| decoded_frames_.clear();
|
| }
|
|
|
| - state_ = NORMAL;
|
| + state_ = STATE_NORMAL;
|
| init_cb_.RunOrHold(PIPELINE_OK);
|
| }
|
|
|
| void FakeVideoDecoder::Decode(const scoped_refptr<DecoderBuffer>& buffer,
|
| const DecodeCB& decode_cb) {
|
| - DCHECK(task_runner_->BelongsToCurrentThread());
|
| - DCHECK(decode_cb_.IsNull()) << "Overlapping decodes are not supported.";
|
| + DCHECK(thread_checker_.CalledOnValidThread());
|
| DCHECK(reset_cb_.IsNull());
|
| - DCHECK_LE(decoded_frames_.size(), static_cast<size_t>(decoding_delay_));
|
| + DCHECK_LE(decoded_frames_.size(),
|
| + decoding_delay_ + held_decode_callbacks_.size());
|
| + DCHECK_LT(static_cast<int>(held_decode_callbacks_.size()),
|
| + max_parallel_decoding_requests_);
|
|
|
| int buffer_size = buffer->end_of_stream() ? 0 : buffer->data_size();
|
| - decode_cb_.SetCallback(
|
| + DecodeCB wrapped_decode_cb =
|
| BindToCurrentLoop(base::Bind(&FakeVideoDecoder::OnFrameDecoded,
|
| weak_factory_.GetWeakPtr(),
|
| buffer_size,
|
| - decode_cb)));
|
| + decode_cb));
|
|
|
| - if (buffer->end_of_stream() && decoded_frames_.empty()) {
|
| - decode_cb_.RunOrHold(kOk, VideoFrame::CreateEOSFrame());
|
| + if (state_ == STATE_ERROR) {
|
| + wrapped_decode_cb.Run(kDecodeError, scoped_refptr<VideoFrame>());
|
| return;
|
| }
|
|
|
| - if (!buffer->end_of_stream()) {
|
| + if (buffer->end_of_stream()) {
|
| + state_ = STATE_END_OF_STREAM;
|
| + } else {
|
| DCHECK(VerifyFakeVideoBufferForTest(buffer, current_config_));
|
| scoped_refptr<VideoFrame> video_frame = VideoFrame::CreateColorFrame(
|
| current_config_.coded_size(), 0, 0, 0, buffer->timestamp());
|
| decoded_frames_.push_back(video_frame);
|
| -
|
| - if (decoded_frames_.size() <= static_cast<size_t>(decoding_delay_)) {
|
| - decode_cb_.RunOrHold(kNotEnoughData, scoped_refptr<VideoFrame>());
|
| - return;
|
| - }
|
| }
|
|
|
| - scoped_refptr<VideoFrame> frame = decoded_frames_.front();
|
| - decoded_frames_.pop_front();
|
| - decode_cb_.RunOrHold(kOk, frame);
|
| + RunOrHoldDecode(wrapped_decode_cb);
|
| }
|
|
|
| void FakeVideoDecoder::Reset(const base::Closure& closure) {
|
| - DCHECK(task_runner_->BelongsToCurrentThread());
|
| + DCHECK(thread_checker_.CalledOnValidThread());
|
| DCHECK(reset_cb_.IsNull());
|
| +
|
| reset_cb_.SetCallback(BindToCurrentLoop(closure));
|
| + decoded_frames_.clear();
|
|
|
| // Defer the reset if a decode is pending.
|
| - if (!decode_cb_.IsNull())
|
| + if (!held_decode_callbacks_.empty())
|
| return;
|
|
|
| DoReset();
|
| }
|
|
|
| void FakeVideoDecoder::Stop() {
|
| - DCHECK(task_runner_->BelongsToCurrentThread());
|
| + DCHECK(thread_checker_.CalledOnValidThread());
|
|
|
| if (!init_cb_.IsNull())
|
| SatisfyInit();
|
| - if (!decode_cb_.IsNull())
|
| + if (!held_decode_callbacks_.empty())
|
| SatisfyDecode();
|
| if (!reset_cb_.IsNull())
|
| SatisfyReset();
|
|
|
| decoded_frames_.clear();
|
| - state_ = UNINITIALIZED;
|
| + state_ = STATE_UNINITIALIZED;
|
| }
|
|
|
| scoped_refptr<VideoFrame> FakeVideoDecoder::GetDecodeOutput() {
|
| - DCHECK(task_runner_->BelongsToCurrentThread());
|
| + DCHECK(thread_checker_.CalledOnValidThread());
|
| if (!supports_get_decode_output_ || decoded_frames_.empty())
|
| return NULL;
|
| scoped_refptr<VideoFrame> out = decoded_frames_.front();
|
| @@ -120,49 +122,71 @@ scoped_refptr<VideoFrame> FakeVideoDecoder::GetDecodeOutput() {
|
| }
|
|
|
| void FakeVideoDecoder::HoldNextInit() {
|
| - DCHECK(task_runner_->BelongsToCurrentThread());
|
| + DCHECK(thread_checker_.CalledOnValidThread());
|
| init_cb_.HoldCallback();
|
| }
|
|
|
| -void FakeVideoDecoder::HoldNextDecode() {
|
| - DCHECK(task_runner_->BelongsToCurrentThread());
|
| - decode_cb_.HoldCallback();
|
| +void FakeVideoDecoder::HoldDecode() {
|
| + DCHECK(thread_checker_.CalledOnValidThread());
|
| + hold_decode_ = true;
|
| }
|
|
|
| void FakeVideoDecoder::HoldNextReset() {
|
| - DCHECK(task_runner_->BelongsToCurrentThread());
|
| + DCHECK(thread_checker_.CalledOnValidThread());
|
| reset_cb_.HoldCallback();
|
| }
|
|
|
| void FakeVideoDecoder::SatisfyInit() {
|
| - DCHECK(task_runner_->BelongsToCurrentThread());
|
| - DCHECK(decode_cb_.IsNull());
|
| + DCHECK(thread_checker_.CalledOnValidThread());
|
| + DCHECK(held_decode_callbacks_.empty());
|
| DCHECK(reset_cb_.IsNull());
|
|
|
| init_cb_.RunHeldCallback();
|
| }
|
|
|
| void FakeVideoDecoder::SatisfyDecode() {
|
| - DCHECK(task_runner_->BelongsToCurrentThread());
|
| - decode_cb_.RunHeldCallback();
|
| + DCHECK(thread_checker_.CalledOnValidThread());
|
| + DCHECK(hold_decode_);
|
|
|
| - if (!reset_cb_.IsNull())
|
| + hold_decode_ = false;
|
| +
|
| + while (!held_decode_callbacks_.empty()) {
|
| + SatisfySingleDecode();
|
| + }
|
| +}
|
| +
|
| +void FakeVideoDecoder::SatisfySingleDecode() {
|
| + DCHECK(thread_checker_.CalledOnValidThread());
|
| + DCHECK(!held_decode_callbacks_.empty());
|
| +
|
| + DecodeCB decode_cb = held_decode_callbacks_.front();
|
| + held_decode_callbacks_.pop_front();
|
| + RunDecodeCallback(decode_cb);
|
| +
|
| + if (!reset_cb_.IsNull() && held_decode_callbacks_.empty())
|
| DoReset();
|
| }
|
|
|
| void FakeVideoDecoder::SatisfyReset() {
|
| - DCHECK(task_runner_->BelongsToCurrentThread());
|
| - DCHECK(decode_cb_.IsNull());
|
| + DCHECK(thread_checker_.CalledOnValidThread());
|
| + DCHECK(held_decode_callbacks_.empty());
|
| reset_cb_.RunHeldCallback();
|
| }
|
|
|
| -void FakeVideoDecoder::DoReset() {
|
| - DCHECK(task_runner_->BelongsToCurrentThread());
|
| - DCHECK(decode_cb_.IsNull());
|
| - DCHECK(!reset_cb_.IsNull());
|
| +void FakeVideoDecoder::SimulateError() {
|
| + DCHECK(thread_checker_.CalledOnValidThread());
|
|
|
| + state_ = STATE_ERROR;
|
| + while (!held_decode_callbacks_.empty()) {
|
| + held_decode_callbacks_.front().Run(kDecodeError,
|
| + scoped_refptr<VideoFrame>());
|
| + held_decode_callbacks_.pop_front();
|
| + }
|
| decoded_frames_.clear();
|
| - reset_cb_.RunOrHold();
|
| +}
|
| +
|
| +int FakeVideoDecoder::GetMaxDecodeRequests() const {
|
| + return max_parallel_decoding_requests_;
|
| }
|
|
|
| void FakeVideoDecoder::OnFrameDecoded(
|
| @@ -170,9 +194,59 @@ void FakeVideoDecoder::OnFrameDecoded(
|
| const DecodeCB& decode_cb,
|
| Status status,
|
| const scoped_refptr<VideoFrame>& video_frame) {
|
| + DCHECK(thread_checker_.CalledOnValidThread());
|
| +
|
| if (status == kOk || status == kNotEnoughData)
|
| total_bytes_decoded_ += buffer_size;
|
| decode_cb.Run(status, video_frame);
|
| }
|
|
|
| +void FakeVideoDecoder::RunOrHoldDecode(const DecodeCB& decode_cb) {
|
| + DCHECK(thread_checker_.CalledOnValidThread());
|
| +
|
| + if (hold_decode_) {
|
| + held_decode_callbacks_.push_back(decode_cb);
|
| + } else {
|
| + DCHECK(held_decode_callbacks_.empty());
|
| + RunDecodeCallback(decode_cb);
|
| + }
|
| +}
|
| +
|
| +void FakeVideoDecoder::RunDecodeCallback(const DecodeCB& decode_cb) {
|
| + DCHECK(thread_checker_.CalledOnValidThread());
|
| +
|
| + if (!reset_cb_.IsNull()) {
|
| + DCHECK(decoded_frames_.empty());
|
| + decode_cb.Run(kAborted, scoped_refptr<VideoFrame>());
|
| + return;
|
| + }
|
| +
|
| + // Make sure we leave decoding_delay_ frames in the queue and also frames for
|
| + // all pending decode callbacks, except the current one.
|
| + if (decoded_frames_.size() <=
|
| + decoding_delay_ + held_decode_callbacks_.size() &&
|
| + state_ != STATE_END_OF_STREAM) {
|
| + decode_cb.Run(kNotEnoughData, scoped_refptr<VideoFrame>());
|
| + return;
|
| + }
|
| +
|
| + scoped_refptr<VideoFrame> frame;
|
| + if (decoded_frames_.empty()) {
|
| + DCHECK_EQ(state_, STATE_END_OF_STREAM);
|
| + frame = VideoFrame::CreateEOSFrame();
|
| + } else {
|
| + frame = decoded_frames_.front();
|
| + decoded_frames_.pop_front();
|
| + }
|
| + decode_cb.Run(kOk, frame);
|
| +}
|
| +
|
| +void FakeVideoDecoder::DoReset() {
|
| + DCHECK(thread_checker_.CalledOnValidThread());
|
| + DCHECK(held_decode_callbacks_.empty());
|
| + DCHECK(!reset_cb_.IsNull());
|
| +
|
| + reset_cb_.RunOrHold();
|
| +}
|
| +
|
| } // namespace media
|
|
|