FFmpeg 常见用法

FFmpeg 常见用法

RayAlto OP

记得小学的时候还在用格式工厂,当时还没有普及安卓手机,我经常用格式工厂把各种奇妙的视频转换成 3GP 格式放进一个功能机里看。

后来大学时期开始鼓捣 Linux 之后染上了开源洁癖和比特洁癖,开源洁癖很好理解,比特洁癖是我自己取的名字,大概就是我总是追求矢量大于标量、无损大于有损、元数据必须要干净整洁等等怪癖,总体来说就是我希望我的存储设备中的文件的细节越多越好(比如音频的话 96kHz/24bit 的 FLAC 大于 320k 的 MP3 、图片的话 SVG 大于 Lossless WebP 等无损标量格式大于 Lossy WebP 等有损标量格式,视频这个确实没办法,我太穷以至于没有足够的存储设备,来随心所欲的保存我喜欢的 BD 原盘),在这个基础上,元数据越丰富、准确越好(比如音乐的专辑名、艺术家名等是否准确全面),而且元数据一定不能包含垃圾信息(比如用 Adobe Acrobat DC 生成的 PDF 会有一大坨 XML Metadata 表示这个文档是 Adobe Acrobat DC 生成的,在我眼里这种行为和狗撒尿标记自己的地盘是同类行为, PDF 标准 Metadata 里也会有 Acrobat 相关条目,在我眼里都是垃圾信息)。算了,不能再展开了,不然偏题太严重了。

不信你可以看看我的博客,除了屏幕截图等实在不能变成矢量的情况以外,几乎所有的图片都是 SVG 。

00. 制作铃声

铃声这种东西并不需要多高的质量,我个人认为更重要的是铃声文件能不能尽快被设备读取并播放,所以我选择 320k 的 MP3 格式。比如我准备了瑞克与莫蒂第三季第一集 Rick and Morty S03E01 - The Rickshank Rickdemption.mp4 ,里面 00:11:15.210 开始,瑞克占据了虫子的身体说了一句 Another day another dollar ,这四个单词到 00:11:16.540 结束,用 FFmpeg 制作铃声:

1
2
ffmpeg -ss 00:11:15.210 -to 00:11:16.540 -i 'Rick and Morty S03E01 - The Rickshank Rickdemption.mp4' \
-c:a libmp3lame -b:a 320k rnm.S03E01.another.day.another.dollar.ringtone.mp3

这样能做出一个 CBR 320Kbit/s 的 MP3

  1. 为啥不做 VBR ?因为 libmp3lame 的 VBR 最高档平均码率也只有 220-260Kbit/s
  2. 为啥不做更高码率的?没必要,我认为设备能尽快把铃声播放出来才是重要的,而且遵循 MP3 标准,最高码率就是 320K
  3. 为啥不用 ABR ?因为 FFmpeg - libmp3lame 的 ABR 就是 CBR 和 VBR 的某种结合,统一用 -b 选项定义码率

如果你的设备没有播放铃声时声音逐渐变大之类的选项, FFmpeg 还可以帮你加上渐入效果:

1
2
3
ffmpeg -ss <start> -to <end> -i <input> \
-af afade=type=in:start_time=0:duration=5 \
-c:a libmp3lame -b:a 320k <output>

意思是小于等于零秒时音量为零,零秒到五秒之间音量逐渐增加,大于等于五秒时音量为百分之百(这里的时间按截取后为标准)。同时加上渐出效果:

1
2
3
ffmpeg -ss <start> -to <end> -i <input> \
-af afade=type=in:start_time=0:duration=5,afade=type=out:start_time=40:duration=5 \
-c:a libmp3lame -b:a 320k <output>

小于等于四十秒时音量为百分之百,四十秒开始五秒之间音量逐渐减小,大于等于四十五秒时音量为零。

01. 给音乐贴上封面

比如我手上有 Skrillex 2010 年免费发布的 My Name Is Skrillex 专辑,我比较喜欢里面的 With You Friends ,当时质量最高的音频格式是 M4A Lossless 44.1kHz 24bit (苹果的一个无损格式),众所周知 M4A 现在不算一个好的音频格式,而且貌似不能内置封面,现在把这个 M4A 加上封面做成 FLAC :

1
2
3
4
ffmpeg -i '06 Skrillex - With You Friends.m4a' -i full-cover.jpg \
-map 0:0 -map 1:0 -c:a flac -c:v copy -metadata:s:v title='Album cover' \
-metadata:s:v comment='Cover (front)' -disposition:v attached_pic \
'Skrillex - With You Friends.flac'

