使用FFmpeg进行HLS打包——FFmpeg简单学

2022年05月15日 阅读数:6
这篇文章主要向大家介绍使用FFmpeg进行HLS打包——FFmpeg简单学,主要内容包括基础应用、实用技巧、原理机制等方面,希望对大家有所帮助。
 点击上方“ LiveVideoStack ”关注咱们

翻译、编辑:Alex

技术审校:赵军css

本文来自OTTVerse,做者为Krishna Rao Vijayanagar。html


▲扫描图中 二维码或点击阅读原文
了解音视频技术大会更多信息

FFmpeg
web

Easy-Tech
shell


#023#



在本文中,咱们将学习使用FFmpeg进行HLS打包。使用FFmpeg的好处在于:你能够在不离开命令行的状况下,执行提取视频、调整视频尺寸、转码、打包以及传输视频的全部操做。swift


咱们首先看一下为VOD(点播)建立HLS打包的全部步骤,而后再来了解HLS实时流的打包。数组


若是你想了解HLS播放列表的更多信息,能够访问咱们的m3u8文件合集:https://ottverse.com/free-hls-m3u8-test-urls/,查看使用不一样用例的不一样厂商的示例。若是你刚刚接触HLS,请阅读咱们以前的文章:什么是HLS(HTTP Live Streaming)? 和 理解ABR及其工做原理微信


事不宜迟,让咱们开始吧!markdown



使用FFmpeg进行HLS打包的基础步骤app


好,如今让咱们看下使用HLS打包点播文件的基础步骤:
ide


  1. 从磁盘读取输入视频

  2. 将视频缩放/调整(scale/resize)为所需的多种分辨率版本

  3. 将每一个缩放后的视频转码到所需码率

  4. 将音频转码到所需码率

  5. 将视频与音频组合,而后打包每个音、视频组合,再建立各TS视频切片和播放列表(playlist)

  6. 建立一个主播放列表(master playlist),用于指向每一个变体(variant)


如今,让咱们一步一步来解决。

 


FFmpeg将视频调整为多种分辨率版本


第一步和第二步包括从磁盘中读取视频,而后将其调整为多种分辨率。上述操做仅需一个命令,以下所示:


ffmpeg -i brooklynsfinest_clip_1080p.mp4 \-filter_complex \"[0:v]split=3[v1][v2][v3];\[v1]copy[v1out];\[v2]scale=w=1280:h=720[v2out];\[v3]scale=w=640:h=360[v3out]"


[0:v]指输入文件的第一个视频流。在咱们的例子中,只有一个视频流,它被分红3个输出[v1][v2][v3]。它们每个都做为FFmpeg缩放函数的输入,该缩放函数接受一个高度和宽度数值用于执行缩放。


这里,咱们将输入视频调整为1080p、720p和360p。


这里的[v1out][v2out][v3out]是包含缩放过程的输出变量。注意,这里咱们假设缩放过程会保留长宽比(aspect ratio)。固然,你能够在必要时使用letterboxing来处理。


审校者注:letterboxing是指将以宽银幕比例拍摄的电影转换到标准宽度的视频格式时,同时保留电影的原始宽高比,由此产生的视频图像上下都有黑条的这个过程;这些黑条是图像的一部分(即视频信号的每一帧)。LTBX是其缩写,标识如此格式化的电影和图像。这个术语来自于信箱的形状,信箱是墙壁或门上的一个槽,邮件经过它来传递,它是长方形的,宽于它的高度。下图是一个 2.35:1比例的 widescreen 图像通过letterboxing 处理以后,放在 1.33:1 屏幕上的一个例子。以下:



除此以外,还有pillarboxing和windowboxing等常见转换模式。



将视频转码为多种码率用于HLS打包


接着,咱们进入第三步和第四步:咱们必须将视频转码为多种码率,正如ABR技术常作的那样。


记住,咱们已经将视频调整为所需的分辨率并存储进 [v1out][v2out][v3out]的输出。咱们将直接使用它们做为转码步骤的输入。


