Roll src/third_party/WebKit 05e9c31:d6595eb (svn 198725:198727)
[chromium-blink-merge.git] / media / test / pipeline_integration_test_base.cc
blobc13c4bea93cb062365a57fbe03b5da0c645924dd
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.
5 #include "media/test/pipeline_integration_test_base.h"
7 #include "base/bind.h"
8 #include "base/memory/scoped_vector.h"
9 #include "media/base/cdm_context.h"
10 #include "media/base/media_log.h"
11 #include "media/base/test_data_util.h"
12 #include "media/filters/chunk_demuxer.h"
13 #if !defined(MEDIA_DISABLE_FFMPEG)
14 #include "media/filters/ffmpeg_audio_decoder.h"
15 #include "media/filters/ffmpeg_demuxer.h"
16 #include "media/filters/ffmpeg_video_decoder.h"
17 #endif
18 #include "media/filters/file_data_source.h"
19 #include "media/filters/opus_audio_decoder.h"
20 #include "media/renderers/audio_renderer_impl.h"
21 #include "media/renderers/renderer_impl.h"
22 #if !defined(MEDIA_DISABLE_LIBVPX)
23 #include "media/filters/vpx_video_decoder.h"
24 #endif
26 using ::testing::_;
27 using ::testing::AnyNumber;
28 using ::testing::AtLeast;
29 using ::testing::AtMost;
30 using ::testing::Invoke;
31 using ::testing::InvokeWithoutArgs;
32 using ::testing::SaveArg;
34 namespace media {
36 const char kNullVideoHash[] = "d41d8cd98f00b204e9800998ecf8427e";
37 const char kNullAudioHash[] = "0.00,0.00,0.00,0.00,0.00,0.00,";
39 PipelineIntegrationTestBase::PipelineIntegrationTestBase()
40 : hashing_enabled_(false),
41 clockless_playback_(false),
42 pipeline_(
43 new Pipeline(message_loop_.task_runner(), new MediaLog())),
44 ended_(false),
45 pipeline_status_(PIPELINE_OK),
46 last_video_frame_format_(VideoFrame::UNKNOWN),
47 last_video_frame_color_space_(VideoFrame::COLOR_SPACE_UNSPECIFIED),
48 hardware_config_(AudioParameters(), AudioParameters()) {
49 base::MD5Init(&md5_context_);
52 PipelineIntegrationTestBase::~PipelineIntegrationTestBase() {
53 if (!pipeline_->IsRunning())
54 return;
56 Stop();
59 void PipelineIntegrationTestBase::OnSeeked(base::TimeDelta seek_time,
60 PipelineStatus status) {
61 EXPECT_EQ(seek_time, pipeline_->GetMediaTime());
62 pipeline_status_ = status;
65 void PipelineIntegrationTestBase::OnStatusCallback(
66 PipelineStatus status) {
67 pipeline_status_ = status;
68 message_loop_.PostTask(FROM_HERE, base::MessageLoop::QuitClosure());
71 void PipelineIntegrationTestBase::DemuxerEncryptedMediaInitDataCB(
72 EmeInitDataType type,
73 const std::vector<uint8>& init_data) {
74 DCHECK(!init_data.empty());
75 CHECK(!encrypted_media_init_data_cb_.is_null());
76 encrypted_media_init_data_cb_.Run(type, init_data);
79 void PipelineIntegrationTestBase::OnEnded() {
80 DCHECK(!ended_);
81 ended_ = true;
82 pipeline_status_ = PIPELINE_OK;
83 message_loop_.PostTask(FROM_HERE, base::MessageLoop::QuitClosure());
86 bool PipelineIntegrationTestBase::WaitUntilOnEnded() {
87 if (ended_)
88 return (pipeline_status_ == PIPELINE_OK);
89 message_loop_.Run();
90 EXPECT_TRUE(ended_);
91 return ended_ && (pipeline_status_ == PIPELINE_OK);
94 PipelineStatus PipelineIntegrationTestBase::WaitUntilEndedOrError() {
95 if (ended_ || pipeline_status_ != PIPELINE_OK)
96 return pipeline_status_;
97 message_loop_.Run();
98 return pipeline_status_;
101 void PipelineIntegrationTestBase::OnError(PipelineStatus status) {
102 DCHECK_NE(status, PIPELINE_OK);
103 pipeline_status_ = status;
104 message_loop_.PostTask(FROM_HERE, base::MessageLoop::QuitClosure());
107 PipelineStatus PipelineIntegrationTestBase::Start(const std::string& filename) {
108 return Start(filename, nullptr);
111 PipelineStatus PipelineIntegrationTestBase::Start(const std::string& filename,
112 CdmContext* cdm_context) {
113 EXPECT_CALL(*this, OnMetadata(_))
114 .Times(AtMost(1))
115 .WillRepeatedly(SaveArg<0>(&metadata_));
116 EXPECT_CALL(*this, OnBufferingStateChanged(BUFFERING_HAVE_ENOUGH))
117 .Times(AnyNumber());
118 EXPECT_CALL(*this, OnBufferingStateChanged(BUFFERING_HAVE_NOTHING))
119 .Times(AnyNumber());
120 CreateDemuxer(filename);
122 if (cdm_context) {
123 EXPECT_CALL(*this, DecryptorAttached(true));
124 pipeline_->SetCdm(
125 cdm_context, base::Bind(&PipelineIntegrationTestBase::DecryptorAttached,
126 base::Unretained(this)));
129 // Should never be called as the required decryption keys for the encrypted
130 // media files are provided in advance.
131 EXPECT_CALL(*this, OnWaitingForDecryptionKey()).Times(0);
133 pipeline_->Start(
134 demuxer_.get(), CreateRenderer(),
135 base::Bind(&PipelineIntegrationTestBase::OnEnded, base::Unretained(this)),
136 base::Bind(&PipelineIntegrationTestBase::OnError, base::Unretained(this)),
137 base::Bind(&PipelineIntegrationTestBase::OnStatusCallback,
138 base::Unretained(this)),
139 base::Bind(&PipelineIntegrationTestBase::OnMetadata,
140 base::Unretained(this)),
141 base::Bind(&PipelineIntegrationTestBase::OnBufferingStateChanged,
142 base::Unretained(this)),
143 base::Closure(), base::Bind(&PipelineIntegrationTestBase::OnAddTextTrack,
144 base::Unretained(this)),
145 base::Bind(&PipelineIntegrationTestBase::OnWaitingForDecryptionKey,
146 base::Unretained(this)));
147 message_loop_.Run();
148 return pipeline_status_;
151 PipelineStatus PipelineIntegrationTestBase::Start(const std::string& filename,
152 kTestType test_type) {
153 hashing_enabled_ = test_type == kHashed;
154 clockless_playback_ = test_type == kClockless;
155 return Start(filename);
158 void PipelineIntegrationTestBase::Play() {
159 pipeline_->SetPlaybackRate(1);
162 void PipelineIntegrationTestBase::Pause() {
163 pipeline_->SetPlaybackRate(0);
166 bool PipelineIntegrationTestBase::Seek(base::TimeDelta seek_time) {
167 ended_ = false;
169 EXPECT_CALL(*this, OnBufferingStateChanged(BUFFERING_HAVE_ENOUGH))
170 .WillOnce(InvokeWithoutArgs(&message_loop_, &base::MessageLoop::QuitNow));
171 pipeline_->Seek(seek_time, base::Bind(&PipelineIntegrationTestBase::OnSeeked,
172 base::Unretained(this), seek_time));
173 message_loop_.Run();
174 return (pipeline_status_ == PIPELINE_OK);
177 void PipelineIntegrationTestBase::Stop() {
178 DCHECK(pipeline_->IsRunning());
179 pipeline_->Stop(base::MessageLoop::QuitClosure());
180 message_loop_.Run();
183 void PipelineIntegrationTestBase::QuitAfterCurrentTimeTask(
184 const base::TimeDelta& quit_time) {
185 if (pipeline_->GetMediaTime() >= quit_time ||
186 pipeline_status_ != PIPELINE_OK) {
187 message_loop_.Quit();
188 return;
191 message_loop_.PostDelayedTask(
192 FROM_HERE,
193 base::Bind(&PipelineIntegrationTestBase::QuitAfterCurrentTimeTask,
194 base::Unretained(this), quit_time),
195 base::TimeDelta::FromMilliseconds(10));
198 bool PipelineIntegrationTestBase::WaitUntilCurrentTimeIsAfter(
199 const base::TimeDelta& wait_time) {
200 DCHECK(pipeline_->IsRunning());
201 DCHECK_GT(pipeline_->GetPlaybackRate(), 0);
202 DCHECK(wait_time <= pipeline_->GetMediaDuration());
204 message_loop_.PostDelayedTask(
205 FROM_HERE,
206 base::Bind(&PipelineIntegrationTestBase::QuitAfterCurrentTimeTask,
207 base::Unretained(this),
208 wait_time),
209 base::TimeDelta::FromMilliseconds(10));
210 message_loop_.Run();
211 return (pipeline_status_ == PIPELINE_OK);
214 void PipelineIntegrationTestBase::CreateDemuxer(const std::string& filename) {
215 FileDataSource* file_data_source = new FileDataSource();
216 base::FilePath file_path(GetTestDataFilePath(filename));
217 CHECK(file_data_source->Initialize(file_path)) << "Is " << file_path.value()
218 << " missing?";
219 data_source_.reset(file_data_source);
221 Demuxer::EncryptedMediaInitDataCB encrypted_media_init_data_cb =
222 base::Bind(&PipelineIntegrationTestBase::DemuxerEncryptedMediaInitDataCB,
223 base::Unretained(this));
225 #if !defined(MEDIA_DISABLE_FFMPEG)
226 demuxer_ = scoped_ptr<Demuxer>(
227 new FFmpegDemuxer(message_loop_.task_runner(), data_source_.get(),
228 encrypted_media_init_data_cb, new MediaLog()));
229 #endif
232 scoped_ptr<Renderer> PipelineIntegrationTestBase::CreateRenderer() {
233 ScopedVector<VideoDecoder> video_decoders;
234 #if !defined(MEDIA_DISABLE_LIBVPX)
235 video_decoders.push_back(
236 new VpxVideoDecoder(message_loop_.task_runner()));
237 #endif // !defined(MEDIA_DISABLE_LIBVPX)
239 #if !defined(MEDIA_DISABLE_FFMPEG)
240 video_decoders.push_back(
241 new FFmpegVideoDecoder(message_loop_.task_runner()));
242 #endif
244 // Simulate a 60Hz rendering sink.
245 video_sink_.reset(new NullVideoSink(
246 clockless_playback_, base::TimeDelta::FromSecondsD(1.0 / 60),
247 base::Bind(&PipelineIntegrationTestBase::OnVideoFramePaint,
248 base::Unretained(this)),
249 message_loop_.task_runner()));
251 // Disable frame dropping if hashing is enabled.
252 scoped_ptr<VideoRenderer> video_renderer(new VideoRendererImpl(
253 message_loop_.task_runner(), video_sink_.get(),
254 video_decoders.Pass(), false, nullptr, new MediaLog()));
256 if (!clockless_playback_) {
257 audio_sink_ = new NullAudioSink(message_loop_.task_runner());
258 } else {
259 clockless_audio_sink_ = new ClocklessAudioSink();
262 ScopedVector<AudioDecoder> audio_decoders;
264 #if !defined(MEDIA_DISABLE_FFMPEG)
265 audio_decoders.push_back(
266 new FFmpegAudioDecoder(message_loop_.task_runner(), LogCB()));
267 #endif
269 audio_decoders.push_back(
270 new OpusAudioDecoder(message_loop_.task_runner()));
272 AudioParameters out_params(AudioParameters::AUDIO_PCM_LOW_LATENCY,
273 CHANNEL_LAYOUT_STEREO,
274 44100,
276 512);
277 hardware_config_.UpdateOutputConfig(out_params);
279 scoped_ptr<AudioRenderer> audio_renderer(new AudioRendererImpl(
280 message_loop_.task_runner(),
281 (clockless_playback_)
282 ? static_cast<AudioRendererSink*>(clockless_audio_sink_.get())
283 : audio_sink_.get(),
284 audio_decoders.Pass(), hardware_config_, new MediaLog()));
285 if (hashing_enabled_)
286 audio_sink_->StartAudioHashForTesting();
288 scoped_ptr<RendererImpl> renderer_impl(
289 new RendererImpl(message_loop_.task_runner(),
290 audio_renderer.Pass(),
291 video_renderer.Pass()));
293 // Prevent non-deterministic buffering state callbacks from firing (e.g., slow
294 // machine, valgrind).
295 renderer_impl->DisableUnderflowForTesting();
297 if (clockless_playback_)
298 renderer_impl->EnableClocklessVideoPlaybackForTesting();
300 return renderer_impl.Pass();
303 void PipelineIntegrationTestBase::OnVideoFramePaint(
304 const scoped_refptr<VideoFrame>& frame) {
305 last_video_frame_format_ = frame->format();
306 int result;
307 if (frame->metadata()->GetInteger(VideoFrameMetadata::COLOR_SPACE, &result))
308 last_video_frame_color_space_ = static_cast<VideoFrame::ColorSpace>(result);
309 if (!hashing_enabled_)
310 return;
311 VideoFrame::HashFrameForTesting(&md5_context_, frame);
314 std::string PipelineIntegrationTestBase::GetVideoHash() {
315 DCHECK(hashing_enabled_);
316 base::MD5Digest digest;
317 base::MD5Final(&digest, &md5_context_);
318 return base::MD5DigestToBase16(digest);
321 std::string PipelineIntegrationTestBase::GetAudioHash() {
322 DCHECK(hashing_enabled_);
323 return audio_sink_->GetAudioHashForTesting();
326 base::TimeDelta PipelineIntegrationTestBase::GetAudioTime() {
327 DCHECK(clockless_playback_);
328 return clockless_audio_sink_->render_time();
331 base::TimeTicks DummyTickClock::NowTicks() {
332 now_ += base::TimeDelta::FromSeconds(60);
333 return now_;
336 } // namespace media