| Index: media/filters/fake_video_decoder.cc | 
| diff --git a/media/filters/fake_video_decoder.cc b/media/filters/fake_video_decoder.cc | 
| new file mode 100644 | 
| index 0000000000000000000000000000000000000000..b5039d51724c177e963868afcdd956c55979cc2b | 
| --- /dev/null | 
| +++ b/media/filters/fake_video_decoder.cc | 
| @@ -0,0 +1,235 @@ | 
| +// Copyright (c) 2013 The Chromium Authors. All rights reserved. | 
| +// Use of this source code is governed by a BSD-style license that can be | 
| +// found in the LICENSE file. | 
| + | 
| +#include "media/filters/fake_video_decoder.h" | 
| + | 
| +#include "base/bind.h" | 
| +#include "base/callback_helpers.h" | 
| +#include "base/location.h" | 
| +#include "base/message_loop_proxy.h" | 
| +#include "media/base/bind_to_loop.h" | 
| +#include "media/base/demuxer_stream.h" | 
| + | 
| +namespace media { | 
| + | 
| +FakeVideoDecoder::FakeVideoDecoder(int decoding_delay) | 
| +    : message_loop_(base::MessageLoopProxy::current()), | 
| +      weak_factory_(this), | 
| +      decoding_delay_(decoding_delay), | 
| +      state_(UNINITIALIZED), | 
| +      demuxer_stream_(NULL) { | 
| +  DCHECK_GE(decoding_delay, 0); | 
| +} | 
| + | 
| +FakeVideoDecoder::~FakeVideoDecoder() { | 
| +  DCHECK_EQ(state_, UNINITIALIZED); | 
| +} | 
| + | 
| +void FakeVideoDecoder::Initialize(DemuxerStream* stream, | 
| +                                  const PipelineStatusCB& status_cb, | 
| +                                  const StatisticsCB& statistics_cb) { | 
| +  DCHECK(message_loop_->BelongsToCurrentThread()); | 
| +  DCHECK(stream); | 
| +  DCHECK(stream->video_decoder_config().IsValidConfig()); | 
| +  DCHECK(read_cb_.IsNull()) << "No reinitialization during pending read."; | 
| +  DCHECK(reset_cb_.IsNull()) << "No reinitialization during pending reset."; | 
| + | 
| +  weak_this_ = weak_factory_.GetWeakPtr(); | 
| + | 
| +  demuxer_stream_ = stream; | 
| +  statistics_cb_ = statistics_cb; | 
| +  current_config_ = stream->video_decoder_config(); | 
| +  init_cb_.SetCallback(BindToCurrentLoop(status_cb)); | 
| + | 
| +  if (!decoded_frames_.empty()) { | 
| +    DVLOG(1) << "Decoded frames dropped during reinitialization."; | 
| +    decoded_frames_.clear(); | 
| +  } | 
| + | 
| +  state_ = NORMAL; | 
| +  init_cb_.RunOrHold(PIPELINE_OK); | 
| +} | 
| + | 
| +void FakeVideoDecoder::Read(const ReadCB& read_cb) { | 
| +  DCHECK(message_loop_->BelongsToCurrentThread()); | 
| +  DCHECK(read_cb_.IsNull()) << "Overlapping decodes are not supported."; | 
| +  DCHECK(reset_cb_.IsNull()); | 
| +  DCHECK_LE(decoded_frames_.size(), static_cast<size_t>(decoding_delay_)); | 
| + | 
| +  read_cb_.SetCallback(BindToCurrentLoop(read_cb)); | 
| +  ReadFromDemuxerStream(); | 
| +} | 
| + | 
| +void FakeVideoDecoder::Reset(const base::Closure& closure) { | 
| +  DCHECK(message_loop_->BelongsToCurrentThread()); | 
| +  DCHECK(reset_cb_.IsNull()); | 
| +  reset_cb_.SetCallback(BindToCurrentLoop(closure)); | 
| + | 
| +  // Defer the reset if a read is pending. | 
| +  if (!read_cb_.IsNull()) | 
| +    return; | 
| + | 
| +  DoReset(); | 
| +} | 
| + | 
| +void FakeVideoDecoder::Stop(const base::Closure& closure) { | 
| +  DCHECK(message_loop_->BelongsToCurrentThread()); | 
| +  stop_cb_.SetCallback(BindToCurrentLoop(closure)); | 
| + | 
| +  // Defer the reset if a read and/or a reset is pending. | 
| +  if (!read_cb_.IsNull() || !reset_cb_.IsNull()) | 
| +    return; | 
| + | 
| +  DoStop(); | 
| +} | 
| + | 
| +void FakeVideoDecoder::HoldNextInit() { | 
| +  DCHECK(message_loop_->BelongsToCurrentThread()); | 
| +  init_cb_.HoldCallback(); | 
| +} | 
| + | 
| +void FakeVideoDecoder::HoldNextRead() { | 
| +  DCHECK(message_loop_->BelongsToCurrentThread()); | 
| +  read_cb_.HoldCallback(); | 
| +} | 
| + | 
| +void FakeVideoDecoder::HoldNextReset() { | 
| +  DCHECK(message_loop_->BelongsToCurrentThread()); | 
| +  reset_cb_.HoldCallback(); | 
| +} | 
| + | 
| +void FakeVideoDecoder::HoldNextStop() { | 
| +  DCHECK(message_loop_->BelongsToCurrentThread()); | 
| +  stop_cb_.HoldCallback(); | 
| +} | 
| + | 
| +void FakeVideoDecoder::SatisfyInit() { | 
| +  DCHECK(message_loop_->BelongsToCurrentThread()); | 
| +  DCHECK(read_cb_.IsNull()); | 
| +  DCHECK(reset_cb_.IsNull()); | 
| + | 
| +  init_cb_.RunHeldCallback(); | 
| + | 
| +  if (!stop_cb_.IsNull()) | 
| +    DoStop(); | 
| +} | 
| + | 
| +void FakeVideoDecoder::SatisfyRead() { | 
| +  DCHECK(message_loop_->BelongsToCurrentThread()); | 
| +  read_cb_.RunHeldCallback(); | 
| + | 
| +  if (!reset_cb_.IsNull()) | 
| +    DoReset(); | 
| + | 
| +  if (reset_cb_.IsNull() && !stop_cb_.IsNull()) | 
| +    DoStop(); | 
| +} | 
| + | 
| +void FakeVideoDecoder::SatisfyReset() { | 
| +  DCHECK(message_loop_->BelongsToCurrentThread()); | 
| +  DCHECK(read_cb_.IsNull()); | 
| +  reset_cb_.RunHeldCallback(); | 
| + | 
| +  if (!stop_cb_.IsNull()) | 
| +    DoStop(); | 
| +} | 
| + | 
| +void FakeVideoDecoder::SatisfyStop() { | 
| +  DCHECK(message_loop_->BelongsToCurrentThread()); | 
| +  DCHECK(read_cb_.IsNull()); | 
| +  DCHECK(reset_cb_.IsNull()); | 
| +  stop_cb_.RunHeldCallback(); | 
| +} | 
| + | 
| +void FakeVideoDecoder::ReadFromDemuxerStream() { | 
| +  DCHECK_EQ(state_, NORMAL); | 
| +  DCHECK(!read_cb_.IsNull()); | 
| +  demuxer_stream_->Read(base::Bind(&FakeVideoDecoder::BufferReady, weak_this_)); | 
| +} | 
| + | 
| +void FakeVideoDecoder::BufferReady(DemuxerStream::Status status, | 
| +                                   const scoped_refptr<DecoderBuffer>& buffer) { | 
| +  DCHECK(message_loop_->BelongsToCurrentThread()); | 
| +  DCHECK_EQ(state_, NORMAL); | 
| +  DCHECK(!read_cb_.IsNull()); | 
| +  DCHECK_EQ(status != DemuxerStream::kOk, !buffer) << status; | 
| + | 
| +  if (!stop_cb_.IsNull()) { | 
| +    read_cb_.RunOrHold(kOk, scoped_refptr<VideoFrame>()); | 
| +    if (!reset_cb_.IsNull()) { | 
| +      DoReset(); | 
| +    } | 
| +    DoStop(); | 
| +    return; | 
| +  } | 
| + | 
| +  if (status == DemuxerStream::kConfigChanged) { | 
| +    DCHECK(demuxer_stream_->video_decoder_config().IsValidConfig()); | 
| +    current_config_ = demuxer_stream_->video_decoder_config(); | 
| + | 
| +    if (reset_cb_.IsNull()) { | 
| +      ReadFromDemuxerStream(); | 
| +      return; | 
| +    } | 
| +  } | 
| + | 
| +  if (!reset_cb_.IsNull()) { | 
| +    read_cb_.RunOrHold(kOk, scoped_refptr<VideoFrame>()); | 
| +    DoReset(); | 
| +    return; | 
| +  } | 
| + | 
| +  if (status == DemuxerStream::kAborted) { | 
| +    read_cb_.RunOrHold(kOk, scoped_refptr<VideoFrame>()); | 
| +    return; | 
| +  } | 
| + | 
| +  DCHECK_EQ(status, DemuxerStream::kOk); | 
| + | 
| +  // Make sure the decoder is always configured with the latest config. | 
| +  DCHECK(current_config_.Matches(demuxer_stream_->video_decoder_config())); | 
| + | 
| +  if (buffer->IsEndOfStream() && decoded_frames_.empty()) { | 
| +    read_cb_.RunOrHold(kOk, VideoFrame::CreateEmptyFrame()); | 
| +    return; | 
| +  } | 
| + | 
| +  if (!buffer->IsEndOfStream()) { | 
| +    scoped_refptr<VideoFrame> video_frame = VideoFrame::CreateColorFrame( | 
| +        current_config_.coded_size(), 0, 0, 0, buffer->GetTimestamp()); | 
| +    decoded_frames_.push_back(video_frame); | 
| + | 
| +    if (decoded_frames_.size() <= static_cast<size_t>(decoding_delay_)) { | 
| +      ReadFromDemuxerStream(); | 
| +      return; | 
| +    } | 
| +  } | 
| + | 
| +  scoped_refptr<VideoFrame> frame = decoded_frames_.front(); | 
| +  decoded_frames_.pop_front(); | 
| +  read_cb_.RunOrHold(kOk, frame); | 
| +} | 
| + | 
| +void FakeVideoDecoder::DoReset() { | 
| +  DCHECK(message_loop_->BelongsToCurrentThread()); | 
| +  DCHECK(read_cb_.IsNull()); | 
| +  DCHECK(!reset_cb_.IsNull()); | 
| + | 
| +  decoded_frames_.clear(); | 
| +  reset_cb_.RunOrHold(); | 
| +} | 
| + | 
| +void FakeVideoDecoder::DoStop() { | 
| +  DCHECK(message_loop_->BelongsToCurrentThread()); | 
| +  DCHECK(read_cb_.IsNull()); | 
| +  DCHECK(reset_cb_.IsNull()); | 
| +  DCHECK(!stop_cb_.IsNull()); | 
| + | 
| +  state_ = UNINITIALIZED; | 
| +  demuxer_stream_ = NULL; | 
| +  decoded_frames_.clear(); | 
| +  stop_cb_.RunOrHold(); | 
| +} | 
| + | 
| +}  // namespace media | 
|  |