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

Side by Side Diff: media/test/pipeline_integration_test.cc

Issue 1163713007: Use 'pssh' data to determine key_id properly (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 5 years, 6 months 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
OLDNEW
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 "base/bind.h" 5 #include "base/bind.h"
6 #include "base/command_line.h" 6 #include "base/command_line.h"
7 #include "base/memory/scoped_ptr.h" 7 #include "base/memory/scoped_ptr.h"
8 #include "base/stl_util.h" 8 #include "base/stl_util.h"
9 #include "base/strings/string_util.h" 9 #include "base/strings/string_util.h"
10 #include "build/build_config.h" 10 #include "build/build_config.h"
11 #include "media/base/cdm_callback_promise.h" 11 #include "media/base/cdm_callback_promise.h"
12 #include "media/base/cdm_context.h" 12 #include "media/base/cdm_context.h"
13 #include "media/base/cdm_key_information.h" 13 #include "media/base/cdm_key_information.h"
14 #include "media/base/decoder_buffer.h" 14 #include "media/base/decoder_buffer.h"
15 #include "media/base/media.h" 15 #include "media/base/media.h"
16 #include "media/base/media_keys.h" 16 #include "media/base/media_keys.h"
17 #include "media/base/media_switches.h" 17 #include "media/base/media_switches.h"
18 #include "media/base/test_data_util.h" 18 #include "media/base/test_data_util.h"
19 #include "media/cdm/aes_decryptor.h" 19 #include "media/cdm/aes_decryptor.h"
20 #include "media/cdm/json_web_key.h" 20 #include "media/cdm/json_web_key.h"
21 #include "media/filters/chunk_demuxer.h" 21 #include "media/filters/chunk_demuxer.h"
22 #include "media/renderers/renderer_impl.h" 22 #include "media/renderers/renderer_impl.h"
23 #include "media/test/pipeline_integration_test_base.h" 23 #include "media/test/pipeline_integration_test_base.h"
24 #include "testing/gmock/include/gmock/gmock.h" 24 #include "testing/gmock/include/gmock/gmock.h"
25 #include "url/gurl.h" 25 #include "url/gurl.h"
26 26
27 #if defined(USE_PROPRIETARY_CODECS)
28 #include "media/cdm/cenc_utils.h"
29 #endif
30
27 #if defined(MOJO_RENDERER) 31 #if defined(MOJO_RENDERER)
28 #include "media/mojo/services/mojo_renderer_impl.h" 32 #include "media/mojo/services/mojo_renderer_impl.h"
29 #include "mojo/application/public/cpp/application_impl.h" 33 #include "mojo/application/public/cpp/application_impl.h"
30 #include "mojo/application/public/cpp/application_test_base.h" 34 #include "mojo/application/public/cpp/application_test_base.h"
31 #include "mojo/application/public/cpp/connect.h" 35 #include "mojo/application/public/cpp/connect.h"
32 36
33 // TODO(dalecurtis): The mojo renderer is in another process, so we have no way 37 // TODO(dalecurtis): The mojo renderer is in another process, so we have no way
34 // currently to get hashes for video and audio samples. This also means that 38 // currently to get hashes for video and audio samples. This also means that
35 // real audio plays out for each test. 39 // real audio plays out for each test.
36 #define EXPECT_HASH_EQ(a, b) 40 #define EXPECT_HASH_EQ(a, b)
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after
74 const char kMP3[] = "audio/mpeg"; 78 const char kMP3[] = "audio/mpeg";
75 #endif // defined(USE_PROPRIETARY_CODECS) 79 #endif // defined(USE_PROPRIETARY_CODECS)
76 80
77 // Key used to encrypt test files. 81 // Key used to encrypt test files.
78 const uint8 kSecretKey[] = { 82 const uint8 kSecretKey[] = {
79 0xeb, 0xdd, 0x62, 0xf1, 0x68, 0x14, 0xd2, 0x7b, 83 0xeb, 0xdd, 0x62, 0xf1, 0x68, 0x14, 0xd2, 0x7b,
80 0x68, 0xef, 0x12, 0x2a, 0xfc, 0xe4, 0xae, 0x3c 84 0x68, 0xef, 0x12, 0x2a, 0xfc, 0xe4, 0xae, 0x3c
81 }; 85 };
82 86
83 // The key ID for all encrypted files. 87 // The key ID for all encrypted files.
84 const uint8 kKeyId[] = { 88 const uint8 kKeyId[] = {
ddorwin 2015/06/04 19:57:17 This is now only used for the rotation test (unles
jrummell 2015/06/15 22:22:10 Added check that key ID matches in non-rotating te
85 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 89 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
86 0x38, 0x39, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35 90 0x38, 0x39, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35
87 }; 91 };
88 92
89 const int kAppendWholeFile = -1; 93 const int kAppendWholeFile = -1;
90 94
91 // Constants for the Media Source config change tests. 95 // Constants for the Media Source config change tests.
92 const int kAppendTimeSec = 1; 96 const int kAppendTimeSec = 1;
93 const int kAppendTimeMs = kAppendTimeSec * 1000; 97 const int kAppendTimeMs = kAppendTimeSec * 1000;
94 const int k320WebMFileDurationMs = 2736; 98 const int k320WebMFileDurationMs = 2736;
(...skipping 210 matching lines...) Expand 10 before | Expand all | Expand 10 after
305 void OnEncryptedMediaInitData(EmeInitDataType init_data_type, 309 void OnEncryptedMediaInitData(EmeInitDataType init_data_type,
306 const std::vector<uint8>& init_data, 310 const std::vector<uint8>& init_data,
307 AesDecryptor* decryptor) override { 311 AesDecryptor* decryptor) override {
308 // Since only 1 session is created, skip the request if the |init_data| 312 // Since only 1 session is created, skip the request if the |init_data|
309 // has been seen before (no need to add the same key again). 313 // has been seen before (no need to add the same key again).
310 if (init_data == prev_init_data_) 314 if (init_data == prev_init_data_)
311 return; 315 return;
312 prev_init_data_ = init_data; 316 prev_init_data_ = init_data;
313 317
314 if (current_session_id_.empty()) { 318 if (current_session_id_.empty()) {
315 if (init_data_type == EmeInitDataType::CENC) { 319 decryptor->CreateSessionAndGenerateRequest(
316 // Since the 'cenc' files are not created with proper 'pssh' boxes, 320 MediaKeys::TEMPORARY_SESSION, init_data_type, init_data,
317 // simply pretend that this is a webm file and pass the expected 321 CreateSessionPromise(RESOLVED));
318 // key ID as the init_data.
319 // http://crbug.com/460308
320 decryptor->CreateSessionAndGenerateRequest(
321 MediaKeys::TEMPORARY_SESSION, EmeInitDataType::WEBM,
322 std::vector<uint8>(kKeyId, kKeyId + arraysize(kKeyId)),
323 CreateSessionPromise(RESOLVED));
324 } else {
325 decryptor->CreateSessionAndGenerateRequest(
326 MediaKeys::TEMPORARY_SESSION, init_data_type, init_data,
327 CreateSessionPromise(RESOLVED));
328 }
329 EXPECT_FALSE(current_session_id_.empty()); 322 EXPECT_FALSE(current_session_id_.empty());
330 } 323 }
331 324
332 // Clear Key really needs the key ID from |init_data|. For WebM, they are 325 // Clear Key needs the key ID from |init_data|.
ddorwin 2015/06/04 19:57:17 We should really wait for the message and extract
jrummell 2015/06/15 22:22:10 Waiting for message means we don't need to care ab
333 // the same, but this is not the case for ISO CENC (key ID embedded in a 326 std::vector<uint8> key_id;
334 // 'pssh' box). Therefore, provide the correct key ID. 327 EXPECT_TRUE(GetKeyId(init_data_type, init_data, &key_id));
335 const uint8* key_id = vector_as_array(&init_data);
336 size_t key_id_length = init_data.size();
337 if (init_data_type == EmeInitDataType::CENC) {
338 key_id = kKeyId;
339 key_id_length = arraysize(kKeyId);
340 }
341 328
342 // Convert key into a JSON structure and then add it. 329 // Convert key into a JSON structure and then add it.
343 std::string jwk = GenerateJWKSet( 330 std::string jwk = GenerateJWKSet(kSecretKey, arraysize(kSecretKey),
344 kSecretKey, arraysize(kSecretKey), key_id, key_id_length); 331 vector_as_array(&key_id), key_id.size());
345 decryptor->UpdateSession(current_session_id_, 332 decryptor->UpdateSession(current_session_id_,
346 std::vector<uint8>(jwk.begin(), jwk.end()), 333 std::vector<uint8>(jwk.begin(), jwk.end()),
347 CreatePromise(RESOLVED)); 334 CreatePromise(RESOLVED));
348 } 335 }
349 336
337 bool GetKeyId(EmeInitDataType init_data_type,
ddorwin 2015/06/04 19:57:17 This can be a static function at the top.
jrummell 2015/06/15 22:22:10 Removed.
338 const std::vector<uint8>& init_data,
339 std::vector<uint8>* key_id) {
340 // For WebM, init_data is key_id; for ISO CENC, init_data should
ddorwin 2015/06/04 19:57:17 Function level comment. nit: use pipes ('|')
jrummell 2015/06/15 22:22:10 Removed.
341 // contain a 'pssh' box for the Common Encryption SystemID which
342 // will contain the key_id.
ddorwin 2015/06/04 19:57:18 You might note that keyids does not need to be sup
jrummell 2015/06/15 22:22:10 Removed.
343 DCHECK_GE(init_data.size(), arraysize(kKeyId));
ddorwin 2015/06/04 19:57:17 arraysize(kKeyId) looks weird. Can we define a sep
jrummell 2015/06/15 22:22:10 Removed.
344 DCHECK_EQ(key_id->size(), 0u);
345
346 switch (init_data_type) {
347 case EmeInitDataType::WEBM:
348 DCHECK_EQ(init_data.size(), arraysize(kKeyId));
349 key_id->assign(init_data.begin(), init_data.end());
350 return true;
351
352 case EmeInitDataType::CENC:
353 #if defined(USE_PROPRIETARY_CODECS)
354 // |init_data| is a set of 0 or more concatenated 'pssh' boxes.
355 {
356 std::vector<std::vector<uint8_t>> keys;
357 EXPECT_TRUE(GetKeyIdsForCommonSystemId(init_data, &keys));
358 if (!keys.empty())
359 key_id->assign(keys[0].begin(), keys[0].end());
360 return !keys.empty();
361 }
362 #else
363 return false;
ddorwin 2015/06/04 19:57:17 Should we add this? NOTREACHED() << "Attempted to
jrummell 2015/06/15 22:22:10 Removed.
364 #endif
365
366 default:
367 // Nothing else is supported.
ddorwin 2015/06/04 19:57:17 NOTREACHED?
jrummell 2015/06/15 22:22:10 Removed.
368 break;
369 }
370
371 return false;
ddorwin 2015/06/04 19:57:18 You can move this up to 368. Or remove default so
jrummell 2015/06/15 22:22:10 Removed.
372 }
373
350 std::string current_session_id_; 374 std::string current_session_id_;
351 std::vector<uint8> prev_init_data_; 375 std::vector<uint8> prev_init_data_;
352 }; 376 };
353 377
354 class RotatingKeyProvidingApp : public KeyProvidingApp { 378 class RotatingKeyProvidingApp : public KeyProvidingApp {
355 public: 379 public:
356 RotatingKeyProvidingApp() : num_distint_need_key_calls_(0) {} 380 RotatingKeyProvidingApp() : num_distint_need_key_calls_(0) {}
357 ~RotatingKeyProvidingApp() override { 381 ~RotatingKeyProvidingApp() override {
358 // Expect that OnEncryptedMediaInitData is fired multiple times with 382 // Expect that OnEncryptedMediaInitData is fired multiple times with
359 // different |init_data|. 383 // different |init_data|.
360 EXPECT_GT(num_distint_need_key_calls_, 1u); 384 EXPECT_GT(num_distint_need_key_calls_, 1u);
361 } 385 }
362 386
363 void OnEncryptedMediaInitData(EmeInitDataType init_data_type, 387 void OnEncryptedMediaInitData(EmeInitDataType init_data_type,
364 const std::vector<uint8>& init_data, 388 const std::vector<uint8>& init_data,
365 AesDecryptor* decryptor) override { 389 AesDecryptor* decryptor) override {
366 // Skip the request if the |init_data| has been seen. 390 // Skip the request if the |init_data| has been seen.
367 if (init_data == prev_init_data_) 391 if (init_data == prev_init_data_)
368 return; 392 return;
369 prev_init_data_ = init_data; 393 prev_init_data_ = init_data;
370 ++num_distint_need_key_calls_; 394 ++num_distint_need_key_calls_;
371 395
372 std::vector<uint8> key_id; 396 std::vector<uint8> key_id;
373 std::vector<uint8> key; 397 std::vector<uint8> key;
374 EXPECT_TRUE(GetKeyAndKeyId(init_data, &key, &key_id)); 398 EXPECT_TRUE(GetKeyAndKeyId(init_data_type, init_data, &key, &key_id));
375 399
376 if (init_data_type == EmeInitDataType::CENC) { 400 decryptor->CreateSessionAndGenerateRequest(MediaKeys::TEMPORARY_SESSION,
377 // Since the 'cenc' files are not created with proper 'pssh' boxes, 401 init_data_type, init_data,
378 // simply pretend that this is a webm file and pass the expected 402 CreateSessionPromise(RESOLVED));
379 // key ID as the init_data.
380 // http://crbug.com/460308
381 decryptor->CreateSessionAndGenerateRequest(
382 MediaKeys::TEMPORARY_SESSION, EmeInitDataType::WEBM, key_id,
383 CreateSessionPromise(RESOLVED));
384 } else {
385 decryptor->CreateSessionAndGenerateRequest(
386 MediaKeys::TEMPORARY_SESSION, init_data_type, init_data,
387 CreateSessionPromise(RESOLVED));
388 }
389 403
390 // Convert key into a JSON structure and then add it. 404 // Convert key into a JSON structure and then add it.
391 std::string jwk = GenerateJWKSet(vector_as_array(&key), 405 std::string jwk = GenerateJWKSet(vector_as_array(&key),
392 key.size(), 406 key.size(),
393 vector_as_array(&key_id), 407 vector_as_array(&key_id),
394 key_id.size()); 408 key_id.size());
395 decryptor->UpdateSession(current_session_id_, 409 decryptor->UpdateSession(current_session_id_,
396 std::vector<uint8>(jwk.begin(), jwk.end()), 410 std::vector<uint8>(jwk.begin(), jwk.end()),
397 CreatePromise(RESOLVED)); 411 CreatePromise(RESOLVED));
398 } 412 }
399 413
400 private: 414 private:
401 bool GetKeyAndKeyId(std::vector<uint8> init_data, 415 bool GetKeyAndKeyId(EmeInitDataType init_data_type,
416 const std::vector<uint8>& init_data,
402 std::vector<uint8>* key, 417 std::vector<uint8>* key,
403 std::vector<uint8>* key_id) { 418 std::vector<uint8>* key_id) {
404 // For WebM, init_data is key_id; for ISO CENC, init_data should contain
405 // the key_id. We assume key_id is in the end of init_data here (that is
406 // only a reasonable assumption for WebM and clear key ISO CENC).
407 DCHECK_GE(init_data.size(), arraysize(kKeyId)); 419 DCHECK_GE(init_data.size(), arraysize(kKeyId));
408 std::vector<uint8> key_id_from_init_data( 420 std::vector<uint8> key_id_from_init_data;
409 init_data.end() - arraysize(kKeyId), init_data.end()); 421 EXPECT_TRUE(GetKeyId(init_data_type, init_data, &key_id_from_init_data));
410 422
411 key->assign(kSecretKey, kSecretKey + arraysize(kSecretKey)); 423 key->assign(kSecretKey, kSecretKey + arraysize(kSecretKey));
412 key_id->assign(kKeyId, kKeyId + arraysize(kKeyId)); 424 key_id->assign(kKeyId, kKeyId + arraysize(kKeyId));
413 425
414 // The Key and KeyId for this testing key provider are created by left 426 // The Key and KeyId for this testing key provider are created by left
ddorwin 2015/06/04 19:57:17 Do we still need to do this for the key ID since w
jrummell 2015/06/15 22:22:10 Yes. The key for the rotated key ID is |kSecretKey
415 // rotating kSecretKey and kKeyId. Note that this implementation is only 427 // rotating kSecretKey and kKeyId. Note that this implementation is only
416 // intended for testing purpose. The actual key rotation algorithm can be 428 // intended for testing purpose. The actual key rotation algorithm can be
417 // much more complicated. 429 // much more complicated.
418 // Find out the rotating position from |key_id_from_init_data| and apply on 430 // Find out the rotating position from |key_id_from_init_data| and apply on
419 // |key|. 431 // |key|.
420 for (size_t pos = 0; pos < arraysize(kKeyId); ++pos) { 432 for (size_t pos = 0; pos < arraysize(kKeyId); ++pos) {
421 std::rotate(key_id->begin(), key_id->begin() + pos, key_id->end()); 433 std::rotate(key_id->begin(), key_id->begin() + pos, key_id->end());
422 if (*key_id == key_id_from_init_data) { 434 if (*key_id == key_id_from_init_data) {
423 std::rotate(key->begin(), key->begin() + pos, key->end()); 435 std::rotate(key->begin(), key->begin() + pos, key->end());
424 return true; 436 return true;
(...skipping 1312 matching lines...) Expand 10 before | Expand all | Expand 10 after
1737 1749
1738 TEST_F(PipelineIntegrationTest, BasicPlaybackPositiveStartTime) { 1750 TEST_F(PipelineIntegrationTest, BasicPlaybackPositiveStartTime) {
1739 ASSERT_EQ(PIPELINE_OK, Start("nonzero-start-time.webm")); 1751 ASSERT_EQ(PIPELINE_OK, Start("nonzero-start-time.webm"));
1740 Play(); 1752 Play();
1741 ASSERT_TRUE(WaitUntilOnEnded()); 1753 ASSERT_TRUE(WaitUntilOnEnded());
1742 ASSERT_EQ(base::TimeDelta::FromMicroseconds(396000), 1754 ASSERT_EQ(base::TimeDelta::FromMicroseconds(396000),
1743 demuxer_->GetStartTime()); 1755 demuxer_->GetStartTime());
1744 } 1756 }
1745 1757
1746 } // namespace media 1758 } // namespace media
OLDNEW
« media/cdm/cenc_utils_unittest.cc ('K') | « media/test/data/bear-640x360-v_frag-cenc-key_rotation.mp4 ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698