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
19using ::testing::_;
20using ::testing::StrictMock;
21
22namespace media {
23
24// Utility mock for testing methods expecting Closures and PipelineStatusCBs.
25class 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
39MockCallback::MockCallback() {}
40MockCallback::~MockCallback() {}
41
42base::Closure NewExpectedClosure() {
43  StrictMock<MockCallback>* callback = new StrictMock<MockCallback>();
44  EXPECT_CALL(*callback, Run());
45  return base::Bind(&MockCallback::Run, callback);
46}
47
48PipelineStatusCB 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
54WaitableMessageLoopEvent::WaitableMessageLoopEvent()
55    : message_loop_(base::MessageLoop::current()),
56      signaled_(false),
57      status_(PIPELINE_OK) {
58  DCHECK(message_loop_);
59}
60
61WaitableMessageLoopEvent::~WaitableMessageLoopEvent() {}
62
63base::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
70PipelineStatusCB WaitableMessageLoopEvent::GetPipelineStatusCB() {
71  DCHECK_EQ(message_loop_, base::MessageLoop::current());
72  return BindToCurrentLoop(base::Bind(
73      &WaitableMessageLoopEvent::OnCallback, base::Unretained(this)));
74}
75
76void WaitableMessageLoopEvent::RunAndWait() {
77  RunAndWaitForStatus(PIPELINE_OK);
78}
79
80void 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
96void WaitableMessageLoopEvent::OnCallback(PipelineStatus status) {
97  DCHECK_EQ(message_loop_, base::MessageLoop::current());
98  signaled_ = true;
99  status_ = status;
100  message_loop_->QuitWhenIdle();
101}
102
103void 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
109static 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
120static const gfx::Size kNormalSize(320, 240);
121static const gfx::Size kLargeSize(640, 480);
122
123VideoDecoderConfig TestVideoConfig::Invalid() {
124  return GetTestConfig(kUnknownVideoCodec, kNormalSize, false);
125}
126
127VideoDecoderConfig TestVideoConfig::Normal() {
128  return GetTestConfig(kCodecVP8, kNormalSize, false);
129}
130
131VideoDecoderConfig TestVideoConfig::NormalEncrypted() {
132  return GetTestConfig(kCodecVP8, kNormalSize, true);
133}
134
135VideoDecoderConfig TestVideoConfig::Large() {
136  return GetTestConfig(kCodecVP8, kLargeSize, false);
137}
138
139VideoDecoderConfig TestVideoConfig::LargeEncrypted() {
140  return GetTestConfig(kCodecVP8, kLargeSize, true);
141}
142
143gfx::Size TestVideoConfig::NormalCodedSize() {
144  return kNormalSize;
145}
146
147gfx::Size TestVideoConfig::LargeCodedSize() {
148  return kLargeSize;
149}
150
151template <class T>
152scoped_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)
204DEFINE_MAKE_AUDIO_BUFFER_INSTANCE(uint8);
205DEFINE_MAKE_AUDIO_BUFFER_INSTANCE(int16);
206DEFINE_MAKE_AUDIO_BUFFER_INSTANCE(int32);
207DEFINE_MAKE_AUDIO_BUFFER_INSTANCE(float);
208
209static const char kFakeVideoBufferHeader[] = "FakeVideoBufferForTest";
210
211scoped_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
229bool 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
245CallbackPairChecker::CallbackPairChecker() : expecting_b_(false) {
246}
247
248CallbackPairChecker::~CallbackPairChecker() {
249  EXPECT_FALSE(expecting_b_);
250}
251
252void CallbackPairChecker::RecordACalled() {
253  EXPECT_FALSE(expecting_b_);
254  expecting_b_ = true;
255}
256
257void CallbackPairChecker::RecordBCalled() {
258  EXPECT_TRUE(expecting_b_);
259  expecting_b_ = false;
260}
261
262}  // namespace media
263