2015-11-10 11 views
0

В настоящее время я изучаю тему шифрования и воспроизведения зашифрованных видео в браузере. У меня уже есть некоторые успехи с DRMToday и Shaka Player от Castlabs при использовании Widevine.Как зашифровать файл WebM или MP4 с помощью ClearKey, а затем воспроизвести его

Теперь я пытаюсь зашифровать видео без внешних сервисов с помощью ClearKey и воспроизводить его в Chrome (используя любой js-плеер, который может обрабатывать).

Мне удалось зашифровать один файл mp4 с помощью MP4Box (и mse-eme для создания конфигурации crypt), но я понятия не имею, как играть в браузере. Видео HTML5 даже не вызывало на нем «зашифрованное» событие. Шифрование работает отлично - я смог расшифровать его с помощью того же инструмента с правильным ключом.

Я попытался создать DASH из этого зашифрованного файла и сыграть его в Shaka Player. Я создал манифест, используя MP4Box. Мне пришлось вручную добавить отсутствующий xmlns в этот файл (xmlns: cenc = "urn: mpeg: cenc: 2013"), поэтому DOMParser тщательно анализирует его. Я не знаю, как мне обращаться с лицензией.

Я нашел несколько рабочих примеров игры в закодированные веб-файлы (включая демонстрационную страницу Shaka Player). Как я могу зашифровать веб-файл? Я нашел https://github.com/webmproject/webm-tools, но, похоже, для того, чтобы работать, требуется построить весь Хром.

Есть ли другие инструменты, которые могут шифровать файлы в Интернете?

+0

Здравствуйте, Вы еще не решили проблему? Я смотрю на тебя так же. –

+0

На данный момент я закончил использование widevine с инструментами bento4 (для создания зашифрованных тире файлов) и внешним сервисом ezdrm, который не был бы моей первой рекомендацией. Вам нужна третья сторона для широкой публики. Вы можете напрямую обращаться к Google, но оплата стороннего провайдера намного дешевле. – Xander

+0

Я не следовал теме Clear Key. – Xander

ответ

1

Вы можете использовать Azure Media Services для динамического шифрования многоразрядного MP4 с помощью ключа AES в разных потоковых протоколах (HLS, Smooth Streaming и MPEG-DASH). Вам не нужно самостоятельно создавать шифровщик. У нас также есть плеер для воспроизведения зашифрованного содержимого AES во всех браузерах - например, AES с DASH в современных браузерах, AES с HLS в Safari и AES с плавным потоком с Flash в старых браузерах.

Вы можете посмотреть пример здесь: http://amsplayer.azurewebsites.net/azuremediaplayer.html. И выберите поток проб, связанных с AES. Вы можете настроить шифрование AES для своего видео, следуя этому руководству: https://azure.microsoft.com/en-us/documentation/articles/media-services-protect-with-aes128/.

1

Это мой набор файлов для тестирования воспроизведения ClearKey DRM.

Файл спецификации mp4box (gpac) drm.xml, где вы можете дать одну или несколько таблиц PSSH для создания внутри сегментов init.mp4.

<?xml version="1.0" encoding="UTF-8" ?> 
<GPACDRM type="CENC AES-CTR"> 
<!-- 
    kid=0x43215678123412341234123412341234 
    key=0x12341234123412341234123412341234 
    iv=0x22ee7d4745d3a26a 
--> 

<!-- CENC --> 
<DRMInfo type="pssh" version="1"> 
    <BS ID128="1077efecc0b24d02ace33c1e52e2fb4b"/> 
    <BS bits="32" value="1"/> 
    <BS ID128="43215678123412341234123412341234"/> 
</DRMInfo> 

<CrypTrack trackID="1" IsEncrypted="1" IV_size="8" first_IV="0x22ee7d4745d3a26a" saiSavedBox="senc"> 
    <key KID="0x43215678123412341234123412341234" value="0x12341234123412341234123412341234"/> 
</CrypTrack> 

</GPACDRM> 

командной строки для шифрования видео + аудио и разделения сегментов.

MP4Box.exe -crypt gpacdrm.xml temp-v1.mp4 -out ./drm/temp-v1.mp4 
MP4Box.exe -crypt gpacdrm.xml temp-a1.mp4 -out ./drm/temp-a1.mp4 
MP4Box.exe -dash 6000 -frag 6000 -mem-frags -rap -profile dashavc264:live -profile-ext urn:hbbtv:dash:profile:isoff-live:2012 -min-buffer 3000 -bs-switching no -sample-groups-traf -single-traf -subsegs-per-sidx 1 -segment-name $RepresentationID$_$Number$$Init=i$ -segment-timeline -out manifest.mpd temp-v1.mp4#trackID=1:id=v1:period=p0 temp-a1.mp4#trackID=1:id=a1:period=p0 

