使用 ffmpeg 改变帧率
Posted
技术标签:
【中文标题】使用 ffmpeg 改变帧率【英文标题】:Using ffmpeg to change framerate 【发布时间】:2018-01-09 18:58:56 【问题描述】:我正在尝试将视频剪辑(MP4、yuv420p)从 30 fps 转换为 24 fps。帧数是正确的,所以我的输出应该从 30fps 的 20 分钟变为 24fps 的 25 分钟。其他一切都应该保持不变。
尽我所能尝试使用 ffmpeg 进行的所有操作都会转换帧速率,但会更改帧数以保持相同的持续时间,或者在不改变帧速率的情况下更改持续时间。
所以我通常会尝试这样的事情;
ffmpeg -y -r 30 -i seeing_noaudio.mp4 -r 24 seeing.mp4
(我在 Windows 上执行此操作,但通常会在 linux 上执行此操作)。这会转换帧速率但会丢帧,因此总持续时间不会改变。
或者我试过了
ffmpeg -y -i seeing_noaudio.mp4 -filter:v "setpts=1.25*PTS" seeing.mp4
这会改变持续时间但不会改变帧率。
当然,我应该能够使用单个 ffmpeg 命令来执行此操作,而无需重新编码,甚至像某些人建议的那样返回原始原始帧。
请帮忙
【问题讨论】:
-y
标志表示“不询问就覆盖输出文件”。我必须去找出那意味着什么,以确保我没有误解这里的东西。我认为这对手头的问题无关紧要,因此应该删除以简化每个人的事情。
对于-r
,文档说,“作为输入选项,忽略存储在文件中的任何时间戳,而是在假设恒定帧速率fps
的情况下生成时间戳。作为输出选项,复制或删除输入帧以实现恒定的输出帧速率fps
。"
【参考方案1】:
重新编码:
ffmpeg -y -i seeing_noaudio.mp4 -vf "setpts=1.25*PTS" -r 24 seeing.mp4
无需重新编码:
第一步 - 将视频提取到原始比特流
ffmpeg -y -i seeing_noaudio.mp4 -c copy -f h264 seeing_noaudio.h264
以新的帧速率重新混合
ffmpeg -y -r 24 -i seeing_noaudio.h264 -c copy seeing.mp4
【讨论】:
谢谢。其中第一个有效,但第二个没有按照“无法为输出文件#0(不正确的编解码器参数?)写入标头:无效参数”行返回错误消息。我不知道那是什么意思,但第一个有效。 一般情况下,-r
。当您需要在应用更多过滤器之前更改帧速率时,请使用该过滤器。
关于setpts
的注意事项:要使视频速度加倍:setpts=0.5*PTS
,要减慢视频速度,您必须使用大于1的乘数:setpts=2.0*PTS
(速度减半) reference
取决于输入帧率。 PTS 系数的基本公式为(old rate)/(new rate)
。 -r
只是新的帧率。 23.976
、29.97
和 59.94
的确切值是 24000/1001
、3000/1001
和 60000/1001
。
如果您遇到该错误,请升级 ffmpeg。自 2016 年起不再需要该标志。【参考方案2】:
只需在输入文件前的“-r”选项中指定所需的帧率:
ffmpeg -y -r 24 -i seeing_noaudio.mp4 seeing.mp4
选项会影响它们之后的下一个文件。在输入文件强制重新解释其标题之前的“-r”,就好像视频以给定的帧速率编码一样。无需重新压缩。有一个小实用程序 avifrate.exe 可以直接修补 avi 文件头以更改帧速率。上面的 ffmpeg 命令本质上是相同的,但必须复制整个文件。
【讨论】:
对于 VP8 WebM 文件(我试图在不重新编码的情况下将其从 25 fps 降低到 6fps),这两个答案都不适合我。输出视频与输入相同。 这对我来说根本不会改变输出文件的帧速率。 这对我有用,可以降低帧速率,但会使音频不同步。 这改变了我的电影速度【参考方案3】:据我所知,如果不重新编码,ffmpeg
无法做到这一点。我有一个 24fps 的文件,我想要 25fps 来匹配我正在使用的其他材料。我使用了命令ffmpeg -i inputfile -r 25 outputfile
,它与 webm、matroska 输入完美配合,并使用编码器生成了 h264、matroska 输出:Lavc56.60.100
您可以以 6fps 完成相同的操作,但正如您所指出的,持续时间不会改变(在大多数情况下这是一件好事,否则您将失去音频同步)。如果这不符合您的要求,我建议您尝试this answer,尽管我的经验是它仍然会重新编码输出文件。
为了获得最佳帧精度,您最好还是按照之前的建议解码为原始流。我为此使用了一个脚本,如下所示:
#!/bin/bash
#This script will decompress all files in the current directory, video to huffyuv and audio to PCM
#unsigned 8-bit and place the output #in an avi container to ease frame accurate editing.
for f in *
do
ffmpeg -i "$f" -c:v huffyuv -c:a pcm_u8 "$f".avi
done
显然,此脚本希望当前目录中的所有文件都是媒体文件,但可以轻松更改以将处理限制为您选择的特定扩展名。请注意,当您解压缩为原始流时,您的文件大小会增加一个相当大的倍数。
【讨论】:
【参考方案4】:您可以使用此命令,视频时长仍然保持不变。
ffmpeg -i input.mp4 -r 24 output.mp4
【讨论】:
如果您这样做,您的视频将被切断。您应该在输入文件之前指定-r
参数。
@zenw0lf 怎么截断?我对此进行了测试,效果很好。它记录在 ffmpeg 的网站上。
使用此选项后,我的视频刚从 5 分钟延长到 10 分钟。【参考方案5】:
您可以考虑使用fps
过滤器。它不会改变视频播放速度:
ffmpeg -i <input> -filter:v fps=fps=30 <output>
很好地将 fps 从 59.6 降低到 30。
【讨论】:
这可以使音频与视频保持同步,谢谢 很好,顺便说一句,您可以使用此命令将 OBS 记录大小减少约 2 倍,而不会牺牲质量或平滑度(如果使用 60fps 更改为 fps=fps=60)。所有其他命令,包括使用 x264/nvenc 以最佳质量重新编码都会产生可见的伪影 为什么使用 fps=fps= 指定关键字两次?谢谢 @ch271828n,我是从example 那里得到的。基本上第一个fps
是过滤器的名字,第二个fps
是输入参数,貌似也可以跳过。
ffmpeg -i 一般来说,要将视频的 FPS 设置为 24,几乎总是可以这样做:
有音频但没有重新编码:
# Extract video stream
ffmpeg -y -i input_video.mp4 -c copy -f h264 output_raw_bitstream.h264
# Extract audio stream
ffmpeg -y -i input_video.mp4 -vn -acodec copy output_audio.aac
# Remux with new FPS
ffmpeg -y -r 24 -i output_raw_bitstream.h264 -i output_audio.aac -c copy output.mp4
如果要查找视频格式(本例为H264),可以使用FFprobe,像这样
ffprobe -loglevel error -select_streams v -show_entries stream=codec_name -of default=nw=1:nk=1 input_video.mp4
将输出:
h264
阅读更多How can I analyze file and detect if the file is in H.264 video format?
重新编码:
ffmpeg -y -i input_video.mp4 -vf -r 24 output.mp4
【讨论】:
我用 h265 编码了视频。使用ffmpeg -y -i input_video.mp4 -c copy -f hevc output_raw_bitstream.h264
(hevc
而不是h264
)提取视频流,然后以所需的帧速率成功地重新混合该流。谢谢!
如果音频流有时间戳间隙,您的第一组命令将破坏这些间隙。此外,由于尚未重新定时,音频将不同步。
您的重新编码命令与 OP 想要的视频不一致(“我的输出应该从 30fps 的 20 分钟变为 24fps 的 25 分钟”),它而是将每秒帧的“密度”更改为 24。但更大的问题是语法错误 - ffmpeg 将因错误而中止。您已添加 -vf
但它没有参数,因此 ffmpeg 的解析器将使用 -r
作为其 arg 并出错。
可以通过运行上述命令确认音频完全混乱,因为流没有在正确的时间重新编码。【参考方案7】:
您可以尝试例如(从 25 fps 转换为 24 fps)
ffmpeg -itsscale 1.0416667 -i "你的输入文件" -vcodec copy "输出文件"
itsscale 值 1.0416667 是 25/24 作为 ffmpeg 的浮点变量(0.1234567 是浮点值格式 - 不要使用 1.04166666666666666667 或双精度值:请注意,您不能使用表达式/公式“25/ 24" 这里) 这会将帧速率时间从 25 fps 缩放到 24 fps,保持相同的帧数,但将视频延长 1.0416667。
从 23.976 到 24 或从 29.97 到 30,这个值将是 0.999)
如果您有音频,您将包含一个音频过滤器以通过使用 atempo 设置更改速度来重新调整音频而不改变音高,您还应该包含一个压缩器和比特率。 对于字幕,您只需要包含 -codec:s
所以我们会有
ffmpeg -itsscale 1.0416667 -i "输入文件" -filter:a atempo="24/25" -codec:a ac3 -b:a 640k -vcodec copy -codec:s copy "输出文件"
我使用 ac3 音频编解码器以 640K 的比特率和此处允许的表达式“24/25”:注意:24/25 是 itsscale 值 25/24 的倒数(=1.0416667)
注意:如果您有超过 1 个流(视频或音频或字幕),您可能需要包含 -map i:v:o(或 0:a:0 或 0:s:0 where 'i'是输入流号,'o' 是输出流号
【讨论】:
应该添加一个注释,即 atempo="value" ; value 是音频变化的速率。以上是关于使用 ffmpeg 改变帧率的主要内容,如果未能解决你的问题,请参考以下文章