Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(451)

Side by Side Diff: media/base/android/media_codec_decoder_unittest.cc

Issue 1176993005: Audio and video decoders for MediaCodecPlayer (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Refactored DataFactory into a separate file Created 5 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright 2015 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 "base/bind.h"
6 #include "base/logging.h"
7 #include "base/thread_task_runner_handle.h"
8 #include "base/timer/timer.h"
9 #include "media/base/android/media_codec_audio_decoder.h"
10 #include "media/base/android/media_codec_bridge.h"
11 #include "media/base/android/media_codec_video_decoder.h"
12 #include "media/base/android/test_data_factory.h"
13 #include "testing/gtest/include/gtest/gtest.h"
14 #include "ui/gl/android/surface_texture.h"
15
16 namespace media {
17
18 // Helper macro to skip the test if MediaCodecBridge isn't available.
19 #define SKIP_TEST_IF_MEDIA_CODEC_BRIDGE_IS_NOT_AVAILABLE() \
20 do { \
21 if (!MediaCodecBridge::IsAvailable()) { \
22 VLOG(0) << "Could not run test - not supported on device."; \
23 return; \
24 } \
25 } while (0)
26
27 namespace {
28
29 const base::TimeDelta kDefaultTimeout = base::TimeDelta::FromMilliseconds(200);
30 const base::TimeDelta kAudioFramePeriod = base::TimeDelta::FromMilliseconds(20);
31 const base::TimeDelta kVideoFramePeriod = base::TimeDelta::FromMilliseconds(20);
32
33 class AudioFactory : public TestDataFactory {
34 public:
35 AudioFactory(const base::TimeDelta& duration);
36 DemuxerConfigs GetConfigs();
37
38 protected:
39 void ModifyAccessUnit(int index_in_chunk, AccessUnit* unit) override;
40 };
41
42 class VideoFactory : public TestDataFactory {
43 public:
44 VideoFactory(const base::TimeDelta& duration);
45 DemuxerConfigs GetConfigs();
46
47 protected:
48 void ModifyAccessUnit(int index_in_chunk, AccessUnit* unit) override;
49 };
50
51 AudioFactory::AudioFactory(const base::TimeDelta& duration)
52 : TestDataFactory("vorbis-packet-%d", duration, kAudioFramePeriod) {
53 }
54
55 DemuxerConfigs AudioFactory::GetConfigs() {
56 return TestDataFactory::CreateAudioConfigs(kCodecVorbis, duration_);
57 }
58
59 void AudioFactory::ModifyAccessUnit(int index_in_chunk, AccessUnit* unit) {
60 // Vorbis needs 4 extra bytes padding on Android to decode properly. Check
61 // NuMediaExtractor.cpp in Android source code.
62 uint8 padding[4] = {0xff, 0xff, 0xff, 0xff};
63 unit->data.insert(unit->data.end(), padding, padding + 4);
64 }
65
66 VideoFactory::VideoFactory(const base::TimeDelta& duration)
67 : TestDataFactory("h264-320x180-frame-%d", duration, kVideoFramePeriod) {
68 }
69
70 DemuxerConfigs VideoFactory::GetConfigs() {
71 return TestDataFactory::CreateVideoConfigs(kCodecH264, duration_,
72 gfx::Size(320, 180));
73 }
74
75 void VideoFactory::ModifyAccessUnit(int index_in_chunk, AccessUnit* unit) {
76 // The frames are taken from High profile and some are B-frames.
77 // The first 4 frames appear in the file in the following order:
78 //
79 // Frames: I P B P
80 // Decoding order: 0 1 2 3
81 // Presentation order: 0 2 1 4(3)
82 //
83 // I keep the last PTS to be 3 for simplicity.
84
85 // Swap pts for second and third frames.
86 if (index_in_chunk == 1) // second frame
87 unit->timestamp += frame_period_;
88 if (index_in_chunk == 2) // third frame
89 unit->timestamp -= frame_period_;
90
91 if (index_in_chunk == 0)
92 unit->is_key_frame = true;
93 }
94
95 // Class that computes statistics: number of calls, minimum and maximum values.
96 // It is used for PTS statistics to verify that playback did actually happen.
97
98 template <typename T>
99 class Minimax {
100 public:
101 Minimax() : num_values_(0) {}
102 ~Minimax() {}
103
104 void AddValue(const T& value) {
105 ++num_values_;
106 if (value < min_)
107 min_ = value;
108 else if (max_ < value)
109 max_ = value;
110 }
111
112 const T& min() const { return min_; }
113 const T& max() const { return max_; }
114 int num_values() const { return num_values_; }
115
116 private:
117 T min_;
118 T max_;
119 int num_values_;
120 };
121
122 } // namespace (anonymous)
123
124 // The test fixture for MediaCodecDecoder
125
126 class MediaCodecDecoderTest : public testing::Test {
127 public:
128 MediaCodecDecoderTest();
129 ~MediaCodecDecoderTest() override;
130
131 // Conditions we wait for.
132 bool is_prefetched() const { return is_prefetched_; }
133 bool is_stopped() const { return is_stopped_; }
134 bool is_starved() const { return is_starved_; }
135
136 // Prefetch callback has to be public.
137 void SetPrefetched() { is_prefetched_ = true; }
138
139 protected:
140 typedef base::Callback<bool()> Predicate;
141
142 typedef base::Callback<void(const DemuxerData&)> DataAvailableCallback;
143
144 // Waits for condition to become true or for timeout to expire.
145 // Returns true if the condition becomes true.
146 bool WaitForCondition(const Predicate& condition,
147 const base::TimeDelta& timeout = kDefaultTimeout);
148
149 void SetDataFactory(scoped_refptr<TestDataFactory> factory) {
150 data_factory_ = factory;
151 }
152
153 void CreateAudioDecoder();
154 void CreateVideoDecoder();
155 void SetVideoSurface();
156
157 // Decoder callbacks.
158 void OnDataRequested();
159 void OnStarvation() { is_starved_ = true; }
160 void OnStopDone() { is_stopped_ = true; }
161 void OnError() {}
162 void OnUpdateCurrentTime(base::TimeDelta now_playing,
163 base::TimeDelta last_buffered) {
164 pts_stat_.AddValue(now_playing);
165 }
166 void OnVideoSizeChanged(const gfx::Size& video_size) {}
167 void OnVideoCodecCreated() {}
168
169 scoped_ptr<MediaCodecDecoder> decoder_;
170 scoped_refptr<TestDataFactory> data_factory_;
171 Minimax<base::TimeDelta> pts_stat_;
172
173 private:
174 bool is_timeout_expired() const { return is_timeout_expired_; }
175 void SetTimeoutExpired(bool value) { is_timeout_expired_ = value; }
176
177 base::MessageLoop message_loop_;
178 bool is_timeout_expired_;
179
180 bool is_prefetched_;
181 bool is_stopped_;
182 bool is_starved_;
183
184 scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
185 DataAvailableCallback data_available_cb_;
186 scoped_refptr<gfx::SurfaceTexture> surface_texture_;
187
188 DISALLOW_COPY_AND_ASSIGN(MediaCodecDecoderTest);
189 };
190
191 MediaCodecDecoderTest::MediaCodecDecoderTest()
192 : is_timeout_expired_(false),
193 is_prefetched_(false),
194 is_stopped_(false),
195 is_starved_(false),
196 task_runner_(base::ThreadTaskRunnerHandle::Get()) {
197 }
198
199 MediaCodecDecoderTest::~MediaCodecDecoderTest() {
200 }
qinmin 2015/06/18 00:24:40 this can go to the previous line
Tima Vaisburd 2015/06/18 19:34:04 Done.
201
202 bool MediaCodecDecoderTest::WaitForCondition(const Predicate& condition,
203 const base::TimeDelta& timeout) {
204 // Let the message_loop_ process events.
205 // We start the timer and RunUntilIdle() until it signals.
206
207 SetTimeoutExpired(false);
208
209 base::Timer timer(false, false);
210 timer.Start(FROM_HERE, timeout,
211 base::Bind(&MediaCodecDecoderTest::SetTimeoutExpired,
212 base::Unretained(this), true));
213
214 do {
215 if (condition.Run()) {
216 timer.Stop();
217 return true;
218 }
219 message_loop_.RunUntilIdle();
220 } while (!is_timeout_expired());
221
222 DCHECK(!timer.IsRunning());
223 return false;
224 }
225
226 void MediaCodecDecoderTest::CreateAudioDecoder() {
227 decoder_ = scoped_ptr<MediaCodecDecoder>(new MediaCodecAudioDecoder(
228 task_runner_, base::Bind(&MediaCodecDecoderTest::OnDataRequested,
229 base::Unretained(this)),
230 base::Bind(&MediaCodecDecoderTest::OnStarvation, base::Unretained(this)),
231 base::Bind(&MediaCodecDecoderTest::OnStopDone, base::Unretained(this)),
232 base::Bind(&MediaCodecDecoderTest::OnError, base::Unretained(this)),
233 base::Bind(&MediaCodecDecoderTest::OnUpdateCurrentTime,
234 base::Unretained(this))));
235
236 data_available_cb_ = base::Bind(&MediaCodecDecoder::OnDemuxerDataAvailable,
237 base::Unretained(decoder_.get()));
238 }
239
240 void MediaCodecDecoderTest::CreateVideoDecoder() {
241 decoder_ = scoped_ptr<MediaCodecDecoder>(new MediaCodecVideoDecoder(
242 task_runner_, base::Bind(&MediaCodecDecoderTest::OnDataRequested,
243 base::Unretained(this)),
244 base::Bind(&MediaCodecDecoderTest::OnStarvation, base::Unretained(this)),
245 base::Bind(&MediaCodecDecoderTest::OnStopDone, base::Unretained(this)),
246 base::Bind(&MediaCodecDecoderTest::OnError, base::Unretained(this)),
247 base::Bind(&MediaCodecDecoderTest::OnUpdateCurrentTime,
248 base::Unretained(this)),
249 base::Bind(&MediaCodecDecoderTest::OnVideoSizeChanged,
250 base::Unretained(this)),
251 base::Bind(&MediaCodecDecoderTest::OnVideoCodecCreated,
252 base::Unretained(this))));
253
254 data_available_cb_ = base::Bind(&MediaCodecDecoder::OnDemuxerDataAvailable,
255 base::Unretained(decoder_.get()));
256 }
257
258 void MediaCodecDecoderTest::OnDataRequested() {
259 if (!data_factory_)
260 return;
261
262 DemuxerData data;
263 base::TimeDelta delay;
264 data_factory_->CreateChunk(&data, &delay);
265
266 task_runner_->PostDelayedTask(FROM_HERE, base::Bind(data_available_cb_, data),
267 delay);
268 }
269
270 void MediaCodecDecoderTest::SetVideoSurface() {
271 surface_texture_ = gfx::SurfaceTexture::Create(0);
272 gfx::ScopedJavaSurface surface(surface_texture_.get());
273 ASSERT_NE(nullptr, decoder_.get());
274 MediaCodecVideoDecoder* video_decoder =
275 static_cast<MediaCodecVideoDecoder*>(decoder_.get());
276 video_decoder->SetPendingSurface(surface.Pass());
277 }
278
279 TEST_F(MediaCodecDecoderTest, AudioPrefetch) {
280 CreateAudioDecoder();
281
282 base::TimeDelta duration = base::TimeDelta::FromMilliseconds(500);
283 SetDataFactory(scoped_refptr<TestDataFactory>(new AudioFactory(duration)));
284
285 decoder_->Prefetch(base::Bind(&MediaCodecDecoderTest::SetPrefetched,
286 base::Unretained(this)));
287
288 EXPECT_TRUE(WaitForCondition(base::Bind(&MediaCodecDecoderTest::is_prefetched,
289 base::Unretained(this))));
290 }
291
292 TEST_F(MediaCodecDecoderTest, VideoPrefetch) {
293 CreateVideoDecoder();
294
295 base::TimeDelta duration = base::TimeDelta::FromMilliseconds(500);
296 SetDataFactory(scoped_refptr<TestDataFactory>(new VideoFactory(duration)));
297
298 decoder_->Prefetch(base::Bind(&MediaCodecDecoderTest::SetPrefetched,
299 base::Unretained(this)));
300
301 EXPECT_TRUE(WaitForCondition(base::Bind(&MediaCodecDecoderTest::is_prefetched,
302 base::Unretained(this))));
303 }
304
305 TEST_F(MediaCodecDecoderTest, AudioConfigureNoParams) {
306 SKIP_TEST_IF_MEDIA_CODEC_BRIDGE_IS_NOT_AVAILABLE();
307
308 CreateAudioDecoder();
309
310 // Cannot configure without config parameters.
311 EXPECT_EQ(MediaCodecDecoder::CONFIG_FAILURE, decoder_->Configure());
312 }
313
314 TEST_F(MediaCodecDecoderTest, AudioConfigureValidParams) {
315 SKIP_TEST_IF_MEDIA_CODEC_BRIDGE_IS_NOT_AVAILABLE();
316
317 CreateAudioDecoder();
318
319 base::TimeDelta duration = base::TimeDelta::FromMilliseconds(500);
320 scoped_refptr<AudioFactory> factory(new AudioFactory(duration));
321 decoder_->SetDemuxerConfigs(factory->GetConfigs());
322
323 EXPECT_EQ(MediaCodecDecoder::CONFIG_OK, decoder_->Configure());
324 }
325
326 TEST_F(MediaCodecDecoderTest, VideoConfigureNoParams) {
327 SKIP_TEST_IF_MEDIA_CODEC_BRIDGE_IS_NOT_AVAILABLE();
328
329 CreateVideoDecoder();
330
331 // Cannot configure without config parameters.
332 EXPECT_EQ(MediaCodecDecoder::CONFIG_FAILURE, decoder_->Configure());
333 }
334
335 TEST_F(MediaCodecDecoderTest, VideoConfigureNoSurface) {
336 SKIP_TEST_IF_MEDIA_CODEC_BRIDGE_IS_NOT_AVAILABLE();
337
338 CreateVideoDecoder();
339
340 // decoder_->Configure() searches back for the key frame.
341 // We have to prefetch decoder.
342
343 base::TimeDelta duration = base::TimeDelta::FromMilliseconds(500);
344 scoped_refptr<VideoFactory> factory(new VideoFactory(duration));
345 SetDataFactory(factory);
346
347 decoder_->Prefetch(base::Bind(&MediaCodecDecoderTest::SetPrefetched,
348 base::Unretained(this)));
349
350 EXPECT_TRUE(WaitForCondition(base::Bind(&MediaCodecDecoderTest::is_prefetched,
351 base::Unretained(this))));
352
353 decoder_->SetDemuxerConfigs(factory->GetConfigs());
354
355 // Surface is not set, Configure() should fail.
356
357 EXPECT_EQ(MediaCodecDecoder::CONFIG_FAILURE, decoder_->Configure());
358 }
359
360 TEST_F(MediaCodecDecoderTest, VideoConfigureInvalidSurface) {
361 SKIP_TEST_IF_MEDIA_CODEC_BRIDGE_IS_NOT_AVAILABLE();
362
363 CreateVideoDecoder();
364
365 // decoder_->Configure() searches back for the key frame.
366 // We have to prefetch decoder.
367
368 base::TimeDelta duration = base::TimeDelta::FromMilliseconds(500);
369 scoped_refptr<VideoFactory> factory(new VideoFactory(duration));
370 SetDataFactory(factory);
371
372 decoder_->Prefetch(base::Bind(&MediaCodecDecoderTest::SetPrefetched,
373 base::Unretained(this)));
374
375 EXPECT_TRUE(WaitForCondition(base::Bind(&MediaCodecDecoderTest::is_prefetched,
376 base::Unretained(this))));
377
378 decoder_->SetDemuxerConfigs(factory->GetConfigs());
379
380 // Prepare the surface.
381 scoped_refptr<gfx::SurfaceTexture> surface_texture(
382 gfx::SurfaceTexture::Create(0));
383 gfx::ScopedJavaSurface surface(surface_texture.get());
384
385 // Release the surface texture.
386 surface_texture = NULL;
387
388 MediaCodecVideoDecoder* video_decoder =
389 static_cast<MediaCodecVideoDecoder*>(decoder_.get());
390 video_decoder->SetPendingSurface(surface.Pass());
391
392 EXPECT_EQ(MediaCodecDecoder::CONFIG_FAILURE, decoder_->Configure());
393 }
394
395 TEST_F(MediaCodecDecoderTest, VideoConfigureValidParams) {
396 SKIP_TEST_IF_MEDIA_CODEC_BRIDGE_IS_NOT_AVAILABLE();
397
398 CreateVideoDecoder();
399
400 // decoder_->Configure() searches back for the key frame.
401 // We have to prefetch decoder.
402
403 base::TimeDelta duration = base::TimeDelta::FromMilliseconds(500);
404 scoped_refptr<VideoFactory> factory(new VideoFactory(duration));
405 SetDataFactory(factory);
406
407 decoder_->Prefetch(base::Bind(&MediaCodecDecoderTest::SetPrefetched,
408 base::Unretained(this)));
409
410 EXPECT_TRUE(WaitForCondition(base::Bind(&MediaCodecDecoderTest::is_prefetched,
411 base::Unretained(this))));
412
413 decoder_->SetDemuxerConfigs(factory->GetConfigs());
414
415 SetVideoSurface();
416
417 // Now we can expect Configure() to succeed.
418
419 EXPECT_EQ(MediaCodecDecoder::CONFIG_OK, decoder_->Configure());
420 }
421
422 TEST_F(MediaCodecDecoderTest, AudioStartWithoutConfigure) {
423 SKIP_TEST_IF_MEDIA_CODEC_BRIDGE_IS_NOT_AVAILABLE();
424
425 CreateAudioDecoder();
426
427 // Decoder has to be prefetched and configured before the start.
428
429 // Wrong state: not prefetched
430 EXPECT_FALSE(decoder_->Start(base::TimeDelta::FromMilliseconds(0)));
431
432 // Do the prefetch.
433 base::TimeDelta duration = base::TimeDelta::FromMilliseconds(500);
434 scoped_refptr<AudioFactory> factory(new AudioFactory(duration));
435 SetDataFactory(factory);
436
437 // Prefetch to avoid starvation at the beginning of playback.
438 decoder_->Prefetch(base::Bind(&MediaCodecDecoderTest::SetPrefetched,
439 base::Unretained(this)));
440
441 EXPECT_TRUE(WaitForCondition(base::Bind(&MediaCodecDecoderTest::is_prefetched,
442 base::Unretained(this))));
443
444 // Still, decoder is not configured.
445 EXPECT_FALSE(decoder_->Start(base::TimeDelta::FromMilliseconds(0)));
446 }
447
448 TEST_F(MediaCodecDecoderTest, AudioPlayTillCompletion) {
449 SKIP_TEST_IF_MEDIA_CODEC_BRIDGE_IS_NOT_AVAILABLE();
450
451 CreateAudioDecoder();
452
453 base::TimeDelta duration = base::TimeDelta::FromMilliseconds(500);
454 base::TimeDelta timeout = base::TimeDelta::FromMilliseconds(600);
455 scoped_refptr<AudioFactory> factory(new AudioFactory(duration));
456 SetDataFactory(factory);
457
458 // Prefetch to avoid starvation at the beginning of playback.
459 decoder_->Prefetch(base::Bind(&MediaCodecDecoderTest::SetPrefetched,
460 base::Unretained(this)));
461
462 EXPECT_TRUE(WaitForCondition(base::Bind(&MediaCodecDecoderTest::is_prefetched,
463 base::Unretained(this))));
464
465 decoder_->SetDemuxerConfigs(factory->GetConfigs());
466
467 EXPECT_EQ(MediaCodecDecoder::CONFIG_OK, decoder_->Configure());
468
469 EXPECT_TRUE(decoder_->Start(base::TimeDelta::FromMilliseconds(0)));
470
471 EXPECT_TRUE(WaitForCondition(
472 base::Bind(&MediaCodecDecoderTest::is_stopped, base::Unretained(this)),
473 timeout));
474
475 EXPECT_TRUE(decoder_->IsStopped());
476 EXPECT_TRUE(decoder_->IsCompleted());
477
478 // It is hard to properly estimate minimum and maximum values because
479 // reported times are different from PTS.
480 EXPECT_EQ(25, pts_stat_.num_values());
481 }
482
483 TEST_F(MediaCodecDecoderTest, VideoPlayTillCompletion) {
484 SKIP_TEST_IF_MEDIA_CODEC_BRIDGE_IS_NOT_AVAILABLE();
485
486 CreateVideoDecoder();
487
488 base::TimeDelta duration = base::TimeDelta::FromMilliseconds(500);
489 base::TimeDelta timeout = base::TimeDelta::FromMilliseconds(600);
490 scoped_refptr<VideoFactory> factory(new VideoFactory(duration));
491 SetDataFactory(factory);
492
493 // Prefetch
494 decoder_->Prefetch(base::Bind(&MediaCodecDecoderTest::SetPrefetched,
495 base::Unretained(this)));
496
497 EXPECT_TRUE(WaitForCondition(base::Bind(&MediaCodecDecoderTest::is_prefetched,
498 base::Unretained(this))));
499
500 decoder_->SetDemuxerConfigs(factory->GetConfigs());
501
502 SetVideoSurface();
503
504 EXPECT_EQ(MediaCodecDecoder::CONFIG_OK, decoder_->Configure());
505
506 EXPECT_TRUE(decoder_->Start(base::TimeDelta::FromMilliseconds(0)));
507
508 EXPECT_TRUE(WaitForCondition(
509 base::Bind(&MediaCodecDecoderTest::is_stopped, base::Unretained(this)),
510 timeout));
511
512 EXPECT_TRUE(decoder_->IsStopped());
513 EXPECT_TRUE(decoder_->IsCompleted());
514
515 EXPECT_EQ(26, pts_stat_.num_values());
516 EXPECT_EQ(data_factory_->last_pts(), pts_stat_.max());
517 }
518
519 } // namespace media
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698