使用FFmpeg生成HLS

 

HLS也就是HTTP Live Streaming,是苹果出的一个基于HTTP的流媒体通信协议。字面意思有个live,也就是直播相关的。其实HLS可以分为点播以及直播两种。后面具体说两者在处理上有什么区别。目前HLS在RFC上还只是草案,并且一直不断更新,发现ffmpeg对于HLS的实现,不同版本的实现对应rfc版本也不一样,最新版本的,对应的HLS RFC草案规范也比较新(追新并不一定好,有些设备对于新版本的规范支持还不是很完整,可能会有播放失败的问题,所以如果需要正常使用,选择一个稳定的版本即可)。rfc的草案现在到了16版本。由于项目比较敢,这规范其实我看的不多。

HLS对于音视频是有编码要求的,HLS要求视频必须是H264协议,H264是目前最流行也是最成熟的视频编解码方案了。而在音频上,则要求为MP3, HE-AAC或AC-3这三种格式。在转换成HLS流后,会生成多个的TS文件。如果是点播的话,则是对视频文件进行TS的切片处理,一般情况下,每个TS文件的播放时间为10秒。但这并不是固定的,切片的多少,这是会影响直播的延迟情况。这个后面会稍微做一些说明。

HLS会生成一个m3u8的播放文件。这个播放文件可以通过VLC等一些播放器直接播放。现在大部分手机也支持HLS了,所以手机也是可以进行对HLS的直播或点播进行观看。但是目前的桌面端浏览器尚未完全支持HTML5的HLS播放,大部分直播还是依赖flash player进行封装直播(据说国内的很多视频站有自己的播放技术)。这边主要讨论的并非是桌面端,主要还是移动端的支持。

现在简单说一下m3u8文件。以下是由ffmpeg生成的一个直播的m3u8文件:

EXT-X-TARGETDURATION用来表示每个TS分片间隔为13秒。该参数是必须的,并且在同一个列表中是不能被改变的(直播是有列表大小的,当列表被刷新后,这个参数也可能不一样)。一般为10秒。

EXT-X-MEDIA-SEQUENCE用来表示当前列表中第一个播放的媒体序列号。

EXTINF则表示当前TS分片所播放的时常。

EXT-X-ENDLIST表示列表结束,是必须要有的参数。

m3u8文件还有一些其余的参数,并可以控制对应带宽播放哪些文件(也就是HLS可以更好自适应当前的网络带宽)等,这些具体还是去看RFC草案吧。由于我也是新学习的,探究并不是很深。

先说说二者HLS实现上的一些区别吧。

  1. 点播就是将一个媒体文件切分成多个TS文件,并且m3u8文件包含全部的TS文件列表。
  2. 直播则列表长度上会有所控制,也就是一般会比较短,并且为了减少延迟,可能会将每个分片的时长控制低于10秒,而点播应该都会直接使用10秒这个默认值吧。(并不是十分清楚现在移动端的实现是否如我这边所说)
  3. 点播的m3u8是死的,也就是一旦分片完成后,一般不会再去修改m3u8文件(内容)。而直播的m3u8文件(内容)则会根据直播的时间进行更新。(其实这点很重要,直播与点播的最大区别,也应该是大部分客户端判断的标准吧,目前还没细致去研究任何一款客户端)

既然已经说到这里了,这里顺便说一下,HLS点播其实是很不错的一个技术,支持不同带宽的播放列表(前提切片后需要对应的子m3u8播放文件以及对应分辨率的TS文件),缺点就是10秒的切片,会导致有很多的小文件存在。而直播,怎么说,依托现有CDN技术以及HTTP的支持,可以很好的支持高清直播。但是也有一定的硬伤,那就是延迟。我自己在实验的时候,两台手机进行直播m3u8文件,都有不同发延迟(当然,也不是说其余的直播技术没有延迟,只能说HLS这个短板比较大吧)。当然,可以通过减少每个TS文件的时长来降低部分延迟。

接下来就说一下ffmpeg如何来生成点播与直播吧。

首先是点播,点播就是用ffmpeg将视频文件给切片成多个。

这个用的ffmpeg的segment模块来进行对source.mp4文件进行切片,不带上-re参数,这样可以以最快的速度进行切片操作(当然该操作会消耗很大的CPU)。等一段时间后,就可以看到N个的outXXX.ts(其中XXX为数字,根据你视频的大小,会有不同的数量),ffmpeg会根据out%03d,自动计算生成的文件名称格式。由于生成的playlist.m3u8文件很长,这里就不贴出来了。这里简单说一下ssegment的一些参数,segment_format来指定输出格式为mpegts   segment_list用来配置输出的列表文件名,segment_time则是切片的时长。还有一些其余的参数,可以看ffmpeg的官方使用文档,或直接看libavformat/segment.c源文件,就会比较清楚了。

接下来说一下直播,直播的话,ffmpeg可以通过上面的点播的ssegment模块,也可以直接通过hls模块来实现。先说说如果通过ssegment模块来实现:

与点播的区别就是在加了-segment_list_flags +live以示直播,并且加上了-re参数(不加这个参数,一下子就切片过去,客户端还来不及播放,列表已经被更新了,该参数表示ffmpeg将会按照source.mp4的播放速率进行转码)。带上segment_list_size参数对列表数量进行控制在6个。但是目前的话,ssegment模块有个缺点,虽然可以通过以上方式达到直播,但是生成的TS文件并不会循环,会一直被保留(当然如果要顺带将内容录制下来,这反倒是一个优点,只能说其实现的还是切片的功能,并非纯粹的直播)。这时候,HLS模块就可以更好的胜任直播功能了(能独立成模块,相对术业有专攻吧!)。HLS模块实现于libavformat/hlsenc.c libavformat/hls.c 以及 libavformat/hlsproto.c

hls_list_size即为HLS播放的列表,hls_wrap则表示为最大的TS循环数,也就是每10个一个循环,比如现在是生成playlist0.ts~playlist9.ts,10个文件,之后又会从playlist0.ts重新生成。目前新版本的ffmpeg的HLS模块加了很多参数,具体可以看libavformat/hlsenc.c中的static const AVOption options[]的内容,其中HLS还支持加密的操作,加密操作目前没做探究,下次有空再研究下吧。我目前开发用的1.2版本并没有过多的参数。其余的参数也没做太多的深究。有时间再补充吧。

从此次对HLS相关的实验以及知识点的学习,HLS确实是一个很不错的解决方案,主要是对移动设备的兼容非常之好,TS格式解码方便。并且可以大量使用现成的HTTP的CDN加速功能。目前互联网就HTTP协议的使用度最高,也最成熟了。关于ffmpeg生成HLS就先说到这里了。

 

转载请注明: 转载自elkPi

本文链接地址: 使用FFmpeg生成HLS

使用FFMPEG生成HLS
标签: