Nginx教程

使用nginx搭建音视频点播服务——基于DASH协议

本文主要是介绍使用nginx搭建音视频点播服务——基于DASH协议,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

文章目录

    • 1 DASH流媒体协议
    • 2 搭建点播服务
      • 2.1 nginx代理
      • 2.2 nginx-vod-module模块
      • 2.3 配置nginx下的DASH点播服务
        • 2.3.1 常规配置
        • 2.3.2 多码率自适应配置
      • 2.4 使用shakaplayer播放DASH流
        • 2.4.1 编译安装shakaplayer
        • 2.4.2 使用shakaplayer播放DASH流
    • 3 DRM加密
      • 3.1 常规DRM配置
        • 3.1.1 搭建DRM秘钥服务器
          • 3.1.1.1 加密秘钥的形式
          • 3.1.1.2 解密秘钥的形式
        • 3.1.2 视频内容服务器端添加DRM配置(加密用)
        • 3.1.3 播放器端添加DRM配置(解密用)
      • 3.2 多码率自适应下的DRM加密
        • 3.2.1 DRM秘钥服务器配置
        • 3.2.2 视频内容服务器配置
    • 4 附加补充:mpd清单文件相关内容

  前一段研究过HLS协议下的点播服务,与本文介绍的DASH协议下搭建所使用的nginx模块是同一个,可以参考 使用nginx搭建音视频点播服务器——基于HLS协议 1

1 DASH流媒体协议

  DASH的全称是Dynamic Adaptive Streaming Over HTTP,是一种自适应比特率流媒体技术。与苹果的HTTP Live Streaming(HLS)技术相似,通过把内容分割成小的基于HTTP的文件段序列,来进行流媒体播放。MPEG(Moving Picture Experts Group,动态图像专家组)是一个针对音视频压缩的国际标准化组织,为了寻求HLS的替代方案而推出了MPEG-DASH标准,MPEG-DASH作为一种基于HTTP的自适应码率的流媒体传输解决方案,在2012年由ISO/IEC发表,正式成为国际标准。

DASH的优点:

  1. DASH是MPEG组织定义的国际开放标准,对业界的各种技术进行规范整合,得到众多公司的支持,其中也包括拥有HLS的Apple。
  2. DASH由于其开放性,围绕其产生了一系列开源软件,有利于DASH技术的推广。
  3. DASH不指定特定的编解码器,它与编解码器无关,即内容供应商只需要提供一种视频格式,不用考虑其兼容性问题。
  4. DASH与HLS一样基于HTTP,不用考虑防火墙或者代理的问题。
  5. DASH可以很容易的支持播放中的多音轨、多视频轨、多字幕轨的切换。

目前在使用DASH协议的视频网站比较出名的有BiliBili、YouTube等。

DASH的缺点:

  1. DASH与HLS同为采用切片方式运作的流媒体,都具有一定的端对端延时(6~30s)。
  2. 目前DASH协议的市场占有不高,主要还是HLS的份额,各端对DASH的支持依赖于开源软件的集成,原生支持不够。

其实对于延迟高的问题,DASH与HLS两个协议都发展出了各自的低延迟解决方案,DASH协议有DASH-LL,HLS协议有LL-HLS2和LHLS,本文暂不讨论。

2 搭建点播服务

2.1 nginx代理

  nginx是一个代理服务器,首先需要在Linux上搭建nginx服务,具体的流程可以参考nginx的安装流程3,搭建视频点播服务器会用到nginx-vod-module模块,按照安装流程添加该模块到nginx中,搭建点播服务使用的具体环境如下:

系统版本:CentOS Linux release 7.9 2009(Core)
nginx版本:1.20.1
nginx-vod-module版本:1.29

2.2 nginx-vod-module模块

  nginx-vod-module模块是基于nginx来提供VOD(video on demand)服务的第三方模块,它支持基于DASH、HDS、HLS、MSS的点播服务搭建。

