【问题标题】:FFMPEG (libx264) "height not divisible by 2"FFMPEG(libx264)“高度不能被 2 整除”
【发布时间】:2014-01-17 19:39:05
【问题描述】:

我正在尝试使用 FFMPEG 使用 libx264 编解码器从一组帧中编码 .mp4 视频。

这是我正在运行的命令:

/usr/local/bin/ffmpeg -r 24 -i frame_%05d.jpg -vcodec libx264 -y -an video.mp4

我有时会收到以下错误:

[libx264 @ 0xa3b85a0] height not divisible by 2 (520x369)

经过一番搜索后,问题似乎与缩放算法有关,可以通过添加 -vf 参数来解决。

但是,就我而言,我不想进行任何缩放。理想情况下,我想保持尺寸与框架完全相同。有什么建议吗? h264 是否强制执行某种纵横比?

【问题讨论】:

  • @AleksandrDubinsky 但是 LordNeckbeard 的回答没有保留原始宽度和高度。这里我们需要手动指定宽度或高度。如果 w 使用 -vf scale=-2:ih 或 -vf scale =iw:-2 如果高度和宽度都不均匀,这将不起作用..请解释这个答案如何更优化?..谢谢
  • @varmashrivastava 好吧,SO 的工作方式是,最初可能有一个问题,然后谷歌发送了一群有不同问题的人,然后他们劫持了页面。就是这样,尽量不要与之抗争。原始问题的正确答案是-vf pad="width=ceil(iw/2)*2:height=ceil(ih/2)*2",这甚至不是答案之一。其他人的问题的正确答案是 LordNeckbeard 的。
  • @varmashrivastava 我已经解决了第一个答案。希望它不会被模组破坏。
  • @AleksandrDubinsky 谢谢..如果他/她不想要彩色填充像素,用户可以使用"scale=" 而不是"pad="

标签: ffmpeg h.264 libx264


【解决方案1】:
想要缩放视频的原始问题的答案是:
-vf "pad=ceil(iw/2)*2:ceil(ih/2)*2"

命令:

ffmpeg -r 24 -i frame_%05d.jpg -vf "pad=ceil(iw/2)*2:ceil(ih/2)*2" -vcodec libx264 -y -an video.mp4 

基本上,.h264 需要偶数尺寸,因此此过滤器将:

  1. 将原始高度和宽度除以 2
  2. 四舍五入到最近的像素
  3. 再乘以 2,成为偶数
  4. 将黑色填充像素添加到此数字

您可以通过添加过滤器参数:color=white来更改填充的颜色。见the documentation of pad

【讨论】:

  • 这不是错误。您不执行缩放并不重要,因为输出将继承输入的帧大小。
  • 为了记录,我只是在做一些我从图像中创建视频的事情,它使用 yuvj444p 作为像素格式;它不关心视频大小。然后我需要将它转换为yuv420p,然后它关心视频大小。我在维基百科上查找了 yuv420p,我认为它是一种多像素颜色格式,需要图像为特定尺寸。不过,不知道为什么压缩很重要。
  • 您最好使用 pad 而不是 scale 来添加黑色行/列。将图像放大一个像素会使其模糊。
  • @NickeManarin,此过滤器应该可以在垂直维度上添加 1 个像素的白色填充,视频位于左上方:-vf pad="width=iw:height=ih+1:x=0:y=0:color=white"。 ffmpeg pad 文档在这里:ffmpeg.org/ffmpeg-filters.html#pad-1.
  • 这里有一个解决方案,它只为奇数尺寸添加一个填充像素:-vf pad="width=ceil(iw/2)*2:height=ceil(ih/2)*2"
【解决方案2】:

这可能是因为 H264 视频通常在应用压缩之前以 4:2:0 的形式从 RGB 转换为 YUV 空间(尽管格式转换本身是一种有损压缩算法,可节省 50% 的空间)。

YUV-420 从 RGB(红绿蓝)图片开始,然后将其转换为 YUV(基本上是一个强度通道和两个“色调”通道)。然后,通过为该色调的每 2X2 平方创建一个色调样本来对色调通道进行二次采样。

如果水平或垂直有奇数个 RGB 像素,则 YUV 帧的子采样色调空间中最后一个像素列或行的数据不完整。

【讨论】:

  • 另一个有趣的事实...当您使用 Microsoft Media Foundation 的东西进行解码时,您需要为 H264 使用 16 的倍数。所以 1080P 视频实际上解码成一个 1088 高的缓冲区(尽管你忽略了最后 8 行)。
【解决方案3】:

如果你想设置一些输出宽度并以与原始相同的比例输出

scale=720:-1 

不要陷入这个问题,那么你可以使用

scale="720:trunc(ow/a/2)*2"

(仅适用于搜索如何通过缩放来做到这一点的人)

【讨论】:

  • 固定高度是scale="trunc(oh*a/2)*2:720"
【解决方案4】:

