环境:
工具:
*注:本文基于Bento4的mp4dash
实现,关于基于MP4Box
的实现方案,参见:Ubuntu下GPAC(MP4Box)的安装 | 基于MP4Box搭建DASH视频系统
视频:
分辨率级别:
参考:
说明:
本文记录了一个最基础的DASH视频服务器与播放器的搭建过程,并在本人掉坑之后补充了一些细节。有兴趣的初学者不需要了解具体知识,只需跟随说明,即可成功复现。
为了可读性,将工具的安装过程单独写在了别的博文里,点开即见,相当于函数封装了。
见:Ubuntu下Nginx的安装及使用
(建议使用源码安装)
视频名称:Elephants Dream
来源:Xiph.org :: Derf’s Test Media Collection
1. 视频
原始格式:y4m
原始帧率:24fps
原始时长:10m53s
原始比例:16:9
原始分辨率:1920×1080(1080p)
原始大小:46GB
下载链接:elephants_dream_1080p24.y4m.xz
文件为.xz压缩包,大小为7.13GB,解压命令为:
xz -d elephants_dream_1080p24.y4m.xz
2. 音频
原始格式:flac
原始时长:10m58s(*注:比视频长5s左右,后续没有对这个时间差进行处理)
下载页面:Index of /video/derf/flac/ED
下载链接:ED-CM-St-16bit.flac(*注:其他6个文件是5.1环绕立体声的6条音轨,只有这个是完整的音频)
见:Ubuntu下FFmpeg的安装(支持libfdk_acc)
(需支持libfdk_aac
,因此应使用源码安装)
目的编码:H.264/AVC
目的分辨率级别:
使用最简单的编码方式,每个分辨率视频的对应命令为:
ffmpeg -i elephants_dream_1080p24.y4m -s 1920x1080 -c:v libx264 -keyint_min 48 -g 48 -sc_threshold 0 -an ED1920x1080.mp4
ffmpeg -i elephants_dream_1080p24.y4m -s 1280x720 -c:v libx264 -keyint_min 48 -g 48 -sc_threshold 0 -an ED1280x720.mp4
ffmpeg -i elephants_dream_1080p24.y4m -s 896x504 -c:v libx264 -keyint_min 48 -g 48 -sc_threshold 0 -an ED896x504.mp4
ffmpeg -i elephants_dream_1080p24.y4m -s 640x360 -c:v libx264 -keyint_min 48 -g 48 -sc_threshold 0 -an ED640x360.mp4
ffmpeg -i elephants_dream_1080p24.y4m -s 256x144 -c:v libx264 -keyint_min 48 -g 48 -sc_threshold 0 -an ED256x144.mp4
关于选项:
*注:
编码完成后,各分辨率下的视频I帧对齐,I帧个数均为327个,对应327个GOP,每个GOP时长2s。各分辨率下的视频码率(单位:kbps)分别为(见ffmpeg
输出信息):
需要将音频使用AAC进行编码为m4a格式3,命令为:
ffmpeg -i ED-CM-St-16bit.flac -c:a libfdk_aac ED.m4a
为了后续的步骤,需要将该m4a音频与之前编码的视频进行合并,输出一个有音轨的视频4,具体命令为:
ffmpeg -i ED1920x1080.mp4 -i ED.m4a -vn -c:a copy ED_audio.mp4
*注:此视频只需要音轨,不需要视频画面,因此用-vn
忽略视频编码,否则后面会多生成一种视频的Representation
*注:对音频编码时,若换用其他编码库(如alac),可能会在播放时引起错误:
[6395][Stream] audioCodec (audio/mp4;codecs="mp4a") is not supported.
这是因为浏览器不支持其他编码的音频,参考:Profiles and codecs supported by the Reference Client ( dash.js )?
Dash.js itself does not support codecs. It is a MSE client, meaning that it relies upon the browser’s MSE implementation to decode the content. It will pass along ANY codec that is specified within the manifest and ask the sourceBuffer if it can play it. So the answer to your question is really what codecs do Chrome, IE11, FF and Safari/Yosemite support for MSE?
见:Ubuntu下Bento4(mp4info、mp4fragment、mp4dash)的安装及使用
步骤:
1. fragment:使用mp4fragment
对各分辨率视频及音频视频进行fragment(指定fragment时长为2s)
mp4fragment --fragment-duration 2000 ED1920x1080.mp4 f1080p.mp4
mp4fragment --fragment-duration 2000 ED1280x720.mp4 f720p.mp4
mp4fragment --fragment-duration 2000 ED896x504.mp4 f480p.mp4
mp4fragment --fragment-duration 2000 ED640x360.mp4 f360p.mp4
mp4fragment --fragment-duration 2000 ED256x144.mp4 f144p.mp4
mp4fragment --fragment-duration 2000 ED_audio.mp4 f_audio.mp4
2. 切片:使用mp4dash
对已fragment的视频进行切片
mp4dash f1080p.mp4 f720p.mp4 f480p.mp4 f360p.mp4 f144p.mp4 f_audio.mp4
成功后,生成文件的目录结构为:
output/
├── audio/
│ └── und/
│ └── mp4a/
│ ├── init.mp4
│ ├── seg-1.m4s
│ ├── ...
│ └── seg-330.m4s
├── stream.mpd
└── video/
└── avc1/
├── 1/
├── 2/
├── 3/
├── 4/
└── 5/
├── init.mp4
├── seg-1.m4s
├── ...
└── seg-327.m4s
可以看到,mp4dash
将5种分辨率的视频分别分为了327个视频段,并为其生成了mpd文件。此外,由于音频比视频长5s左右,因此音频有330个段,比视频多了3个
生成的stream.mpd
5的内容为:
<MPD mediaPresentationDuration="PT10M53.792S" minBufferTime="PT2.00S" profiles="urn:mpeg:dash:profile:isoff-live:2011" type="static" xmlns="urn:mpeg:dash:schema:mpd:2011">
<Period>
<AdaptationSet maxHeight="1080" maxWidth="1920" mimeType="video/mp4" segmentAlignment="true" startWithSAP="1">
<SegmentTemplate duration="2000" initialization="$RepresentationID$/init.mp4" media="$RepresentationID$/seg-$Number$.m4s" startNumber="1" timescale="1000"/>
<Representation bandwidth="16079970" codecs="avc1.640028" frameRate="24" height="1080" id="video/avc1/1" scanType="progressive" width="1920"/>
<Representation bandwidth="7753362" codecs="avc1.64001F" frameRate="24" height="720" id="video/avc1/2" scanType="progressive" width="1280"/>
<Representation bandwidth="4310870" codecs="avc1.64001F" frameRate="24" height="504" id="video/avc1/3" scanType="progressive" width="896"/>
<Representation bandwidth="2391544" codecs="avc1.64001E" frameRate="24" height="360" id="video/avc1/4" scanType="progressive" width="640"/>
<Representation bandwidth="402408" codecs="avc1.64000C" frameRate="24" height="144" id="video/avc1/5" scanType="progressive" width="256"/>
AdaptationSet>
<AdaptationSet mimeType="audio/mp4" segmentAlignment="true" startWithSAP="1">
<SegmentTemplate duration="2000" initialization="$RepresentationID$/init.mp4" media="$RepresentationID$/seg-$Number$.m4s" startNumber="1" timescale="1000"/>
<Representation audioSamplingRate="48000" bandwidth="141821" codecs="mp4a.40.2" id="audio/und/mp4a">
<AudioChannelConfiguration schemeIdUri="urn:mpeg:dash:23003:3:audio_channel_configuration:2011" value="2"/>
Representation>
AdaptationSet>
Period>
MPD>
*注:如果视频服务器有公网IP,则无需自己实现网页播放器,直接在Dash JavaScript Player中填上MPD文件的链接,点击"Load"即可(先完成本文第9步)。
播放器实现基于dash.js: Dash-Industry-Forum/dash.js: A reference client implementation for the playback of MPEG DASH via Javascript and compliant browsers
首先,需要下载dash.js到本地,下载链接为:dash.all.min.js
之后,编写一个简单的播放器页面(index.html
):
<html>
<head>
<title>Dash.js Rockstitle>
<style>
video {
width: 640px;
height: 360px;
}
style>
head>
<body>
<div>
<video data-dashjs-player autoplay src="./stream.mpd" controls>
video>
div>
<script src="./dash.all.min.js">script>
body>
html>
*注意:这种写法要求index.html
、dash.all.min.js
、stream.mpd
在同一目录下
步骤:
1. 修改Nginx配置
在/usr/local/conf/nginx.conf
中,添加6:
location /
{
...
add_header Access-Control-Allow-Methods “GET,OPTIONS,POST,HEAD,PUT,DELETE”;
add_header Accept-Ranges “bytes”;
add_header Access-Control-Allow-Origin “*”;
add_header Access-Control-Expose-Headers “Content-Lengrh,Content-Range,Date,Server,Transfer-Encoding,origin,range,x-goog-meta-foo1”;
}
之后,验证并重载配置:
nginx -t
nginx -s reload
2. 部署相关文件
/usr/local/nginx/html/
)下原本的index.html
改名为index_bak.html
index.html
及下载的dash.all.min.js
转移至html/目录下此时,html/下的文件目录结构为:
/usr/local/nginx/html/
50x.html
audio/
und/
mp4a/
init.mp4
seg-1.m4s
...
seg-330.m4s
dash.all.min.js
index_bak.html
index.html
stream.mpd
video/
avc1/
1/
2/
3/
4/
5/
init.mp4
seg-1.m4s
...
seg-327.m4s
最后,打开本地浏览器,输入:
http://localhost/
或在其他机器(客户端)上,输入:
http://服务器IP/
可以看出,视频和音频是以一个个格式为m4s的分段进行传输的,其中较小的为音频,较大的为视频。
到此,一个完整的DASH视频系统就正式完成了。Enjoy it!~
这个分辨率是参考爱奇艺的 ↩︎
该问题详见:FFmpeg的GOP(I帧)对齐问题 ↩︎
参考:audio - How do I convert FLAC files to AAC (preferrably VBR 320k+)? ↩︎
参考:使用FFmpeg合并音视频 ↩︎
此处生成的MPD文件中的bandwidth
值与之前ffmpeg
编码得到的视频码率不一致,原因及分析见:mp4dash生成的MPD文件中的Bandwidth取值及其对客户端码率选择的影响 ↩︎
与HTTP访问控制相关,详见:HTTP访问控制(CORS) ↩︎