nginx-vod-module下载地址:https://github.com/kaltura/nginx-vod-module/archive/refs/tags/1.29.tar.gz

在nginx进行安装配置的过程中,需要使用--add-module=选项来添加第三方模块一起进行编译,相关的步骤可以参考模块的github网址:

nginx-vod-module的github网址:https://github.com/kaltura/nginx-vod-module

在配置nginx进行编译的时候使用的配置参数如下:

./configure --prefix=/web/webserver/nginx-vod-hls --with-http_stub_status_module --with-http_ssl_module --with-cc-opt=’-O0 -gstabs+3’ --with-debug --add-module=…/nginx-vod-module-1.29

配置、编译、安装都完成之后,即可在nginx的配置文件中使用nginx-vod-module模块提供的关键字了。

2.3 配置nginx下的DASH点播服务

  此处使用local模式,如果想要使用mapped模式,可以参考使用nginx搭建音视频点播服务——基于HLS协议4中的mapped模式介绍。这里假设部署nginx服务的机器ip地址为192.168.192.128。

2.3.1 常规配置

在nginx的配置文件中,添加对应的location配置:

location /vod_dash {
    vod dash; # 协议使用dash模式
    vod_mode local; # 访问模式指定为local模式

    vod_align_segments_to_key_frames on; # 每个切片以关键帧开头

    vod_dash_manifest_format segmenttemplate; # 在mpd清单文件中使用片段模板的格式
    vod_dash_profiles urn:mpeg:dash:profile:isoff-live:2011; # 在mpd清单文件中指定profile标记

    ## DRM相关配置
    #vod_drm_enabled on;                         # 启用DRM
    #vod_drm_clear_lead_segment_count 0;         # 设置所有切片都需要经过DRM处理
    #vod_drm_upstream_location /php_proxy/;      # 指定DRM地址
    #vod_drm_request_uri /dash_clear_key.php;    # 配置php地址

    #跨域相关配置
    add_header Access-Control-Allow-Headers '*';
    add_header Access-Control-Expose-Headers 'Server,range,Content-Length,Content-Range,Date';
    add_header Access-Control-Allow-Methods 'GET, HEAD, OPTIONS';
    add_header Access-Control-Allow-Origin '*';

    alias /media;
}

## 配置指向DRM服务器地址的location
#location /php_proxy/ {
#    proxy_pass http://192.168.192.182/; # 转发地址指向DRM服务器地址
#    proxy_set_header Host $http_host;
#}

conf文件修改后,nginx需要reload才能使配置生效。

./nginx -s reload

这里还需要特别注意的一点是由于DASH协议的原因,播放地址必须使用https进行访问才能正常播放。

在nginx上配置https服务:
配置教程在网上很多,就不冗余了,略过。

服务器上对应的视频文件目录结构:

/media/example0001.mp4

URL播放地址(https):

https://192.168.192.128/vod_dash/example0001.mp4/manifest.mpd

2.3.2 多码率自适应配置

  多码率自适应指的是在视频播放中自动判断网络状态,在网络状态好的时候播放高码率视频,网络状态差的时候播放低码率的视频,多码率自适应需要在服务器上需要有2个或者2个以上对应的不同码率的视频源。

假设在服务器上对应的视频文件目录结构:

/media/example0001.mp4
/media/example0001_low.mp4

使用nginx-vod-module模块可以自动计算视频对应的带宽并完成清单文件的生成,只需要拼接好对应的URL地址即可,多码率自适应的URL播放地址(https):

https://192.168.192.128/vod_dash/,example0001,example0001_low,.mp4.urlset/manifest.mpd

2.4 使用shakaplayer播放DASH流

  DASH流媒体的播放目前在各端并不是原生支持的,还需要播放器的支持,比较主流的有shakaplayer、Dash.js等,本文使用开源的Html5播放器shakaplayer。

