ozone: evdev: Sync caps lock LED state to evdev
[chromium-blink-merge.git] / chromecast / media / cma / backend / audio_video_pipeline_device_unittest.cc
blob26f903e855f30b1c36bf59fe44e887cfac3f9266
1 // Copyright 2014 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 <vector>
7 #include "base/basictypes.h"
8 #include "base/bind.h"
9 #include "base/files/file_path.h"
10 #include "base/files/memory_mapped_file.h"
11 #include "base/logging.h"
12 #include "base/memory/ref_counted.h"
13 #include "base/memory/scoped_ptr.h"
14 #include "base/memory/scoped_vector.h"
15 #include "base/message_loop/message_loop.h"
16 #include "base/message_loop/message_loop_proxy.h"
17 #include "base/path_service.h"
18 #include "base/threading/thread.h"
19 #include "base/time/time.h"
20 #include "chromecast/media/base/decrypt_context.h"
21 #include "chromecast/media/cma/backend/audio_pipeline_device.h"
22 #include "chromecast/media/cma/backend/media_clock_device.h"
23 #include "chromecast/media/cma/backend/media_pipeline_device.h"
24 #include "chromecast/media/cma/backend/media_pipeline_device_params.h"
25 #include "chromecast/media/cma/backend/video_pipeline_device.h"
26 #include "chromecast/media/cma/base/decoder_buffer_adapter.h"
27 #include "chromecast/media/cma/base/decoder_buffer_base.h"
28 #include "chromecast/media/cma/test/frame_segmenter_for_test.h"
29 #include "chromecast/media/cma/test/media_component_device_feeder_for_test.h"
30 #include "media/base/audio_decoder_config.h"
31 #include "media/base/buffers.h"
32 #include "media/base/decoder_buffer.h"
33 #include "media/base/video_decoder_config.h"
34 #include "testing/gtest/include/gtest/gtest.h"
36 namespace chromecast {
37 namespace media {
39 namespace {
41 typedef ScopedVector<MediaComponentDeviceFeederForTest>::iterator
42 ComponentDeviceIterator;
44 const base::TimeDelta kMonitorLoopDelay = base::TimeDelta::FromMilliseconds(20);
46 base::FilePath GetTestDataFilePath(const std::string& name) {
47 base::FilePath file_path;
48 CHECK(PathService::Get(base::DIR_SOURCE_ROOT, &file_path));
50 file_path = file_path.Append(FILE_PATH_LITERAL("media"))
51 .Append(FILE_PATH_LITERAL("test")).Append(FILE_PATH_LITERAL("data"))
52 .AppendASCII(name);
53 return file_path;
56 } // namespace
58 class AudioVideoPipelineDeviceTest : public testing::Test {
59 public:
60 struct PauseInfo {
61 PauseInfo() {}
62 PauseInfo(base::TimeDelta d, base::TimeDelta l) : delay(d), length(l) {}
63 ~PauseInfo() {}
65 base::TimeDelta delay;
66 base::TimeDelta length;
69 AudioVideoPipelineDeviceTest();
70 ~AudioVideoPipelineDeviceTest() override;
72 void ConfigureForFile(std::string filename);
73 void ConfigureForAudioOnly(std::string filename);
74 void ConfigureForVideoOnly(std::string filename, bool raw_h264);
76 // Pattern loops, waiting >= pattern[i].delay against media clock between
77 // pauses, then pausing for >= pattern[i].length against MessageLoop
78 // A pause with delay <0 signals to stop sequence and do not loop
79 void SetPausePattern(const std::vector<PauseInfo> pattern);
81 // Adds a pause to the end of pause pattern
82 void AddPause(base::TimeDelta delay, base::TimeDelta length);
84 void Start();
86 private:
87 void Initialize();
89 void LoadAudioStream(std::string filename);
90 void LoadVideoStream(std::string filename, bool raw_h264);
92 void MonitorLoop();
94 void OnPauseCompleted();
96 void OnEos(MediaComponentDeviceFeederForTest* device_feeder);
98 scoped_ptr<MediaPipelineDevice> media_pipeline_device_;
99 MediaClockDevice* media_clock_device_;
101 // Devices to feed
102 ScopedVector<MediaComponentDeviceFeederForTest>
103 component_device_feeders_;
105 // Current media time.
106 base::TimeDelta pause_time_;
108 // Pause settings
109 std::vector<PauseInfo> pause_pattern_;
110 int pause_pattern_idx_;
112 DISALLOW_COPY_AND_ASSIGN(AudioVideoPipelineDeviceTest);
115 AudioVideoPipelineDeviceTest::AudioVideoPipelineDeviceTest()
116 : pause_pattern_() {
119 AudioVideoPipelineDeviceTest::~AudioVideoPipelineDeviceTest() {
122 void AudioVideoPipelineDeviceTest::AddPause(base::TimeDelta delay,
123 base::TimeDelta length) {
124 pause_pattern_.push_back(PauseInfo(delay, length));
127 void AudioVideoPipelineDeviceTest::SetPausePattern(
128 const std::vector<PauseInfo> pattern) {
129 pause_pattern_ = pattern;
132 void AudioVideoPipelineDeviceTest::ConfigureForAudioOnly(std::string filename) {
133 Initialize();
134 LoadAudioStream(filename);
137 void AudioVideoPipelineDeviceTest::ConfigureForVideoOnly(std::string filename,
138 bool raw_h264) {
139 Initialize();
140 LoadVideoStream(filename, raw_h264);
143 void AudioVideoPipelineDeviceTest::ConfigureForFile(std::string filename) {
144 Initialize();
145 LoadVideoStream(filename, false /* raw_h264 */);
146 LoadAudioStream(filename);
149 void AudioVideoPipelineDeviceTest::LoadAudioStream(std::string filename) {
150 base::FilePath file_path = GetTestDataFilePath(filename);
151 DemuxResult demux_result = FFmpegDemuxForTest(file_path, true /* audio */);
152 BufferList frames = demux_result.frames;
154 AudioPipelineDevice* audio_pipeline_device =
155 media_pipeline_device_->GetAudioPipelineDevice();
157 bool success = audio_pipeline_device->SetConfig(demux_result.audio_config);
158 ASSERT_TRUE(success);
160 VLOG(2) << "Got " << frames.size() << " audio input frames";
162 frames.push_back(
163 scoped_refptr<DecoderBufferBase>(
164 new DecoderBufferAdapter(::media::DecoderBuffer::CreateEOSBuffer())));
166 MediaComponentDeviceFeederForTest* device_feeder =
167 new MediaComponentDeviceFeederForTest(audio_pipeline_device, frames);
168 device_feeder->Initialize(base::Bind(&AudioVideoPipelineDeviceTest::OnEos,
169 base::Unretained(this),
170 device_feeder));
171 component_device_feeders_.push_back(device_feeder);
174 void AudioVideoPipelineDeviceTest::LoadVideoStream(std::string filename,
175 bool raw_h264) {
176 BufferList frames;
177 ::media::VideoDecoderConfig video_config;
179 if (raw_h264) {
180 base::FilePath file_path = GetTestDataFilePath(filename);
181 base::MemoryMappedFile video_stream;
182 ASSERT_TRUE(video_stream.Initialize(file_path))
183 << "Couldn't open stream file: " << file_path.MaybeAsASCII();
184 frames = H264SegmenterForTest(video_stream.data(), video_stream.length());
186 // Use arbitraty sizes.
187 gfx::Size coded_size(320, 240);
188 gfx::Rect visible_rect(0, 0, 320, 240);
189 gfx::Size natural_size(320, 240);
191 // TODO(kjoswiak): Either pull data from stream or make caller specify value
192 video_config = ::media::VideoDecoderConfig(
193 ::media::kCodecH264,
194 ::media::H264PROFILE_MAIN,
195 ::media::VideoFrame::I420,
196 coded_size,
197 visible_rect,
198 natural_size,
199 NULL, 0, false);
200 } else {
201 base::FilePath file_path = GetTestDataFilePath(filename);
202 DemuxResult demux_result = FFmpegDemuxForTest(file_path,
203 /*audio*/ false);
204 frames = demux_result.frames;
205 video_config = demux_result.video_config;
208 VideoPipelineDevice* video_pipeline_device =
209 media_pipeline_device_->GetVideoPipelineDevice();
211 // Set configuration.
212 bool success = video_pipeline_device->SetConfig(video_config);
213 ASSERT_TRUE(success);
215 VLOG(2) << "Got " << frames.size() << " video input frames";
217 frames.push_back(
218 scoped_refptr<DecoderBufferBase>(new DecoderBufferAdapter(
219 ::media::DecoderBuffer::CreateEOSBuffer())));
221 MediaComponentDeviceFeederForTest* device_feeder =
222 new MediaComponentDeviceFeederForTest(video_pipeline_device, frames);
223 device_feeder->Initialize(base::Bind(&AudioVideoPipelineDeviceTest::OnEos,
224 base::Unretained(this),
225 device_feeder));
226 component_device_feeders_.push_back(device_feeder);
229 void AudioVideoPipelineDeviceTest::Start() {
230 pause_time_ = base::TimeDelta();
231 pause_pattern_idx_ = 0;
233 for (int i = 0; i < component_device_feeders_.size(); i++) {
234 base::MessageLoopProxy::current()->PostTask(
235 FROM_HERE,
236 base::Bind(&MediaComponentDeviceFeederForTest::Feed,
237 base::Unretained(component_device_feeders_[i])));
240 media_clock_device_->SetState(MediaClockDevice::kStateRunning);
242 base::MessageLoopProxy::current()->PostTask(
243 FROM_HERE,
244 base::Bind(&AudioVideoPipelineDeviceTest::MonitorLoop,
245 base::Unretained(this)));
248 void AudioVideoPipelineDeviceTest::MonitorLoop() {
249 base::TimeDelta media_time = media_clock_device_->GetTime();
251 if (!pause_pattern_.empty() &&
252 pause_pattern_[pause_pattern_idx_].delay >= base::TimeDelta() &&
253 media_time >= pause_time_ + pause_pattern_[pause_pattern_idx_].delay) {
254 // Do Pause
255 media_clock_device_->SetRate(0.0);
256 pause_time_ = media_clock_device_->GetTime();
258 VLOG(2) << "Pausing at " << pause_time_.InMilliseconds() << "ms for " <<
259 pause_pattern_[pause_pattern_idx_].length.InMilliseconds() << "ms";
261 // Wait for pause finish
262 base::MessageLoopProxy::current()->PostDelayedTask(
263 FROM_HERE,
264 base::Bind(&AudioVideoPipelineDeviceTest::OnPauseCompleted,
265 base::Unretained(this)),
266 pause_pattern_[pause_pattern_idx_].length);
267 return;
270 // Check state again in a little while
271 base::MessageLoopProxy::current()->PostDelayedTask(
272 FROM_HERE,
273 base::Bind(&AudioVideoPipelineDeviceTest::MonitorLoop,
274 base::Unretained(this)),
275 kMonitorLoopDelay);
278 void AudioVideoPipelineDeviceTest::OnPauseCompleted() {
279 // Make sure the media time didn't move during that time.
280 base::TimeDelta media_time = media_clock_device_->GetTime();
282 // TODO(damienv):
283 // Should be:
284 // EXPECT_EQ(media_time, media_time_);
285 // However, some backends, when rendering the first frame while in paused
286 // mode moves the time forward.
287 // This behaviour is not intended.
288 EXPECT_GE(media_time, pause_time_);
289 EXPECT_LE(media_time, pause_time_ + base::TimeDelta::FromMilliseconds(50));
291 pause_time_ = media_time;
292 pause_pattern_idx_ = (pause_pattern_idx_ + 1) % pause_pattern_.size();
294 VLOG(2) << "Pause complete, restarting media clock";
296 // Resume playback and frame feeding.
297 media_clock_device_->SetRate(1.0);
299 MonitorLoop();
302 void AudioVideoPipelineDeviceTest::OnEos(
303 MediaComponentDeviceFeederForTest* device_feeder) {
304 for (ComponentDeviceIterator it = component_device_feeders_.begin();
305 it != component_device_feeders_.end();
306 ++it) {
307 if (*it == device_feeder) {
308 component_device_feeders_.erase(it);
309 break;
313 // Check if all streams finished
314 if (component_device_feeders_.empty())
315 base::MessageLoop::current()->QuitWhenIdle();
318 void AudioVideoPipelineDeviceTest::Initialize() {
319 // Create the media device.
320 MediaPipelineDeviceParams params;
321 media_pipeline_device_.reset(CreateMediaPipelineDevice(params).release());
322 media_clock_device_ = media_pipeline_device_->GetMediaClockDevice();
324 // Clock initialization and configuration.
325 bool success =
326 media_clock_device_->SetState(MediaClockDevice::kStateIdle);
327 ASSERT_TRUE(success);
328 success = media_clock_device_->ResetTimeline(base::TimeDelta());
329 ASSERT_TRUE(success);
330 media_clock_device_->SetRate(1.0);
333 TEST_F(AudioVideoPipelineDeviceTest, Mp3Playback) {
334 scoped_ptr<base::MessageLoop> message_loop(new base::MessageLoop());
336 ConfigureForAudioOnly("sfx.mp3");
337 Start();
338 message_loop->Run();
341 TEST_F(AudioVideoPipelineDeviceTest, VorbisPlayback) {
342 scoped_ptr<base::MessageLoop> message_loop(new base::MessageLoop());
344 ConfigureForAudioOnly("sfx.ogg");
345 Start();
346 message_loop->Run();
349 TEST_F(AudioVideoPipelineDeviceTest, H264Playback) {
350 scoped_ptr<base::MessageLoop> message_loop(new base::MessageLoop());
352 ConfigureForVideoOnly("bear.h264", true /* raw_h264 */);
353 Start();
354 message_loop->Run();
357 TEST_F(AudioVideoPipelineDeviceTest, WebmPlaybackWithPause) {
358 scoped_ptr<base::MessageLoop> message_loop(new base::MessageLoop());
360 // Setup to pause for 100ms every 500ms
361 AddPause(base::TimeDelta::FromMilliseconds(500),
362 base::TimeDelta::FromMilliseconds(100));
364 ConfigureForVideoOnly("bear-640x360.webm", false /* raw_h264 */);
365 Start();
366 message_loop->Run();
369 TEST_F(AudioVideoPipelineDeviceTest, Vp8Playback) {
370 scoped_ptr<base::MessageLoop> message_loop(new base::MessageLoop());
372 ConfigureForVideoOnly("bear-vp8a.webm", false /* raw_h264 */);
373 Start();
374 message_loop->Run();
377 TEST_F(AudioVideoPipelineDeviceTest, WebmPlayback) {
378 scoped_ptr<base::MessageLoop> message_loop(new base::MessageLoop());
380 ConfigureForFile("bear-640x360.webm");
381 Start();
382 message_loop->Run();
385 } // namespace media
386 } // namespace chromecast