ShakaPlayer автономный демо для воспроизведения ClearKey, использовать Chrome или Firefox. Я нашел этот исходный код в Интернете, так что кредиты тому, кто это сделал.

<!DOCTYPE html> 
<html> 
<head> 
    <meta charset="utf-8" /> 
    <script src="https://cdnjs.cloudflare.com/ajax/libs/shaka-player/2.1.0/shaka-player.compiled.js"></script> 
    <title>MPEG-DASH Player Test</title> 
    <script> 
     var manifestUrl = 'https://my.server.com/drm/manifest_clearkey.mpd'; 
     var laUrl  = 'https://my.server.com/drm/laurl_ck.php'; 

     function initApp() { 
      // Install built-in polyfills to patch browser incompatibilities. 
      shaka.polyfill.installAll(); 

      // Check to see if the browser supports the basic APIs Shaka needs. 
      if (shaka.Player.isBrowserSupported()) { 
       // Everything looks good! 
       initPlayer(); 
      } else { 
       // This browser does not have the minimum set of APIs we need. 
       console.error('Browser not supported!'); 
      } 
     } 

     function initPlayer() { 
      // Create a Player instance. 
      var video = document.getElementById('video'); 
      var player = new shaka.Player(video); 

      // Configue 
      player.configure({ 
       drm: { 
        servers: { 
         'org.w3.clearkey': laUrl 
        }, 
        clearKeys: { 
         //'kid': 'key' 
        } 
       } 
      }); 

      // Attach player to the window to make it easy to access in the JS console. 
      window.player = player; 

      // Listen for error events. 
      player.addEventListener('error', onErrorEvent); 

      // Try to load a manifest. 
      // This is an asynchronous process. 
      player.load(manifestUrl).then(function() { 
       // This runs if the asynchronous load is successful. 
       console.log('The video has now been loaded!'); 
      }).catch(onError); // onError is executed if the asynchronous load fails. 
     } 

     function onErrorEvent(event) { 
      // Extract the shaka.util.Error object from the event. 
      onError(event.detail); 
     } 

     function onError(error) { 
      console.error('Error code', error.code, 'object', error); 
      alert("ErrorCode="+error.code); 
     } 

     document.addEventListener('DOMContentLoaded', initApp); 
    </script> 
</head> 
<body> 
    <video id="video" autoplay controls></video> 
</body> 
</html> 

ClearKey DRM "PHP скрипт сервера лицензий", игрок посылает JSon документ и этот скрипт возвращает KID = KEY спаривание.

<?php 
header("Expires: Mon, 20 Dec 1998 01:00:00 GMT"); 
header("Last-Modified: " . gmdate("D, d M Y H:i:s") . " GMT"); 
header("Cache-Control: no-cache, must-revalidate"); 
header("Pragma: no-cache"); 
header('Access-Control-Allow-Origin: *'); 
header('Access-Control-Allow-Headers: origin,range,accept,accept-encoding,referer,content-type, SOAPAction,X-AxDRM-Message'); 
header('Access-Control-Allow-Methods: GET,HEAD,OPTIONS,POST'); 
header('Access-Control-Expose-Headers: server,range,content-range,content-length,content-type'); 
// write content-type header after OPTIONS check 
// ClearKey DRM server 

// some players may submit OPTIONS request(zero-length) before POST drm.xml submit 
if ($_SERVER['REQUEST_METHOD']=="OPTIONS") { 
    header("Content-Length: 0"); 
    header("Expires: -1"); 
    return; 
} 
//header('Content-Type: text/plain; charset=utf-8'); 
header('Content-Type: application/json; charset=utf-8'); 

// Request may have one or more KIDs(base64), read first KID from the request for now. 
// KID base64 is without trailing "=" padding chars. 
// Request : {"kids":["QyFWeBI0EjQSNBI0EjQSNA"],"type":"temporary"} 
// Response: {"keys": [{"k": "EjQSNBI0EjQSNBI0EjQSNA", "kty": "oct", "kid": "QyFWeBI0EjQSNBI0EjQSNA" }], "type": "temporary"} 
$req = file_get_contents('php://input'); // read POST bodypart 
$json= json_decode($req); 
$kidb= $json->{"kids"}[0]; // base64 format 
$kid = bin2hex(base64_decode($kidb, true)); // hex format 

// KID=KEY lookup table, find KEY and base64(trim trailing "==" chars) 
// "EjQSNBI0EjQSNBI0EjQSNA==" -> "EjQSNBI0EjQSNBI0EjQSNA" 
$keys = array(
    "43215678123412341234123412341234" => "12341234123412341234123412341234", 
    "43215678123412341234123412341235" => "12341234123412341234123412341235", 
    "43215678123412341234123412341236" => "12341234123412341234123412341236", 
    "43215678123412341234123412341237" => "12341234123412341234123412341237", 
    "43215678123412341234123412341238" => "12341234123412341234123412341238" 
); 
$key = base64_encode(hex2bin($keys[$kid])); 
$key = str_replace("=", "", $key); 