2.4.1 编译安装shakaplayer

  安装shakaplayer之前需要先安装一些工具:Git v1.9+、Python v2.7 or v3.5+、Java Runtime Environment v8+、NodeJS v10+、Apache(A local web server)。

可以参考shakaplayer官网的安装说明https://shaka-player-demo.appspot.com/docs/api/tutorial-welcome.html。

安装Git v1.9+:
用yum安装的git版本太低,需要从https://mirrors.edge.kernel.org/pub/software/scm/git/下载对应版本的源码编译安装。

安装Python v2.7 or v3.5+:
可以用yum安装,如果yum无法使用,也可以从https://www.python.org/downloads/source/下载对应版本的源码编译安装。

安装Java Runtime Environment v8+:
jre需要从https://java.com/en/download/manual.jsp下载对应的版本;
解压后建立软链接ln -s /.../jre1.8.0_321/bin/java /usr/bin/java即可,其中/.../jre1.8.0_321/bin/java为压缩包解压后的目录。

可以参考官网的安装说明https://java.com/en/download/help/linux_x64_install.html#install

安装NodeJS v10+:
可以使用yum安装nodejs,如果yum无法使用,也可以从https://nodejs.org/en/download/下载对应版本的源码编译安装。

nodejs的yum安装步骤:
安装centos-release-scl
    yum install centos-release-scl-rh
安装yum-config-manager命令
    yum install yum-utils
安装RHSCL
    yum-config-manager --enable rhel-server-rhscl-7-rpms
安装nodejs
    yum install rh-nodejs10
启用nodejs
    scl enable rh-nodejs10 bash

可以参考官网的安装说明https://www.softwarecollections.org/en/scls/rhscl/rh-nodejs10/

安装Web Server:
这里直接用nginx即可,运行shakaplayer需要web服务器支持,因为浏览器对来自file:///url的应用程序有限制,所以不能把shakaplayer放在本地运行。

有了上面的工具支持后,就可以安装shakaplayer了:
下载shakaplayer,地址为https://github.com/google/shaka-player/releases;
解压之后进入目录,执行python build/all.py,成功后会在dist目录下会生成shaka-player.compiled.js文件,之后在web中创建shakaplayer播放器时需要依赖该文件。

2.4.2 使用shakaplayer播放DASH流

  在html中包含上一步生成的js文件路径,加载shakaplayer,并指定URL播放地址https://192.168.192.128/vod_dash/example0001.mp4/manifest.mpd(需要使用https),具体细节如下:

<!DOCTYPE html>
<html>

<head>
    <!-- Shaka Player compiled library: -->
    <script src="/html/shaka-player-3.3.0/dist/shaka-player.compiled.js"></script>
</head>

<body>
    <video id="video" width="640" controls autoplay></video>
    <script>
        // 注意这里播放的mpd清单文件需要使用https来访问
        const manifestUri =
            'https://192.168.192.128/vod_dash/example0001.mp4/manifest.mpd';

        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!');
            }
        }

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

            // // 配置DRM
            // player.configure({
            //     drm: {
            //         servers: {
            //             'org.w3.clearkey': 'https://192.168.192.182/dash_clear_key.php'
            //         }
            //     }
            // });

            // 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', one rrorEvent);

            // Try to load a manifest.
            // This is an asynchronous process.
            try {
                await player.load(manifestUri);
                // This runs if the asynchronous load is successful.
                console.log('The video has now been loaded!');
            } catch (e) {
                // one rror is executed if the asynchronous load fails.
                one rror(e);
            }
        }

        function one rrorEvent(event) {
            // Extract the shaka.util.Error object from the event.
            one rror(event.detail);
        }

        function one rror(error) {
            // Log the error.
            console.error('Error code', error.code, 'object', error);
        }

        document.addEventListener('DOMContentLoaded', initApp);
    </script>
</body>

</html>

这样即可在shakaplayer中播放DASH流媒体视频。

