7

使用FFMPEG生成HLS

 3 years ago
source link: https://blog.p2hp.com/archives/5162
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client
使用FFMPEG生成HLS | Lenix Blog

使用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的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模块来实现:

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就先说到这里了。


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK