Skip navigation.

exploreopera

| Help

Sign up | Help

随风飘荡

    笑古今,雨打风吹去

视频播放颜色问题小探

  很多人都知道播放视频文件时各种输出方式的效果是不一样的,我之前也对这些问题感到困惑,比如直观感觉上用vmr9输出时偏灰,而overlay方式输出颜色要鲜艳,经过几天折腾,基本上搞清楚了。

RGB、YUV
RGB:
  计算机彩色显示器显示色彩的原理与彩色电视机一样,都是采用R(Red)、G(Green)、B(Blue)相加混色的原理。这种色彩的表示方法称为RGB色彩空间表示。
  根据三基色原理,任意一种色光F都可以用不同分量的R、G、B三色相加混合而成。在数字视频中,对RGB三基色各进行8位编码就构成了大约16.7万种颜色,这就是咱们常说的真彩色。

YUV:
  在现代彩色电视系统中,通常采用三管彩色摄像机或彩色CCD摄像机进行摄像,然后把摄得的彩色图像信号经分色、分别放大校正后得到RGB,再经过矩阵变换电路得到亮度信号Y和两个色差信号R-Y(即U)、B-Y(即V),最后发送端将亮度和色差三个信号分别进行编码,用同一信道发送出去。这种色彩的表示方法就是所谓的YUV色彩空间表示。
  采用YUV色彩空间的重要性是它的亮度信号Y和色度信号U、V是分离的。如果只有Y信号分量而没有U、V分量,那么这样表示的图像就是黑白灰度图像。彩色电视采用YUV空间正是为了用亮度信号Y解决彩色电视机与黑白电视机的兼容问题,使黑白电视机也能接收彩色电视信号。同时,由于人眼对色度的敏感程度要低于对亮度的敏感程度,可以通过压缩U、V信号来节约空间和加速处理。
  色度信号U和V还经常被称作Pb和Pr或Cb和Cr,这些都是由不同的编码格式所产生的,但是实际上,他们的概念基本相同。在DVD中,色度信号被存储成Cb和Cr(C代表颜色,b代表蓝色,r代表红色)。

YUV与RGB相互转换的公式如下(RGB取值范围均为0-255):
Y = 0.299R + 0.587G + 0.114B
U = -0.147R - 0.289G + 0.436B
V = 0.615R - 0.515G - 0.100B

R = Y + 1.14V
G = Y - 0.39U - 0.58V
B = Y + 2.03U

  解码器使用RGB输出时不会有颜色问题(下面会说原因),以下我们主要讨论YUV输出的颜色问题。

PC、TV level
TV level:
  DVD、HDTV视频采用的记录方式,8bit亮度信号Y的范围为16-235,参考黑色记录为16,参考白色记录为235。低于16的信号称为BTB(black than black), 留有15级footroom(下动态余量);高于235的信号称为Peak White,留有19级headroom(上动态余量)。所以:
- DVD记录的信号16,在电视机被正确还原成黑色,而低于16 的信号(若有)不需要被显示出来。
- 信号235被还原成(参考)白色,如果DVD 记录有高于235的Peak White信号,若电视机的对比度设定还没有饱和的话,可以还原出这个比参考白色还“亮”的白画面,若电视机已达到饱和状态,则只能是做削波处理。
  16-235其实是对模拟电视格式的延续。
  在模拟时代,为了减小动态范围,防止出现信号饱和,就让白电平压缩。为了减少噪声对黑电平的影响(本底噪声大小是不变的),提升黑电平。然后在电视机内部用模拟电路伸张回来。
  在数字时代为了防止编辑的时候出现数据溢出,采用了同样的技巧。YUV格式,绝大多数情况下面都是以16-235格式记录的(编辑软件的默认格式也是这个)。视频解码后(大部分的编码格式用大部分的解码器) 生成的YUV都是16-235。后面还需要电路做伸张。高端数字视频系统里面 这个是用FPGA完成的。这个可以是DVD机里面的FPGA,也可以是投影里面的FPGA,也可以是显卡GPU内部集成的FPGA,如果是模拟色差输出,那么这个伸张可以用显示设备内部的模拟电路完成。
  如果你觉得这种做法挺bt的,那没有办法,因为标准就是这么要求的(ITU-R BT.601),而且还有,在这个标准里面,DVD等媒介中存储的mpeg视频的像素(取样的点之间的长宽比)还不是正方形的……标准如其名。

PC level:
  对于PC应用,采用8位的采样方式,YUV和RGB数据通常的范围都是0-255,PC显示器以(0,0,0)为纯黑,(255,255,255)为纯白。
注:并不是所有的PC显示屏都能显示(0~255)的颜色的,比如TN面板通过抖动也只能达到16.2M色(不抖动是64×64×64=0.2M色,没法看),而不是256×256×256=16.7M色。

VMR9、Overlay Mixer
  如果解码器是用RGB输出的,自然都没有问题,因为解码器在做YUV-RGB转换时会自己做伸张处理,将TV Level转为PC Level。下面说说YUV输出时的不同。

  采用Overlay渲染播放时,把解码出来的Y分量的16-235 信号,转换成(扩展)成0-255的信号,即把原来的TV level 转换成PC level,和PC桌面显示设定一致,PC 显示器就可以还原正确的画面颜色。至于BTW和Peak White 信号,一概切掉。不过,这样做也有弊端,例如:
