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_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 BindToLoop(message_loop_->message_loop_proxy(), 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 BindToLoop(message_loop_->message_loop_proxy(), 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> MakeInterleavedAudioBuffer( 153 SampleFormat format, 154 int channels, 155 T start, 156 T increment, 157 int frames, 158 base::TimeDelta start_time, 159 base::TimeDelta duration) { 160 DCHECK(format == kSampleFormatU8 || format == kSampleFormatS16 || 161 format == kSampleFormatS32 || format == kSampleFormatF32); 162 163 // Create a block of memory with values: 164 // start 165 // start + increment 166 // start + 2 * increment, ... 167 // Since this is interleaved data, channel 0 data will be: 168 // start 169 // start + channels * increment 170 // start + 2 * channels * increment, ... 171 int buffer_size = frames * channels * sizeof(T); 172 scoped_ptr<uint8[]> memory(new uint8[buffer_size]); 173 uint8* data[] = { memory.get() }; 174 T* buffer = reinterpret_cast<T*>(memory.get()); 175 for (int i = 0; i < frames * channels; ++i) { 176 buffer[i] = start; 177 start += increment; 178 } 179 return AudioBuffer::CopyFrom( 180 format, channels, frames, data, start_time, duration); 181 } 182 183 template <class T> 184 scoped_refptr<AudioBuffer> MakePlanarAudioBuffer( 185 SampleFormat format, 186 int channels, 187 T start, 188 T increment, 189 int frames, 190 base::TimeDelta start_time, 191 base::TimeDelta duration) { 192 DCHECK(format == kSampleFormatPlanarF32 || format == kSampleFormatPlanarS16); 193 194 // Create multiple blocks of data, one for each channel. 195 // Values in channel 0 will be: 196 // start 197 // start + increment 198 // start + 2 * increment, ... 199 // Values in channel 1 will be: 200 // start + frames * increment 201 // start + (frames + 1) * increment 202 // start + (frames + 2) * increment, ... 203 int buffer_size = frames * sizeof(T); 204 scoped_ptr<uint8*[]> data(new uint8*[channels]); 205 scoped_ptr<uint8[]> memory(new uint8[channels * buffer_size]); 206 for (int i = 0; i < channels; ++i) { 207 data.get()[i] = memory.get() + i * buffer_size; 208 T* buffer = reinterpret_cast<T*>(data.get()[i]); 209 for (int j = 0; j < frames; ++j) { 210 buffer[j] = start; 211 start += increment; 212 } 213 } 214 return AudioBuffer::CopyFrom( 215 format, channels, frames, data.get(), start_time, duration); 216 } 217 218 // Instantiate all the types of MakeInterleavedAudioBuffer() and 219 // MakePlanarAudioBuffer() needed. 220 221 #define DEFINE_INTERLEAVED_INSTANCE(type) \ 222 template scoped_refptr<AudioBuffer> MakeInterleavedAudioBuffer<type>( \ 223 SampleFormat format, \ 224 int channels, \ 225 type start, \ 226 type increment, \ 227 int frames, \ 228 base::TimeDelta start_time, \ 229 base::TimeDelta duration) 230 DEFINE_INTERLEAVED_INSTANCE(uint8); 231 DEFINE_INTERLEAVED_INSTANCE(int16); 232 DEFINE_INTERLEAVED_INSTANCE(int32); 233 DEFINE_INTERLEAVED_INSTANCE(float); 234 235 #define DEFINE_PLANAR_INSTANCE(type) \ 236 template scoped_refptr<AudioBuffer> MakePlanarAudioBuffer<type>( \ 237 SampleFormat format, \ 238 int channels, \ 239 type start, \ 240 type increment, \ 241 int frames, \ 242 base::TimeDelta start_time, \ 243 base::TimeDelta duration); 244 DEFINE_PLANAR_INSTANCE(int16); 245 DEFINE_PLANAR_INSTANCE(float); 246 247 static const char kFakeVideoBufferHeader[] = "FakeVideoBufferForTest"; 248 249 scoped_refptr<DecoderBuffer> CreateFakeVideoBufferForTest( 250 const VideoDecoderConfig& config, 251 base::TimeDelta timestamp, base::TimeDelta duration) { 252 Pickle pickle; 253 pickle.WriteString(kFakeVideoBufferHeader); 254 pickle.WriteInt(config.coded_size().width()); 255 pickle.WriteInt(config.coded_size().height()); 256 pickle.WriteInt64(timestamp.InMilliseconds()); 257 258 scoped_refptr<DecoderBuffer> buffer = DecoderBuffer::CopyFrom( 259 static_cast<const uint8*>(pickle.data()), 260 static_cast<int>(pickle.size())); 261 buffer->set_timestamp(timestamp); 262 buffer->set_duration(duration); 263 264 return buffer; 265 } 266 267 bool VerifyFakeVideoBufferForTest( 268 const scoped_refptr<DecoderBuffer>& buffer, 269 const VideoDecoderConfig& config) { 270 // Check if the input |buffer| matches the |config|. 271 PickleIterator pickle(Pickle(reinterpret_cast<const char*>(buffer->data()), 272 buffer->data_size())); 273 std::string header; 274 int width = 0; 275 int height = 0; 276 bool success = pickle.ReadString(&header) && pickle.ReadInt(&width) && 277 pickle.ReadInt(&height); 278 return (success && header == kFakeVideoBufferHeader && 279 width == config.coded_size().width() && 280 height == config.coded_size().height()); 281 } 282 283 } // namespace media 284