Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "media/filters/pipeline_integration_test_base.h" | 5 #include "media/filters/pipeline_integration_test_base.h" |
| 6 | 6 |
| 7 #include "base/bind.h" | 7 #include "base/bind.h" |
| 8 #include "base/memory/scoped_ptr.h" | |
| 8 #include "base/string_util.h" | 9 #include "base/string_util.h" |
| 9 #include "build/build_config.h" | 10 #include "build/build_config.h" |
| 10 #include "media/base/decoder_buffer.h" | 11 #include "media/base/decoder_buffer.h" |
| 11 #include "media/base/test_data_util.h" | 12 #include "media/base/test_data_util.h" |
| 12 #include "media/crypto/aes_decryptor.h" | 13 #include "media/crypto/aes_decryptor.h" |
| 13 | 14 |
| 14 using testing::AtMost; | 15 using testing::AtMost; |
| 15 | 16 |
| 16 namespace media { | 17 namespace media { |
| 17 | 18 |
| (...skipping 18 matching lines...) Expand all Loading... | |
| 36 static const int kAppendTimeSec = 1; | 37 static const int kAppendTimeSec = 1; |
| 37 static const int kAppendTimeMs = kAppendTimeSec * 1000; | 38 static const int kAppendTimeMs = kAppendTimeSec * 1000; |
| 38 static const int k320WebMFileDurationMs = 2737; | 39 static const int k320WebMFileDurationMs = 2737; |
| 39 static const int k640WebMFileDurationMs = 2763; | 40 static const int k640WebMFileDurationMs = 2763; |
| 40 static const int k1280IsoFileDurationMs = 2736; | 41 static const int k1280IsoFileDurationMs = 2736; |
| 41 | 42 |
| 42 // Note: Tests using this class only exercise the DecryptingDemuxerStream path. | 43 // Note: Tests using this class only exercise the DecryptingDemuxerStream path. |
| 43 // They do not exercise the Decrypting{Audio|Video}Decoder path. | 44 // They do not exercise the Decrypting{Audio|Video}Decoder path. |
| 44 class FakeEncryptedMedia { | 45 class FakeEncryptedMedia { |
| 45 public: | 46 public: |
| 46 FakeEncryptedMedia() | 47 // Defines the behavior of the "app" that responds to EME events. |
| 48 class AppBase { | |
|
xhwang
2013/01/09 21:18:21
Looks like AppBase isn't doing a lot of work and i
ddorwin
2013/01/10 04:44:46
Done.
I left KeyError since that's likely to be co
| |
| 49 public: | |
| 50 virtual ~AppBase() {} | |
| 51 | |
| 52 virtual void KeyAdded(const std::string& key_system, | |
| 53 const std::string& session_id) { | |
| 54 EXPECT_EQ(kClearKeySystem, key_system); | |
| 55 EXPECT_FALSE(session_id.empty()); | |
| 56 FAIL() << "Unexpected KeyAdded"; | |
| 57 } | |
| 58 | |
| 59 virtual void KeyMessage(const std::string& key_system, | |
| 60 const std::string& session_id, | |
| 61 const std::string& message, | |
| 62 const std::string& default_url) { | |
| 63 EXPECT_EQ(kClearKeySystem, key_system); | |
| 64 EXPECT_FALSE(session_id.empty()); | |
| 65 EXPECT_FALSE(message.empty()); | |
| 66 FAIL() << "Unexpected KeyMessage"; | |
| 67 } | |
| 68 | |
| 69 virtual void NeedKey(const std::string& key_system, | |
| 70 const std::string& session_id, | |
| 71 const std::string& type, | |
| 72 scoped_array<uint8> init_data, int init_data_length, | |
| 73 AesDecryptor* decryptor) { | |
| 74 FAIL() << "Unexpected NeedKey"; | |
| 75 } | |
| 76 | |
| 77 virtual void KeyError(const std::string& key_system, | |
| 78 const std::string& session_id, | |
| 79 AesDecryptor::KeyError error_code, | |
| 80 int system_code) { | |
| 81 FAIL() << "Unexpected Key Error"; | |
| 82 } | |
| 83 }; | |
| 84 | |
| 85 FakeEncryptedMedia(AppBase* app) | |
| 47 : decryptor_(base::Bind(&FakeEncryptedMedia::KeyAdded, | 86 : decryptor_(base::Bind(&FakeEncryptedMedia::KeyAdded, |
| 48 base::Unretained(this)), | 87 base::Unretained(this)), |
| 49 base::Bind(&FakeEncryptedMedia::KeyError, | 88 base::Bind(&FakeEncryptedMedia::KeyError, |
| 50 base::Unretained(this)), | 89 base::Unretained(this)), |
| 51 base::Bind(&FakeEncryptedMedia::KeyMessage, | 90 base::Bind(&FakeEncryptedMedia::KeyMessage, |
| 52 base::Unretained(this)), | 91 base::Unretained(this)), |
| 53 base::Bind(&FakeEncryptedMedia::NeedKey, | 92 base::Bind(&FakeEncryptedMedia::NeedKey, |
| 54 base::Unretained(this))) { | 93 base::Unretained(this))), |
| 94 app_(app) { | |
| 55 } | 95 } |
| 56 | 96 |
| 57 AesDecryptor* decryptor() { | 97 AesDecryptor* decryptor() { |
| 58 return &decryptor_; | 98 return &decryptor_; |
| 59 } | 99 } |
| 60 | 100 |
| 61 // Callbacks for firing key events. | 101 // Callbacks for firing key events. Delegate to |app_|. |
| 62 void KeyAdded(const std::string& key_system, const std::string& session_id) { | 102 void KeyAdded(const std::string& key_system, const std::string& session_id) { |
| 63 EXPECT_EQ(kClearKeySystem, key_system); | 103 app_->KeyAdded(key_system, session_id); |
| 64 EXPECT_FALSE(session_id.empty()); | |
| 65 } | 104 } |
| 66 | 105 |
| 67 void KeyError(const std::string& key_system, | 106 void KeyError(const std::string& key_system, |
| 68 const std::string& session_id, | 107 const std::string& session_id, |
| 69 AesDecryptor::KeyError error_code, | 108 AesDecryptor::KeyError error_code, |
| 70 int system_code) { | 109 int system_code) { |
| 71 FAIL() << "Unexpected Key Error"; | 110 app_->KeyError(key_system, session_id, error_code, system_code); |
| 72 } | 111 } |
| 73 | 112 |
| 74 void KeyMessage(const std::string& key_system, | 113 void KeyMessage(const std::string& key_system, |
| 75 const std::string& session_id, | 114 const std::string& session_id, |
| 76 const std::string& message, | 115 const std::string& message, |
| 77 const std::string& default_url) { | 116 const std::string& default_url) { |
| 117 app_->KeyMessage(key_system, session_id, message, default_url); | |
| 118 } | |
| 119 | |
| 120 void NeedKey(const std::string& key_system, | |
| 121 const std::string& session_id, | |
| 122 const std::string& type, | |
| 123 scoped_array<uint8> init_data, int init_data_length) { | |
| 124 app_->NeedKey(key_system, session_id, type, | |
| 125 init_data.Pass(), init_data_length, &decryptor_); | |
| 126 } | |
| 127 | |
| 128 private: | |
| 129 AesDecryptor decryptor_; | |
| 130 scoped_ptr<AppBase> app_; | |
| 131 }; | |
| 132 | |
| 133 // Provides |kSecretKey| in response to needkey. | |
| 134 class KeyProvidingApp : public FakeEncryptedMedia::AppBase { | |
| 135 public: | |
| 136 void KeyAdded(const std::string& key_system, | |
| 137 const std::string& session_id) OVERRIDE { | |
| 138 EXPECT_EQ(kClearKeySystem, key_system); | |
| 139 EXPECT_FALSE(session_id.empty()); | |
| 140 } | |
| 141 | |
| 142 void KeyMessage(const std::string& key_system, | |
| 143 const std::string& session_id, | |
| 144 const std::string& message, | |
| 145 const std::string& default_url) OVERRIDE { | |
| 78 EXPECT_EQ(kClearKeySystem, key_system); | 146 EXPECT_EQ(kClearKeySystem, key_system); |
| 79 EXPECT_FALSE(session_id.empty()); | 147 EXPECT_FALSE(session_id.empty()); |
| 80 EXPECT_FALSE(message.empty()); | 148 EXPECT_FALSE(message.empty()); |
| 81 | 149 |
| 82 current_key_system_ = key_system; | 150 current_key_system_ = key_system; |
| 83 current_session_id_ = session_id; | 151 current_session_id_ = session_id; |
| 84 } | 152 } |
| 85 | 153 |
| 86 void NeedKey(const std::string& key_system, | 154 void NeedKey(const std::string& key_system, |
| 87 const std::string& session_id, | 155 const std::string& session_id, |
| 88 const std::string& type, | 156 const std::string& type, |
| 89 scoped_array<uint8> init_data, int init_data_length) { | 157 scoped_array<uint8> init_data, int init_data_length, |
| 158 AesDecryptor* decryptor) OVERRIDE { | |
| 90 current_key_system_ = key_system; | 159 current_key_system_ = key_system; |
| 91 current_session_id_ = session_id; | 160 current_session_id_ = session_id; |
| 92 | 161 |
| 93 // When NeedKey is called from the demuxer, the |key_system| will be empty. | 162 // When NeedKey is called from the demuxer, the |key_system| will be empty. |
| 94 // In this case, we need to call GenerateKeyRequest() to initialize a | 163 // In this case, we need to call GenerateKeyRequest() to initialize a |
| 95 // session (which will call KeyMessage). | 164 // session (which will call KeyMessage). |
| 96 if (current_key_system_.empty()) { | 165 if (current_key_system_.empty()) { |
| 97 EXPECT_TRUE(current_session_id_.empty()); | 166 EXPECT_TRUE(current_session_id_.empty()); |
| 98 EXPECT_TRUE(decryptor_.GenerateKeyRequest( | 167 EXPECT_TRUE(decryptor->GenerateKeyRequest( |
| 99 kClearKeySystem, type, kInitData, arraysize(kInitData))); | 168 kClearKeySystem, type, kInitData, arraysize(kInitData))); |
| 100 } | 169 } |
| 101 | 170 |
| 102 EXPECT_FALSE(current_key_system_.empty()); | 171 EXPECT_FALSE(current_key_system_.empty()); |
| 103 EXPECT_FALSE(current_session_id_.empty()); | 172 EXPECT_FALSE(current_session_id_.empty()); |
| 104 decryptor_.AddKey(current_key_system_, kSecretKey, arraysize(kSecretKey), | 173 decryptor->AddKey(current_key_system_, kSecretKey, arraysize(kSecretKey), |
| 105 init_data.get(), init_data_length, current_session_id_); | 174 init_data.get(), init_data_length, current_session_id_); |
| 106 } | 175 } |
| 107 | 176 |
| 108 private: | |
| 109 AesDecryptor decryptor_; | |
| 110 std::string current_key_system_; | 177 std::string current_key_system_; |
| 111 std::string current_session_id_; | 178 std::string current_session_id_; |
| 112 }; | 179 }; |
| 113 | 180 |
| 181 // Ignores needkey and does not perform a license request | |
| 182 class NoResponseApp : public FakeEncryptedMedia::AppBase { | |
| 183 public: | |
| 184 void NeedKey(const std::string& key_system, | |
| 185 const std::string& session_id, | |
| 186 const std::string& type, | |
| 187 scoped_array<uint8> init_data, int init_data_length, | |
| 188 AesDecryptor* decryptor) OVERRIDE { | |
| 189 } | |
| 190 }; | |
| 191 | |
| 114 // Helper class that emulates calls made on the ChunkDemuxer by the | 192 // Helper class that emulates calls made on the ChunkDemuxer by the |
| 115 // Media Source API. | 193 // Media Source API. |
| 116 class MockMediaSource { | 194 class MockMediaSource { |
| 117 public: | 195 public: |
| 118 MockMediaSource(const std::string& filename, const std::string& mimetype, | 196 MockMediaSource(const std::string& filename, const std::string& mimetype, |
| 119 int initial_append_size) | 197 int initial_append_size) |
| 120 : file_path_(GetTestDataFilePath(filename)), | 198 : file_path_(GetTestDataFilePath(filename)), |
| 121 current_position_(0), | 199 current_position_(0), |
| 122 initial_append_size_(initial_append_size), | 200 initial_append_size_(initial_append_size), |
| 123 mimetype_(mimetype) { | 201 mimetype_(mimetype) { |
| (...skipping 228 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 352 Play(); | 430 Play(); |
| 353 | 431 |
| 354 EXPECT_TRUE(WaitUntilOnEnded()); | 432 EXPECT_TRUE(WaitUntilOnEnded()); |
| 355 source.Abort(); | 433 source.Abort(); |
| 356 Stop(); | 434 Stop(); |
| 357 } | 435 } |
| 358 | 436 |
| 359 TEST_F(PipelineIntegrationTest, MediaSource_ConfigChange_Encrypted_WebM) { | 437 TEST_F(PipelineIntegrationTest, MediaSource_ConfigChange_Encrypted_WebM) { |
| 360 MockMediaSource source("bear-320x240-16x9-aspect-av-enc_av.webm", kWebM, | 438 MockMediaSource source("bear-320x240-16x9-aspect-av-enc_av.webm", kWebM, |
| 361 kAppendWholeFile); | 439 kAppendWholeFile); |
| 362 FakeEncryptedMedia encrypted_media; | 440 FakeEncryptedMedia encrypted_media(new KeyProvidingApp()); |
| 363 StartPipelineWithEncryptedMedia(&source, &encrypted_media); | 441 StartPipelineWithEncryptedMedia(&source, &encrypted_media); |
| 364 | 442 |
| 365 scoped_refptr<DecoderBuffer> second_file = | 443 scoped_refptr<DecoderBuffer> second_file = |
| 366 ReadTestDataFile("bear-640x360-av-enc_av.webm"); | 444 ReadTestDataFile("bear-640x360-av-enc_av.webm"); |
| 367 | 445 |
| 368 source.AppendAtTime(base::TimeDelta::FromSeconds(kAppendTimeSec), | 446 source.AppendAtTime(base::TimeDelta::FromSeconds(kAppendTimeSec), |
| 369 second_file->GetData(), second_file->GetDataSize()); | 447 second_file->GetData(), second_file->GetDataSize()); |
| 370 | 448 |
| 371 source.EndOfStream(); | 449 source.EndOfStream(); |
| 372 | 450 |
| 373 EXPECT_EQ(1u, pipeline_->GetBufferedTimeRanges().size()); | 451 EXPECT_EQ(1u, pipeline_->GetBufferedTimeRanges().size()); |
| 374 EXPECT_EQ(0, pipeline_->GetBufferedTimeRanges().start(0).InMilliseconds()); | 452 EXPECT_EQ(0, pipeline_->GetBufferedTimeRanges().start(0).InMilliseconds()); |
| 375 EXPECT_EQ(kAppendTimeMs + k640WebMFileDurationMs, | 453 EXPECT_EQ(kAppendTimeMs + k640WebMFileDurationMs, |
| 376 pipeline_->GetBufferedTimeRanges().end(0).InMilliseconds()); | 454 pipeline_->GetBufferedTimeRanges().end(0).InMilliseconds()); |
| 377 | 455 |
| 378 Play(); | 456 Play(); |
| 379 | 457 |
| 380 EXPECT_TRUE(WaitUntilOnEnded()); | 458 EXPECT_TRUE(WaitUntilOnEnded()); |
| 381 source.Abort(); | 459 source.Abort(); |
| 382 Stop(); | 460 Stop(); |
| 383 } | 461 } |
| 384 | 462 |
| 385 // Config changes from encrypted to clear are not currently supported. | 463 // Config changes from encrypted to clear are not currently supported. |
| 386 TEST_F(PipelineIntegrationTest, | 464 TEST_F(PipelineIntegrationTest, |
| 387 MediaSource_ConfigChange_ClearThenEncrypted_WebM) { | 465 MediaSource_ConfigChange_ClearThenEncrypted_WebM) { |
| 388 MockMediaSource source("bear-320x240-16x9-aspect.webm", kWebM, | 466 MockMediaSource source("bear-320x240-16x9-aspect.webm", kWebM, |
| 389 kAppendWholeFile); | 467 kAppendWholeFile); |
| 390 FakeEncryptedMedia encrypted_media; | 468 FakeEncryptedMedia encrypted_media(new KeyProvidingApp()); |
| 391 StartPipelineWithEncryptedMedia(&source, &encrypted_media); | 469 StartPipelineWithEncryptedMedia(&source, &encrypted_media); |
| 392 | 470 |
| 393 scoped_refptr<DecoderBuffer> second_file = | 471 scoped_refptr<DecoderBuffer> second_file = |
| 394 ReadTestDataFile("bear-640x360-av-enc_av.webm"); | 472 ReadTestDataFile("bear-640x360-av-enc_av.webm"); |
| 395 | 473 |
| 396 source.AppendAtTime(base::TimeDelta::FromSeconds(kAppendTimeSec), | 474 source.AppendAtTime(base::TimeDelta::FromSeconds(kAppendTimeSec), |
| 397 second_file->GetData(), second_file->GetDataSize()); | 475 second_file->GetData(), second_file->GetDataSize()); |
| 398 | 476 |
| 399 source.EndOfStream(); | 477 source.EndOfStream(); |
| 400 | 478 |
| (...skipping 10 matching lines...) Expand all Loading... | |
| 411 | 489 |
| 412 EXPECT_EQ(PIPELINE_ERROR_DECODE, WaitUntilEndedOrError()); | 490 EXPECT_EQ(PIPELINE_ERROR_DECODE, WaitUntilEndedOrError()); |
| 413 source.Abort(); | 491 source.Abort(); |
| 414 } | 492 } |
| 415 | 493 |
| 416 // Config changes from clear to encrypted are not currently supported. | 494 // Config changes from clear to encrypted are not currently supported. |
| 417 TEST_F(PipelineIntegrationTest, | 495 TEST_F(PipelineIntegrationTest, |
| 418 MediaSource_ConfigChange_EncryptedThenClear_WebM) { | 496 MediaSource_ConfigChange_EncryptedThenClear_WebM) { |
| 419 MockMediaSource source("bear-320x240-16x9-aspect-av-enc_av.webm", kWebM, | 497 MockMediaSource source("bear-320x240-16x9-aspect-av-enc_av.webm", kWebM, |
| 420 kAppendWholeFile); | 498 kAppendWholeFile); |
| 421 FakeEncryptedMedia encrypted_media; | 499 FakeEncryptedMedia encrypted_media(new KeyProvidingApp()); |
| 422 StartPipelineWithEncryptedMedia(&source, &encrypted_media); | 500 StartPipelineWithEncryptedMedia(&source, &encrypted_media); |
| 423 | 501 |
| 424 scoped_refptr<DecoderBuffer> second_file = | 502 scoped_refptr<DecoderBuffer> second_file = |
| 425 ReadTestDataFile("bear-640x360.webm"); | 503 ReadTestDataFile("bear-640x360.webm"); |
| 426 | 504 |
| 427 source.AppendAtTime(base::TimeDelta::FromSeconds(kAppendTimeSec), | 505 source.AppendAtTime(base::TimeDelta::FromSeconds(kAppendTimeSec), |
| 428 second_file->GetData(), second_file->GetDataSize()); | 506 second_file->GetData(), second_file->GetDataSize()); |
| 429 | 507 |
| 430 source.EndOfStream(); | 508 source.EndOfStream(); |
| 431 | 509 |
| (...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 469 | 547 |
| 470 TEST_F(PipelineIntegrationTest, BasicPlayback_16x9AspectRatio) { | 548 TEST_F(PipelineIntegrationTest, BasicPlayback_16x9AspectRatio) { |
| 471 ASSERT_TRUE(Start(GetTestDataFilePath("bear-320x240-16x9-aspect.webm"), | 549 ASSERT_TRUE(Start(GetTestDataFilePath("bear-320x240-16x9-aspect.webm"), |
| 472 PIPELINE_OK)); | 550 PIPELINE_OK)); |
| 473 Play(); | 551 Play(); |
| 474 ASSERT_TRUE(WaitUntilOnEnded()); | 552 ASSERT_TRUE(WaitUntilOnEnded()); |
| 475 } | 553 } |
| 476 | 554 |
| 477 TEST_F(PipelineIntegrationTest, EncryptedPlayback) { | 555 TEST_F(PipelineIntegrationTest, EncryptedPlayback) { |
| 478 MockMediaSource source("bear-320x240-encrypted.webm", kWebM, 219816); | 556 MockMediaSource source("bear-320x240-encrypted.webm", kWebM, 219816); |
| 479 FakeEncryptedMedia encrypted_media; | 557 FakeEncryptedMedia encrypted_media(new KeyProvidingApp()); |
| 480 StartPipelineWithEncryptedMedia(&source, &encrypted_media); | 558 StartPipelineWithEncryptedMedia(&source, &encrypted_media); |
| 481 | 559 |
| 482 source.EndOfStream(); | 560 source.EndOfStream(); |
| 561 ASSERT_EQ(PIPELINE_OK, pipeline_status_); | |
| 562 | |
| 563 Play(); | |
| 564 | |
| 565 ASSERT_TRUE(WaitUntilOnEnded()); | |
| 566 source.Abort(); | |
| 567 Stop(); | |
| 568 } | |
| 569 | |
| 570 TEST_F(PipelineIntegrationTest, EncryptedPlayback_NoEncryptedFrames) { | |
| 571 MockMediaSource source("bear-320x240-av-enc_av_un-all.webm", | |
| 572 kWebM, kAppendWholeFile); | |
| 573 FakeEncryptedMedia encrypted_media(new NoResponseApp()); | |
| 574 StartPipelineWithEncryptedMedia(&source, &encrypted_media); | |
| 575 | |
| 576 source.EndOfStream(); | |
| 483 ASSERT_EQ(PIPELINE_OK, pipeline_status_); | 577 ASSERT_EQ(PIPELINE_OK, pipeline_status_); |
| 484 | 578 |
| 485 Play(); | 579 Play(); |
| 486 | 580 |
| 487 ASSERT_TRUE(WaitUntilOnEnded()); | 581 ASSERT_TRUE(WaitUntilOnEnded()); |
| 488 source.Abort(); | 582 source.Abort(); |
| 489 Stop(); | 583 Stop(); |
| 490 } | 584 } |
| 491 | 585 |
| 492 // TODO(acolwell): Fix flakiness http://crbug.com/117921 | 586 // TODO(acolwell): Fix flakiness http://crbug.com/117921 |
| (...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 545 // Verify video decoder & renderer can handle aborted demuxer reads. | 639 // Verify video decoder & renderer can handle aborted demuxer reads. |
| 546 TEST_F(PipelineIntegrationTest, ChunkDemuxerAbortRead_VideoOnly) { | 640 TEST_F(PipelineIntegrationTest, ChunkDemuxerAbortRead_VideoOnly) { |
| 547 ASSERT_TRUE(TestSeekDuringRead("bear-320x240-video-only.webm", kVideoOnlyWebM, | 641 ASSERT_TRUE(TestSeekDuringRead("bear-320x240-video-only.webm", kVideoOnlyWebM, |
| 548 32768, | 642 32768, |
| 549 base::TimeDelta::FromMilliseconds(200), | 643 base::TimeDelta::FromMilliseconds(200), |
| 550 base::TimeDelta::FromMilliseconds(1668), | 644 base::TimeDelta::FromMilliseconds(1668), |
| 551 0x1C896, 65536)); | 645 0x1C896, 65536)); |
| 552 } | 646 } |
| 553 | 647 |
| 554 } // namespace media | 648 } // namespace media |
| OLD | NEW |