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