Home | History | Annotate | Download | only in media
      1 // Copyright 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 "chrome/renderer/media/chrome_key_systems.h"
      6 
      7 #include <string>
      8 #include <vector>
      9 
     10 #include "base/logging.h"
     11 #include "base/strings/string16.h"
     12 #include "base/strings/string_split.h"
     13 #include "base/strings/utf_string_conversions.h"
     14 #include "chrome/common/render_messages.h"
     15 #include "components/cdm/renderer/widevine_key_systems.h"
     16 #include "content/public/renderer/render_thread.h"
     17 
     18 #if defined(OS_ANDROID)
     19 #include "components/cdm/renderer/android_key_systems.h"
     20 #endif
     21 
     22 #include "widevine_cdm_version.h" // In SHARED_INTERMEDIATE_DIR.
     23 
     24 // The following must be after widevine_cdm_version.h.
     25 
     26 #if defined(WIDEVINE_CDM_AVAILABLE) && defined(WIDEVINE_CDM_MIN_GLIBC_VERSION)
     27 #include <gnu/libc-version.h>
     28 #include "base/version.h"
     29 #endif
     30 
     31 using content::KeySystemInfo;
     32 using content::SupportedCodecs;
     33 
     34 #if defined(ENABLE_PEPPER_CDMS)
     35 static bool IsPepperCdmAvailable(
     36     const std::string& pepper_type,
     37     std::vector<base::string16>* additional_param_names,
     38     std::vector<base::string16>* additional_param_values) {
     39   bool is_available = false;
     40   content::RenderThread::Get()->Send(
     41       new ChromeViewHostMsg_IsInternalPluginAvailableForMimeType(
     42           pepper_type,
     43           &is_available,
     44           additional_param_names,
     45           additional_param_values));
     46 
     47   return is_available;
     48 }
     49 
     50 // External Clear Key (used for testing).
     51 static void AddExternalClearKey(
     52     std::vector<KeySystemInfo>* concrete_key_systems) {
     53   static const char kExternalClearKeyKeySystem[] =
     54       "org.chromium.externalclearkey";
     55   static const char kExternalClearKeyDecryptOnlyKeySystem[] =
     56       "org.chromium.externalclearkey.decryptonly";
     57   static const char kExternalClearKeyFileIOTestKeySystem[] =
     58       "org.chromium.externalclearkey.fileiotest";
     59   static const char kExternalClearKeyInitializeFailKeySystem[] =
     60       "org.chromium.externalclearkey.initializefail";
     61   static const char kExternalClearKeyCrashKeySystem[] =
     62       "org.chromium.externalclearkey.crash";
     63   static const char kExternalClearKeyPepperType[] =
     64       "application/x-ppapi-clearkey-cdm";
     65 
     66   std::vector<base::string16> additional_param_names;
     67   std::vector<base::string16> additional_param_values;
     68   if (!IsPepperCdmAvailable(kExternalClearKeyPepperType,
     69                             &additional_param_names,
     70                             &additional_param_values)) {
     71     return;
     72   }
     73 
     74   KeySystemInfo info(kExternalClearKeyKeySystem);
     75 
     76   info.supported_codecs = content::EME_CODEC_WEBM_ALL;
     77 #if defined(USE_PROPRIETARY_CODECS)
     78   info.supported_codecs |= content::EME_CODEC_MP4_ALL;
     79 #endif  // defined(USE_PROPRIETARY_CODECS)
     80 
     81   info.pepper_type = kExternalClearKeyPepperType;
     82 
     83   concrete_key_systems->push_back(info);
     84 
     85   // Add support of decrypt-only mode in ClearKeyCdm.
     86   info.key_system = kExternalClearKeyDecryptOnlyKeySystem;
     87   concrete_key_systems->push_back(info);
     88 
     89   // A key system that triggers FileIO test in ClearKeyCdm.
     90   info.key_system = kExternalClearKeyFileIOTestKeySystem;
     91   concrete_key_systems->push_back(info);
     92 
     93   // A key system that Chrome thinks is supported by ClearKeyCdm, but actually
     94   // will be refused by ClearKeyCdm. This is to test the CDM initialization
     95   // failure case.
     96   info.key_system = kExternalClearKeyInitializeFailKeySystem;
     97   concrete_key_systems->push_back(info);
     98 
     99   // A key system that triggers a crash in ClearKeyCdm.
    100   info.key_system = kExternalClearKeyCrashKeySystem;
    101   concrete_key_systems->push_back(info);
    102 }
    103 
    104 #if defined(WIDEVINE_CDM_AVAILABLE)
    105 // This function finds "codecs" and parses the value into the vector |codecs|.
    106 // Converts the codec strings to UTF-8 since we only expect ASCII strings and
    107 // this simplifies the rest of the code in this file.
    108 void GetSupportedCodecsForPepperCdm(
    109     const std::vector<base::string16>& additional_param_names,
    110     const std::vector<base::string16>& additional_param_values,
    111     std::vector<std::string>* codecs) {
    112   DCHECK(codecs->empty());
    113   DCHECK_EQ(additional_param_names.size(), additional_param_values.size());
    114   for (size_t i = 0; i < additional_param_names.size(); ++i) {
    115     if (additional_param_names[i] ==
    116         base::ASCIIToUTF16(kCdmSupportedCodecsParamName)) {
    117       const base::string16& codecs_string16 = additional_param_values[i];
    118       std::string codecs_string;
    119       if (!base::UTF16ToUTF8(codecs_string16.c_str(),
    120                              codecs_string16.length(),
    121                              &codecs_string)) {
    122         DLOG(WARNING) << "Non-UTF-8 codecs string.";
    123         // Continue using the best effort conversion.
    124       }
    125       base::SplitString(codecs_string,
    126                         kCdmSupportedCodecsValueDelimiter,
    127                         codecs);
    128       break;
    129     }
    130   }
    131 }
    132 
    133 static void AddPepperBasedWidevine(
    134     std::vector<KeySystemInfo>* concrete_key_systems) {
    135 #if defined(WIDEVINE_CDM_MIN_GLIBC_VERSION)
    136   Version glibc_version(gnu_get_libc_version());
    137   DCHECK(glibc_version.IsValid());
    138   if (glibc_version.IsOlderThan(WIDEVINE_CDM_MIN_GLIBC_VERSION))
    139     return;
    140 #endif  // defined(WIDEVINE_CDM_MIN_GLIBC_VERSION)
    141 
    142   std::vector<base::string16> additional_param_names;
    143   std::vector<base::string16> additional_param_values;
    144   if (!IsPepperCdmAvailable(kWidevineCdmPluginMimeType,
    145                             &additional_param_names,
    146                             &additional_param_values)) {
    147     DVLOG(1) << "Widevine CDM is not currently available.";
    148     return;
    149   }
    150 
    151   std::vector<std::string> codecs;
    152   GetSupportedCodecsForPepperCdm(additional_param_names,
    153                                  additional_param_values,
    154                                  &codecs);
    155 
    156   SupportedCodecs supported_codecs = content::EME_CODEC_NONE;
    157   for (size_t i = 0; i < codecs.size(); ++i) {
    158     if (codecs[i] == kCdmSupportedCodecVorbis)
    159       supported_codecs |= content::EME_CODEC_WEBM_VORBIS;
    160     if (codecs[i] == kCdmSupportedCodecVp8)
    161       supported_codecs |= content::EME_CODEC_WEBM_VP8;
    162     if (codecs[i] == kCdmSupportedCodecVp9)
    163       supported_codecs |= content::EME_CODEC_WEBM_VP9;
    164 #if defined(USE_PROPRIETARY_CODECS)
    165     if (codecs[i] == kCdmSupportedCodecAac)
    166       supported_codecs |= content::EME_CODEC_MP4_AAC;
    167     if (codecs[i] == kCdmSupportedCodecAvc1)
    168       supported_codecs |= content::EME_CODEC_MP4_AVC1;
    169 #endif  // defined(USE_PROPRIETARY_CODECS)
    170   }
    171 
    172   cdm::AddWidevineWithCodecs(cdm::WIDEVINE,
    173                              supported_codecs,
    174                              concrete_key_systems);
    175 }
    176 #endif  // defined(WIDEVINE_CDM_AVAILABLE)
    177 #endif  // defined(ENABLE_PEPPER_CDMS)
    178 
    179 void AddChromeKeySystems(std::vector<KeySystemInfo>* key_systems_info) {
    180 #if defined(ENABLE_PEPPER_CDMS)
    181   AddExternalClearKey(key_systems_info);
    182 
    183 #if defined(WIDEVINE_CDM_AVAILABLE)
    184   AddPepperBasedWidevine(key_systems_info);
    185 #endif  // defined(WIDEVINE_CDM_AVAILABLE)
    186 #endif  // defined(ENABLE_PEPPER_CDMS)
    187 
    188 #if defined(OS_ANDROID)
    189   cdm::AddAndroidWidevine(key_systems_info);
    190 #endif  // defined(OS_ANDROID)
    191 }
    192