02. 调整字幕偏移

比如我在某个种子网站下载了一个电影,又在某手网找了个字幕 subtitle.ass ,发现字幕时间轴和视频的对不上,通过 Mpv 调整发现字幕晚出现 1.5 秒即可与视频时间轴对上,用 FFmpeg 调整字幕偏移,输出为 subtitle.new.ass

1
ffmpeg -itsoffset 1.5 -i subtitle.ass -c copy subtitle.new.ass

当然负数也可以,比如 -itsoffset -1.5 ,表示字幕应该提前 1.5 秒出现

03. 编辑元数据

最近补了无职转生动画第二季,真的是触动灵魂、回味无穷、挥之不去、余音绕梁、叹为观止、令我久久不能释怀。意犹未尽去逛 Bangumi 发现竟然有人抓着「鲁迪连他爸头七都没过就开始搞外遇」不放,长篇大论鲁迪怎么怎么堕落,我真的好无语😅,你怎么不说鲁迪婴儿的时候没把塞妮丝当妈,整天不是摸塞妮丝的扔子就是摸莉莉雅的扔子呢?现在开始评头论足?况且重要的是洛琪希像希露菲叶特一样在鲁迪陷入低谷的时候拉了鲁迪一把呀,而且他爸保罗也在领便当之前用他的两把剑暗示鲁迪了,挺好的故事在你眼里只有「外遇」两个字了是吧。哎,不多说了。

第二季的音乐也是一如既往的顶,大原ゆい子,神!网易云音乐,启动!……啊?「守りたいもの」只有 320k MP3 ?……「かげくらべの唄」下架了?好吧,我充会员不是因为网易云曲库丰富或者我有钱,是因为我贱。

去某花园找到了某动漫论坛分享的一系列 96kHz 24bit 的 FLAC 资源,迫不及待下下来解压,试探性的 ffprobe 一下(太过于广告的部分用 * 替换了):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
$ ffprobe 01.かげくらべの唄.flac
(此处省略 ffprobe 输出的版本信息)
Input #0, flac, from '01.かげくらべの唄.flac':
Metadata:
ARTIST : 大原ゆい子
(此处省略一些正确且全面的元数据)
COMMENT : 天使*漫 i******4 自购[Hi-Res][96kHz/24bit][FLAC]原贴
: http://www.t**m.v*p/?tid=1*****4
:
: 8350张Hi-Res自购专辑**** 16900张CD自抓(WAV+FLAC+BK+DVD)
: http://www.k**m.v*p/?tid=7****2
Duration: 00:04:33.61, start: 0.000000, bitrate: 3157 kb/s
Stream #0:0: Audio: flac, 96000 Hz, stereo, s32 (24 bit)
Stream #0:1: Video: mjpeg (Baseline), yuvj444p(pc, bt470bg/unknown/unknown), 1500x1500 [SAR 72:72 DAR 1:1], 90k tbr, 90k tbn (attached pic)
Metadata:
comment : Cover (front)

我非常清楚我在无耻的白嫖,而你们在无私的分享,我非常敬佩你们,但讲道理你们分享的文件结构是这样的(太过于广告的部分用 * 替换了):

1
2
3
4
5
6
7
8
$ tree
.
├── 01.かげくらべの唄.flac
├── COVER.jpg
├── 天使*漫 i******4 自购[Hi-Res][96kHz/24bit][FLAC]原贴.url
└── 天使*漫音乐区 CD Hi-Res *******地.url

1 directory, 4 files

真的有必要在 FLAC 里也嵌这种信息吗?当然,我不是说我既要又要,只是我个人认为这种行为差不多就是在破坏你们分享的资源,和你们的广告语中的「爱好者」不符,好在只是污染了 Metadata ,而不是在 FLAC 的音频里面嵌一段广告语音,如果音频数据也被污染了,虽然我在白嫖,但我也不绝会白嫖这种垃圾。

回归正题,用 FFmpeg 删除上面的 COMMENT 元数据:

1
ffmpeg -i 01.かげくらべの唄.flac -c copy -metadata COMMENT= 01.かげくらべの唄.sanitized.flac

这里需要注意的是要删除的元数据在 Input #0 下,也就是容器的元数据,所以不需要加 Specifier ,如果是下面的 Stream #x:x 下的 Metadata ,则需要加 Specifier ,比如选中第一个音频:

1
ffmpeg -i <input> -c copy -metadata:s:a:0 <key=value> <output>