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. 4 5 #include "media/filters/pipeline_integration_test_base.h" 6 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 21 using testing::_; 22 using testing::AnyNumber; 23 using testing::AtMost; 24 using testing::SaveArg; 25 26 namespace media { 27 28 const char kSourceId[] = "SourceId"; 29 const uint8 kInitData[] = { 0x69, 0x6e, 0x69, 0x74 }; 30 31 const char kWebM[] = "video/webm; codecs=\"vp8,vorbis\""; 32 const char kWebMVP9[] = "video/webm; codecs=\"vp9\""; 33 const char kAudioOnlyWebM[] = "video/webm; codecs=\"vorbis\""; 34 const char kOpusAudioOnlyWebM[] = "video/webm; codecs=\"opus\""; 35 const char kVideoOnlyWebM[] = "video/webm; codecs=\"vp8\""; 36 const char kMP4VideoType[] = "video/mp4"; 37 const char kMP4AudioType[] = "audio/mp4"; 38 #if defined(USE_PROPRIETARY_CODECS) 39 const char kADTS[] = "audio/aac"; 40 const char kMP4[] = "video/mp4; codecs=\"avc1.4D4041,mp4a.40.2\""; 41 const char kMP4Video[] = "video/mp4; codecs=\"avc1.4D4041\""; 42 const char kMP4VideoAVC3[] = "video/mp4; codecs=\"avc3.64001f\""; 43 const char kMP4Audio[] = "audio/mp4; codecs=\"mp4a.40.2\""; 44 const char kMP3[] = "audio/mpeg"; 45 #endif // defined(USE_PROPRIETARY_CODECS) 46 47 // Key used to encrypt test files. 48 const uint8 kSecretKey[] = { 49 0xeb, 0xdd, 0x62, 0xf1, 0x68, 0x14, 0xd2, 0x7b, 50 0x68, 0xef, 0x12, 0x2a, 0xfc, 0xe4, 0xae, 0x3c 51 }; 52 53 // The key ID for all encrypted files. 54 const uint8 kKeyId[] = { 55 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 56 0x38, 0x39, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35 57 }; 58 59 const int kAppendWholeFile = -1; 60 61 // Constants for the Media Source config change tests. 62 const int kAppendTimeSec = 1; 63 const int kAppendTimeMs = kAppendTimeSec * 1000; 64 const int k320WebMFileDurationMs = 2736; 65 const int k640WebMFileDurationMs = 2749; 66 const int kOpusEndTrimmingWebMFileDurationMs = 2741; 67 const int kVP9WebMFileDurationMs = 2736; 68 const int kVP8AWebMFileDurationMs = 2733; 69 70 #if defined(USE_PROPRIETARY_CODECS) 71 const int k640IsoFileDurationMs = 2737; 72 const int k640IsoCencFileDurationMs = 2736; 73 const int k1280IsoFileDurationMs = 2736; 74 const int k1280IsoAVC3FileDurationMs = 2736; 75 #endif // defined(USE_PROPRIETARY_CODECS) 76 77 // Return a timeline offset for bear-320x240-live.webm. 78 static base::Time kLiveTimelineOffset() { 79 // The file contians the following UTC timeline offset: 80 // 2012-11-10 12:34:56.789123456 81 // Since base::Time only has a resolution of microseconds, 82 // construct a base::Time for 2012-11-10 12:34:56.789123. 83 base::Time::Exploded exploded_time; 84 exploded_time.year = 2012; 85 exploded_time.month = 11; 86 exploded_time.day_of_month = 10; 87 exploded_time.hour = 12; 88 exploded_time.minute = 34; 89 exploded_time.second = 56; 90 exploded_time.millisecond = 789; 91 base::Time timeline_offset = base::Time::FromUTCExploded(exploded_time); 92 93 timeline_offset += base::TimeDelta::FromMicroseconds(123); 94 95 return timeline_offset; 96 } 97 98 // FFmpeg only supports time a resolution of seconds so this 99 // helper function truncates a base::Time to seconds resolution. 100 static base::Time TruncateToFFmpegTimeResolution(base::Time t) { 101 base::Time::Exploded exploded_time; 102 t.UTCExplode(&exploded_time); 103 exploded_time.millisecond = 0; 104 105 return base::Time::FromUTCExploded(exploded_time); 106 } 107 108 // Note: Tests using this class only exercise the DecryptingDemuxerStream path. 109 // They do not exercise the Decrypting{Audio|Video}Decoder path. 110 class FakeEncryptedMedia { 111 public: 112 // Defines the behavior of the "app" that responds to EME events. 113 class AppBase { 114 public: 115 virtual ~AppBase() {} 116 117 virtual void OnSessionMessage(const std::string& web_session_id, 118 const std::vector<uint8>& message, 119 const GURL& destination_url) = 0; 120 121 virtual void OnSessionReady(const std::string& web_session_id) = 0; 122 123 virtual void OnSessionClosed(const std::string& web_session_id) = 0; 124 125 // Errors are not expected unless overridden. 126 virtual void OnSessionError(const std::string& web_session_id, 127 const std::string& error_name, 128 uint32 system_code, 129 const std::string& error_message) { 130 FAIL() << "Unexpected Key Error"; 131 } 132 133 virtual void NeedKey(const std::string& type, 134 const std::vector<uint8>& init_data, 135 AesDecryptor* decryptor) = 0; 136 }; 137 138 FakeEncryptedMedia(AppBase* app) 139 : decryptor_(base::Bind(&FakeEncryptedMedia::OnSessionMessage, 140 base::Unretained(this)), 141 base::Bind(&FakeEncryptedMedia::OnSessionClosed, 142 base::Unretained(this))), 143 app_(app) {} 144 145 AesDecryptor* decryptor() { 146 return &decryptor_; 147 } 148 149 // Callbacks for firing session events. Delegate to |app_|. 150 void OnSessionMessage(const std::string& web_session_id, 151 const std::vector<uint8>& message, 152 const GURL& destination_url) { 153 app_->OnSessionMessage(web_session_id, message, destination_url); 154 } 155 156 void OnSessionReady(const std::string& web_session_id) { 157 app_->OnSessionReady(web_session_id); 158 } 159 160 void OnSessionClosed(const std::string& web_session_id) { 161 app_->OnSessionClosed(web_session_id); 162 } 163 164 void OnSessionError(const std::string& web_session_id, 165 const std::string& error_name, 166 uint32 system_code, 167 const std::string& error_message) { 168 app_->OnSessionError( 169 web_session_id, error_name, system_code, error_message); 170 } 171 172 void NeedKey(const std::string& type, 173 const std::vector<uint8>& init_data) { 174 app_->NeedKey(type, init_data, &decryptor_); 175 } 176 177 private: 178 AesDecryptor decryptor_; 179 scoped_ptr<AppBase> app_; 180 }; 181 182 enum PromiseResult { RESOLVED, REJECTED }; 183 184 // Provides |kSecretKey| in response to needkey. 185 class KeyProvidingApp : public FakeEncryptedMedia::AppBase { 186 public: 187 KeyProvidingApp() {} 188 189 void OnResolveWithSession(PromiseResult expected, 190 const std::string& web_session_id) { 191 EXPECT_EQ(expected, RESOLVED); 192 EXPECT_GT(web_session_id.length(), 0ul); 193 current_session_id_ = web_session_id; 194 } 195 196 void OnResolve(PromiseResult expected) { 197 EXPECT_EQ(expected, RESOLVED); 198 } 199 200 void OnReject(PromiseResult expected, 201 media::MediaKeys::Exception exception_code, 202 uint32 system_code, 203 const std::string& error_message) { 204 EXPECT_EQ(expected, REJECTED); 205 } 206 207 scoped_ptr<SimpleCdmPromise> CreatePromise(PromiseResult expected) { 208 scoped_ptr<media::SimpleCdmPromise> promise(new media::SimpleCdmPromise( 209 base::Bind( 210 &KeyProvidingApp::OnResolve, base::Unretained(this), expected), 211 base::Bind( 212 &KeyProvidingApp::OnReject, base::Unretained(this), expected))); 213 return promise.Pass(); 214 } 215 216 scoped_ptr<NewSessionCdmPromise> CreateSessionPromise( 217 PromiseResult expected) { 218 scoped_ptr<media::NewSessionCdmPromise> promise( 219 new media::NewSessionCdmPromise( 220 base::Bind(&KeyProvidingApp::OnResolveWithSession, 221 base::Unretained(this), 222 expected), 223 base::Bind( 224 &KeyProvidingApp::OnReject, base::Unretained(this), expected))); 225 return promise.Pass(); 226 } 227 228 virtual void OnSessionMessage(const std::string& web_session_id, 229 const std::vector<uint8>& message, 230 const GURL& destination_url) OVERRIDE { 231 EXPECT_FALSE(web_session_id.empty()); 232 EXPECT_FALSE(message.empty()); 233 EXPECT_EQ(current_session_id_, web_session_id); 234 } 235 236 virtual void OnSessionReady(const std::string& web_session_id) OVERRIDE { 237 EXPECT_EQ(current_session_id_, web_session_id); 238 } 239 240 virtual void OnSessionClosed(const std::string& web_session_id) OVERRIDE { 241 EXPECT_EQ(current_session_id_, web_session_id); 242 } 243 244 virtual void NeedKey(const std::string& type, 245 const std::vector<uint8>& init_data, 246 AesDecryptor* decryptor) OVERRIDE { 247 if (current_session_id_.empty()) { 248 decryptor->CreateSession(type, 249 kInitData, 250 arraysize(kInitData), 251 MediaKeys::TEMPORARY_SESSION, 252 CreateSessionPromise(RESOLVED)); 253 EXPECT_FALSE(current_session_id_.empty()); 254 } 255 256 // Clear Key really needs the key ID in |init_data|. For WebM, they are the 257 // same, but this is not the case for ISO CENC. Therefore, provide the 258 // correct key ID. 259 const uint8* key_id = init_data.empty() ? NULL : &init_data[0]; 260 size_t key_id_length = init_data.size(); 261 if (type == kMP4AudioType || type == kMP4VideoType) { 262 key_id = kKeyId; 263 key_id_length = arraysize(kKeyId); 264 } 265 266 // Convert key into a JSON structure and then add it. 267 std::string jwk = GenerateJWKSet( 268 kSecretKey, arraysize(kSecretKey), key_id, key_id_length); 269 decryptor->UpdateSession(current_session_id_, 270 reinterpret_cast<const uint8*>(jwk.data()), 271 jwk.size(), 272 CreatePromise(RESOLVED)); 273 } 274 275 std::string current_session_id_; 276 }; 277 278 class RotatingKeyProvidingApp : public KeyProvidingApp { 279 public: 280 RotatingKeyProvidingApp() : num_distint_need_key_calls_(0) {} 281 virtual ~RotatingKeyProvidingApp() { 282 // Expect that NeedKey is fired multiple times with different |init_data|. 283 EXPECT_GT(num_distint_need_key_calls_, 1u); 284 } 285 286 virtual void NeedKey(const std::string& type, 287 const std::vector<uint8>& init_data, 288 AesDecryptor* decryptor) OVERRIDE { 289 // Skip the request if the |init_data| has been seen. 290 if (init_data == prev_init_data_) 291 return; 292 prev_init_data_ = init_data; 293 ++num_distint_need_key_calls_; 294 295 decryptor->CreateSession(type, 296 vector_as_array(&init_data), 297 init_data.size(), 298 MediaKeys::TEMPORARY_SESSION, 299 CreateSessionPromise(RESOLVED)); 300 301 std::vector<uint8> key_id; 302 std::vector<uint8> key; 303 EXPECT_TRUE(GetKeyAndKeyId(init_data, &key, &key_id)); 304 305 // Convert key into a JSON structure and then add it. 306 std::string jwk = GenerateJWKSet(vector_as_array(&key), 307 key.size(), 308 vector_as_array(&key_id), 309 key_id.size()); 310 decryptor->UpdateSession(current_session_id_, 311 reinterpret_cast<const uint8*>(jwk.data()), 312 jwk.size(), 313 CreatePromise(RESOLVED)); 314 } 315 316 private: 317 bool GetKeyAndKeyId(std::vector<uint8> init_data, 318 std::vector<uint8>* key, 319 std::vector<uint8>* key_id) { 320 // For WebM, init_data is key_id; for ISO CENC, init_data should contain 321 // the key_id. We assume key_id is in the end of init_data here (that is 322 // only a reasonable assumption for WebM and clear key ISO CENC). 323 DCHECK_GE(init_data.size(), arraysize(kKeyId)); 324 std::vector<uint8> key_id_from_init_data( 325 init_data.end() - arraysize(kKeyId), init_data.end()); 326 327 key->assign(kSecretKey, kSecretKey + arraysize(kSecretKey)); 328 key_id->assign(kKeyId, kKeyId + arraysize(kKeyId)); 329 330 // The Key and KeyId for this testing key provider are created by left 331 // rotating kSecretKey and kKeyId. Note that this implementation is only 332 // intended for testing purpose. The actual key rotation algorithm can be 333 // much more complicated. 334 // Find out the rotating position from |key_id_from_init_data| and apply on 335 // |key|. 336 for (size_t pos = 0; pos < arraysize(kKeyId); ++pos) { 337 std::rotate(key_id->begin(), key_id->begin() + pos, key_id->end()); 338 if (*key_id == key_id_from_init_data) { 339 std::rotate(key->begin(), key->begin() + pos, key->end()); 340 return true; 341 } 342 } 343 return false; 344 } 345 346 std::vector<uint8> prev_init_data_; 347 uint32 num_distint_need_key_calls_; 348 }; 349 350 // Ignores needkey and does not perform a license request 351 class NoResponseApp : public FakeEncryptedMedia::AppBase { 352 public: 353 virtual void OnSessionMessage(const std::string& web_session_id, 354 const std::vector<uint8>& message, 355 const GURL& default_url) OVERRIDE { 356 EXPECT_FALSE(web_session_id.empty()); 357 EXPECT_FALSE(message.empty()); 358 FAIL() << "Unexpected Message"; 359 } 360 361 virtual void OnSessionReady(const std::string& web_session_id) OVERRIDE { 362 EXPECT_FALSE(web_session_id.empty()); 363 FAIL() << "Unexpected Ready"; 364 } 365 366 virtual void OnSessionClosed(const std::string& web_session_id) OVERRIDE { 367 EXPECT_FALSE(web_session_id.empty()); 368 FAIL() << "Unexpected Closed"; 369 } 370 371 virtual void NeedKey(const std::string& type, 372 const std::vector<uint8>& init_data, 373 AesDecryptor* decryptor) OVERRIDE { 374 } 375 }; 376 377 // Helper class that emulates calls made on the ChunkDemuxer by the 378 // Media Source API. 379 class MockMediaSource { 380 public: 381 MockMediaSource(const std::string& filename, 382 const std::string& mimetype, 383 int initial_append_size) 384 : file_path_(GetTestDataFilePath(filename)), 385 current_position_(0), 386 initial_append_size_(initial_append_size), 387 mimetype_(mimetype), 388 chunk_demuxer_(new ChunkDemuxer( 389 base::Bind(&MockMediaSource::DemuxerOpened, base::Unretained(this)), 390 base::Bind(&MockMediaSource::DemuxerNeedKey, 391 base::Unretained(this)), 392 LogCB(), 393 true)), 394 owned_chunk_demuxer_(chunk_demuxer_) { 395 396 file_data_ = ReadTestDataFile(filename); 397 398 if (initial_append_size_ == kAppendWholeFile) 399 initial_append_size_ = file_data_->data_size(); 400 401 DCHECK_GT(initial_append_size_, 0); 402 DCHECK_LE(initial_append_size_, file_data_->data_size()); 403 } 404 405 virtual ~MockMediaSource() {} 406 407 scoped_ptr<Demuxer> GetDemuxer() { return owned_chunk_demuxer_.Pass(); } 408 409 void set_need_key_cb(const Demuxer::NeedKeyCB& need_key_cb) { 410 need_key_cb_ = need_key_cb; 411 } 412 413 void Seek(base::TimeDelta seek_time, int new_position, int seek_append_size) { 414 chunk_demuxer_->StartWaitingForSeek(seek_time); 415 416 chunk_demuxer_->Abort( 417 kSourceId, 418 base::TimeDelta(), kInfiniteDuration(), &last_timestamp_offset_); 419 420 DCHECK_GE(new_position, 0); 421 DCHECK_LT(new_position, file_data_->data_size()); 422 current_position_ = new_position; 423 424 AppendData(seek_append_size); 425 } 426 427 void AppendData(int size) { 428 DCHECK(chunk_demuxer_); 429 DCHECK_LT(current_position_, file_data_->data_size()); 430 DCHECK_LE(current_position_ + size, file_data_->data_size()); 431 432 chunk_demuxer_->AppendData( 433 kSourceId, file_data_->data() + current_position_, size, 434 base::TimeDelta(), kInfiniteDuration(), &last_timestamp_offset_); 435 current_position_ += size; 436 } 437 438 void AppendAtTime(base::TimeDelta timestamp_offset, 439 const uint8* pData, 440 int size) { 441 CHECK(!chunk_demuxer_->IsParsingMediaSegment(kSourceId)); 442 chunk_demuxer_->AppendData(kSourceId, pData, size, 443 base::TimeDelta(), kInfiniteDuration(), 444 ×tamp_offset); 445 last_timestamp_offset_ = timestamp_offset; 446 } 447 448 void AppendAtTimeWithWindow(base::TimeDelta timestamp_offset, 449 base::TimeDelta append_window_start, 450 base::TimeDelta append_window_end, 451 const uint8* pData, 452 int size) { 453 CHECK(!chunk_demuxer_->IsParsingMediaSegment(kSourceId)); 454 chunk_demuxer_->AppendData(kSourceId, 455 pData, 456 size, 457 append_window_start, 458 append_window_end, 459 ×tamp_offset); 460 last_timestamp_offset_ = timestamp_offset; 461 } 462 463 void EndOfStream() { 464 chunk_demuxer_->MarkEndOfStream(PIPELINE_OK); 465 } 466 467 void Abort() { 468 if (!chunk_demuxer_) 469 return; 470 chunk_demuxer_->Shutdown(); 471 chunk_demuxer_ = NULL; 472 } 473 474 void DemuxerOpened() { 475 base::MessageLoop::current()->PostTask( 476 FROM_HERE, base::Bind(&MockMediaSource::DemuxerOpenedTask, 477 base::Unretained(this))); 478 } 479 480 void DemuxerOpenedTask() { 481 // This code assumes that |mimetype_| is one of the following forms. 482 // 1. audio/mpeg 483 // 2. video/webm;codec="vorbis,vp8". 484 size_t semicolon = mimetype_.find(";"); 485 std::string type = mimetype_; 486 std::vector<std::string> codecs; 487 if (semicolon != std::string::npos) { 488 type = mimetype_.substr(0, semicolon); 489 size_t codecs_param_start = mimetype_.find("codecs=\"", semicolon); 490 491 CHECK_NE(codecs_param_start, std::string::npos); 492 493 codecs_param_start += 8; // Skip over the codecs=". 494 495 size_t codecs_param_end = mimetype_.find("\"", codecs_param_start); 496 497 CHECK_NE(codecs_param_end, std::string::npos); 498 499 std::string codecs_param = 500 mimetype_.substr(codecs_param_start, 501 codecs_param_end - codecs_param_start); 502 Tokenize(codecs_param, ",", &codecs); 503 } 504 505 CHECK_EQ(chunk_demuxer_->AddId(kSourceId, type, codecs), ChunkDemuxer::kOk); 506 507 AppendData(initial_append_size_); 508 } 509 510 void DemuxerNeedKey(const std::string& type, 511 const std::vector<uint8>& init_data) { 512 DCHECK(!init_data.empty()); 513 CHECK(!need_key_cb_.is_null()); 514 need_key_cb_.Run(type, init_data); 515 } 516 517 base::TimeDelta last_timestamp_offset() const { 518 return last_timestamp_offset_; 519 } 520 521 private: 522 base::FilePath file_path_; 523 scoped_refptr<DecoderBuffer> file_data_; 524 int current_position_; 525 int initial_append_size_; 526 std::string mimetype_; 527 ChunkDemuxer* chunk_demuxer_; 528 scoped_ptr<Demuxer> owned_chunk_demuxer_; 529 Demuxer::NeedKeyCB need_key_cb_; 530 base::TimeDelta last_timestamp_offset_; 531 }; 532 533 class PipelineIntegrationTest 534 : public testing::Test, 535 public PipelineIntegrationTestBase { 536 public: 537 void StartPipelineWithMediaSource(MockMediaSource* source) { 538 EXPECT_CALL(*this, OnMetadata(_)).Times(AtMost(1)) 539 .WillRepeatedly(SaveArg<0>(&metadata_)); 540 EXPECT_CALL(*this, OnPrerollCompleted()).Times(AtMost(1)); 541 pipeline_->Start( 542 CreateFilterCollection(source->GetDemuxer(), NULL), 543 base::Bind(&PipelineIntegrationTest::OnEnded, base::Unretained(this)), 544 base::Bind(&PipelineIntegrationTest::OnError, base::Unretained(this)), 545 QuitOnStatusCB(PIPELINE_OK), 546 base::Bind(&PipelineIntegrationTest::OnMetadata, 547 base::Unretained(this)), 548 base::Bind(&PipelineIntegrationTest::OnPrerollCompleted, 549 base::Unretained(this)), 550 base::Closure()); 551 552 message_loop_.Run(); 553 } 554 555 void StartHashedPipelineWithMediaSource(MockMediaSource* source) { 556 hashing_enabled_ = true; 557 StartPipelineWithMediaSource(source); 558 } 559 560 void StartPipelineWithEncryptedMedia( 561 MockMediaSource* source, 562 FakeEncryptedMedia* encrypted_media) { 563 EXPECT_CALL(*this, OnMetadata(_)).Times(AtMost(1)) 564 .WillRepeatedly(SaveArg<0>(&metadata_)); 565 EXPECT_CALL(*this, OnPrerollCompleted()).Times(AtMost(1)); 566 pipeline_->Start( 567 CreateFilterCollection(source->GetDemuxer(), 568 encrypted_media->decryptor()), 569 base::Bind(&PipelineIntegrationTest::OnEnded, base::Unretained(this)), 570 base::Bind(&PipelineIntegrationTest::OnError, base::Unretained(this)), 571 QuitOnStatusCB(PIPELINE_OK), 572 base::Bind(&PipelineIntegrationTest::OnMetadata, 573 base::Unretained(this)), 574 base::Bind(&PipelineIntegrationTest::OnPrerollCompleted, 575 base::Unretained(this)), 576 base::Closure()); 577 578 source->set_need_key_cb(base::Bind(&FakeEncryptedMedia::NeedKey, 579 base::Unretained(encrypted_media))); 580 581 message_loop_.Run(); 582 } 583 584 // Verifies that seeking works properly for ChunkDemuxer when the 585 // seek happens while there is a pending read on the ChunkDemuxer 586 // and no data is available. 587 bool TestSeekDuringRead(const std::string& filename, 588 const std::string& mimetype, 589 int initial_append_size, 590 base::TimeDelta start_seek_time, 591 base::TimeDelta seek_time, 592 int seek_file_position, 593 int seek_append_size) { 594 MockMediaSource source(filename, mimetype, initial_append_size); 595 StartPipelineWithMediaSource(&source); 596 597 if (pipeline_status_ != PIPELINE_OK) 598 return false; 599 600 Play(); 601 if (!WaitUntilCurrentTimeIsAfter(start_seek_time)) 602 return false; 603 604 source.Seek(seek_time, seek_file_position, seek_append_size); 605 if (!Seek(seek_time)) 606 return false; 607 608 source.EndOfStream(); 609 610 source.Abort(); 611 Stop(); 612 return true; 613 } 614 }; 615 616 TEST_F(PipelineIntegrationTest, BasicPlayback) { 617 ASSERT_TRUE(Start(GetTestDataFilePath("bear-320x240.webm"), PIPELINE_OK)); 618 619 Play(); 620 621 ASSERT_TRUE(WaitUntilOnEnded()); 622 } 623 624 TEST_F(PipelineIntegrationTest, BasicPlaybackOpusOgg) { 625 ASSERT_TRUE(Start(GetTestDataFilePath("bear-opus.ogg"), PIPELINE_OK)); 626 627 Play(); 628 629 ASSERT_TRUE(WaitUntilOnEnded()); 630 } 631 632 TEST_F(PipelineIntegrationTest, BasicPlaybackHashed) { 633 ASSERT_TRUE(Start( 634 GetTestDataFilePath("bear-320x240.webm"), PIPELINE_OK, kHashed)); 635 636 Play(); 637 638 ASSERT_TRUE(WaitUntilOnEnded()); 639 640 EXPECT_EQ("f0be120a90a811506777c99a2cdf7cc1", GetVideoHash()); 641 EXPECT_EQ("-3.59,-2.06,-0.43,2.15,0.77,-0.95,", GetAudioHash()); 642 EXPECT_TRUE(demuxer_->GetTimelineOffset().is_null()); 643 } 644 645 TEST_F(PipelineIntegrationTest, BasicPlaybackLive) { 646 ASSERT_TRUE(Start( 647 GetTestDataFilePath("bear-320x240-live.webm"), PIPELINE_OK, kHashed)); 648 649 Play(); 650 651 ASSERT_TRUE(WaitUntilOnEnded()); 652 653 EXPECT_EQ("f0be120a90a811506777c99a2cdf7cc1", GetVideoHash()); 654 EXPECT_EQ("-3.59,-2.06,-0.43,2.15,0.77,-0.95,", GetAudioHash()); 655 656 // TODO: Fix FFmpeg code to return higher resolution time values so 657 // we don't have to truncate our expectations here. 658 EXPECT_EQ(TruncateToFFmpegTimeResolution(kLiveTimelineOffset()), 659 demuxer_->GetTimelineOffset()); 660 } 661 662 TEST_F(PipelineIntegrationTest, F32PlaybackHashed) { 663 ASSERT_TRUE( 664 Start(GetTestDataFilePath("sfx_f32le.wav"), PIPELINE_OK, kHashed)); 665 Play(); 666 ASSERT_TRUE(WaitUntilOnEnded()); 667 EXPECT_EQ(std::string(kNullVideoHash), GetVideoHash()); 668 EXPECT_EQ("3.03,2.86,2.99,3.31,3.57,4.06,", GetAudioHash()); 669 } 670 671 TEST_F(PipelineIntegrationTest, BasicPlaybackEncrypted) { 672 FakeEncryptedMedia encrypted_media(new KeyProvidingApp()); 673 set_need_key_cb(base::Bind(&FakeEncryptedMedia::NeedKey, 674 base::Unretained(&encrypted_media))); 675 676 ASSERT_TRUE(Start(GetTestDataFilePath("bear-320x240-av_enc-av.webm"), 677 encrypted_media.decryptor())); 678 679 Play(); 680 681 ASSERT_TRUE(WaitUntilOnEnded()); 682 Stop(); 683 } 684 685 TEST_F(PipelineIntegrationTest, BasicPlayback_MediaSource) { 686 MockMediaSource source("bear-320x240.webm", kWebM, 219229); 687 StartPipelineWithMediaSource(&source); 688 source.EndOfStream(); 689 690 EXPECT_EQ(1u, pipeline_->GetBufferedTimeRanges().size()); 691 EXPECT_EQ(0, pipeline_->GetBufferedTimeRanges().start(0).InMilliseconds()); 692 EXPECT_EQ(k320WebMFileDurationMs, 693 pipeline_->GetBufferedTimeRanges().end(0).InMilliseconds()); 694 695 Play(); 696 697 ASSERT_TRUE(WaitUntilOnEnded()); 698 699 EXPECT_TRUE(demuxer_->GetTimelineOffset().is_null()); 700 source.Abort(); 701 Stop(); 702 } 703 704 TEST_F(PipelineIntegrationTest, BasicPlayback_MediaSource_Live) { 705 MockMediaSource source("bear-320x240-live.webm", kWebM, 219221); 706 StartPipelineWithMediaSource(&source); 707 source.EndOfStream(); 708 709 EXPECT_EQ(1u, pipeline_->GetBufferedTimeRanges().size()); 710 EXPECT_EQ(0, pipeline_->GetBufferedTimeRanges().start(0).InMilliseconds()); 711 EXPECT_EQ(k320WebMFileDurationMs, 712 pipeline_->GetBufferedTimeRanges().end(0).InMilliseconds()); 713 714 Play(); 715 716 ASSERT_TRUE(WaitUntilOnEnded()); 717 718 EXPECT_EQ(kLiveTimelineOffset(), 719 demuxer_->GetTimelineOffset()); 720 source.Abort(); 721 Stop(); 722 } 723 724 TEST_F(PipelineIntegrationTest, BasicPlayback_MediaSource_VP9_WebM) { 725 MockMediaSource source("bear-vp9.webm", kWebMVP9, 67504); 726 StartPipelineWithMediaSource(&source); 727 source.EndOfStream(); 728 729 EXPECT_EQ(1u, pipeline_->GetBufferedTimeRanges().size()); 730 EXPECT_EQ(0, pipeline_->GetBufferedTimeRanges().start(0).InMilliseconds()); 731 EXPECT_EQ(kVP9WebMFileDurationMs, 732 pipeline_->GetBufferedTimeRanges().end(0).InMilliseconds()); 733 734 Play(); 735 736 ASSERT_TRUE(WaitUntilOnEnded()); 737 source.Abort(); 738 Stop(); 739 } 740 741 TEST_F(PipelineIntegrationTest, BasicPlayback_MediaSource_VP8A_WebM) { 742 MockMediaSource source("bear-vp8a.webm", kVideoOnlyWebM, kAppendWholeFile); 743 StartPipelineWithMediaSource(&source); 744 source.EndOfStream(); 745 746 EXPECT_EQ(1u, pipeline_->GetBufferedTimeRanges().size()); 747 EXPECT_EQ(0, pipeline_->GetBufferedTimeRanges().start(0).InMilliseconds()); 748 EXPECT_EQ(kVP8AWebMFileDurationMs, 749 pipeline_->GetBufferedTimeRanges().end(0).InMilliseconds()); 750 751 Play(); 752 753 ASSERT_TRUE(WaitUntilOnEnded()); 754 source.Abort(); 755 Stop(); 756 } 757 758 TEST_F(PipelineIntegrationTest, BasicPlayback_MediaSource_Opus_WebM) { 759 MockMediaSource source("bear-opus-end-trimming.webm", kOpusAudioOnlyWebM, 760 kAppendWholeFile); 761 StartPipelineWithMediaSource(&source); 762 source.EndOfStream(); 763 764 EXPECT_EQ(1u, pipeline_->GetBufferedTimeRanges().size()); 765 EXPECT_EQ(0, pipeline_->GetBufferedTimeRanges().start(0).InMilliseconds()); 766 EXPECT_EQ(kOpusEndTrimmingWebMFileDurationMs, 767 pipeline_->GetBufferedTimeRanges().end(0).InMilliseconds()); 768 Play(); 769 770 ASSERT_TRUE(WaitUntilOnEnded()); 771 source.Abort(); 772 Stop(); 773 } 774 775 // Flaky. http://crbug.com/304776 776 TEST_F(PipelineIntegrationTest, DISABLED_MediaSource_Opus_Seeking_WebM) { 777 MockMediaSource source("bear-opus-end-trimming.webm", kOpusAudioOnlyWebM, 778 kAppendWholeFile); 779 StartHashedPipelineWithMediaSource(&source); 780 781 EXPECT_EQ(1u, pipeline_->GetBufferedTimeRanges().size()); 782 EXPECT_EQ(0, pipeline_->GetBufferedTimeRanges().start(0).InMilliseconds()); 783 EXPECT_EQ(kOpusEndTrimmingWebMFileDurationMs, 784 pipeline_->GetBufferedTimeRanges().end(0).InMilliseconds()); 785 786 base::TimeDelta start_seek_time = base::TimeDelta::FromMilliseconds(1000); 787 base::TimeDelta seek_time = base::TimeDelta::FromMilliseconds(2000); 788 789 Play(); 790 ASSERT_TRUE(WaitUntilCurrentTimeIsAfter(start_seek_time)); 791 source.Seek(seek_time, 0x1D5, 34017); 792 source.EndOfStream(); 793 ASSERT_TRUE(Seek(seek_time)); 794 795 ASSERT_TRUE(WaitUntilOnEnded()); 796 797 EXPECT_EQ("0.76,0.20,-0.82,-0.58,-1.29,-0.29,", GetAudioHash()); 798 799 source.Abort(); 800 Stop(); 801 } 802 803 TEST_F(PipelineIntegrationTest, MediaSource_ConfigChange_WebM) { 804 MockMediaSource source("bear-320x240-16x9-aspect.webm", kWebM, 805 kAppendWholeFile); 806 StartPipelineWithMediaSource(&source); 807 808 scoped_refptr<DecoderBuffer> second_file = 809 ReadTestDataFile("bear-640x360.webm"); 810 811 source.AppendAtTime(base::TimeDelta::FromSeconds(kAppendTimeSec), 812 second_file->data(), second_file->data_size()); 813 814 source.EndOfStream(); 815 816 EXPECT_EQ(1u, pipeline_->GetBufferedTimeRanges().size()); 817 EXPECT_EQ(0, pipeline_->GetBufferedTimeRanges().start(0).InMilliseconds()); 818 EXPECT_EQ(kAppendTimeMs + k640WebMFileDurationMs, 819 pipeline_->GetBufferedTimeRanges().end(0).InMilliseconds()); 820 821 Play(); 822 823 EXPECT_TRUE(WaitUntilOnEnded()); 824 source.Abort(); 825 Stop(); 826 } 827 828 TEST_F(PipelineIntegrationTest, MediaSource_ConfigChange_Encrypted_WebM) { 829 MockMediaSource source("bear-320x240-16x9-aspect-av_enc-av.webm", kWebM, 830 kAppendWholeFile); 831 FakeEncryptedMedia encrypted_media(new KeyProvidingApp()); 832 StartPipelineWithEncryptedMedia(&source, &encrypted_media); 833 834 scoped_refptr<DecoderBuffer> second_file = 835 ReadTestDataFile("bear-640x360-av_enc-av.webm"); 836 837 source.AppendAtTime(base::TimeDelta::FromSeconds(kAppendTimeSec), 838 second_file->data(), second_file->data_size()); 839 840 source.EndOfStream(); 841 842 EXPECT_EQ(1u, pipeline_->GetBufferedTimeRanges().size()); 843 EXPECT_EQ(0, pipeline_->GetBufferedTimeRanges().start(0).InMilliseconds()); 844 EXPECT_EQ(kAppendTimeMs + k640WebMFileDurationMs, 845 pipeline_->GetBufferedTimeRanges().end(0).InMilliseconds()); 846 847 Play(); 848 849 EXPECT_TRUE(WaitUntilOnEnded()); 850 source.Abort(); 851 Stop(); 852 } 853 854 // Config changes from encrypted to clear are not currently supported. 855 TEST_F(PipelineIntegrationTest, 856 MediaSource_ConfigChange_ClearThenEncrypted_WebM) { 857 MockMediaSource source("bear-320x240-16x9-aspect.webm", kWebM, 858 kAppendWholeFile); 859 FakeEncryptedMedia encrypted_media(new KeyProvidingApp()); 860 StartPipelineWithEncryptedMedia(&source, &encrypted_media); 861 862 scoped_refptr<DecoderBuffer> second_file = 863 ReadTestDataFile("bear-640x360-av_enc-av.webm"); 864 865 source.AppendAtTime(base::TimeDelta::FromSeconds(kAppendTimeSec), 866 second_file->data(), second_file->data_size()); 867 868 source.EndOfStream(); 869 870 message_loop_.Run(); 871 EXPECT_EQ(PIPELINE_ERROR_DECODE, pipeline_status_); 872 873 EXPECT_EQ(1u, pipeline_->GetBufferedTimeRanges().size()); 874 EXPECT_EQ(0, pipeline_->GetBufferedTimeRanges().start(0).InMilliseconds()); 875 // The second video was not added, so its time has not been added. 876 EXPECT_EQ(k320WebMFileDurationMs, 877 pipeline_->GetBufferedTimeRanges().end(0).InMilliseconds()); 878 879 Play(); 880 881 EXPECT_EQ(PIPELINE_ERROR_DECODE, WaitUntilEndedOrError()); 882 source.Abort(); 883 } 884 885 // Config changes from clear to encrypted are not currently supported. 886 TEST_F(PipelineIntegrationTest, 887 MediaSource_ConfigChange_EncryptedThenClear_WebM) { 888 MockMediaSource source("bear-320x240-16x9-aspect-av_enc-av.webm", kWebM, 889 kAppendWholeFile); 890 FakeEncryptedMedia encrypted_media(new KeyProvidingApp()); 891 StartPipelineWithEncryptedMedia(&source, &encrypted_media); 892 893 scoped_refptr<DecoderBuffer> second_file = 894 ReadTestDataFile("bear-640x360.webm"); 895 896 source.AppendAtTime(base::TimeDelta::FromSeconds(kAppendTimeSec), 897 second_file->data(), second_file->data_size()); 898 899 source.EndOfStream(); 900 901 EXPECT_EQ(1u, pipeline_->GetBufferedTimeRanges().size()); 902 EXPECT_EQ(0, pipeline_->GetBufferedTimeRanges().start(0).InMilliseconds()); 903 // The second video was not added, so its time has not been added. 904 EXPECT_EQ(k320WebMFileDurationMs, 905 pipeline_->GetBufferedTimeRanges().end(0).InMilliseconds()); 906 907 Play(); 908 909 EXPECT_EQ(PIPELINE_ERROR_DECODE, WaitUntilEndedOrError()); 910 source.Abort(); 911 } 912 913 #if defined(USE_PROPRIETARY_CODECS) 914 TEST_F(PipelineIntegrationTest, MediaSource_ADTS) { 915 MockMediaSource source("sfx.adts", kADTS, kAppendWholeFile); 916 StartPipelineWithMediaSource(&source); 917 source.EndOfStream(); 918 919 EXPECT_EQ(1u, pipeline_->GetBufferedTimeRanges().size()); 920 EXPECT_EQ(0, pipeline_->GetBufferedTimeRanges().start(0).InMilliseconds()); 921 EXPECT_EQ(325, pipeline_->GetBufferedTimeRanges().end(0).InMilliseconds()); 922 923 Play(); 924 925 EXPECT_TRUE(WaitUntilOnEnded()); 926 } 927 928 TEST_F(PipelineIntegrationTest, MediaSource_ADTS_TimestampOffset) { 929 MockMediaSource source("sfx.adts", kADTS, kAppendWholeFile); 930 StartHashedPipelineWithMediaSource(&source); 931 EXPECT_EQ(325, source.last_timestamp_offset().InMilliseconds()); 932 933 // Trim off multiple frames off the beginning of the segment which will cause 934 // the first decoded frame to be incorrect if preroll isn't implemented. 935 const base::TimeDelta adts_preroll_duration = 936 base::TimeDelta::FromSecondsD(2.5 * 1024 / 44100); 937 const base::TimeDelta append_time = 938 source.last_timestamp_offset() - adts_preroll_duration; 939 940 scoped_refptr<DecoderBuffer> second_file = ReadTestDataFile("sfx.adts"); 941 source.AppendAtTimeWithWindow(append_time, 942 append_time + adts_preroll_duration, 943 kInfiniteDuration(), 944 second_file->data(), 945 second_file->data_size()); 946 source.EndOfStream(); 947 948 EXPECT_EQ(592, source.last_timestamp_offset().InMilliseconds()); 949 EXPECT_EQ(1u, pipeline_->GetBufferedTimeRanges().size()); 950 EXPECT_EQ(0, pipeline_->GetBufferedTimeRanges().start(0).InMilliseconds()); 951 EXPECT_EQ(592, pipeline_->GetBufferedTimeRanges().end(0).InMilliseconds()); 952 953 Play(); 954 955 EXPECT_TRUE(WaitUntilOnEnded()); 956 957 // Verify preroll is stripped. 958 EXPECT_EQ("-0.06,0.97,-0.90,-0.70,-0.53,-0.34,", GetAudioHash()); 959 } 960 961 TEST_F(PipelineIntegrationTest, BasicPlaybackHashed_MP3) { 962 ASSERT_TRUE(Start(GetTestDataFilePath("sfx.mp3"), PIPELINE_OK, kHashed)); 963 964 Play(); 965 966 ASSERT_TRUE(WaitUntilOnEnded()); 967 968 // Verify codec delay and preroll are stripped. 969 EXPECT_EQ("3.05,2.87,3.00,3.32,3.58,4.08,", GetAudioHash()); 970 } 971 972 TEST_F(PipelineIntegrationTest, MediaSource_MP3) { 973 MockMediaSource source("sfx.mp3", kMP3, kAppendWholeFile); 974 StartHashedPipelineWithMediaSource(&source); 975 source.EndOfStream(); 976 977 EXPECT_EQ(1u, pipeline_->GetBufferedTimeRanges().size()); 978 EXPECT_EQ(0, pipeline_->GetBufferedTimeRanges().start(0).InMilliseconds()); 979 EXPECT_EQ(313, pipeline_->GetBufferedTimeRanges().end(0).InMilliseconds()); 980 981 Play(); 982 983 EXPECT_TRUE(WaitUntilOnEnded()); 984 985 // Verify that codec delay was stripped. 986 EXPECT_EQ("1.01,2.71,4.18,4.32,3.04,1.12,", GetAudioHash()); 987 } 988 989 TEST_F(PipelineIntegrationTest, MediaSource_MP3_TimestampOffset) { 990 MockMediaSource source("sfx.mp3", kMP3, kAppendWholeFile); 991 StartPipelineWithMediaSource(&source); 992 EXPECT_EQ(313, source.last_timestamp_offset().InMilliseconds()); 993 994 // There are 576 silent frames at the start of this mp3. The second append 995 // should trim them off. 996 const base::TimeDelta mp3_preroll_duration = 997 base::TimeDelta::FromSecondsD(576.0 / 44100); 998 const base::TimeDelta append_time = 999 source.last_timestamp_offset() - mp3_preroll_duration; 1000 1001 scoped_refptr<DecoderBuffer> second_file = ReadTestDataFile("sfx.mp3"); 1002 source.AppendAtTimeWithWindow(append_time, 1003 append_time + mp3_preroll_duration, 1004 kInfiniteDuration(), 1005 second_file->data(), 1006 second_file->data_size()); 1007 source.EndOfStream(); 1008 1009 EXPECT_EQ(613, source.last_timestamp_offset().InMilliseconds()); 1010 EXPECT_EQ(1u, pipeline_->GetBufferedTimeRanges().size()); 1011 EXPECT_EQ(0, pipeline_->GetBufferedTimeRanges().start(0).InMilliseconds()); 1012 EXPECT_EQ(613, pipeline_->GetBufferedTimeRanges().end(0).InMilliseconds()); 1013 1014 Play(); 1015 1016 EXPECT_TRUE(WaitUntilOnEnded()); 1017 } 1018 1019 TEST_F(PipelineIntegrationTest, MediaSource_MP3_Icecast) { 1020 MockMediaSource source("icy_sfx.mp3", kMP3, kAppendWholeFile); 1021 StartPipelineWithMediaSource(&source); 1022 source.EndOfStream(); 1023 1024 Play(); 1025 1026 EXPECT_TRUE(WaitUntilOnEnded()); 1027 } 1028 1029 TEST_F(PipelineIntegrationTest, MediaSource_ConfigChange_MP4) { 1030 MockMediaSource source("bear-640x360-av_frag.mp4", kMP4, kAppendWholeFile); 1031 StartPipelineWithMediaSource(&source); 1032 1033 scoped_refptr<DecoderBuffer> second_file = 1034 ReadTestDataFile("bear-1280x720-av_frag.mp4"); 1035 1036 source.AppendAtTime(base::TimeDelta::FromSeconds(kAppendTimeSec), 1037 second_file->data(), second_file->data_size()); 1038 1039 source.EndOfStream(); 1040 1041 EXPECT_EQ(1u, pipeline_->GetBufferedTimeRanges().size()); 1042 EXPECT_EQ(0, pipeline_->GetBufferedTimeRanges().start(0).InMilliseconds()); 1043 EXPECT_EQ(kAppendTimeMs + k1280IsoFileDurationMs, 1044 pipeline_->GetBufferedTimeRanges().end(0).InMilliseconds()); 1045 1046 Play(); 1047 1048 EXPECT_TRUE(WaitUntilOnEnded()); 1049 source.Abort(); 1050 Stop(); 1051 } 1052 1053 TEST_F(PipelineIntegrationTest, 1054 MediaSource_ConfigChange_Encrypted_MP4_CENC_VideoOnly) { 1055 MockMediaSource source("bear-640x360-v_frag-cenc.mp4", kMP4Video, 1056 kAppendWholeFile); 1057 FakeEncryptedMedia encrypted_media(new KeyProvidingApp()); 1058 StartPipelineWithEncryptedMedia(&source, &encrypted_media); 1059 1060 scoped_refptr<DecoderBuffer> second_file = 1061 ReadTestDataFile("bear-1280x720-v_frag-cenc.mp4"); 1062 1063 source.AppendAtTime(base::TimeDelta::FromSeconds(kAppendTimeSec), 1064 second_file->data(), second_file->data_size()); 1065 1066 source.EndOfStream(); 1067 1068 EXPECT_EQ(1u, pipeline_->GetBufferedTimeRanges().size()); 1069 EXPECT_EQ(0, pipeline_->GetBufferedTimeRanges().start(0).InMilliseconds()); 1070 EXPECT_EQ(kAppendTimeMs + k1280IsoFileDurationMs, 1071 pipeline_->GetBufferedTimeRanges().end(0).InMilliseconds()); 1072 1073 Play(); 1074 1075 EXPECT_TRUE(WaitUntilOnEnded()); 1076 source.Abort(); 1077 Stop(); 1078 } 1079 1080 TEST_F(PipelineIntegrationTest, 1081 MediaSource_ConfigChange_Encrypted_MP4_CENC_KeyRotation_VideoOnly) { 1082 MockMediaSource source("bear-640x360-v_frag-cenc-key_rotation.mp4", kMP4Video, 1083 kAppendWholeFile); 1084 FakeEncryptedMedia encrypted_media(new RotatingKeyProvidingApp()); 1085 StartPipelineWithEncryptedMedia(&source, &encrypted_media); 1086 1087 scoped_refptr<DecoderBuffer> second_file = 1088 ReadTestDataFile("bear-1280x720-v_frag-cenc-key_rotation.mp4"); 1089 1090 source.AppendAtTime(base::TimeDelta::FromSeconds(kAppendTimeSec), 1091 second_file->data(), second_file->data_size()); 1092 1093 source.EndOfStream(); 1094 1095 EXPECT_EQ(1u, pipeline_->GetBufferedTimeRanges().size()); 1096 EXPECT_EQ(0, pipeline_->GetBufferedTimeRanges().start(0).InMilliseconds()); 1097 EXPECT_EQ(kAppendTimeMs + k1280IsoFileDurationMs, 1098 pipeline_->GetBufferedTimeRanges().end(0).InMilliseconds()); 1099 1100 Play(); 1101 1102 EXPECT_TRUE(WaitUntilOnEnded()); 1103 source.Abort(); 1104 Stop(); 1105 } 1106 1107 // Config changes from clear to encrypted are not currently supported. 1108 // TODO(ddorwin): Figure out why this CHECKs in AppendAtTime(). 1109 TEST_F(PipelineIntegrationTest, 1110 DISABLED_MediaSource_ConfigChange_ClearThenEncrypted_MP4_CENC) { 1111 MockMediaSource source("bear-640x360-av_frag.mp4", kMP4Video, 1112 kAppendWholeFile); 1113 FakeEncryptedMedia encrypted_media(new KeyProvidingApp()); 1114 StartPipelineWithEncryptedMedia(&source, &encrypted_media); 1115 1116 scoped_refptr<DecoderBuffer> second_file = 1117 ReadTestDataFile("bear-1280x720-v_frag-cenc.mp4"); 1118 1119 source.AppendAtTime(base::TimeDelta::FromSeconds(kAppendTimeSec), 1120 second_file->data(), second_file->data_size()); 1121 1122 source.EndOfStream(); 1123 1124 message_loop_.Run(); 1125 EXPECT_EQ(PIPELINE_ERROR_DECODE, pipeline_status_); 1126 1127 EXPECT_EQ(1u, pipeline_->GetBufferedTimeRanges().size()); 1128 EXPECT_EQ(0, pipeline_->GetBufferedTimeRanges().start(0).InMilliseconds()); 1129 // The second video was not added, so its time has not been added. 1130 EXPECT_EQ(k640IsoFileDurationMs, 1131 pipeline_->GetBufferedTimeRanges().end(0).InMilliseconds()); 1132 1133 Play(); 1134 1135 EXPECT_EQ(PIPELINE_ERROR_DECODE, WaitUntilEndedOrError()); 1136 source.Abort(); 1137 } 1138 1139 // Config changes from encrypted to clear are not currently supported. 1140 TEST_F(PipelineIntegrationTest, 1141 MediaSource_ConfigChange_EncryptedThenClear_MP4_CENC) { 1142 MockMediaSource source("bear-640x360-v_frag-cenc.mp4", kMP4Video, 1143 kAppendWholeFile); 1144 FakeEncryptedMedia encrypted_media(new KeyProvidingApp()); 1145 StartPipelineWithEncryptedMedia(&source, &encrypted_media); 1146 1147 scoped_refptr<DecoderBuffer> second_file = 1148 ReadTestDataFile("bear-1280x720-av_frag.mp4"); 1149 1150 source.AppendAtTime(base::TimeDelta::FromSeconds(kAppendTimeSec), 1151 second_file->data(), second_file->data_size()); 1152 1153 source.EndOfStream(); 1154 1155 EXPECT_EQ(1u, pipeline_->GetBufferedTimeRanges().size()); 1156 EXPECT_EQ(0, pipeline_->GetBufferedTimeRanges().start(0).InMilliseconds()); 1157 // The second video was not added, so its time has not been added. 1158 EXPECT_EQ(k640IsoCencFileDurationMs, 1159 pipeline_->GetBufferedTimeRanges().end(0).InMilliseconds()); 1160 1161 Play(); 1162 1163 EXPECT_EQ(PIPELINE_ERROR_DECODE, WaitUntilEndedOrError()); 1164 source.Abort(); 1165 } 1166 1167 // Verify files which change configuration midstream fail gracefully. 1168 TEST_F(PipelineIntegrationTest, MidStreamConfigChangesFail) { 1169 ASSERT_TRUE(Start( 1170 GetTestDataFilePath("midstream_config_change.mp3"), PIPELINE_OK)); 1171 Play(); 1172 ASSERT_EQ(WaitUntilEndedOrError(), PIPELINE_ERROR_DECODE); 1173 } 1174 1175 #endif 1176 1177 TEST_F(PipelineIntegrationTest, BasicPlayback_16x9AspectRatio) { 1178 ASSERT_TRUE(Start(GetTestDataFilePath("bear-320x240-16x9-aspect.webm"), 1179 PIPELINE_OK)); 1180 Play(); 1181 ASSERT_TRUE(WaitUntilOnEnded()); 1182 } 1183 1184 TEST_F(PipelineIntegrationTest, EncryptedPlayback_WebM) { 1185 MockMediaSource source("bear-320x240-av_enc-av.webm", kWebM, 219816); 1186 FakeEncryptedMedia encrypted_media(new KeyProvidingApp()); 1187 StartPipelineWithEncryptedMedia(&source, &encrypted_media); 1188 1189 source.EndOfStream(); 1190 ASSERT_EQ(PIPELINE_OK, pipeline_status_); 1191 1192 Play(); 1193 1194 ASSERT_TRUE(WaitUntilOnEnded()); 1195 source.Abort(); 1196 Stop(); 1197 } 1198 1199 TEST_F(PipelineIntegrationTest, EncryptedPlayback_ClearStart_WebM) { 1200 MockMediaSource source("bear-320x240-av_enc-av_clear-1s.webm", kWebM, 1201 kAppendWholeFile); 1202 FakeEncryptedMedia encrypted_media(new KeyProvidingApp()); 1203 StartPipelineWithEncryptedMedia(&source, &encrypted_media); 1204 1205 source.EndOfStream(); 1206 ASSERT_EQ(PIPELINE_OK, pipeline_status_); 1207 1208 Play(); 1209 1210 ASSERT_TRUE(WaitUntilOnEnded()); 1211 source.Abort(); 1212 Stop(); 1213 } 1214 1215 TEST_F(PipelineIntegrationTest, EncryptedPlayback_NoEncryptedFrames_WebM) { 1216 MockMediaSource source("bear-320x240-av_enc-av_clear-all.webm", kWebM, 1217 kAppendWholeFile); 1218 FakeEncryptedMedia encrypted_media(new NoResponseApp()); 1219 StartPipelineWithEncryptedMedia(&source, &encrypted_media); 1220 1221 source.EndOfStream(); 1222 ASSERT_EQ(PIPELINE_OK, pipeline_status_); 1223 1224 Play(); 1225 1226 ASSERT_TRUE(WaitUntilOnEnded()); 1227 source.Abort(); 1228 Stop(); 1229 } 1230 1231 #if defined(USE_PROPRIETARY_CODECS) 1232 TEST_F(PipelineIntegrationTest, EncryptedPlayback_MP4_CENC_VideoOnly) { 1233 MockMediaSource source("bear-1280x720-v_frag-cenc.mp4", kMP4Video, 1234 kAppendWholeFile); 1235 FakeEncryptedMedia encrypted_media(new KeyProvidingApp()); 1236 StartPipelineWithEncryptedMedia(&source, &encrypted_media); 1237 1238 source.EndOfStream(); 1239 ASSERT_EQ(PIPELINE_OK, pipeline_status_); 1240 1241 Play(); 1242 1243 ASSERT_TRUE(WaitUntilOnEnded()); 1244 source.Abort(); 1245 Stop(); 1246 } 1247 1248 TEST_F(PipelineIntegrationTest, EncryptedPlayback_MP4_CENC_AudioOnly) { 1249 MockMediaSource source("bear-1280x720-a_frag-cenc.mp4", kMP4Audio, 1250 kAppendWholeFile); 1251 FakeEncryptedMedia encrypted_media(new KeyProvidingApp()); 1252 StartPipelineWithEncryptedMedia(&source, &encrypted_media); 1253 1254 source.EndOfStream(); 1255 ASSERT_EQ(PIPELINE_OK, pipeline_status_); 1256 1257 Play(); 1258 1259 ASSERT_TRUE(WaitUntilOnEnded()); 1260 source.Abort(); 1261 Stop(); 1262 } 1263 1264 TEST_F(PipelineIntegrationTest, 1265 EncryptedPlayback_NoEncryptedFrames_MP4_CENC_VideoOnly) { 1266 MockMediaSource source("bear-1280x720-v_frag-cenc_clear-all.mp4", kMP4Video, 1267 kAppendWholeFile); 1268 FakeEncryptedMedia encrypted_media(new NoResponseApp()); 1269 StartPipelineWithEncryptedMedia(&source, &encrypted_media); 1270 1271 source.EndOfStream(); 1272 ASSERT_EQ(PIPELINE_OK, pipeline_status_); 1273 1274 Play(); 1275 1276 ASSERT_TRUE(WaitUntilOnEnded()); 1277 source.Abort(); 1278 Stop(); 1279 } 1280 1281 TEST_F(PipelineIntegrationTest, 1282 EncryptedPlayback_NoEncryptedFrames_MP4_CENC_AudioOnly) { 1283 MockMediaSource source("bear-1280x720-a_frag-cenc_clear-all.mp4", kMP4Audio, 1284 kAppendWholeFile); 1285 FakeEncryptedMedia encrypted_media(new NoResponseApp()); 1286 StartPipelineWithEncryptedMedia(&source, &encrypted_media); 1287 1288 source.EndOfStream(); 1289 ASSERT_EQ(PIPELINE_OK, pipeline_status_); 1290 1291 Play(); 1292 1293 ASSERT_TRUE(WaitUntilOnEnded()); 1294 source.Abort(); 1295 Stop(); 1296 } 1297 1298 TEST_F(PipelineIntegrationTest, BasicPlayback_MediaSource_VideoOnly_MP4_AVC3) { 1299 MockMediaSource source("bear-1280x720-v_frag-avc3.mp4", kMP4VideoAVC3, 1300 kAppendWholeFile); 1301 StartPipelineWithMediaSource(&source); 1302 source.EndOfStream(); 1303 1304 EXPECT_EQ(1u, pipeline_->GetBufferedTimeRanges().size()); 1305 EXPECT_EQ(0, pipeline_->GetBufferedTimeRanges().start(0).InMilliseconds()); 1306 EXPECT_EQ(k1280IsoAVC3FileDurationMs, 1307 pipeline_->GetBufferedTimeRanges().end(0).InMilliseconds()); 1308 1309 Play(); 1310 1311 ASSERT_TRUE(WaitUntilOnEnded()); 1312 source.Abort(); 1313 Stop(); 1314 } 1315 1316 TEST_F(PipelineIntegrationTest, EncryptedPlayback_MP4_CENC_KeyRotation_Video) { 1317 MockMediaSource source("bear-1280x720-v_frag-cenc-key_rotation.mp4", 1318 kMP4Video, kAppendWholeFile); 1319 FakeEncryptedMedia encrypted_media(new RotatingKeyProvidingApp()); 1320 StartPipelineWithEncryptedMedia(&source, &encrypted_media); 1321 1322 source.EndOfStream(); 1323 ASSERT_EQ(PIPELINE_OK, pipeline_status_); 1324 1325 Play(); 1326 1327 ASSERT_TRUE(WaitUntilOnEnded()); 1328 source.Abort(); 1329 Stop(); 1330 } 1331 1332 TEST_F(PipelineIntegrationTest, EncryptedPlayback_MP4_CENC_KeyRotation_Audio) { 1333 MockMediaSource source("bear-1280x720-a_frag-cenc-key_rotation.mp4", 1334 kMP4Audio, kAppendWholeFile); 1335 FakeEncryptedMedia encrypted_media(new RotatingKeyProvidingApp()); 1336 StartPipelineWithEncryptedMedia(&source, &encrypted_media); 1337 1338 source.EndOfStream(); 1339 ASSERT_EQ(PIPELINE_OK, pipeline_status_); 1340 1341 Play(); 1342 1343 ASSERT_TRUE(WaitUntilOnEnded()); 1344 source.Abort(); 1345 Stop(); 1346 } 1347 #endif 1348 1349 // TODO(acolwell): Fix flakiness http://crbug.com/117921 1350 TEST_F(PipelineIntegrationTest, DISABLED_SeekWhilePaused) { 1351 ASSERT_TRUE(Start(GetTestDataFilePath("bear-320x240.webm"), PIPELINE_OK)); 1352 1353 base::TimeDelta duration(pipeline_->GetMediaDuration()); 1354 base::TimeDelta start_seek_time(duration / 4); 1355 base::TimeDelta seek_time(duration * 3 / 4); 1356 1357 Play(); 1358 ASSERT_TRUE(WaitUntilCurrentTimeIsAfter(start_seek_time)); 1359 Pause(); 1360 ASSERT_TRUE(Seek(seek_time)); 1361 EXPECT_EQ(pipeline_->GetMediaTime(), seek_time); 1362 Play(); 1363 ASSERT_TRUE(WaitUntilOnEnded()); 1364 1365 // Make sure seeking after reaching the end works as expected. 1366 Pause(); 1367 ASSERT_TRUE(Seek(seek_time)); 1368 EXPECT_EQ(pipeline_->GetMediaTime(), seek_time); 1369 Play(); 1370 ASSERT_TRUE(WaitUntilOnEnded()); 1371 } 1372 1373 // TODO(acolwell): Fix flakiness http://crbug.com/117921 1374 TEST_F(PipelineIntegrationTest, DISABLED_SeekWhilePlaying) { 1375 ASSERT_TRUE(Start(GetTestDataFilePath("bear-320x240.webm"), PIPELINE_OK)); 1376 1377 base::TimeDelta duration(pipeline_->GetMediaDuration()); 1378 base::TimeDelta start_seek_time(duration / 4); 1379 base::TimeDelta seek_time(duration * 3 / 4); 1380 1381 Play(); 1382 ASSERT_TRUE(WaitUntilCurrentTimeIsAfter(start_seek_time)); 1383 ASSERT_TRUE(Seek(seek_time)); 1384 EXPECT_GE(pipeline_->GetMediaTime(), seek_time); 1385 ASSERT_TRUE(WaitUntilOnEnded()); 1386 1387 // Make sure seeking after reaching the end works as expected. 1388 ASSERT_TRUE(Seek(seek_time)); 1389 EXPECT_GE(pipeline_->GetMediaTime(), seek_time); 1390 ASSERT_TRUE(WaitUntilOnEnded()); 1391 } 1392 1393 // Verify audio decoder & renderer can handle aborted demuxer reads. 1394 TEST_F(PipelineIntegrationTest, ChunkDemuxerAbortRead_AudioOnly) { 1395 ASSERT_TRUE(TestSeekDuringRead("bear-320x240-audio-only.webm", kAudioOnlyWebM, 1396 8192, 1397 base::TimeDelta::FromMilliseconds(464), 1398 base::TimeDelta::FromMilliseconds(617), 1399 0x10CA, 19730)); 1400 } 1401 1402 // Verify video decoder & renderer can handle aborted demuxer reads. 1403 TEST_F(PipelineIntegrationTest, ChunkDemuxerAbortRead_VideoOnly) { 1404 ASSERT_TRUE(TestSeekDuringRead("bear-320x240-video-only.webm", kVideoOnlyWebM, 1405 32768, 1406 base::TimeDelta::FromMilliseconds(167), 1407 base::TimeDelta::FromMilliseconds(1668), 1408 0x1C896, 65536)); 1409 } 1410 1411 // Verify that Opus audio in WebM containers can be played back. 1412 TEST_F(PipelineIntegrationTest, BasicPlayback_AudioOnly_Opus_WebM) { 1413 ASSERT_TRUE(Start(GetTestDataFilePath("bear-opus-end-trimming.webm"), 1414 PIPELINE_OK)); 1415 Play(); 1416 ASSERT_TRUE(WaitUntilOnEnded()); 1417 } 1418 1419 // Verify that VP9 video in WebM containers can be played back. 1420 TEST_F(PipelineIntegrationTest, BasicPlayback_VideoOnly_VP9_WebM) { 1421 ASSERT_TRUE(Start(GetTestDataFilePath("bear-vp9.webm"), 1422 PIPELINE_OK)); 1423 Play(); 1424 ASSERT_TRUE(WaitUntilOnEnded()); 1425 } 1426 1427 // Verify that VP9 video and Opus audio in the same WebM container can be played 1428 // back. 1429 TEST_F(PipelineIntegrationTest, BasicPlayback_VP9_Opus_WebM) { 1430 ASSERT_TRUE(Start(GetTestDataFilePath("bear-vp9-opus.webm"), 1431 PIPELINE_OK)); 1432 Play(); 1433 ASSERT_TRUE(WaitUntilOnEnded()); 1434 } 1435 1436 // Verify that VP8 video with alpha channel can be played back. 1437 TEST_F(PipelineIntegrationTest, BasicPlayback_VP8A_WebM) { 1438 ASSERT_TRUE(Start(GetTestDataFilePath("bear-vp8a.webm"), 1439 PIPELINE_OK)); 1440 Play(); 1441 ASSERT_TRUE(WaitUntilOnEnded()); 1442 EXPECT_EQ(last_video_frame_format_, VideoFrame::YV12A); 1443 } 1444 1445 // Verify that VP8A video with odd width/height can be played back. 1446 TEST_F(PipelineIntegrationTest, BasicPlayback_VP8A_Odd_WebM) { 1447 ASSERT_TRUE(Start(GetTestDataFilePath("bear-vp8a-odd-dimensions.webm"), 1448 PIPELINE_OK)); 1449 Play(); 1450 ASSERT_TRUE(WaitUntilOnEnded()); 1451 EXPECT_EQ(last_video_frame_format_, VideoFrame::YV12A); 1452 } 1453 1454 // Verify that VP8 video with inband text track can be played back. 1455 TEST_F(PipelineIntegrationTest, 1456 BasicPlayback_VP8_WebVTT_WebM) { 1457 ASSERT_TRUE(Start(GetTestDataFilePath("bear-vp8-webvtt.webm"), 1458 PIPELINE_OK)); 1459 Play(); 1460 ASSERT_TRUE(WaitUntilOnEnded()); 1461 } 1462 1463 // Verify that VP9 video with 4:4:4 subsampling can be played back. 1464 TEST_F(PipelineIntegrationTest, P444_VP9_WebM) { 1465 ASSERT_TRUE(Start(GetTestDataFilePath("bear-320x240-P444.webm"), 1466 PIPELINE_OK)); 1467 Play(); 1468 ASSERT_TRUE(WaitUntilOnEnded()); 1469 EXPECT_EQ(last_video_frame_format_, VideoFrame::YV24); 1470 } 1471 1472 // Verify that videos with an odd frame size playback successfully. 1473 TEST_F(PipelineIntegrationTest, BasicPlayback_OddVideoSize) { 1474 ASSERT_TRUE(Start(GetTestDataFilePath("butterfly-853x480.webm"), 1475 PIPELINE_OK)); 1476 Play(); 1477 ASSERT_TRUE(WaitUntilOnEnded()); 1478 } 1479 1480 } // namespace media 1481