bf639ccaa5cf1b29ef51d4bb1072a989547654d0
[platform/framework/web/crosswalk.git] / src / media / filters / pipeline_integration_test_base.cc
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/filters/pipeline_integration_test_base.h"
6
7 #include "base/bind.h"
8 #include "base/memory/scoped_vector.h"
9 #include "media/base/clock.h"
10 #include "media/base/media_log.h"
11 #include "media/filters/audio_renderer_impl.h"
12 #include "media/filters/chunk_demuxer.h"
13 #include "media/filters/ffmpeg_audio_decoder.h"
14 #include "media/filters/ffmpeg_demuxer.h"
15 #include "media/filters/ffmpeg_video_decoder.h"
16 #include "media/filters/file_data_source.h"
17 #include "media/filters/opus_audio_decoder.h"
18 #include "media/filters/vpx_video_decoder.h"
19
20 using ::testing::_;
21 using ::testing::AnyNumber;
22 using ::testing::AtMost;
23
24 namespace media {
25
26 const char kNullVideoHash[] = "d41d8cd98f00b204e9800998ecf8427e";
27 const char kNullAudioHash[] = "0.00,0.00,0.00,0.00,0.00,0.00,";
28
29 PipelineIntegrationTestBase::PipelineIntegrationTestBase()
30     : hashing_enabled_(false),
31       clockless_playback_(false),
32       pipeline_(
33           new Pipeline(message_loop_.message_loop_proxy(), new MediaLog())),
34       ended_(false),
35       pipeline_status_(PIPELINE_OK),
36       last_video_frame_format_(VideoFrame::UNKNOWN),
37       hardware_config_(AudioParameters(), AudioParameters()) {
38   base::MD5Init(&md5_context_);
39   EXPECT_CALL(*this, OnSetOpaque(true)).Times(AnyNumber());
40 }
41
42 PipelineIntegrationTestBase::~PipelineIntegrationTestBase() {
43   if (!pipeline_->IsRunning())
44     return;
45
46   Stop();
47 }
48
49 void PipelineIntegrationTestBase::OnStatusCallback(
50     PipelineStatus status) {
51   pipeline_status_ = status;
52   message_loop_.PostTask(FROM_HERE, base::MessageLoop::QuitClosure());
53 }
54
55 void PipelineIntegrationTestBase::OnStatusCallbackChecked(
56     PipelineStatus expected_status,
57     PipelineStatus status) {
58   EXPECT_EQ(expected_status, status);
59   OnStatusCallback(status);
60 }
61
62 PipelineStatusCB PipelineIntegrationTestBase::QuitOnStatusCB(
63     PipelineStatus expected_status) {
64   return base::Bind(&PipelineIntegrationTestBase::OnStatusCallbackChecked,
65                     base::Unretained(this),
66                     expected_status);
67 }
68
69 void PipelineIntegrationTestBase::DemuxerNeedKeyCB(
70     const std::string& type,
71     const std::vector<uint8>& init_data) {
72   DCHECK(!init_data.empty());
73   CHECK(!need_key_cb_.is_null());
74   need_key_cb_.Run(type, init_data);
75 }
76
77 void PipelineIntegrationTestBase::OnEnded() {
78   DCHECK(!ended_);
79   ended_ = true;
80   pipeline_status_ = PIPELINE_OK;
81   message_loop_.PostTask(FROM_HERE, base::MessageLoop::QuitClosure());
82 }
83
84 bool PipelineIntegrationTestBase::WaitUntilOnEnded() {
85   if (ended_)
86     return (pipeline_status_ == PIPELINE_OK);
87   message_loop_.Run();
88   EXPECT_TRUE(ended_);
89   return ended_ && (pipeline_status_ == PIPELINE_OK);
90 }
91
92 PipelineStatus PipelineIntegrationTestBase::WaitUntilEndedOrError() {
93   if (ended_ || pipeline_status_ != PIPELINE_OK)
94     return pipeline_status_;
95   message_loop_.Run();
96   return pipeline_status_;
97 }
98
99 void PipelineIntegrationTestBase::OnError(PipelineStatus status) {
100   DCHECK_NE(status, PIPELINE_OK);
101   pipeline_status_ = status;
102   message_loop_.PostTask(FROM_HERE, base::MessageLoop::QuitClosure());
103 }
104
105 bool PipelineIntegrationTestBase::Start(const base::FilePath& file_path,
106                                         PipelineStatus expected_status) {
107   EXPECT_CALL(*this, OnMetadata(_)).Times(AtMost(1));
108   EXPECT_CALL(*this, OnPrerollCompleted()).Times(AtMost(1));
109   pipeline_->Start(
110       CreateFilterCollection(file_path, NULL),
111       base::Bind(&PipelineIntegrationTestBase::OnEnded, base::Unretained(this)),
112       base::Bind(&PipelineIntegrationTestBase::OnError, base::Unretained(this)),
113       QuitOnStatusCB(expected_status),
114       base::Bind(&PipelineIntegrationTestBase::OnMetadata,
115                  base::Unretained(this)),
116       base::Bind(&PipelineIntegrationTestBase::OnPrerollCompleted,
117                  base::Unretained(this)),
118       base::Closure());
119   message_loop_.Run();
120   return (pipeline_status_ == PIPELINE_OK);
121 }
122
123 bool PipelineIntegrationTestBase::Start(const base::FilePath& file_path,
124                                         PipelineStatus expected_status,
125                                         kTestType test_type) {
126   hashing_enabled_ = test_type == kHashed;
127   clockless_playback_ = test_type == kClockless;
128   if (clockless_playback_) {
129     pipeline_->SetClockForTesting(new Clock(&dummy_clock_));
130   }
131   return Start(file_path, expected_status);
132 }
133
134 bool PipelineIntegrationTestBase::Start(const base::FilePath& file_path) {
135   return Start(file_path, NULL);
136 }
137
138 bool PipelineIntegrationTestBase::Start(const base::FilePath& file_path,
139                                         Decryptor* decryptor) {
140   EXPECT_CALL(*this, OnMetadata(_)).Times(AtMost(1));
141   EXPECT_CALL(*this, OnPrerollCompleted()).Times(AtMost(1));
142   pipeline_->Start(
143       CreateFilterCollection(file_path, decryptor),
144       base::Bind(&PipelineIntegrationTestBase::OnEnded, base::Unretained(this)),
145       base::Bind(&PipelineIntegrationTestBase::OnError, base::Unretained(this)),
146       base::Bind(&PipelineIntegrationTestBase::OnStatusCallback,
147                  base::Unretained(this)),
148       base::Bind(&PipelineIntegrationTestBase::OnMetadata,
149                  base::Unretained(this)),
150       base::Bind(&PipelineIntegrationTestBase::OnPrerollCompleted,
151                  base::Unretained(this)),
152       base::Closure());
153   message_loop_.Run();
154   return (pipeline_status_ == PIPELINE_OK);
155 }
156
157 void PipelineIntegrationTestBase::Play() {
158   pipeline_->SetPlaybackRate(1);
159 }
160
161 void PipelineIntegrationTestBase::Pause() {
162   pipeline_->SetPlaybackRate(0);
163 }
164
165 bool PipelineIntegrationTestBase::Seek(base::TimeDelta seek_time) {
166   ended_ = false;
167
168   EXPECT_CALL(*this, OnPrerollCompleted());
169   pipeline_->Seek(seek_time, QuitOnStatusCB(PIPELINE_OK));
170   message_loop_.Run();
171   return (pipeline_status_ == PIPELINE_OK);
172 }
173
174 void PipelineIntegrationTestBase::Stop() {
175   DCHECK(pipeline_->IsRunning());
176   pipeline_->Stop(base::MessageLoop::QuitClosure());
177   message_loop_.Run();
178 }
179
180 void PipelineIntegrationTestBase::QuitAfterCurrentTimeTask(
181     const base::TimeDelta& quit_time) {
182   if (pipeline_->GetMediaTime() >= quit_time ||
183       pipeline_status_ != PIPELINE_OK) {
184     message_loop_.Quit();
185     return;
186   }
187
188   message_loop_.PostDelayedTask(
189       FROM_HERE,
190       base::Bind(&PipelineIntegrationTestBase::QuitAfterCurrentTimeTask,
191                  base::Unretained(this), quit_time),
192       base::TimeDelta::FromMilliseconds(10));
193 }
194
195 bool PipelineIntegrationTestBase::WaitUntilCurrentTimeIsAfter(
196     const base::TimeDelta& wait_time) {
197   DCHECK(pipeline_->IsRunning());
198   DCHECK_GT(pipeline_->GetPlaybackRate(), 0);
199   DCHECK(wait_time <= pipeline_->GetMediaDuration());
200
201   message_loop_.PostDelayedTask(
202       FROM_HERE,
203       base::Bind(&PipelineIntegrationTestBase::QuitAfterCurrentTimeTask,
204                  base::Unretained(this),
205                  wait_time),
206       base::TimeDelta::FromMilliseconds(10));
207   message_loop_.Run();
208   return (pipeline_status_ == PIPELINE_OK);
209 }
210
211 scoped_ptr<FilterCollection>
212 PipelineIntegrationTestBase::CreateFilterCollection(
213     const base::FilePath& file_path,
214     Decryptor* decryptor) {
215   FileDataSource* file_data_source = new FileDataSource();
216   CHECK(file_data_source->Initialize(file_path));
217   data_source_.reset(file_data_source);
218
219   Demuxer::NeedKeyCB need_key_cb = base::Bind(
220       &PipelineIntegrationTestBase::DemuxerNeedKeyCB, base::Unretained(this));
221   scoped_ptr<Demuxer> demuxer(
222       new FFmpegDemuxer(message_loop_.message_loop_proxy(),
223                         data_source_.get(),
224                         need_key_cb,
225                         new MediaLog()));
226   return CreateFilterCollection(demuxer.Pass(), decryptor);
227 }
228
229 scoped_ptr<FilterCollection>
230 PipelineIntegrationTestBase::CreateFilterCollection(
231     scoped_ptr<Demuxer> demuxer,
232     Decryptor* decryptor) {
233   demuxer_ = demuxer.Pass();
234
235   scoped_ptr<FilterCollection> collection(new FilterCollection());
236   collection->SetDemuxer(demuxer_.get());
237
238   ScopedVector<VideoDecoder> video_decoders;
239   video_decoders.push_back(
240       new VpxVideoDecoder(message_loop_.message_loop_proxy()));
241   video_decoders.push_back(
242       new FFmpegVideoDecoder(message_loop_.message_loop_proxy()));
243
244   // Disable frame dropping if hashing is enabled.
245   scoped_ptr<VideoRenderer> renderer(new VideoRendererImpl(
246       message_loop_.message_loop_proxy(),
247       video_decoders.Pass(),
248       base::Bind(&PipelineIntegrationTestBase::SetDecryptor,
249                  base::Unretained(this),
250                  decryptor),
251       base::Bind(&PipelineIntegrationTestBase::OnVideoRendererPaint,
252                  base::Unretained(this)),
253       base::Bind(&PipelineIntegrationTestBase::OnSetOpaque,
254                  base::Unretained(this)),
255       false));
256   collection->SetVideoRenderer(renderer.Pass());
257
258   if (!clockless_playback_) {
259     audio_sink_ = new NullAudioSink(message_loop_.message_loop_proxy());
260   } else {
261     clockless_audio_sink_ = new ClocklessAudioSink();
262   }
263
264   ScopedVector<AudioDecoder> audio_decoders;
265   audio_decoders.push_back(
266       new FFmpegAudioDecoder(message_loop_.message_loop_proxy()));
267   audio_decoders.push_back(
268       new OpusAudioDecoder(message_loop_.message_loop_proxy()));
269
270   AudioParameters out_params(AudioParameters::AUDIO_PCM_LOW_LATENCY,
271                              CHANNEL_LAYOUT_STEREO,
272                              44100,
273                              16,
274                              512);
275   hardware_config_.UpdateOutputConfig(out_params);
276
277   AudioRendererImpl* audio_renderer_impl = new AudioRendererImpl(
278       message_loop_.message_loop_proxy(),
279       (clockless_playback_)
280           ? static_cast<AudioRendererSink*>(clockless_audio_sink_.get())
281           : audio_sink_.get(),
282       audio_decoders.Pass(),
283       base::Bind(&PipelineIntegrationTestBase::SetDecryptor,
284                  base::Unretained(this),
285                  decryptor),
286       &hardware_config_);
287   // Disable underflow if hashing is enabled.
288   if (hashing_enabled_) {
289     audio_sink_->StartAudioHashForTesting();
290     audio_renderer_impl->DisableUnderflowForTesting();
291   }
292   scoped_ptr<AudioRenderer> audio_renderer(audio_renderer_impl);
293   collection->SetAudioRenderer(audio_renderer.Pass());
294
295   return collection.Pass();
296 }
297
298 void PipelineIntegrationTestBase::SetDecryptor(
299     Decryptor* decryptor,
300     const DecryptorReadyCB& decryptor_ready_cb) {
301   decryptor_ready_cb.Run(decryptor);
302 }
303
304 void PipelineIntegrationTestBase::OnVideoRendererPaint(
305     const scoped_refptr<VideoFrame>& frame) {
306   last_video_frame_format_ = frame->format();
307   if (!hashing_enabled_)
308     return;
309   frame->HashFrameForTesting(&md5_context_);
310 }
311
312 std::string PipelineIntegrationTestBase::GetVideoHash() {
313   DCHECK(hashing_enabled_);
314   base::MD5Digest digest;
315   base::MD5Final(&digest, &md5_context_);
316   return base::MD5DigestToBase16(digest);
317 }
318
319 std::string PipelineIntegrationTestBase::GetAudioHash() {
320   DCHECK(hashing_enabled_);
321   return audio_sink_->GetAudioHashForTesting();
322 }
323
324 base::TimeDelta PipelineIntegrationTestBase::GetAudioTime() {
325   DCHECK(clockless_playback_);
326   return clockless_audio_sink_->render_time();
327 }
328
329 base::TimeTicks DummyTickClock::NowTicks() {
330   now_ += base::TimeDelta::FromSeconds(60);
331   return now_;
332 }
333
334 }  // namespace media