-Peak White 信号没了,某些电影场景的高光细节会丢失。
-16-235共219级灰阶,转成255级灰阶后,会出现某些灰阶断层,例如原来的灰阶25、26,转换后变成10、12,灰级过渡就变得没有这么平滑。在某些画面情况,可能出现轻微的"Color banding"。当然咯,这个在PC显示屏上面是没有办法的事情,不过就这样输出到TV上面一般会比较凄惨,首先Peak White没了,其次如果TV再做一个(16,235)-(0,255)扩展的话,颜色就会超出显示器显示范围,产生色崩。

  而VMR9和OVERLAY不同,是不做扩展直接回放(Pass-through),不会丢失任何信号源信息,但是这样一来0-255输出色阶只有16-235是应该要的,在PC监视器上图像默认设置是不对的,会偏淡(黑色部分实际显示为深灰,白亮区显示为白灰)。
  这并不是VMR9土鳖了,因为只有这样,视频输出到电视上面才是颜色正常的(还视乎接口不同有所不同,参见最后的相关文章)。

N卡和A卡在处理上面是不一样的。
-A卡,VMR默认改为按PC level处理,和Overlay一样。
-N卡,Overlay默认改为按TV level处理,和VMR一样。
所以有些人会觉得A卡颜色比较好而N卡比较烂,其实是设定不同,不过N卡的确有不少版本的驱动预设的颜色设置比较诡异,需要简单调校才能比较合适,而A卡一般都不需要。

简单的颜色判定方法
  从zoom player的论坛上面拿到了一个测试avi,可以作为简单判定依据。
  画面右下角倒数第二个色块,如果1)看到一个灰色竖条,则颜色正确。2)如果看到3条,则为VMR默认处理方式出来的颜色。3)如果黑乎乎一片,那就是按照overlay默认的方式。
下载

还有图例,不过因为我是n卡用户,所以overlay的效果和vmr是一样的。

正确颜色:

vmr默认颜色:


解决方法
  Overlay的方式我是绝对不能够接受的,截图、调整亮度、gamma以及很多硬件后处理都没辙了,所以就先在VMR9上面想办法。
  1. 一是将解码器输出色系改为RGB,但是这样需要改变每个解码器的设置,而且这也意味着YUV-RGB的转换将由CPU(增加2~10%的CPU占用率)而不是GPU(太轻松了,GPU就是干这个的)来处理,所以直接否决。
  2. 很多人提到kmplayer可以调节输出色阶,但是我很不喜欢kmplayer,就想到用ffdshow做后处理,因为ffdshow的后处理也可以做色阶输出调节的(暴风影音1里里面翻译成级别,汗死),在xvid编码的影片上成功了(由xvid解码),但是在其他由ffdshow做解码(比如divx)的影片上却统统不成功,调了很久,换了几套解码器,差点连驱动都换了,还是没有起色,只能放弃。

  这个时候haali大爷出场了,隆重推出了了haali的视频渲染器(地址:http://haali.cs.msu.ru/mkv/,和mkv splitter是放一起的),Haali的渲染器支持选择PC Level/TV Level,还支持BT.601/BT.709选择(这个是传统视频和HD视频在YUV编码上的不同),而且可以利用shader做高质量渲染及缩放。
  不过用haali渲染器还是让我很犹豫,一来对于显卡要求比较高,官方说是最低要求Direct3D Pixelshader 1.1 (DirectX 8.0),推荐PS 2.0(DirectX 9.0);二来就意味着我要升级播放器(最新的zoom player 5.50 alpha才行)或是换用简陋的MPC;三来所有的硬解码(不是硬件后处理)就无效了,不过这一点我不太在乎,本来我这条GeForce Go 5250能硬解码的就只有DVD了,我还基本没得DVD看。
  然后非常顺利就通过了颜色测试,下面是用EVA片头的全黑画面做的对比,左边是VMR9,RGB值为(16,16,16),右边是haali,RGB值为(0,0,0)。

  但是xvid编码的字幕却死活出不来了,然后又是鼓搞了好久的解码器,又甚至要换驱动了,就在我几乎要决定放弃haali,忍受vmr9的时候,我忽然发现,xvid选项中的compatibility render居然是选上的(我原来为了对付某些宽高比不对的影片,尤其是waf版,而选上的),关了它,一切正常。狂汗……差点冤枉好人。
  还有就是暴风影音1中的haali render太旧了,问题不少,更换成新的就行,文件名是dxr.dll,在暴风的codecs目录下。新的文件可以用universal extractor解包官方的MatroskaSplitter取得。

[update]
  haali的渲染器似乎是渲染全屏幕的,因为我的rocket dock在haali render工作时无法弹出。
[update2]
答madonion问:为啥不喜欢RGB?
  因为视频资料基本上都是YUV编码,最终影像送到显卡输出到屏幕时至少要做一次YUV-RGB的转换,而无论是YUV-RGB还是RGB-YUV都是有损的,那为什么我不一路都用YUV,最后再转成RGB呢?而且使用小数据量的YUV可以明显地减轻系统负担,还可以利用显卡的运算能力。
[update3]
  参考了SilkyBibleITU-R BT.601,小修正了一点。

参考资料:
RGB/YUV格式
不要丢失灰阶信号 DVI转HDMI设置研究
视频播放显示系统的校准
Washed out image using VMR9, Why it's happening and how to fix it
DirectShow中常见的RGB/YUV格式
SilkyBible

试了试Safari 3 for Windows微笑的撒旦

Write a comment

You must be logged in to write a comment. if you're not a registered member, please sign up.