打开主菜单

更改

创建页面,内容为“虽然这篇教程的主要内容是视频转码,但除了将文件在各种封装格式、编码中转换以外,一些其他的调整也是很有用的。 在...”
虽然这篇教程的主要内容是视频转码,但除了将文件在各种封装格式、编码中转换以外,一些其他的调整也是很有用的。

在这一章中,我们将学到许多具有各种功能的[[如何使用_FFmpeg_进行视频转码:运行#“选项”与“参数”|命令行选项]],这些选项都需要加在整条命令的输出文件名之前。

万变不离其宗,在前面介绍的[[如何使用_FFmpeg_进行视频转码:运行#查看帮助|查看帮助]]一节中学到的 <code>ffmpeg -help</code> 命令仍然是非常实用的,本章也将一直围绕它的输出来进行。所以,在开始阅读第一节之前,先打开终端,执行一下 <code>ffmpeg -help</code> 吧!

== 音频 ==

我们在 <code>ffmpeg -help</code> 的输出中能找到这样一段信息:

<syntaxhighlight lang="text">
Audio options:
-aframes number set the number of audio frames to output
-aq quality set audio quality (codec-specific)
-ar rate set audio sampling rate (in Hz)
-ac channels set number of audio channels
-an disable audio
-acodec codec force audio codec ('copy' to copy stream)
-vol volume change audio volume (256=normal)
-af filter_graph set audio filters
</syntaxhighlight>

这些就是关于音频的选项了,由于有些东西涉及的知识太多,我在这里只介绍比较常用且简单的 <code>-ar</code>, <code>-an</code>, <code>-vol</code> 这几个选项。( <code>-acodec</code> 早就讲过了,不是吗?)

=== <code>-ar</code> ===

如上面所说, <code>-ar</code> 选项后面还要跟一个叫 <code>rate</code> 的参数,不过参数叫什么名字对我们来说不重要,我们只要知道后面要有一个参数就可以了。这个参数是音频的[https://zh.wikipedia.org/wiki/%E9%87%87%E6%A0%B7%E7%8E%87 采样率],以 Hz 为单位。通常来说,采样率越大,音质越好。电话的采样率通常是 8000 Hz ,普通的录音笔通常是 32000 Hz ,一般的 MP3 音乐是 44100 Hz ,稍高品质的音乐是 48000 Hz ,再高的采样率我们平常就不容易接触到了。

以下是一个将音频文件 <code>input.mp3</code> 转换为 [https://zh.wikipedia.org/wiki/Ogg Ogg] 封装格式, [https://zh.wikipedia.org/wiki/Vorbis Vorbis] 编码,并且指定音频采样率为 32000 Hz 的例子:

<syntaxhighlight lang="shell">
ffmpeg -i input.mp3 -c:a libvorbis -ar 32000 output.ogg
</syntaxhighlight>

{{注意|在 FFmpeg 中使用 Vorbis 编码时,编码器应指定为 <code>libvorbis</code> 而不是 <code>vorbis</code> ,这是两个不同的编码器,而后者还处于不完善的状态。}}

{{提示|如果你喜欢的话,数字 <code>32000</code> 可以简写为 <code>32k</code> ,因为 "k" 就相当与“千”。}}

{{注意|采样率只能变小,不能变大。当然你要是指定一个比原来大的采样率也没人阻止你,不过音质不会有任何的提升就是了。原理跟你把一张分辨率很小的图片拉大一样,画质没有任何提升。}}

=== <code>-an</code> ===

这个其实没什么好讲的,它就是在进行视频转码的时候,将音频给去除,这样就会得到一个没有声音的视频。

=== <code>-vol</code> ===

这个选项有一个参数,用来指定相对与原来的文件的音量大小。不过注意,标准的音量并不是 100 ,而是 256 ,也就是说,我指定了 <code>-vol 256</code> 就是原来的音量不变(跟没指定一样)。

下面的例子是将音量减小为原来的一半:

<syntaxhighlight lang="shell">
ffmpeg -i input.mp3 -c:a libvorbis -vol 128 output.ogg
</syntaxhighlight>

== 视频 ==

在 <code>ffmpeg -help</code> 的输出中,我们也能找到这样一段信息:

<syntaxhighlight lang="text">
Video options:
-vframes number set the number of video frames to output
-r rate set frame rate (Hz value, fraction or abbreviation)
-s size set frame size (WxH or abbreviation)
-aspect aspect set aspect ratio (4:3, 16:9 or 1.3333, 1.7777)
-bits_per_raw_sample number set the number of bits per raw sample
-vn disable video
-vcodec codec force video codec ('copy' to copy stream)
-timecode hh:mm:ss[:;.]ff set initial TimeCode value.
-pass n select the pass number (1 to 3)
-vf filter_graph set video filters
-ab bitrate audio bitrate (please use -b:a)
-b bitrate video bitrate (please use -b:v)
-dn disable data
</syntaxhighlight>

同样的,实用为先,我在这里只挑 <code>-r</code>, <code>-s</code>, <code>-vn</code> 这几个选项来讲。

=== <code>-r</code> ===

<code>-r</code> 选项可以指定视频的[https://zh.wikipedia.org/wiki/%E5%B8%A7%E7%8E%87 帧率],其参数的单位是 Hz ,也就是我们平常所说的“帧每秒”( FPS )。比如 <code>-r 24</code> 即代表输出视频的帧率为每秒 24 帧。

当然,视频的帧率跟音频的采样率一样,只能变小不能变大。

=== <code>-s</code> ===

这个选项可以指定视频的尺寸,以像素为单位。这个选项的参数由 <code>宽度x高度</code> 的格式填写。比如如果要把视频转为 720P (也就是宽度 1280 像素,高度 720 像素),就写上 <code>-s 1280x720</code> 。没错,中间用小写字母 <code>x</code> 分隔两个数字。

下面的例子会将输出文件视频的帧率指定为 15 帧每秒,画面尺寸 1280x720 :

<syntaxhighlight lang="shell">
ffmpeg -i input.mp4 -r 15 -s 1280x720 output.mkv
</syntaxhighlight>

=== <code>-vn</code> ===

与 <code>-an</code> 选项一样,在命令中加入了这个选项之后,视频内容便会被去除。也就是说,只把音频剥离出来。比如,把 <code>video.mp4</code> 这个视频中的音频提取出来,保存为 <code>audio.mp3</code> ,指定音频编码为 <code>mp3</code> ,将使用这样一个命令:

<syntaxhighlight lang="shell">
ffmpeg -i video.mp4 -vn -c:a mp3 audio.mp3
</syntaxhighlight>

{{提示|MP3 封装格式的默认音频编码已经是 <code>mp3</code> ,我在这里写 <code>-c:a mp3</code> 其实是多此一举。}}

== 整体 ==

除了仅仅针对媒体流的选项以外,还有一些针对整个媒体文件的调整选项。那么我们先在 <code>ffmpeg -help</code> 的输出中找出这样一段内容:

<syntaxhighlight lang="text">
Per-file main options:
-f fmt force format
-c codec codec name
-codec codec codec name
-pre preset preset name
-map_metadata outfile[,metadata]:infile[,metadata] set metadata information of
outfile from infile
-t duration record or transcode "duration" seconds of audio/video
-to time_stop record or transcode stop time
-fs limit_size set the limit file size in bytes
-ss time_off set the start time offset
-sseof time_off set the start time offset relative to EOF
-seek_timestamp enable/disable seeking by timestamp with -ss
-timestamp time set the recording timestamp ('now' to set the current time)
-metadata string=string add metadata
-target type specify target file type ("vcd", "svcd", "dvd", "dv" or "dv5
0" with optional prefixes "pal-", "ntsc-" or "film-")
-apad audio pad
-frames number set the number of frames to output
-filter filter_graph set stream filtergraph
-filter_script filename read stream filtergraph description from a file
-reinit_filter reinit filtergraph on input parameter changes
-discard discard
-disposition disposition
</syntaxhighlight>

我在这里将会挑选 <code>-c</code>, <code>-t</code>, <code>-ss</code>, <code>-metadata</code> 这几个选项来讲。

=== <code>-c</code> ===

其实这个选项我们在[[如何使用 FFmpeg 进行视频转码:开始转码#指定编码器]]的最后已经讲过了,不过我觉得有必要再做一次详细的说明。

<code>-c</code> 选项用来指定输出文件的编码,但跟 <code>-vcodec</code> 和 <code>-acodec</code> 不同的是,它指定的是全部媒体流的编码而不是单独一个视频流或音频流。在通常情况下,这是行不通的,因为视频编码和音频编码是两种不同的东西,怎么能是同一个呢?

但是,我们可以通过在 <code>-c</code> 后面紧挨着加上 <code>:v</code> 成为 <code>-c:v</code> 来表示指定视频编码,紧挨着加上 <code>:a</code> 成为 <code>-c:a</code> 来表示指定音频编码。也就跟 <code>-vcode</code> 和 <code>-acodec</code> 一样了。不过 <code>-c:v</code>, <code>-c:a</code> 的写法比 <code>-vcodec</code>, <code>-acodec</code> 的写法要短,所以我喜欢用前者。

当然,单独的 <code>-c</code> 也是有用的,有什么用呢?

还记得在编码器的地方指定 <code>copy</code> 来让 FFmpeg 不重新进行编码吗?众所周知,大部分视频或音频编码都是[https://zh.wikipedia.org/wiki/%E6%9C%89%E6%8D%9F%E6%95%B0%E6%8D%AE%E5%8E%8B%E7%BC%A9 有损压缩],重新进行一次编码不但费时费力,还会产生无法挽回的画质/音质损失,损失一两次通常是人类很难判别的,但是次数多了差别就大了。所以,我们要尽量避免重新编码,能用 <code>copy</code> 作为“编码器”的时候就尽量使用它。

让视频不重新编码的时候使用 <code>-c:v copy</code> ,让音频不重新编码的时候使用 <code>-c:a copy</code> 。那么在两个都要不重新编码的时候,就不用把这两条选项都写上去了,只要 <code>-c copy</code> 就足够。

下面是一些例子:

# 将视频尺寸转换为 `1280x720` ,其他不变。<br>因为视频的尺寸变了,所以视频不得不重新编码,但音频不用。<syntaxhighlight lang="shell">ffmpeg -i input.mp4 -c:v h264 -c:a copy -s 1280x720 output.mp4</syntaxhighlight>
# 将音频的编码转换为 `libvorbis` ,其他不变。<br>音频的编码肯定得变,但是视频不用。<syntaxhighlight lang="shell">ffmpeg -i input.mp4 -c:v copy -c:a libvorbis output.mp4</syntaxhighlight>
# 仅仅将 MP4 封装格式转换为 Matroska 封装格式。<br>只是封装格式变了,视频和音频都不需要重新编码。<syntaxhighlight lang="shell">ffmpeg -i input.mp4 -c copy output.mkv</syntaxhighlight>

=== <code>-t</code> ===

这个选项用来指定输出文件的持续时间,以秒为单位,比如我想截取 <code>full.mp4</code> 这个视频的前 30 秒并保存为 <code>segment.mp4</code> ,就可以使用这个命令:

<syntaxhighlight lang="shell">
ffmpeg -i full.mp4 -c copy -t 30 segment.mp4
</syntaxhighlight>

{{注意|看到了 <code>-c copy</code> 了吗?因为我们只是进行截取,所以不需要进行重新编码。能不重新编码就尽量不要重新编码。}}

这个选项的参数以秒为单位,但这并不意味着 5 分钟你就得写 <code>300</code> , 1 个小时你就得写 <code>3600</code> , 1 小时 23 分钟 45 秒你就得先拿出计算器算出 1&#x00d7;3600+23&#x00d7;60+45=5025 再写上 <code>5025</code> 。
事实上,你只要写 <code>5:00</code> 就可以表示 5 分钟, <code>1:23:45</code> 就可以表示 1 小时 23 分钟 45 秒。

你也可以写小数点,比如 <code>10.0268</code> 或者 <code>1:23:45.678</code> 。

=== <code>-ss</code> ===

这个选项用来指定输出文件相对于输入文件的开始时间,比如我想把 <code>full.mp4</code> 这个视频的前 30 秒剪掉并把剩下的保存为 <code>segment.mp4</code> ,就可以使用这个命令:

<syntaxhighlight lang="shell">
ffmpeg -i full.mp4 -c copy -ss 30 segment.mp4
</syntaxhighlight>

<code>-ss</code> 选项也可以跟 <code>-t</code> 选项配合使用以截取媒体文件的一部分,比如如果我想截取 <code>full.mp4</code> 的 12 分 25 秒至 20 分 27 秒,保存为 <code>segment.mp4</code> ,使用这条命令。

<syntaxhighlight lang="shell">
ffmpeg -i full.mp4 -c copy -ss 12:25 -t 8:02 segment.mp4
</syntaxhighlight>

{{注意|<code>-t</code> 选项后面的参数并不是结束时间而是持续时间,所以在上面的例子中我写的不是 <code>20:27</code> 而是 20:27-12:25 的结果, <code>8:02</code> 。}}

=== <code>-metadata</code> ===

这个选项说的很明白了,它所更改的就是输出文件的[https://zh.wikipedia.org/wiki/%E5%85%83%E6%95%B0%E6%8D%AE 元数据],比如一首歌的标题、艺术家、专辑。比如 <code>-metadata title="我是标题"</code> 就会把输出文件的标题元数据改为 <code>我是标题</code> 。 <code>-metadata</code> 选项可以多次指定以更改多个元数据。

举个例子,把 `no metadata.mp3` 的标题改成 `一首歌` ,艺术家改成 `一位艺术家` ,专辑改成 `一张专辑` ,然后保存为 `with metadata.mp3` :

<syntaxhighlight lang="shell">
ffmpeg -i "no metadata.mp3" -c copy -metadata title="一首歌" -metadata artist="一位艺术家" -metadata album="一张专辑" "with metadata.mp3"
</syntaxhighlight>

{{提示|还记得吗?在文件名包含空格或其他特殊字符的时候,必须用半角双引号包起来。}}

----

<blockquote>我在命令中所写的选项和参数,顺序有关系吗?</blockquote>

这样的问题可能发自一个对命令行不熟悉的用户。那么我就来解答一下:在 FFmpeg 中,以我们目前的知识,除了 <code>-i 输入文件名</code> 必须在仅次于 <code>ffmpeg</code> 的最前面以及输出文件名必须在最后面以外,选项的顺序没有关系。

也就是说,以下两条命令是没有任何区别的。

<syntaxhighlight lang="shell">
ffmpeg -i input.mp4 -c:v vp9 -c:a opus -s 1280x720 -ss 10 -t 1:00 output.webm
ffmpeg -i input.mp4 -t 1:00 -c:v vp9 -s 1280x720 -c:a opus -ss 10 output.webm
</syntaxhighlight>

但是注意了,一个选项跟这个选项的的参数是不可分开的,也就是说,音频编码必须跟在 <code>-c:a</code> 后面,持续时间必须跟在 <code>-t</code> 后面……下面这条命令是'''错误'''且'''无法'''被正常运行的:

<syntaxhighlight lang="shell">
ffmpeg -i input -c:v -ss -t 10 -ss -c:a 1280x720 vp9 1:00 opus -s output.webm
</syntaxhighlight>

看完了这些说明,我想你就应该能够熟练地掌握命令行的规则了。而在接下来的[[如何使用 FFmpeg 进行视频转码:字幕|下一章]]中,我们将会介绍有关字幕的东西。