| 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/string_util.h" | 8 #include "base/string_util.h" |
| 9 #include "media/base/decoder_buffer.h" | 9 #include "media/base/decoder_buffer.h" |
| 10 #include "media/base/decryptor_client.h" | 10 #include "media/base/decryptor_client.h" |
| 11 #include "media/base/test_data_util.h" | 11 #include "media/base/test_data_util.h" |
| 12 #include "media/crypto/aes_decryptor.h" | 12 #include "media/crypto/aes_decryptor.h" |
| 13 #include "media/filters/chunk_demuxer_client.h" | |
| 14 | 13 |
| 15 namespace media { | 14 namespace media { |
| 16 | 15 |
| 17 static const char kSourceId[] = "SourceId"; | 16 static const char kSourceId[] = "SourceId"; |
| 18 static const char kClearKeySystem[] = "org.w3.clearkey"; | 17 static const char kClearKeySystem[] = "org.w3.clearkey"; |
| 19 static const uint8 kInitData[] = { 0x69, 0x6e, 0x69, 0x74 }; | 18 static const uint8 kInitData[] = { 0x69, 0x6e, 0x69, 0x74 }; |
| 20 | 19 |
| 21 static const char kWebM[] = "video/webm; codecs=\"vp8,vorbis\""; | 20 static const char kWebM[] = "video/webm; codecs=\"vp8,vorbis\""; |
| 22 static const char kAudioOnlyWebM[] = "video/webm; codecs=\"vorbis\""; | 21 static const char kAudioOnlyWebM[] = "video/webm; codecs=\"vorbis\""; |
| 23 static const char kVideoOnlyWebM[] = "video/webm; codecs=\"vp8\""; | 22 static const char kVideoOnlyWebM[] = "video/webm; codecs=\"vp8\""; |
| 24 static const char kMP4[] = "video/mp4; codecs=\"avc1.4D4041,mp4a.40.2\""; | 23 static const char kMP4[] = "video/mp4; codecs=\"avc1.4D4041,mp4a.40.2\""; |
| 25 | 24 |
| 26 // Key used to encrypt video track in test file "bear-320x240-encrypted.webm". | 25 // Key used to encrypt video track in test file "bear-320x240-encrypted.webm". |
| 27 static const uint8 kSecretKey[] = { | 26 static const uint8 kSecretKey[] = { |
| 28 0xeb, 0xdd, 0x62, 0xf1, 0x68, 0x14, 0xd2, 0x7b, | 27 0xeb, 0xdd, 0x62, 0xf1, 0x68, 0x14, 0xd2, 0x7b, |
| 29 0x68, 0xef, 0x12, 0x2a, 0xfc, 0xe4, 0xae, 0x3c | 28 0x68, 0xef, 0x12, 0x2a, 0xfc, 0xe4, 0xae, 0x3c |
| 30 }; | 29 }; |
| 31 | 30 |
| 32 static const int kAppendWholeFile = -1; | 31 static const int kAppendWholeFile = -1; |
| 33 | 32 |
| 34 // Helper class that emulates calls made on the ChunkDemuxer by the | 33 // Helper class that emulates calls made on the ChunkDemuxer by the |
| 35 // Media Source API. | 34 // Media Source API. |
| 36 class MockMediaSource : public ChunkDemuxerClient { | 35 class MockMediaSource { |
| 37 public: | 36 public: |
| 38 MockMediaSource(const std::string& filename, const std::string& mimetype, | 37 MockMediaSource(const std::string& filename, const std::string& mimetype, |
| 39 int initial_append_size) | 38 int initial_append_size) |
| 40 : url_(GetTestDataURL(filename)), | 39 : url_(GetTestDataURL(filename)), |
| 41 current_position_(0), | 40 current_position_(0), |
| 42 initial_append_size_(initial_append_size), | 41 initial_append_size_(initial_append_size), |
| 43 mimetype_(mimetype) { | 42 mimetype_(mimetype) { |
| 43 chunk_demuxer_ = new ChunkDemuxer( |
| 44 base::Bind(&MockMediaSource::DemuxerOpened, base::Unretained(this)), |
| 45 base::Bind(&MockMediaSource::DemuxerNeedKey, base::Unretained(this))); |
| 46 |
| 44 file_data_ = ReadTestDataFile(filename); | 47 file_data_ = ReadTestDataFile(filename); |
| 45 | 48 |
| 46 if (initial_append_size_ == kAppendWholeFile) | 49 if (initial_append_size_ == kAppendWholeFile) |
| 47 initial_append_size_ = file_data_->GetDataSize(); | 50 initial_append_size_ = file_data_->GetDataSize(); |
| 48 | 51 |
| 49 DCHECK_GT(initial_append_size_, 0); | 52 DCHECK_GT(initial_append_size_, 0); |
| 50 DCHECK_LE(initial_append_size_, file_data_->GetDataSize()); | 53 DCHECK_LE(initial_append_size_, file_data_->GetDataSize()); |
| 51 } | 54 } |
| 52 | 55 |
| 53 virtual ~MockMediaSource() {} | 56 virtual ~MockMediaSource() {} |
| 54 | 57 |
| 58 const scoped_refptr<ChunkDemuxer>& demuxer() const { return chunk_demuxer_; } |
| 55 void set_decryptor_client(DecryptorClient* decryptor_client) { | 59 void set_decryptor_client(DecryptorClient* decryptor_client) { |
| 56 decryptor_client_ = decryptor_client; | 60 decryptor_client_ = decryptor_client; |
| 57 } | 61 } |
| 58 | 62 |
| 59 void Seek(int new_position, int seek_append_size) { | 63 void Seek(int new_position, int seek_append_size) { |
| 60 chunk_demuxer_->StartWaitingForSeek(); | 64 chunk_demuxer_->StartWaitingForSeek(); |
| 61 | 65 |
| 62 chunk_demuxer_->Abort(kSourceId); | 66 chunk_demuxer_->Abort(kSourceId); |
| 63 | 67 |
| 64 DCHECK_GE(new_position, 0); | 68 DCHECK_GE(new_position, 0); |
| (...skipping 20 matching lines...) Expand all Loading... |
| 85 } | 89 } |
| 86 | 90 |
| 87 void EndOfStream() { | 91 void EndOfStream() { |
| 88 chunk_demuxer_->EndOfStream(PIPELINE_OK); | 92 chunk_demuxer_->EndOfStream(PIPELINE_OK); |
| 89 } | 93 } |
| 90 | 94 |
| 91 void Abort() { | 95 void Abort() { |
| 92 if (!chunk_demuxer_.get()) | 96 if (!chunk_demuxer_.get()) |
| 93 return; | 97 return; |
| 94 chunk_demuxer_->Shutdown(); | 98 chunk_demuxer_->Shutdown(); |
| 99 chunk_demuxer_ = NULL; |
| 95 } | 100 } |
| 96 | 101 |
| 97 // ChunkDemuxerClient methods. | 102 void DemuxerOpened() { |
| 98 virtual void DemuxerOpened(ChunkDemuxer* demuxer) { | |
| 99 chunk_demuxer_ = demuxer; | |
| 100 | |
| 101 size_t semicolon = mimetype_.find(";"); | 103 size_t semicolon = mimetype_.find(";"); |
| 102 std::string type = mimetype_.substr(0, semicolon); | 104 std::string type = mimetype_.substr(0, semicolon); |
| 103 size_t quote1 = mimetype_.find("\""); | 105 size_t quote1 = mimetype_.find("\""); |
| 104 size_t quote2 = mimetype_.find("\"", quote1 + 1); | 106 size_t quote2 = mimetype_.find("\"", quote1 + 1); |
| 105 std::string codecStr = mimetype_.substr(quote1 + 1, quote2 - quote1 - 1); | 107 std::string codecStr = mimetype_.substr(quote1 + 1, quote2 - quote1 - 1); |
| 106 std::vector<std::string> codecs; | 108 std::vector<std::string> codecs; |
| 107 Tokenize(codecStr, ",", &codecs); | 109 Tokenize(codecStr, ",", &codecs); |
| 108 | 110 |
| 109 CHECK_EQ(chunk_demuxer_->AddId(kSourceId, type, codecs), ChunkDemuxer::kOk); | 111 CHECK_EQ(chunk_demuxer_->AddId(kSourceId, type, codecs), ChunkDemuxer::kOk); |
| 110 AppendData(initial_append_size_); | 112 AppendData(initial_append_size_); |
| 111 } | 113 } |
| 112 | 114 |
| 113 virtual void DemuxerClosed() { | 115 void DemuxerNeedKey(scoped_array<uint8> init_data, int init_data_size) { |
| 114 chunk_demuxer_ = NULL; | |
| 115 } | |
| 116 | |
| 117 virtual void DemuxerNeedKey(scoped_array<uint8> init_data, | |
| 118 int init_data_size) { | |
| 119 DCHECK(init_data.get()); | 116 DCHECK(init_data.get()); |
| 120 DCHECK_GT(init_data_size, 0); | 117 DCHECK_GT(init_data_size, 0); |
| 121 DCHECK(decryptor_client_); | 118 DCHECK(decryptor_client_); |
| 122 decryptor_client_->NeedKey("", "", init_data.Pass(), init_data_size); | 119 decryptor_client_->NeedKey("", "", init_data.Pass(), init_data_size); |
| 123 } | 120 } |
| 124 | 121 |
| 125 private: | 122 private: |
| 126 std::string url_; | 123 std::string url_; |
| 127 scoped_refptr<DecoderBuffer> file_data_; | 124 scoped_refptr<DecoderBuffer> file_data_; |
| 128 int current_position_; | 125 int current_position_; |
| (...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 197 }; | 194 }; |
| 198 | 195 |
| 199 class PipelineIntegrationTest | 196 class PipelineIntegrationTest |
| 200 : public testing::Test, | 197 : public testing::Test, |
| 201 public PipelineIntegrationTestBase { | 198 public PipelineIntegrationTestBase { |
| 202 public: | 199 public: |
| 203 void StartPipelineWithMediaSource(MockMediaSource* source) { | 200 void StartPipelineWithMediaSource(MockMediaSource* source) { |
| 204 EXPECT_CALL(*this, OnBufferingState(Pipeline::kHaveMetadata)); | 201 EXPECT_CALL(*this, OnBufferingState(Pipeline::kHaveMetadata)); |
| 205 EXPECT_CALL(*this, OnBufferingState(Pipeline::kPrerollCompleted)); | 202 EXPECT_CALL(*this, OnBufferingState(Pipeline::kPrerollCompleted)); |
| 206 pipeline_->Start( | 203 pipeline_->Start( |
| 207 CreateFilterCollection(source, NULL), | 204 CreateFilterCollection(source->demuxer(), NULL), |
| 208 base::Bind(&PipelineIntegrationTest::OnEnded, base::Unretained(this)), | 205 base::Bind(&PipelineIntegrationTest::OnEnded, base::Unretained(this)), |
| 209 base::Bind(&PipelineIntegrationTest::OnError, base::Unretained(this)), | 206 base::Bind(&PipelineIntegrationTest::OnError, base::Unretained(this)), |
| 210 QuitOnStatusCB(PIPELINE_OK), | 207 QuitOnStatusCB(PIPELINE_OK), |
| 211 base::Bind(&PipelineIntegrationTest::OnBufferingState, | 208 base::Bind(&PipelineIntegrationTest::OnBufferingState, |
| 212 base::Unretained(this))); | 209 base::Unretained(this))); |
| 213 | 210 |
| 214 message_loop_.Run(); | 211 message_loop_.Run(); |
| 215 } | 212 } |
| 216 | 213 |
| 217 void StartPipelineWithEncryptedMedia( | 214 void StartPipelineWithEncryptedMedia( |
| 218 MockMediaSource* source, | 215 MockMediaSource* source, |
| 219 FakeDecryptorClient* encrypted_media) { | 216 FakeDecryptorClient* encrypted_media) { |
| 220 EXPECT_CALL(*this, OnBufferingState(Pipeline::kHaveMetadata)); | 217 EXPECT_CALL(*this, OnBufferingState(Pipeline::kHaveMetadata)); |
| 221 EXPECT_CALL(*this, OnBufferingState(Pipeline::kPrerollCompleted)); | 218 EXPECT_CALL(*this, OnBufferingState(Pipeline::kPrerollCompleted)); |
| 222 pipeline_->Start( | 219 pipeline_->Start( |
| 223 CreateFilterCollection(source, encrypted_media->decryptor()), | 220 CreateFilterCollection(source->demuxer(), encrypted_media->decryptor()), |
| 224 base::Bind(&PipelineIntegrationTest::OnEnded, base::Unretained(this)), | 221 base::Bind(&PipelineIntegrationTest::OnEnded, base::Unretained(this)), |
| 225 base::Bind(&PipelineIntegrationTest::OnError, base::Unretained(this)), | 222 base::Bind(&PipelineIntegrationTest::OnError, base::Unretained(this)), |
| 226 QuitOnStatusCB(PIPELINE_OK), | 223 QuitOnStatusCB(PIPELINE_OK), |
| 227 base::Bind(&PipelineIntegrationTest::OnBufferingState, | 224 base::Bind(&PipelineIntegrationTest::OnBufferingState, |
| 228 base::Unretained(this))); | 225 base::Unretained(this))); |
| 229 | 226 |
| 230 source->set_decryptor_client(encrypted_media); | 227 source->set_decryptor_client(encrypted_media); |
| 231 | 228 |
| 232 message_loop_.Run(); | 229 message_loop_.Run(); |
| 233 } | 230 } |
| (...skipping 196 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 430 // Verify video decoder & renderer can handle aborted demuxer reads. | 427 // Verify video decoder & renderer can handle aborted demuxer reads. |
| 431 TEST_F(PipelineIntegrationTest, ChunkDemuxerAbortRead_VideoOnly) { | 428 TEST_F(PipelineIntegrationTest, ChunkDemuxerAbortRead_VideoOnly) { |
| 432 ASSERT_TRUE(TestSeekDuringRead("bear-320x240-video-only.webm", kVideoOnlyWebM, | 429 ASSERT_TRUE(TestSeekDuringRead("bear-320x240-video-only.webm", kVideoOnlyWebM, |
| 433 32768, | 430 32768, |
| 434 base::TimeDelta::FromMilliseconds(200), | 431 base::TimeDelta::FromMilliseconds(200), |
| 435 base::TimeDelta::FromMilliseconds(1668), | 432 base::TimeDelta::FromMilliseconds(1668), |
| 436 0x1C896, 65536)); | 433 0x1C896, 65536)); |
| 437 } | 434 } |
| 438 | 435 |
| 439 } // namespace media | 436 } // namespace media |
| OLD | NEW |