3 DRM加密

  DRM即数字版权管理,用于对视频内容进行加密保护,通过DRM技术可以避免内容被下载获取并非法传播,DASH的DRM解决方案有Widevine、PlayReady、ClearKey这几种形式。

Widevine最初由Widevine Technologies开发,于2010年被Google收购,原生支持广泛的设备和浏览器,如Google浏览器,Android,Chromecast等;(商业DRM解决方案)
PlayReady是由Microsoft开发的,是可用的主要DRM系统之一,具有广泛的设备支持;(商业DRM解决方案)
ClearKey是商业解决方案的免费替代品,以下示例使用ClearKey形式的DRM方案。

3.1 常规DRM配置

3.1.1 搭建DRM秘钥服务器

  这里通过部署apache配合php代码来进行DRM服务器的搭建,DRM服务器的作用是提供秘钥服务,收到请求后生成并返回加、解密需要的秘钥。

这里的DRM服务器(192.168.192.182)指的是处理秘钥的服务器,与之前保存视频内容的服务器(192.168.192.128)不是同一个,注意区分。示例中将它们分别部署在了不同的机器上,根据实际情况也可以将秘钥服务和视频内容服务放在同一个服务器上。

安装apache以及php支持:
部署教程在网上很多,就不冗余了,略过。

下面是一段可用的php的代码示例,根据不同的请求方式(POST、GET)向请求者提供加密秘钥和解密秘钥,包含了以逻辑方式(当然更简单的方式也可以直接使用明文)生成加、解密秘钥的方式,简单展示了从32位自定义字符串生成秘钥的过程:

<?php
if (!function_exists('hex2bin'))
{
    function hex2bin($str) 
    {
        $sbin = '';
        $len = strlen($str);
        for ($i = 0; $i < $len; $i += 2) 
        {
            $sbin .= pack('H*', substr($str, $i, 2)); // 每两个字符就打包成一个十六进制串
        }

        return $sbin;
    }
}

// 替换 “-” —> “+” , “_” —> “/”,并进行base64解密
function b64url_dec($s)
{
    return base64_decode(str_replace(array('-', '_'), array('+', '/'), $s), true);
}

// 进行base64加密后,替换 “+” —> “-” , “/” —> “_”,去掉 “=”
function b64url_enc($s)
{
    return str_replace(array('+', '/', '='), array('-', '_', ''), base64_encode($s));
}

function getKey($kid)
{
    // TODO: update secret
    return md5('secret' . $kid, true); // 加上前缀secret,并进行MD5加密
}

// TODO: add security controls and error validation

if ($_SERVER['REQUEST_METHOD'] == 'POST')
{
    // 请求使用POST方式获取解密秘钥
    $req = file_get_contents('php://input');
    $req = json_decode($req);
    $type = $req->type;
    $keys = array();
    foreach ($req->kids as $kid)
    {
        $key = b64url_enc(getKey(b64url_dec($kid)));
        $keys[] = array('k' => $key, 'kty' => 'oct', 'kid' => $kid);
    }

    $res = array('keys' => $keys, 'type' => $type);
    header('access-control-allow-origin: *');
}
else
{
    // 请求使用GET方式获取加密秘钥
    $kid = hex2bin('0123456789abcdef0123456789abcdef'); // TODO: allocate according to media id
    $res = array(array(
        'key' => base64_encode(getKey($kid)),
        'key_id' => base64_encode($kid),
        'pssh' => array(array(
            'uuid' => '1077efec-c0b2-4d02-ace3-3c1e52e2fb4b',
            'data' => base64_encode(hex2bin('00000001') . $kid . hex2bin('00000000'))
        ))
    ));
}

// 转换成json格式输出
echo str_replace('\\/', '/', json_encode($res));
?>
3.1.1.1 加密秘钥的形式

通过GET请求获取的Encryption加密秘钥:

