http://blog.csdn.net/nonmarking/article/details/50397153
DASH(Dynamic Adaptive Streaming over HTTP)即自适应流媒体传输,典型的系统框图如下

简单概括来说,就是在服务器端提前存好同一内容的不同码率、不同分辨率的多个分片以及相应的描述文件MPD,客户端在播放时即可以根据自身性能以及网络环境选择最适宜的版本。更多详细的内容可以参见MPEG组织出台的标准,标准号ISO/IEC 23009-1。
在这篇文章中主要说一下如何生成服务器端的媒体内容和相应的MPD文件。通过上面的框图可以看到,主要的流程即输入-编码-分片-组织MPD。下面将首先介绍一下目前网络上有的一些能在服务器端完成相应全部或部分工作的开源工程,然后介绍一个本人开发的用于完成这一任务的开源项目以及一个整合了此项目的java web示例。
网络上已有的开源项目
1、MPD验证器 MPEG-DASH MPD Validator
这是一个在线的MPD验证器,通过上传自己的MPD文件,就可以检验该文件与标准的一致性。该验证器支持到ISO/IEC 23009-1:2012。验证结果如下图

但实际上最保险的方法还是用播放器试着播放一下看看
2、DASHEncoder
该项目可以通过读入配置文件或命令行来完成DASH媒体内容和MPD文件的生成。并且支持计算PSNR值并存入mysql数据库。它的实现方法基本是通过调用x264\ffmpeg\mp4box来实现的。但是其作者表示目前该项目的维护已经结束,在github上下载的代码也已经无法正确运行。下面贴一个它的配置文件的示例
- #========================================
- # Config File for DASH Encoder
- #========================================
-
- #========================================
- # General Options
- #========================================
-
- dest-directory : /opt/lampp/htdocs/tests_updates/
-
-
- video-encoder : x264
- audio-encoder : ffmpegAAC
- multiplexer : mp4box
-
- #store-psnr
- sql-host : localhost
- sql-user : root
- sql-pw :
- sql-database : dash
-
- add-non-segmented
-
- #use-ffmpeg-pipe
- ffmpeg-opt : -f rawvideo
- #input-res : 384x208
- #input-res : 352x288
- input-res : 854x480
- #========================================
- # x264 Options
- #========================================
-
- bitrate : 300
-
- #bitrate : 250@480x360|500@480x360|1000
- #bitrate : 200|400|600|1000
- statistics : stat.temp
- gop : 48
- scenecut : 0
- profile : baseline
- preset : slow
- input : /home/stefan/sintel_trailer_2k_480p24.y4m
- #input : /home/stefan/foreman_cif.y4m
- #input : /home/stefan/kingkong.mp4
- #input : /media/Volume/MI200802010028-video_newsroom_hd_1080_p29_97-channelSelectionT0C0_T0C1.mp4
- passes : 1
- const-filesize : 0
-
- #Additional Options for Encoding
-
- #pass1 : --frames 500 --fps 29.970029
- pass1 : --verbose --fps 24
- pass2 : --verbose --psnr
-
- #========================================
- # FFMPEG AAC Options
- #========================================
-
- # [channels, samplerate, bitrate]
- #audio-quality : 2,44100,48|2,44000,128
- #audio-quality : 2,44100,48
- audio-quality :
-
- audio-input : /home/stefan/sintel_trailer-audio.flac
- audio-codec : libfaac
-
- #========================================
- # MP4Box Options
- #========================================
-
- #AV Muxing
- #mux-combi : 300@48|600@128
- mux-combi :
-
- fragment-size : 2000
- segment-size : 2000
- rap-aligned
- segment-name : sintel
- folder-prefix : sintel
-
-
- #========================================
- # MPD Options
- #========================================
- mpd-name : sintel.mpd
- url-root : http://localhost/tests_updates/
- #set-base-url
- mpdActStandardPostfix : _actVersion.mpd
- duration : 9M4S
- transform-mpd
- minBufferTime : 2.0S
- segDuration : 2
- #========================================
- # Other Options
- #========================================
3、
bitcodin
前面说到DASHEncoder的作者表示已经不再对其进行维护了,其实是在他们转而开发了这个在线的编码分片与MPD生成平台。和许多类似的平台的一样,要体验完整的功能、更大的云端空间是需要付费的。此平台除了可以生成DASH内容外,也支持HLS,而且生成的媒体内容可以直接存储在他们的服务器上。界面如下

