Chromium Code Reviews| 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 "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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 |
| OLD | NEW |