Initialize media timeline correctly for positive start times.
[chromium-blink-merge.git] / media / filters / pipeline_integration_test.cc
blobbce580d76fada5c541828964337f6412a171e12f
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/filters/pipeline_integration_test_base.h"
7 #include "base/bind.h"
8 #include "base/command_line.h"
9 #include "base/memory/scoped_ptr.h"
10 #include "base/strings/string_util.h"
11 #include "build/build_config.h"
12 #include "media/base/cdm_promise.h"
13 #include "media/base/decoder_buffer.h"
14 #include "media/base/media_keys.h"
15 #include "media/base/media_switches.h"
16 #include "media/base/test_data_util.h"
17 #include "media/cdm/aes_decryptor.h"
18 #include "media/cdm/json_web_key.h"
19 #include "media/filters/chunk_demuxer.h"
20 #include "media/filters/renderer_impl.h"
21 #include "testing/gmock/include/gmock/gmock.h"
23 using testing::_;
24 using testing::AnyNumber;
25 using testing::AtLeast;
26 using testing::AtMost;
27 using testing::SaveArg;
29 namespace media {
31 const char kSourceId[] = "SourceId";
32 const uint8 kInitData[] = { 0x69, 0x6e, 0x69, 0x74 };
34 const char kWebM[] = "video/webm; codecs=\"vp8,vorbis\"";
35 const char kWebMVP9[] = "video/webm; codecs=\"vp9\"";
36 const char kAudioOnlyWebM[] = "video/webm; codecs=\"vorbis\"";
37 const char kOpusAudioOnlyWebM[] = "video/webm; codecs=\"opus\"";
38 const char kVideoOnlyWebM[] = "video/webm; codecs=\"vp8\"";
39 const char kMP4VideoType[] = "video/mp4";
40 const char kMP4AudioType[] = "audio/mp4";
41 #if defined(USE_PROPRIETARY_CODECS)
42 const char kADTS[] = "audio/aac";
43 const char kMP4[] = "video/mp4; codecs=\"avc1.4D4041,mp4a.40.2\"";
44 const char kMP4Video[] = "video/mp4; codecs=\"avc1.4D4041\"";
45 const char kMP4VideoAVC3[] = "video/mp4; codecs=\"avc3.64001f\"";
46 const char kMP4Audio[] = "audio/mp4; codecs=\"mp4a.40.2\"";
47 const char kMP3[] = "audio/mpeg";
48 #endif // defined(USE_PROPRIETARY_CODECS)
50 // Key used to encrypt test files.
51 const uint8 kSecretKey[] = {
52 0xeb, 0xdd, 0x62, 0xf1, 0x68, 0x14, 0xd2, 0x7b,
53 0x68, 0xef, 0x12, 0x2a, 0xfc, 0xe4, 0xae, 0x3c
56 // The key ID for all encrypted files.
57 const uint8 kKeyId[] = {
58 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
59 0x38, 0x39, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35
62 const int kAppendWholeFile = -1;
64 // Constants for the Media Source config change tests.
65 const int kAppendTimeSec = 1;
66 const int kAppendTimeMs = kAppendTimeSec * 1000;
67 const int k320WebMFileDurationMs = 2736;
68 const int k640WebMFileDurationMs = 2749;
69 const int kOpusEndTrimmingWebMFileDurationMs = 2741;
70 const int kVP9WebMFileDurationMs = 2736;
71 const int kVP8AWebMFileDurationMs = 2733;
73 #if defined(USE_PROPRIETARY_CODECS)
74 const int k640IsoFileDurationMs = 2737;
75 const int k640IsoCencFileDurationMs = 2736;
76 const int k1280IsoFileDurationMs = 2736;
77 const int k1280IsoAVC3FileDurationMs = 2736;
78 #endif // defined(USE_PROPRIETARY_CODECS)
80 // Return a timeline offset for bear-320x240-live.webm.
81 static base::Time kLiveTimelineOffset() {
82 // The file contians the following UTC timeline offset:
83 // 2012-11-10 12:34:56.789123456
84 // Since base::Time only has a resolution of microseconds,
85 // construct a base::Time for 2012-11-10 12:34:56.789123.
86 base::Time::Exploded exploded_time;
87 exploded_time.year = 2012;
88 exploded_time.month = 11;
89 exploded_time.day_of_month = 10;
90 exploded_time.hour = 12;
91 exploded_time.minute = 34;
92 exploded_time.second = 56;
93 exploded_time.millisecond = 789;
94 base::Time timeline_offset = base::Time::FromUTCExploded(exploded_time);
96 timeline_offset += base::TimeDelta::FromMicroseconds(123);
98 return timeline_offset;
101 // FFmpeg only supports time a resolution of seconds so this
102 // helper function truncates a base::Time to seconds resolution.
103 static base::Time TruncateToFFmpegTimeResolution(base::Time t) {
104 base::Time::Exploded exploded_time;
105 t.UTCExplode(&exploded_time);
106 exploded_time.millisecond = 0;
108 return base::Time::FromUTCExploded(exploded_time);
111 // Note: Tests using this class only exercise the DecryptingDemuxerStream path.
112 // They do not exercise the Decrypting{Audio|Video}Decoder path.
113 class FakeEncryptedMedia {
114 public:
115 // Defines the behavior of the "app" that responds to EME events.
116 class AppBase {
117 public:
118 virtual ~AppBase() {}
120 virtual void OnSessionMessage(const std::string& web_session_id,
121 const std::vector<uint8>& message,
122 const GURL& destination_url) = 0;
124 virtual void OnSessionReady(const std::string& web_session_id) = 0;
126 virtual void OnSessionClosed(const std::string& web_session_id) = 0;
128 // Errors are not expected unless overridden.
129 virtual void OnSessionError(const std::string& web_session_id,
130 const std::string& error_name,
131 uint32 system_code,
132 const std::string& error_message) {
133 FAIL() << "Unexpected Key Error";
136 virtual void NeedKey(const std::string& type,
137 const std::vector<uint8>& init_data,
138 AesDecryptor* decryptor) = 0;
141 FakeEncryptedMedia(AppBase* app)
142 : decryptor_(base::Bind(&FakeEncryptedMedia::OnSessionMessage,
143 base::Unretained(this)),
144 base::Bind(&FakeEncryptedMedia::OnSessionClosed,
145 base::Unretained(this))),
146 app_(app) {}
148 AesDecryptor* decryptor() {
149 return &decryptor_;
152 // Callbacks for firing session events. Delegate to |app_|.
153 void OnSessionMessage(const std::string& web_session_id,
154 const std::vector<uint8>& message,
155 const GURL& destination_url) {
156 app_->OnSessionMessage(web_session_id, message, destination_url);
159 void OnSessionReady(const std::string& web_session_id) {
160 app_->OnSessionReady(web_session_id);
163 void OnSessionClosed(const std::string& web_session_id) {
164 app_->OnSessionClosed(web_session_id);
167 void OnSessionError(const std::string& web_session_id,
168 const std::string& error_name,
169 uint32 system_code,
170 const std::string& error_message) {
171 app_->OnSessionError(
172 web_session_id, error_name, system_code, error_message);
175 void NeedKey(const std::string& type,
176 const std::vector<uint8>& init_data) {
177 app_->NeedKey(type, init_data, &decryptor_);
180 private:
181 AesDecryptor decryptor_;
182 scoped_ptr<AppBase> app_;
185 enum PromiseResult { RESOLVED, REJECTED };
187 // Provides |kSecretKey| in response to needkey.
188 class KeyProvidingApp : public FakeEncryptedMedia::AppBase {
189 public:
190 KeyProvidingApp() {}
192 void OnResolveWithSession(PromiseResult expected,
193 const std::string& web_session_id) {
194 EXPECT_EQ(expected, RESOLVED);
195 EXPECT_GT(web_session_id.length(), 0ul);
196 current_session_id_ = web_session_id;
199 void OnResolve(PromiseResult expected) {
200 EXPECT_EQ(expected, RESOLVED);
203 void OnReject(PromiseResult expected,
204 media::MediaKeys::Exception exception_code,
205 uint32 system_code,
206 const std::string& error_message) {
207 EXPECT_EQ(expected, REJECTED);
210 scoped_ptr<SimpleCdmPromise> CreatePromise(PromiseResult expected) {
211 scoped_ptr<media::SimpleCdmPromise> promise(new media::SimpleCdmPromise(
212 base::Bind(
213 &KeyProvidingApp::OnResolve, base::Unretained(this), expected),
214 base::Bind(
215 &KeyProvidingApp::OnReject, base::Unretained(this), expected)));
216 return promise.Pass();
219 scoped_ptr<NewSessionCdmPromise> CreateSessionPromise(
220 PromiseResult expected) {
221 scoped_ptr<media::NewSessionCdmPromise> promise(
222 new media::NewSessionCdmPromise(
223 base::Bind(&KeyProvidingApp::OnResolveWithSession,
224 base::Unretained(this),
225 expected),
226 base::Bind(
227 &KeyProvidingApp::OnReject, base::Unretained(this), expected)));
228 return promise.Pass();
231 virtual void OnSessionMessage(const std::string& web_session_id,
232 const std::vector<uint8>& message,
233 const GURL& destination_url) OVERRIDE {
234 EXPECT_FALSE(web_session_id.empty());
235 EXPECT_FALSE(message.empty());
236 EXPECT_EQ(current_session_id_, web_session_id);
239 virtual void OnSessionReady(const std::string& web_session_id) OVERRIDE {
240 EXPECT_EQ(current_session_id_, web_session_id);
243 virtual void OnSessionClosed(const std::string& web_session_id) OVERRIDE {
244 EXPECT_EQ(current_session_id_, web_session_id);
247 virtual void NeedKey(const std::string& type,
248 const std::vector<uint8>& init_data,
249 AesDecryptor* decryptor) OVERRIDE {
250 if (current_session_id_.empty()) {
251 decryptor->CreateSession(type,
252 kInitData,
253 arraysize(kInitData),
254 MediaKeys::TEMPORARY_SESSION,
255 CreateSessionPromise(RESOLVED));
256 EXPECT_FALSE(current_session_id_.empty());
259 // Clear Key really needs the key ID in |init_data|. For WebM, they are the
260 // same, but this is not the case for ISO CENC. Therefore, provide the
261 // correct key ID.
262 const uint8* key_id = init_data.empty() ? NULL : &init_data[0];
263 size_t key_id_length = init_data.size();
264 if (type == kMP4AudioType || type == kMP4VideoType) {
265 key_id = kKeyId;
266 key_id_length = arraysize(kKeyId);
269 // Convert key into a JSON structure and then add it.
270 std::string jwk = GenerateJWKSet(
271 kSecretKey, arraysize(kSecretKey), key_id, key_id_length);
272 decryptor->UpdateSession(current_session_id_,
273 reinterpret_cast<const uint8*>(jwk.data()),
274 jwk.size(),
275 CreatePromise(RESOLVED));
278 std::string current_session_id_;
281 class RotatingKeyProvidingApp : public KeyProvidingApp {
282 public:
283 RotatingKeyProvidingApp() : num_distint_need_key_calls_(0) {}
284 virtual ~RotatingKeyProvidingApp() {
285 // Expect that NeedKey is fired multiple times with different |init_data|.
286 EXPECT_GT(num_distint_need_key_calls_, 1u);
289 virtual void NeedKey(const std::string& type,
290 const std::vector<uint8>& init_data,
291 AesDecryptor* decryptor) OVERRIDE {
292 // Skip the request if the |init_data| has been seen.
293 if (init_data == prev_init_data_)
294 return;
295 prev_init_data_ = init_data;
296 ++num_distint_need_key_calls_;
298 decryptor->CreateSession(type,
299 vector_as_array(&init_data),
300 init_data.size(),
301 MediaKeys::TEMPORARY_SESSION,
302 CreateSessionPromise(RESOLVED));
304 std::vector<uint8> key_id;
305 std::vector<uint8> key;
306 EXPECT_TRUE(GetKeyAndKeyId(init_data, &key, &key_id));
308 // Convert key into a JSON structure and then add it.
309 std::string jwk = GenerateJWKSet(vector_as_array(&key),
310 key.size(),
311 vector_as_array(&key_id),
312 key_id.size());
313 decryptor->UpdateSession(current_session_id_,
314 reinterpret_cast<const uint8*>(jwk.data()),
315 jwk.size(),
316 CreatePromise(RESOLVED));
319 private:
320 bool GetKeyAndKeyId(std::vector<uint8> init_data,
321 std::vector<uint8>* key,
322 std::vector<uint8>* key_id) {
323 // For WebM, init_data is key_id; for ISO CENC, init_data should contain
324 // the key_id. We assume key_id is in the end of init_data here (that is
325 // only a reasonable assumption for WebM and clear key ISO CENC).
326 DCHECK_GE(init_data.size(), arraysize(kKeyId));
327 std::vector<uint8> key_id_from_init_data(
328 init_data.end() - arraysize(kKeyId), init_data.end());
330 key->assign(kSecretKey, kSecretKey + arraysize(kSecretKey));
331 key_id->assign(kKeyId, kKeyId + arraysize(kKeyId));
333 // The Key and KeyId for this testing key provider are created by left
334 // rotating kSecretKey and kKeyId. Note that this implementation is only
335 // intended for testing purpose. The actual key rotation algorithm can be
336 // much more complicated.
337 // Find out the rotating position from |key_id_from_init_data| and apply on
338 // |key|.
339 for (size_t pos = 0; pos < arraysize(kKeyId); ++pos) {
340 std::rotate(key_id->begin(), key_id->begin() + pos, key_id->end());
341 if (*key_id == key_id_from_init_data) {
342 std::rotate(key->begin(), key->begin() + pos, key->end());
343 return true;
346 return false;
349 std::vector<uint8> prev_init_data_;
350 uint32 num_distint_need_key_calls_;
353 // Ignores needkey and does not perform a license request
354 class NoResponseApp : public FakeEncryptedMedia::AppBase {
355 public:
356 virtual void OnSessionMessage(const std::string& web_session_id,
357 const std::vector<uint8>& message,
358 const GURL& default_url) OVERRIDE {
359 EXPECT_FALSE(web_session_id.empty());
360 EXPECT_FALSE(message.empty());
361 FAIL() << "Unexpected Message";
364 virtual void OnSessionReady(const std::string& web_session_id) OVERRIDE {
365 EXPECT_FALSE(web_session_id.empty());
366 FAIL() << "Unexpected Ready";
369 virtual void OnSessionClosed(const std::string& web_session_id) OVERRIDE {
370 EXPECT_FALSE(web_session_id.empty());
371 FAIL() << "Unexpected Closed";
374 virtual void NeedKey(const std::string& type,
375 const std::vector<uint8>& init_data,
376 AesDecryptor* decryptor) OVERRIDE {
380 // Helper class that emulates calls made on the ChunkDemuxer by the
381 // Media Source API.
382 class MockMediaSource {
383 public:
384 MockMediaSource(const std::string& filename,
385 const std::string& mimetype,
386 int initial_append_size)
387 : file_path_(GetTestDataFilePath(filename)),
388 current_position_(0),
389 initial_append_size_(initial_append_size),
390 mimetype_(mimetype),
391 chunk_demuxer_(new ChunkDemuxer(
392 base::Bind(&MockMediaSource::DemuxerOpened, base::Unretained(this)),
393 base::Bind(&MockMediaSource::DemuxerNeedKey,
394 base::Unretained(this)),
395 LogCB(),
396 true)),
397 owned_chunk_demuxer_(chunk_demuxer_) {
399 file_data_ = ReadTestDataFile(filename);
401 if (initial_append_size_ == kAppendWholeFile)
402 initial_append_size_ = file_data_->data_size();
404 DCHECK_GT(initial_append_size_, 0);
405 DCHECK_LE(initial_append_size_, file_data_->data_size());
408 virtual ~MockMediaSource() {}
410 scoped_ptr<Demuxer> GetDemuxer() { return owned_chunk_demuxer_.Pass(); }
412 void set_need_key_cb(const Demuxer::NeedKeyCB& need_key_cb) {
413 need_key_cb_ = need_key_cb;
416 void Seek(base::TimeDelta seek_time, int new_position, int seek_append_size) {
417 chunk_demuxer_->StartWaitingForSeek(seek_time);
419 chunk_demuxer_->Abort(
420 kSourceId,
421 base::TimeDelta(), kInfiniteDuration(), &last_timestamp_offset_);
423 DCHECK_GE(new_position, 0);
424 DCHECK_LT(new_position, file_data_->data_size());
425 current_position_ = new_position;
427 AppendData(seek_append_size);
430 void AppendData(int size) {
431 DCHECK(chunk_demuxer_);
432 DCHECK_LT(current_position_, file_data_->data_size());
433 DCHECK_LE(current_position_ + size, file_data_->data_size());
435 chunk_demuxer_->AppendData(
436 kSourceId, file_data_->data() + current_position_, size,
437 base::TimeDelta(), kInfiniteDuration(), &last_timestamp_offset_,
438 base::Bind(&MockMediaSource::InitSegmentReceived,
439 base::Unretained(this)));
440 current_position_ += size;
443 void AppendAtTime(base::TimeDelta timestamp_offset,
444 const uint8* pData,
445 int size) {
446 CHECK(!chunk_demuxer_->IsParsingMediaSegment(kSourceId));
447 chunk_demuxer_->AppendData(kSourceId, pData, size,
448 base::TimeDelta(), kInfiniteDuration(),
449 &timestamp_offset,
450 base::Bind(&MockMediaSource::InitSegmentReceived,
451 base::Unretained(this)));
452 last_timestamp_offset_ = timestamp_offset;
455 void AppendAtTimeWithWindow(base::TimeDelta timestamp_offset,
456 base::TimeDelta append_window_start,
457 base::TimeDelta append_window_end,
458 const uint8* pData,
459 int size) {
460 CHECK(!chunk_demuxer_->IsParsingMediaSegment(kSourceId));
461 chunk_demuxer_->AppendData(kSourceId,
462 pData,
463 size,
464 append_window_start,
465 append_window_end,
466 &timestamp_offset,
467 base::Bind(&MockMediaSource::InitSegmentReceived,
468 base::Unretained(this)));
469 last_timestamp_offset_ = timestamp_offset;
472 void EndOfStream() {
473 chunk_demuxer_->MarkEndOfStream(PIPELINE_OK);
476 void Abort() {
477 if (!chunk_demuxer_)
478 return;
479 chunk_demuxer_->Shutdown();
480 chunk_demuxer_ = NULL;
483 void DemuxerOpened() {
484 base::MessageLoop::current()->PostTask(
485 FROM_HERE, base::Bind(&MockMediaSource::DemuxerOpenedTask,
486 base::Unretained(this)));
489 void DemuxerOpenedTask() {
490 // This code assumes that |mimetype_| is one of the following forms.
491 // 1. audio/mpeg
492 // 2. video/webm;codec="vorbis,vp8".
493 size_t semicolon = mimetype_.find(";");
494 std::string type = mimetype_;
495 std::vector<std::string> codecs;
496 if (semicolon != std::string::npos) {
497 type = mimetype_.substr(0, semicolon);
498 size_t codecs_param_start = mimetype_.find("codecs=\"", semicolon);
500 CHECK_NE(codecs_param_start, std::string::npos);
502 codecs_param_start += 8; // Skip over the codecs=".
504 size_t codecs_param_end = mimetype_.find("\"", codecs_param_start);
506 CHECK_NE(codecs_param_end, std::string::npos);
508 std::string codecs_param =
509 mimetype_.substr(codecs_param_start,
510 codecs_param_end - codecs_param_start);
511 Tokenize(codecs_param, ",", &codecs);
514 CHECK_EQ(chunk_demuxer_->AddId(kSourceId, type, codecs), ChunkDemuxer::kOk);
516 AppendData(initial_append_size_);
519 void DemuxerNeedKey(const std::string& type,
520 const std::vector<uint8>& init_data) {
521 DCHECK(!init_data.empty());
522 CHECK(!need_key_cb_.is_null());
523 need_key_cb_.Run(type, init_data);
526 base::TimeDelta last_timestamp_offset() const {
527 return last_timestamp_offset_;
530 MOCK_METHOD0(InitSegmentReceived, void(void));
532 private:
533 base::FilePath file_path_;
534 scoped_refptr<DecoderBuffer> file_data_;
535 int current_position_;
536 int initial_append_size_;
537 std::string mimetype_;
538 ChunkDemuxer* chunk_demuxer_;
539 scoped_ptr<Demuxer> owned_chunk_demuxer_;
540 Demuxer::NeedKeyCB need_key_cb_;
541 base::TimeDelta last_timestamp_offset_;
544 class PipelineIntegrationTest
545 : public testing::Test,
546 public PipelineIntegrationTestBase {
547 public:
548 void StartPipelineWithMediaSource(MockMediaSource* source) {
549 EXPECT_CALL(*source, InitSegmentReceived()).Times(AtLeast(1));
550 EXPECT_CALL(*this, OnMetadata(_))
551 .Times(AtMost(1))
552 .WillRepeatedly(SaveArg<0>(&metadata_));
553 EXPECT_CALL(*this, OnBufferingStateChanged(BUFFERING_HAVE_ENOUGH))
554 .Times(AtMost(1));
555 demuxer_ = source->GetDemuxer().Pass();
556 pipeline_->Start(
557 demuxer_.get(),
558 CreateRenderer(NULL),
559 base::Bind(&PipelineIntegrationTest::OnEnded, base::Unretained(this)),
560 base::Bind(&PipelineIntegrationTest::OnError, base::Unretained(this)),
561 QuitOnStatusCB(PIPELINE_OK),
562 base::Bind(&PipelineIntegrationTest::OnMetadata,
563 base::Unretained(this)),
564 base::Bind(&PipelineIntegrationTest::OnBufferingStateChanged,
565 base::Unretained(this)),
566 base::Closure(),
567 base::Bind(&PipelineIntegrationTest::OnAddTextTrack,
568 base::Unretained(this)));
569 message_loop_.Run();
572 void StartHashedPipelineWithMediaSource(MockMediaSource* source) {
573 hashing_enabled_ = true;
574 StartPipelineWithMediaSource(source);
577 void StartPipelineWithEncryptedMedia(
578 MockMediaSource* source,
579 FakeEncryptedMedia* encrypted_media) {
580 EXPECT_CALL(*this, OnMetadata(_))
581 .Times(AtMost(1))
582 .WillRepeatedly(SaveArg<0>(&metadata_));
583 EXPECT_CALL(*this, OnBufferingStateChanged(BUFFERING_HAVE_ENOUGH))
584 .Times(AtMost(1));
585 demuxer_ = source->GetDemuxer().Pass();
586 pipeline_->Start(
587 demuxer_.get(),
588 CreateRenderer(encrypted_media->decryptor()),
589 base::Bind(&PipelineIntegrationTest::OnEnded, base::Unretained(this)),
590 base::Bind(&PipelineIntegrationTest::OnError, base::Unretained(this)),
591 QuitOnStatusCB(PIPELINE_OK),
592 base::Bind(&PipelineIntegrationTest::OnMetadata,
593 base::Unretained(this)),
594 base::Bind(&PipelineIntegrationTest::OnBufferingStateChanged,
595 base::Unretained(this)),
596 base::Closure(),
597 base::Bind(&PipelineIntegrationTest::OnAddTextTrack,
598 base::Unretained(this)));
600 source->set_need_key_cb(base::Bind(&FakeEncryptedMedia::NeedKey,
601 base::Unretained(encrypted_media)));
603 message_loop_.Run();
606 // Verifies that seeking works properly for ChunkDemuxer when the
607 // seek happens while there is a pending read on the ChunkDemuxer
608 // and no data is available.
609 bool TestSeekDuringRead(const std::string& filename,
610 const std::string& mimetype,
611 int initial_append_size,
612 base::TimeDelta start_seek_time,
613 base::TimeDelta seek_time,
614 int seek_file_position,
615 int seek_append_size) {
616 MockMediaSource source(filename, mimetype, initial_append_size);
617 StartPipelineWithMediaSource(&source);
619 if (pipeline_status_ != PIPELINE_OK)
620 return false;
622 Play();
623 if (!WaitUntilCurrentTimeIsAfter(start_seek_time))
624 return false;
626 source.Seek(seek_time, seek_file_position, seek_append_size);
627 if (!Seek(seek_time))
628 return false;
630 source.EndOfStream();
632 source.Abort();
633 Stop();
634 return true;
638 TEST_F(PipelineIntegrationTest, BasicPlayback) {
639 ASSERT_TRUE(Start(GetTestDataFilePath("bear-320x240.webm"), PIPELINE_OK));
641 Play();
643 ASSERT_TRUE(WaitUntilOnEnded());
646 TEST_F(PipelineIntegrationTest, BasicPlaybackOpusOgg) {
647 ASSERT_TRUE(Start(GetTestDataFilePath("bear-opus.ogg"), PIPELINE_OK));
649 Play();
651 ASSERT_TRUE(WaitUntilOnEnded());
654 TEST_F(PipelineIntegrationTest, BasicPlaybackHashed) {
655 ASSERT_TRUE(Start(
656 GetTestDataFilePath("bear-320x240.webm"), PIPELINE_OK, kHashed));
658 Play();
660 ASSERT_TRUE(WaitUntilOnEnded());
662 EXPECT_EQ("f0be120a90a811506777c99a2cdf7cc1", GetVideoHash());
663 EXPECT_EQ("-3.59,-2.06,-0.43,2.15,0.77,-0.95,", GetAudioHash());
664 EXPECT_TRUE(demuxer_->GetTimelineOffset().is_null());
667 TEST_F(PipelineIntegrationTest, BasicPlaybackLive) {
668 ASSERT_TRUE(Start(
669 GetTestDataFilePath("bear-320x240-live.webm"), PIPELINE_OK, kHashed));
671 Play();
673 ASSERT_TRUE(WaitUntilOnEnded());
675 EXPECT_EQ("f0be120a90a811506777c99a2cdf7cc1", GetVideoHash());
676 EXPECT_EQ("-3.59,-2.06,-0.43,2.15,0.77,-0.95,", GetAudioHash());
678 // TODO: Fix FFmpeg code to return higher resolution time values so
679 // we don't have to truncate our expectations here.
680 EXPECT_EQ(TruncateToFFmpegTimeResolution(kLiveTimelineOffset()),
681 demuxer_->GetTimelineOffset());
684 TEST_F(PipelineIntegrationTest, F32PlaybackHashed) {
685 ASSERT_TRUE(
686 Start(GetTestDataFilePath("sfx_f32le.wav"), PIPELINE_OK, kHashed));
687 Play();
688 ASSERT_TRUE(WaitUntilOnEnded());
689 EXPECT_EQ(std::string(kNullVideoHash), GetVideoHash());
690 EXPECT_EQ("3.03,2.86,2.99,3.31,3.57,4.06,", GetAudioHash());
693 TEST_F(PipelineIntegrationTest, BasicPlaybackEncrypted) {
694 FakeEncryptedMedia encrypted_media(new KeyProvidingApp());
695 set_need_key_cb(base::Bind(&FakeEncryptedMedia::NeedKey,
696 base::Unretained(&encrypted_media)));
698 ASSERT_TRUE(Start(GetTestDataFilePath("bear-320x240-av_enc-av.webm"),
699 encrypted_media.decryptor()));
701 Play();
703 ASSERT_TRUE(WaitUntilOnEnded());
704 Stop();
707 TEST_F(PipelineIntegrationTest, BasicPlayback_MediaSource) {
708 MockMediaSource source("bear-320x240.webm", kWebM, 219229);
709 StartPipelineWithMediaSource(&source);
710 source.EndOfStream();
712 EXPECT_EQ(1u, pipeline_->GetBufferedTimeRanges().size());
713 EXPECT_EQ(0, pipeline_->GetBufferedTimeRanges().start(0).InMilliseconds());
714 EXPECT_EQ(k320WebMFileDurationMs,
715 pipeline_->GetBufferedTimeRanges().end(0).InMilliseconds());
717 Play();
719 ASSERT_TRUE(WaitUntilOnEnded());
721 EXPECT_TRUE(demuxer_->GetTimelineOffset().is_null());
722 source.Abort();
723 Stop();
726 TEST_F(PipelineIntegrationTest, BasicPlayback_MediaSource_Live) {
727 MockMediaSource source("bear-320x240-live.webm", kWebM, 219221);
728 StartPipelineWithMediaSource(&source);
729 source.EndOfStream();
731 EXPECT_EQ(1u, pipeline_->GetBufferedTimeRanges().size());
732 EXPECT_EQ(0, pipeline_->GetBufferedTimeRanges().start(0).InMilliseconds());
733 EXPECT_EQ(k320WebMFileDurationMs,
734 pipeline_->GetBufferedTimeRanges().end(0).InMilliseconds());
736 Play();
738 ASSERT_TRUE(WaitUntilOnEnded());
740 EXPECT_EQ(kLiveTimelineOffset(),
741 demuxer_->GetTimelineOffset());
742 source.Abort();
743 Stop();
746 TEST_F(PipelineIntegrationTest, BasicPlayback_MediaSource_VP9_WebM) {
747 MockMediaSource source("bear-vp9.webm", kWebMVP9, 67504);
748 StartPipelineWithMediaSource(&source);
749 source.EndOfStream();
751 EXPECT_EQ(1u, pipeline_->GetBufferedTimeRanges().size());
752 EXPECT_EQ(0, pipeline_->GetBufferedTimeRanges().start(0).InMilliseconds());
753 EXPECT_EQ(kVP9WebMFileDurationMs,
754 pipeline_->GetBufferedTimeRanges().end(0).InMilliseconds());
756 Play();
758 ASSERT_TRUE(WaitUntilOnEnded());
759 source.Abort();
760 Stop();
763 TEST_F(PipelineIntegrationTest, BasicPlayback_MediaSource_VP8A_WebM) {
764 MockMediaSource source("bear-vp8a.webm", kVideoOnlyWebM, kAppendWholeFile);
765 StartPipelineWithMediaSource(&source);
766 source.EndOfStream();
768 EXPECT_EQ(1u, pipeline_->GetBufferedTimeRanges().size());
769 EXPECT_EQ(0, pipeline_->GetBufferedTimeRanges().start(0).InMilliseconds());
770 EXPECT_EQ(kVP8AWebMFileDurationMs,
771 pipeline_->GetBufferedTimeRanges().end(0).InMilliseconds());
773 Play();
775 ASSERT_TRUE(WaitUntilOnEnded());
776 source.Abort();
777 Stop();
780 TEST_F(PipelineIntegrationTest, BasicPlayback_MediaSource_Opus_WebM) {
781 MockMediaSource source("bear-opus-end-trimming.webm", kOpusAudioOnlyWebM,
782 kAppendWholeFile);
783 StartPipelineWithMediaSource(&source);
784 source.EndOfStream();
786 EXPECT_EQ(1u, pipeline_->GetBufferedTimeRanges().size());
787 EXPECT_EQ(0, pipeline_->GetBufferedTimeRanges().start(0).InMilliseconds());
788 EXPECT_EQ(kOpusEndTrimmingWebMFileDurationMs,
789 pipeline_->GetBufferedTimeRanges().end(0).InMilliseconds());
790 Play();
792 ASSERT_TRUE(WaitUntilOnEnded());
793 source.Abort();
794 Stop();
797 // Flaky. http://crbug.com/304776
798 TEST_F(PipelineIntegrationTest, DISABLED_MediaSource_Opus_Seeking_WebM) {
799 MockMediaSource source("bear-opus-end-trimming.webm", kOpusAudioOnlyWebM,
800 kAppendWholeFile);
801 StartHashedPipelineWithMediaSource(&source);
803 EXPECT_EQ(1u, pipeline_->GetBufferedTimeRanges().size());
804 EXPECT_EQ(0, pipeline_->GetBufferedTimeRanges().start(0).InMilliseconds());
805 EXPECT_EQ(kOpusEndTrimmingWebMFileDurationMs,
806 pipeline_->GetBufferedTimeRanges().end(0).InMilliseconds());
808 base::TimeDelta start_seek_time = base::TimeDelta::FromMilliseconds(1000);
809 base::TimeDelta seek_time = base::TimeDelta::FromMilliseconds(2000);
811 Play();
812 ASSERT_TRUE(WaitUntilCurrentTimeIsAfter(start_seek_time));
813 source.Seek(seek_time, 0x1D5, 34017);
814 source.EndOfStream();
815 ASSERT_TRUE(Seek(seek_time));
817 ASSERT_TRUE(WaitUntilOnEnded());
819 EXPECT_EQ("0.76,0.20,-0.82,-0.58,-1.29,-0.29,", GetAudioHash());
821 source.Abort();
822 Stop();
825 TEST_F(PipelineIntegrationTest, MediaSource_ConfigChange_WebM) {
826 MockMediaSource source("bear-320x240-16x9-aspect.webm", kWebM,
827 kAppendWholeFile);
828 StartPipelineWithMediaSource(&source);
830 scoped_refptr<DecoderBuffer> second_file =
831 ReadTestDataFile("bear-640x360.webm");
833 source.AppendAtTime(base::TimeDelta::FromSeconds(kAppendTimeSec),
834 second_file->data(), second_file->data_size());
836 source.EndOfStream();
838 EXPECT_EQ(1u, pipeline_->GetBufferedTimeRanges().size());
839 EXPECT_EQ(0, pipeline_->GetBufferedTimeRanges().start(0).InMilliseconds());
840 EXPECT_EQ(kAppendTimeMs + k640WebMFileDurationMs,
841 pipeline_->GetBufferedTimeRanges().end(0).InMilliseconds());
843 Play();
845 EXPECT_TRUE(WaitUntilOnEnded());
846 source.Abort();
847 Stop();
850 TEST_F(PipelineIntegrationTest, MediaSource_ConfigChange_Encrypted_WebM) {
851 MockMediaSource source("bear-320x240-16x9-aspect-av_enc-av.webm", kWebM,
852 kAppendWholeFile);
853 FakeEncryptedMedia encrypted_media(new KeyProvidingApp());
854 StartPipelineWithEncryptedMedia(&source, &encrypted_media);
856 scoped_refptr<DecoderBuffer> second_file =
857 ReadTestDataFile("bear-640x360-av_enc-av.webm");
859 source.AppendAtTime(base::TimeDelta::FromSeconds(kAppendTimeSec),
860 second_file->data(), second_file->data_size());
862 source.EndOfStream();
864 EXPECT_EQ(1u, pipeline_->GetBufferedTimeRanges().size());
865 EXPECT_EQ(0, pipeline_->GetBufferedTimeRanges().start(0).InMilliseconds());
866 EXPECT_EQ(kAppendTimeMs + k640WebMFileDurationMs,
867 pipeline_->GetBufferedTimeRanges().end(0).InMilliseconds());
869 Play();
871 EXPECT_TRUE(WaitUntilOnEnded());
872 source.Abort();
873 Stop();
876 // Config changes from encrypted to clear are not currently supported.
877 TEST_F(PipelineIntegrationTest,
878 MediaSource_ConfigChange_ClearThenEncrypted_WebM) {
879 MockMediaSource source("bear-320x240-16x9-aspect.webm", kWebM,
880 kAppendWholeFile);
881 FakeEncryptedMedia encrypted_media(new KeyProvidingApp());
882 StartPipelineWithEncryptedMedia(&source, &encrypted_media);
884 scoped_refptr<DecoderBuffer> second_file =
885 ReadTestDataFile("bear-640x360-av_enc-av.webm");
887 source.AppendAtTime(base::TimeDelta::FromSeconds(kAppendTimeSec),
888 second_file->data(), second_file->data_size());
890 source.EndOfStream();
892 message_loop_.Run();
893 EXPECT_EQ(PIPELINE_ERROR_DECODE, pipeline_status_);
895 EXPECT_EQ(1u, pipeline_->GetBufferedTimeRanges().size());
896 EXPECT_EQ(0, pipeline_->GetBufferedTimeRanges().start(0).InMilliseconds());
897 // The second video was not added, so its time has not been added.
898 EXPECT_EQ(k320WebMFileDurationMs,
899 pipeline_->GetBufferedTimeRanges().end(0).InMilliseconds());
901 Play();
903 EXPECT_EQ(PIPELINE_ERROR_DECODE, WaitUntilEndedOrError());
904 source.Abort();
907 // Config changes from clear to encrypted are not currently supported.
908 TEST_F(PipelineIntegrationTest,
909 MediaSource_ConfigChange_EncryptedThenClear_WebM) {
910 MockMediaSource source("bear-320x240-16x9-aspect-av_enc-av.webm", kWebM,
911 kAppendWholeFile);
912 FakeEncryptedMedia encrypted_media(new KeyProvidingApp());
913 StartPipelineWithEncryptedMedia(&source, &encrypted_media);
915 scoped_refptr<DecoderBuffer> second_file =
916 ReadTestDataFile("bear-640x360.webm");
918 source.AppendAtTime(base::TimeDelta::FromSeconds(kAppendTimeSec),
919 second_file->data(), second_file->data_size());
921 source.EndOfStream();
923 EXPECT_EQ(1u, pipeline_->GetBufferedTimeRanges().size());
924 EXPECT_EQ(0, pipeline_->GetBufferedTimeRanges().start(0).InMilliseconds());
925 // The second video was not added, so its time has not been added.
926 EXPECT_EQ(k320WebMFileDurationMs,
927 pipeline_->GetBufferedTimeRanges().end(0).InMilliseconds());
929 Play();
931 EXPECT_EQ(PIPELINE_ERROR_DECODE, WaitUntilEndedOrError());
932 source.Abort();
935 #if defined(USE_PROPRIETARY_CODECS)
936 TEST_F(PipelineIntegrationTest, MediaSource_ADTS) {
937 MockMediaSource source("sfx.adts", kADTS, kAppendWholeFile);
938 StartPipelineWithMediaSource(&source);
939 source.EndOfStream();
941 EXPECT_EQ(1u, pipeline_->GetBufferedTimeRanges().size());
942 EXPECT_EQ(0, pipeline_->GetBufferedTimeRanges().start(0).InMilliseconds());
943 EXPECT_EQ(325, pipeline_->GetBufferedTimeRanges().end(0).InMilliseconds());
945 Play();
947 EXPECT_TRUE(WaitUntilOnEnded());
950 TEST_F(PipelineIntegrationTest, MediaSource_ADTS_TimestampOffset) {
951 MockMediaSource source("sfx.adts", kADTS, kAppendWholeFile);
952 StartHashedPipelineWithMediaSource(&source);
953 EXPECT_EQ(325, source.last_timestamp_offset().InMilliseconds());
955 // Trim off multiple frames off the beginning of the segment which will cause
956 // the first decoded frame to be incorrect if preroll isn't implemented.
957 const base::TimeDelta adts_preroll_duration =
958 base::TimeDelta::FromSecondsD(2.5 * 1024 / 44100);
959 const base::TimeDelta append_time =
960 source.last_timestamp_offset() - adts_preroll_duration;
962 scoped_refptr<DecoderBuffer> second_file = ReadTestDataFile("sfx.adts");
963 source.AppendAtTimeWithWindow(append_time,
964 append_time + adts_preroll_duration,
965 kInfiniteDuration(),
966 second_file->data(),
967 second_file->data_size());
968 source.EndOfStream();
970 EXPECT_EQ(592, source.last_timestamp_offset().InMilliseconds());
971 EXPECT_EQ(1u, pipeline_->GetBufferedTimeRanges().size());
972 EXPECT_EQ(0, pipeline_->GetBufferedTimeRanges().start(0).InMilliseconds());
973 EXPECT_EQ(592, pipeline_->GetBufferedTimeRanges().end(0).InMilliseconds());
975 Play();
977 EXPECT_TRUE(WaitUntilOnEnded());
979 // Verify preroll is stripped.
980 EXPECT_EQ("-0.06,0.97,-0.90,-0.70,-0.53,-0.34,", GetAudioHash());
983 TEST_F(PipelineIntegrationTest, BasicPlaybackHashed_MP3) {
984 ASSERT_TRUE(Start(GetTestDataFilePath("sfx.mp3"), PIPELINE_OK, kHashed));
986 Play();
988 ASSERT_TRUE(WaitUntilOnEnded());
990 // Verify codec delay and preroll are stripped.
991 EXPECT_EQ("3.05,2.87,3.00,3.32,3.58,4.08,", GetAudioHash());
994 TEST_F(PipelineIntegrationTest, MediaSource_MP3) {
995 MockMediaSource source("sfx.mp3", kMP3, kAppendWholeFile);
996 StartHashedPipelineWithMediaSource(&source);
997 source.EndOfStream();
999 EXPECT_EQ(1u, pipeline_->GetBufferedTimeRanges().size());
1000 EXPECT_EQ(0, pipeline_->GetBufferedTimeRanges().start(0).InMilliseconds());
1001 EXPECT_EQ(313, pipeline_->GetBufferedTimeRanges().end(0).InMilliseconds());
1003 Play();
1005 EXPECT_TRUE(WaitUntilOnEnded());
1007 // Verify that codec delay was stripped.
1008 EXPECT_EQ("1.01,2.71,4.18,4.32,3.04,1.12,", GetAudioHash());
1011 TEST_F(PipelineIntegrationTest, MediaSource_MP3_TimestampOffset) {
1012 MockMediaSource source("sfx.mp3", kMP3, kAppendWholeFile);
1013 StartPipelineWithMediaSource(&source);
1014 EXPECT_EQ(313, source.last_timestamp_offset().InMilliseconds());
1016 // There are 576 silent frames at the start of this mp3. The second append
1017 // should trim them off.
1018 const base::TimeDelta mp3_preroll_duration =
1019 base::TimeDelta::FromSecondsD(576.0 / 44100);
1020 const base::TimeDelta append_time =
1021 source.last_timestamp_offset() - mp3_preroll_duration;
1023 scoped_refptr<DecoderBuffer> second_file = ReadTestDataFile("sfx.mp3");
1024 source.AppendAtTimeWithWindow(append_time,
1025 append_time + mp3_preroll_duration,
1026 kInfiniteDuration(),
1027 second_file->data(),
1028 second_file->data_size());
1029 source.EndOfStream();
1031 EXPECT_EQ(613, source.last_timestamp_offset().InMilliseconds());
1032 EXPECT_EQ(1u, pipeline_->GetBufferedTimeRanges().size());
1033 EXPECT_EQ(0, pipeline_->GetBufferedTimeRanges().start(0).InMilliseconds());
1034 EXPECT_EQ(613, pipeline_->GetBufferedTimeRanges().end(0).InMilliseconds());
1036 Play();
1038 EXPECT_TRUE(WaitUntilOnEnded());
1041 TEST_F(PipelineIntegrationTest, MediaSource_MP3_Icecast) {
1042 MockMediaSource source("icy_sfx.mp3", kMP3, kAppendWholeFile);
1043 StartPipelineWithMediaSource(&source);
1044 source.EndOfStream();
1046 Play();
1048 EXPECT_TRUE(WaitUntilOnEnded());
1051 TEST_F(PipelineIntegrationTest, MediaSource_ConfigChange_MP4) {
1052 MockMediaSource source("bear-640x360-av_frag.mp4", kMP4, kAppendWholeFile);
1053 StartPipelineWithMediaSource(&source);
1055 scoped_refptr<DecoderBuffer> second_file =
1056 ReadTestDataFile("bear-1280x720-av_frag.mp4");
1058 source.AppendAtTime(base::TimeDelta::FromSeconds(kAppendTimeSec),
1059 second_file->data(), second_file->data_size());
1061 source.EndOfStream();
1063 EXPECT_EQ(1u, pipeline_->GetBufferedTimeRanges().size());
1064 EXPECT_EQ(0, pipeline_->GetBufferedTimeRanges().start(0).InMilliseconds());
1065 EXPECT_EQ(kAppendTimeMs + k1280IsoFileDurationMs,
1066 pipeline_->GetBufferedTimeRanges().end(0).InMilliseconds());
1068 Play();
1070 EXPECT_TRUE(WaitUntilOnEnded());
1071 source.Abort();
1072 Stop();
1075 TEST_F(PipelineIntegrationTest,
1076 MediaSource_ConfigChange_Encrypted_MP4_CENC_VideoOnly) {
1077 MockMediaSource source("bear-640x360-v_frag-cenc.mp4", kMP4Video,
1078 kAppendWholeFile);
1079 FakeEncryptedMedia encrypted_media(new KeyProvidingApp());
1080 StartPipelineWithEncryptedMedia(&source, &encrypted_media);
1082 scoped_refptr<DecoderBuffer> second_file =
1083 ReadTestDataFile("bear-1280x720-v_frag-cenc.mp4");
1085 source.AppendAtTime(base::TimeDelta::FromSeconds(kAppendTimeSec),
1086 second_file->data(), second_file->data_size());
1088 source.EndOfStream();
1090 EXPECT_EQ(1u, pipeline_->GetBufferedTimeRanges().size());
1091 EXPECT_EQ(0, pipeline_->GetBufferedTimeRanges().start(0).InMilliseconds());
1092 EXPECT_EQ(kAppendTimeMs + k1280IsoFileDurationMs,
1093 pipeline_->GetBufferedTimeRanges().end(0).InMilliseconds());
1095 Play();
1097 EXPECT_TRUE(WaitUntilOnEnded());
1098 source.Abort();
1099 Stop();
1102 TEST_F(PipelineIntegrationTest,
1103 MediaSource_ConfigChange_Encrypted_MP4_CENC_KeyRotation_VideoOnly) {
1104 MockMediaSource source("bear-640x360-v_frag-cenc-key_rotation.mp4", kMP4Video,
1105 kAppendWholeFile);
1106 FakeEncryptedMedia encrypted_media(new RotatingKeyProvidingApp());
1107 StartPipelineWithEncryptedMedia(&source, &encrypted_media);
1109 scoped_refptr<DecoderBuffer> second_file =
1110 ReadTestDataFile("bear-1280x720-v_frag-cenc-key_rotation.mp4");
1112 source.AppendAtTime(base::TimeDelta::FromSeconds(kAppendTimeSec),
1113 second_file->data(), second_file->data_size());
1115 source.EndOfStream();
1117 EXPECT_EQ(1u, pipeline_->GetBufferedTimeRanges().size());
1118 EXPECT_EQ(0, pipeline_->GetBufferedTimeRanges().start(0).InMilliseconds());
1119 EXPECT_EQ(kAppendTimeMs + k1280IsoFileDurationMs,
1120 pipeline_->GetBufferedTimeRanges().end(0).InMilliseconds());
1122 Play();
1124 EXPECT_TRUE(WaitUntilOnEnded());
1125 source.Abort();
1126 Stop();
1129 // Config changes from clear to encrypted are not currently supported.
1130 // TODO(ddorwin): Figure out why this CHECKs in AppendAtTime().
1131 TEST_F(PipelineIntegrationTest,
1132 DISABLED_MediaSource_ConfigChange_ClearThenEncrypted_MP4_CENC) {
1133 MockMediaSource source("bear-640x360-av_frag.mp4", kMP4Video,
1134 kAppendWholeFile);
1135 FakeEncryptedMedia encrypted_media(new KeyProvidingApp());
1136 StartPipelineWithEncryptedMedia(&source, &encrypted_media);
1138 scoped_refptr<DecoderBuffer> second_file =
1139 ReadTestDataFile("bear-1280x720-v_frag-cenc.mp4");
1141 source.AppendAtTime(base::TimeDelta::FromSeconds(kAppendTimeSec),
1142 second_file->data(), second_file->data_size());
1144 source.EndOfStream();
1146 message_loop_.Run();
1147 EXPECT_EQ(PIPELINE_ERROR_DECODE, pipeline_status_);
1149 EXPECT_EQ(1u, pipeline_->GetBufferedTimeRanges().size());
1150 EXPECT_EQ(0, pipeline_->GetBufferedTimeRanges().start(0).InMilliseconds());
1151 // The second video was not added, so its time has not been added.
1152 EXPECT_EQ(k640IsoFileDurationMs,
1153 pipeline_->GetBufferedTimeRanges().end(0).InMilliseconds());
1155 Play();
1157 EXPECT_EQ(PIPELINE_ERROR_DECODE, WaitUntilEndedOrError());
1158 source.Abort();
1161 // Config changes from encrypted to clear are not currently supported.
1162 TEST_F(PipelineIntegrationTest,
1163 MediaSource_ConfigChange_EncryptedThenClear_MP4_CENC) {
1164 MockMediaSource source("bear-640x360-v_frag-cenc.mp4", kMP4Video,
1165 kAppendWholeFile);
1166 FakeEncryptedMedia encrypted_media(new KeyProvidingApp());
1167 StartPipelineWithEncryptedMedia(&source, &encrypted_media);
1169 scoped_refptr<DecoderBuffer> second_file =
1170 ReadTestDataFile("bear-1280x720-av_frag.mp4");
1172 source.AppendAtTime(base::TimeDelta::FromSeconds(kAppendTimeSec),
1173 second_file->data(), second_file->data_size());
1175 source.EndOfStream();
1177 EXPECT_EQ(1u, pipeline_->GetBufferedTimeRanges().size());
1178 EXPECT_EQ(0, pipeline_->GetBufferedTimeRanges().start(0).InMilliseconds());
1179 // The second video was not added, so its time has not been added.
1180 EXPECT_EQ(k640IsoCencFileDurationMs,
1181 pipeline_->GetBufferedTimeRanges().end(0).InMilliseconds());
1183 Play();
1185 EXPECT_EQ(PIPELINE_ERROR_DECODE, WaitUntilEndedOrError());
1186 source.Abort();
1189 // Verify files which change configuration midstream fail gracefully.
1190 TEST_F(PipelineIntegrationTest, MidStreamConfigChangesFail) {
1191 ASSERT_TRUE(Start(
1192 GetTestDataFilePath("midstream_config_change.mp3"), PIPELINE_OK));
1193 Play();
1194 ASSERT_EQ(WaitUntilEndedOrError(), PIPELINE_ERROR_DECODE);
1197 #endif
1199 TEST_F(PipelineIntegrationTest, BasicPlayback_16x9AspectRatio) {
1200 ASSERT_TRUE(Start(GetTestDataFilePath("bear-320x240-16x9-aspect.webm"),
1201 PIPELINE_OK));
1202 Play();
1203 ASSERT_TRUE(WaitUntilOnEnded());
1206 TEST_F(PipelineIntegrationTest, EncryptedPlayback_WebM) {
1207 MockMediaSource source("bear-320x240-av_enc-av.webm", kWebM, 219816);
1208 FakeEncryptedMedia encrypted_media(new KeyProvidingApp());
1209 StartPipelineWithEncryptedMedia(&source, &encrypted_media);
1211 source.EndOfStream();
1212 ASSERT_EQ(PIPELINE_OK, pipeline_status_);
1214 Play();
1216 ASSERT_TRUE(WaitUntilOnEnded());
1217 source.Abort();
1218 Stop();
1221 TEST_F(PipelineIntegrationTest, EncryptedPlayback_ClearStart_WebM) {
1222 MockMediaSource source("bear-320x240-av_enc-av_clear-1s.webm", kWebM,
1223 kAppendWholeFile);
1224 FakeEncryptedMedia encrypted_media(new KeyProvidingApp());
1225 StartPipelineWithEncryptedMedia(&source, &encrypted_media);
1227 source.EndOfStream();
1228 ASSERT_EQ(PIPELINE_OK, pipeline_status_);
1230 Play();
1232 ASSERT_TRUE(WaitUntilOnEnded());
1233 source.Abort();
1234 Stop();
1237 TEST_F(PipelineIntegrationTest, EncryptedPlayback_NoEncryptedFrames_WebM) {
1238 MockMediaSource source("bear-320x240-av_enc-av_clear-all.webm", kWebM,
1239 kAppendWholeFile);
1240 FakeEncryptedMedia encrypted_media(new NoResponseApp());
1241 StartPipelineWithEncryptedMedia(&source, &encrypted_media);
1243 source.EndOfStream();
1244 ASSERT_EQ(PIPELINE_OK, pipeline_status_);
1246 Play();
1248 ASSERT_TRUE(WaitUntilOnEnded());
1249 source.Abort();
1250 Stop();
1253 #if defined(USE_PROPRIETARY_CODECS)
1254 TEST_F(PipelineIntegrationTest, EncryptedPlayback_MP4_CENC_VideoOnly) {
1255 MockMediaSource source("bear-1280x720-v_frag-cenc.mp4", kMP4Video,
1256 kAppendWholeFile);
1257 FakeEncryptedMedia encrypted_media(new KeyProvidingApp());
1258 StartPipelineWithEncryptedMedia(&source, &encrypted_media);
1260 source.EndOfStream();
1261 ASSERT_EQ(PIPELINE_OK, pipeline_status_);
1263 Play();
1265 ASSERT_TRUE(WaitUntilOnEnded());
1266 source.Abort();
1267 Stop();
1270 TEST_F(PipelineIntegrationTest, EncryptedPlayback_MP4_CENC_AudioOnly) {
1271 MockMediaSource source("bear-1280x720-a_frag-cenc.mp4", kMP4Audio,
1272 kAppendWholeFile);
1273 FakeEncryptedMedia encrypted_media(new KeyProvidingApp());
1274 StartPipelineWithEncryptedMedia(&source, &encrypted_media);
1276 source.EndOfStream();
1277 ASSERT_EQ(PIPELINE_OK, pipeline_status_);
1279 Play();
1281 ASSERT_TRUE(WaitUntilOnEnded());
1282 source.Abort();
1283 Stop();
1286 TEST_F(PipelineIntegrationTest,
1287 EncryptedPlayback_NoEncryptedFrames_MP4_CENC_VideoOnly) {
1288 MockMediaSource source("bear-1280x720-v_frag-cenc_clear-all.mp4", kMP4Video,
1289 kAppendWholeFile);
1290 FakeEncryptedMedia encrypted_media(new NoResponseApp());
1291 StartPipelineWithEncryptedMedia(&source, &encrypted_media);
1293 source.EndOfStream();
1294 ASSERT_EQ(PIPELINE_OK, pipeline_status_);
1296 Play();
1298 ASSERT_TRUE(WaitUntilOnEnded());
1299 source.Abort();
1300 Stop();
1303 TEST_F(PipelineIntegrationTest,
1304 EncryptedPlayback_NoEncryptedFrames_MP4_CENC_AudioOnly) {
1305 MockMediaSource source("bear-1280x720-a_frag-cenc_clear-all.mp4", kMP4Audio,
1306 kAppendWholeFile);
1307 FakeEncryptedMedia encrypted_media(new NoResponseApp());
1308 StartPipelineWithEncryptedMedia(&source, &encrypted_media);
1310 source.EndOfStream();
1311 ASSERT_EQ(PIPELINE_OK, pipeline_status_);
1313 Play();
1315 ASSERT_TRUE(WaitUntilOnEnded());
1316 source.Abort();
1317 Stop();
1320 TEST_F(PipelineIntegrationTest, BasicPlayback_MediaSource_VideoOnly_MP4_AVC3) {
1321 MockMediaSource source("bear-1280x720-v_frag-avc3.mp4", kMP4VideoAVC3,
1322 kAppendWholeFile);
1323 StartPipelineWithMediaSource(&source);
1324 source.EndOfStream();
1326 EXPECT_EQ(1u, pipeline_->GetBufferedTimeRanges().size());
1327 EXPECT_EQ(0, pipeline_->GetBufferedTimeRanges().start(0).InMilliseconds());
1328 EXPECT_EQ(k1280IsoAVC3FileDurationMs,
1329 pipeline_->GetBufferedTimeRanges().end(0).InMilliseconds());
1331 Play();
1333 ASSERT_TRUE(WaitUntilOnEnded());
1334 source.Abort();
1335 Stop();
1338 TEST_F(PipelineIntegrationTest, EncryptedPlayback_MP4_CENC_KeyRotation_Video) {
1339 MockMediaSource source("bear-1280x720-v_frag-cenc-key_rotation.mp4",
1340 kMP4Video, kAppendWholeFile);
1341 FakeEncryptedMedia encrypted_media(new RotatingKeyProvidingApp());
1342 StartPipelineWithEncryptedMedia(&source, &encrypted_media);
1344 source.EndOfStream();
1345 ASSERT_EQ(PIPELINE_OK, pipeline_status_);
1347 Play();
1349 ASSERT_TRUE(WaitUntilOnEnded());
1350 source.Abort();
1351 Stop();
1354 TEST_F(PipelineIntegrationTest, EncryptedPlayback_MP4_CENC_KeyRotation_Audio) {
1355 MockMediaSource source("bear-1280x720-a_frag-cenc-key_rotation.mp4",
1356 kMP4Audio, kAppendWholeFile);
1357 FakeEncryptedMedia encrypted_media(new RotatingKeyProvidingApp());
1358 StartPipelineWithEncryptedMedia(&source, &encrypted_media);
1360 source.EndOfStream();
1361 ASSERT_EQ(PIPELINE_OK, pipeline_status_);
1363 Play();
1365 ASSERT_TRUE(WaitUntilOnEnded());
1366 source.Abort();
1367 Stop();
1369 #endif
1371 // TODO(acolwell): Fix flakiness http://crbug.com/117921
1372 TEST_F(PipelineIntegrationTest, DISABLED_SeekWhilePaused) {
1373 ASSERT_TRUE(Start(GetTestDataFilePath("bear-320x240.webm"), PIPELINE_OK));
1375 base::TimeDelta duration(pipeline_->GetMediaDuration());
1376 base::TimeDelta start_seek_time(duration / 4);
1377 base::TimeDelta seek_time(duration * 3 / 4);
1379 Play();
1380 ASSERT_TRUE(WaitUntilCurrentTimeIsAfter(start_seek_time));
1381 Pause();
1382 ASSERT_TRUE(Seek(seek_time));
1383 EXPECT_EQ(pipeline_->GetMediaTime(), seek_time);
1384 Play();
1385 ASSERT_TRUE(WaitUntilOnEnded());
1387 // Make sure seeking after reaching the end works as expected.
1388 Pause();
1389 ASSERT_TRUE(Seek(seek_time));
1390 EXPECT_EQ(pipeline_->GetMediaTime(), seek_time);
1391 Play();
1392 ASSERT_TRUE(WaitUntilOnEnded());
1395 // TODO(acolwell): Fix flakiness http://crbug.com/117921
1396 TEST_F(PipelineIntegrationTest, DISABLED_SeekWhilePlaying) {
1397 ASSERT_TRUE(Start(GetTestDataFilePath("bear-320x240.webm"), PIPELINE_OK));
1399 base::TimeDelta duration(pipeline_->GetMediaDuration());
1400 base::TimeDelta start_seek_time(duration / 4);
1401 base::TimeDelta seek_time(duration * 3 / 4);
1403 Play();
1404 ASSERT_TRUE(WaitUntilCurrentTimeIsAfter(start_seek_time));
1405 ASSERT_TRUE(Seek(seek_time));
1406 EXPECT_GE(pipeline_->GetMediaTime(), seek_time);
1407 ASSERT_TRUE(WaitUntilOnEnded());
1409 // Make sure seeking after reaching the end works as expected.
1410 ASSERT_TRUE(Seek(seek_time));
1411 EXPECT_GE(pipeline_->GetMediaTime(), seek_time);
1412 ASSERT_TRUE(WaitUntilOnEnded());
1415 #if defined(USE_PROPRIETARY_CODECS)
1416 TEST_F(PipelineIntegrationTest, Rotated_Metadata_0) {
1417 ASSERT_TRUE(Start(GetTestDataFilePath("bear_rotate_0.mp4"), PIPELINE_OK));
1418 ASSERT_EQ(VIDEO_ROTATION_0, metadata_.video_rotation);
1421 TEST_F(PipelineIntegrationTest, Rotated_Metadata_90) {
1422 ASSERT_TRUE(Start(GetTestDataFilePath("bear_rotate_90.mp4"), PIPELINE_OK));
1423 ASSERT_EQ(VIDEO_ROTATION_90, metadata_.video_rotation);
1426 TEST_F(PipelineIntegrationTest, Rotated_Metadata_180) {
1427 ASSERT_TRUE(Start(GetTestDataFilePath("bear_rotate_180.mp4"), PIPELINE_OK));
1428 ASSERT_EQ(VIDEO_ROTATION_180, metadata_.video_rotation);
1431 TEST_F(PipelineIntegrationTest, Rotated_Metadata_270) {
1432 ASSERT_TRUE(Start(GetTestDataFilePath("bear_rotate_270.mp4"), PIPELINE_OK));
1433 ASSERT_EQ(VIDEO_ROTATION_270, metadata_.video_rotation);
1435 #endif
1437 // Verify audio decoder & renderer can handle aborted demuxer reads.
1438 TEST_F(PipelineIntegrationTest, ChunkDemuxerAbortRead_AudioOnly) {
1439 ASSERT_TRUE(TestSeekDuringRead("bear-320x240-audio-only.webm", kAudioOnlyWebM,
1440 8192,
1441 base::TimeDelta::FromMilliseconds(464),
1442 base::TimeDelta::FromMilliseconds(617),
1443 0x10CA, 19730));
1446 // Verify video decoder & renderer can handle aborted demuxer reads.
1447 TEST_F(PipelineIntegrationTest, ChunkDemuxerAbortRead_VideoOnly) {
1448 ASSERT_TRUE(TestSeekDuringRead("bear-320x240-video-only.webm", kVideoOnlyWebM,
1449 32768,
1450 base::TimeDelta::FromMilliseconds(167),
1451 base::TimeDelta::FromMilliseconds(1668),
1452 0x1C896, 65536));
1455 // Verify that Opus audio in WebM containers can be played back.
1456 TEST_F(PipelineIntegrationTest, BasicPlayback_AudioOnly_Opus_WebM) {
1457 ASSERT_TRUE(Start(GetTestDataFilePath("bear-opus-end-trimming.webm"),
1458 PIPELINE_OK));
1459 Play();
1460 ASSERT_TRUE(WaitUntilOnEnded());
1463 // Verify that VP9 video in WebM containers can be played back.
1464 TEST_F(PipelineIntegrationTest, BasicPlayback_VideoOnly_VP9_WebM) {
1465 ASSERT_TRUE(Start(GetTestDataFilePath("bear-vp9.webm"),
1466 PIPELINE_OK));
1467 Play();
1468 ASSERT_TRUE(WaitUntilOnEnded());
1471 // Verify that VP9 video and Opus audio in the same WebM container can be played
1472 // back.
1473 TEST_F(PipelineIntegrationTest, BasicPlayback_VP9_Opus_WebM) {
1474 ASSERT_TRUE(Start(GetTestDataFilePath("bear-vp9-opus.webm"),
1475 PIPELINE_OK));
1476 Play();
1477 ASSERT_TRUE(WaitUntilOnEnded());
1480 // Verify that VP8 video with alpha channel can be played back.
1481 TEST_F(PipelineIntegrationTest, BasicPlayback_VP8A_WebM) {
1482 ASSERT_TRUE(Start(GetTestDataFilePath("bear-vp8a.webm"),
1483 PIPELINE_OK));
1484 Play();
1485 ASSERT_TRUE(WaitUntilOnEnded());
1486 EXPECT_EQ(last_video_frame_format_, VideoFrame::YV12A);
1489 // Verify that VP8A video with odd width/height can be played back.
1490 TEST_F(PipelineIntegrationTest, BasicPlayback_VP8A_Odd_WebM) {
1491 ASSERT_TRUE(Start(GetTestDataFilePath("bear-vp8a-odd-dimensions.webm"),
1492 PIPELINE_OK));
1493 Play();
1494 ASSERT_TRUE(WaitUntilOnEnded());
1495 EXPECT_EQ(last_video_frame_format_, VideoFrame::YV12A);
1498 // Verify that VP9 video with odd width/height can be played back.
1499 TEST_F(PipelineIntegrationTest, BasicPlayback_VP9_Odd_WebM) {
1500 ASSERT_TRUE(Start(GetTestDataFilePath("bear-vp9-odd-dimensions.webm"),
1501 PIPELINE_OK));
1502 Play();
1503 ASSERT_TRUE(WaitUntilOnEnded());
1506 // Verify that VP8 video with inband text track can be played back.
1507 TEST_F(PipelineIntegrationTest, BasicPlayback_VP8_WebVTT_WebM) {
1508 EXPECT_CALL(*this, OnAddTextTrack(_, _));
1509 ASSERT_TRUE(Start(GetTestDataFilePath("bear-vp8-webvtt.webm"),
1510 PIPELINE_OK));
1511 Play();
1512 ASSERT_TRUE(WaitUntilOnEnded());
1515 // Verify that VP9 video with 4:4:4 subsampling can be played back.
1516 TEST_F(PipelineIntegrationTest, P444_VP9_WebM) {
1517 ASSERT_TRUE(Start(GetTestDataFilePath("bear-320x240-P444.webm"),
1518 PIPELINE_OK));
1519 Play();
1520 ASSERT_TRUE(WaitUntilOnEnded());
1521 EXPECT_EQ(last_video_frame_format_, VideoFrame::YV24);
1524 // Verify that videos with an odd frame size playback successfully.
1525 TEST_F(PipelineIntegrationTest, BasicPlayback_OddVideoSize) {
1526 ASSERT_TRUE(Start(GetTestDataFilePath("butterfly-853x480.webm"),
1527 PIPELINE_OK));
1528 Play();
1529 ASSERT_TRUE(WaitUntilOnEnded());
1532 // Verify that OPUS audio in a webm which reports a 44.1kHz sample rate plays
1533 // correctly at 48kHz
1534 TEST_F(PipelineIntegrationTest, BasicPlayback_Opus441kHz) {
1535 ASSERT_TRUE(Start(GetTestDataFilePath("sfx-opus-441.webm"), PIPELINE_OK));
1536 Play();
1537 ASSERT_TRUE(WaitUntilOnEnded());
1538 EXPECT_EQ(48000,
1539 demuxer_->GetStream(DemuxerStream::AUDIO)
1540 ->audio_decoder_config()
1541 .samples_per_second());
1544 // Same as above but using MediaSource.
1545 TEST_F(PipelineIntegrationTest, BasicPlayback_MediaSource_Opus441kHz) {
1546 MockMediaSource source(
1547 "sfx-opus-441.webm", kOpusAudioOnlyWebM, kAppendWholeFile);
1548 StartPipelineWithMediaSource(&source);
1549 source.EndOfStream();
1550 Play();
1551 ASSERT_TRUE(WaitUntilOnEnded());
1552 source.Abort();
1553 Stop();
1554 EXPECT_EQ(48000,
1555 demuxer_->GetStream(DemuxerStream::AUDIO)
1556 ->audio_decoder_config()
1557 .samples_per_second());
1560 // Ensures audio-only playback with missing or negative timestamps works. Tests
1561 // the common live-streaming case for chained ogg. See http://crbug.com/396864.
1562 TEST_F(PipelineIntegrationTest, BasicPlaybackChainedOgg) {
1563 ASSERT_TRUE(Start(GetTestDataFilePath("double-sfx.ogg"), PIPELINE_OK));
1564 Play();
1565 ASSERT_TRUE(WaitUntilOnEnded());
1566 ASSERT_EQ(base::TimeDelta(), demuxer_->GetStartTime());
1569 // Ensures audio-video playback with missing or negative timestamps fails softly
1570 // instead of crashing. See http://crbug.com/396864.
1571 TEST_F(PipelineIntegrationTest, BasicPlaybackChainedOggVideo) {
1572 ASSERT_TRUE(Start(GetTestDataFilePath("double-bear.ogv"), PIPELINE_OK));
1573 Play();
1574 EXPECT_EQ(PIPELINE_ERROR_DECODE, WaitUntilEndedOrError());
1575 ASSERT_EQ(base::TimeDelta(), demuxer_->GetStartTime());
1578 // Tests that we signal ended even when audio runs longer than video track.
1579 TEST_F(PipelineIntegrationTest, BasicPlaybackAudioLongerThanVideo) {
1580 ASSERT_TRUE(Start(GetTestDataFilePath("bear_audio_longer_than_video.ogv"),
1581 PIPELINE_OK));
1582 // Audio track is 2000ms. Video track is 1001ms. Duration should be higher
1583 // of the two.
1584 EXPECT_EQ(2000, pipeline_->GetMediaDuration().InMilliseconds());
1585 Play();
1586 ASSERT_TRUE(WaitUntilOnEnded());
1589 // Tests that we signal ended even when audio runs shorter than video track.
1590 TEST_F(PipelineIntegrationTest, BasicPlaybackAudioShorterThanVideo) {
1591 ASSERT_TRUE(Start(GetTestDataFilePath("bear_audio_shorter_than_video.ogv"),
1592 PIPELINE_OK));
1593 // Audio track is 500ms. Video track is 1001ms. Duration should be higher of
1594 // the two.
1595 EXPECT_EQ(1001, pipeline_->GetMediaDuration().InMilliseconds());
1596 Play();
1597 ASSERT_TRUE(WaitUntilOnEnded());
1600 TEST_F(PipelineIntegrationTest, BasicPlaybackPositiveStartTime) {
1601 ASSERT_TRUE(
1602 Start(GetTestDataFilePath("nonzero-start-time.webm"), PIPELINE_OK));
1603 Play();
1604 ASSERT_TRUE(WaitUntilOnEnded());
1605 ASSERT_EQ(base::TimeDelta::FromMicroseconds(396000),
1606 demuxer_->GetStartTime());
1609 } // namespace media