4、Bento4
该项目提供了用于MP4和DASH格式的一套工具集,例如用于查看mp4封装格式信息的mp4info、生成HLS内容的mp4-hls等。用于生成DASH内容的工具主要有两个,mp4-dash和mp4-dash-encoder。mp4-dash-encode可以将单个序列编码为多个不同码率的序列,并进行分片,不过默认的码率是在一个最低值(默认500k)和最高值(默认2M)之间进行平均分配,不能随意选择码率。mp4-dash则可以利用已有的单个或多个文件组织生成MPD。所以二者往往合作使用。具体使用教程看这里。
在这里简单描述一下使用方法
首先需要自己使用ffmpeg将原始视频编码为你需要的码率和分辨率等,然后使用mp4fragment工具将mp4 fragment化,接下来就可以使用mp4-dash工具完成dash内容的生成工作了
5、GPAC
与Bento4类似,GPAC也是一个开源的多媒体工具包,包括用于MP4打包的mp4box等。用于生成DASH内容的工具是DASHCast,也是通过读取输入文件和配置文件来生成DASH内容和对应的MPD文件,但是测试发现生成直播内容时一切正常,但是生成点播内容时会出现错误,无法使用。此外,这个工具包里还有一个mp4box也支持DASH内容和MPD的生成,不过需要搭配x264或ffmpeg来完成编码的工作。一个简单的使用教程看这里 。
本人制作的开源示例
1、DASHEncoder2
+++++++++++++++++++++++++++
20170518更新
点击这里查看最新的DASHEncoder2工具。最新工具基于ffmpeg和bento4工具集开发,简单来说就是python调用命令行工具,目前只做了windows版本,linux版本有需求的也可以自行修改出来,应该是比较简单的。
因为Bento4工具集只能处理MP4封装的媒体资源,并且没有编解码功能,这意味着无法直接将任意输入媒体资源转化为需求的DASH内容,为了解决这一问题,实现根据设置参数自动生成DASH内容和对应MPD文件的功能,开发了新版DashEncoder2工具,该工具的数据处理流程如下图

该工具支持如下的常用命令
命令参数 | 含义 |
-h, --help | 输出帮助信息 |
-v, --verbose | 输出verbose级别日志信息 |
-d, --debug | 输出debug级别日志信息 |
-f, --force | 当指定输出路径已经存在时,强制覆盖路径 |
-k, --keep-files | 保留编码分片过程中的中间文件 |
--encfiles-output-dir=<encfiles-output-dir> | 转码文件的保存路径 |
-b BITRATES, --bitrates=BITRATES | 视频码率,若同时转码为多个码率,则以逗号区分各个码率 |
-r RESOLUTIONS, --resolutions=RESOLUTIONS | 视频分片,以宽x高的形式记录,若同时转码为多个分辨率,则以逗号区分各个分辨率 |
-c VIDEO_CODEC, --video-codec=VIDEO_CODEC | 视频编码器,可选libx264(默认)或libx265 |
-a AUDIO_BITRATES, --audio-bitrates=AUDIO_BITRATES | 音频码率,若同时转码为多个码率,则以逗号区分各个码率 |
--select-streams=SELECT_STREAMS | 仅编码文件在选中的流 |
-s SEGMENT_SIZE, --segment-size=SEGMENT_SIZE | DASH内容的分片时长,以帧数为单位,默认为3*fps,即3秒 |
-e ENCODER_PARAMS, --encoder-params=ENCODER_PARAMS | 其他自定义编码参数 |
-o <output-dir>, --output-dir=<output-dir> | DASH内容的保存路径 |
--mpd-name=<filename> | MPD文件名 |
--profiles=<profiles> | 选择DASH profile |
--init-segment=<filename> | 初始化分片的名称 |
--no-split | 是否要对媒体文件进行分片 |
--use-segment-list | 使用SegmentList标识DASH内容 |
--use-segment-template-number-padding | 使用递增数字的SegmentTemplate标识DASH内容 |
--use-segment-timeline | 使用Segment Timeliness标识DASH内容 |
--min-buffer-time=<duration> | 指定DASH内容的最小缓冲时间,以秒为单位 |
只需输入如下的示例命令,即可将媒体资源转化为DASH内容并且生成对应的MPD文件
- dashencode.bat -v -d -f --encfiles-output-dir=dashencode -b 100,300 -a 64,128 -r 512x288,640x360 -s 60 -o dashtest --mpd-name=cuc_ieschool.mpd --use-segment-timeline cuc_ieschool.mp4
实验性功能:
通过修改python脚本的源码,还可以在mpd中输出自定义内容,比如我们可以在编码分片的同时计算每一个分片文件的视频特性信息,也就是TI值和SI值,前者代表时间复杂度,利用帧差计算,后者代表空间复杂度,利用sobel滤波计算,具体来说,调用TIandSIprocmd工具完成计算。此时,数据处理流程如下

