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