奇数分辨率视频导出报错

发布时间 2023-11-05 15:27:22作者: eth258

奇数分辨率的导出报错

前记:有群u说了个冷知识,说ae里面mp4导出奇数分辨率会报错,我当时就当作个知识点来看待了。最近想起来这件事,就去了解查询了一下,发现是yuv编码还有输出本身的问题。我也只是浅入浅出,内容写的可能有点乱,见谅

尝试验证阶段

AE内置

我用的是23sp版本,记得好像是23版本以上就开始支持不用AME也能导h264了。所以我直接用原生的来试试。合成调成奇数分辨率后,发现左下角已经是上警告了,确实是不给导。如果你强行导的话,奇数会自动减一。

AfterCode

用aftercode来导h264的奇数分辨率视频,他就没惯着你帮你修改了,直接给你报错(aftercode默认是yuv422)

image-20231104233436233

但是,如果你修改这个YUV变成444后,它是可以导出的

image-20231104234927173

而且他不是偷偷摸摸帮你修改分辨率,而是真的是奇数分辨率的视频

image-20231105103232032

YUV编码

前面的情景讲了这么多,ae能成功导出奇数分辨率的mp4格式视频就是靠YUV444来的。那么YUV是什么?

什么是YUV

YUV编码格式是一种将彩色图像表示为亮度(Y)和色度(U、V)分量的颜色空间编码方法。它是一种广泛用于视频压缩和传输的格式。其中的Y(Luma)表示图像的明亮度或灰度信息,它决定了图像的亮暗程度。U和V(Chroma)表示图像的颜色信息,它们决定了图像的色调和饱和度。

YUV数值/色彩转换

YUV中的数值,使用的是图像中的RGB来做转换而来的,转换公式有挺多种,这里列出一个

例如:将 RGB888 转换为 YUV 4:4:4

Y = ( (  66 * R + 129 * G +  25 * B + 128) >> 8) +  16
U = ( ( -38 * R -  74 * G + 112 * B + 128) >> 8) + 128
V = ( ( 112 * R -  94 * G -  18 * B + 128) >> 8) + 128
  • R、G、B中相乘的数值是一系列权重而来的常数
  • >>为右移8位
  • 后面相加的数值也是各种权重而来的值

例子来自于链接内,想了解的更深可以看看这里使用 8 位 YUV 格式进行视频渲染 |Microsoft 学习

那么到这里,就差不多可以理解YUV是对像素点做了亮度和色彩信息上的收集

YUV优势

  1. 节省存储空间:相对于RGB格式,YUV格式可以更有效地压缩视频数据。因为对于RGB来说需要同时存储R、G、B三种信息,而YUV只要存储Y和UV即可
  2. 视频编码效率高:由于人眼对亮度的敏感性更高,视频编码器可以更多地分配比特率给亮度分量,从而保留更多的细节和质量。这种分配比特率的方式与人眼感知的特性相匹配,可以在保持良好视觉质量的同时减少数据量。
  3. 跨平台兼容性:YUV格式是广泛支持的视频格式之一,几乎所有的视频编码器和解码器都支持YUV格式。

常见YUV格式

常见的YUV格式有YUV 444、YUV 422和YUV 420,它们之间的区别在于色度(U和V)的取样方式和存储方式。

  1. YUV 444:

    • YUV 444是一种无损的取样格式,它在每个像素中都包含完整的亮度(Y)和色度(U和V)信息。

    • 对于每个像素,都有一个对应的Y、U和V值,因此色度的取样率与亮度相同。

    • 这种格式产生的图像质量最高,但需要更多的存储空间。

      image-20231105005848535

    YUV 444采样格式图--X代表亮度样本、⚪代表色度样本

  2. YUV 422:

    • YUV 422是一种有损的取样格式,它在每两个水平像素中共享一个色度(U和V)样本

    • 对于每两个相邻的像素,都有一个对应的Y值,但只有一个U和一个V值。

    • 这种格式在色度分辨率上进行了折衷,相对于YUV 444,它减少了一半的色度样本,从而减少了存储空间。

      image-20231105010129469

      YUV 422采样格式图--X代表亮度样本、⚪代表色度样本

  3. YUV 420:

    • YUV 420是一种更高度压缩的取样格式,它在每四个像素中共享一个色度(U和V)样本(2×2)

    • 对于每四个相邻的像素,都有一个对应的Y值,但只有一个U和一个V值。

    • 这种格式在色度分辨率上进一步减少,相对于YUV 422,它减少了一半的色度样本,从而进一步减少了存储空间。

      image-20231105011400246

      YUV 420采样格式图--X代表亮度样本、⚪代表色度样本

    对UV采样方式的了解可以看看这个文章一文读懂 YUV 的采样与格式 - 知乎 (zhihu.com)

导出失败原因分析

​ 当我了解到YUV的三种采样格式后,我第一感觉就是:“哦!是奇数分辨率导致UV取样时候不能平均分配”。但是又仔细想了想,不对啊!1921*1080不都是能被2(YUV422)和4(YUV420)整除吗?怎么会报错呢?

​ 我拿了个24*19分辨率的视频导出,AE自己的h264报错(情理之中),然后用aftercode里面的yuv422和yuv420来导h264,都失败了。24是2也是4的倍数,按道理UV采样不是能整数分配吗?网上查询一番,突然看到有人贴了个315*81的格式工厂导出来的视频,YUV居然是420.我开始感觉到不理解了这怎么做到的(找不到原因,有知道的佬说说)。

格式工厂

​ 我直接去格式工厂试了试,发现会导出错误,然后捣鼓了一番,没有找到可以改YUV的地方

image-20231105132335796

但是发现编码格式改为DivX后可以导24*19的视频,YUV为420。我当时感觉挺合理的,因为24是4的倍数,能均分UV。但是当我极端一点,用17*15来尝试,用格式工厂来导,发现也可以。

image-20231105134533358

这个时候我感觉的是自己在YUV420的知识点可能是接触的不够深了。

FFMPEG

后面我转希望在ffmpeg,为了能展示到YUV422与420的区别性,我拿18*19这个富有代表性的分辨率来尝试

  • YUV422是成功的
ffmpeg -i 2419-444.mp4 -s 18*19 -pix_fmt yuv422p 1819-422.mp4
-i指定选择的视频
-s指定输出大小

image-20231105134958135

  • YUV420会报错
ffmpeg -i 2419-444.mp4 -s 18*19 -pix_fmt yuv420p 1819-420.mp4

报错如下:

[libx264 @ 00000242bd1ba3c0] height not divisible by 2 (18x19)
[vost#0:0/libx264 @ 00000242bd1ba100] Error while opening encoder - maybe incorrect parameters such as bit_rate, rate, width or height.
Error while filtering: Generic error in an external library
[out#0/mp4 @ 00000242bd1b1d40] Nothing was written into output file, because at least one of its streams received no packets.

符合我的想法预期

总结

对于用YUV编码格式导出奇数分辨率这个问题,除了编码原因本身,渲染导出工具的逻辑也是一个问题。像AE就写死不给你导出奇数分辨率,不管他默认的YUV是多少,Aftercode也是一样。而对于格式工厂的奇怪问题,有佬明白的话可以说说。内置的QuickTime倒是能随便导各种分辨率,因为他的色彩空间是RGB类型的,不受像素点数量而影响。