| OLD | NEW |
| 1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2013 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/base/android/media_drm_bridge.h" | 5 #include "media/base/android/media_drm_bridge.h" |
| 6 | 6 |
| 7 #include <algorithm> | 7 #include <algorithm> |
| 8 | 8 |
| 9 #include "base/android/build_info.h" | 9 #include "base/android/build_info.h" |
| 10 #include "base/android/jni_array.h" | 10 #include "base/android/jni_array.h" |
| 11 #include "base/android/jni_string.h" | 11 #include "base/android/jni_string.h" |
| 12 #include "base/callback_helpers.h" | 12 #include "base/callback_helpers.h" |
| 13 #include "base/containers/hash_tables.h" | 13 #include "base/containers/hash_tables.h" |
| 14 #include "base/lazy_instance.h" | 14 #include "base/lazy_instance.h" |
| 15 #include "base/location.h" | 15 #include "base/location.h" |
| 16 #include "base/logging.h" | 16 #include "base/logging.h" |
| 17 #include "base/message_loop/message_loop_proxy.h" | 17 #include "base/message_loop/message_loop_proxy.h" |
| 18 #include "base/numerics/safe_conversions.h" |
| 19 #include "base/stl_util.h" |
| 18 #include "base/strings/string_util.h" | 20 #include "base/strings/string_util.h" |
| 19 #include "base/sys_byteorder.h" | 21 #include "base/sys_byteorder.h" |
| 20 #include "base/sys_info.h" | 22 #include "base/sys_info.h" |
| 21 #include "jni/MediaDrmBridge_jni.h" | 23 #include "jni/MediaDrmBridge_jni.h" |
| 22 #include "media/base/cdm_key_information.h" | 24 #include "media/base/cdm_key_information.h" |
| 23 | 25 |
| 24 #include "widevine_cdm_version.h" // In SHARED_INTERMEDIATE_DIR. | 26 #include "widevine_cdm_version.h" // In SHARED_INTERMEDIATE_DIR. |
| 25 | 27 |
| 26 using base::android::AttachCurrentThread; | 28 using base::android::AttachCurrentThread; |
| 27 using base::android::ConvertUTF8ToJavaString; | 29 using base::android::ConvertUTF8ToJavaString; |
| (...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 85 | 87 |
| 86 typedef std::vector<uint8> UUID; | 88 typedef std::vector<uint8> UUID; |
| 87 | 89 |
| 88 // Tries to find a PSSH box whose "SystemId" is |uuid| in |data|, parses the | 90 // Tries to find a PSSH box whose "SystemId" is |uuid| in |data|, parses the |
| 89 // "Data" of the box and put it in |pssh_data|. Returns true if such a box is | 91 // "Data" of the box and put it in |pssh_data|. Returns true if such a box is |
| 90 // found and successfully parsed. Returns false otherwise. | 92 // found and successfully parsed. Returns false otherwise. |
| 91 // Notes: | 93 // Notes: |
| 92 // 1, If multiple PSSH boxes are found,the "Data" of the first matching PSSH box | 94 // 1, If multiple PSSH boxes are found,the "Data" of the first matching PSSH box |
| 93 // will be set in |pssh_data|. | 95 // will be set in |pssh_data|. |
| 94 // 2, Only PSSH and TENC boxes are allowed in |data|. TENC boxes are skipped. | 96 // 2, Only PSSH and TENC boxes are allowed in |data|. TENC boxes are skipped. |
| 95 bool GetPsshData(const uint8* data, | 97 bool GetPsshData(const std::vector<uint8_t>& data, |
| 96 int data_size, | |
| 97 const UUID& uuid, | 98 const UUID& uuid, |
| 98 std::vector<uint8>* pssh_data) { | 99 std::vector<uint8>* pssh_data) { |
| 99 const uint8* cur = data; | 100 int bytes_left = base::checked_cast<int>(data.size()); |
| 100 const uint8* data_end = data + data_size; | 101 const uint8_t* cur = &data[0]; |
| 101 int bytes_left = data_size; | 102 const uint8_t* data_end = cur + bytes_left; |
| 102 | 103 |
| 103 while (bytes_left > 0) { | 104 while (bytes_left > 0) { |
| 104 const uint8* box_head = cur; | 105 const uint8* box_head = cur; |
| 105 | 106 |
| 106 if (bytes_left < kBoxHeaderSize) | 107 if (bytes_left < kBoxHeaderSize) |
| 107 return false; | 108 return false; |
| 108 | 109 |
| 109 uint64_t box_size = ReadUint32(cur); | 110 uint64_t box_size = ReadUint32(cur); |
| 110 uint32 type = ReadUint32(cur + 4); | 111 uint32 type = ReadUint32(cur + 4); |
| 111 cur += kBoxHeaderSize; | 112 cur += kBoxHeaderSize; |
| (...skipping 308 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 420 if (security_level_str.empty()) | 421 if (security_level_str.empty()) |
| 421 return false; | 422 return false; |
| 422 | 423 |
| 423 ScopedJavaLocalRef<jstring> j_security_level = | 424 ScopedJavaLocalRef<jstring> j_security_level = |
| 424 ConvertUTF8ToJavaString(env, security_level_str); | 425 ConvertUTF8ToJavaString(env, security_level_str); |
| 425 return Java_MediaDrmBridge_setSecurityLevel( | 426 return Java_MediaDrmBridge_setSecurityLevel( |
| 426 env, j_media_drm_.obj(), j_security_level.obj()); | 427 env, j_media_drm_.obj(), j_security_level.obj()); |
| 427 } | 428 } |
| 428 | 429 |
| 429 void MediaDrmBridge::SetServerCertificate( | 430 void MediaDrmBridge::SetServerCertificate( |
| 430 const uint8* certificate_data, | 431 const std::vector<uint8_t>& certificate, |
| 431 int certificate_data_length, | |
| 432 scoped_ptr<media::SimpleCdmPromise> promise) { | 432 scoped_ptr<media::SimpleCdmPromise> promise) { |
| 433 promise->reject(NOT_SUPPORTED_ERROR, 0, | 433 promise->reject(NOT_SUPPORTED_ERROR, 0, |
| 434 "SetServerCertificate() is not supported."); | 434 "SetServerCertificate() is not supported."); |
| 435 } | 435 } |
| 436 | 436 |
| 437 void MediaDrmBridge::CreateSessionAndGenerateRequest( | 437 void MediaDrmBridge::CreateSessionAndGenerateRequest( |
| 438 SessionType session_type, | 438 SessionType session_type, |
| 439 media::EmeInitDataType init_data_type, | 439 media::EmeInitDataType init_data_type, |
| 440 const uint8* init_data, | 440 const std::vector<uint8_t>& init_data, |
| 441 int init_data_length, | |
| 442 scoped_ptr<media::NewSessionCdmPromise> promise) { | 441 scoped_ptr<media::NewSessionCdmPromise> promise) { |
| 443 DVLOG(1) << __FUNCTION__; | 442 DVLOG(1) << __FUNCTION__; |
| 444 | 443 |
| 445 if (session_type != media::MediaKeys::TEMPORARY_SESSION) { | 444 if (session_type != media::MediaKeys::TEMPORARY_SESSION) { |
| 446 promise->reject(NOT_SUPPORTED_ERROR, 0, | 445 promise->reject(NOT_SUPPORTED_ERROR, 0, |
| 447 "Only the temporary session type is supported."); | 446 "Only the temporary session type is supported."); |
| 448 return; | 447 return; |
| 449 } | 448 } |
| 450 | 449 |
| 451 JNIEnv* env = AttachCurrentThread(); | 450 JNIEnv* env = AttachCurrentThread(); |
| 452 ScopedJavaLocalRef<jbyteArray> j_init_data; | 451 ScopedJavaLocalRef<jbyteArray> j_init_data; |
| 453 | 452 |
| 454 // Widevine MediaDrm plugin only accepts the "data" part of the PSSH box as | 453 // Widevine MediaDrm plugin only accepts the "data" part of the PSSH box as |
| 455 // the init data when using MP4 container. | 454 // the init data when using MP4 container. |
| 456 if (std::equal(scheme_uuid_.begin(), scheme_uuid_.end(), kWidevineUuid) && | 455 if (std::equal(scheme_uuid_.begin(), scheme_uuid_.end(), kWidevineUuid) && |
| 457 init_data_type == media::EmeInitDataType::CENC) { | 456 init_data_type == media::EmeInitDataType::CENC) { |
| 458 std::vector<uint8> pssh_data; | 457 std::vector<uint8> pssh_data; |
| 459 if (!GetPsshData(init_data, init_data_length, scheme_uuid_, &pssh_data)) { | 458 if (!GetPsshData(init_data, scheme_uuid_, &pssh_data)) { |
| 460 promise->reject(INVALID_ACCESS_ERROR, 0, "Invalid PSSH data."); | 459 promise->reject(INVALID_ACCESS_ERROR, 0, "Invalid PSSH data."); |
| 461 return; | 460 return; |
| 462 } | 461 } |
| 463 j_init_data = | 462 j_init_data = base::android::ToJavaByteArray( |
| 464 base::android::ToJavaByteArray(env, &pssh_data[0], pssh_data.size()); | 463 env, vector_as_array(&pssh_data), pssh_data.size()); |
| 465 } else { | 464 } else { |
| 466 j_init_data = | 465 j_init_data = base::android::ToJavaByteArray( |
| 467 base::android::ToJavaByteArray(env, init_data, init_data_length); | 466 env, vector_as_array(&init_data), init_data.size()); |
| 468 } | 467 } |
| 469 | 468 |
| 470 ScopedJavaLocalRef<jstring> j_mime = | 469 ScopedJavaLocalRef<jstring> j_mime = |
| 471 ConvertUTF8ToJavaString(env, ConvertInitDataType(init_data_type)); | 470 ConvertUTF8ToJavaString(env, ConvertInitDataType(init_data_type)); |
| 472 uint32_t promise_id = cdm_promise_adapter_.SavePromise(promise.Pass()); | 471 uint32_t promise_id = cdm_promise_adapter_.SavePromise(promise.Pass()); |
| 473 Java_MediaDrmBridge_createSession(env, j_media_drm_.obj(), j_init_data.obj(), | 472 Java_MediaDrmBridge_createSession(env, j_media_drm_.obj(), j_init_data.obj(), |
| 474 j_mime.obj(), promise_id); | 473 j_mime.obj(), promise_id); |
| 475 } | 474 } |
| 476 | 475 |
| 477 void MediaDrmBridge::LoadSession( | 476 void MediaDrmBridge::LoadSession( |
| 478 SessionType session_type, | 477 SessionType session_type, |
| 479 const std::string& session_id, | 478 const std::string& session_id, |
| 480 scoped_ptr<media::NewSessionCdmPromise> promise) { | 479 scoped_ptr<media::NewSessionCdmPromise> promise) { |
| 481 promise->reject(NOT_SUPPORTED_ERROR, 0, "LoadSession() is not supported."); | 480 promise->reject(NOT_SUPPORTED_ERROR, 0, "LoadSession() is not supported."); |
| 482 } | 481 } |
| 483 | 482 |
| 484 void MediaDrmBridge::UpdateSession( | 483 void MediaDrmBridge::UpdateSession( |
| 485 const std::string& session_id, | 484 const std::string& session_id, |
| 486 const uint8* response, | 485 const std::vector<uint8_t>& response, |
| 487 int response_length, | |
| 488 scoped_ptr<media::SimpleCdmPromise> promise) { | 486 scoped_ptr<media::SimpleCdmPromise> promise) { |
| 489 DVLOG(1) << __FUNCTION__; | 487 DVLOG(1) << __FUNCTION__; |
| 490 | 488 |
| 491 JNIEnv* env = AttachCurrentThread(); | 489 JNIEnv* env = AttachCurrentThread(); |
| 492 ScopedJavaLocalRef<jbyteArray> j_response = | 490 ScopedJavaLocalRef<jbyteArray> j_response = base::android::ToJavaByteArray( |
| 493 base::android::ToJavaByteArray(env, response, response_length); | 491 env, vector_as_array(&response), response.size()); |
| 494 ScopedJavaLocalRef<jbyteArray> j_session_id = base::android::ToJavaByteArray( | 492 ScopedJavaLocalRef<jbyteArray> j_session_id = base::android::ToJavaByteArray( |
| 495 env, reinterpret_cast<const uint8_t*>(session_id.data()), | 493 env, reinterpret_cast<const uint8_t*>(session_id.data()), |
| 496 session_id.size()); | 494 session_id.size()); |
| 497 uint32_t promise_id = cdm_promise_adapter_.SavePromise(promise.Pass()); | 495 uint32_t promise_id = cdm_promise_adapter_.SavePromise(promise.Pass()); |
| 498 Java_MediaDrmBridge_updateSession(env, j_media_drm_.obj(), j_session_id.obj(), | 496 Java_MediaDrmBridge_updateSession(env, j_media_drm_.obj(), j_session_id.obj(), |
| 499 j_response.obj(), promise_id); | 497 j_response.obj(), promise_id); |
| 500 } | 498 } |
| 501 | 499 |
| 502 void MediaDrmBridge::CloseSession(const std::string& session_id, | 500 void MediaDrmBridge::CloseSession(const std::string& session_id, |
| 503 scoped_ptr<media::SimpleCdmPromise> promise) { | 501 scoped_ptr<media::SimpleCdmPromise> promise) { |
| (...skipping 155 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 659 JNIEnv* env = AttachCurrentThread(); | 657 JNIEnv* env = AttachCurrentThread(); |
| 660 Java_MediaDrmBridge_resetDeviceCredentials(env, j_media_drm_.obj()); | 658 Java_MediaDrmBridge_resetDeviceCredentials(env, j_media_drm_.obj()); |
| 661 } | 659 } |
| 662 | 660 |
| 663 void MediaDrmBridge::OnResetDeviceCredentialsCompleted( | 661 void MediaDrmBridge::OnResetDeviceCredentialsCompleted( |
| 664 JNIEnv* env, jobject, bool success) { | 662 JNIEnv* env, jobject, bool success) { |
| 665 base::ResetAndReturn(&reset_credentials_cb_).Run(success); | 663 base::ResetAndReturn(&reset_credentials_cb_).Run(success); |
| 666 } | 664 } |
| 667 | 665 |
| 668 } // namespace media | 666 } // namespace media |
| OLD | NEW |