FFmpeg 常见问题

网站翻译由林建有提供支持

内容目录

1 一般问题

1.1 为什么 FFmpeg 不支持功能 [xyz]?

因为还没有人承担这个任务。FFmpeg 的开发由开发者自身的重要任务驱动。 如果有一个对您而言很重要的功能,最好自己承担任务或赞助开发者来实现它。

1.2 FFmpeg 不支持编解码器 XXX。能否加入一个 Windows DLL 加载器来支持它?

不支持。Windows DLL 不便于移植、臃肿且通常较慢。此外,FFmpeg 致力于原生支持所有编解码器。 DLL 加载器与这一目标不符。

1.3 我无法读取这个文件,虽然它的格式似乎被 ffmpeg 支持。

即使 ffmpeg 能够读取容器格式,它也可能不支持该容器中的所有编解码器。请查阅 ffmpeg 文档中的支持的编解码器列表。

1.4 哪些编解码器被 Windows 支持?

Windows 对标准格式如 MPEG 支持非常差,除非您安装了额外的编解码器。

以下视频编解码器列表应该能在多数 Windows 系统上运行:

msmpeg4v2

.avi/.asf

msmpeg4

.asf 仅支持

wmv1

.asf 仅支持

wmv2

.asf 仅支持

mpeg4

只有安装了某些 MPEG-4 编解码器,如 ffdshow 或 Xvid。

mpeg1video

.mpg 仅支持

注意,ASF 文件在 Windows 中通常有 .wmv 或 .wma 扩展名。此外,需要提及的是,微软声称拥有 ASF 格式的专利,并可能对使用非微软软件创建 ASF 文件的用户提起诉讼或威胁。强烈建议尽量避免使用 ASF。

以下音频编解码器列表应该能在多数 Windows 系统上运行:

adpcm_ima_wav
adpcm_ms
pcm_s16le

总是支持

libmp3lame

如果安装了一些 MP3 编解码器如 LAME。

2 编译

2.1 error: can't find a register in class 'GENERAL_REGS' while reloading 'asm'

这是 gcc 的错误,请不要向我们报告。而是向 gcc 开发者报告它。请注意,我们不会为 gcc 错误添加解决方法。

还需注意 (一些) gcc 开发者认为这不是一个错误或者不是他们应该解决的问题:https://gcc.gnu.org/bugzilla/show_bug.cgi?id=11203。 此外,其中一些开发者甚至可能不知道不可判定问题与 NP 问题之间的区别...

2.2 我用发行版的包管理器安装了这个库。为什么configure没有找到它?

发行版通常将库拆分成多个包。主包包含运行使用该库的程序所需的文件。开发模块包含构建使用该库的程序所需的文件。有时,文档和/或数据也会单独在一个包中。

要构建 FFmpeg,您需要安装开发模块。它通常被称为libfoo-dev或者libfoo-devel。构建完成后您可以删除它,但一定要保留主包。

2.3 我如何让pkg-config找到我的库?

在您的库文件旁边会有一个.pc文件(或多个)位于pkgconfig目录中。您需要设置环境变量指向pkg-config这些文件。

如果您需要添加目录到pkg-config的搜索列表中 (典型用例:库单独安装),将其添加到$PKG_CONFIG_PATH:

export PKG_CONFIG_PATH=/opt/x264/lib/pkgconfig:/opt/opus/lib/pkgconfig

如果您需要替换 pkg-config的搜索列表 典型用例:交叉编译),将其设置在$PKG_CONFIG_LIBDIR:

export PKG_CONFIG_LIBDIR=/home/me/cross/usr/lib/pkgconfig:/home/me/cross/usr/local/lib/pkgconfig

如果您需要了解库的内部依赖项(静态链接的典型用例),请使用--static选项添加到pkg-config:

./configure --pkg-config-flags=--static

2.4 如何使用pkg-config进行交叉编译?

最佳方法是将pkg-config安装在您的交叉编译环境中。它会自动使用交叉编译库。

您也可以使用pkg-config从主机环境中通过明确指定--pkg-config=pkg-configconfigure的方式实现。pkg-config在这种情况下,您必须使用PKG_CONFIG_LIBDIR

