Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(48)

Side by Side Diff: media/filters/decrypting_demuxer_stream_unittest.cc

Issue 11342031: Add DecryptingDemuxerStream. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: ddorwin's comments mostly resolved Created 8 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « media/filters/decrypting_demuxer_stream.cc ('k') | media/filters/decrypting_video_decoder.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
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 <string>
6 #include <vector>
7
8 #include "base/bind.h"
9 #include "base/callback_helpers.h"
10 #include "base/message_loop.h"
11 #include "media/base/decoder_buffer.h"
12 #include "media/base/decrypt_config.h"
13 #include "media/base/gmock_callback_support.h"
14 #include "media/base/mock_callback.h"
15 #include "media/base/mock_filters.h"
16 #include "media/filters/decrypting_demuxer_stream.h"
17 #include "media/filters/ffmpeg_decoder_unittest.h"
18 #include "testing/gmock/include/gmock/gmock.h"
19
20 using ::testing::_;
21 using ::testing::IsNull;
22 using ::testing::Return;
23 using ::testing::ReturnRef;
24 using ::testing::SaveArg;
25 using ::testing::StrictMock;
26
27 namespace media {
28
29 static const int kFakeBufferSize = 16;
30 static const VideoFrame::Format kVideoFormat = VideoFrame::YV12;
31 static const gfx::Size kCodedSize(320, 240);
32 static const gfx::Rect kVisibleRect(320, 240);
33 static const gfx::Size kNaturalSize(320, 240);
34 static const uint8 kFakeKeyId[] = { 0x4b, 0x65, 0x79, 0x20, 0x49, 0x44 };
35 static const uint8 kFakeIv[DecryptConfig::kDecryptionKeySize] = { 0 };
36
37 // Create a fake non-empty encrypted buffer.
38 static scoped_refptr<DecoderBuffer> CreateFakeEncryptedBuffer() {
39 scoped_refptr<DecoderBuffer> buffer(new DecoderBuffer(kFakeBufferSize));
40 buffer->SetDecryptConfig(scoped_ptr<DecryptConfig>(new DecryptConfig(
41 std::string(reinterpret_cast<const char*>(kFakeKeyId),
42 arraysize(kFakeKeyId)),
43 std::string(reinterpret_cast<const char*>(kFakeIv), arraysize(kFakeIv)),
44 0,
45 std::vector<SubsampleEntry>())));
46 return buffer;
47 }
48
49 // Use anonymous namespace here to prevent the actions to be defined multiple
50 // times across multiple test files. Sadly we can't use static for them.
51 namespace {
52
53 ACTION_P(ReturnBuffer, buffer) {
54 arg0.Run(buffer ? DemuxerStream::kOk : DemuxerStream::kAborted, buffer);
55 }
56
57 ACTION_P(RunCallbackIfNotNull, param) {
58 if (!arg0.is_null())
59 arg0.Run(param);
60 }
61
62 ACTION_P2(ResetAndRunCallback, callback, param) {
63 base::ResetAndReturn(callback).Run(param);
64 }
65
66 MATCHER(IsEndOfStream, "end of stream") {
67 return (arg->IsEndOfStream());
68 }
69
70 } // namespace
71
72 class DecryptingDemuxerStreamTest : public testing::Test {
73 public:
74 DecryptingDemuxerStreamTest()
75 : demuxer_stream_(new DecryptingDemuxerStream(
76 base::Bind(&Identity<scoped_refptr<base::MessageLoopProxy> >,
77 message_loop_.message_loop_proxy()),
78 base::Bind(
79 &DecryptingDemuxerStreamTest::RequestDecryptorNotification,
80 base::Unretained(this)))),
81 decryptor_(new StrictMock<MockDecryptor>()),
82 input_audio_stream_(new StrictMock<MockDemuxerStream>()),
83 input_video_stream_(new StrictMock<MockDemuxerStream>()),
84 encrypted_buffer_(CreateFakeEncryptedBuffer()),
85 decrypted_buffer_(new DecoderBuffer(kFakeBufferSize)) {
86 }
87
88 void InitializeAudioAndExpectStatus(const AudioDecoderConfig& config,
89 PipelineStatus status) {
90 EXPECT_CALL(*input_audio_stream_, audio_decoder_config())
91 .WillRepeatedly(ReturnRef(config));
92 EXPECT_CALL(*input_audio_stream_, type())
93 .WillRepeatedly(Return(DemuxerStream::AUDIO));
94
95 demuxer_stream_->Initialize(input_audio_stream_,
96 NewExpectedStatusCB(status));
97 message_loop_.RunUntilIdle();
98 }
99
100 void InitializeVideoAndExpectStatus(const VideoDecoderConfig& config,
101 PipelineStatus status) {
102 EXPECT_CALL(*input_video_stream_, video_decoder_config())
103 .WillRepeatedly(ReturnRef(config));
104 EXPECT_CALL(*input_video_stream_, type())
105 .WillRepeatedly(Return(DemuxerStream::VIDEO));
106
107 demuxer_stream_->Initialize(input_video_stream_,
108 NewExpectedStatusCB(status));
109 message_loop_.RunUntilIdle();
110 }
111
112 // The following functions are used to test stream-type-neutral logics in
ddorwin 2012/11/13 22:52:33 s/logics/logic/
xhwang 2012/11/14 18:01:52 Done.
113 // DecryptingDemuxerStream. Therefore, we don't specify audio or video in the
114 // function names. But for testing purpose, they all use an audio input
115 // demuxer stream.
116
117 void Initialize() {
118 EXPECT_CALL(*this, RequestDecryptorNotification(_))
119 .WillOnce(RunCallbackIfNotNull(decryptor_.get()));
120 EXPECT_CALL(*decryptor_, RegisterKeyAddedCB(Decryptor::kAudio, _))
121 .WillOnce(SaveArg<1>(&key_added_cb_));
122
123 AudioDecoderConfig input_config(
124 kCodecVorbis, 16, CHANNEL_LAYOUT_STEREO, 44100, NULL, 0, true);
125 InitializeAudioAndExpectStatus(input_config, PIPELINE_OK);
126
127 const AudioDecoderConfig& output_config =
128 demuxer_stream_->audio_decoder_config();
129 EXPECT_EQ(DemuxerStream::AUDIO, demuxer_stream_->type());
130 EXPECT_FALSE(output_config.is_encrypted());
131 EXPECT_EQ(16, output_config.bits_per_channel());
132 EXPECT_EQ(CHANNEL_LAYOUT_STEREO, output_config.channel_layout());
133 EXPECT_EQ(44100, output_config.samples_per_second());
134 }
135
136 void ReadAndExpectBufferReadyWith(
137 DemuxerStream::Status status,
138 const scoped_refptr<DecoderBuffer>& decrypted_buffer) {
139 if (status != DemuxerStream::kOk)
140 EXPECT_CALL(*this, BufferReady(status, IsNull()));
141 else if (decrypted_buffer->IsEndOfStream())
142 EXPECT_CALL(*this, BufferReady(status, IsEndOfStream()));
143 else
144 EXPECT_CALL(*this, BufferReady(status, decrypted_buffer));
145
146 demuxer_stream_->Read(base::Bind(&DecryptingDemuxerStreamTest::BufferReady,
147 base::Unretained(this)));
148 message_loop_.RunUntilIdle();
149 }
150
151 // Sets up expectations and actions to put DecryptingDemuxerStream in an
152 // active normal reading state.
153 void EnterNormalReadingState() {
154 EXPECT_CALL(*input_audio_stream_, Read(_))
155 .WillOnce(ReturnBuffer(encrypted_buffer_));
156 EXPECT_CALL(*decryptor_, Decrypt(_, _, _))
157 .WillOnce(RunCallback<2>(Decryptor::kSuccess, decrypted_buffer_));
158
159 ReadAndExpectBufferReadyWith(DemuxerStream::kOk, decrypted_buffer_);
160 }
161
162 // Make the read callback pending by saving and not firing it.
163 void EnterPendingReadState() {
164 EXPECT_TRUE(pending_demuxer_read_cb_.is_null());
165 EXPECT_CALL(*input_audio_stream_, Read(_))
166 .WillOnce(SaveArg<0>(&pending_demuxer_read_cb_));
167 demuxer_stream_->Read(base::Bind(&DecryptingDemuxerStreamTest::BufferReady,
168 base::Unretained(this)));
169 message_loop_.RunUntilIdle();
170 // Make sure the Read() triggers a Read() on the input demuxer stream.
171 EXPECT_FALSE(pending_demuxer_read_cb_.is_null());
172 }
173
174 // Make the decrypt callback pending by saving and not firing it.
175 void EnterPendingDecryptState() {
176 EXPECT_TRUE(pending_decrypt_cb_.is_null());
177 EXPECT_CALL(*input_audio_stream_, Read(_))
178 .WillRepeatedly(ReturnBuffer(encrypted_buffer_));
179 EXPECT_CALL(*decryptor_, Decrypt(_, encrypted_buffer_, _))
180 .WillOnce(SaveArg<2>(&pending_decrypt_cb_));
181
182 demuxer_stream_->Read(base::Bind(&DecryptingDemuxerStreamTest::BufferReady,
183 base::Unretained(this)));
184 message_loop_.RunUntilIdle();
185 // Make sure Read() triggers a Decrypt() on the decryptor.
186 EXPECT_FALSE(pending_decrypt_cb_.is_null());
187 }
188
189 void EnterWaitingForKeyState() {
190 EXPECT_CALL(*input_audio_stream_, Read(_))
191 .WillRepeatedly(ReturnBuffer(encrypted_buffer_));
192 EXPECT_CALL(*decryptor_, Decrypt(_, encrypted_buffer_, _))
193 .WillRepeatedly(RunCallback<2>(Decryptor::kNoKey,
194 scoped_refptr<DecoderBuffer>()));
195 demuxer_stream_->Read(base::Bind(&DecryptingDemuxerStreamTest::BufferReady,
196 base::Unretained(this)));
197 message_loop_.RunUntilIdle();
198 }
199
200 void AbortPendingDecryptCB() {
201 if (!pending_decrypt_cb_.is_null()) {
202 base::ResetAndReturn(&pending_decrypt_cb_).Run(Decryptor::kSuccess, NULL);
203 }
204 }
205
206 void Reset() {
207 EXPECT_CALL(*decryptor_, CancelDecrypt(Decryptor::kAudio))
208 .WillRepeatedly(InvokeWithoutArgs(
209 this, &DecryptingDemuxerStreamTest::AbortPendingDecryptCB));
210
211 demuxer_stream_->Reset(NewExpectedClosure());
212 message_loop_.RunUntilIdle();
213 }
214
215 MOCK_METHOD1(RequestDecryptorNotification,
216 void(const DecryptingDemuxerStream::DecryptorNotificationCB&));
217
218 MOCK_METHOD2(BufferReady, void(DemuxerStream::Status,
219 const scoped_refptr<DecoderBuffer>&));
220
221 MessageLoop message_loop_;
222 scoped_refptr<DecryptingDemuxerStream> demuxer_stream_;
223 scoped_ptr<StrictMock<MockDecryptor> > decryptor_;
224 scoped_refptr<StrictMock<MockDemuxerStream> > input_audio_stream_;
225 scoped_refptr<StrictMock<MockDemuxerStream> > input_video_stream_;
226
227 DemuxerStream::ReadCB pending_demuxer_read_cb_;
228 Decryptor::KeyAddedCB key_added_cb_;
229 Decryptor::DecryptCB pending_decrypt_cb_;
230
231 // Constant buffers to be returned by the input demuxer streams and the
232 // |decryptor_|.
233 scoped_refptr<DecoderBuffer> encrypted_buffer_;
234 scoped_refptr<DecoderBuffer> decrypted_buffer_;
235
236 private:
237 DISALLOW_COPY_AND_ASSIGN(DecryptingDemuxerStreamTest);
238 };
239
240 TEST_F(DecryptingDemuxerStreamTest, Initialize_NormalAudio) {
241 Initialize();
242 }
243
244 // Ensure that DecryptingDemuxerStream only accepts encrypted audio.
245 TEST_F(DecryptingDemuxerStreamTest, Initialize_UnencryptedAudioConfig) {
246 AudioDecoderConfig config(kCodecVorbis, 16, CHANNEL_LAYOUT_STEREO, 44100,
247 NULL, 0, false);
248
249 InitializeAudioAndExpectStatus(config, DEMUXER_ERROR_NO_SUPPORTED_STREAMS);
250 }
251
252 // Ensure DecryptingDemuxerStream handles invalid audio config without crashing.
253 TEST_F(DecryptingDemuxerStreamTest, Initialize_InvalidAudioConfig) {
254 AudioDecoderConfig config(kUnknownAudioCodec, 0, CHANNEL_LAYOUT_STEREO, 0,
255 NULL, 0, true);
256
257 InitializeAudioAndExpectStatus(config, DEMUXER_ERROR_NO_SUPPORTED_STREAMS);
258 }
259
260 TEST_F(DecryptingDemuxerStreamTest, Initialize_NormalVideo) {
261 EXPECT_CALL(*this, RequestDecryptorNotification(_))
262 .WillOnce(RunCallbackIfNotNull(decryptor_.get()));
263 EXPECT_CALL(*decryptor_, RegisterKeyAddedCB(Decryptor::kVideo, _))
264 .WillOnce(SaveArg<1>(&key_added_cb_));
265
266 VideoDecoderConfig config(kCodecVP8, VIDEO_CODEC_PROFILE_UNKNOWN,
267 kVideoFormat,
268 kCodedSize, kVisibleRect, kNaturalSize,
269 NULL, 0, true);
270 InitializeVideoAndExpectStatus(config, PIPELINE_OK);
271
272 const VideoDecoderConfig& output_config =
273 demuxer_stream_->video_decoder_config();
274 EXPECT_EQ(DemuxerStream::VIDEO, demuxer_stream_->type());
275 EXPECT_FALSE(output_config.is_encrypted());
276 EXPECT_EQ(kCodecVP8, output_config.codec());
277 EXPECT_EQ(kVideoFormat, output_config.format());
278 EXPECT_EQ(VIDEO_CODEC_PROFILE_UNKNOWN, output_config.profile());
279 EXPECT_EQ(kCodedSize, output_config.coded_size());
280 EXPECT_EQ(kVisibleRect, output_config.visible_rect());
281 EXPECT_EQ(kNaturalSize, output_config.natural_size());
282 EXPECT_FALSE(output_config.extra_data());
283 EXPECT_EQ(0u, output_config.extra_data_size());
284 }
285
286 // Ensure that DecryptingDemuxerStream only accepts encrypted video.
287 TEST_F(DecryptingDemuxerStreamTest, Initialize_UnencryptedVideoConfig) {
288 VideoDecoderConfig config(kCodecVP8, VIDEO_CODEC_PROFILE_UNKNOWN,
289 kVideoFormat,
290 kCodedSize, kVisibleRect, kNaturalSize,
291 NULL, 0, false);
292
293 InitializeVideoAndExpectStatus(config, DEMUXER_ERROR_NO_SUPPORTED_STREAMS);
294 }
295
296 // Ensure DecryptingDemuxerStream handles invalid video config without crashing.
297 TEST_F(DecryptingDemuxerStreamTest, Initialize_InvalidVideoConfig) {
298 VideoDecoderConfig config(kCodecVP8, VIDEO_CODEC_PROFILE_UNKNOWN,
299 VideoFrame::INVALID,
300 kCodedSize, kVisibleRect, kNaturalSize,
301 NULL, 0, true);
302
303 InitializeVideoAndExpectStatus(config, DEMUXER_ERROR_NO_SUPPORTED_STREAMS);
304 }
305
306 // Test normal read case.
307 TEST_F(DecryptingDemuxerStreamTest, Read_Normal) {
308 Initialize();
309 EnterNormalReadingState();
310 }
311
312 // Test the case where the decryptor returns error during read.
313 TEST_F(DecryptingDemuxerStreamTest, Read_DecryptError) {
314 Initialize();
315
316 EXPECT_CALL(*input_audio_stream_, Read(_))
317 .WillRepeatedly(ReturnBuffer(encrypted_buffer_));
318 EXPECT_CALL(*decryptor_, Decrypt(_, encrypted_buffer_, _))
319 .WillRepeatedly(RunCallback<2>(Decryptor::kError,
320 scoped_refptr<DecoderBuffer>()));
321 ReadAndExpectBufferReadyWith(DemuxerStream::kAborted, NULL);
322 }
323
324 // Test the case where the input is an end-of-stream buffer.
325 TEST_F(DecryptingDemuxerStreamTest, Read_EndOfStream) {
326 Initialize();
327 EnterNormalReadingState();
328
329 // No Decryptor::Decrypt() call is expected for EOS buffer.
330 EXPECT_CALL(*input_audio_stream_, Read(_))
331 .WillOnce(ReturnBuffer(DecoderBuffer::CreateEOSBuffer()));
332
333 ReadAndExpectBufferReadyWith(DemuxerStream::kOk,
334 DecoderBuffer::CreateEOSBuffer());
335 }
336
337 // Test the case where the a key is added when the decryptor is in
338 // kWaitingForKey state.
339 TEST_F(DecryptingDemuxerStreamTest, KeyAdded_DuringWaitingForKey) {
340 Initialize();
341 EnterWaitingForKeyState();
342
343 EXPECT_CALL(*decryptor_, Decrypt(_, encrypted_buffer_, _))
344 .WillRepeatedly(RunCallback<2>(Decryptor::kSuccess, decrypted_buffer_));
345 EXPECT_CALL(*this, BufferReady(DemuxerStream::kOk, decrypted_buffer_));
346 key_added_cb_.Run();
347 message_loop_.RunUntilIdle();
348 }
349
350 // Test the case where the a key is added when the decryptor is in
351 // kPendingDecrypt state.
352 TEST_F(DecryptingDemuxerStreamTest, KeyAdded_DruingPendingDecrypt) {
353 Initialize();
354 EnterPendingDecryptState();
355
356 EXPECT_CALL(*decryptor_, Decrypt(_, encrypted_buffer_, _))
357 .WillRepeatedly(RunCallback<2>(Decryptor::kSuccess, decrypted_buffer_));
358 EXPECT_CALL(*this, BufferReady(DemuxerStream::kOk, decrypted_buffer_));
359 // The decrypt callback is returned after the correct decryption key is added.
360 key_added_cb_.Run();
361 base::ResetAndReturn(&pending_decrypt_cb_).Run(Decryptor::kNoKey, NULL);
362 message_loop_.RunUntilIdle();
363 }
364
365 // Test resetting when the DecryptingDemuxerStream is in kIdle state but has
366 // not returned any buffer.
367 TEST_F(DecryptingDemuxerStreamTest, Reset_DuringIdleAfterInitialization) {
368 Initialize();
369 Reset();
370 }
371
372 // Test resetting when the DecryptingDemuxerStream is in kIdle state after it
373 // has returned one buffer.
374 TEST_F(DecryptingDemuxerStreamTest, Reset_DuringIdleAfterReadOneBuffer) {
375 Initialize();
376 EnterNormalReadingState();
377 Reset();
378 }
379
380 // Test resetting when DecryptingDemuxerStream is in kPendingDemuxerRead state.
381 TEST_F(DecryptingDemuxerStreamTest, Reset_DuringPendingDemuxerRead) {
382 Initialize();
383 EnterPendingReadState();
384
385 EXPECT_CALL(*this, BufferReady(DemuxerStream::kAborted, IsNull()));
386
387 Reset();
388 base::ResetAndReturn(&pending_demuxer_read_cb_).Run(DemuxerStream::kOk,
389 encrypted_buffer_);
390 message_loop_.RunUntilIdle();
391 }
392
393 // Test resetting when the DecryptingDemuxerStream is in kPendingDecrypt state.
394 TEST_F(DecryptingDemuxerStreamTest, Reset_DuringPendingDecrypt) {
395 Initialize();
396 EnterPendingDecryptState();
397
398 EXPECT_CALL(*this, BufferReady(DemuxerStream::kAborted, IsNull()));
399
400 Reset();
401 }
402
403 // Test resetting when the DecryptingDemuxerStream is in kWaitingForKey state.
404 TEST_F(DecryptingDemuxerStreamTest, Reset_DuringWaitingForKey) {
405 Initialize();
406 EnterWaitingForKeyState();
407
408 EXPECT_CALL(*this, BufferReady(DemuxerStream::kAborted, IsNull()));
409
410 Reset();
411 }
412
413 // Test resetting after the DecryptingDemuxerStream has been reset.
414 TEST_F(DecryptingDemuxerStreamTest, Reset_AfterReset) {
415 Initialize();
416 EnterNormalReadingState();
417 Reset();
418 Reset();
419 }
420
421 // Test aborted read on the demuxer stream.
422 TEST_F(DecryptingDemuxerStreamTest, DemuxerRead_Aborted) {
423 Initialize();
424
425 // ReturnBuffer() with NULL triggers aborted demuxer read.
426 EXPECT_CALL(*input_audio_stream_, Read(_))
427 .WillOnce(ReturnBuffer(scoped_refptr<DecoderBuffer>()));
428
429 ReadAndExpectBufferReadyWith(DemuxerStream::kAborted, NULL);
430 }
431
432 // Test aborted read on the input demuxer stream when the
433 // DecryptingDemuxerStream is being reset.
434 TEST_F(DecryptingDemuxerStreamTest, DemuxerRead_AbortedDuringReset) {
435 Initialize();
436 EnterPendingReadState();
437
438 // Make sure we get a NULL audio frame returned.
439 EXPECT_CALL(*this, BufferReady(DemuxerStream::kAborted, IsNull()));
440
441 Reset();
442 base::ResetAndReturn(&pending_demuxer_read_cb_).Run(DemuxerStream::kAborted,
443 NULL);
444 message_loop_.RunUntilIdle();
445 }
446
447 // Test config change on the input demuxer stream.
448 TEST_F(DecryptingDemuxerStreamTest, DemuxerRead_ConfigChanged) {
449 Initialize();
450
451 EXPECT_CALL(*input_audio_stream_, Read(_))
452 .WillOnce(RunCallback<0>(DemuxerStream::kConfigChanged,
453 scoped_refptr<DecoderBuffer>()));
454
455 // TODO(xhwang): Update this when kConfigChanged is supported.
456 ReadAndExpectBufferReadyWith(DemuxerStream::kAborted, NULL);
457 }
458
459 } // namespace media
OLDNEW
« no previous file with comments | « media/filters/decrypting_demuxer_stream.cc ('k') | media/filters/decrypting_video_decoder.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698