Home | History | Annotate | Download | only in filters
      1 // Copyright 2013 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "media/filters/fake_video_decoder.h"
      6 
      7 #include "base/bind.h"
      8 #include "base/callback_helpers.h"
      9 #include "base/location.h"
     10 #include "base/message_loop/message_loop_proxy.h"
     11 #include "media/base/bind_to_loop.h"
     12 #include "media/base/test_helpers.h"
     13 
     14 namespace media {
     15 
     16 FakeVideoDecoder::FakeVideoDecoder(int decoding_delay)
     17     : message_loop_(base::MessageLoopProxy::current()),
     18       weak_factory_(this),
     19       decoding_delay_(decoding_delay),
     20       state_(UNINITIALIZED),
     21       total_bytes_decoded_(0) {
     22   DCHECK_GE(decoding_delay, 0);
     23 }
     24 
     25 FakeVideoDecoder::~FakeVideoDecoder() {
     26   DCHECK_EQ(state_, UNINITIALIZED);
     27 }
     28 
     29 void FakeVideoDecoder::Initialize(const VideoDecoderConfig& config,
     30                                   const PipelineStatusCB& status_cb) {
     31   DCHECK(message_loop_->BelongsToCurrentThread());
     32   DCHECK(config.IsValidConfig());
     33   DCHECK(decode_cb_.IsNull()) << "No reinitialization during pending decode.";
     34   DCHECK(reset_cb_.IsNull()) << "No reinitialization during pending reset.";
     35 
     36   weak_this_ = weak_factory_.GetWeakPtr();
     37 
     38   current_config_ = config;
     39   init_cb_.SetCallback(BindToCurrentLoop(status_cb));
     40 
     41   if (!decoded_frames_.empty()) {
     42     DVLOG(1) << "Decoded frames dropped during reinitialization.";
     43     decoded_frames_.clear();
     44   }
     45 
     46   state_ = NORMAL;
     47   init_cb_.RunOrHold(PIPELINE_OK);
     48 }
     49 
     50 void FakeVideoDecoder::Decode(const scoped_refptr<DecoderBuffer>& buffer,
     51                               const DecodeCB& decode_cb) {
     52   DCHECK(message_loop_->BelongsToCurrentThread());
     53   DCHECK(decode_cb_.IsNull()) << "Overlapping decodes are not supported.";
     54   DCHECK(reset_cb_.IsNull());
     55   DCHECK_LE(decoded_frames_.size(), static_cast<size_t>(decoding_delay_));
     56 
     57   int buffer_size = buffer->end_of_stream() ? 0 : buffer->data_size();
     58   decode_cb_.SetCallback(BindToCurrentLoop(base::Bind(
     59       &FakeVideoDecoder::OnFrameDecoded, weak_this_, buffer_size, decode_cb)));
     60 
     61   if (buffer->end_of_stream() && decoded_frames_.empty()) {
     62     decode_cb_.RunOrHold(kOk, VideoFrame::CreateEmptyFrame());
     63     return;
     64   }
     65 
     66   if (!buffer->end_of_stream()) {
     67     DCHECK(VerifyFakeVideoBufferForTest(buffer, current_config_));
     68     scoped_refptr<VideoFrame> video_frame = VideoFrame::CreateColorFrame(
     69         current_config_.coded_size(), 0, 0, 0, buffer->timestamp());
     70     decoded_frames_.push_back(video_frame);
     71 
     72     if (decoded_frames_.size() <= static_cast<size_t>(decoding_delay_)) {
     73       decode_cb_.RunOrHold(kNotEnoughData, scoped_refptr<VideoFrame>());
     74       return;
     75     }
     76   }
     77 
     78   scoped_refptr<VideoFrame> frame = decoded_frames_.front();
     79   decoded_frames_.pop_front();
     80   decode_cb_.RunOrHold(kOk, frame);
     81 }
     82 
     83 void FakeVideoDecoder::Reset(const base::Closure& closure) {
     84   DCHECK(message_loop_->BelongsToCurrentThread());
     85   DCHECK(reset_cb_.IsNull());
     86   reset_cb_.SetCallback(BindToCurrentLoop(closure));
     87 
     88   // Defer the reset if a decode is pending.
     89   if (!decode_cb_.IsNull())
     90     return;
     91 
     92   DoReset();
     93 }
     94 
     95 void FakeVideoDecoder::Stop(const base::Closure& closure) {
     96   DCHECK(message_loop_->BelongsToCurrentThread());
     97   stop_cb_.SetCallback(BindToCurrentLoop(closure));
     98 
     99   // Defer the stop if an init, a decode or a reset is pending.
    100   if (!init_cb_.IsNull() || !decode_cb_.IsNull() || !reset_cb_.IsNull())
    101     return;
    102 
    103   DoStop();
    104 }
    105 
    106 void FakeVideoDecoder::HoldNextInit() {
    107   DCHECK(message_loop_->BelongsToCurrentThread());
    108   init_cb_.HoldCallback();
    109 }
    110 
    111 void FakeVideoDecoder::HoldNextRead() {
    112   DCHECK(message_loop_->BelongsToCurrentThread());
    113   decode_cb_.HoldCallback();
    114 }
    115 
    116 void FakeVideoDecoder::HoldNextReset() {
    117   DCHECK(message_loop_->BelongsToCurrentThread());
    118   reset_cb_.HoldCallback();
    119 }
    120 
    121 void FakeVideoDecoder::HoldNextStop() {
    122   DCHECK(message_loop_->BelongsToCurrentThread());
    123   stop_cb_.HoldCallback();
    124 }
    125 
    126 void FakeVideoDecoder::SatisfyInit() {
    127   DCHECK(message_loop_->BelongsToCurrentThread());
    128   DCHECK(decode_cb_.IsNull());
    129   DCHECK(reset_cb_.IsNull());
    130 
    131   init_cb_.RunHeldCallback();
    132 
    133   if (!stop_cb_.IsNull())
    134     DoStop();
    135 }
    136 
    137 void FakeVideoDecoder::SatisfyRead() {
    138   DCHECK(message_loop_->BelongsToCurrentThread());
    139   decode_cb_.RunHeldCallback();
    140 
    141   if (!reset_cb_.IsNull())
    142     DoReset();
    143 
    144   if (reset_cb_.IsNull() && !stop_cb_.IsNull())
    145     DoStop();
    146 }
    147 
    148 void FakeVideoDecoder::SatisfyReset() {
    149   DCHECK(message_loop_->BelongsToCurrentThread());
    150   DCHECK(decode_cb_.IsNull());
    151   reset_cb_.RunHeldCallback();
    152 
    153   if (!stop_cb_.IsNull())
    154     DoStop();
    155 }
    156 
    157 void FakeVideoDecoder::SatisfyStop() {
    158   DCHECK(message_loop_->BelongsToCurrentThread());
    159   DCHECK(decode_cb_.IsNull());
    160   DCHECK(reset_cb_.IsNull());
    161   stop_cb_.RunHeldCallback();
    162 }
    163 
    164 void FakeVideoDecoder::DoReset() {
    165   DCHECK(message_loop_->BelongsToCurrentThread());
    166   DCHECK(decode_cb_.IsNull());
    167   DCHECK(!reset_cb_.IsNull());
    168 
    169   decoded_frames_.clear();
    170   reset_cb_.RunOrHold();
    171 }
    172 
    173 void FakeVideoDecoder::DoStop() {
    174   DCHECK(message_loop_->BelongsToCurrentThread());
    175   DCHECK(decode_cb_.IsNull());
    176   DCHECK(reset_cb_.IsNull());
    177   DCHECK(!stop_cb_.IsNull());
    178 
    179   state_ = UNINITIALIZED;
    180   decoded_frames_.clear();
    181   stop_cb_.RunOrHold();
    182 }
    183 
    184 void FakeVideoDecoder::OnFrameDecoded(
    185     int buffer_size,
    186     const DecodeCB& decode_cb,
    187     Status status,
    188     const scoped_refptr<VideoFrame>& video_frame) {
    189   if (status == kOk || status == kNotEnoughData)
    190     total_bytes_decoded_ += buffer_size;
    191   decode_cb.Run(status, video_frame);
    192 }
    193 
    194 }  // namespace media
    195