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