[
    {
        "key":"6JDXwILoGcZuYDKGNPiXgA==",
        "key_id":"ASNFZ4mrze8BI0VniavN7w==",
        "pssh":[
            {
                "uuid":"1077efec-c0b2-4d02-ace3-3c1e52e2fb4b",
                "data":"AAAAAQEjRWeJq83vASNFZ4mrze8AAAAA"
            }
        ]
    }
]

key表示加密秘钥,key_id表示秘钥的id号,pssh是Protection System Specific Header的缩写,pssh是标准化委员会规定的被加密的媒体资源所应该包含相对应的信息,关于标准化委员会规定的更加细节的方面可以查看——国际标准化组织对于流格式的基本媒体文件的通用加密方案(cenc)5。示例中keykey_idpssh->data都由自定义字符串0123456789abcdef0123456789abcdef通过hash生成,通用唯一标识码uuid是固定值。

key值
0123456789abcdef0123456789abcdef    // 自定义串
#Eg����#Eg����            // 按每2位数按照十六进制格式打包到二进制字符串中(二进制不可读)
������n`2�4���         // 加上secret前缀,再进行md5加密(二进制不可读)
6JDXwILoGcZuYDKGNPiXgA==        // 进行base64加密得到key值

key_id值
0123456789abcdef0123456789abcdef    // 自定义串
#Eg����#Eg����            // 按每2位数按照十六进制格式打包到二进制字符串中(二进制不可读)
ASNFZ4mrze8BI0VniavN7w==            // 进行base64加密得到key_id值

pssh->uuid值
1077efec-c0b2-4d02-ace3-3c1e52e2fb4b    // 固定值

pssh->data值
00000001、0123456789abcdef0123456789abcdef、00000000 // 三个自定义串
、#Eg����#Eg����、空值    // 分别按每2位数按照十六进制格式打包到二进制字符串中,并首尾连接在一起(二进制不可读)
AAAAAQEjRWeJq83vASNFZ4mrze8AAAAA // 进行base64加密得到data值
3.1.1.2 解密秘钥的形式

播放时通过POST请求携带kids信息从秘钥服务器获取对应的License解密秘钥。

POST请求携带的kids信息:

{kids: ["ASNFZ4mrze8BI0VniavN7w"], type: "temporary"}

获取的License解密秘钥:

{
    "keys":[
        {
            "k":"6JDXwILoGcZuYDKGNPiXgA",
            "kty":"oct",
            "kid":"ASNFZ4mrze8BI0VniavN7w"
        }
    ],
    "type":"temporary"
}

k表示加密秘钥,kid表示秘钥标号。示例中的k可以由kid转换得到,实际中只要标号与秘钥一一对应即可。

ASNFZ4mrze8BI0VniavN7w          // 解析请求中附带的json数据从kids中获取kid值
#Eg����#Eg����        // "-"转“+”,“_”转“/”,base64解密(二进制不可读)
������n`2�4���         // 加上前缀secret,并进行MD5加密(二进制不可读)
6JDXwILoGcZuYDKGNPiXgA          // 进行base64加密,`+`转`-`,`/`转`_`,去掉`=`得到k值

当前搭建好的DRM服务器的所在的机器ip为192.168.192.182,在之后的nginx配置中会配置该ip。

3.1.2 视频内容服务器端添加DRM配置(加密用)

在nginx中配置并启用DRM,这里添加DRM配置的作用是使nginx-vod-module模块在对原视频进行切片的时候进行加密,并向DASH的清单文件MPD中加入DRM信息。

location /vod_dash {
    ……
    # DRM相关配置
    vod_drm_enabled on;                         # 启用DRM
    vod_drm_clear_lead_segment_count 0;         # 设置所有切片都需要经过DRM处理
    vod_drm_upstream_location /php_proxy/;      # 指定DRM地址
    vod_drm_request_uri /dash_clear_key.php;    # 配置php地址
    ……
}

