前天我和VempX瞄准DVDRIP过程中的YV伸张与压缩进行了一些实验。今天我做了一些实验,整理了一下播放过程中YC伸张与否的规律,分享给大家。其实我有些怀疑这篇文章的意义,因为用户随便按一下显示器上的MagicSet之类的按钮,或者调节一下亮度色温对比度给图像带来的改变远远大于播放设置错误带来的误差。老实说,我在这做了半天实验带来的实际意义似乎并不是很大。
但就算这样,该做的还是要做,该写的还是要写。少点错误总比多点错误强。
本文理论浓度较低,但是实践的部分比较复杂,估计有不少人会头晕,头晕的话可以先去看结论,等回过头来再看实践部分或许就能理解了。
文章中若存在错误、不足的地方,还要您请多指教。
废话少说,现在进入理论。
理论篇首先我们要明确,
YC伸张发生且仅发生于从YUV颜色空间向RGB颜色空间进行转换的过程。明确了这点之后我们就可以减少很多不必要的猜想和迷惑。
其次,在播放过程中影响YC伸张的环节有三,一个是解码器,一个是渲染器,还有就是显卡。
有些解码器/渲染器不带有YC伸张或RGB转换功能,那最终完成YUV到RGB转换任务的或许就是显卡。
实验准备篇为了清楚地知道播放过程中是否进行了YC伸张,必须要准备的东西还是彩条,这里称为
彩条A。因为普通的彩条难以判断黑、白、红、绿、蓝的范围,所以我们用Photoshop制作一张专门用来判断颜色、亮度范围的640*480的彩条图片,保存为24bit bmp格式。彩条上半部分的颜色范围为16~240,黑白部分为16~235(601 Range)。下半部分全部为0~255(Full range),用于进行对比。
之后,使用使用以下AVS代码将bmp图片生成一个5秒钟的短片。
- #AVS代码1:
- ImageSource ("colorbar.bmp",end=149)
- AssumeFPS("ntsc_video")
将这个短片送入TMPGEnc压缩成MPEG2格式。压缩时,
打开TMPGEnc的YC压缩选项,此时图像上部为30~217,下部为16~235。
播放时:
[*]图像上部为30~217、下部为16~235,则没有进行YC伸张。(也就是MPEG2里面的原始数据)
[*]图像上部正常回复为601 Range、下部为Full range则判断为进行了一次YC伸张。
[*]如果上下全都变成了0~255的Full range,则是进行了两次YC伸张。
当然,只有第二种情况才是正确的。
除此之外,为了判断显卡/渲染器是否能够自动判断是否进行YC伸张,我们制作了另一个彩条,这里称为
彩条B。彩条B的内容与彩条A完全一致,但是在送入TMPGEnc压缩成MPEG2格式时,
关闭TMPGEnc的YC压缩选项,此时图像上部为16~235,下部为0~255。
播放时:
[*]图像上部为16~235、下部为0~255,则没有进行YC伸张。(也就是MPEG2里面的原始数据)
[*]图像上下完全相同,都是0~255,则进行了至少一次YC伸张。
只有第一种情况是正确的。
因为我在学校只有一台笔记本电脑,主板集成Intel X3100显卡,所以没办法测试其他厂商的显卡效果如何,所以在测试显卡是否做了YC伸张这个环节里,结果只代表X3100。
实验进行篇【播放TV Scale的视频(彩条A)】(我们下载到的99%的视频都是TV Scale的)
haali's video render(设置为tv scale,进行YC伸张)Elecard(yuy2) 正确
ffdshow libmpeg2(yuy2 tv/pc) 正确
ffdshow libmpeg2(转换为rgb,设定为TV Scale,伸张) 正确
ffdshow libmpeg2(转换为rgb,设定为PC Scale,不伸张) 错误
haali's video render(设置为pc scale,不进行YC伸张)ffdshow libmpeg2(yuy2) 错误
ffdshow libmpeg2(转换为rgb,设定为TV Scale,伸张) 错误
ffdshow libmpeg2(转换为rgb,设定为PC Scale,不伸张) 正确
覆盖合成器ffdshow libmpeg2(yv12) 正确
ffdshow libmpeg2(转换为rgb,设定为TV Scale,伸张) 正确
ffdshow libmpeg2(转换为rgb,设定为PC Scale,不伸张) 错误
VMR9无渲染ffdshow libmpeg2(yv12) 正确
ffdshow libmpeg2(转换为rgb,设定为TV Scale,伸张) 正确
ffdshow libmpeg2(转换为rgb,设定为PC Scale,不伸张) 错误
小结:因为片源是TV Scale的,因此播放过程中需要做一次且只能做一次YC伸张。从实验结果看出,YC伸张发生并且仅发生于YUV颜色空间到RGB颜色空间的转换过程中。因此,要不在解码器这一步伸张并转换RGB,要不在渲染器中伸张转换成RGB。
当在解码器中转换为RGB时:ffdshow中,RGB变换页里的“对比度”设置会起作用。当选择“标准”的时候做YC伸张,选择“全范围”的时候不做YC伸张。渲染器收到RGB之后会跳过YC伸张步骤。
不在解码器中转换为RGB时:当解码器输出YUV颜色空间给渲染器时(haali不吃YV12,只吃YUY2和RGB的样子),部分渲染器会将其转换为RGB颜色输出给显卡。haali好像就是这样做的,haali会根据用户设置的TV range(伸张)还是PC range(不伸张)决定是否进行伸张。覆盖合成器和VMR9的资料比较少,我不知道他们是否会将颜色空间转换为RGB,但是至少从直观看来,通过覆盖合成器和VMR9之后,都经过了YC伸张,只是不知道这个伸张是显卡做的还是合成器做的。
【播放PC Scale的视频(彩条B)】
覆盖合成器ffdshow libmpeg2(yv12) 错误
VMR9无渲染ffdshow libmpeg2(yv12) 错误
haali's video render(tv scale)ffdshow libmpeg2(yuy2) 错误
haali's video render(pc scale)ffdshow libmpeg2(yuy2) 正确
小结:自动判断是否需要YC伸张是不可能实现的?
结论篇主要的结论在前面的小结中已经给出。尽管不同的显卡对于图像具体的处理方式不同,我们仍然有一个方法可以在所有的显卡上显示出正确的图像:将正确的RGB颜色交给显卡就可以了(尽管可能需要较高的系统配置,但大多数标清级的视频的话P4以上的CPU应该都能胜任)。因此,ffdshow解码和haali渲染着对组合不错。ffdshow输出yuy2颜色,在haali渲染器中进行YC伸张。如果实在不知所措的话,不如干脆拿彩条试一试,看看怎么能放出正确的颜色即可。