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 "media/base/decoder_buffer.h" | 8 #include "media/base/decoder_buffer.h" |
9 #include "media/base/mock_filters.h" | |
9 #include "media/base/test_data_util.h" | 10 #include "media/base/test_data_util.h" |
11 #include "media/crypto/aes_decryptor.h" | |
12 #include "media/crypto/decryptor_client.h" | |
10 #include "media/filters/chunk_demuxer_client.h" | 13 #include "media/filters/chunk_demuxer_client.h" |
14 #include "testing/gtest/include/gtest/gtest.h" | |
15 | |
16 using ::testing::_; | |
11 | 17 |
12 namespace media { | 18 namespace media { |
13 | 19 |
14 // Key ID of the video track in test file "bear-320x240-encrypted.webm". | 20 static const char kSourceId[] = "SourceId"; |
15 static const unsigned char kKeyId[] = | 21 static const char kClearKeySystem[] = "org.w3.clearkey"; |
16 "\x11\xa5\x18\x37\xc4\x73\x84\x03\xe5\xe6\x57\xed\x8e\x06\xd9\x7c"; | 22 static const uint8 kInitData[] = { 0x69, 0x6e, 0x69, 0x74 }; |
17 | |
18 static const char* kSourceId = "SourceId"; | |
19 | 23 |
20 // Helper class that emulates calls made on the ChunkDemuxer by the | 24 // Helper class that emulates calls made on the ChunkDemuxer by the |
21 // Media Source API. | 25 // Media Source API. |
22 class MockMediaSource : public ChunkDemuxerClient { | 26 class MockMediaSource : public ChunkDemuxerClient { |
23 public: | 27 public: |
24 MockMediaSource(const std::string& filename, int initial_append_size) | 28 MockMediaSource(const std::string& filename, int initial_append_size) |
25 : url_(GetTestDataURL(filename)), | 29 : url_(GetTestDataURL(filename)), |
26 current_position_(0), | 30 current_position_(0), |
27 initial_append_size_(initial_append_size) { | 31 initial_append_size_(initial_append_size) { |
28 file_data_ = ReadTestDataFile(filename); | 32 file_data_ = ReadTestDataFile(filename); |
29 | 33 |
30 DCHECK_GT(initial_append_size_, 0); | 34 DCHECK_GT(initial_append_size_, 0); |
31 DCHECK_LE(initial_append_size_, file_data_->GetDataSize()); | 35 DCHECK_LE(initial_append_size_, file_data_->GetDataSize()); |
32 } | 36 } |
33 | 37 |
34 virtual ~MockMediaSource() {} | 38 virtual ~MockMediaSource() {} |
35 | 39 |
36 void set_decryptor(AesDecryptor* decryptor) { | 40 void set_decryptor_client(DecryptorClient* decryptor_client) { |
37 decryptor_ = decryptor; | 41 decryptor_client_ = decryptor_client; |
38 } | |
39 AesDecryptor* decryptor() const { | |
40 return decryptor_; | |
41 } | 42 } |
42 | 43 |
43 const std::string& url() const { return url_; } | 44 const std::string& url() const { return url_; } |
44 | 45 |
45 void Seek(int new_position, int seek_append_size) { | 46 void Seek(int new_position, int seek_append_size) { |
46 chunk_demuxer_->StartWaitingForSeek(); | 47 chunk_demuxer_->StartWaitingForSeek(); |
47 | 48 |
48 chunk_demuxer_->Abort(kSourceId); | 49 chunk_demuxer_->Abort(kSourceId); |
49 | 50 |
50 DCHECK_GE(new_position, 0); | 51 DCHECK_GE(new_position, 0); |
(...skipping 30 matching lines...) Expand all Loading... | |
81 codecs[0] = "vp8"; | 82 codecs[0] = "vp8"; |
82 codecs[1] = "vorbis"; | 83 codecs[1] = "vorbis"; |
83 chunk_demuxer_->AddId(kSourceId, "video/webm", codecs); | 84 chunk_demuxer_->AddId(kSourceId, "video/webm", codecs); |
84 AppendData(initial_append_size_); | 85 AppendData(initial_append_size_); |
85 } | 86 } |
86 | 87 |
87 virtual void DemuxerClosed() { | 88 virtual void DemuxerClosed() { |
88 chunk_demuxer_ = NULL; | 89 chunk_demuxer_ = NULL; |
89 } | 90 } |
90 | 91 |
91 virtual void KeyNeeded(scoped_array<uint8> init_data, int init_data_size) { | 92 virtual void DemuxerNeedKey(scoped_array<uint8> init_data, |
93 int init_data_size) { | |
92 DCHECK(init_data.get()); | 94 DCHECK(init_data.get()); |
93 DCHECK_EQ(init_data_size, 16); | 95 DCHECK_EQ(init_data_size, 16); |
94 DCHECK(decryptor()); | 96 DCHECK(decryptor_client_); |
95 // In test file bear-320x240-encrypted.webm, the decryption key is equal to | 97 decryptor_client_->NeedKey("", "", init_data.Pass(), init_data_size); |
96 // |init_data|. | |
97 decryptor()->AddKey(init_data.get(), init_data_size, | |
98 init_data.get(), init_data_size); | |
99 } | 98 } |
100 | 99 |
101 private: | 100 private: |
102 std::string url_; | 101 std::string url_; |
103 scoped_refptr<DecoderBuffer> file_data_; | 102 scoped_refptr<DecoderBuffer> file_data_; |
104 int current_position_; | 103 int current_position_; |
105 int initial_append_size_; | 104 int initial_append_size_; |
106 scoped_refptr<ChunkDemuxer> chunk_demuxer_; | 105 scoped_refptr<ChunkDemuxer> chunk_demuxer_; |
107 AesDecryptor* decryptor_; | 106 DecryptorClient* decryptor_client_; |
107 }; | |
108 | |
109 class MockEncryptedMedia : public MockDecryptorClient { | |
scherkus (not reviewing)
2012/06/13 23:35:08
does this need to extend MockDecryptorClient?
if
xhwang
2012/06/15 01:41:04
Done.
| |
110 public: | |
111 MockEncryptedMedia() : decryptor_(this) {} | |
112 | |
113 AesDecryptor* decryptor() { | |
114 return &decryptor_; | |
115 } | |
116 | |
117 // DecryptorClient implementation. | |
118 virtual void KeyMessage(const std::string& key_system, | |
119 const std::string& session_id, | |
120 scoped_array<uint8> message, | |
121 int message_length, | |
122 const std::string& default_url) { | |
123 EXPECT_TRUE(key_system == kClearKeySystem); | |
124 EXPECT_TRUE(!session_id.empty()); | |
125 EXPECT_TRUE(message.get()); | |
126 EXPECT_GT(message_length, 0); | |
scherkus (not reviewing)
2012/06/13 23:35:08
do we not care what the message is?
xhwang
2012/06/15 01:41:04
Currently the AesDecryptor just returns the init_d
| |
127 key_system_string_ = key_system; | |
128 session_id_string_ = session_id; | |
129 } | |
130 | |
131 virtual void NeedKey(const std::string& key_system, | |
132 const std::string& session_id, | |
133 scoped_array<uint8> init_data, | |
134 int init_data_length) { | |
135 key_system_string_ = key_system; | |
136 session_id_string_ = session_id; | |
137 if (key_system_string_.empty()) { | |
scherkus (not reviewing)
2012/06/13 23:35:08
do we fire need key w/ empty key system today?
xhwang
2012/06/15 01:41:04
Yes. When NeedKey is fired from the demuxer. Added
| |
138 DCHECK(session_id_string_.empty()); | |
139 decryptor_.GenerateKeyRequest(kClearKeySystem, | |
140 kInitData, arraysize(kInitData)); | |
141 } | |
142 | |
143 EXPECT_FALSE(key_system_string_.empty()); | |
scherkus (not reviewing)
2012/06/13 23:35:08
based on if statement above it looks like key_syst
ddorwin
2012/06/14 21:04:04
This assumes KeyMessage gets called (and that AesD
xhwang
2012/06/15 01:41:04
Done.
| |
144 EXPECT_FALSE(session_id_string_.empty()); | |
145 // In test file bear-320x240-encrypted.webm, the decryption key is equal to | |
146 // |init_data|. | |
147 decryptor_.AddKey(key_system_string_, init_data.get(), init_data_length, | |
148 init_data.get(), init_data_length, session_id_string_); | |
149 } | |
150 | |
151 private: | |
152 AesDecryptor decryptor_; | |
153 std::string key_system_string_; | |
154 std::string session_id_string_; | |
108 }; | 155 }; |
109 | 156 |
110 class PipelineIntegrationTest | 157 class PipelineIntegrationTest |
111 : public testing::Test, | 158 : public testing::Test, |
112 public PipelineIntegrationTestBase { | 159 public PipelineIntegrationTestBase { |
113 public: | 160 public: |
114 void StartPipelineWithMediaSource(MockMediaSource& source) { | 161 void StartPipelineWithMediaSource(MockMediaSource* source) { |
115 pipeline_->Start( | 162 pipeline_->Start( |
116 CreateFilterCollection(&source), | 163 CreateFilterCollection(source), |
117 base::Bind(&PipelineIntegrationTest::OnEnded, base::Unretained(this)), | 164 base::Bind(&PipelineIntegrationTest::OnEnded, base::Unretained(this)), |
118 base::Bind(&PipelineIntegrationTest::OnError, base::Unretained(this)), | 165 base::Bind(&PipelineIntegrationTest::OnError, base::Unretained(this)), |
119 NetworkEventCB(), QuitOnStatusCB(PIPELINE_OK)); | 166 NetworkEventCB(), QuitOnStatusCB(PIPELINE_OK)); |
120 | 167 |
121 ASSERT_TRUE(decoder_.get()); | 168 ASSERT_TRUE(decoder_.get()); |
122 source.set_decryptor(decryptor_.get()); | |
123 | 169 |
124 message_loop_.Run(); | 170 message_loop_.Run(); |
125 } | 171 } |
172 | |
173 void StartPipelineWithEncryptedMedia(MockMediaSource* source, | |
174 MockEncryptedMedia* encrypted_media) { | |
175 pipeline_->Start( | |
176 CreateFilterCollection(source), | |
177 base::Bind(&PipelineIntegrationTest::OnEnded, base::Unretained(this)), | |
178 base::Bind(&PipelineIntegrationTest::OnError, base::Unretained(this)), | |
179 NetworkEventCB(), QuitOnStatusCB(PIPELINE_OK)); | |
180 | |
181 ASSERT_TRUE(decoder_.get()); | |
182 decoder_->set_decryptor(encrypted_media->decryptor()); | |
183 source->set_decryptor_client(encrypted_media); | |
184 | |
185 EXPECT_CALL(*encrypted_media, KeyAdded(kClearKeySystem, _)); | |
186 | |
187 message_loop_.Run(); | |
188 } | |
126 | 189 |
127 // Verifies that seeking works properly for ChunkDemuxer when the | 190 // Verifies that seeking works properly for ChunkDemuxer when the |
128 // seek happens while there is a pending read on the ChunkDemuxer | 191 // seek happens while there is a pending read on the ChunkDemuxer |
129 // and no data is available. | 192 // and no data is available. |
130 bool TestSeekDuringRead(const std::string& filename, | 193 bool TestSeekDuringRead(const std::string& filename, |
131 int initial_append_size, | 194 int initial_append_size, |
132 base::TimeDelta start_seek_time, | 195 base::TimeDelta start_seek_time, |
133 base::TimeDelta seek_time, | 196 base::TimeDelta seek_time, |
134 int seek_file_position, | 197 int seek_file_position, |
135 int seek_append_size) { | 198 int seek_append_size) { |
136 MockMediaSource source(filename, initial_append_size); | 199 MockMediaSource source(filename, initial_append_size); |
137 StartPipelineWithMediaSource(source); | 200 StartPipelineWithMediaSource(&source); |
138 | 201 |
139 if (pipeline_status_ != PIPELINE_OK) | 202 if (pipeline_status_ != PIPELINE_OK) |
140 return false; | 203 return false; |
141 | 204 |
142 Play(); | 205 Play(); |
143 if (!WaitUntilCurrentTimeIsAfter(start_seek_time)) | 206 if (!WaitUntilCurrentTimeIsAfter(start_seek_time)) |
144 return false; | 207 return false; |
145 | 208 |
146 source.Seek(seek_file_position, seek_append_size); | 209 source.Seek(seek_file_position, seek_append_size); |
147 if (!Seek(seek_time)) | 210 if (!Seek(seek_time)) |
(...skipping 22 matching lines...) Expand all Loading... | |
170 Play(); | 233 Play(); |
171 | 234 |
172 ASSERT_TRUE(WaitUntilOnEnded()); | 235 ASSERT_TRUE(WaitUntilOnEnded()); |
173 | 236 |
174 EXPECT_EQ(GetVideoHash(), "f0be120a90a811506777c99a2cdf7cc1"); | 237 EXPECT_EQ(GetVideoHash(), "f0be120a90a811506777c99a2cdf7cc1"); |
175 EXPECT_EQ(GetAudioHash(), "6138555be3389e6aba4c8e6f70195d50"); | 238 EXPECT_EQ(GetAudioHash(), "6138555be3389e6aba4c8e6f70195d50"); |
176 } | 239 } |
177 | 240 |
178 TEST_F(PipelineIntegrationTest, EncryptedPlayback) { | 241 TEST_F(PipelineIntegrationTest, EncryptedPlayback) { |
179 MockMediaSource source("bear-320x240-encrypted.webm", 219726); | 242 MockMediaSource source("bear-320x240-encrypted.webm", 219726); |
180 StartPipelineWithMediaSource(source); | 243 MockEncryptedMedia encrypted_media; |
244 StartPipelineWithEncryptedMedia(&source, &encrypted_media); | |
181 | 245 |
182 source.EndOfStream(); | 246 source.EndOfStream(); |
183 ASSERT_EQ(PIPELINE_OK, pipeline_status_); | 247 ASSERT_EQ(PIPELINE_OK, pipeline_status_); |
184 | 248 |
185 Play(); | 249 Play(); |
186 | 250 |
187 ASSERT_TRUE(WaitUntilOnEnded()); | 251 ASSERT_TRUE(WaitUntilOnEnded()); |
188 source.Abort(); | 252 source.Abort(); |
189 Stop(); | 253 Stop(); |
190 } | 254 } |
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
243 | 307 |
244 // Verify video decoder & renderer can handle aborted demuxer reads. | 308 // Verify video decoder & renderer can handle aborted demuxer reads. |
245 TEST_F(PipelineIntegrationTest, ChunkDemuxerAbortRead_VideoOnly) { | 309 TEST_F(PipelineIntegrationTest, ChunkDemuxerAbortRead_VideoOnly) { |
246 ASSERT_TRUE(TestSeekDuringRead("bear-320x240-video-only.webm", 32768, | 310 ASSERT_TRUE(TestSeekDuringRead("bear-320x240-video-only.webm", 32768, |
247 base::TimeDelta::FromMilliseconds(200), | 311 base::TimeDelta::FromMilliseconds(200), |
248 base::TimeDelta::FromMilliseconds(1668), | 312 base::TimeDelta::FromMilliseconds(1668), |
249 0x1C896, 65536)); | 313 0x1C896, 65536)); |
250 } | 314 } |
251 | 315 |
252 } // namespace media | 316 } // namespace media |
OLD | NEW |