Upstream version 10.39.225.0
[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/media_log.h"
10 #include "media/filters/audio_renderer_impl.h"
11 #include "media/filters/chunk_demuxer.h"
12 #include "media/filters/ffmpeg_audio_decoder.h"
13 #include "media/filters/ffmpeg_demuxer.h"
14 #include "media/filters/ffmpeg_video_decoder.h"
15 #include "media/filters/file_data_source.h"
16 #include "media/filters/opus_audio_decoder.h"
17 #include "media/filters/renderer_impl.h"
18 #include "media/filters/vpx_video_decoder.h"
19
20 using ::testing::_;
21 using ::testing::AnyNumber;
22 using ::testing::AtMost;
23 using ::testing::SaveArg;
24
25 namespace media {
26
27 const char kNullVideoHash[] = "d41d8cd98f00b204e9800998ecf8427e";
28 const char kNullAudioHash[] = "0.00,0.00,0.00,0.00,0.00,0.00,";
29
30 PipelineIntegrationTestBase::PipelineIntegrationTestBase()
31     : hashing_enabled_(false),
32       clockless_playback_(false),
33       pipeline_(
34           new Pipeline(message_loop_.message_loop_proxy(), new MediaLog())),
35       ended_(false),
36       pipeline_status_(PIPELINE_OK),
37       last_video_frame_format_(VideoFrame::UNKNOWN),
38       hardware_config_(AudioParameters(), AudioParameters()) {
39   base::MD5Init(&md5_context_);
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(_))
108       .Times(AtMost(1))
109       .WillRepeatedly(SaveArg<0>(&metadata_));
110   EXPECT_CALL(*this, OnBufferingStateChanged(BUFFERING_HAVE_ENOUGH))
111       .Times(AtMost(1));
112   CreateDemuxer(file_path);
113   pipeline_->Start(
114       demuxer_.get(),
115       CreateRenderer(NULL),
116       base::Bind(&PipelineIntegrationTestBase::OnEnded, base::Unretained(this)),
117       base::Bind(&PipelineIntegrationTestBase::OnError, base::Unretained(this)),
118       QuitOnStatusCB(expected_status),
119       base::Bind(&PipelineIntegrationTestBase::OnMetadata,
120                  base::Unretained(this)),
121       base::Bind(&PipelineIntegrationTestBase::OnBufferingStateChanged,
122                  base::Unretained(this)),
123       base::Closure(),
124       base::Bind(&PipelineIntegrationTestBase::OnAddTextTrack,
125                  base::Unretained(this)));
126   message_loop_.Run();
127   return (pipeline_status_ == PIPELINE_OK);
128 }
129
130 bool PipelineIntegrationTestBase::Start(const base::FilePath& file_path,
131                                         PipelineStatus expected_status,
132                                         kTestType test_type) {
133   hashing_enabled_ = test_type == kHashed;
134   clockless_playback_ = test_type == kClockless;
135   return Start(file_path, expected_status);
136 }
137
138 bool PipelineIntegrationTestBase::Start(const base::FilePath& file_path) {
139   return Start(file_path, NULL);
140 }
141
142 bool PipelineIntegrationTestBase::Start(const base::FilePath& file_path,
143                                         Decryptor* decryptor) {
144   EXPECT_CALL(*this, OnMetadata(_))
145       .Times(AtMost(1))
146       .WillRepeatedly(SaveArg<0>(&metadata_));
147   EXPECT_CALL(*this, OnBufferingStateChanged(BUFFERING_HAVE_ENOUGH))
148       .Times(AtMost(1));
149
150   CreateDemuxer(file_path);
151   pipeline_->Start(
152       demuxer_.get(),
153       CreateRenderer(decryptor),
154       base::Bind(&PipelineIntegrationTestBase::OnEnded, base::Unretained(this)),
155       base::Bind(&PipelineIntegrationTestBase::OnError, base::Unretained(this)),
156       base::Bind(&PipelineIntegrationTestBase::OnStatusCallback,
157                  base::Unretained(this)),
158       base::Bind(&PipelineIntegrationTestBase::OnMetadata,
159                  base::Unretained(this)),
160       base::Bind(&PipelineIntegrationTestBase::OnBufferingStateChanged,
161                  base::Unretained(this)),
162       base::Closure(),
163       base::Bind(&PipelineIntegrationTestBase::OnAddTextTrack,
164                  base::Unretained(this)));
165   message_loop_.Run();
166   return (pipeline_status_ == PIPELINE_OK);
167 }
168
169 void PipelineIntegrationTestBase::Play() {
170   pipeline_->SetPlaybackRate(1);
171 }
172
173 void PipelineIntegrationTestBase::Pause() {
174   pipeline_->SetPlaybackRate(0);
175 }
176
177 bool PipelineIntegrationTestBase::Seek(base::TimeDelta seek_time) {
178   ended_ = false;
179
180   EXPECT_CALL(*this, OnBufferingStateChanged(BUFFERING_HAVE_ENOUGH));
181   pipeline_->Seek(seek_time, QuitOnStatusCB(PIPELINE_OK));
182   message_loop_.Run();
183   return (pipeline_status_ == PIPELINE_OK);
184 }
185
186 void PipelineIntegrationTestBase::Stop() {
187   DCHECK(pipeline_->IsRunning());
188   pipeline_->Stop(base::MessageLoop::QuitClosure());
189   message_loop_.Run();
190 }
191
192 void PipelineIntegrationTestBase::QuitAfterCurrentTimeTask(
193     const base::TimeDelta& quit_time) {
194   if (pipeline_->GetMediaTime() >= quit_time ||
195       pipeline_status_ != PIPELINE_OK) {
196     message_loop_.Quit();
197     return;
198   }
199
200   message_loop_.PostDelayedTask(
201       FROM_HERE,
202       base::Bind(&PipelineIntegrationTestBase::QuitAfterCurrentTimeTask,
203                  base::Unretained(this), quit_time),
204       base::TimeDelta::FromMilliseconds(10));
205 }
206
207 bool PipelineIntegrationTestBase::WaitUntilCurrentTimeIsAfter(
208     const base::TimeDelta& wait_time) {
209   DCHECK(pipeline_->IsRunning());
210   DCHECK_GT(pipeline_->GetPlaybackRate(), 0);
211   DCHECK(wait_time <= pipeline_->GetMediaDuration());
212
213   message_loop_.PostDelayedTask(
214       FROM_HERE,
215       base::Bind(&PipelineIntegrationTestBase::QuitAfterCurrentTimeTask,
216                  base::Unretained(this),
217                  wait_time),
218       base::TimeDelta::FromMilliseconds(10));
219   message_loop_.Run();
220   return (pipeline_status_ == PIPELINE_OK);
221 }
222
223 void PipelineIntegrationTestBase::CreateDemuxer(
224     const base::FilePath& file_path) {
225   FileDataSource* file_data_source = new FileDataSource();
226   CHECK(file_data_source->Initialize(file_path)) << "Is " << file_path.value()
227                                                  << " missing?";
228   data_source_.reset(file_data_source);
229
230   Demuxer::NeedKeyCB need_key_cb = base::Bind(
231       &PipelineIntegrationTestBase::DemuxerNeedKeyCB, base::Unretained(this));
232   demuxer_ =
233       scoped_ptr<Demuxer>(new FFmpegDemuxer(message_loop_.message_loop_proxy(),
234                                             data_source_.get(),
235                                             need_key_cb,
236                                             new MediaLog()));
237 }
238
239 scoped_ptr<Renderer> PipelineIntegrationTestBase::CreateRenderer(
240     Decryptor* decryptor) {
241   ScopedVector<VideoDecoder> video_decoders;
242 #if !defined(MEDIA_DISABLE_LIBVPX)
243   video_decoders.push_back(
244       new VpxVideoDecoder(message_loop_.message_loop_proxy()));
245 #endif  // !defined(MEDIA_DISABLE_LIBVPX)
246   video_decoders.push_back(
247       new FFmpegVideoDecoder(message_loop_.message_loop_proxy()));
248
249   // Disable frame dropping if hashing is enabled.
250   scoped_ptr<VideoRenderer> video_renderer(new VideoRendererImpl(
251       message_loop_.message_loop_proxy(),
252       video_decoders.Pass(),
253       base::Bind(&PipelineIntegrationTestBase::SetDecryptor,
254                  base::Unretained(this),
255                  decryptor),
256       base::Bind(&PipelineIntegrationTestBase::OnVideoRendererPaint,
257                  base::Unretained(this)),
258       false,
259       new MediaLog()));
260
261   if (!clockless_playback_) {
262     audio_sink_ = new NullAudioSink(message_loop_.message_loop_proxy());
263   } else {
264     clockless_audio_sink_ = new ClocklessAudioSink();
265   }
266
267   ScopedVector<AudioDecoder> audio_decoders;
268   audio_decoders.push_back(
269       new FFmpegAudioDecoder(message_loop_.message_loop_proxy(), LogCB()));
270   audio_decoders.push_back(
271       new OpusAudioDecoder(message_loop_.message_loop_proxy()));
272
273   AudioParameters out_params(AudioParameters::AUDIO_PCM_LOW_LATENCY,
274                              CHANNEL_LAYOUT_STEREO,
275                              44100,
276                              16,
277                              512);
278   hardware_config_.UpdateOutputConfig(out_params);
279
280   scoped_ptr<AudioRenderer> audio_renderer(new AudioRendererImpl(
281       message_loop_.message_loop_proxy(),
282       (clockless_playback_)
283           ? static_cast<AudioRendererSink*>(clockless_audio_sink_.get())
284           : audio_sink_.get(),
285       audio_decoders.Pass(),
286       base::Bind(&PipelineIntegrationTestBase::SetDecryptor,
287                  base::Unretained(this),
288                  decryptor),
289       hardware_config_,
290       new MediaLog()));
291   if (hashing_enabled_)
292     audio_sink_->StartAudioHashForTesting();
293
294   scoped_ptr<RendererImpl> renderer_impl(
295       new RendererImpl(message_loop_.message_loop_proxy(),
296                        demuxer_.get(),
297                        audio_renderer.Pass(),
298                        video_renderer.Pass()));
299
300   // Prevent non-deterministic buffering state callbacks from firing (e.g., slow
301   // machine, valgrind).
302   renderer_impl->DisableUnderflowForTesting();
303
304   if (clockless_playback_)
305     renderer_impl->EnableClocklessVideoPlaybackForTesting();
306
307   return renderer_impl.PassAs<Renderer>();
308 }
309
310 void PipelineIntegrationTestBase::SetDecryptor(
311     Decryptor* decryptor,
312     const DecryptorReadyCB& decryptor_ready_cb) {
313   decryptor_ready_cb.Run(
314       decryptor,
315       base::Bind(&PipelineIntegrationTestBase::DecryptorAttached,
316                  base::Unretained(this)));
317   EXPECT_CALL(*this, DecryptorAttached(true));
318 }
319
320 void PipelineIntegrationTestBase::OnVideoRendererPaint(
321     const scoped_refptr<VideoFrame>& frame) {
322   last_video_frame_format_ = frame->format();
323   if (!hashing_enabled_)
324     return;
325   frame->HashFrameForTesting(&md5_context_);
326 }
327
328 std::string PipelineIntegrationTestBase::GetVideoHash() {
329   DCHECK(hashing_enabled_);
330   base::MD5Digest digest;
331   base::MD5Final(&digest, &md5_context_);
332   return base::MD5DigestToBase16(digest);
333 }
334
335 std::string PipelineIntegrationTestBase::GetAudioHash() {
336   DCHECK(hashing_enabled_);
337   return audio_sink_->GetAudioHashForTesting();
338 }
339
340 base::TimeDelta PipelineIntegrationTestBase::GetAudioTime() {
341   DCHECK(clockless_playback_);
342   return clockless_audio_sink_->render_time();
343 }
344
345 base::TimeTicks DummyTickClock::NowTicks() {
346   now_ += base::TimeDelta::FromSeconds(60);
347   return now_;
348 }
349
350 }  // namespace media