ffmpeg下载
我们通过 http://ffmpeg.org/ 下载ffmpeg。解压之后会找到三个文件:
- ffmpeg,fast forword mpeg,音视频文件转换命令行工具
- ffplay,fast forword play,用ffmpeg实现的简单媒体播放器
- ffprobe,fast forword probe,用来分析查看多媒体文件的输入流
在这里,我们只需要利用"ffmpeg",音视频文件转换命令行工具。
视频文件
为了更好的讨论下文"ffmpeg"的应用,我们简单的介绍一下视频文件。
容器
视频文件被称作容器(container),一个视频文件就是一个容器(container),里面包括了视频和音频,也可能有字幕等其他内容。
常见的容器格式有:mp4、mkv、avi等,也就是我们常见的视频文件的格式。
通过命令ffmpeg -formats
,可以查看ffmpeg支持的容器。示例代码:
运行结果:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| ffmpeg version 2021-11-07-git-45dc668aea-full_build-www.gyan.dev Copyright (c) 2000-2021 the ffmpeg developers built with gcc 11.2.0 (Rev1, Built by MSYS2 project) configuration: --enable-gpl --enable-version3 --enable-static --disable-w32threads --disable-autodetect --enable-fontconfig --enable-iconv --enable-gnutls --enable-libxml2 --enable-gmp --enable-lzma --enable-libsnappy --enable-zlib --enable-librist --enable-libsrt --enable-libssh --enable-libzmq --enable-avisynth --enable-libbluray --enable-libcaca --enable-sdl2 --enable-libdav1d --enable-libzvbi --enable-librav1e --enable-libsvtav1 --enable-libwebp --enable-libx264 --enable-libx265 --enable-libxvid --enable-libaom --enable-libopenjpeg --enable-libvpx --enable-libass --enable-frei0r --enable-libfreetype --enable-libfribidi --enable-libvidstab --enable-libvmaf --enable-libzimg --enable-amf --enable-cuda-llvm --enable-cuvid --enable-ffnvcodec --enable-nvdec --enable-nvenc --enable-d3d11va --enable-dxva2 --enable-libmfx --enable-libglslang --enable-vulkan --enable-opencl --enable-libcdio --enable-libgme --enable-libmodplug --enable-libopenmpt --enable-libopencore-amrwb --enable-libmp3lame --enable-libshine --enable-libtheora --enable-libtwolame --enable-libvo-amrwbenc --enable-libilbc --enable-libgsm --enable-libopencore-amrnb --enable-libopus --enable-libspeex --enable-libvorbis --enable-ladspa --enable-libbs2b --enable-libflite --enable-libmysofa --enable-librubberband --enable-libsoxr --enable-chromaprint libavutil 57. 7.100 / 57. 7.100 libavcodec 59. 12.100 / 59. 12.100 libavformat 59. 8.100 / 59. 8.100 libavdevice 59. 0.101 / 59. 0.101 libavfilter 8. 16.101 / 8. 16.101 libswscale 6. 1.100 / 6. 1.100 libswresample 4. 0.100 / 4. 0.100 libpostproc 56. 0.100 / 56. 0.100 File formats: D. = Demuxing supported .E = Muxing supported -- D 3dostr 3DO STR E 3g2 3GP2 (3GPP2 file format) E 3gp 3GP (3GPP file format) D 4xm 4X Technologies E a64 a64 - video for Commodore 64
【部分运行结果略】
D xvag Sony PS3 XVAG D xwd_pipe piped xwd sequence D xwma Microsoft xWMA D yop Psygnosis YOP DE yuv4mpegpipe YUV4MPEG pipe
|
编码格式
视频和音频都需要经过编码,才能保存成文件。不同的编码格式(CODEC),有不同的压缩率,会导致文件大小和清晰度的差异。
常用的视频编码格式如下:
H.262
H.264
H.265
VP8
VP9
AV1
常用的音频编码格式如下:
通过命令ffmpeg -codecs
,可以查看ffmpeg支持的编码格式。示例代码:
运行结果:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
| ffmpeg version 2021-11-07-git-45dc668aea-full_build-www.gyan.dev Copyright (c) 2000-2021 the ffmpeg developers built with gcc 11.2.0 (Rev1, Built by MSYS2 project) configuration: --enable-gpl --enable-version3 --enable-static --disable-w32threads --disable-autodetect --enable-fontconfig --enable-iconv --enable-gnutls --enable-libxml2 --enable-gmp --enable-lzma --enable-libsnappy --enable-zlib --enable-librist --enable-libsrt --enable-libssh --enable-libzmq --enable-avisynth --enable-libbluray --enable-libcaca --enable-sdl2 --enable-libdav1d --enable-libzvbi --enable-librav1e --enable-libsvtav1 --enable-libwebp --enable-libx264 --enable-libx265 --enable-libxvid --enable-libaom --enable-libopenjpeg --enable-libvpx --enable-libass --enable-frei0r --enable-libfreetype --enable-libfribidi --enable-libvidstab --enable-libvmaf --enable-libzimg --enable-amf --enable-cuda-llvm --enable-cuvid --enable-ffnvcodec --enable-nvdec --enable-nvenc --enable-d3d11va --enable-dxva2 --enable-libmfx --enable-libglslang --enable-vulkan --enable-opencl --enable-libcdio --enable-libgme --enable-libmodplug --enable-libopenmpt --enable-libopencore-amrwb --enable-libmp3lame --enable-libshine --enable-libtheora --enable-libtwolame --enable-libvo-amrwbenc --enable-libilbc --enable-libgsm --enable-libopencore-amrnb --enable-libopus --enable-libspeex --enable-libvorbis --enable-ladspa --enable-libbs2b --enable-libflite --enable-libmysofa --enable-librubberband --enable-libsoxr --enable-chromaprint libavutil 57. 7.100 / 57. 7.100 libavcodec 59. 12.100 / 59. 12.100 libavformat 59. 8.100 / 59. 8.100 libavdevice 59. 0.101 / 59. 0.101 libavfilter 8. 16.101 / 8. 16.101 libswscale 6. 1.100 / 6. 1.100 libswresample 4. 0.100 / 4. 0.100 libpostproc 56. 0.100 / 56. 0.100 Codecs: D..... = Decoding supported .E.... = Encoding supported ..V... = Video codec ..A... = Audio codec ..S... = Subtitle codec ...I.. = Intra frame-only codec ....L. = Lossy compression .....S = Lossless compression ------- D.VI.S 012v Uncompressed 4:2:2 10-bit D.V.L. 4xm 4X Movie D.VI.S 8bps QuickTime 8BPS video .EVIL. a64_multi Multicolor charset for Commodore 64 (encoders: a64multi ) .EVIL. a64_multi5 Multicolor charset for Commodore 64, extended with 5th color (colram) (encoders: a64multi5 ) D.V..S aasc Autodesk RLE D.V.L. agm Amuse Graphics Movie D.VIL. aic Apple Intermediate Codec DEVI.S alias_pix Alias/Wavefront PIX image DEVIL. amv AMV Video D.V.L. anm Deluxe Paint Animation D.V.L. ansi ASCII/ANSI art DEV..S apng APNG (Animated Portable Network Graphics) image
【部分运行结果略】
|
编码器
那么,如何按照编码格式进行文件的编码呢?
这就需要编码器(encoders)了。
ffmpeg内置的视频编码器有:
libx264
:最流行的开源H.264
编码器
NVENC
:基于NVIDIA GPU的H.264
编码器
libx265
:开源的HEVC
编码器
libvpx
:谷歌的VP8
和VP9
编码器
libaom
:AV1
编码器
ffmpeg内置的音频编码器有:
可以通过命令ffmpeg -encoders
可以查看ffmpeg已安装的编码器。
示例代码:
运行结果:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
| ffmpeg version 2021-11-07-git-45dc668aea-full_build-www.gyan.dev Copyright (c) 2000-2021 the ffmpeg developers built with gcc 11.2.0 (Rev1, Built by MSYS2 project) configuration: --enable-gpl --enable-version3 --enable-static --disable-w32threads --disable-autodetect --enable-fontconfig --enable-iconv --enable-gnutls --enable-libxml2 --enable-gmp --enable-lzma --enable-libsnappy --enable-zlib --enable-librist --enable-libsrt --enable-libssh --enable-libzmq --enable-avisynth --enable-libbluray --enable-libcaca --enable-sdl2 --enable-libdav1d --enable-libzvbi --enable-librav1e --enable-libsvtav1 --enable-libwebp --enable-libx264 --enable-libx265 --enable-libxvid --enable-libaom --enable-libopenjpeg --enable-libvpx --enable-libass --enable-frei0r --enable-libfreetype --enable-libfribidi --enable-libvidstab --enable-libvmaf --enable-libzimg --enable-amf --enable-cuda-llvm --enable-cuvid --enable-ffnvcodec --enable-nvdec --enable-nvenc --enable-d3d11va --enable-dxva2 --enable-libmfx --enable-libglslang --enable-vulkan --enable-opencl --enable-libcdio --enable-libgme --enable-libmodplug --enable-libopenmpt --enable-libopencore-amrwb --enable-libmp3lame --enable-libshine --enable-libtheora --enable-libtwolame --enable-libvo-amrwbenc --enable-libilbc --enable-libgsm --enable-libopencore-amrnb --enable-libopus --enable-libspeex --enable-libvorbis --enable-ladspa --enable-libbs2b --enable-libflite --enable-libmysofa --enable-librubberband --enable-libsoxr --enable-chromaprint libavutil 57. 7.100 / 57. 7.100 libavcodec 59. 12.100 / 59. 12.100 libavformat 59. 8.100 / 59. 8.100 libavdevice 59. 0.101 / 59. 0.101 libavfilter 8. 16.101 / 8. 16.101 libswscale 6. 1.100 / 6. 1.100 libswresample 4. 0.100 / 4. 0.100 libpostproc 56. 0.100 / 56. 0.100 Encoders: V..... = Video A..... = Audio S..... = Subtitle .F.... = Frame-level multithreading ..S... = Slice-level multithreading ...X.. = Codec is experimental ....B. = Supports draw_horiz_band .....D = Supports direct rendering method 1 ------ V....D a64multi Multicolor charset for Commodore 64 (codec a64_multi) V....D a64multi5 Multicolor charset for Commodore 64, extended with 5th color (colram) (codec a64_multi5) V..... alias_pix Alias/Wavefront PIX image V..... amv AMV Video V....D apng APNG (Animated Portable Network Graphics) image V..... asv1 ASUS V1 V..... asv2 ASUS V2 V....D libaom-av1 libaom AV1 (codec av1) V....D librav1e librav1e AV1 (codec av1) V..... libsvtav1 SVT-AV1(Scalable Video Technology for AV1) encoder (codec av1) V....D avrp Avid 1:1 10-bit RGB Packer V..X.D avui Avid Meridien Uncompressed
【部分运行结果略】
|
ffmpeg命令
上文我们简单的讨论了视频文件,知道了"容器"和"编码"两个概念。
现在,我们着重讨论一下ffmpeg命令。
ffmpeg命令格式
ffmpeg 命令的参数非常多,大致可以分成五个部分。
1
| ffmpeg {1} {2} -i {3} {4} {5}
|
{1}
:全局参数
{2}
:输入文件参数
{3}
:输入文件
{4}
:输出文件参数
{5}
:输出文件
为了便于阅读,我们还可以将ffmpeg命令还可以写成多行,用\
标识换行
1 2 3 4 5 6
| ffmpeg \ [全局参数] \ [输入文件参数] \ -i [输入文件] \ [输出文件参数] \ [输出文件]
|
示例代码:
1 2 3 4 5 6
| ffmpeg \ -y \ # 全局参数 -c:a libfdk_aac -c:v libx264 \ # 输入文件参数 -i input.mp4 \ # 输入文件 -c:v libvpx-vp9 -c:a libvorbis \ # 输出文件参数 output.webm # 输出文件
|
解释说明:
上述的命令将"mp4容器"转成"webm容器",输入的"mp4容器"的音频编码格式是"aac",视频编码格式是"H.264";输出的"webm容器"的视频编码格式是"VP9",音频格式是"vorbis",如果存在同名的输出文件,直接覆盖。
常用命令参数
ffmpeg的常用命令行参数如下:
-c
:指定编码器
-c copy
:直接复制,不经过重新编码。
-c:v
:指定视频编码器
-c:a
:指定音频编码器
-i
:指定输入文件
-an
:去除音频流
-vn
: 去除视频流
-preset
:指定输出的视频质量
有以下几个可用的值:ultrafast
、superfast
、veryfast
、faster
、fast
、medium
、slow
、slower
、veryslow
。
-y
:对于命令执行期间的选项直接同意,在这里是输出时直接覆盖同名文件。
我们举几个例子。
1、查看视频文件的编码格式和比特率等
示例代码:
1
| .\ffmpeg.exe -i .\01.avi
|
运行结果:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| ffmpeg version 4.4-full_build-www.gyan.dev Copyright (c) 2000-2021 the ffmpeg developers built with gcc 10.2.0 (Rev6, Built by MSYS2 project) configuration: --enable-gpl --enable-version3 --enable-static --disable-w32threads --disable-autodetect --enable-fontconfig --enable-iconv --enable-gnutls --enable-libxml2 --enable-gmp --enable-lzma --enable-libsnappy --enable-zlib --enable-librist --enable-libsrt --enable-libssh --enable-libzmq --enable-avisynth --enable-libbluray --enable-libcaca --enable-sdl2 --enable-libdav1d --enable-libzvbi --enable-librav1e --enable-libsvtav1 --enable-libwebp --enable-libx264 --enable-libx265 --enable-libxvid --enable-libaom --enable-libopenjpeg --enable-libvpx --enable-libass --enable-frei0r --enable-libfreetype --enable-libfribidi --enable-libvidstab --enable-libvmaf --enable-libzimg --enable-amf --enable-cuda-llvm --enable-cuvid --enable-ffnvcodec --enable-nvdec --enable-nvenc --enable-d3d11va --enable-dxva2 --enable-libmfx --enable-libglslang --enable-vulkan --enable-opencl --enable-libcdio --enable-libgme --enable-libmodplug --enable-libopenmpt --enable-libopencore-amrwb --enable-libmp3lame --enable-libshine --enable-libtheora --enable-libtwolame --enable-libvo-amrwbenc --enable-libilbc --enable-libgsm --enable-libopencore-amrnb --enable-libopus --enable-libspeex --enable-libvorbis --enable-ladspa --enable-libbs2b --enable-libflite --enable-libmysofa --enable-librubberband --enable-libsoxr --enable-chromaprint libavutil 56. 70.100 / 56. 70.100 libavcodec 58.134.100 / 58.134.100 libavformat 58. 76.100 / 58. 76.100 libavdevice 58. 13.100 / 58. 13.100 libavfilter 7.110.100 / 7.110.100 libswscale 5. 9.100 / 5. 9.100 libswresample 3. 9.100 / 3. 9.100 libpostproc 55. 9.100 / 55. 9.100 Input #0, avi, from '.\01.avi': Duration: 00:45:23.32, start: 0.000000, bitrate: 1619 kb/s Stream #0:0: Video: mpeg4 (Advanced Simple Profile) (XVID / 0x44495658), yuv420p, 720x486 [SAR 1:1 DAR 40:27], 1494 kb/s, 29.97 fps, 29.97 tbr, 29.97 tbn, 29.97 tbc Stream #0:1: Audio: mp3 (U[0][0][0] / 0x0055), 44100 Hz, stereo, fltp, 111 kb/s At least one output file must be specified
|
上面命令会输出很多冗余信息,加上-hide_banner
参数,可以只显示元信息。
示例代码:
1
| .\ffmpeg.exe -i .\01.avi -hide_banner
|
运行结果:
1 2 3 4
| Input #0, avi, from '.\01.avi': Duration: 00:45:23.32, start: 0.000000, bitrate: 1619 kb/s Stream #0:0: Video: mpeg4 (Advanced Simple Profile) (XVID / 0x44495658), yuv420p, 720x486 [SAR 1:1 DAR 40:27], 1494 kb/s, 29.97 fps, 29.97 tbr, 29.97 tbn, 29.97 tbc Stream #0:1: Audio: mp3 (U[0][0][0] / 0x0055), 44100 Hz, stereo, fltp, 111 kb/s
|
2、转换编码格式
转换编码格式(transcoding)指的是,将视频文件从一种编码转成另一种编码。
示例代码:
1
| .\ffmpeg -i 01.avi -c:v libx264 output.mp4
|
运行结果:
1 2 3 4 5 6 7 8 9 10 11 12 13
| ffmpeg version 4.4-full_build-www.gyan.dev Copyright (c) 2000-2021 the ffmpeg developers built with gcc 10.2.0 (Rev6, Built by MSYS2 project) configuration: --enable-gpl --enable-version3 --enable-static --disable-w32threads --disable-autodetect --enable-fontconfig --enable-iconv --enable-gnutls --enable-libxml2 --enable-gmp --enable-lzma --enable-libsnappy --enable-zlib --enable-librist --enable-libsrt --enable-libssh --enable-libzmq --enable-avisynth --enable-libbluray --enable-libcaca --enable-sdl2 --enable-libdav1d --enable-libzvbi --enable-librav1e --enable-libsvtav1 --enable-libwebp --enable-libx264 --enable-libx265 --enable-libxvid --enable-libaom --enable-libopenjpeg --enable-libvpx --enable-libass --enable-frei0r --enable-libfreetype --enable-libfribidi --enable-libvidstab --enable-libvmaf --enable-libzimg --enable-amf --enable-cuda-llvm --enable-cuvid --enable-ffnvcodec --enable-nvdec --enable-nvenc --enable-d3d11va --enable-dxva2 --enable-libmfx --enable-libglslang --enable-vulkan --enable-opencl --enable-libcdio --enable-libgme --enable-libmodplug --enable-libopenmpt --enable-libopencore-amrwb --enable-libmp3lame --enable-libshine --enable-libtheora --enable-libtwolame --enable-libvo-amrwbenc --enable-libilbc --enable-libgsm --enable-libopencore-amrnb --enable-libopus --enable-libspeex --enable-libvorbis --enable-ladspa --enable-libbs2b --enable-libflite --enable-libmysofa --enable-librubberband --enable-libsoxr --enable-chromaprint libavutil 56. 70.100 / 56. 70.100 libavcodec 58.134.100 / 58.134.100
【部分运行结果略】
Press [q] to stop, [?] for help
【部分运行结果略】
frame= 5136 fps=364 q=29.0 size= 16128kB time=00:02:52.03 bitrate= 768.0kbits/s dup=3 drop=0 speed=12.2x
|
这个操作会比较慢,按q
停止。
另外,我们也可以利用格式工厂等软件,这些软件会启用多线程进行转换。
如果当前电脑并不在处理复杂业务的话,用多线程会更快。如果正在处理复杂业务的话,会更慢。原因我们在《基于Java的后端开发入门:8.多线程 [2/2]》有过讨论,有两点:
- 线程创建和销毁都非常耗时并消耗资源。
- 线程之间的切换也会非常耗时并消耗资源。
3、转换容器
转换容器指的是,将视频文件从一种容器转到另一种容器。
示例代码:
1
| ffmpeg -i input.mp4 -c copy output.webm
|
解释一下,该命令只是转了一下容器,内部的编码格式不变,使用-c copy
指定直接拷贝,不转码。
4、调整码率
调整码率指的是,改变编码的比特率,这样视频文件的体积会更小。
1 2 3 4
| ffmpeg \ -i input.mp4 \ -minrate 964K -maxrate 3856K -bufsize 2000K \ output.mp4
|
解释说明:该命令的含义是指定码率最小为964K,最大为3856K,缓冲区大小为2000K。
5、改变分辨率
示例代码:
1 2 3 4
| ffmpeg \ -i input.mp4 \ -vf scale=480:-1 \ output.mp4
|
6、提取音频
示例代码:
1 2 3 4
| ffmpeg \ -i input.mp4 \ -vn -c:a copy \ output.aac
|
解释说明:-vn
表示去掉视频,-c:a copy
表示不改变音频编码,直接拷贝。
7、添加音轨
添加音轨指的是,将外部音频加入视频,比如添加背景音乐或旁白。
示例代码:
1 2 3
| ffmpeg \ -i input.aac -i input.mp4 \ output.mp4
|
解释说明:有音频和视频两个输入文件,ffmpeg会将它们合成为一个文件。
8、视频文件的合并
示例代码:
1
| ffmpeg -i "concat:1.ts|2.ts" -acodec copy -vcodec copy -absf aac_adtstoasc output.mp4
|
切片命令
在讨论了ffmpeg命令之后,我们来解讨论一下和切片有关的命令。
- 将视频转换为ts格式
- 对ts文件进行切片
将视频转换为ts格式
示例代码:
1
| .\ffmpeg -y -i 【文件名】.mp4 -vcodec copy -acodec copy -vbsf h264_mp4toannexb 【文件名】.ts
|
解释说明:
-y
:如果有同名文件,直接覆盖
-i
:输入文件
-vcodec copy
:指定视频编码
-acodec copy
:指定音频编码
-vbsf
:bitstream_filter
在对视频文件转换为ts格式,并进行切片之前,我们还需要做一个操作,“对视频文件进行标准化”,将视频流的编码转为AVC(H264)
,将音频流的编码转为AAC
。
为什么不直接转换为ts格式呢?
因为对于非标准的视频文件,切片会报错,具体的报错原因有待进一步讨论。
但直接进行格式转换,并在转换期间指定编码,可以解决问题。
对ts文件进行切片
通过上述操作,我们得到了一个大的ts文件,接下来要做的就是对ts文件进行切片。
1
| .\ffmpeg -i 【文件名】.ts -c copy -map 0 -f segment -segment_list playlist.m3u8 -segment_time 30 【文件名】%03d.ts
|
解释说明:
-i
:输入文件
-c copy
:编码格式
-map
:-map
用于手动控制每个输出文件中的流选择。
-map 0
:所有
-segment_time
:表示每个片段的长度
-f
:定义输出类型
切片建议
建议每个ts片段以上长度为30秒左右。
那么,为什么建议每个ts片段的长度为30秒呢?
因为每次建立HTTP连接,传输数据,都有一个复杂的过程。
- 如果ts片段太短的话,比如5秒,意味着下一个ts片段需要在5秒内传输过来,而每一次请求都耗费了大量建立连接的时间。
(我试验过ts片段为5秒的情况,卡顿的情况比30秒严重太多)
- 如果ts片段太长的话,比如超过60秒,意味着文件太大,可能加载会非常缓慢。
那么为什么是30秒?不是28秒,29秒呢?30秒只是一个经验数字。
也有资料建议:第一个ts片段长度为3秒;第二个ts片段长度为5秒;第三个ts片段长度为10秒左右;第四个ts片段以上长度为30秒左右;最长ts片段不超过35秒。这种建议是为了提高视频初次载入速度,无论哪种建议,其原因都和网络请求的过程有关。
(在本章的附录部分,会讨论一下网络请求的过程。)
m3u8的概述
通过切片,我们除了得到了一个一个小的ts片段,还得到了"m3u8"文件。
文件内容如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| #EXTM3U #EXT-X-VERSION:3 #EXT-X-MEDIA-SEQUENCE:0 #EXT-X-ALLOW-CACHE:YES #EXT-X-TARGETDURATION:34 #EXTINF:33.433433, 01000.ts #EXTINF:33.366700, 01001.ts #EXTINF:25.025022, 01002.ts #EXTINF:33.366700, 01003.ts #EXTINF:25.025033, 01004.ts
【部分文件内容略】
#EXTINF:25.025022, 01086.ts #EXTINF:33.366700, 01087.ts #EXTINF:33.366700, 01088.ts #EXTINF:25.025022, 01089.ts #EXTINF:20.653989, 01090.ts #EXT-X-ENDLIST
|
"m3u8"是HTTP Live Streaming(HLS)协议的一部分。
HLS是一种流媒体传输协议,其思路为将一个大的媒体文件进行切片,将该切片文件资源路径记录于"m3u8"文件内,并附带一些额外描述用于提供给客户端。客户端依据该"m3u8"文件即可获取对应的媒体资源,进行播放。
m3u8的标签
在上文,我们得到了一个m3u8
文件。
现在,我们讨论一下常见标签及其含义。
EXTM3U
EXTM3U
,表明该文件是一个"m3u8"文件,每个"m3u8"文件必须将该标签放置在第一行。
EXT-X-VERSION
EXT-X-VERSION
,表示"HLS"的协议版本号,每个"m3u8"文件内最多只能出现一个该标签定义。
不同的版本号,对于后续的部分标签都或有影响。
(比如,对于EXTINF
标签)
我们这里的版本号是3
。
EXT-X-MEDIA-SEQUENCE
,表示播放列表第一个片段文件的序列号,每个媒体片段都拥有一个唯一的整型序列号,每个媒体片段序列号按出现顺序依次加1。
EXT-X-ALLOW-CACHE
EXT-X-ALLOW-CACHE
,表示是否允许缓存
EXT-X-TARGETDURATION
EXT-X-TARGETDURATION
,表示每个视频分段最大的时长(单位秒)。
EXT-X-ENDLIST
EXT-X-ENDLIST
,表示"m3u8"文件的结束。
EXT-X-PLAYLIST-TYPE
EXT-X-PLAYLIST-TYPE
,表示流媒体类型,有点播和直播两种。
其格式为:
1
| #EXT-X-PLAYLIST-TYPE:<type-enum>
|
"type-enum"的值表示是点播或直播:
VOD
:表示该视屏流为点播源,通常带有EXT-X-ENDLIST
标签。
EVENT
:表示该视频流为直播源,一般不会有EXT-X-ENDLIST
标签,如果有新的媒体片段会添加到播放列表末尾,因此也需要客户端定时获取该m3u8文件,直到访问到EXT-X-ENDLIST
标签才停止。
EXTINF
EXTINF
,表示其后URI指定的媒体片段时长(单位为秒),每个URI媒体片段之前必须指定该标签。
1
| #EXTINF:<duration>,[<title>]
|
duration
:可以为整型或者浮点型,其值必须小于或等于EXT-X-TARGETDURATION
指定的值。
建议采用浮点型指定时长,这可以让客户端在定位流时,减少四舍五入错误。
但是如果EXT-X-VERSION
小于3,则只支持整型。
m3u8的注意
关于"m3u8"还有几点注意事项。
文件的编码格式
"m3u8"文件必须以"utf-8"进行编码,这也是最后一个字符8
的含义。
m3u8中的#号
"m3u8"文件中以#
开头的字符串要么是注释,要么就是标签。标签以#EXT
开头,大小写敏感。
m3u8中媒体片段的路径
"m3u8"文件中,媒体片段可以采用全路径表示,例如:https://example.com/movie1/fileSequenceA.ts
(所以,也可以将"m3u8"文件和"ts"片段分开存储)
请求m3u8的方法
请求"m3u8"有两种方法:
一是通过"m3u8"的"URL"进行请求,则该文件必须以.m3u8
或.m3u
结尾。
二是通过"HTTP"进行请求,则Content-Type
必须设置为application/vnd.apple.mpegurl
或者audio/mpegurl
。
题外话:网络请求过程
以Chrome浏览器访问"www.kakawanyifan.com"为例。
整体的过程有两步:
- 域名解析
- TCP的3次握手
域名解析
域名解析是解析"www.kakawanyifan.com"这个域名对应的IP地址。
- 首先,Chrome浏览器会搜索浏览器自身的DNS缓存,检索自身的缓存中是否有"www.kakawanyifan.com"对应的条目且没有过期。
该缓存时间比较短,大概只有1分钟。
可以通过chrome://net-internals/#dns
查看。
- 如果浏览器自身的缓存里面没有找到,那么Chrome会搜索操作系统自身的DNS缓存。
可以通过命令ipconfig/displaydns
查看。
- 如果在操作系统的DNS缓存也没有找到,那么尝试读取hosts文件(C:\Windows\System32\drivers\etc),检查hosts文件中是否有该域名对应的IP地址。
- 如果在hosts文件中也没有找到对应的条目,浏览器就会发起一个DNS的系统调用,就会向本地配置的首选DNS服务器(一般是运营商的DNS服务器)发起域名解析请求
- 运营商的DNS服务器首先查找自身的缓存,是否有对应的条目且没有过期。
- 如果没有,接下来就是递归调用了。运营商的DNS服务器首先会找根域的DNS的IP地址,并发起请求(请问"www.kakawanyifan.com"这个域名的IP地址是多少?)
- 根域会返回com域的DNS地址
- 接下来,运营商的DNS服务器向com域的DNS地址发起请求(请问"www.kakawanyifan.com"这个域名的IP地址是多少?)
- com域会kakawanyifan.com这个域的DNS地址
- 运营商的DNS服务器又向kakawanyifan.com这个域名的DNS地址(一般就是由域名注册商提供的)发起请求(请问"www.kakawanyifan.com"这个域的IP地址是多少?)
- 终于!"kakawanyifan.com"域的DNS服务器一查,把结果发送给运营商的DNS服务器,这个时候运营商的DNS服务器终于拿到了"www.kakawanyifan.com"这个域名对应的IP地址,并返回给操作系统,操作系统又把结果返回给浏览器,终于浏览器拿到了"www.kakawanyifan.com"对应的IP地址。
例如:"kakawanyifan.com"的DNS的解析:
正常情况下,通过上述步骤就找到了。如果没有的话,会有如下的操作
- 操作系统就会查找Net BIOS name Cache,但凡最近一段时间内成功通讯过的计算机的计算机名和IP地址,就都会在这个缓存里面。
- 如果没有找到,就会查询WINS服务器。
- 如果没有找到,那么就进行广播查找。
- 如果没有找到,那么就检索LMHOSTS文件中是否有。
- 如果还是没有,那么就失败了。
发起TCP的3次握手
通过域名解析到对应的IP地址之后,故事并没有结束。
这时候浏览器会以一个随机端口[1024,65535]向服务器的WEB程序的80端口发起TCP的连接请求。
这个连接请求,经过各种路由设备,到达服务器端,进入网卡,再进入系统内核的TCP/IP协议栈,最终到达WEB程序,建立了TCP/IP的连接。
然后
- 客户端首先发送一个连接试探,进入syn_sent状态,表示客户端等待服务端的回复。
- 服务端监听到连接请求报文后,如同意建立连接,向客户端发送确认。这时服务端进入syn_rcvd,表示服务端已经收到客户端的连接请求,等待客户端的确认。
- 客户端收到确认后还需再次发送确认给服务端,服务端收到客户端的确认之后,这个TCP连接才进入established状态,可以发起HTTP请求了。
然后,浏览器才发起了HTTP的请求,请求第一个ts片段,服务端把第一个ts片段返回给浏览器。