我将一个流从一个 FFmpeg 实例传输到另一个实例,但由于中间流使用了压缩,最终结果很糟糕。我需要一个无损管道来防止这种情况,并且我希望它同时包含音频和视频。
我怀疑这个问题的答案不止一个,所以任何能提供详尽解决方案列表(兼容的容器和可以管道传输的编解码器)的人都会获得加分。任何能考虑其他数据(如字幕)的人也会获得加分。
编辑:我正在寻找合适的编解码器/容器组合。我不知道为什么人们很难弄清楚这一点,因为我说我已经使用了管道,现在我需要它是无损的。
我不知道如何解释这一点而不显得自负,但这是一个常见问题解答网站。提出需要极其具体答案的问题不会帮助数百万通过在搜索引擎中输入自己的问题来访问此网站的用户。我的问题旨在帮助任何需要在 FFmpeg 实例之间无损传输数据的人,而不会用一大堆叙述和代码来解释我在做什么、为什么它不起作用以及为什么这是唯一的选择,从而分散所有人的注意力。
答案1
如何无损传输视频和ffmpeg
音频ffmpeg
提问者的要求:
- 无损地从一个实例传输
ffmpeg
到另一个实例 - 不管它是来是去
/dev/null
例子:
ffmpeg -s 1280x720 -f rawvideo -i /dev/zero -ar 48000 -ac 2 -f s16le -i \
/dev/zero -c copy -f nut pipe:1 | ffmpeg -y -i pipe:0 -c copy -f nut /dev/null
我不明白为什么有人会这样做。此外,当您很可能只使用一个进程来做任何您想做的事情时,就没有必要使用管道来ffmpeg
。ffmpeg
ffmpeg
这些选项的作用:
-s 1280x720 -f rawvideo
– 描述输入的选项/dev/zero
不是典型的输入格式,因此需要这些附加选项。-i /dev/zero
– 视频输入。本例中使用它来从“无”中生成视频流。之所以在本例中使用这个,是因为提问者拒绝提供有关所用输入的任何信息。-ar 48000 -ac 2 -f s16le
– 描述输入的选项/dev/zero
不是典型的音频格式。-i /dev/zero
– 音频输入。本例中使用它来从“无”生成音频流。-c copy
–流复制或重新多路复用输入到输出。没有执行重新编码,因此该过程是无损的。不知道提问者是否接受流复制。也许需要重新编码?-f nut
– 您需要说明ffmpeg
管道要使用什么格式。Nut 是一种容器格式。请参阅ffmpeg -formats
了解完整列表。另一种灵活的格式是-f matroska
,但如果没有问题提问者的更多信息,就不可能建议使用适当或特定的输出容器格式。pipe:1
- 使用pipe
协议输出到 stdout。或者,可以省略数字(只使用pipe:
),默认情况下,stdout 文件描述符将用于写入,stdin 将用于读取。
答案2
我学会这样做的方法(从以前的答案的部分)是使用rawvideo
视频编解码器、pcm_s16le
音频编解码器和 FFmpeg 的nut
包装器来编码流。nut
不受 FFmpeg 之外的主要程序支持,但它是我目前所知道的唯一可以支持在进程之间有效地传输数据所需的未压缩格式的容器。
此编码的参数可能如下所示:
... -c:v rawvideo -c:a pcm_16le -f nut - ...
有些音频以 24 位或更大的样本存储,对于这些音频,您应该使用pcm_24le
或其他格式。运行后会列出未压缩音频格式的完整列表ffmpeg -codecs
(您必须在列表中搜索它们)。如果您不知道音频的样本大小,使用pcm_16le
应该不会造成明显的质量损失。
在管道的接收端,将输入设置为标准输入,ffmpeg 将检测格式并解码流。
... ffmpeg -i - ...
此答案中的省略号 (...) 不是代码的一部分。这些是您的代码所在的位置。单独的连字符 (-) 告诉 FFmpeg 使用标准输入或标准输出,具体取决于它们出现的位置。
更新:
我尝试了一个简单的实验来改进这一点,似乎更好的容器是 AVI,因为其他程序可以理解它(至少 VLC 可以)。
... -c:v rawvideo -c:a pcm_16le -f avi - ...
其工作方式与旧版本完全相同,但还具有兼容性的优势。
回想起来,我很后悔发布了一个在很多情况下都没有帮助的问题,尽管我声称问题应该对每个人都有帮助。这让答案更有用。
答案3
另一个答案的一个问题是它是 pcm_s16le,而不是 s16le。此外,它包含许多冗余参数。
我会在管道中使用 pcm 而不是 flac,因为它需要的处理时间要少得多(PCM 是原始音频,FLAC 需要大量时间来编码)。
无论如何,我会这样做。
ffmpeg -i <input video file/stream> -vcodec rawvideo -acodec pcm_s16le pipe:1 | ffmpeg -f rawvideo -i - -vcodec <video output codec> -acodec <audio output codec> -vb <video bitrate if applicable> -ab <audio bitrate if applicable> <final-output-filename>
上次我尝试时,这个方法有效,但我的目标是将 ffmpeg 导入 ffplay,这是一个略有不同的过程。
例子:
这会将视频从 ffmpeg 传输到另一个实例作为原始视频输出和 16 位小端 PCM(除非您有 24 位 PCM,否则两者都是无损的,然后替换pcm_s24le
。)然后在第二个实例中将它们转换为 h.264,使用来自 Android 项目的 fraunhoefer AAC 库(libfaac
通常包含在 ffmpeg 构建中。您可以用它来替换它。)
ffmpeg -i montypythonsflyingcircus-s1e1.avi -vcodec rawvideo -acodec pcm_s16le pipe:1 | ffmpeg -i - -vcodec libx264 -acodec libfdk_aac -vb 1200k -ab 96k mpfc-s1e01-output.mkv
如果这不能将字幕传输到管道,您可以随时将它们翻录为 SRT,然后稍后再将它们混合回来,或者轻松地将它们添加到上面的管道中。