From 2288c539cc227ec262be28c4b684ff38527f7768 Mon Sep 17 00:00:00 2001 From: gunsch Date: Wed, 29 Apr 2015 20:58:45 -0700 Subject: Adds MediaClientAndroid to support embedder/MediaDrmBridge interaction. This CL does a few things: * Adds a MediaDrmBridgeDelegate interface to support per DRM-scheme logic for Android in MediaDrmBridge. * Adds a MediaClientAndroid interface for embedders to provide MediaDrmBridgeDelegate implementations and key-system-UUID mappings * Removes the Java-based key-system-UUID mapping path * Embedders no longer call directly into MediaDrmBridge R=qinmin@chromium.org,xhwang@chromium.org,boliu@chromium.org,jochen@chromium.org BUG=462443 Review URL: https://codereview.chromium.org/962793005 Cr-Commit-Position: refs/heads/master@{#327650} --- components/cdm/browser/BUILD.gn | 2 + .../cdm/browser/widevine_drm_delegate_android.cc | 163 +++++++++++++++++++++ .../cdm/browser/widevine_drm_delegate_android.h | 32 ++++ 3 files changed, 197 insertions(+) create mode 100644 components/cdm/browser/widevine_drm_delegate_android.cc create mode 100644 components/cdm/browser/widevine_drm_delegate_android.h (limited to 'components/cdm') diff --git a/components/cdm/browser/BUILD.gn b/components/cdm/browser/BUILD.gn index e18b670..cea393b 100644 --- a/components/cdm/browser/BUILD.gn +++ b/components/cdm/browser/BUILD.gn @@ -6,6 +6,8 @@ source_set("browser") { sources = [ "cdm_message_filter_android.cc", "cdm_message_filter_android.h", + "widevine_drm_delegate_android.cc", + "widevine_drm_delegate_android.h", ] deps = [ diff --git a/components/cdm/browser/widevine_drm_delegate_android.cc b/components/cdm/browser/widevine_drm_delegate_android.cc new file mode 100644 index 0000000..64b90bf --- /dev/null +++ b/components/cdm/browser/widevine_drm_delegate_android.cc @@ -0,0 +1,163 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "components/cdm/browser/widevine_drm_delegate_android.h" + +#include "base/logging.h" +#include "base/numerics/safe_conversions.h" + +namespace cdm { + +namespace { + +uint32_t ReadUint32(const uint8_t* data) { + uint32_t value = 0; + for (int i = 0; i < 4; ++i) + value = (value << 8) | data[i]; + return value; +} + +uint64_t ReadUint64(const uint8_t* data) { + uint64_t value = 0; + for (int i = 0; i < 8; ++i) + value = (value << 8) | data[i]; + return value; +} + +// The structure of an ISO CENC Protection System Specific Header (PSSH) box is +// as follows. (See ISO/IEC FDIS 23001-7:2011(E).) +// Note: ISO boxes use big-endian values. +// +// PSSH { +// uint32_t Size +// uint32_t Type +// uint64_t LargeSize # Field is only present if value(Size) == 1. +// uint32_t VersionAndFlags +// uint8_t[16] SystemId +// uint32_t DataSize +// uint8_t[DataSize] Data +// } +const int kBoxHeaderSize = 8; // Box's header contains Size and Type. +const int kBoxLargeSizeSize = 8; +const int kPsshVersionFlagSize = 4; +const int kPsshSystemIdSize = 16; +const int kPsshDataSizeSize = 4; +const uint32_t kTencType = 0x74656e63; +const uint32_t kPsshType = 0x70737368; + +const uint8_t kWidevineUuid[16] = { + 0xED, 0xEF, 0x8B, 0xA9, 0x79, 0xD6, 0x4A, 0xCE, + 0xA3, 0xC8, 0x27, 0xDC, 0xD5, 0x1D, 0x21, 0xED }; + +// Tries to find a PSSH box with the Widevine UUID, parses the +// "Data" of the box and put it in |pssh_data|. Returns true if such a box is +// found and successfully parsed. Returns false otherwise. +// Notes: +// 1, If multiple PSSH boxes are found,the "Data" of the first matching PSSH box +// will be set in |pssh_data|. +// 2, Only PSSH and TENC boxes are allowed in |data|. TENC boxes are skipped. +bool GetPsshData(const std::vector& data, + std::vector* pssh_data) { + int bytes_left = base::checked_cast(data.size()); + const uint8_t* cur = &data[0]; + const uint8_t* data_end = cur + bytes_left; + + while (bytes_left > 0) { + const uint8_t* box_head = cur; + + if (bytes_left < kBoxHeaderSize) + return false; + + uint64_t box_size = ReadUint32(cur); + uint32_t type = ReadUint32(cur + 4); + cur += kBoxHeaderSize; + bytes_left -= kBoxHeaderSize; + + if (box_size == 1) { // LargeSize is present. + if (bytes_left < kBoxLargeSizeSize) + return false; + + box_size = ReadUint64(cur); + cur += kBoxLargeSizeSize; + bytes_left -= kBoxLargeSizeSize; + } else if (box_size == 0) { + box_size = bytes_left + kBoxHeaderSize; + } + + const uint8_t* box_end = box_head + box_size; + if (data_end < box_end) + return false; + + if (type == kTencType) { + // Skip 'tenc' box. + cur = box_end; + bytes_left = data_end - cur; + continue; + } else if (type != kPsshType) { + return false; + } + + const int kPsshBoxMinimumSize = + kPsshVersionFlagSize + kPsshSystemIdSize + kPsshDataSizeSize; + if (box_end < cur + kPsshBoxMinimumSize) + return false; + + uint32_t version_and_flags = ReadUint32(cur); + cur += kPsshVersionFlagSize; + bytes_left -= kPsshVersionFlagSize; + if (version_and_flags != 0) + return false; + + DCHECK_GE(bytes_left, kPsshSystemIdSize); + if (!std::equal(kWidevineUuid, + kWidevineUuid + sizeof(kWidevineUuid), cur)) { + cur = box_end; + bytes_left = data_end - cur; + continue; + } + + cur += kPsshSystemIdSize; + bytes_left -= kPsshSystemIdSize; + + uint32_t data_size = ReadUint32(cur); + cur += kPsshDataSizeSize; + bytes_left -= kPsshDataSizeSize; + + if (box_end < cur + data_size) + return false; + + pssh_data->assign(cur, cur + data_size); + return true; + } + + return false; +} + +} + +WidevineDrmDelegateAndroid::WidevineDrmDelegateAndroid() { +} + +WidevineDrmDelegateAndroid::~WidevineDrmDelegateAndroid() { +} + +const std::vector WidevineDrmDelegateAndroid::GetUUID() const { + return std::vector(kWidevineUuid, + kWidevineUuid + arraysize(kWidevineUuid)); +} + +bool WidevineDrmDelegateAndroid::OnCreateSession( + const media::EmeInitDataType init_data_type, + const std::vector& init_data, + std::vector* init_data_out, + std::vector* /* optional_parameters_out */) { + if (init_data_type != media::EmeInitDataType::CENC) + return true; + + // Widevine MediaDrm plugin only accepts the "data" part of the PSSH box as + // the init data when using MP4 container. + return GetPsshData(init_data, init_data_out); +} + +} // namespace cdm diff --git a/components/cdm/browser/widevine_drm_delegate_android.h b/components/cdm/browser/widevine_drm_delegate_android.h new file mode 100644 index 0000000..09a54ae --- /dev/null +++ b/components/cdm/browser/widevine_drm_delegate_android.h @@ -0,0 +1,32 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef COMPONENTS_CDM_BROWSER_WIDEVINE_DRM_DELEGATE_ANDROID_H_ +#define COMPONENTS_CDM_BROWSER_WIDEVINE_DRM_DELEGATE_ANDROID_H_ + +#include "base/macros.h" +#include "media/base/android/media_drm_bridge_delegate.h" + +namespace cdm { + +class WidevineDrmDelegateAndroid : public media::MediaDrmBridgeDelegate { + public: + WidevineDrmDelegateAndroid(); + ~WidevineDrmDelegateAndroid() override; + + // media::MediaDrmBridgeDelegate implementation: + const std::vector GetUUID() const override; + bool OnCreateSession( + const media::EmeInitDataType init_data_type, + const std::vector& init_data, + std::vector* init_data_out, + std::vector* optional_parameters_out) override; + + private: + DISALLOW_COPY_AND_ASSIGN(WidevineDrmDelegateAndroid); +}; + +} // namespace cdm + +#endif // COMPONENTS_CDM_BROWSER_WIDEVINE_DRM_DELEGATE_ANDROID_H_ -- cgit v1.1