指向正确的目录使用,如前面提到的条目所述。pkg-config设置调用主机PKG_CONFIG_LIBDIR set. That script can look like that:

#!/bin/sh
PKG_CONFIG_LIBDIR=/path/to/cross/lib/pkgconfig
export PKG_CONFIG_LIBDIR
exec /usr/bin/pkg-config "$@"

3 使用

3.1 ffmpeg 无法工作;出了什么问题?

在构建之前尝试在 ffmpeg 源目录中执行一个make distclean。 如果这不起作用,请参阅 (https://ffmpeg.org/bugreports.html).

3.2 如何将单张图片编码成电影?

首先将您的图片重命名为符合数字顺序。例如,img1.jpg,img2.jpg,img3.jpg,... 然后运行:

ffmpeg -f image2 -i img%d.jpg /tmp/a.mpg

请注意,'%d' 被替换为图片编号。

img%03d.jpg表示序列img001.jpg, img002.jpg等。

使用-start_number选项声明序列的起始数字。如果您的序列不是从img001.jpg开始但仍然是数字顺序的话,这将很实用。以下示例将以img100.jpg:

ffmpeg -f image2 -start_number 100 -i img%d.jpg /tmp/a.mpg

如果您有大量的图片需要重命名,可以使用以下命令来减轻负担。这个命令,使用 bourne shell 语法,符号链接当前目录中所有匹配*jpg的文件到/tmp目录中,以img001.jpg, img002.jpg开始的顺序。

x=1; for i in *jpg; do counter=$(printf %03d $x); ln -s "$i" /tmp/img"$counter".jpg; x=$(($x+1)); done

如果您想按照文件最后修改时间排序,替换$(ls -r -t *jpg)*jpg.

然后运行:

ffmpeg -f image2 -i /tmp/img%03d.jpg /tmp/a.mpg

同样的逻辑也用于 ffmpeg 可读取的任何图像格式。

您也可以使用cat向 ffmpeg 管道传输图像:

cat *.jpg | ffmpeg -f image2pipe -c:v mjpeg -i - output.mpg

3.3 如何将电影编码成单张图片?

使用:

ffmpeg -i movie.mpg movie%d.jpg

作为输入的视频文件将被转换为movie.mpg used as input will be converted to movie1.jpg, movie2.jpg等...

除了依赖于文件格式的自我识别外,您还可以使用

-c:v ppm
-c:v png
-c:v mjpeg

强制编码。

应用到前一个示例:

ffmpeg -i movie.mpg -f image2 -c:v mjpeg menu%d.jpg

请注意,没有“jpeg”编解码器,请使用“mjpeg”代替。

3.4 为什么多线程 MPEG* 编码会导致轻微的质量下降?

对于多线程 MPEG* 编码,编码的切片必须是独立的,否则线程 n 实际上必须等待 n-1 完成。因此质量略有下降是很正常的。这不是一个错误。

3.5 如何从标准输入读取或写入到标准输出?

使用-作为文件名。

3.6 -f jpeg 无法工作。

尝试 '-f image2 test%d.jpg'。

3.7 为什么我无法更改帧率?

一些编解码器,如 MPEG-1/2,只允许少量的固定帧率。使用 -c:v 命令行选项选择不同的编解码器。

3.8 如何用 ffmpeg 编码 Xvid 或 DivX?

Xvid 和 DivX(版本 4+)都是 ISO MPEG-4 标准的实现(需要注意有许多其他格式使用了这个同标准)。使用‘-c:v mpeg4’以这些格式编码。存储在 MPEG-4 编码文件中的默认四字符代码为‘FMP4’。如果您想要一个不同的四字符代码,使用‘-vtag’选项。例如,使用‘-vtag xvid’将强制存储视频四字符代码为‘xvid’而不是默认值。

3.9 高质量 MPEG-4 编码的好参数是什么?

'-mbd rd -flags +mv4+aic -trellis 2 -cmp 2 -subcmp 2 -g 300 -pass 1/2',试试这些:'-bf 2','-mpv_flags qp_rd','-mpv_flags mv0','-mpv_flags skip_rd'

3.10 高质量 MPEG-1/MPEG-2 编码的好参数是什么?

'-mbd rd -trellis 2 -cmp 2 -subcmp 2 -g 100 -pass 1/2',但需注意‘-g 100’可能会导致某些解码器问题。试试这些:'-bf 2','-mpv_flags qp_rd','-mpv_flags mv0','-mpv_flags skip_rd'

3.11 隔行扫描的视频经 ffmpeg 编码后看起来非常糟糕,是什么问题?

对于隔行扫描的内容,您应该使用‘-flags +ilme+ildct’,也许可以试试‘-flags +alt’,如果结果看起来真的乱七八糟,试试‘-top 0/1’。

3.12 如何读取 DirectShow 文件?

如果您使用./configure --enable-avisynth(仅在 MinGW/Cygwin 平台可行) 构建 FFmpeg, 那么您可以使用 DirectShow 能够读取的任何文件作为输入。

只需创建一个名为 "input.avs" 的文本文件,其中包含如下单行 ...

DirectShowSource("C:\path to your file\yourfile.asf")

... 然后将该文本文件作为输入提供给 ffmpeg:

ffmpeg -i input.avs

有关 AviSynth 的任何其他帮助,请访问AviSynth 首页.

3.13 如何连接视频文件?

“连接”视频文件的含义有些模糊。以下列表解释了“连接”的不同含义,并指出如何在 FFmpeg 中处理这些情况。视频文件的连接可能意味着:

  • 将它们一个接一个放置:这称为串联它们(简称:concat)并在本FAQ中讲解。本FAQ.
  • 将它们放在同一个文件中,让用户在不同版本之间选择(例如:不同的音频语言):这称为多路复用它们(简称:mux),可以通过简单地调用 ffmpeg 并带有几个-i选项完成。
  • 对于音频,将所有通道放在同一个流中(例如:两个单声道流合成一个立体声流):这有时被称为合并它们,可以使用amerge过滤器。
  • 对于音频,叠加播放:这是指混音它们,可以先将它们合并为一个单一流,然后再使用pan过滤器随意混合通道。
  • 对于视频,将两者一起显示,彼此并排或者一个放在另一个一部分之上;这可以使用overlay视频过滤器。

3.14 如何将视频文件串联?

根据具体情况,有多种解决方案。

3.14.1 使用 concat过滤器

FFmpeg 提供了一个concat专门为此设计的过滤器,文档中有相关示例。如果您需要重新编码,建议使用此操作。

3.14.2 使用 concat解复用器

FFmpeg 提供了一个concat解复用器,当您希望避免重新编码并且您的格式不支持文件级拼接时可以使用它。

3.14.3 使用 concat协议(文件级)

FFmpeg 提供了一个concat专门为此设计的协议,文档中有相关示例。

一些多媒体容器(如 MPEG-1、MPEG-2 PS、DV)允许通过简单地拼接包含它们的文件来连接视频。

因此,您可以先将多媒体文件转码为这些特殊格式,然后使用简洁的cat命令(或在 Windows 下同样简洁的copy),最后重新转码回您选择的格式。

ffmpeg -i input1.avi -qscale:v 1 intermediate1.mpg
ffmpeg -i input2.avi -qscale:v 1 intermediate2.mpg
cat intermediate1.mpg intermediate2.mpg > intermediate_all.mpg
ffmpeg -i intermediate_all.mpg -qscale:v 2 output.avi

此外,您可以使用concat协议代替catcopy,这样可以避免创建可能很大的中间文件。

ffmpeg -i input1.avi -qscale:v 1 intermediate1.mpg
ffmpeg -i input2.avi -qscale:v 1 intermediate2.mpg
ffmpeg -i concat:"intermediate1.mpg|intermediate2.mpg" -c copy intermediate_all.mpg
ffmpeg -i intermediate_all.mpg -qscale:v 2 output.avi

请注意,您可能需要转义字符“|”,它在许多 shell 中是特殊的。

另一个选项是使用命名管道,如果您的平台支持的话:

mkfifo intermediate1.mpg
mkfifo intermediate2.mpg
ffmpeg -i input1.avi -qscale:v 1 -y intermediate1.mpg < /dev/null &
ffmpeg -i input2.avi -qscale:v 1 -y intermediate2.mpg < /dev/null &
cat intermediate1.mpg intermediate2.mpg |\
ffmpeg -f mpeg -i - -c:v mpeg4 -c:a libmp3lame output.avi

3.14.4 使用原始音频和视频连接

类似地,yuv4mpegpipe 格式和原始视频、原始音频编解码器也支持串联,并且转码几乎是无损的。当使用多个 yuv4mpegpipe 时,必须丢弃除第一流之外的所有流的第一行。这可以通过通过tail来实现,如下所示。请注意,当通过tail管道时,您必须使用命令分组{ ;},以正确地置于后台。

例如,假设我们想将两个 FLV 文件连接成一个 output.flv 文件:

mkfifo temp1.a
mkfifo temp1.v
mkfifo temp2.a
mkfifo temp2.v
mkfifo all.a
mkfifo all.v
ffmpeg -i input1.flv -vn -f u16le -c:a pcm_s16le -ac 2 -ar 44100 - > temp1.a < /dev/null &
ffmpeg -i input2.flv -vn -f u16le -c:a pcm_s16le -ac 2 -ar 44100 - > temp2.a < /dev/null &
ffmpeg -i input1.flv -an -f yuv4mpegpipe - > temp1.v < /dev/null &
{ ffmpeg -i input2.flv -an -f yuv4mpegpipe - < /dev/null | tail -n +2 > temp2.v ; } &
cat temp1.a temp2.a > all.a &
cat temp1.v temp2.v > all.v &
ffmpeg -f u16le -c:a pcm_s16le -ac 2 -ar 44100 -i all.a \
       -f yuv4mpegpipe -i all.v \
       -y output.flv
rm temp[12].[av] all.[av]

3.15 使用-f lavfi时,音频无缘无故变成了单声道。

使用-dumpgraph -找出确切丢失通道布局的位置。

很可能是通过auto-inserted aresample的地方。尝试理解为什么需要在那个位置插入转换过滤器。

输出之前是一个可能的位置,因为-f lavfi目前仅支持打包的 S16。

然后在过滤图中显式插入正确的aformat,指定确切的格式。

aformat=sample_fmts=s16:channel_layouts=stereo

3.16 为什么 FFmpeg 无法识别我的 VOB 文件中的字幕?

VOB 和一些其他格式没有描述文件中所有内容的全局头部。相反,应用应该扫描文件以查看其包含内容。由于 VOB 文件通常很大,因此只扫描开头部分。如果字幕仅在文件后面出现,则不会在初始检测中被识别。

一些应用程序,包括ffmpeg命令行工具,只能处理在初始扫描期间检测到的流;后来检测到的流将被忽略。

初始扫描的大小由两个选项控制:probesize(默认约5 Mo)和analyzeduration(默认 5,000,000 µs = 5 秒)。若要检测到字幕流,这两个值必须足够大。

3.17 为什么ffmpeg -sameq选项被移除?应该使用什么替代?

选项的意思是“相同量化器”,仅在非常有限的情况下有意义。不幸的是,很多人将其误解为“相同质量”,并在不合适的地方使用它:它大致能达到预期的视觉效果,但效率非常低下。-sameq option meant "same quantizer", and made sense only in a very limited set of cases. Unfortunately, a lot of people mistook it for "same quality" and used it in places where it did not make sense: it had roughly the expected visible effect, but achieved it in a very inefficient way.

每个编码器都有自己的选项集来设置质量与大小之间的平衡,请使用您选用的编码器的选项将质量水平设置到符合您口味的点。最常用的选项是-qscale-qmax,但您应该仔细阅读您选择的编码器的文档。

3.18 我有一个拉伸的视频,为什么缩放不能修复它?

许多视频编解码器和格式可以存储视频的纵横比:这是宽度和高度之间的比率,可能是全图像的(DAR,显示纵横比)或单个像素的(SAR,采样纵横比)。例如,640×350 分辨率的 EGA 屏幕具有 4:3 DAR 和 35:48 SAR。

大多数静态图像处理都使用方形像素,即 SAR 为 1:1,但许多视频标准,特别是模拟-数字转换时代的标准,使用非方形像素。

FFmpeg 中的大多数处理过滤器都处理纵横比以避免拉伸图像:裁剪调整 DAR 以保持 SAR 不变,缩放调整 SAR 以保持 DAR 不变。

如果您想拉伸或“取消拉伸”图像,需要使用setdar or setsar filters.

覆盖信息。

例如,要修复错误编码的 EGA 捕获,请使用以下命令:第一个用于放大到方形像素,第二个用于设置正确的纵横比,第三个用于避免转码(可能取决于格式/编解码器/播放器/月相是否有效):

ffmpeg -i ega_screen.nut -vf scale=640:480,setsar=1 ega_screen_scaled.nut
ffmpeg -i ega_screen.nut -vf setdar=4/3 ega_screen_anamorphic.nut
ffmpeg -i ega_screen.nut -aspect 4/3 -c copy ega_screen_overridden.nut

3.19 如何将 ffmpeg 作为后台任务运行?

在执行操作时,ffmpeg 通常会检查控制台输入,例如“q”来停止和“?”来获取帮助。ffmpeg 无法检测它何时作为后台任务运行。当它检查控制台输入时,可能会导致后台运行 ffmpeg 的进程挂起。

为了防止这些输入检查,使 ffmpeg 可以作为后台任务运行,请在 ffmpeg 调用中使用-nostdin选项。无论您是在 shell 中运行还是通过操作系统 API 调用 ffmpeg,此方法都有效。

另一种选择是,当您在 shell 中运行 ffmpeg 时,可以将标准输入重定向到/dev/null(在 Linux 和 macOS 上)或NUL(在 Windows 上)。您可以在 ffmpeg 调用时进行这种重定向,也可以在调用 ffmpeg 的 shell 脚本中完成这种重定向。

例如:

ffmpeg -nostdin -i INPUT OUTPUT

或(在 Linux、macOS 和其他类似 UNIX 的 shell 上):

ffmpeg -i INPUT OUTPUT </dev/null

或(在 Windows 上):

ffmpeg -i INPUT OUTPUT <NUL

3.20 如何防止 ffmpeg 停止并显示“挂起 (tty 输出)?

如果您在后台运行 ffmpeg,可能会发现其进程被挂起。可能会显示类似挂起 (tty 输出)的消息。问题是如何阻止进程被挂起。

例如:

% ffmpeg -i INPUT OUTPUT &> ~/tmp/log.txt &
[1] 93352
%
[1]  + suspended (tty output)  ffmpeg -i INPUT OUTPUT &>

尽管消息显示为“tty 输出”,问题是 ffmpeg 运行时通常会检查控制台输入。操作系统检测到此情况,挂起该进程,直到您将其置于前台并处理它。

解决方法是使用正确的技术告诉 ffmpeg 不要查询控制台输入。您可以使用-nostdin选项,或者用< /dev/null重定向标准输入。 请参考 FAQ如何将 ffmpeg 作为后台任务运行?获取更多详细信息。

4 开发

4.1 是否有用例说明如何使用 FFmpeg 库(尤其是 libavcodec 和 libavformat)?

是的。请查看doc/examples源代码库中的目录,也可以通过以下网址在线访问:https://github.com/FFmpeg/FFmpeg/tree/master/doc/examples.

示例通常默认安装在$PREFIX/share/ffmpeg/examples.

此外,您可以阅读 FFmpeg 文档中的开发者指南。作为替代,检查已经集成 FFmpeg 的众多开源项目的源代码。projects.html).

