Upstream version 11.40.271.0
[platform/framework/web/crosswalk.git] / src / chromecast / media / cma / backend / audio_video_pipeline_device_unittest.cc
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.
4
5 #include <vector>
6
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"
35
36 namespace chromecast {
37 namespace media {
38
39 namespace {
40
41 typedef ScopedVector<MediaComponentDeviceFeederForTest>::iterator
42     ComponentDeviceIterator;
43
44 const base::TimeDelta kMonitorLoopDelay = base::TimeDelta::FromMilliseconds(20);
45
46 base::FilePath GetTestDataFilePath(const std::string& name) {
47   base::FilePath file_path;
48   CHECK(PathService::Get(base::DIR_SOURCE_ROOT, &file_path));
49
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;
54 }
55
56 }  // namespace
57
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() {}
64
65     base::TimeDelta delay;
66     base::TimeDelta length;
67   };
68
69   AudioVideoPipelineDeviceTest();
70   virtual ~AudioVideoPipelineDeviceTest();
71
72   void ConfigureForFile(std::string filename);
73   void ConfigureForAudioOnly(std::string filename);
74   void ConfigureForVideoOnly(std::string filename, bool raw_h264);
75
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);
80
81   // Adds a pause to the end of pause pattern
82   void AddPause(base::TimeDelta delay, base::TimeDelta length);
83
84   void Start();
85
86  private:
87   void Initialize();
88
89   void LoadAudioStream(std::string filename);
90   void LoadVideoStream(std::string filename, bool raw_h264);
91
92   void MonitorLoop();
93
94   void OnPauseCompleted();
95
96   void OnEos(MediaComponentDeviceFeederForTest* device_feeder);
97
98   scoped_ptr<MediaPipelineDevice> media_pipeline_device_;
99   MediaClockDevice* media_clock_device_;
100
101   // Devices to feed
102   ScopedVector<MediaComponentDeviceFeederForTest>
103       component_device_feeders_;
104
105   // Current media time.
106   base::TimeDelta pause_time_;
107
108   // Pause settings
109   std::vector<PauseInfo> pause_pattern_;
110   int pause_pattern_idx_;
111
112   DISALLOW_COPY_AND_ASSIGN(AudioVideoPipelineDeviceTest);
113 };
114
115 AudioVideoPipelineDeviceTest::AudioVideoPipelineDeviceTest()
116     : pause_pattern_() {
117 }
118
119 AudioVideoPipelineDeviceTest::~AudioVideoPipelineDeviceTest() {
120 }
121
122 void AudioVideoPipelineDeviceTest::AddPause(base::TimeDelta delay,
123                                             base::TimeDelta length) {
124   pause_pattern_.push_back(PauseInfo(delay, length));
125 }
126
127 void AudioVideoPipelineDeviceTest::SetPausePattern(
128     const std::vector<PauseInfo> pattern) {
129   pause_pattern_ = pattern;
130 }
131
132 void AudioVideoPipelineDeviceTest::ConfigureForAudioOnly(std::string filename) {
133   Initialize();
134   LoadAudioStream(filename);
135 }
136
137 void AudioVideoPipelineDeviceTest::ConfigureForVideoOnly(std::string filename,
138                                                          bool raw_h264) {
139   Initialize();
140   LoadVideoStream(filename, raw_h264);
141 }
142
143 void AudioVideoPipelineDeviceTest::ConfigureForFile(std::string filename) {
144   Initialize();
145   LoadVideoStream(filename, false /* raw_h264 */);
146   LoadAudioStream(filename);
147 }
148
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;
153
154   AudioPipelineDevice* audio_pipeline_device =
155       media_pipeline_device_->GetAudioPipelineDevice();
156
157   bool success = audio_pipeline_device->SetConfig(demux_result.audio_config);
158   ASSERT_TRUE(success);
159
160   VLOG(2) << "Got " << frames.size() << " audio input frames";
161
162   frames.push_back(
163       scoped_refptr<DecoderBufferBase>(
164           new DecoderBufferAdapter(::media::DecoderBuffer::CreateEOSBuffer())));
165
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);
172 }
173
174 void AudioVideoPipelineDeviceTest::LoadVideoStream(std::string filename,
175                                                    bool raw_h264) {
176   BufferList frames;
177   ::media::VideoDecoderConfig video_config;
178
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());
185
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);
190
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;
206   }
207
208   VideoPipelineDevice* video_pipeline_device =
209       media_pipeline_device_->GetVideoPipelineDevice();
210
211   // Set configuration.
212   bool success = video_pipeline_device->SetConfig(video_config);
213   ASSERT_TRUE(success);
214
215   VLOG(2) << "Got " << frames.size() << " video input frames";
216
217   frames.push_back(
218       scoped_refptr<DecoderBufferBase>(new DecoderBufferAdapter(
219           ::media::DecoderBuffer::CreateEOSBuffer())));
220
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);
227 }
228
229 void AudioVideoPipelineDeviceTest::Start() {
230   pause_time_ = base::TimeDelta();
231   pause_pattern_idx_ = 0;
232
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])));
238   }
239
240   media_clock_device_->SetState(MediaClockDevice::kStateRunning);
241
242   base::MessageLoopProxy::current()->PostTask(
243       FROM_HERE,
244       base::Bind(&AudioVideoPipelineDeviceTest::MonitorLoop,
245                  base::Unretained(this)));
246 }
247
248 void AudioVideoPipelineDeviceTest::MonitorLoop() {
249   base::TimeDelta media_time = media_clock_device_->GetTime();
250
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();
257
258     VLOG(2) << "Pausing at " << pause_time_.InMilliseconds() << "ms for " <<
259         pause_pattern_[pause_pattern_idx_].length.InMilliseconds() << "ms";
260
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;
268   }
269
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);
276 }
277
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();
281
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));
290
291   pause_time_ = media_time;
292   pause_pattern_idx_ = (pause_pattern_idx_ + 1) % pause_pattern_.size();
293
294   VLOG(2) << "Pause complete, restarting media clock";
295
296   // Resume playback and frame feeding.
297   media_clock_device_->SetRate(1.0);
298
299   MonitorLoop();
300 }
301
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;
310     }
311   }
312
313   // Check if all streams finished
314   if (component_device_feeders_.empty())
315     base::MessageLoop::current()->QuitWhenIdle();
316 }
317
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();
323
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);
331 }
332
333 TEST_F(AudioVideoPipelineDeviceTest, Mp3Playback) {
334   scoped_ptr<base::MessageLoop> message_loop(new base::MessageLoop());
335
336   ConfigureForAudioOnly("sfx.mp3");
337   Start();
338   message_loop->Run();
339 }
340
341 TEST_F(AudioVideoPipelineDeviceTest, VorbisPlayback) {
342   scoped_ptr<base::MessageLoop> message_loop(new base::MessageLoop());
343
344   ConfigureForAudioOnly("sfx.ogg");
345   Start();
346   message_loop->Run();
347 }
348
349 TEST_F(AudioVideoPipelineDeviceTest, H264Playback) {
350   scoped_ptr<base::MessageLoop> message_loop(new base::MessageLoop());
351
352   ConfigureForVideoOnly("bear.h264", true /* raw_h264 */);
353   Start();
354   message_loop->Run();
355 }
356
357 TEST_F(AudioVideoPipelineDeviceTest, WebmPlaybackWithPause) {
358   scoped_ptr<base::MessageLoop> message_loop(new base::MessageLoop());
359
360   // Setup to pause for 100ms every 500ms
361   AddPause(base::TimeDelta::FromMilliseconds(500),
362            base::TimeDelta::FromMilliseconds(100));
363
364   ConfigureForVideoOnly("bear-640x360.webm", false /* raw_h264 */);
365   Start();
366   message_loop->Run();
367 }
368
369 TEST_F(AudioVideoPipelineDeviceTest, Vp8Playback) {
370   scoped_ptr<base::MessageLoop> message_loop(new base::MessageLoop());
371
372   ConfigureForVideoOnly("bear-vp8a.webm", false /* raw_h264 */);
373   Start();
374   message_loop->Run();
375 }
376
377 TEST_F(AudioVideoPipelineDeviceTest, WebmPlayback) {
378   scoped_ptr<base::MessageLoop> message_loop(new base::MessageLoop());
379
380   ConfigureForFile("bear-640x360.webm");
381   Start();
382   message_loop->Run();
383 }
384
385 }  // namespace media
386 }  // namespace chromecast