$data = "{\"keys\": [{\"k\": \$key, \"kty\": \"oct\", \"kid\": \$kid }], \"type\": \"temporary\"}"; 
$data = str_replace("\$key", "\"".$key."\"", $data); 
$data = str_replace("\$kid", "\"".$kidb."\"", $data); 

echo $data; 

?> 

манифеста с Cenc и ClearKey элементов contentprotection.

<?xml version="1.0" encoding="UTF-8"?> 
<MPD xmlns="urn:mpeg:dash:schema:mpd:2011" xmlns:cenc="urn:mpeg:cenc:2013" xmlns:mas="urn:marlin:mas:1-0:services:schemas:mpd" xmlns:mspr="urn:microsoft:playready" maxSegmentDuration="PT0H0M6.000S" mediaPresentationDuration="PT0H1M30.000S" minBufferTime="PT3.000S" profiles="urn:mpeg:dash:profile:isoff-live:2011,http://dashif.org/guidelines/dash264,urn:hbbtv:dash:profile:isoff-live:2012" type="static"> 


<Period duration="PT0H1M30.000S" id="p0"> 
    <AdaptationSet lang="und" maxFrameRate="25" maxHeight="360" maxWidth="640" par="16:9" segmentAlignment="true" startWithSAP="1"> 
    <ContentProtection cenc:default_KID="43215678-1234-1234-1234-123412341234" schemeIdUri="urn:mpeg:dash:mp4protection:2011" value="cenc"/> 
<ContentProtection schemeIdUri="urn:uuid:1077efec-c0b2-4d02-ace3-3c1e52e2fb4b"> 
    <cenc:pssh>AAAANHBzc2gBAAAAEHfv7MCyTQKs4zweUuL7SwAAAAFDIVZ4EjQSNBI0EjQSNBI0AAAAAA==</cenc:pssh> 
</ContentProtection> 
    <SegmentTemplate initialization="$RepresentationID$_i.mp4" media="$RepresentationID$_$Number$.m4s" startNumber="1" timescale="1000"> 
    <SegmentTimeline> 
    <S d="6000" r="14" t="0"/> 
    </SegmentTimeline> 
    </SegmentTemplate> 
    <Representation bandwidth="491773" codecs="avc1.4D4028" frameRate="25" height="360" id="v1" mimeType="video/mp4" sar="1:1" width="640"> 
    </Representation> 
    </AdaptationSet> 
    <AdaptationSet lang="und" segmentAlignment="true" startWithSAP="1"> 
    <ContentProtection cenc:default_KID="43215678-1234-1234-1234-123412341234" schemeIdUri="urn:mpeg:dash:mp4protection:2011" value="cenc"/> 
<ContentProtection schemeIdUri="urn:uuid:1077efec-c0b2-4d02-ace3-3c1e52e2fb4b"> 
    <cenc:pssh>AAAANHBzc2gBAAAAEHfv7MCyTQKs4zweUuL7SwAAAAFDIVZ4EjQSNBI0EjQSNBI0AAAAAA==</cenc:pssh> 
</ContentProtection> 
    <SegmentTemplate initialization="$RepresentationID$_i.mp4" media="$RepresentationID$_$Number$.m4s" startNumber="1" timescale="1000"> 
    <SegmentTimeline> 
    <S d="5973" t="0"/> 
    <S d="5995" r="1"/> 
    <S d="5994"/> 
    <S d="5995" r="1"/> 
    <S d="5994"/> 
    <S d="5995"/> 
    <S d="5994"/> 
    <S d="5995" r="2"/> 
    <S d="5994"/> 
    <S d="5995" r="1"/> 
    <S d="101"/> 
    </SegmentTimeline> 
    </SegmentTemplate> 
    <Representation audioSamplingRate="48000" bandwidth="133119" codecs="mp4a.40.2" id="a1" mimeType="audio/mp4"> 
    <AudioChannelConfiguration schemeIdUri="urn:mpeg:dash:23003:3:audio_channel_configuration:2011" value="2"/> 
    </Representation> 
    </AdaptationSet> 
</Period> 
</MPD> 

Manifest Cenc: pssh содержит значения KID и легко произвести, если используется только один ключ. См. Этот base64tohexdump значения элемента pssh.

00 00 00 34 70 73 73 68 01 00 00 00 
10 77 EF EC C0 B2 4D 02 AC E3 3C 1E 52 E2 FB 4B 
00 00 00 01 
43 21 56 78 12 34 12 34 12 34 12 34 12 34 12 34 
00 00 00 00