4.2 你们能否支持我的 C 编译器 XXX?

这取决于。如果您的编译器符合 C99,那么支持它的补丁可能会被接受,只要它们不会向源代码中添加与编译器相关的污染#ifdef

4.3 是否支持 Microsoft Visual C++?

是的。请参阅 FFmpeg 文档中的Microsoft Visual C++部分。

4.4 你们能否添加 automake、libtool 或 autoconf 支持?

不。这些工具太过臃肿,并且会使构建变得复杂。

4.5 为什么不将 FFmpeg 用面向对象的 C++ 重写?

FFmpeg 已经以高度模块化的方式组织起来,并不需要重写为正式的面向对象语言。此外,许多开发者更喜欢使用 C;它们习惯用 C。关于该问题的更多争论,请阅读“编程宗教论”.

4.6 为什么 ffmpeg 程序缺少调试符号?

构建过程会创建ffmpeg_g, ffplay_g等文件,这些文件包含完整的调试信息。这些二进制文件被剥离得到ffmpeg, ffplay版本等。如果需要调试信息,请使用 *_g 版本。

4.7 我不喜欢 LGPL,可以用 GPL 提交代码吗?

可以,只要代码是可选的,并且可以轻松清晰放在 #if CONFIG_GPL 下而不会破坏任何东西。例如,一个新的编解码器或过滤器可以使用 GPL,但对 LGPL 代码的错误修复则不能。

