| 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) { | 103 MessageLoop::current()->PostTask( |
| 99 chunk_demuxer_ = demuxer; | 104 FROM_HERE, base::Bind(&MockMediaSource::DemuxerOpenedTask, |
| 105 base::Unretained(this))); |
| 106 } |
| 100 | 107 |
| 108 void DemuxerOpenedTask() { |
| 101 size_t semicolon = mimetype_.find(";"); | 109 size_t semicolon = mimetype_.find(";"); |
| 102 std::string type = mimetype_.substr(0, semicolon); | 110 std::string type = mimetype_.substr(0, semicolon); |
| 103 size_t quote1 = mimetype_.find("\""); | 111 size_t quote1 = mimetype_.find("\""); |
| 104 size_t quote2 = mimetype_.find("\"", quote1 + 1); | 112 size_t quote2 = mimetype_.find("\"", quote1 + 1); |
| 105 std::string codecStr = mimetype_.substr(quote1 + 1, quote2 - quote1 - 1); | 113 std::string codecStr = mimetype_.substr(quote1 + 1, quote2 - quote1 - 1); |
| 106 std::vector<std::string> codecs; | 114 std::vector<std::string> codecs; |
| 107 Tokenize(codecStr, ",", &codecs); | 115 Tokenize(codecStr, ",", &codecs); |
| 108 | 116 |
| 109 CHECK_EQ(chunk_demuxer_->AddId(kSourceId, type, codecs), ChunkDemuxer::kOk); | 117 CHECK_EQ(chunk_demuxer_->AddId(kSourceId, type, codecs), ChunkDemuxer::kOk); |
| 110 AppendData(initial_append_size_); | 118 AppendData(initial_append_size_); |
| 111 } | 119 } |
| 112 | 120 |
| 113 virtual void DemuxerClosed() { | 121 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()); | 122 DCHECK(init_data.get()); |
| 120 DCHECK_GT(init_data_size, 0); | 123 DCHECK_GT(init_data_size, 0); |
| 121 DCHECK(decryptor_client_); | 124 DCHECK(decryptor_client_); |
| 122 decryptor_client_->NeedKey("", "", init_data.Pass(), init_data_size); | 125 decryptor_client_->NeedKey("", "", init_data.Pass(), init_data_size); |
| 123 } | 126 } |
| 124 | 127 |
| 125 private: | 128 private: |
| 126 std::string url_; | 129 std::string url_; |
| 127 scoped_refptr<DecoderBuffer> file_data_; | 130 scoped_refptr<DecoderBuffer> file_data_; |
| 128 int current_position_; | 131 int current_position_; |
| (...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 197 }; | 200 }; |
| 198 | 201 |
| 199 class PipelineIntegrationTest | 202 class PipelineIntegrationTest |
| 200 : public testing::Test, | 203 : public testing::Test, |
| 201 public PipelineIntegrationTestBase { | 204 public PipelineIntegrationTestBase { |
| 202 public: | 205 public: |
| 203 void StartPipelineWithMediaSource(MockMediaSource* source) { | 206 void StartPipelineWithMediaSource(MockMediaSource* source) { |
| 204 EXPECT_CALL(*this, OnBufferingState(Pipeline::kHaveMetadata)); | 207 EXPECT_CALL(*this, OnBufferingState(Pipeline::kHaveMetadata)); |
| 205 EXPECT_CALL(*this, OnBufferingState(Pipeline::kPrerollCompleted)); | 208 EXPECT_CALL(*this, OnBufferingState(Pipeline::kPrerollCompleted)); |
| 206 pipeline_->Start( | 209 pipeline_->Start( |
| 207 CreateFilterCollection(source, NULL), | 210 CreateFilterCollection(source->demuxer(), NULL), |
| 208 base::Bind(&PipelineIntegrationTest::OnEnded, base::Unretained(this)), | 211 base::Bind(&PipelineIntegrationTest::OnEnded, base::Unretained(this)), |
| 209 base::Bind(&PipelineIntegrationTest::OnError, base::Unretained(this)), | 212 base::Bind(&PipelineIntegrationTest::OnError, base::Unretained(this)), |
| 210 QuitOnStatusCB(PIPELINE_OK), | 213 QuitOnStatusCB(PIPELINE_OK), |
| 211 base::Bind(&PipelineIntegrationTest::OnBufferingState, | 214 base::Bind(&PipelineIntegrationTest::OnBufferingState, |
| 212 base::Unretained(this))); | 215 base::Unretained(this))); |
| 213 | 216 |
| 214 message_loop_.Run(); | 217 message_loop_.Run(); |
| 215 } | 218 } |
| 216 | 219 |
| 217 void StartPipelineWithEncryptedMedia( | 220 void StartPipelineWithEncryptedMedia( |
| 218 MockMediaSource* source, | 221 MockMediaSource* source, |
| 219 FakeDecryptorClient* encrypted_media) { | 222 FakeDecryptorClient* encrypted_media) { |
| 220 EXPECT_CALL(*this, OnBufferingState(Pipeline::kHaveMetadata)); | 223 EXPECT_CALL(*this, OnBufferingState(Pipeline::kHaveMetadata)); |
| 221 EXPECT_CALL(*this, OnBufferingState(Pipeline::kPrerollCompleted)); | 224 EXPECT_CALL(*this, OnBufferingState(Pipeline::kPrerollCompleted)); |
| 222 pipeline_->Start( | 225 pipeline_->Start( |
| 223 CreateFilterCollection(source, encrypted_media->decryptor()), | 226 CreateFilterCollection(source->demuxer(), encrypted_media->decryptor()), |
| 224 base::Bind(&PipelineIntegrationTest::OnEnded, base::Unretained(this)), | 227 base::Bind(&PipelineIntegrationTest::OnEnded, base::Unretained(this)), |
| 225 base::Bind(&PipelineIntegrationTest::OnError, base::Unretained(this)), | 228 base::Bind(&PipelineIntegrationTest::OnError, base::Unretained(this)), |
| 226 QuitOnStatusCB(PIPELINE_OK), | 229 QuitOnStatusCB(PIPELINE_OK), |
| 227 base::Bind(&PipelineIntegrationTest::OnBufferingState, | 230 base::Bind(&PipelineIntegrationTest::OnBufferingState, |
| 228 base::Unretained(this))); | 231 base::Unretained(this))); |
| 229 | 232 |
| 230 source->set_decryptor_client(encrypted_media); | 233 source->set_decryptor_client(encrypted_media); |
| 231 | 234 |
| 232 message_loop_.Run(); | 235 message_loop_.Run(); |
| 233 } | 236 } |
| (...skipping 196 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 430 // Verify video decoder & renderer can handle aborted demuxer reads. | 433 // Verify video decoder & renderer can handle aborted demuxer reads. |
| 431 TEST_F(PipelineIntegrationTest, ChunkDemuxerAbortRead_VideoOnly) { | 434 TEST_F(PipelineIntegrationTest, ChunkDemuxerAbortRead_VideoOnly) { |
| 432 ASSERT_TRUE(TestSeekDuringRead("bear-320x240-video-only.webm", kVideoOnlyWebM, | 435 ASSERT_TRUE(TestSeekDuringRead("bear-320x240-video-only.webm", kVideoOnlyWebM, |
| 433 32768, | 436 32768, |
| 434 base::TimeDelta::FromMilliseconds(200), | 437 base::TimeDelta::FromMilliseconds(200), |
| 435 base::TimeDelta::FromMilliseconds(1668), | 438 base::TimeDelta::FromMilliseconds(1668), |
| 436 0x1C896, 65536)); | 439 0x1C896, 65536)); |
| 437 } | 440 } |
| 438 | 441 |
| 439 } // namespace media | 442 } // namespace media |
| OLD | NEW |