# 配置指向DRM服务器地址的location
location /php_proxy/ {
    proxy_pass http://192.168.192.182/; # 转发地址指向DRM服务器地址
    proxy_set_header Host $http_host;
}

该段代码在之前nginx的配置中注释掉了,需要使用DRM的时候放开注释即可。

配置好nginx之后,播放时被请求的DASH清单文件MPD(xml格式)中会出现相对应的用ContentProtection字段进行包装的DRM信息。

3.1.3 播放器端添加DRM配置(解密用)

  在shakaplayer上也需要进行一些配置,在player的configure中配置DRM信息,这里添加DRM配置的作用是在shakaplayer播放DASH流的每个切片的之前使用请求到的解密秘钥进行对切片解密。

player.configure({
    drm: {
        servers: {
            'org.w3.clearkey': 'https://192.168.192.182/dash_clear_key.php'
        }
    }
});

需要注意DRM地址也需要使用https,该段代码在之前加载shakaplayer的html中注释掉了,需要使用DRM的时候放开注释即可。

把DRM秘钥服务器、视频内容服务器、播放器三个地方的DRM配置都完成之后,此时播放的媒体流视频已经是经过DRM加密的了,示例使用明文字符串进行简单hash之后进行加、解密,可以通过提高hash函数的复杂性、在URL中加上身份验证等方式继续提高安全性。

播放的媒体内容经过DRM,虽然示例中在播放上看起来并没有什么不同的感觉,但下载保存的内容切片如果不经过DRM的验证则是无法播放的。

3.2 多码率自适应下的DRM加密

  由于多码率自适应需要有2个或者2个以上的视频来支持不同带宽下的播放,出于内容安全的考虑一般情况下会为每个视频配置各自不同的秘钥。

3.2.1 DRM秘钥服务器配置

  为了支持对不同视频使用不同秘钥,需要在DRM服务器配置多组秘钥,以下php代码配置了两组ClearKey秘钥,按照之前的规则生成了两组秘钥,秘钥1是由字符串0123456789abcdef0123456789abcdef所生成,秘钥2是由字符串01234567890123456789abcdefabcdef所生成,为了简单起见,,在返回时直接使用已生成好了的明文进行返回:

<?php

if ($_SERVER['REQUEST_METHOD'] == 'POST')
{
    // get liense
    $key1 = array('k' => '6JDXwILoGcZuYDKGNPiXgA', 'kty' => 'oct', 'kid' => 'ASNFZ4mrze8BI0VniavN7w');
    $key2 = array('k' => 'XHYyt3r8i4EDVtu3HoFl1g', 'kty' => 'oct', 'kid' => 'ASNFZ4kBI0VniavN76vN7w');
    $license = array('keys' => array($key1, $key2), 'type' => 'temporary');
    
    echo str_replace('\\/', '/', json_encode($license));
    header('access-control-allow-origin: *');
}
else
{
    $currentUrl = $_SERVER["REQUEST_URI"];
    
    // get key
    $pssh1 = array('uuid' => '1077efec-c0b2-4d02-ace3-3c1e52e2fb4b', 'data' => 'AAAAAQEjRWeJq83vASNFZ4mrze8AAAAA');
    $encrpytion1 = array('key' => '6JDXwILoGcZuYDKGNPiXgA==', 'key_id' => 'ASNFZ4mrze8BI0VniavN7w==', 'pssh' => array($pssh1));
    
    $pssh2 = array('uuid' => '1077efec-c0b2-4d02-ace3-3c1e52e2fb4b', 'data' => 'AAAAAQEjRWeJASNFZ4mrze+rze8AAAAA');
    $encrpytion2 = array('key' => 'XHYyt3r8i4EDVtu3HoFl1g==', 'key_id' => 'ASNFZ4kBI0VniavN76vN7w==', 'pssh' => array($pssh2));

    if (strpos($currentUrl, 'low') !== false) // URL中包含字符串low,则使用encryption1
        $encrpytion = array($encrpytion1/*, $encrpytion2*/);
    else
        $encrpytion = array($encrpytion2);

    echo str_replace('\\/', '/', json_encode($encrpytion));
}