-map [v1out] -c:v:0 libx264 -x264-params "nal-hrd=cbr:force-cfr=1" -b:v:0 5M -maxrate:v:0 5M -minrate:v:0 5M -bufsize:v:0 10M -preset slow -g 48 -sc_threshold 0 -keyint_min 48 \-map [v2out] -c:v:1 libx264 -x264-params "nal-hrd=cbr:force-cfr=1" -b:v:1 3M -maxrate:v:1 3M -minrate:v:1 3M -bufsize:v:1 3M -preset slow -g 48 -sc_threshold 0 -keyint_min 48 \-map [v3out] -c:v:2 libx264 -x264-params "nal-hrd=cbr:force-cfr=1" -b:v:2 1M -maxrate:v:2 1M -minrate:v:2 1M -bufsize:v:2 1M -preset slow -g 48 -sc_threshold 0 -keyint_min 48 \-map a:0 -c:a:0 aac -b:a:0 96k -ac 2 \-map a:0 -c:a:1 aac -b:a:1 96k -ac 2 \-map a:0 -c:a:2 aac -b:a:2 48k -ac 2 \


你能发现这里发生了什么吗?咱们已将三个变量[v1out][v2out][v3out]做为输入,并使用libx264的slow预设置转码每一个输入到所需码率。


注意:你也能够选择你本身的编码参数,并根据本身的喜爱和要求进行修改。在这个示例中,我使用一些简单的参数模拟CBR编码。使用FFmpeg有无数方法能够转码你的视频,你能够在预设置、crf值和CBR设置等不一样参数组合之间任意选择。


重要的是,咱们已经将-keyint_min设置为48,它会强制设置关键帧出现的周期,这在ABR转码技术中很是重要。


如今,咱们进行到下一个阶段:为每个码率版本/变体(rendition/variant)建立HLS m3u8播放清单。

 


使用FFmpeg建立HLS播放清单(m3u8)


如今咱们已经有了将视频转码为不一样码率变体的命令,让咱们来使用FFmpeg建立HLS点播播放列表。


下面是进行HLS打包所需的重要设置:


  • hls_playlist_type=vod: 经过设置该值,FFmpeg建立了一个点播播放列表,将#EXT-X-PLAYLIST-TYPE:VOD插入到m3u8头部中,并强制hls_list_size为0。

  • hls_time seconds:咱们须要使用它设置目标切片长度(以秒为单位)。

  • 默认值为2秒,当2秒过去,切片将在下一个关键帧处被切片。

  • 之因此要求确保每一个比特流变体在每N秒结束的时候都有一个关键帧(这点很是重要),由于ABR要求切片时候的关键帧要对齐,这样才能无缝切换。

  • hls_segment_type:这里有两个值:mpegts或fmp4,用于指定建立TS片断或fmp4(CMAF)片断,这对建立HLS和DASH的单一数据流颇有用。

  • -hls_flags independent_segments:当确保播放列表中全部切片都以一个关键帧开始时,将#EXT-X-INDEPENDENT-SEGMENTS添加到播放列表中。

  • hls_segment_filename filename 用于在打包过程当中为所建立的视频切片命名。


下面是为单一视频文件建立播放列表的示例:


-f hls \-hls_time 2 \-hls_playlist_type vod \-hls_flags independent_segments \-hls_segment_type mpegts \-hls_segment_filename stream_%v/data%02d.ts \-var_stream_map “v:0,a:0 v:1,a:1 v:2,a:2” stream_%v/stream.m3u8

 

若是你看到最后一行,你会注意到一个名为var_stream_map的功能选项。它是作什么的?


var_stream_map是一个FFmpeg功能选项,它帮助咱们将各类视频和音频转码组合起来,以建立不一样的HLS播放列表。若是你有两个使用相同视频但不一样音频的码率版本,那么你能够选择不一样的视频和音频版本并将它们链接起来,而不是为了建立不一样的播放列表而建立多个编码。

 