对于宽度高度

使用crop 过滤器使宽度可以被 2 整除:

ffmpeg -i input.mp4 -vf "crop=trunc(iw/2)*2:trunc(ih/2)*2" output.mp4

如果您想scale 而不是裁剪,请将crop 更改为scale

对于宽度高度

使用scale 过滤器。这将使宽度为 1280。高度将被自动计算以保持纵横比,并且宽度将被 2 整除:

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

与上面类似,但将高度设为 720 并自动计算宽度:

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

您不能同时将-2 用于宽度 高度,但如果您已经指定了一个维度,那么使用-2 是一个简单的解决方案。

【讨论】:

  • 我认为 tihis 应该被标记为正确答案,因为不涉及“技巧”。希望多次投票
  • 为什么-vf scale=-2:-2 不起作用?就我而言,我想尽可能地保留原始文件大小。对我有用的是-vf scale=-2:ih。但如果两个 h/w 不均匀,它就不起作用了。
  • @tuner -2的结果值取决于另一个维度的声明值。
  • 在我的情况下,这给了我以下错误:Size values less than -1 are not acceptable. 但@Zbyszek 的回答完美。
【解决方案5】:

LordNeckbeard 有正确的答案,非常快

-vf scale=1280:-2

安卓版别忘了加

"-preset ultrafast" and|or "-threads n"

【讨论】:

  • 你不需要声明线程:这是自动处理的。我相信 Andriod 编码为 H.264 时的缓慢是由于人们使用流行的“WritingMinds/ffmpeg-android”,它在其--disable-asm 中使用x264 build script。这会导致不必要的和显着的缓慢(您可以检查 ffmpeg 日志,如果它显示using cpu capabilties: none!,那就不好了)。我不确定他们为什么要添加它,但我不是 Android 开发人员。
【解决方案6】:

您也可以使用bitand 函数代替trunc

bitand(x, 65534)

将与trunc(x/2)*2 做同样的事情,我认为它更透明。
(在这里考虑 65534 一个神奇的数字;))


我的任务是将大量视频文件自动缩放到半分辨率

scale=-2,ih/2 导致图像略微模糊

原因:

  • 输入视频已设置显示纵横比 (DAR)
  • scale 缩放真实框架尺寸
  • 在预览期间,必须使用 DAR 校正新视频的大小,如果视频分辨率非常低(360x288, DAR 16:9) 可能会导致模糊

解决方案:

-vf "scale='bitand(oh*dar, 65534)':'bitand(ih/2, 65534)', setsar=1"

解释:

  • output_height = input_height / 2
  • output_width = output_height * original_display_aspect_ratio
  • output_widthoutput_height 现在都四舍五入到可被 2 整除的最接近的较小数字
  • setsar=1 表示 output_dimensions 现在是最终版本,不应应用纵横比校正

有人可能会觉得这很有帮助。

【讨论】:

  • 这对我有用。我使用了其他建议,但都失败了。谢谢
【解决方案7】:

scale 解决方案的问题在于它们会扭曲源图像/视频,这几乎不是您想要的。

相反,我发现最好的解决方案是在奇数维度上添加一个 1 像素的填充。 (默认情况下,填充是黑色的,很难注意到。)

其他pad 解决方案的问题在于它们不能泛化任意维度,因为它们总是填充。

如果它们是奇数,此解决方案只会在高度和/或宽度上添加一个 1 像素的填充:

-vf pad="width=ceil(iw/2)*2:height=ceil(ih/2)*2"

这是理想的,因为即使不需要填充,它也总是做正确的事情。

【讨论】:

  • 缩放解决方案最多将像素数改变 1。这几乎不会扭曲图像。如果您担心过滤速度,请使用scale=iw+mod(iw,2):ih+mod(ih,2):flags=neighbor。如果需要,这只能将每个维度增加 1,并且会复制最后一行/列。
  • @Gyan 我已经很久没有解决这个问题了(我的答案是从我很久以前发表的评论中提取的),但我记得按单个像素缩放确实 在某些情况下会引入明显的视觉伪影,这就是我首先烦恼的原因。我不记得确切,也许是单个像素变化造成的不成比例的模糊?也许仅在某些 vid/图像格式上?我只能说,我用这个修复处理了数千个视频,这是一个有利的转换。
  • 可以确认;填充像素不会增加伪影。拉伸,即使只有一个像素,也会由于混叠而添加小的伪影。
  • 刚刚遇到这个问题,可以确认这个答案有效。或者,如果您使用复杂的过滤器,这样的解决方案可以解决问题-filter_complex "[0:v] {some filters you have} [outv]; [outv]pad='width=ceil(iw/2)*2:height=ceil(ih/2)*2'[outvpad]" -map "[outvpad]"
猜你喜欢
  • 2018-06-07
  • 2020-07-02
  • 2020-07-28
  • 2020-06-21
  • 2018-09-27
相关资源
最近更新 更多