media_drm_bridge.cc revision eb525c5499e34cc9c4b825d6d9e75bb07cc06ace
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 3// found in the LICENSE file. 4 5#include "media/base/android/media_drm_bridge.h" 6 7#include "base/android/jni_array.h" 8#include "base/android/jni_string.h" 9#include "base/logging.h" 10#include "media/base/android/media_player_manager.h" 11 12using base::android::ConvertJavaStringToUTF8; 13using base::android::JavaByteArrayToByteVector; 14using base::android::ScopedJavaLocalRef; 15 16namespace media { 17 18static uint32 ReadUint32(const uint8_t* data) { 19 uint32 value = 0; 20 for (int i = 0; i < 4; ++i) 21 value = (value << 8) | data[i]; 22 return value; 23} 24 25static uint64 ReadUint64(const uint8_t* data) { 26 uint64 value = 0; 27 for (int i = 0; i < 8; ++i) 28 value = (value << 8) | data[i]; 29 return value; 30} 31 32// The structure of an ISO CENC Protection System Specific Header (PSSH) box is 33// as follows. (See ISO/IEC FDIS 23001-7:2011(E).) 34// Note: ISO boxes use big-endian values. 35// 36// PSSH { 37// uint32 Size 38// uint32 Type 39// uint64 LargeSize # Field is only present if value(Size) == 1. 40// uint32 VersionAndFlags 41// uint8[16] SystemId 42// uint32 DataSize 43// uint8[DataSize] Data 44// } 45static const int kBoxHeaderSize = 8; // Box's header contains Size and Type. 46static const int kBoxLargeSizeSize = 8; 47static const int kPsshVersionFlagSize = 4; 48static const int kPsshSystemIdSize = 16; 49static const int kPsshDataSizeSize = 4; 50static const uint32 kTencType = 0x74656e63; 51static const uint32 kPsshType = 0x70737368; 52 53// Tries to find a PSSH box whose "SystemId" is |uuid| in |data|, parses the 54// "Data" of the box and put it in |pssh_data|. Returns true if such a box is 55// found and successfully parsed. Returns false otherwise. 56// Notes: 57// 1, If multiple PSSH boxes are found,the "Data" of the first matching PSSH box 58// will be set in |pssh_data|. 59// 2, Only PSSH and TENC boxes are allowed in |data|. TENC boxes are skipped. 60static bool GetPsshData(const uint8* data, int data_size, 61 const std::vector<uint8>& uuid, 62 std::vector<uint8>* pssh_data) { 63 const uint8* cur = data; 64 const uint8* data_end = data + data_size; 65 int bytes_left = data_size; 66 67 while (bytes_left > 0) { 68 const uint8* box_head = cur; 69 70 if (bytes_left < kBoxHeaderSize) 71 return false; 72 73 uint64_t box_size = ReadUint32(cur); 74 uint32 type = ReadUint32(cur + 4); 75 cur += kBoxHeaderSize; 76 bytes_left -= kBoxHeaderSize; 77 78 if (box_size == 1) { // LargeSize is present. 79 if (bytes_left < kBoxLargeSizeSize) 80 return false; 81 82 box_size = ReadUint64(cur); 83 cur += kBoxLargeSizeSize; 84 bytes_left -= kBoxLargeSizeSize; 85 } else if (box_size == 0) { 86 box_size = bytes_left + kBoxHeaderSize; 87 } 88 89 const uint8* box_end = box_head + box_size; 90 if (data_end < box_end) 91 return false; 92 93 if (type == kTencType) { 94 // Skip 'tenc' box. 95 cur = box_end; 96 bytes_left = data_end - cur; 97 continue; 98 } else if (type != kPsshType) { 99 return false; 100 } 101 102 const int kPsshBoxMinimumSize = 103 kPsshVersionFlagSize + kPsshSystemIdSize + kPsshDataSizeSize; 104 if (box_end < cur + kPsshBoxMinimumSize) 105 return false; 106 107 uint32 version_and_flags = ReadUint32(cur); 108 cur += kPsshVersionFlagSize; 109 bytes_left -= kPsshVersionFlagSize; 110 if (version_and_flags != 0) 111 return false; 112 113 DCHECK_GE(bytes_left, kPsshSystemIdSize); 114 if (!std::equal(uuid.begin(), uuid.end(), cur)) { 115 cur = box_end; 116 bytes_left = data_end - cur; 117 continue; 118 } 119 120 cur += kPsshSystemIdSize; 121 bytes_left -= kPsshSystemIdSize; 122 123 uint32 data_size = ReadUint32(cur); 124 cur += kPsshDataSizeSize; 125 bytes_left -= kPsshDataSizeSize; 126 127 if (box_end < cur + data_size) 128 return false; 129 130 pssh_data->assign(cur, cur + data_size); 131 return true; 132 } 133 134 return false; 135} 136 137// static 138bool MediaDrmBridge::IsAvailable() { 139 return false; 140} 141 142MediaDrmBridge* MediaDrmBridge::Create(int media_keys_id, 143 const std::vector<uint8>& uuid, 144 MediaPlayerManager* manager) { 145 if (!IsAvailable()) 146 return NULL; 147 148 // TODO(qinmin): check whether the uuid is valid. 149 return new MediaDrmBridge(media_keys_id, uuid, manager); 150} 151 152MediaDrmBridge::MediaDrmBridge(int media_keys_id, 153 const std::vector<uint8>& uuid, 154 MediaPlayerManager* manager) 155 : media_keys_id_(media_keys_id), uuid_(uuid), manager_(manager) { 156 // TODO(qinmin): pass the uuid to DRM engine. 157} 158 159MediaDrmBridge::~MediaDrmBridge() {} 160 161bool MediaDrmBridge::GenerateKeyRequest(const std::string& type, 162 const uint8* init_data, 163 int init_data_length) { 164 std::vector<uint8> pssh_data; 165 if (!GetPsshData(init_data, init_data_length, uuid_, &pssh_data)) 166 return false; 167 168 NOTIMPLEMENTED(); 169 return false; 170} 171 172void MediaDrmBridge::CancelKeyRequest(const std::string& session_id) { 173 NOTIMPLEMENTED(); 174} 175 176void MediaDrmBridge::AddKey(const uint8* key, int key_length, 177 const uint8* init_data, int init_data_length, 178 const std::string& session_id) { 179 NOTIMPLEMENTED(); 180} 181 182ScopedJavaLocalRef<jobject> MediaDrmBridge::GetMediaCrypto() { 183 NOTIMPLEMENTED(); 184 return ScopedJavaLocalRef<jobject>(); 185} 186 187void MediaDrmBridge::OnKeyMessage(JNIEnv* env, 188 jobject j_media_drm, 189 jstring j_session_id, 190 jbyteArray j_message, 191 jstring j_destination_url) { 192 std::string session_id = ConvertJavaStringToUTF8(env, j_session_id); 193 std::vector<uint8> message; 194 JavaByteArrayToByteVector(env, j_message, &message); 195 std::string destination_url = ConvertJavaStringToUTF8(env, j_destination_url); 196 197 manager_->OnKeyMessage(media_keys_id_, session_id, message, destination_url); 198} 199 200void MediaDrmBridge::OnDrmEvent(JNIEnv* env, 201 jobject j_media_drm, 202 jstring session_id, 203 jint event, 204 jint extra, 205 jstring data) { 206 NOTIMPLEMENTED(); 207} 208 209} // namespace media 210