使用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文件:

#EXTM3U
#EXT-X-VERSION:3
#EXT-X-TARGETDURATION:13
#EXT-X-MEDIA-SEQUENCE:4
#EXTINF:12.345667,
playlist4.ts
#EXTINF:9.217544,
playlist5.ts
#EXTINF:7.757744,
playlist6.ts
#EXTINF:11.928589,
playlist7.ts
#EXTINF:11.761744,
playlist8.ts
#EXTINF:1.710044,
playlist9.ts
#EXT-X-ENDLIST

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 -i source.mp4 -codec:v libx264 -codec:a mp3 -map 0 -f ssegment -segment_format mpegts -segment_list playlist.m3u8 -segment_time 10 out%03d.ts

这个用的ffmpeg的ssegment模块来进行对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模块来实现:

ffmpeg -re -i source.mp4 -codec:v libx264 -codec:a mp3 -map 0 -f ssegment -segment_format mpegts -segment_list playlist.m3u8 -segment_list_flags +live -segment_list_size 6 -segment_time 10 out%03d.ts

与点播的区别就是在加了-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

ffmpeg -re -i source.mp4 -codec:v libx264 -codec:a libfaac -map 0 -f hls  -hls_list_size 6 -hls_wrap 10 -hls_time 10 playlist.m3u8

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.com

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

7 Comments

  1. teachmyself
    2015年10月9日

    ffmpeg -i Wildlife.wmv -codec:v libx264 -codec:a mp3 -map 0 -f ssegment -segment_format mpegts -segment_list ./m3u8/index.m3u8 -segment_time 10 ./m3u8/’%03d.ts’

    你好我使用你的命令转码,然后使用html的video标签引用转以后的文件

    这个不能播放

    但是直接引用ts文件可以播放

    m3u8内容貌似也没问题:
    #EXTM3U
    #EXT-X-VERSION:3
    #EXT-X-MEDIA-SEQUENCE:0
    #EXT-X-ALLOW-CACHE:YES
    #EXT-X-TARGETDURATION:12
    #EXTINF:11.878533,
    000.ts
    #EXTINF:9.042367,
    001.ts
    #EXTINF:9.242567,
    002.ts
    #EXT-X-ENDLIST

    想跟你请教下是什么问题导致的

    1. 米鹿π
      2015年10月10日

      你是用什么浏览器播放的,据我测试,目前还只能在手机浏览器上播放,如果是桌面版本的,chrome等都不能播放!

      1. teachmyself
        2015年10月10日

        是safari浏览器,目前貌似只有safari和手机上的chrome支持;
        我的问题找到了,太低级,因为是本地测试我的video标签src属性引用的相对路径 src=”xxx/xxx.m3u8″,貌似HLS必须是引用http地址,修改为src=”http://localhost/xxx/xxx/m3u8″就正常了,感谢!

        1. 米鹿π
          2015年10月11日

          呃,好吧,我也忘记当初用的src是怎么写的了。。

  2. vanti
    2016年4月13日

    ffmpeg可以对视频文件生成视频切片,如果我对视频文件进行切片后只想保留音频内容,做音频点播或者直播,ffmpeg支持吗

    1. 米鹿π
      2016年4月13日

      你在编解码的时候 带上-vn 也就是禁止video,比如ffmpeg -re -i source.mp4 -vn -codec:a libfaac -map 0 -f hls -hls_list_size 6 -hls_wrap 10 -hls_time 10 playlist.m3u8 可以测试下,我觉得应该可以单独音频直播/点播的

  3. […] 使用FFmpeg生成HLS […]

Comments are closed.

Scroll to top