?>

使用GET进行请求时,会根据URL中是否携带某个字符串(示例中为low),返回不同的加密秘钥:

URL中带low字符串,返回加密秘钥1:

[
    {
        "key": "6JDXwILoGcZuYDKGNPiXgA==",
        "key_id": "ASNFZ4mrze8BI0VniavN7w==",
        "pssh": [
            {
                "uuid": "1077efec-c0b2-4d02-ace3-3c1e52e2fb4b",
                "data": "AAAAAQEjRWeJq83vASNFZ4mrze8AAAAA"
            }
        ]
    }
]

URL中不带low字符串,返回加密秘钥2:

[
    {
        "key": "XHYyt3r8i4EDVtu3HoFl1g==",
        "key_id": "ASNFZ4kBI0VniavN76vN7w==",
        "pssh": [
            {
                "uuid": "1077efec-c0b2-4d02-ace3-3c1e52e2fb4b",
                "data": "AAAAAQEjRWeJASNFZ4mrze+rze8AAAAA"
            }
        ]
    }
]

使用POST进行请求时,会统一返回解密秘钥组:

{
    "keys": [
        {
            "k": "6JDXwILoGcZuYDKGNPiXgA",
            "kty": "oct",
            "kid": "ASNFZ4mrze8BI0VniavN7w"
        },
        {
            "k": "XHYyt3r8i4EDVtu3HoFl1g",
            "kty": "oct",
            "kid": "ASNFZ4kBI0VniavN76vN7w"
        }
    ],
    "type": "temporary"
}

3.2.2 视频内容服务器配置

  为了让DRM服务器能够识别不同的视频,需要在对秘钥服务器的请求URL中附带一些能够识别不同视频的参数。在nginx配置中,加入$vod_suburi变量,将视频文件路径附加到请求的尾部。

vod_drm_request_uri /dash_clear_key.php$vod_suburi;

配合DRM秘钥服务器上对字符串(示例中的low)的判定检测,可以识别不用码率的视频(示例中的example0001.mp4example0001_low.mp4)。

对DRM服务器和视频内容服务器进行了配置之后,使用2.3.2小节提供的访问方式即可播放多码率自适应的DASH流媒体视频,此时不同码率的视频是使用不同的加密秘钥进行加密的。

4 附加补充:mpd清单文件相关内容

  最后还需要了解一下mpd清单文件,DASH的mpd文件(Media Presentation Description)是用来组织需要播放的各种内容的一个清单列表,本质上是一个xml格式的文件,结构如下:

Period(媒体时段),完整的视频可以按时间分为多个Period,一个Period可以包含一个或者多个AdaptationSet;
AdaptationSet(自适应集合),一个AdaptationSet可以包含一个或多个Representation,这些Representation可具有不同的码率和分辨率,也可能是不同的媒体类型,例如视频或者音频;
Representation(媒体文件描述),每个Representation描述了一段可以独立解码的流媒体,包含码率、分辨率、编码器等信息,一个Representation包含多个Segment;
Segment(切片),流媒体按照一定的时长被切割成的片段。

  示例中使用nginx-vod-module模块通过修改nginx配置来动态生成mpd清单文件,因此并不需要手动配置该清单文件,这里贴一下引入DRM后生成的mpd清单文件完整内容如下:

