Home | History | Annotate | Download | only in android
      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 
     12 using base::android::ConvertJavaStringToUTF8;
     13 using base::android::JavaByteArrayToByteVector;
     14 using base::android::ScopedJavaLocalRef;
     15 
     16 namespace media {
     17 
     18 static 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 
     25 static 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 // }
     45 static const int kBoxHeaderSize = 8;  // Box's header contains Size and Type.
     46 static const int kBoxLargeSizeSize = 8;
     47 static const int kPsshVersionFlagSize = 4;
     48 static const int kPsshSystemIdSize = 16;
     49 static const int kPsshDataSizeSize = 4;
     50 static const uint32 kTencType = 0x74656e63;
     51 static 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.
     60 static 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
    138 bool MediaDrmBridge::IsAvailable() {
    139   return false;
    140 }
    141 
    142 MediaDrmBridge* 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 
    152 MediaDrmBridge::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 
    159 MediaDrmBridge::~MediaDrmBridge() {}
    160 
    161 bool 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 
    172 void MediaDrmBridge::CancelKeyRequest(const std::string& session_id) {
    173   NOTIMPLEMENTED();
    174 }
    175 
    176 void 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 
    182 ScopedJavaLocalRef<jobject> MediaDrmBridge::GetMediaCrypto() {
    183   NOTIMPLEMENTED();
    184   return ScopedJavaLocalRef<jobject>();
    185 }
    186 
    187 void 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 
    200 void 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