1 // Copyright (c) 2012 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/base/test_helpers.h" 6 7 #include "base/bind.h" 8 #include "base/logging.h" 9 #include "base/message_loop/message_loop.h" 10 #include "base/pickle.h" 11 #include "base/test/test_timeouts.h" 12 #include "base/time/time.h" 13 #include "base/timer/timer.h" 14 #include "media/base/audio_buffer.h" 15 #include "media/base/bind_to_current_loop.h" 16 #include "media/base/decoder_buffer.h" 17 #include "ui/gfx/rect.h" 18 19 using ::testing::_; 20 using ::testing::StrictMock; 21 22 namespace media { 23 24 // Utility mock for testing methods expecting Closures and PipelineStatusCBs. 25 class MockCallback : public base::RefCountedThreadSafe<MockCallback> { 26 public: 27 MockCallback(); 28 MOCK_METHOD0(Run, void()); 29 MOCK_METHOD1(RunWithStatus, void(PipelineStatus)); 30 31 protected: 32 friend class base::RefCountedThreadSafe<MockCallback>; 33 virtual ~MockCallback(); 34 35 private: 36 DISALLOW_COPY_AND_ASSIGN(MockCallback); 37 }; 38 39 MockCallback::MockCallback() {} 40 MockCallback::~MockCallback() {} 41 42 base::Closure NewExpectedClosure() { 43 StrictMock<MockCallback>* callback = new StrictMock<MockCallback>(); 44 EXPECT_CALL(*callback, Run()); 45 return base::Bind(&MockCallback::Run, callback); 46 } 47 48 PipelineStatusCB NewExpectedStatusCB(PipelineStatus status) { 49 StrictMock<MockCallback>* callback = new StrictMock<MockCallback>(); 50 EXPECT_CALL(*callback, RunWithStatus(status)); 51 return base::Bind(&MockCallback::RunWithStatus, callback); 52 } 53 54 WaitableMessageLoopEvent::WaitableMessageLoopEvent() 55 : message_loop_(base::MessageLoop::current()), 56 signaled_(false), 57 status_(PIPELINE_OK) { 58 DCHECK(message_loop_); 59 } 60 61 WaitableMessageLoopEvent::~WaitableMessageLoopEvent() {} 62 63 base::Closure WaitableMessageLoopEvent::GetClosure() { 64 DCHECK_EQ(message_loop_, base::MessageLoop::current()); 65 return BindToCurrentLoop(base::Bind( 66 &WaitableMessageLoopEvent::OnCallback, base::Unretained(this), 67 PIPELINE_OK)); 68 } 69 70 PipelineStatusCB WaitableMessageLoopEvent::GetPipelineStatusCB() { 71 DCHECK_EQ(message_loop_, base::MessageLoop::current()); 72 return BindToCurrentLoop(base::Bind( 73 &WaitableMessageLoopEvent::OnCallback, base::Unretained(this))); 74 } 75 76 void WaitableMessageLoopEvent::RunAndWait() { 77 RunAndWaitForStatus(PIPELINE_OK); 78 } 79 80 void WaitableMessageLoopEvent::RunAndWaitForStatus(PipelineStatus expected) { 81 DCHECK_EQ(message_loop_, base::MessageLoop::current()); 82 if (signaled_) { 83 EXPECT_EQ(expected, status_); 84 return; 85 } 86 87 base::Timer timer(false, false); 88 timer.Start(FROM_HERE, TestTimeouts::action_timeout(), base::Bind( 89 &WaitableMessageLoopEvent::OnTimeout, base::Unretained(this))); 90 91 message_loop_->Run(); 92 EXPECT_TRUE(signaled_); 93 EXPECT_EQ(expected, status_); 94 } 95 96 void WaitableMessageLoopEvent::OnCallback(PipelineStatus status) { 97 DCHECK_EQ(message_loop_, base::MessageLoop::current()); 98 signaled_ = true; 99 status_ = status; 100 message_loop_->QuitWhenIdle(); 101 } 102 103 void WaitableMessageLoopEvent::OnTimeout() { 104 DCHECK_EQ(message_loop_, base::MessageLoop::current()); 105 ADD_FAILURE() << "Timed out waiting for message loop to quit"; 106 message_loop_->QuitWhenIdle(); 107 } 108 109 static VideoDecoderConfig GetTestConfig(VideoCodec codec, 110 gfx::Size coded_size, 111 bool is_encrypted) { 112 gfx::Rect visible_rect(coded_size.width(), coded_size.height()); 113 gfx::Size natural_size = coded_size; 114 115 return VideoDecoderConfig(codec, VIDEO_CODEC_PROFILE_UNKNOWN, 116 VideoFrame::YV12, coded_size, visible_rect, natural_size, 117 NULL, 0, is_encrypted); 118 } 119 120 static const gfx::Size kNormalSize(320, 240); 121 static const gfx::Size kLargeSize(640, 480); 122 123 VideoDecoderConfig TestVideoConfig::Invalid() { 124 return GetTestConfig(kUnknownVideoCodec, kNormalSize, false); 125 } 126 127 VideoDecoderConfig TestVideoConfig::Normal() { 128 return GetTestConfig(kCodecVP8, kNormalSize, false); 129 } 130 131 VideoDecoderConfig TestVideoConfig::NormalEncrypted() { 132 return GetTestConfig(kCodecVP8, kNormalSize, true); 133 } 134 135 VideoDecoderConfig TestVideoConfig::Large() { 136 return GetTestConfig(kCodecVP8, kLargeSize, false); 137 } 138 139 VideoDecoderConfig TestVideoConfig::LargeEncrypted() { 140 return GetTestConfig(kCodecVP8, kLargeSize, true); 141 } 142 143 gfx::Size TestVideoConfig::NormalCodedSize() { 144 return kNormalSize; 145 } 146 147 gfx::Size TestVideoConfig::LargeCodedSize() { 148 return kLargeSize; 149 } 150 151 template <class T> 152 scoped_refptr<AudioBuffer> MakeAudioBuffer(SampleFormat format, 153 ChannelLayout channel_layout, 154 size_t channel_count, 155 int sample_rate, 156 T start, 157 T increment, 158 size_t frames, 159 base::TimeDelta timestamp) { 160 const size_t channels = ChannelLayoutToChannelCount(channel_layout); 161 scoped_refptr<AudioBuffer> output = 162 AudioBuffer::CreateBuffer(format, 163 channel_layout, 164 static_cast<int>(channel_count), 165 sample_rate, 166 static_cast<int>(frames)); 167 output->set_timestamp(timestamp); 168 169 const bool is_planar = 170 format == kSampleFormatPlanarS16 || format == kSampleFormatPlanarF32; 171 172 // Values in channel 0 will be: 173 // start 174 // start + increment 175 // start + 2 * increment, ... 176 // While, values in channel 1 will be: 177 // start + frames * increment 178 // start + (frames + 1) * increment 179 // start + (frames + 2) * increment, ... 180 for (size_t ch = 0; ch < channels; ++ch) { 181 T* buffer = 182 reinterpret_cast<T*>(output->channel_data()[is_planar ? ch : 0]); 183 const T v = static_cast<T>(start + ch * frames * increment); 184 for (size_t i = 0; i < frames; ++i) { 185 buffer[is_planar ? i : ch + i * channels] = 186 static_cast<T>(v + i * increment); 187 } 188 } 189 return output; 190 } 191 192 // Instantiate all the types of MakeAudioBuffer() and 193 // MakeAudioBuffer() needed. 194 #define DEFINE_MAKE_AUDIO_BUFFER_INSTANCE(type) \ 195 template scoped_refptr<AudioBuffer> MakeAudioBuffer<type>( \ 196 SampleFormat format, \ 197 ChannelLayout channel_layout, \ 198 size_t channel_count, \ 199 int sample_rate, \ 200 type start, \ 201 type increment, \ 202 size_t frames, \ 203 base::TimeDelta start_time) 204 DEFINE_MAKE_AUDIO_BUFFER_INSTANCE(uint8); 205 DEFINE_MAKE_AUDIO_BUFFER_INSTANCE(int16); 206 DEFINE_MAKE_AUDIO_BUFFER_INSTANCE(int32); 207 DEFINE_MAKE_AUDIO_BUFFER_INSTANCE(float); 208 209 static const char kFakeVideoBufferHeader[] = "FakeVideoBufferForTest"; 210 211 scoped_refptr<DecoderBuffer> CreateFakeVideoBufferForTest( 212 const VideoDecoderConfig& config, 213 base::TimeDelta timestamp, base::TimeDelta duration) { 214 Pickle pickle; 215 pickle.WriteString(kFakeVideoBufferHeader); 216 pickle.WriteInt(config.coded_size().width()); 217 pickle.WriteInt(config.coded_size().height()); 218 pickle.WriteInt64(timestamp.InMilliseconds()); 219 220 scoped_refptr<DecoderBuffer> buffer = DecoderBuffer::CopyFrom( 221 static_cast<const uint8*>(pickle.data()), 222 static_cast<int>(pickle.size())); 223 buffer->set_timestamp(timestamp); 224 buffer->set_duration(duration); 225 226 return buffer; 227 } 228 229 bool VerifyFakeVideoBufferForTest( 230 const scoped_refptr<DecoderBuffer>& buffer, 231 const VideoDecoderConfig& config) { 232 // Check if the input |buffer| matches the |config|. 233 PickleIterator pickle(Pickle(reinterpret_cast<const char*>(buffer->data()), 234 buffer->data_size())); 235 std::string header; 236 int width = 0; 237 int height = 0; 238 bool success = pickle.ReadString(&header) && pickle.ReadInt(&width) && 239 pickle.ReadInt(&height); 240 return (success && header == kFakeVideoBufferHeader && 241 width == config.coded_size().width() && 242 height == config.coded_size().height()); 243 } 244 245 } // namespace media 246