我目前正在研究在浏览器中加密和播放加密视频的主题。在使用Widevine时,我已经在castlabs的DRMToday和Shaka播放器上取得了一些成功。
现在我正尝试在没有外部服务的情况下使用ClearKey加密视频,并在Chrome中播放(使用任何可以处理的js播放器)。
我确实设法使用MP4Box加密了单个mp4文件(以及用于创建加密配置的mse-eme ),但我不知道如何在浏览器中播放它。HTML5的视频甚至没有触发“加密”事件。加密本身运行良好-我能够使用相同的工具使用适当的密钥解密它。
我试图从这个加密文件中创建一个破折号,并在Shaka播放器中播放它。我使用MP4Box创建了清单。我必须手动添加一个缺失的xmlns到这个文件(xmlns:cenc="urn:mpeg:cenc:2013"),这样DOMParser才能正确地解析它。我不知道该怎么办理驾照。
我发现播放编码的webm文件的工作示例很少(包括Shaka Player的演示页面)。如何加密webm文件?我确实找到了https://github.com/webmproject/webm-tools,但它似乎需要构建整个Chromium才能工作。
有没有其他工具可以加密webm文件?
发布于 2017-10-24 03:29:19
这是我测试ClearKey数字版权管理播放的一组文件。
mp4box(gpac) drm.xml规范文件,您可以在其中给出一个或多个要在init.mp4段内生成的drm.xml表。
<?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>用于加密video+audio和拆分数据段的命令行。
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=p0ShakaPlayer独立演示用于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 "license server php script",播放器发送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内容保护元素的清单。
<?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>pssh:包含KID值,如果只使用一个密钥,则很容易生成。查看此base64tohexdump of 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发布于 2016-01-22 13:12:48
你可以使用Azure Media Services在不同的流协议(HLS,平滑流和MPEG-DASH)中使用AES clear key动态加密多比特率MP4。您不必自己构建加密器。我们还有一个播放器可以在所有浏览器中播放AES加密内容-例如,在现代浏览器中使用DASH的AES,在Safari中使用HLS的AES,以及在旧浏览器中使用Flash的平滑流式处理的AES。
你可以在这里查看一个例子:http://amsplayer.azurewebsites.net/azuremediaplayer.html。并选择与AES相关的样本流。您可以按照以下教程为视频配置AES加密:https://azure.microsoft.com/en-us/documentation/articles/media-services-protect-with-aes128/。
发布于 2019-11-18 16:13:42
具体回答“ChromeHTML5的视频甚至没有在上面触发"encrypted”事件。“-在2019年,将不会触发onencrypted事件,除非MSE与视频一起使用,并且火狐显示一个错误,表明没有MSE EME不起作用。所以要播放加密的视频,必须使用媒体源扩展。
这在文档中并不明显,但在https://github.com/cpearce/eme-in-non-fragmented-mp4中突出显示了这一点
有了一个正确加密的媒体,你可以在MSE中添加一个单独的MP4文件作为“片段”,并在chrome中播放(例如,使用这个https://github.com/cpearce/mse-eme的修改版本)(我的测试只是明码,使用bento4来第一个片段,然后加密单个MP4文件-不要混淆片段和片段....)。这不是很高效,因为我假设在播放开始之前整个文件已经下载(并保存在浏览器内存中),也就是说,它不像直接的html5视频元素播放,浏览器使用范围请求并管理文件下载和内存使用。
https://stackoverflow.com/questions/33632240
复制相似问题