最近做了点关于这俩玩意的东西,记在这。
友提:废话较多,想看 tl;dr 的按end后往回翻。
首先,这俩东西都是用来处理视频的,为视频提供基于HTTP的Streaming方案,除了这俩之外,还有下面的技术:
- Adobe HTTP Dynamic Streaming (HDS)
- Microsoft Smooth Streaming (MSS)
这俩没接触,不写。标题中提到的那俩,也就记下来用到的东西,没研究过的,比如说直播啥的也不写。
Overview
先说需求吧,抛开需求谈技术就是耍流氓,嗯。
随着网络的发展,技术的演进,人们手上的电子垃圾设备也越来越多,碰到的网络状况也越来越多,本文的废话也越来越多。在现实的网络环境中做媒体分发,以视频为例,不同的设备所需的大小,码率都不同,就算在相同的设备上,也需要根据网络情况的不同选择合适的码率来播放。在此基础上,还需要提供流畅的切换体验。不难看出,想法很美好,但是现实很复杂。所以,需要有更好的办法向用户提供多码率的媒体分发。
历史
纯废话,可以无视
N年前在学校的时候就有这些东西了,当时是 RTSP
和 MMS
(暴露年龄了哇~),自己架好后去BBS(又一个暴露年龄的东西)上贴地址,然后傻等着那收听数带来的莫名其妙的成就感。好像把这玩意给革命掉的是Flash播放器,在播放的时候可以选择码率,不过在切换码率的时候视频会停一下(这个后台具体的实现没考证过,只描述现象)。慢慢的人们发现,Flash将设备变成暧手宝/电熨斗的功能是如此的显著,但是这些热量又不能给电池充电,总不能出门就给手机电脑啥的背尿袋吧,于是又开始鼓捣新玩意了~
HLS
Apple弄的流媒体标准,基于HTTP提供流媒体的功能,在苹果系的软件中被原生支持,至于Windows/Linux/Android,不好意思Who are you?
MPEG DASH
在基于HTTP提供流媒体的方面,到目前为止已经看到了三种方案,苹果的HLS,土坯的HDS和巨硬的MSS,当然,各家用的协议,格式神马的都不会一样。于是每次做支持都要来三人份的。看到这三倍工作量,再想想老板不给加工资,码农们的心都寒了...
MPEG的同志们体察到了这份疾苦,呼吁大家来个标准点的玩意呗,于是就有了MPEG DASH 。这里有一篇综述,写的比我好还图文并茂的,去那看吧~
解决方案
此处是我在项目中的理解,没查文档,不保证正确
就接触到的MPEG DASH和HLS来看,它们的主要想法都是把一个长视频给切成小块,然后通过一个个的HTTP请求分别下载。这样一是每次请求的数据量不是很大,二是当用户需要换码率或分辨率时,在下次请求给新的视频就好。但是两种方法还是有些不同的,这个会在后面描述。此外,MPEG DASH还支持对于单一的媒体文件按时间戳请求,不过这次用到的不多,只会在后面介绍下生成方法。
在本文中,切片出来的视频片段被称为Segments。除了这些Segments外,还有描述这些Segments的文件,一般称为 Manifest 文件,但是后面也会根据文件扩展名称为 MPD 文件(MPEG DASH)或 M3U8 文件(HLS)。
进行MPEG DASH切片用的工具是 MP4Box
,而HLS切片的工具是 ffmpeg
需求
终于说到了这次的需求。首先,是个视频服务提供商,之前的做法就是把mp4丢s3上让用户自己去看。不过现在发现一是一个视频看下来,HTTP长连接受不了,二是如果只想给用户一段视频小样(切片播放),现在的方案没法实现。找了一圈,决定拿HTTP Streaming来试一试。
在做原型测试的时候,把HLS和DASH都尝试了下,由于需要支持切片播放,目前的实现方案选择的是HLS。
一些命令
源视频为 foo.mp4 ,就是随便从油管找一段720p的视频下到本地来用的
MPEG DASH
-
切成 Segments
$ MP4Box -dash-strict 5000 -profile dashavc264:live -rap foo.mp4#video foo.mp4#audio -out index.mpd
命令执行成功后会在当前目录下生成一个mpd文件,两个mp4文件和一系列的m4s文件。下面分别说明:
-
index.mpd
: 上面提到的 Manifest 文件,XML格式,包含对视频的描述。至于完整的Schema介绍,我也没找到......一点点问G吧。 -
*_init.mp4
: 初始的mp4文件,相当于视频头,在这个头文件中包含了完整的视频元信息(moov),具体的可以使用MP4Box <init video> -info
查看。 -
*.m4s
: 即上面提到的Segments文件,每个m4s仅包含媒体信息 (moof + mdat),而播放器是不能直接播放这个文件的,需要用支持DASH的播放器从init文件开始播放。
关于video structure的知识,可以参考这个网页
命令行参数中,
-dash 5000
表示把视频按5s一段来切,-profile
指定一些预设的配置,-rap
强制Segments的起始位置为random access point,这个我也不清楚具体指什么,就是网上抄的命令。后面列出所有要导入的媒体流,如果有多个码率,按规则写即可,最后在-out
后跟上输出的mpd文件名,m4s文件会存放在和mpd文件同级的目录中。这个切片基本上相当于把视频从中间直接分开,没有重新编码之类的过程,所以比较快。
注意在切片时把audio和video通过上面的命令分开,因为虽然DASH协议并没有限制一个m4s中是否可以包含多过一个moof块,但是目前的浏览器如Chrome是只支持在一个 Segment 中只包含一个moof的。
-
-
多码率支持
DASH中,对多码率的支持是通过增加
<Representation>
来完成的,具体可以问Google。
-
播放
把生成出来的所有东西放到http服务器的static目录中,即可通过mpd播放器访问了。除此之外,也可以使用支持mpd的app来放。
HLS
-
切成 Segments
$ ffmpeg -i foo.mp4 -g 25 -hls_time 1 -hls_list_size 0 index.m3u8
这个命令把视频按1秒切成Segments。命令执行成功后,会在当前目录下生成一个m3u8文件和一系列的ts文件。在HLS中,每个Segments都是可以独立播放的MPEG-2 TS文件,而m3u8的作用就是明确这些ts文件的顺序。m3u8文件是纯文本格式,可以方便的阅读修改。命令行参数中,
-g
用来指定按frame切视频,而-hls_time
指定Segments的长度为1s。这两个参数可以限定切出来的Segments 基本 符合1s一段的规则。所以在使用-g
时需要先确定源视频文件的fps后再设定。不过,即便如此,也有一些Segments的长度会有1s以内的偏差,应该是无法避免的了。-hls_list_size
表示最后生成的m3u8中列出的ts文件的数目,默认是5,此处写0表示把所有的ts文件都列上(这里是项目需求,实际使用中可以适当设置以减少m3u8文件大小)。没有测过如果最后生成10个ts文件,但是m3u8中只有5个的情况下,能不能把视频放完。回头如果试了再补充。
由于这个命令需要使用ffmpeg对源视频进行重新编码,所以需要占用比较多的CPU和时间。
-
多码率支持
HLS中,多码率的支持是通过
#EXT-X-STREAM-INF
标签指定的,在此标签中通过设置BANDWIDTH
参数来指定码率,然后在接下来的一行中填写uri来标明此码率对应的m3u8。 -
播放
如果使用Safari,可以直接把m3u8的地址输入地址栏,即可直接播放。据称Android的Chrome也支持,但是桌面的不支持,不过可以通过扩展播放。
播放器
虽然说有些浏览器可以内建支持HLS或者DASH,但是对于开发这边而言,有一个统一的播放器会更方便些。之前查的时候找到了这些播放器,有些是两者通吃,有些是只能放一个;有些免费,有些收费,按需取用吧~
- http://demo.theoplayer.com/test-hls-mpeg-dash-stream
- http://bitmovin.com/hls-mpeg-dash-test-player/
- http://dash-mse-test.appspot.com/dash-player.html
- http://shaka-player-demo.appspot.com/demo/
- http://dashif.org/reference/players/javascript/1.4.0/samples/dash-if-reference-player/
基本上就是这些了,主要是做项目中查到的东西,整理下以便查阅。如有错误,欢迎告知。