<?xml version="1.0"?>
<MPD
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns="urn:mpeg:dash:schema:mpd:2011"
    xsi:schemaLocation="urn:mpeg:dash:schema:mpd:2011 http://standards.iso.org/ittf/PubliclyAvailableStandards/MPEG-DASH_schema_files/DASH-MPD.xsd"
    type="static"
    mediaPresentationDuration="PT1880.979S"
    minBufferTime="PT10S"
    profiles="urn:mpeg:dash:profile:isoff-live:2011">
  <Period>
    <AdaptationSet
        id="1"
        segmentAlignment="true"
        maxWidth="1280"
        maxHeight="720"
        maxFrameRate="25">
        <SegmentTemplate
            timescale="1000"
            media="https://192.168.192.128/vod_dash/example0001.mp4/fragment-$Number$-$RepresentationID$.m4s"
            initialization="https://192.168.192.128/vod_dash/example0001.mp4/init-$RepresentationID$.mp4"
            duration="10000"
            startNumber="1">
        </SegmentTemplate>
      <Representation
          id="v1-x3"
          mimeType="video/mp4"
          codecs="avc1.640029"
          width="1280"
          height="720"
          frameRate="25"
          sar="1:1"
          startWithSAP="1"
          bandwidth="549135">
        <ContentProtection schemeIdUri="urn:mpeg:dash:mp4protection:2011" value="cenc"/>
        <ContentProtection xmlns:cenc="urn:mpeg:cenc:2013" schemeIdUri="urn:uuid:1077efec-c0b2-4d02-ace3-3c1e52e2fb4b" cenc:default_KID="01234567-89ab-cdef-0123-456789abcdef">
          <cenc:pssh>AAAANHBzc2gBAAAAEHfv7MCyTQKs4zweUuL7SwAAAAEBI0VniavN7wEjRWeJq83vAAAAAA==</cenc:pssh>
        </ContentProtection>
      </Representation>
    </AdaptationSet>
    <AdaptationSet
        id="2"
        segmentAlignment="true">
      <AudioChannelConfiguration
          schemeIdUri="urn:mpeg:dash:23003:3:audio_channel_configuration:2011"
          value="1"/>
        <SegmentTemplate
            timescale="1000"
            media="https://192.168.192.128/vod_dash/example0001.mp4/fragment-$Number$-$RepresentationID$.m4s"
            initialization="https://192.168.192.128/vod_dash/example0001.mp4/init-$RepresentationID$.mp4"
            duration="10000"
            startNumber="1">
        </SegmentTemplate>
      <Representation
          id="a1-x3"
          mimeType="audio/mp4"
          codecs="mp4a.40.2"
          audioSamplingRate="44100"
          startWithSAP="1"
          bandwidth="64000">
        <ContentProtection schemeIdUri="urn:mpeg:dash:mp4protection:2011" value="cenc"/>
        <ContentProtection xmlns:cenc="urn:mpeg:cenc:2013" schemeIdUri="urn:uuid:1077efec-c0b2-4d02-ace3-3c1e52e2fb4b" cenc:default_KID="01234567-89ab-cdef-0123-456789abcdef">
          <cenc:pssh>AAAANHBzc2gBAAAAEHfv7MCyTQKs4zweUuL7SwAAAAEBI0VniavN7wEjRWeJq83vAAAAAA==</cenc:pssh>
        </ContentProtection>
      </Representation>
    </AdaptationSet>
  </Period>
</MPD>

  1. 使用nginx搭建音视频点播服务器——基于HLS协议:https://blog.csdn.net/SeeDoubleU/article/details/121805174 ↩︎

  2. Introducing LowLatency HLS:https://developer.apple.com/videos/play/wwdc2019/502/ ↩︎

  3. nginx的安装流程:https://blog.csdn.net/SeeDoubleU/article/details/121727292 ↩︎

  4. 使用nginx搭建音视频点播服务——基于HLS协议:https://blog.csdn.net/SeeDoubleU/article/details/121805174 ↩︎

  5. ISO Common Encryption (‘cenc’) Protection Scheme for ISO Base Media File Format Stream Format: https://www.w3.org/TR/eme-stream-mp4/ ↩︎

这篇关于使用nginx搭建音视频点播服务——基于DASH协议的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!