4.8 我在我的 C 应用中使用 FFmpeg,链接器抱怨库本身的符号丢失。

FFmpeg 默认构建静态库。在静态库中,依赖关系未被处理。这有两个后果。首先,您必须按照依赖顺序指定库文件:-lavdevice必须在-lavformat, -lavutil之前,必须在所有其他项后面,等等。其次,FFmpeg 中使用的外部库也必须被指定。

获取按依赖顺序排列的完整库清单的简便方法是使用pkg-config.

c99 -o program program.c $(pkg-config --cflags --libs libavformat libavcodec)

参见doc/example/Makefiledoc/example/pc-uninstalled获取更多详细信息。

4.9 我在 C++ 应用中使用 FFmpeg,但链接器抱怨似乎可用的符号丢失。

FFmpeg 是一个纯 C 项目,因此在您的 C++ 应用中使用 FFmpeg 库时,您需要显式声明使用的是 C 库。可以通过将您的 FFmpeg 头文件包含在extern "C".

环境块中完成。http://www.parashift.com/c++-faq-lite/mixing-c-and-cpp.html#faq-32.3

4.10 我在我的 C++ 应用程序中使用 libavutil,但编译器抱怨“未在此范围内声明 UINT64_C”。

FFmpeg 是一个纯 C 项目,使用了 C99 数学功能,为了让 C++ 能使用它们,你必须在 CXXFLAGS 中添加 -D__STDC_CONSTANT_MACROS。