好比,-var_stream_map "v:0,a:0 v:1,a:0 v:2,a:0"是指由a:0表示的音频流被用于三种视频码率版本(rendition)。


FFmpeg获取这些音频和视频的组合后,建立出名为stream_%v.m3u8的各变体的.m3u8 文件,其中%v 是一个迭代器,它从被打包的视频流编号获取对应的值。

 

使用FFmpeg建立主播放列表(m3u8)


若是你已经理解了如何使用FFmpeg建立HLS播放列表,那么使用FFmpeg建立主播放列表对你而言就很简单了。若是你不知道什么是主播放列表的话,我能够告诉你:主播放列表就是一个文件,它列出了已由HLS打包的各个变体的播放列表。


为了使用FFmpeg建立主播放列表,只需将关键词master_pl_name 添加到你的FFmpeg命令中,并提供你为主播放列表准备的名称。好比,若是你想称“主播放列表”为“master.m3u8”,只需写下以下命令:


-master_pl_name master.m3u8

 

这就能够了。在FFmpeg执行该命令行以后,你将拥有一个HLS主播放列表,其中列出了其余播放列表的名称。



使用FFmpeg-VOD进行HLS打包的最终脚本


ffmpeg -i brooklynsfinest_clip_1080p.mp4 \-filter_complex \"[0:v]split=3[v1][v2][v3]; \[v1]copy[v1out]; [v2]scale=w=1280:h=720[v2out]; [v3]scale=w=640:h=360[v3out]" \-map [v1out] -c:v:0 libx264 -x264-params "nal-hrd=cbr:force-cfr=1" -b:v:0 5M -maxrate:v:0 5M -minrate:v:0 5M -bufsize:v:0 10M -preset slow -g 48 -sc_threshold 0 -keyint_min 48 \-map [v2out] -c:v:1 libx264 -x264-params "nal-hrd=cbr:force-cfr=1" -b:v:1 3M -maxrate:v:1 3M -minrate:v:1 3M -bufsize:v:1 3M -preset slow -g 48 -sc_threshold 0 -keyint_min 48 \-map [v3out] -c:v:2 libx264 -x264-params "nal-hrd=cbr:force-cfr=1" -b:v:2 1M -maxrate:v:2 1M -minrate:v:2 1M -bufsize:v:2 1M -preset slow -g 48 -sc_threshold 0 -keyint_min 48 \-map a:0 -c:a:0 aac -b:a:0 96k -ac 2 \-map a:0 -c:a:1 aac -b:a:1 96k -ac 2 \-map a:0 -c:a:2 aac -b:a:2 48k -ac 2 \-f hls \-hls_time 2 \-hls_playlist_type vod \-hls_flags independent_segments \-hls_segment_type mpegts \-hls_segment_filename stream_%v/data%02d.ts \-master_pl_name master.m3u8 \-var_stream_map "v:0,a:0 v:1,a:1 v:2,a:2" stream_%v.m3u8


让咱们看下该脚本的输出。


它首先生成一个主播放列表,三个文件夹包含独立的切片,以及三个变体的播放列表。


                                                  

下面是master.m3u8文件:


#EXTM3U#EXT-X-VERSION:6#EXT-X-STREAM-INF:BANDWIDTH=5605600,RESOLUTION=1920x1080,CODECS="avc1.640032,mp4a.40.2"stream_0.m3u8
#EXT-X-STREAM-INF:BANDWIDTH=3405600,RESOLUTION=1280x720,CODECS="avc1.64001f,mp4a.40.2"stream_1.m3u8
#EXT-X-STREAM-INF:BANDWIDTH=1205600,RESOLUTION=640x360,CODECS="avc1.64001e,mp4a.40.2"stream_2.m3u8

 

你能够看到,主播放列表引用了分别用于1080p、720p和360p的HLS变体播放列表。


如今,咱们来看看1080p HLS变体。它很明确地代表它是一个VOD播放列表,视频切片都是独立的,每一个切片长度是2秒(按照咱们的设置)。

 

