×

MPEG DASH 和 HLS

96
hzmangel
2016.11.01 17:56* 字数 2546

最近做了点关于这俩玩意的东西,记在这。

友提:废话较多,想看 tl;dr 的按end后往回翻。


首先,这俩东西都是用来处理视频的,为视频提供基于HTTP的Streaming方案,除了这俩之外,还有下面的技术:

  • Adobe HTTP Dynamic Streaming (HDS)
  • Microsoft Smooth Streaming (MSS)

这俩没接触,不写。标题中提到的那俩,也就记下来用到的东西,没研究过的,比如说直播啥的也不写。

Overview

先说需求吧,抛开需求谈技术就是耍流氓,嗯。

随着网络的发展,技术的演进,人们手上的电子垃圾设备也越来越多,碰到的网络状况也越来越多,本文的废话也越来越多。在现实的网络环境中做媒体分发,以视频为例,不同的设备所需的大小,码率都不同,就算在相同的设备上,也需要根据网络情况的不同选择合适的码率来播放。在此基础上,还需要提供流畅的切换体验。不难看出,想法很美好,但是现实很复杂。所以,需要有更好的办法向用户提供多码率的媒体分发。

历史

纯废话,可以无视

N年前在学校的时候就有这些东西了,当时是 RTSPMMS (暴露年龄了哇~),自己架好后去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,但是对于开发这边而言,有一个统一的播放器会更方便些。之前查的时候找到了这些播放器,有些是两者通吃,有些是只能放一个;有些免费,有些收费,按需取用吧~


基本上就是这些了,主要是做项目中查到的东西,整理下以便查阅。如有错误,欢迎告知。

TIL
Web note ad 1