Chromium Code Reviews| Index: components/cdm/browser/widevine_drm_delegate_android.cc |
| 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 0000000000000000000000000000000000000000..da6b5d6394aedf25ecd34c65cd7a2b65a4bbebf2 |
| --- /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<uint8_t>& data, |
| + std::vector<uint8_t>* pssh_data) { |
| + int bytes_left = base::checked_cast<int>(data.size()); |
| + const uint8_t* cur = &data[0]; |
| + const uint8_t* data_end = cur + bytes_left; |
| + |
| + while (bytes_left > 0) { |
| + const uint8* box_head = cur; |
|
xhwang
2015/04/28 05:25:11
uint8_t
|
| + |
| + if (bytes_left < kBoxHeaderSize) |
| + return false; |
| + |
| + uint64_t box_size = ReadUint32(cur); |
| + uint32 type = ReadUint32(cur + 4); |
|
xhwang
2015/04/28 05:25:11
Now it's recommended to use *_t integer types. So
gunsch
2015/04/28 18:50:51
Oops, thanks for catching---I copied the new imple
|
| + 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* box_end = box_head + box_size; |
|
xhwang
2015/04/28 05:25:11
ditto
gunsch
2015/04/28 18:50:51
Done.
|
| + 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 version_and_flags = ReadUint32(cur); |
|
xhwang
2015/04/28 05:25:11
ditto
gunsch
2015/04/28 18:50:51
Done.
|
| + 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 data_size = ReadUint32(cur); |
|
xhwang
2015/04/28 05:25:11
ditto
gunsch
2015/04/28 18:50:51
Done.
|
| + 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<uint8_t> WidevineDrmDelegateAndroid::GetUUID() const { |
| + return std::vector<uint8_t>(kWidevineUuid, |
| + kWidevineUuid + arraysize(kWidevineUuid)); |
| +} |
| + |
| +bool WidevineDrmDelegateAndroid::OnCreateSession( |
| + const media::EmeInitDataType init_data_type, |
| + const std::vector<uint8_t>& init_data, |
| + std::vector<uint8_t>* init_data_out, |
| + std::vector<std::string>* /* 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 |