当选择输出segmentList的时候,就会同时记录TI和SI值,可以得到如下的mpd内容,可以看到在SegmentURL元素的属性中记录了TI和SI值。
- <?xml version="1.0" ?>
- <MPD mediaPresentationDuration="PT14.040S" minBufferTime="PT4.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" minHeight="360" minWidth="640" segmentAlignment="true" startWithSAP="1">
- <Representation bandwidth="760472" codecs="avc1.42C01E" frameRate="25" height="360" id="video/1" scanType="progressive" width="640">
- <SegmentList duration="4000" timescale="1000">
- <Initialization sourceURL="video/1/init.mp4"/>
- <SegmentURL SI="62.66" TI="26.09" media="video/1/seg-1.m4s"/>
- <SegmentURL SI="78.02" TI="15.77" media="video/1/seg-2.m4s"/>
- <SegmentURL SI="66.68" TI="14.83" media="video/1/seg-3.m4s"/>
- <SegmentURL SI="72.02" TI="11.77" media="video/1/seg-4.m4s"/>
- </SegmentList>
- </Representation>
- <Representation bandwidth="1167336" codecs="avc1.42C01F" frameRate="25" height="720" id="video/2" scanType="progressive" width="1280">
- <SegmentList duration="4000" timescale="1000">
- <Initialization sourceURL="video/2/init.mp4"/>
- <SegmentURL SI="43.08" TI="26.05" media="video/2/seg-1.m4s"/>
- <SegmentURL SI="64.89" TI="16.14" media="video/2/seg-2.m4s"/>
- <SegmentURL SI="50.92" TI="15.09" media="video/2/seg-3.m4s"/>
- <SegmentURL SI="58.49" TI="11.98" media="video/2/seg-4.m4s"/>
- </SegmentList>
- </Representation>
- <Representation bandwidth="1683750" codecs="avc1.42C028" frameRate="25" height="1080" id="video/3" scanType="progressive" width="1920">
- <SegmentList duration="4000" timescale="1000">
- <Initialization sourceURL="video/3/init.mp4"/>
- <SegmentURL SI="32.57" TI="25.99" media="video/3/seg-1.m4s"/>
- <SegmentURL SI="54.54" TI="16.21" media="video/3/seg-2.m4s"/>
- <SegmentURL SI="40.21" TI="15.18" media="video/3/seg-3.m4s"/>
- <SegmentURL SI="48.33" TI="12.04" media="video/3/seg-4.m4s"/>
- </SegmentList>
- </Representation>
- </AdaptationSet>
-
- <AdaptationSet mimeType="audio/mp4" segmentAlignment="true" startWithSAP="1">
- <Representation audioSamplingRate="48000" bandwidth="68943" codecs="mp4a.40.2" id="audio/und/mp4a/1">
- <AudioChannelConfiguration schemeIdUri="urn:mpeg:dash:23003:3:audio_channel_configuration:2011" value="2"/>
- <SegmentList duration="4000" timescale="1000">
- <Initialization sourceURL="audio/und/mp4a/1/init.mp4"/>
- <SegmentURL media="audio/und/mp4a/1/seg-1.m4s"/>
- <SegmentURL media="audio/und/mp4a/1/seg-2.m4s"/>
- <SegmentURL media="audio/und/mp4a/1/seg-3.m4s"/>
- <SegmentURL media="audio/und/mp4a/1/seg-4.m4s"/>
- <SegmentURL media="audio/und/mp4a/1/seg-5.m4s"/>
- </SegmentList>
- </Representation>
- <Representation audioSamplingRate="48000" bandwidth="134618" codecs="mp4a.40.2" id="audio/und/mp4a/2">
- <AudioChannelConfiguration schemeIdUri="urn:mpeg:dash:23003:3:audio_channel_configuration:2011" value="2"/>
- <SegmentList duration="4000" timescale="1000">
- <Initialization sourceURL="audio/und/mp4a/2/init.mp4"/>
- <SegmentURL media="audio/und/mp4a/2/seg-1.m4s"/>
- <SegmentURL media="audio/und/mp4a/2/seg-2.m4s"/>
- <SegmentURL media="audio/und/mp4a/2/seg-3.m4s"/>
- <SegmentURL media="audio/und/mp4a/2/seg-4.m4s"/>
- <SegmentURL media="audio/und/mp4a/2/seg-5.m4s"/>
- </SegmentList>
- </Representation>
- </AdaptationSet>
- </Period>
- </MPD>
目前默认在segmentLIst模式下会记录TI和SI值,如果想要关闭这一功能,修改mp4-dash.py文件即可。
+++++++++++++++++++++++++++
正如这个示例的名字所示,我是在DASHEncoder的基础上进行修改制作的这个示例,修改的内容包括:重新设计了结构,将编码、分片和MPD生成这三个步骤完全分离;编码工作全部使用ffmpeg完成,不再需要x264;生成的媒体分片内容根据属性组织存放在各自的文件夹中;暂时去掉了与数据库相关的功能;增加了一些文档,易于使用;修改了一些bug。经过测试,是可以使用的,当然也可能会有一些暂未发现的bug,希望大家提出,我计划持续维护这个项目。
源码下载地址在这里,会进行更新的github地址在这里。
更新:目前的dashencoder基于ffmpeg和gpac的mp4box工具,但就实际使用来看,mp4box生成的dash流有很多播放器不支持,例如vlc,在下一步的修改计划中,将改成利用bento4工具.
2、DASH website demo
在以上项目的基础上,我还制作了一个示例网站,利用这个网站可以实现bitcodin类似的功能,当然界面就没有那么绚丽了,基本的选择文件、上传文件、自动生成DASH内容、播放DASH内容的功能都包括了。在使用的时候需要将DASHEncoder2添加到系统环境变量中。这个网站是在我师哥的代码的基础上做的,原本是一个不支持DASH内容的视频网站示例。还是一样,如果有一些bug,希望大家提出,我同样计划持续维护这个项目。
源码下载在这里,会进行更新的github源码地址。