Home | History | Annotate | Download | only in base
      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