使用FFmpeg保持宽高比

74

我需要使用FFmpeg转换一堆视频文件。我运行一个Bash文件来转换所有的文件,但如果转换的文件不是16:9格式,则会出现问题。

由于我将屏幕大小设为-s 720x400,如果原始文件的宽高比为4:3,则FFmpeg会创建一个16:9的输出文件,从而破坏了宽高比。

是否有一种设置可以将宽高比作为主要参数进行设置,并只调整大小(例如仅固定X或Y维度)?

10个回答

97
-vf "scale=640:-1"

工作得很好,直到你遇到错误

[libx264 @ 0x2f08120] height not divisible by 2 (640x853)

所以最通用的方法是使用过滤表达式:

scale=640:trunc(ow/a/2)*2

它获取输出宽度(ow),将其除以宽高比(a),再将其除以2,截断小数点后的数字,并乘以2。这确保了生成的高度可被2整除。

感谢 ffmpeg trac

更新

正如评论指出的那样,更简单的方法是使用-vf "scale=640:-2"。 感谢@BradWerth提供优雅的解决方案。


11
或者,如果您想指定高度并让ffmpeg按比例设置宽度,则为scale=trunc(oh*a/2)*2:min(480\,iw) - Christian Davén
1
@BradWerth 这个有文档记录吗? - Adam
1
@Adam 我想不起来了。我相信我只是在实现这个优秀的答案时阅读选项并调整设置。 - Brad Werth
2
小注:scale=640:trunc(ow/a/2)*2scale=640:-2 都是足够的答案,但不一定等价。前者中的截断可能会根据输入源的大小而使值小 2 像素,例如。 - systemexit
2
据我所知,这仅适用于x264,并与宽度和高度相关。 - mente
显示剩余2条评论

33
例如:

1920x1080宽高比16:9 => 640x480宽高比4:3:

ffmpeg -y -i import.media -aspect 16:9 scale=640x360,pad=640:480:0:60:black output.media

宽高比 16:9,宽度为 640 像素 => 高度为 360 像素:
最终输出大小为 640x480,使用黑色图像填充 60 像素(上下):

"-vf scale=640x360,pad=640:480:0:60:black"

2
我刚需要从640x480转换到1280x720,并使用了-aspect 16:9 -vf scale=960x720,pad=1280:720:160:0:white(我也需要白色填充而不是黑色)。谢谢! - Peter K.
1
我需要走相反的路线,从640x480到1920x1080并且使用pillar boxing:-vf“scale=1440x1080,pad=1920:1080:240:0:black” - whereisalext
我用以下命令成功运行了它:ffmpeg -y -i 01.mp4 -vf "scale=640x360,pad=640:480:0:60:black" 02.mp4 - John Trichereau

25

我很久以前问过这个问题,但事实上我现在有了一个解决方案--为了保持宽高比,你应该使用视频滤镜缩放,它是一个非常强大的滤镜。

你可以简单地像这样使用它:

-vf "scale=640:-1" 

这将固定宽度并提供所需的高度以保持纵横比。但您还可以使用许多其他选项甚至数学函数,请在此处查看文档-http://ffmpeg.org/ffmpeg.html#scale


3
这个方案很好,但我发现如果高度不能被2整除,仍然可能遇到问题。有没有什么办法可以解决这个问题? - DevDave
18
请注意这里的答案也包括了-vf "scale=640:-2" - coco

15
使用来自ffmpeg tracforce_original_aspect_ratio
ffmpeg -i input.mp4 -vf scale=720:400:force_original_aspect_ratio=decrease output.mp4

当你的视频尺寸像1438x800这样奇怪时,这个方法会失败,结果将是719x400,并且会因为宽度不能被2整除而报错... - Daniel Carrasco Marín
@DanielCarrascoMarín 是的,当您无法控制输入视频大小时,ffmpeg 本身无法解决除以2的问题(不幸的是)。我已经通过在Python脚本中计算宽高比,然后传递我想要的 ffmpeg scale= 参数来解决了这个问题。 - xmedeko
2
我刚刚使用ffmpeg 3.4和3.2.9进行了测试,它完美地工作了。视频变成了719x400,但没有出现任何错误。我可以使用VLC媒体播放器播放它(在右侧看到了额外的像素)。Ubuntu本地视频播放器也能够很好地播放它。之后,ffmpeg可以读取该文件并将其转换为另一个文件。 - Kostanos

