Upstreaming browser/ui/uikit_ui_util from iOS.
[chromium-blink-merge.git] / media / test / pipeline_integration_test_base.cc
blobcd72c3d69a6068084734381b82ac08facdb5e310
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_(new Pipeline(message_loop_.task_runner(), new MediaLog())),
43 ended_(false),
44 pipeline_status_(PIPELINE_OK),
45 last_video_frame_format_(PIXEL_FORMAT_UNKNOWN),
46 last_video_frame_color_space_(COLOR_SPACE_UNSPECIFIED),
47 hardware_config_(AudioParameters(), AudioParameters()) {
48 base::MD5Init(&md5_context_);
51 PipelineIntegrationTestBase::~PipelineIntegrationTestBase() {
52 if (!pipeline_->IsRunning())
53 return;
55 Stop();
58 void PipelineIntegrationTestBase::OnSeeked(base::TimeDelta seek_time,
59 PipelineStatus status) {
60 EXPECT_EQ(seek_time, pipeline_->GetMediaTime());
61 pipeline_status_ = status;
64 void PipelineIntegrationTestBase::OnStatusCallback(
65 PipelineStatus status) {
66 pipeline_status_ = status;
67 message_loop_.PostTask(FROM_HERE, base::MessageLoop::QuitClosure());
70 void PipelineIntegrationTestBase::DemuxerEncryptedMediaInitDataCB(
71 EmeInitDataType type,
72 const std::vector<uint8>& init_data) {
73 DCHECK(!init_data.empty());
74 CHECK(!encrypted_media_init_data_cb_.is_null());
75 encrypted_media_init_data_cb_.Run(type, init_data);
78 void PipelineIntegrationTestBase::OnEnded() {
79 DCHECK(!ended_);
80 ended_ = true;
81 pipeline_status_ = PIPELINE_OK;
82 message_loop_.PostTask(FROM_HERE, base::MessageLoop::QuitClosure());
85 bool PipelineIntegrationTestBase::WaitUntilOnEnded() {
86 if (ended_)
87 return (pipeline_status_ == PIPELINE_OK);
88 message_loop_.Run();
89 EXPECT_TRUE(ended_);
90 return ended_ && (pipeline_status_ == PIPELINE_OK);
93 PipelineStatus PipelineIntegrationTestBase::WaitUntilEndedOrError() {
94 if (ended_ || pipeline_status_ != PIPELINE_OK)
95 return pipeline_status_;
96 message_loop_.Run();
97 return pipeline_status_;
100 void PipelineIntegrationTestBase::OnError(PipelineStatus status) {
101 DCHECK_NE(status, PIPELINE_OK);
102 pipeline_status_ = status;
103 message_loop_.PostTask(FROM_HERE, base::MessageLoop::QuitClosure());
106 PipelineStatus PipelineIntegrationTestBase::Start(const std::string& filename) {
107 return Start(filename, nullptr);
110 PipelineStatus PipelineIntegrationTestBase::Start(const std::string& filename,
111 CdmContext* cdm_context) {
112 EXPECT_CALL(*this, OnMetadata(_))
113 .Times(AtMost(1))
114 .WillRepeatedly(SaveArg<0>(&metadata_));
115 EXPECT_CALL(*this, OnBufferingStateChanged(BUFFERING_HAVE_ENOUGH))
116 .Times(AnyNumber());
117 EXPECT_CALL(*this, OnBufferingStateChanged(BUFFERING_HAVE_NOTHING))
118 .Times(AnyNumber());
119 CreateDemuxer(filename);
121 if (cdm_context) {
122 EXPECT_CALL(*this, DecryptorAttached(true));
123 pipeline_->SetCdm(
124 cdm_context, base::Bind(&PipelineIntegrationTestBase::DecryptorAttached,
125 base::Unretained(this)));
128 // Should never be called as the required decryption keys for the encrypted
129 // media files are provided in advance.
130 EXPECT_CALL(*this, OnWaitingForDecryptionKey()).Times(0);
132 pipeline_->Start(
133 demuxer_.get(), CreateRenderer(),
134 base::Bind(&PipelineIntegrationTestBase::OnEnded, base::Unretained(this)),
135 base::Bind(&PipelineIntegrationTestBase::OnError, base::Unretained(this)),
136 base::Bind(&PipelineIntegrationTestBase::OnStatusCallback,
137 base::Unretained(this)),
138 base::Bind(&PipelineIntegrationTestBase::OnMetadata,
139 base::Unretained(this)),
140 base::Bind(&PipelineIntegrationTestBase::OnBufferingStateChanged,
141 base::Unretained(this)),
142 base::Closure(), base::Bind(&PipelineIntegrationTestBase::OnAddTextTrack,
143 base::Unretained(this)),
144 base::Bind(&PipelineIntegrationTestBase::OnWaitingForDecryptionKey,
145 base::Unretained(this)));
146 message_loop_.Run();
147 return pipeline_status_;
150 PipelineStatus PipelineIntegrationTestBase::Start(const std::string& filename,
151 uint8_t test_type) {
152 hashing_enabled_ = test_type & kHashed;
153 clockless_playback_ = test_type & kClockless;
154 return Start(filename);
157 void PipelineIntegrationTestBase::Play() {
158 pipeline_->SetPlaybackRate(1);
161 void PipelineIntegrationTestBase::Pause() {
162 pipeline_->SetPlaybackRate(0);
165 bool PipelineIntegrationTestBase::Seek(base::TimeDelta seek_time) {
166 ended_ = false;
168 EXPECT_CALL(*this, OnBufferingStateChanged(BUFFERING_HAVE_ENOUGH))
169 .WillOnce(InvokeWithoutArgs(&message_loop_, &base::MessageLoop::QuitNow));
170 pipeline_->Seek(seek_time, base::Bind(&PipelineIntegrationTestBase::OnSeeked,
171 base::Unretained(this), seek_time));
172 message_loop_.Run();
173 return (pipeline_status_ == PIPELINE_OK);
176 void PipelineIntegrationTestBase::Stop() {
177 DCHECK(pipeline_->IsRunning());
178 pipeline_->Stop(base::MessageLoop::QuitClosure());
179 message_loop_.Run();
182 void PipelineIntegrationTestBase::QuitAfterCurrentTimeTask(
183 const base::TimeDelta& quit_time) {
184 if (pipeline_->GetMediaTime() >= quit_time ||
185 pipeline_status_ != PIPELINE_OK) {
186 message_loop_.Quit();
187 return;
190 message_loop_.PostDelayedTask(
191 FROM_HERE,
192 base::Bind(&PipelineIntegrationTestBase::QuitAfterCurrentTimeTask,
193 base::Unretained(this), quit_time),
194 base::TimeDelta::FromMilliseconds(10));
197 bool PipelineIntegrationTestBase::WaitUntilCurrentTimeIsAfter(
198 const base::TimeDelta& wait_time) {
199 DCHECK(pipeline_->IsRunning());
200 DCHECK_GT(pipeline_->GetPlaybackRate(), 0);
201 DCHECK(wait_time <= pipeline_->GetMediaDuration());
203 message_loop_.PostDelayedTask(
204 FROM_HERE,
205 base::Bind(&PipelineIntegrationTestBase::QuitAfterCurrentTimeTask,
206 base::Unretained(this),
207 wait_time),
208 base::TimeDelta::FromMilliseconds(10));
209 message_loop_.Run();
210 return (pipeline_status_ == PIPELINE_OK);
213 void PipelineIntegrationTestBase::CreateDemuxer(const std::string& filename) {
214 FileDataSource* file_data_source = new FileDataSource();
215 base::FilePath file_path(GetTestDataFilePath(filename));
216 CHECK(file_data_source->Initialize(file_path)) << "Is " << file_path.value()
217 << " missing?";
218 data_source_.reset(file_data_source);
220 Demuxer::EncryptedMediaInitDataCB encrypted_media_init_data_cb =
221 base::Bind(&PipelineIntegrationTestBase::DemuxerEncryptedMediaInitDataCB,
222 base::Unretained(this));
224 #if !defined(MEDIA_DISABLE_FFMPEG)
225 demuxer_ = scoped_ptr<Demuxer>(
226 new FFmpegDemuxer(message_loop_.task_runner(), data_source_.get(),
227 encrypted_media_init_data_cb, new MediaLog()));
228 #endif
231 scoped_ptr<Renderer> PipelineIntegrationTestBase::CreateRenderer() {
232 ScopedVector<VideoDecoder> video_decoders;
233 #if !defined(MEDIA_DISABLE_LIBVPX)
234 video_decoders.push_back(
235 new VpxVideoDecoder(message_loop_.task_runner()));
236 #endif // !defined(MEDIA_DISABLE_LIBVPX)
238 #if !defined(MEDIA_DISABLE_FFMPEG)
239 video_decoders.push_back(
240 new FFmpegVideoDecoder(message_loop_.task_runner()));
241 #endif
243 // Simulate a 60Hz rendering sink.
244 video_sink_.reset(new NullVideoSink(
245 clockless_playback_, base::TimeDelta::FromSecondsD(1.0 / 60),
246 base::Bind(&PipelineIntegrationTestBase::OnVideoFramePaint,
247 base::Unretained(this)),
248 message_loop_.task_runner()));
250 // Disable frame dropping if hashing is enabled.
251 scoped_ptr<VideoRenderer> video_renderer(new VideoRendererImpl(
252 message_loop_.task_runner(), video_sink_.get(),
253 video_decoders.Pass(), false, nullptr, new MediaLog()));
255 if (!clockless_playback_) {
256 audio_sink_ = new NullAudioSink(message_loop_.task_runner());
257 } else {
258 clockless_audio_sink_ = new ClocklessAudioSink();
261 ScopedVector<AudioDecoder> audio_decoders;
263 #if !defined(MEDIA_DISABLE_FFMPEG)
264 audio_decoders.push_back(
265 new FFmpegAudioDecoder(message_loop_.task_runner(), new MediaLog()));
266 #endif
268 audio_decoders.push_back(
269 new OpusAudioDecoder(message_loop_.task_runner()));
271 // Don't allow the audio renderer to resample buffers if hashing is enabled.
272 if (!hashing_enabled_) {
273 AudioParameters out_params(AudioParameters::AUDIO_PCM_LOW_LATENCY,
274 CHANNEL_LAYOUT_STEREO,
275 44100,
277 512);
278 hardware_config_.UpdateOutputConfig(out_params);
281 scoped_ptr<AudioRenderer> audio_renderer(new AudioRendererImpl(
282 message_loop_.task_runner(),
283 (clockless_playback_)
284 ? static_cast<AudioRendererSink*>(clockless_audio_sink_.get())
285 : audio_sink_.get(),
286 audio_decoders.Pass(), hardware_config_, new MediaLog()));
287 if (hashing_enabled_) {
288 if (clockless_playback_)
289 clockless_audio_sink_->StartAudioHashForTesting();
290 else
291 audio_sink_->StartAudioHashForTesting();
294 scoped_ptr<RendererImpl> renderer_impl(
295 new RendererImpl(message_loop_.task_runner(),
296 audio_renderer.Pass(),
297 video_renderer.Pass()));
299 // Prevent non-deterministic buffering state callbacks from firing (e.g., slow
300 // machine, valgrind).
301 renderer_impl->DisableUnderflowForTesting();
303 if (clockless_playback_)
304 renderer_impl->EnableClocklessVideoPlaybackForTesting();
306 return renderer_impl.Pass();
309 void PipelineIntegrationTestBase::OnVideoFramePaint(
310 const scoped_refptr<VideoFrame>& frame) {
311 last_video_frame_format_ = frame->format();
312 int result;
313 if (frame->metadata()->GetInteger(VideoFrameMetadata::COLOR_SPACE, &result))
314 last_video_frame_color_space_ = static_cast<ColorSpace>(result);
315 if (!hashing_enabled_)
316 return;
317 VideoFrame::HashFrameForTesting(&md5_context_, frame);
320 std::string PipelineIntegrationTestBase::GetVideoHash() {
321 DCHECK(hashing_enabled_);
322 base::MD5Digest digest;
323 base::MD5Final(&digest, &md5_context_);
324 return base::MD5DigestToBase16(digest);
327 std::string PipelineIntegrationTestBase::GetAudioHash() {
328 DCHECK(hashing_enabled_);
330 if (clockless_playback_)
331 return clockless_audio_sink_->GetAudioHashForTesting();
332 return audio_sink_->GetAudioHashForTesting();
335 base::TimeDelta PipelineIntegrationTestBase::GetAudioTime() {
336 DCHECK(clockless_playback_);
337 return clockless_audio_sink_->render_time();
340 base::TimeTicks DummyTickClock::NowTicks() {
341 now_ += base::TimeDelta::FromSeconds(60);
342 return now_;
345 } // namespace media