#EXTM3U#EXT-X-VERSION:6#EXT-X-TARGETDURATION:2#EXT-X-MEDIA-SEQUENCE:0#EXT-X-PLAYLIST-TYPE:VOD#EXT-X-INDEPENDENT-SEGMENTS#EXTINF:2.002000,data00.ts#EXTINF:2.002000,data01.ts#EXTINF:2.002011,data02.ts#EXTINF:2.002000,data03.ts#EXTINF:2.002000,data04.ts#EXTINF:2.002000,data05.ts#EXTINF:2.002000,data06.ts#EXTINF:2.002000,data07.ts#EXTINF:2.002011,data08.ts#EXTINF:2.002000,data09.ts#EXTINF:0.041711,data10.ts#EXT-X-ENDLIST


 

使用FFmpeg进行HLS直播打包


若是你想经过FFmpeg建立一个直播HLS播放列表,这个过程和咱们刚刚讲过的VOD步骤区别不是很大。下面是你须要作出的更改: 


  1. 删除-hls_playlist_type vod

  2. 添加-hls_list_size ,并将其设置为一个数字,该数字表示各个变体播放列表中的切片数(你但愿设置的数字)。


好比,若是咱们将-hls_list_size 设置为2,那么整个播放列表将只包含两个切片,FFmpeg将经过添加新的切片及删除旧切片来重写这个播放列表。


下面是一个示例:

 

#EXTM3U#EXT-X-VERSION:6#EXT-X-TARGETDURATION:2#EXT-X-MEDIA-SEQUENCE:1#EXT-X-INDEPENDENT-SEGMENTS#EXTINF:2.002000,data01.ts#EXTINF:2.002011,data02.ts


几秒以后,切片data01.ts被删除,并被切片data03.ts所取代。


#EXTM3U#EXT-X-VERSION:6#EXT-X-TARGETDURATION:2#EXT-X-MEDIA-SEQUENCE:2#EXT-X-INDEPENDENT-SEGMENTS#EXTINF:2.002011,data02.ts#EXTINF:2.002000,data03.ts

 

 

FFmepg中其余有用的HLS打包选项


最后,让咱们来快速浏览一些FFmpeg为点播和直播HLS打包所提供的一些其余有趣选项:


  1. hls_base_url baseurl  : 可用于将baseurl表示的值追加到播放列表的每一个条目。


  2. hls_fmp4_init_filename filename :  设置文件名为分片文件头文件,默认文件名为init.mp4。当你把片断类型设置为fmp4而非mpegts时,就会用到这个文件。


  3. hls_fmp4_init_resend:在m3u8文件每次刷新时,从新发送init文件,默认为0。


    审校者注:当var_stream_map设置为两个或多个变体流时,文件名模式必须包含字符串"%v",这个字符串指定变体流索引在生成的init文件名中的位置。这时候能够结合上面的 hls_fmp4_init_resend 从新发送init文件。


  4. iframes_only : 将#EXT-X-I-FRAMES-ONLY添加到包含视频切片并只能在 #EXT-X-BYTERANGE 模式下播放I帧的播放列表中。


 

结语


如今,我但愿你已经很好地理解了如何经过FFmpeg来执行HLS流媒体协议转码和打包。有关使用 FFmpeg 进行 HLS 打包的完整选项列表,请查看 FFmpeg文档:

https://ffmpeg.org/ffmpeg-formats.html#hls-2

 

保重,咱们下次见!




致谢:

本文已得到做者Krishna Rao Vijayanagar受权翻译和发布,特此感谢。


原文连接:

https://ottverse.com/hls-packaging-using-ffmpeg-live-vod/


延伸阅读:

如何使用FFmpeg将AVI转换为MP4(有损转换和无损转换)

使用FFmpeg添加、删除、替换和提取视频中的音频

一文简述FFmpeg

FFmpeg 5.0 正式发布





喜欢咱们的内容就点个“在看”吧!

本文分享自微信公众号 - LiveVideoStack(livevideostack)。
若有侵权,请联系 support@oschina.cn 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一块儿分享。