【深入理解FFMPEG】命令行阅读笔记
这里写自定义目录标题
- 第三章 FFmpeg工具使用基础
- 3.1 ffmpeg常用命令
- 3.1.1
- 3.1.3 转码流程
- 3.2 ffprobe 常用命令
- 3.2.1 ffprobe常用参数
- 3.2.2 ffprobe 使用示例
- 3.3 ffplay常用命令
- 3.3.1 ffplay常用参数
- 3.3.2 ffplay高级参数
- 3.3.4 ffplay快捷键
- 第4章 封装与解封装
- 4.1 视频文件转MP4
- 4.1.4 MP4在FFmpeg中的Demuxer
- 4.2 视频文件转FLV
- 4.3 视频文件转MPEG-TS
- 4.4 视频文件转HLS
- 4.5 视频文件切片
- 4.5.3 使用ss与t参数切片
- 4.6 视频文件的音视频流提取
- 4.6.1 提前AAC音频流
- 4.6.2 提取H.264视频流
- 4.6.3 提取H.265视频流
- 4.7 系统资源使用情况
- 第5章 编码与转码
- 5.1 软编码 H.264
- 5.1.2 H.264编码举例
- 1. 编码器预设参数设置
- 2. H.264编码优化
- 3. H.264的profile和level设置
- 4. 控制场景切换时关键帧的插入
- 5. 设置x264内部参数
- 6. CBR设置
第三章 FFmpeg工具使用基础
3.1 ffmpeg常用命令
ffmpeg --help
ffmpeg -h
ffmpeg -h long 查看高级参数部分
ffmpeg -h full 产科全部参数部分
ffmpeg -h type=name
其中 type为 decoder/encoder/demuxer/muxer/filter/bsf/protocol 的一种
name为对应的组件的名字
ffmpeg -L 查看ffmpeg目前支持的license协议
ffmpeg -version 查看ffmpeg版本,以及子模块的详细版本信息
ffmpeg -formats 查看当前ffmpeg支持的容器文件格式,返回值如下:
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表示 Demuxing, E表示 Muxing
第二列 容器格式在FFmpeg中使用的简短名字
第三列 容器文件格式的补充说明
ffmpeg -codecs 查看编解码格式的所有信息,如:
Codecs:
D..... = Decoding supported
.E.... = Encoding supported
..V... = Video codec
..A... = Audio codec
..S... = Subtitle codec
..D... = Data codec
..T... = Attachment 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表示支持解码,E表示支持编码,以及编码的音频/视频/字幕/数据/附件类型,或者只有I帧的编码压缩格式,以及有损和无损压缩类型
第二列 Codec在FFmpeg中使用的简短名字
第三列 Codec格式的详细说明,如果一个Codec有多个对应实现,也会在小括号中显示出来
ffmpeg -encoders / ffmpeg -decoders
ffmpeg -h muxer=flv
ffmpeg -h demuxer=flv
ffmpeg -h encoder=h264
ffmpeg -h filter=colorkey
3.1.1
ffmpeg 中 AVFormatContext 的主要参数
参数 | 说明 |
---|---|
avioflags | 缓冲设置, 默认为0 direct: 无缓冲 |
probesize | probing size |
等等
ffmpeg 中 AVCodecContext 的主要参数
参数 | 说明 |
---|---|
b | 设置文件码流 |
ab | 设置音频码率(不同音频encoder有不同的默认值), |
g | 设置max gop size |
ar | 设置音频sample_rate, |
ac | 设置音频channel_count, |
bf | 设置连续编码B帧的个数,设置为0是无B帧 |
profile | 设置音视频的profle |
level | 设置音视频的level |
level | 设置音视频的level |
color_primaries | 设置视频的primaries (from 1 to 10) (default unspecified) |
color_trc | 设置视频的color transfer characteristics (from 1 to 18) (default unspecified) |
colorspace | 设置视频的colorspace,如 bt709, rgb 等 |
color_range | 设置视频的range mpeg: MPEG (219*2^(n-8)) jpeg: JPEG (2^n-1) |
更多信息查看ffmpeg -h full 的返回值 |
3.1.3 转码流程
ffmpeg -i input1.rmvb -vcodec mpeg4 -b:v 200k -r 15 -an output.mp4
3.2 ffprobe 常用命令
3.2.1 ffprobe常用参数
ffprobe -v 指定log级别, quiet/panic -> debug/ trace
ffprobe -show_format
ffprobe -show_streams 查看文件的流信息, 如视频codec, 帧率,位深,nal_length_size, profile/level, has_b_frames等
ffprobe -show_chpters
ffprobe -v trace -show_format -show_streams -show_chapters -of json video.mp4
3.2.2 ffprobe 使用示例
ffprobe -show_packets input.flv 查看多媒体数据包信息
ffprobe -show_data -show_packets input.flv 查看每一包信息以及包中的具体数据
ffprobe -show_format output.mp4 查看文件format信息
ffprobe -show_frames input.flv 查看视频的每一帧信息
ffprobe -of xml -show_streams input.flv 查看每一路stream的信息,xml的格式输出
此外,of还可以跟 ini/ json/ csv / flat 等信息
ffprobe -show_frames -select_streams v -of xml input.mp4 只查看视频信息
select_streams 后面可以跟 v a s,分别表示 视频/音频/字幕
如果不需要输出所有字段的信息,可以结合 show_entries来使用,如:
ffprobe -select_streams v -show_packets -show_entries packet=codec_type,pts_time,pos input.mp4
表示只输出 packet中的 codec_type/pst_time/pos等字段信息
ffprobe -v trace input.mp4 2>&1| findstr “parent:‘root’” 查看文件中box的位置信息
3.3 ffplay常用命令
3.3.1 ffplay常用参数
ffplay --help
与ffplay 相关的命令
x, y 设置显示窗口的宽高
s 设置视频显示宽高,主要用于播放yuv/rgb裸流, 有的版本没有这个信息
fs 强制全屏播放
an/vn/sn 屏蔽音频/视频/字幕
ss/t 设置seek开始的秒数/设置播放的时间长度
bytes: seek by byes, 0:off, 1:on, -1 auto
nodisp: 关闭显示窗口
f 强制使用某格式,主要用于rawvideo播放裸流
window_title 设置显示窗口的标题
af/vf 设置音频/视频滤镜
codec 强制使用某个codec, 主要针对存在多个视频codec的情况
autorotate 自动旋转视频
ffplay -ss 0 -t 10 input.mp4
ffplay -window_title “Hello, World” output.mp4
ffplay -window_title “播放测试” rtmp://up.v.test.com/live/stream //实际播放不了
3.3.2 ffplay高级参数
ast/vst/sst 设置将要播放音频/视频/字幕流
stats 输出多媒体播放状态 //没发现有啥作用
autoexit 播放完成后自动退出ffplay, 默认不自动退出
exitonkeydown/exitonmousedown 有按键事件/鼠标按键事件后退出ffplay
loop 设置播放循环次数
framedrop cpu占用过高时,自动丢帧
infbuf 设置无极限的播放器buffer,主要用于流媒体播放场景
vf 设置视频滤镜
acodec/vcodec/scodec 强制使用某个codec
time xxx // window上无法使用time统计耗时信息
ffplay -vcodec h264 output.mp4 强制使用h264解码器解码非h264码流会报错
ffmpeg -vst 4 -ast 5 test.ts 针对ts流中有多路节目时,选择对应的音频流和视频流
ffplay -window_title “Test Movie” -vf “subtitles=input.srt” output.mp4
播放视频时,带上 input.srt的字幕文件
input.srt内容可以为
1
00:00:00.000 --> 00:00::30.000
Test first 30 second
2
00:00:00.301 --> 00:00::60.000
Test second 30 second
3
00:01:01.000 --> 00:01::10.000
Test end
3.3.3 ffplay的数据可视化分析应用
ffplay -showmode 1 output.mp3 //音频的波形以振幅的形式显示出来
ffplay -debug vis_mb_type -window_title “show vis_mb_type” -ss 20 -t 10 -autoexit output.mp4
注: 较新的版本上的 AVCodecContext 帮助中,其-debug没有 vis_mb_type, 只有 qp/mb_type 等信息,不是打印在视频的宏块上,而是直接打印在log里面,如下图,打印的是720x960(每帧45x60个宏块)视频的qp信息,
下面时某一帧每个宏块的qp值
ffplay -vismv pf output.mp4 // 没有 vismv 这个命令
ffplay -flags2 +export_mvs video.mp4 -vf codecview=mv=pf+bf+bb // 这个可以将mv信息显示在画面上,如果没有 flags参数,单纯使用 codecview filter,还是无效果
3.3.4 ffplay快捷键
ffplay播放过程中的一些快捷键
快捷键 | 功能 |
---|---|
f | 全屏/非全屏切换 |
f | 全屏/非全屏切换 |
s | 逐帧显示图像,(暂停的状态时) |
w | 显示图像和声音波形之间切换 |
← / → | 后退10s/前进10s |
↑ / ↓ | 前进60s/后台60s |
鼠标右键单击 | seek至指定位置 |
鼠标左键双击 | 切换全屏/非全屏 |
m | 静音切换 |
功能键区(非小键盘)的 9和0 | 增大和减小音量 |
小键盘区的 / 和 * | 增大和减小音量 |
p | 暂停/恢复播放 |
q和 ESC | 退出播放 |
第4章 封装与解封装
4.1 视频文件转MP4
4.1.4 MP4在FFmpeg中的Demuxer
ffmpeg -h demuxer=mp4
个人觉得有用的信息
ignore_editlist 忽略EditList box信息,默认不开启,
如果同一个视频,ffplay播放音视频不同步,其他播放器正常,可能是mp4的 editlist box里面的参数缘故,设置这个参数再尝试一下
ffmpeg -h muxer=mp4
个人觉得有用的信息
movflags
faststart 设置将moov box置于文件的开头,
dash 将MP4封装为fragment mp4,以便兼容DASH
ffmpeg -i input.flv -c copy -f mp4 output.mp4
ffmpeg -i input.flv -c copy -f mp4 -movflags faststart output.mp4
ffmpeg -i input.flv -c copy -f mp4 -movflags dash output.mp4
ffmpeg -re -i input.mp4 -c copy -movflags isml+frag_keyframe -f ismv Stream //与普通mp4的差异就是,Stream里面的 compatible_brands为 ismlpiff, 这里的 -re 表示 每秒只读取1s的input.mp4数据来处理,所以视频有多长,转码时间就会有多长,为了加快速度,可以取消到 -re 这个命令
ffmpeg -i input.mp4 -c:v libx265 -c:a aac -crf 25 -tag:v hvc1 outputh265.mp4
与不加 -tag:v hvc1生成的普通Mp4相比,
普通MP4视频生成 hev1 box, 这里生成 hvc1 box
4.2 视频文件转FLV
ffmpeg -h muxer=flv 查看 flv muxer的使用信息
ffmpeg -i input_ac3.mp4 -c copy -f flv output.flv
ffmpeg -i input_ac3.mp4 -vcodec copy -acodec aac -f flv output.flv
ffmpeg -i input.mp4 -c copy -f flv -flvflags add_keyframe_index output.flv
相比默认 不加 flvflags的命令,生成的flv文件,多了存放关键帧信息的metadata
ffprobe -v trace -i output.flv // 查看flv信息
4.3 视频文件转MPEG-TS
TS/PS 分为三层
- ES层: 单独的音频流视频流组成的Elementary Stream, ES
- PES层: 将ES按一定的规则进行封装,如H.264的AU作为拆分单元,打上时间戳,组成分组的基本数据流 Packetized Elementary Stream, PES,
- TS/PS 层: 将PES包进行切分再封装成固定大小(一般为188 Byte)的传输流 Transport Stream, TS
ffmpeg -h muxer=mpegts 查看mpegts muxer的帮助信息
4.4 视频文件转HLS
ffmpeg -h muxer=hls 查看hls muxer的help信息
ffmpeg -i input.mp4 -c copy -f hls -bsf:v h264_mp4toannexb output.m3u8
实操发现是否加 -bsf:v h264_mp4toannexb, 效果一样,ffmpeg内部会自动把MP4中nal的长度头更换为起始码的头
- start_number参数
ffmpeg -i input.mp4 -c copy -f hls -bsf:v h264_mp4toannexb -start_number 300 output.m3u8 // 设置m3u8中的切片从 300开始
ffmpeg -i input.mp4 -c copy -f hls -bsf:v h264_mp4toannexb -hls_time 10 output.m3u8
每一个切片,几乎都是10s
D:\_Video>type output.m3u8
#EXTM3U
#EXT-X-VERSION:3
#EXT-X-TARGETDURATION:11
#EXT-X-MEDIA-SEQUENCE:0
#EXTINF:11.066667,
output0.ts
#EXTINF:10.166667,
output1.ts
#EXTINF:10.000000,
output2.ts
#EXTINF:6.166667,
output3.ts
#EXT-X-ENDLIST
ffmpeg -i input.mp4 -c copy -f hls -hls_list_size 3 output.m3u8
只保留了最多3片的切片
D:\_Video>type output.m3u8
#EXTM3U
#EXT-X-VERSION:3
#EXT-X-TARGETDURATION:2
#EXT-X-MEDIA-SEQUENCE:13
#EXTINF:2.266667,
output13.ts
#EXTINF:2.300000,
output14.ts
#EXTINF:1.600000,
output15.ts
#EXT-X-ENDLIST
hls_wrap 参数已经废弃
ffmpeg -i input.mp4 -c copy -f hls -hls_base_url http://192.168.0.1/lives/ output1.m3u8
从生成的m3u8来看,每个分片都加了 http://192.168.0.1/lives/ 的前缀
D:\_Video>type output1.m3u8
#EXTM3U
#EXT-X-VERSION:3
#EXT-X-TARGETDURATION:2
#EXT-X-MEDIA-SEQUENCE:11
#EXTINF:1.800000,
http://192.168.0.1/lives/output111.ts
#EXTINF:1.833333,
http://192.168.0.1/lives/output112.ts
#EXTINF:2.266667,
http://192.168.0.1/lives/output113.ts
#EXTINF:2.300000,
http://192.168.0.1/lives/output114.ts
#EXTINF:1.600000,
http://192.168.0.1/lives/output115.ts
#EXT-X-ENDLIST
ffmpeg -i input.mp4 -c copy -vframes 1000 -f hls -hls_segment_filename test_output-%d.ts output.m3u8
可以看出,切片名字不再是默认的 output1.ts, output2.ts 这些ts
而是指定的 test_output-%d.ts
D:\_Video>type output.m3u8
#EXTM3U
#EXT-X-VERSION:3
#EXT-X-TARGETDURATION:3
#EXT-X-MEDIA-SEQUENCE:9
#EXTINF:3.066667,
test_output-9.ts
#EXTINF:3.300000,
test_output-10.ts
#EXTINF:1.800000,
test_output-11.ts
#EXTINF:1.833333,
test_output-12.ts
#EXTINF:2.100000,
test_output-13.ts
#EXT-X-ENDLIST
ffmpeg -f lavfi -i testsrc2=s=176x144:r=15 -vcodec libx264 -g 30 -r:v 15 -f hls -hls_time 2 -hls_list_size 4 -hls_flags delete_segments -t 30 output-test.m3u8
D:\_Video>type output-test.m3u8
#EXTM3U
#EXT-X-VERSION:3
#EXT-X-TARGETDURATION:2
#EXT-X-MEDIA-SEQUENCE:11
#EXTINF:2.000000,
output-test11.ts
#EXTINF:2.000000,
output-test12.ts
#EXTINF:2.000000,
output-test13.ts
#EXTINF:2.000000,
output-test14.ts
#EXT-X-ENDLIST
-t 30 指定要生成30s的视频,hls_time 为2,指定切片duration为2s, 故一共有15个切片
从 output-test0 - output-test14
而这是了 delete_segment, 且 hls_list_size 4, 故前11个切片都删了,只保留最后4个
ffmpeg -i input.mp4 -c copy -f hls -hls_flags round_durations output.m3u8
D:\_Video>type output.m3u8
#EXTM3U
#EXT-X-VERSION:2
#EXT-X-TARGETDURATION:2
#EXT-X-MEDIA-SEQUENCE:11
#EXTINF:2,
output11.ts
#EXTINF:2,
output12.ts
#EXTINF:2,
output13.ts
#EXTINF:2,
output14.ts
#EXTINF:2,
output15.ts
#EXT-X-ENDLIST
每一片的切片时长变为了整数,而不是浮点数了
ffmpeg -i input.mp4 -c copy -f hls -hls_flags discont_start -bsf:v h264_mp4toannexb output.m3u8
生成的m3u8文件中,实际并没有 discontinuity 标签, why?
D:\_Video>type output.m3u8
#EXTM3U
#EXT-X-VERSION:3
#EXT-X-TARGETDURATION:2
#EXT-X-MEDIA-SEQUENCE:11
#EXTINF:1.800000,
output11.ts
#EXTINF:1.833333,
output12.ts
#EXTINF:2.266667,
output13.ts
#EXTINF:2.300000,
output14.ts
#EXTINF:1.600000,
output15.ts
#EXT-X-ENDLIST
ffmpeg -i input.mp4 -c copy -vframes 2000 -f hls -hls_flags omit_endlist -bsf:v h264_mp4toannexb output.m3u8
生成的 m3u8文件中,没有 endlist 标签
D:\_Video>type output.m3u8
#EXTM3U
#EXT-X-VERSION:3
#EXT-X-TARGETDURATION:2
#EXT-X-MEDIA-SEQUENCE:11
#EXTINF:1.800000,
output11.ts
#EXTINF:1.833333,
output12.ts
#EXTINF:2.266667,
output13.ts
#EXTINF:2.300000,
output14.ts
#EXTINF:1.600000,
output15.ts
ffmpeg -i input.mp4 -c copy -f hls -hls_time 2 -hls_flags split_by_time output.m3u8
hls_time设置的切片duration已经生效,几乎都是2s,
由于不是根据关键帧分隔的,所有播放某些片段是,会先花屏或者报错,直至遇到I帧
D:\_Video>type output.m3u8
#EXTM3U
#EXT-X-VERSION:3
#EXT-X-TARGETDURATION:2
#EXT-X-MEDIA-SEQUENCE:14
#EXTINF:2.033333,
output14.ts
#EXTINF:1.966667,
output15.ts
#EXTINF:2.000000,
output16.ts
#EXTINF:2.133333,
output17.ts
#EXTINF:1.400000,
output18.ts
#EXT-X-ENDLIST
ffmpeg -re -i input.mp4 -c copy -vframes 2000 -f hls -strftime 1 -bsf:v h264_mp4toannexb output.m3u8
strftime参数用于设置HLS切片文件名,以生成TS切片文件时的系统时间作为文件名。
注意必须要加 -re参数,要不文件1s内生成完毕,所有的文件名都是同一个
D:\_Video>type output.m3u8
#EXTM3U
#EXT-X-VERSION:3
#EXT-X-TARGETDURATION:2
#EXT-X-MEDIA-SEQUENCE:11
#EXTINF:1.800000,
output-20250125232835.ts
#EXTINF:1.833333,
output-20250125232837.ts
#EXTINF:2.266667,
output-20250125232838.ts
#EXTINF:2.300000,
output-20250125232841.ts
#EXTINF:1.600000,
output-20250125232843.ts
#EXT-X-ENDLIST
ffmpeg -i input.mp4 -c copy -f hls -hls_time 3 -hls_list_size 0 -method PUT -t 30 http://127.0.0.1/test/output_test.m3u8
没有搭建推流服务器,等搭建了Nginx后再试(todo)
ffmpeg -i input.mp4 =b:a:0 32k -b:a:1 64k -b:v:0 1000k -map 0:a -map 0:a -map 0:v -f hls -var_stream_map "a:0,agroup:aud_ow,default:yes,language:ENG a:1,agroup:aud_high,language:CHN v:0,agroup:aud_low" -master_pl_name master.m3u8 -t 30 output%v.m3u8
此命令一共生成4个m3u8文件, master.m3u8和 output0.m3u8, output1.m3u8, output2.m3u8,
其中 output0.m3u8和 output1.m3u8中关联的都是音频,output2.m3u8中关联的是视频,
直接播放master.m3u8时,播放的是无声视频,尚不清楚如何播放出相关的音频
内容分别为:
D:\_Video>type master.m3u8
#EXTM3U
#EXT-X-VERSION:3
#EXT-X-MEDIA:TYPE=AUDIO,GROUP-ID="group_aud_ow",NAME="audio_0",DEFAULT=YES,LANGUAGE="ENG",URI="output0.m3u8"
#EXT-X-MEDIA:TYPE=AUDIO,GROUP-ID="group_aud_high",NAME="audio_1",DEFAULT=NO,LANGUAGE="CHN",URI="output1.m3u8"
#EXT-X-STREAM-INF:BANDWIDTH=1100000,RESOLUTION=720x960,CODECS="avc1.64001f"
output2.m3u8
D:\_Video>type output0.m3u8
#EXTM3U
#EXT-X-VERSION:3
#EXT-X-TARGETDURATION:2
#EXT-X-MEDIA-SEQUENCE:11
#EXTINF:1.996911,
output011.ts
#EXTINF:1.996922,
output012.ts
#EXTINF:1.996911,
output013.ts
#EXTINF:1.996922,
output014.ts
#EXTINF:0.023222,
output015.ts
#EXT-X-ENDLIST
D:\_Video>type output1.m3u8
#EXTM3U
#EXT-X-VERSION:3
#EXT-X-TARGETDURATION:2
#EXT-X-MEDIA-SEQUENCE:11
#EXTINF:1.996911,
output111.ts
#EXTINF:1.996922,
output112.ts
#EXTINF:1.996911,
output113.ts
#EXTINF:1.996922,
output114.ts
#EXTINF:0.023222,
output115.ts
#EXT-X-ENDLIST
D:\_Video>type output2.m3u8
#EXTM3U
#EXT-X-VERSION:3
#EXT-X-TARGETDURATION:3
#EXT-X-MEDIA-SEQUENCE:10
#EXTINF:1.033333,
output210.ts
#EXTINF:2.033333,
output211.ts
#EXTINF:3.333333,
output212.ts
#EXTINF:0.900000,
output213.ts
#EXTINF:1.466667,
output214.ts
#EXT-X-ENDLIST
4.5 视频文件切片
ffmpeg -i input.mp4 -c copy -f segment -segment_format mp4 test_output-%d.mp4
此命令生成一堆切片好的mp4文件
如下命令查看第一个切片文件的最后三个pts_time,
ffprobe -v quiet -show_packets -select_streams v test_output-0.mp4 | findstr pts_time > 0.txt
type 0.txt | find /c /v "" > tmp.txt && set /p line=<tmp.txt && set /a last=%line%-10
more +%last% 0.txt
为
pts_time=2.632682
pts_time=2.766016
pts_time=2.699349
pts_time=2.666016
pts_time=2.732682
pts_time=2.932682
pts_time=2.832682
pts_time=2.799349
pts_time=2.866016
pts_time=2.899349
···
ffprobe -v quiet -show_packets -select_streams v test_output-1.mp4 | findstr pts_time > 1.txt
for /l %l in (1,1,10) do @for /f “tokens=1,2* delims=:” %a in (‘findstr /n /r “^” 1.txt ^| findstr /r “^%l:”’) do @echo %b
···
为
pts_time=2.966016
pts_time=3.099349
pts_time=3.032682
pts_time=2.999349
pts_time=3.066016
pts_time=3.232682
pts_time=3.166016
pts_time=3.132682
pts_time=3.199349
pts_time=3.366016
可以看出 test_output-0.mp4的最后一帧时间戳为 2.932682
test_output-1.mp4的第一帧时间戳为 2.966016
是相邻的
- 生成 ffconcat格式的索引文件
ffmpeg -i input.mp4 -c copy -f segment -segment_format mp4 -segment_list_type ffconcat -segment_list output.lst test_output-%d.mp4
生成的 output.lst 内容如下:
D:\_Video>type output.lst
ffconcat version 1.0
file test_output-0.mp4
file test_output-1.mp4
file test_output-2.mp4
file test_output-3.mp4
file test_output-4.mp4
file test_output-5.mp4
file test_output-6.mp4
file test_output-7.mp4
file test_output-8.mp4
file test_output-9.mp4
file test_output-10.mp4
file test_output-11.mp4
file test_output-12.mp4
file test_output-13.mp4
file test_output-14.mp4
file test_output-15.mp4
- 生成FLAT格式索引文件
ffmpeg -i input.mp4 -c copy -f segment -segment_format mp4 -segment_list_type flat -segment_list filelist.txt test_output-%d.mp4
生成的 filelist.txt的内容如下:
D:\_Video>type filelist.txt
test_output-0.mp4
test_output-1.mp4
test_output-2.mp4
test_output-3.mp4
test_output-4.mp4
test_output-5.mp4
test_output-6.mp4
test_output-7.mp4
test_output-8.mp4
test_output-9.mp4
test_output-10.mp4
test_output-11.mp4
test_output-12.mp4
test_output-13.mp4
test_output-14.mp4
test_output-15.mp4
- 生成 csv格式索引文件
ffmpeg -i input.mp4 -c copy -f segment -segment_format mp4 -segment_list_type csv -segment_list filelist.csv test_output-%d.mp4
生成的 filelist.txt的内容如下:
D:\_Video>type filelist.csv
test_output-0.mp4,0.000000,2.966667
test_output-1.mp4,2.966667,4.833333
test_output-2.mp4,4.833333,6.866667
test_output-3.mp4,6.866667,8.833333
test_output-4.mp4,8.833333,11.133333
test_output-5.mp4,11.133333,14.466667
test_output-6.mp4,14.466667,17.133333
test_output-7.mp4,17.133333,19.566667
test_output-8.mp4,19.566667,21.300000
test_output-9.mp4,21.300000,24.366667
test_output-10.mp4,24.366667,27.666667
test_output-11.mp4,27.666667,29.466667
test_output-12.mp4,29.466667,31.300000
test_output-13.mp4,31.300000,33.566667
test_output-14.mp4,33.566667,35.866667
test_output-15.mp4,35.866667,37.466667
- 生成 M3U8索引文件
ffmpeg -i input.mp4 -c copy -f segment -segment_format mp4 -segment_list_type m3u8 -segment_list output.m3u8 test_output-%d.mp4
生成的 output.m3u8 的内容如下:
D:\_Video>type output.m3u8
#EXTM3U
#EXT-X-VERSION:3
#EXT-X-MEDIA-SEQUENCE:0
#EXT-X-ALLOW-CACHE:YES
#EXT-X-TARGETDURATION:4
#EXTINF:2.966667,
test_output-0.mp4
...
ffmpeg -i input.mp4 -c copy -f segment -segment_format mp4 -reset_timestamps 1 test_output-%d.mp4
ffprobe -v quiet -show_packets -select_streams v test_output-1.mp4 | findstr pts_time > 1.txt
发现test_output_1.mp4的其实时间戳已经变为了0
pts_time=0.000000
pts_time=0.133333
pts_time=0.066667
pts_time=0.033333
pts_time=0.100000
ffmpeg -i input.mp4 -c copy -f segment -segment_format mp4 -segment_times 3,9,12 test_output-%d.mp4
所有查看切片视频文件,前三片的duration几乎为 3s/6s/3s
4.5.3 使用ss与t参数切片
- 使用ss指定剪切开头
ffmpeg -ss 8 -i input.mp4 -c copy output.ts
从第8s位置开始切片,随后查看原始视频和切片后视频,duration相差几乎8s
D:\_Video>ffprobe -v quiet -show_format input.mp4 | findstr duration
duration=37.400000
D:\_Video>ffprobe -v quiet -show_format output.ts | findstr duration
duration=30.690433
- 使用 t 指定视频总长度
ffmpeg -i input.mp4 -c copy -t 10 -copyts output.ts
查看转码前后文件信息,转码后文件duration几乎为10s
D:\_Video>ffprobe -v quiet -show_format input.mp4 | findstr "start_time duration"
start_time=0.000000
duration=37.400000
D:\_Video>ffprobe -v quiet -show_format output.ts | findstr "start_time duration"
start_time=1.465667
duration=10.134333
- 使用 output_ts_offset 指定输出 start_time
ffmpeg -i input.mp4 -c copy -t 10 -output_ts_offset 120 output.ts
可以看出转码后的文件的其实时间戳几乎为 120s
D:\_Video>ffprobe -v quiet -show_format input.mp4 | findstr "start_time duration"
start_time=0.000000
duration=37.400000
D:\_Video>ffprobe -v quiet -show_format output.ts | findstr "start_time duration"
start_time=121.399000
duration=10.134333
4.6 视频文件的音视频流提取
4.6.1 提前AAC音频流
ffmpeg -i input.mp4 -vn -acodec copy output.aac
4.6.2 提取H.264视频流
ffmpeg -i input.mp4 -vcodec copy -an output.h264
注意:input.mp4里面的视频流必须是H.264格式才能这样做
4.6.3 提取H.265视频流
ffmpeg -i input.mp4 -vcodec copy -an -bsf hevc_mp4toannexb -f hevc output.hevc
注意:input.mp4里面的视频流必须是H.265格式才能这样做, 另,最新ffmpeg中,不需要加 -bsf hevc_mp4toannexb 参数,内部会自动处理,将长度头转换成起始码头
4.7 系统资源使用情况
注意:
ffmpeg -re -i input.mp4 -c copy -f mpegts output.ts 不涉及转码,只涉及转封装
比命令
ffmpeg -re -i input.mp4 -vcodec libx264 -acodec copy -f mpegts output.ts 既转码又转封装
的负载要轻,后条命令需要大量的转码计算。
第5章 编码与转码
5.1 软编码 H.264
ffmpeg -h encoder=libx264 查看libx264编码的使用说明
附:
x264 window bin 下载地址
x265 window bin 下载地址
5.1.2 H.264编码举例
1. 编码器预设参数设置
x264 --fullhelp 查看preset参数包含的集中预设参数
- ultrafast 最开的编码方式
- superfast 超级快的编码方式
- veryfast 非常快的编码方式
- faster
- fast
- medium
- slow
- slower
- veryslow
- placebo
查看help中关于preset的参数
- ultrafast:
--no-8x8dct --aq-mode 0 --b-adapt 0
--bframes 0 --no-cabac --no-deblock
--no-mbtree --me dia --no-mixed-refs
--partitions none --rc-lookahead 0 --ref 1
--scenecut 0 --subme 0 --trellis 0
--no-weightb --weightp 0
- superfast:
--no-mbtree --me dia --no-mixed-refs
--partitions i8x8,i4x4 --rc-lookahead 0
--ref 1 --subme 1 --trellis 0 --weightp 1
- veryfast:
--no-mixed-refs --rc-lookahead 10
--ref 1 --subme 2 --trellis 0 --weightp 1
- faster:
--no-mixed-refs --rc-lookahead 20
--ref 2 --subme 4 --weightp 1
- fast:
--rc-lookahead 30 --ref 2 --subme 6
--weightp 1
- medium:
Default settings apply.
- slow:
--direct auto --rc-lookahead 50 --ref 5
--subme 8 --trellis 2
- slower:
--b-adapt 2 --direct auto --me umh
--partitions all --rc-lookahead 60
--ref 8 --subme 9 --trellis 2
- veryslow:
--b-adapt 2 --bframes 8 --direct auto
--me umh --merange 24 --partitions all
--ref 16 --subme 10 --trellis 2
--rc-lookahead 60
- placebo:
--bframes 16 --b-adapt 2 --direct auto
--slow-firstpass --no-fast-pskip
--me tesa --merange 24 --partitions all
--rc-lookahead 60 --ref 16 --subme 11
--trellis 2
随后分别测试 ultrafast和medium级别的转码速度
ffmpeg -i input.mp4 -c:v libx264 -preset ultrafast -b:v 2000k output_ultrafast.mp4
转码速度约为10.1倍速
frame= 1122 fps=304 q=-1.0 Lsize= 10989kB time=00:00:37.36 bitrate=2409.1kbits/s speed=10.1x
video:10369kB audio:587kB subtitle:0kB other streams:0kB global headers:0kB muxing overhead: 0.294363%
[libx264 @ 0000028a77241340] frame I:5 Avg QP:19.80 size: 33589
[libx264 @ 0000028a77241340] frame P:1117 Avg QP:21.62 size: 9355
[libx264 @ 0000028a77241340] mb I I16..4: 100.0% 0.0% 0.0%
[libx264 @ 0000028a77241340] mb P I16..4: 4.5% 0.0% 0.0% P16..4: 22.2% 0.0% 0.0% 0.0% 0.0% skip:73.4%
[libx264 @ 0000028a77241340] final ratefactor: 25.50
[libx264 @ 0000028a77241340] coded y,uvDC,uvAC intra: 46.1% 26.5% 5.1% inter: 12.1% 4.1% 0.1%
[libx264 @ 0000028a77241340] i16 v,h,dc,p: 47% 26% 11% 16%
[libx264 @ 0000028a77241340] i8c dc,h,v,p: 56% 20% 18% 5%
[libx264 @ 0000028a77241340] kb/s:2271.13
[aac @ 0000028a771003c0] Qavg: 1228.998
再测试 medium基本的转码,转码速度约为2.43倍速
ffmpeg -i input.mp4 -c:v libx264 -preset medium -b:v 2000k output_medium.mp4
frame= 1122 fps= 73 q=-1.0 Lsize= 11075kB time=00:00:37.30 bitrate=2432.4kbits/s speed=2.43x
video:10447kB audio:587kB subtitle:0kB other streams:0kB global headers:0kB muxing overhead: 0.368136%
[libx264 @ 0000021dc16a1740] frame I:36 Avg QP: 4.22 size: 43106
[libx264 @ 0000021dc16a1740] frame P:343 Avg QP: 6.77 size: 17844
[libx264 @ 0000021dc16a1740] frame B:743 Avg QP:10.07 size: 4071
[libx264 @ 0000021dc16a1740] consecutive B-frames: 5.1% 15.7% 12.6% 66.7%
[libx264 @ 0000021dc16a1740] mb I I16..4: 62.8% 18.4% 18.8%
[libx264 @ 0000021dc16a1740] mb P I16..4: 2.0% 5.4% 3.6% P16..4: 13.4% 8.2% 6.0% 0.0% 0.0% skip:61.5%
[libx264 @ 0000021dc16a1740] mb B I16..4: 0.1% 0.5% 0.5% B16..8: 12.4% 3.9% 1.5% direct: 1.3% skip:79.8% L0:49.7% L1:37.7% BI:12.5%
[libx264 @ 0000021dc16a1740] final ratefactor: 12.31
[libx264 @ 0000021dc16a1740] 8x8 transform intra:35.5% inter:49.4%
[libx264 @ 0000021dc16a1740] coded y,uvDC,uvAC intra: 58.3% 38.9% 24.9% inter: 8.1% 3.3% 1.1%
[libx264 @ 0000021dc16a1740] i16 v,h,dc,p: 81% 10% 4% 5%
[libx264 @ 0000021dc16a1740] i8 v,h,dc,ddl,ddr,vr,hd,vl,hu: 39% 19% 11% 4% 4% 6% 5% 7% 6%
[libx264 @ 0000021dc16a1740] i4 v,h,dc,ddl,ddr,vr,hd,vl,hu: 32% 24% 10% 5% 6% 6% 6% 6% 5%
[libx264 @ 0000021dc16a1740] i8c dc,h,v,p: 68% 16% 14% 3%
[libx264 @ 0000021dc16a1740] Weighted P-Frames: Y:2.9% UV:1.5%
[libx264 @ 0000021dc16a1740] ref P L0: 65.9% 9.7% 15.8% 8.5% 0.1%
[libx264 @ 0000021dc16a1740] ref B L0: 84.2% 13.1% 2.7%
[libx264 @ 0000021dc16a1740] ref B L1: 98.2% 1.8%
[libx264 @ 0000021dc16a1740] kb/s:2288.19
[aac @ 0000021dbf7ab280] Qavg: 1228.998
对比生成的转码文件,medium比ultrafast的画质会稍微好点
由于原始视频画质太差,好的不太明显
2. H.264编码优化
除了preset参数,还有 tune 参数,即
film 用于高质量的电脑内容,使用低强度的deblocking
animation 用于动画片,使用高强度的deblocking和更多的参考帧
grain 保留老的,有颗粒的电影素材中的颗粒结构
stillimage 适用于类似幻灯片这种变换较慢的内容
psnr
ssim
fastdecode 允许通过禁止某些过滤器、CABAC等来加速解码
zerolatency 适用于快速编码和低延时流媒体。
- film (psy tuning):
--deblock -1:-1 --psy-rd <unset>:0.15
- animation (psy tuning):
--bframes {+2} --deblock 1:1
--psy-rd 0.4:<unset> --aq-strength 0.6
--ref {Double if >1 else 1}
- grain (psy tuning):
--aq-strength 0.5 --no-dct-decimate
--deadzone-inter 6 --deadzone-intra 6
--deblock -2:-2 --ipratio 1.1
--pbratio 1.1 --psy-rd <unset>:0.25
--qcomp 0.8
- stillimage (psy tuning):
--aq-strength 1.2 --deblock -3:-3
--psy-rd 2.0:0.7
- psnr (psy tuning):
--aq-mode 0 --no-psy
- ssim (psy tuning):
--aq-mode 2 --no-psy
- fastdecode:
--no-cabac --no-deblock --no-weightb
--weightp 0
- zerolatency:
--bframes 0 --force-cfr --no-mbtree
--sync-lookahead 0 --sliced-threads
--rc-lookahead 0
3. H.264的profile和level设置
profile涉及的编码参数为
- baseline:
--no-8x8dct --bframes 0 --no-cabac
--cqm flat --weightp 0
No interlaced.
No lossless.
- main:
--no-8x8dct --cqm flat
No lossless.
- high:
No lossless.
- high10:
No lossless.
Support for bit depth 8-10.
- high422:
No lossless.
Support for bit depth 8-10.
Support for 4:2:0/4:2:2 chroma subsampling.
- high444:
Support for bit depth 8-10.
Support for 4:2:0/4:2:2/4:4:4 chroma subsampling.
ffmpeg -i input.mp4 -c:v libx264 -profile:v baseline -level 3.1 output_baseline.ts
ffmpeg -i input.mp4 -c:v libx264 -profile:v high -level 3.1 output_high.ts
查看两次生成的码流的B帧情况
统计码流B帧数量
D:\_Video>ffprobe -v quiet -show_frames -select_streams v output_baseline.ts | findstr "pict_type=B" | find /c /v ""
0
D:\_Video>ffprobe -v quiet -show_frames -select_streams v output_high.ts | findstr "pict_type=B" | find /c /v ""
743
4. 控制场景切换时关键帧的插入
ffmpeg -i input.mp4 -c:v libx264 -g 50 -t 60 output.mp4
ffmpeg -i input.mp4 -c:v libx264 -g 50 -sc_threshold 0 -t 60 -y output2.mp4
查看I帧间隔信息
D:\_Video>ffprobe -v quiet -select_streams v -show_packets -i output.mp4 | findstr /N "K__"
12:flags=K__
272:flags=K__
610:flags=K__
1143:flags=K__
1351:flags=K_
...
D:\_Video>ffprobe -v quiet -select_streams v -show_packets -i output2.mp4 | findstr /N "K__"
12:flags=K__
662:flags=K__
1312:flags=K__
1962:flags=K__
2612:flags=K__
3262:flags=K__
可以看出,后者生成的码流的I帧间隔更均匀,每隔 650/13=50帧出现一个I帧
因为前者遇到场景切换时会自动插入IDR帧,后者的 sc_threshold 0 关闭了场景切换判定
13的来由,每个PACKET的信息占13行
[PACKET]
codec_type=video
stream_index=0
pts=0
pts_time=0.000000
dts=-1024
dts_time=-0.066667
duration=512
duration_time=0.033333
size=8368
pos=48
flags=K__
[/PACKET]
[PACKET]
codec_type=video
stream_index=0
pts=512
pts_time=0.033333
dts=-512
dts_time=-0.033333
duration=512
duration_time=0.033333
size=268
pos=8416
flags=___
[/PACKET]
5. 设置x264内部参数
ffmpeg -i input.mp4 -vframes 500 -c:v libx264 -x264-params “bframes=0” -g 50 -sc_threshold 0 output_nb.mp4
转码过程中,可以看到没有生成B帧
[libx264 @ 00000244b9931740] frame I:10 Avg QP:14.86 size: 11698
[libx264 @ 00000244b9931740] frame P:490 Avg QP:21.12 size: 2144
[libx264 @ 00000244b9931740] mb I I16..4: 62.9% 28.4% 8.7%
[libx264 @ 00000244b9931740] mb P I16..4: 2.0% 3.6% 0.6% P16..4: 11.3% 1.9% 0.6% 0.0% 0.0% skip:79.9%
[libx264 @ 00000244b9931740] 8x8 transform intra:50.5% inter:81.2%
ffmpeg -i input.mp4 -vframes 500 -c:v libx264 -x264-params “bframes=3:b-adapt=0” -g 20 -sc_threshold 0 output_b.mp4
6. CBR设置
P152 TODO