14
尽管大多数答案都很好,但我正在寻找一种可以调整到目标尺寸(宽度或高度)并保持纵横比的命令。我使用了ffmpeg的表达式求值来实现这一点。
以下是相关的视频滤镜,目标尺寸为512: -vf“thumbnail,scale ='if(gt(iw,ih),512,trunc(oh*a/2)*2)':'if(gt(iw,ih),trunc(ow/a/2)*2,512)'”

对于输出宽度:

'if(gt(iw,ih),512,trunc(oh*a/2)*2)'

如果宽度大于高度,则返回目标宽度,否则返回相应比例的宽度。


对于输出的高度:

'if(gt(iw,ih),trunc(ow/a/2)*2,512)'

如果宽度大于高度,则返回相应的高度,否则返回目标高度。


"-vf“scale='if(gt(iw,ih),512,-1)':'if(gt(iw,ih),-1,512)'”更加简单易懂。 - PRMan

13

如果你想要适应一个边界框,那么按照xmedeko的回答中提到的使用force_original_aspect_ratio是一个好的起点。

但是,如果你的输入视频尺寸很奇怪,且你正在将其编码为需要宽高为偶数的格式时,这种方法就不适用了,会导致错误。

在这种情况下,可以在scale函数中使用表达式求值,就像Charlie的回答所示。

假设输出边界框为720x400:

-vf "scale='trunc(min(1,min(720/iw,400/ih))*iw/2)*2':'trunc(min(1,min(720/iw,400/ih))*ih/2)*2'"

对此进行分解:

  • min(1,min(720/iw,400/ih)找到缩放因子以适应边界框(来自这里),将其限制为最大为1,以确保只有缩小,以及
  • trunc(<scaling factor>*iw/2)*2trunc(<scaling factor>*iw/2)*2通过除以2,使结果为整数,然后再乘回来,确保尺寸是偶数。

这消除了在编码之前找到输入视频尺寸的需求。


3

由于ffmpeg需要宽度/高度可被2整除, 而我猜想您想指定其中一个维度,因此这将是选项:

ffmpeg -i input.mp4 -vf scale=1280:-2 output.mp4

难以置信这个方法可以解决“参数不正确”的错误。我想补充一点,即0符合此条件,但会导致意外的扭曲。 -2是一个令人恼火的简洁解决方法,而且它确实有效!+1 - 1owk3y
会因为垂直视频、移动用户内容等而中断。 - Oliver Dixon

2
以上的回答都很好,但大多数都假定了特定的视频尺寸,并且不能处理通用的宽高比。
您可以使用以下方法将视频填充到任何宽高比,而不管具体的尺寸:
-vf 'pad=x=(ow-iw)/2:y=(oh-ih)/2:aspect=16/9'

我在我的示例中使用比率16/9。上述是一个快捷方式,只需执行更多手动操作,如下所示:

pad='max(iw,(16/9)*ih)':'max(ih,iw/(16/9))':(ow-iw)/2:(oh-ih)/2

那可能会输出奇数尺寸(不是偶数)的视频尺寸,因此您可以像这样确保输出为偶数:
pad='trunc(max(iw,(16/9)*ih)/2)*2':'trunc(max(ih,iw/(16/9))/2)*2':(ow-iw)/2:(oh-ih)/2

但实际上你只需要 pad=x=(ow-iw)/2:y=(oh-ih)/2:aspect=16/9

对于以上所有示例,如果输入视频具有奇数尺寸,则会出现错误。即使是pad=iw:ih,如果输入是奇数大小也会出错。通常情况下,您不会有奇数大小的输入,但如果确实有,您可以先使用此过滤器进行修复:pad='mod(iw,2)+iw':'mod(ih,2)+ih'


1
如果存在“-aspect x:y”并且输出文件格式为ISO媒体文件格式(mp4),则ffmpeg会在视频轨道的stsd-box中添加pasp-atom(PixelAspectRatioBox)以向播放器指示预期的纵横比。播放器应相应地缩放视频帧。不需要在编码或转码之前缩放视频以适应纵横比,这应由播放器执行。

1

你可以使用ffmpeg -i命令获取原始文件的尺寸,并在编码命令中使用它。你在哪个平台上使用ffmpeg?


嗨,我正在Linux上使用它。理想情况下,我希望有一个Bash脚本,可以适用于任何宽高比。我猜我可以手动调整非宽屏分辨率,但是在ffmpeg中有太多选项,我认为我只是不知道如何设置... - 0-alpha
2
是的,这是一个答案,因为通过使用原始尺寸并通过简单计算将其缩小(或放大),OP可以“手动”解决问题。 - Alfe
无论如何,我发现它非常有用。就个人而言,我很高兴这个答案被发布了。 - TripleAntigen

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接