4.11 我在内存中有一个文件/一个与 *open/*read/libc 不同的 API,我如何在 libavformat 中使用它?

你必须创建一个自定义的 AVIOContext 使用avio_alloc_context,见libavformat/aviobuf.cFFmpeg 中和libmpdemux/demux_lavf.cMPlayer 或 MPlayer2 源代码中。

4.12 关于 ffv1、msmpeg4、asv1、4xm 的文档在哪里?

https://www.ffmpeg.org/~michael/

4.13 如何向 libavcodec 传递 H.263-RTP(及其他 RTP 编解码器)?

即使网络相关,它也像其他容器一样是一个容器。你需要解复用RTP 后再将有效载荷传递到 libavcodec。 在这种特殊情况下,请参阅 RFC 4629 了解具体操作。

4.14 AVStream.r_frame_rate 是错的,它比帧率大得多。

r_frame_rate并不是平均帧率,它是能够准确表示所有时间戳的最小帧率。所以,如果它比平均帧率大,这并没有错! 例如,如果你有混合的 25 和 30 fps 内容,那么r_frame_rate将是 150(它是最小公倍数)。 如果你在寻找平均帧率,请参阅AVStream.avg_frame_rate.

4.15 为什么make fate没有运行所有测试?

确保你有 fate-suite 样本,并且SAMPLESMake 变量 或FATE_SAMPLES环境变量或--samples configure选项设置为正确的路径。

4.16 为什么make fate找不到样本?

你的样本路径中是否有用于表示主目录的~字符?该值被用于无法由 shell 展开的位置,导致 FATE 找不到文件。只需将~替换为完整路径。

本文档使用makeinfo.

托管服务提供者为telepoint.bg