Ubuntu有点折腾人....但是在折腾之后发现它更加方便,而且懂得更多的东西
最近在调试一个视频采集芯片的驱动,主要是接收vga输入和hdmi输入,在实验的过程中遇到了一个恼火的问题,就是同一台电脑(我的联想笔记本y400),在win8的vga输出的1360768分辨率我的采集芯片能识别到,但是ubuntu下,同样的分辨率却无法识别到,采集芯片识别到参数和VESA上的标准似乎不一致...问题到底出现在哪里呢?另外一个问题,win8的vga输出多了好几个分辨率比如说19201080@60...而ubuntu却没有,最大只到1360*768..
我的ubuntu的显卡驱动有安装啊...难道是英伟达区别对待??我不相信...应用开发商不开发应用这我没办法,但是硬件应该是可以保持功能上的一致。下面就来说我是如何解决这个问题的。
必须知道的一些视频知识
vga视频信号是模拟信号,一开始它(VGA)表示一个视频分辨率640*480后面也通常表示为一个视频接口(硬件接口,规定引脚功能和电平等),我们知道显示分辨率有非常多种,见下图:
即使同一分辨率但是他们的时序不一定一样的,这个时序规定什么呢?视频信号除了有效图像数据还有消隐区,这个消隐区存在的理由是因为:
行场消隐信号,是针对老式显像管的成像扫描电路而言的。电子枪所发出的电子束从屏幕的左上角开始向右扫描,一行扫完需将电子束从右边移回到左边以便扫描第 二行。在移动期间就必须有一个信号加到电路上,使得电子束不能发出,不然这个回扫线会破坏屏幕图像。这个阻止回扫线产生的信号就叫作消隐信号,场信号的消隐也是一个道理。
除了消隐区之外,还有一个东西是必备的,那就是同步信号。
几乎所有通信都需要同步信号,无线通信(3G、4G),TCP/IP通信等。
视频信号的同步,有可以分为外同步和内嵌同步,同步信号又分为:数据使能信号(DE)、水平同步信号(HS),垂直同步信号(VS)/场同步信号(Filed)
用下面一幅图来说明这些同步信号在传输视频中的位置:
如上图所示,上半部分是者视频一行之内的信号,而下半部分是视频整体同步信号情况,data enable就是DE信号它指示了有效数据开始的时候,在视频处理中,只要知道这个信号我们就可以取出有效数据了.
然后是hs信号,它的作用就是上面提到的消隐区问题,它决定了行消隐区插入的时刻,如果是内嵌同步信号的话,也决定了EAV和SAV信号的插入时刻。
VS信号的作用是决定场消隐信号的插入时刻...
不同视频标准同样分辨率下时序的不同就体现在,诸如VS,HS宽度不同,HS到有效数据之间长度(显示后沿:148),HS离上一行结束的长度(显示前沿:88)
内嵌同步信号出现的原因是我的猜想是解决并行的干扰,或者少几条线吧..就是在数据线中传输同步信号,然后接受方检测头...内嵌同步的情况是这样滴:
一行从参考时序EAV(有效视频结尾)开始,EAV后面就是水消隐白区,水消隐白区的结尾是SAV。有SAV后面紧跟的就是有效视频区。有效视频区的样本就是真正显示在屏幕上的点,而空白区对应的就是模拟视频信号中的消隐区效视频开始)
这就是内嵌同步下一行视频的情况...
其中,SAV是有效视频行的开始标志,占4个字,前三个是3FF、000、000第四个字是XYZ,包含主要的时序信息。EAV表示有效视频行的结束,同SAV格式相同。
其中,F表示该行属于哪一个场,F=0表示场1,F=1表示场2。V表示该行是否为场消隐区的行,H用于区分EAV和SAV,H=0表示SAV,H=1表示EAV。
P3=V⊕h、P2=F⊕H、P1=F⊕V、P0=F⊕V⊕H
EAV之后的两个字LN,表示该视频行在特定的视频格式中所处的行数,色度和亮度信息中的LN是相同的。
LN后面的两个字是前一行的循环冗余码(CRC)
由于接收端需要,我的视频采集芯片配置都是内嵌同步模式..需要根据视频标准指定上面提到的同步信号的一些信息,比如和说一行之中总共像素,有效像素,一行所用时间,hs和vs的宽度,hs或者vs的显示前沿和显示后沿的宽度,这些信号的有效电平是高还是低等等。
视频标准
关于视频标准,真是五代十国般混乱,所谓视频标准就是规定上面说的这些时序..我们知道视频信号有模拟的,数字的,高清的,非高清的,还有各种各样的视频接口:hdmi、vga、S-vdieo、DVI、DP等,串行的并行的...无论它们怎么传,它们传的视频信号都是按照上面说的形式来组织的。
首先是VESA:
视频电子标准协会(Video Electronics Standards Association, VESA)是由代表来自世界各地的、享有投票权利的140多家成员公司的董事会领导的非盈利国际组织,总部设立于加利福尼亚州的Milpitas,自1989年创立以来,一直致力于制订并推广显示相关标准
VESA这个组织总共弄了三个标准:GTF、DMT和CVT。
gtf和cvt准确的说都是一套公式用于计算视频时序..你只要给出视频长宽和帧率就能按照其公式算出相关时序。
Generalized Timing Formula (GTF) is a method of generating industry standard timings used by a wide variety of display products
而cvt是:
Coordinated Video Timings (CVT) were released on March 2003 as the newest VESA standard for generating display timings
cvt是gtf的代替者。
dmt是啥?我们知道网络通信的OSI分为七层,这是专家们制定的标准,但是最后采用的却是TCP/IP的4层结构...原因就是市场往往是是否采用某个标准的决定性原因.
dmt就是这样的一个视频时序集,它是在市面上早已采用的视频标准集,这些视频格式大部分不兼容cvt和gtf公式,但是它却被市场所采纳。
Display Monitor Timings (DMT) are a list of VESA standard pre-defined timings which are commonly used within the Computer industry
这两年高清视频很火,可是高清视频的标准是另外一个制定的(==!),但是后来VESA的dmt也收集部分高清视频格式并标明是取至哪个标准.
比如说:CEA/EIA
Electronic Industries Alliance (EIA-861B) refers to a CEA/EIA standard which consists of display timing and formats supported by Digital Television
这货是专门制定数字视频标准的,难道模拟信号的vga就不能输出1080p@60的视频吗,我们的电脑最后处理和显示都是数字信号,模拟信号都需要经过ADC转换的,所以答案是:可以。
比如在VESA DMT 12p3标准中:对1080p@60视频格式有这样注明:
关于内嵌同步的标准有bt.656和bt.1120这样的标准,关于输入颜色空间有bt.601和bt.709这样的标准,关于视频接口比如说hdmi或者sdi又有各自的标准,我们做信号采集和处理的(用fpga、dsp或者专用芯片)必须仔细查看这些标准才能准确解出视频信号然后才能处理..
ubuntu的vga输出分辨率问题
有了上面的知识,现在知道为啥同样分辨率同样的帧率,同样的硬件,为什么在win8可以检测到,而在ubuntu检测不到的答案吗?梳理了一遍知识,发现很大可能是采用的标准不同导致的!!
ubuntu自带了两个命令:cvt
和gtf
。
这两个命令根据输入的分辨率和帧率得到相应的时序...
比如说
cvt 1366 768 60
# 1360x768 59.80 Hz (CVT) hsync: 47.72 kHz; pclk: 84.75 MHz
Modeline "1360x768_60.00" 84.75 1360 1432 1568 1776 768 771 781 798 -hsync +vsync
gtf 1360 768 60
# 1360x768 @ 60.00 Hz (GTF) hsync: 47.70 kHz; pclk: 84.72 MHz
Modeline "1360x768_60.00" 84.72 1360 1424 1568 1776 768 769 772 795 -HSync +Vsync
值得注意,在VESA制定视频标准中,同样视频分辨率和会分为normal blanking和reduced blanking这两种类型的视频格式,这是由于当今时代的显示器不再需要像以前那样用电子枪扫了...所以场消隐,行消隐其实没啥意义而且浪费带宽..所以催生了一种reduced blanking的视频格式,意在减少视频信号在带宽的占用...
cvt 1360 768 60 -r
# 1360x768 59.96 Hz (CVT) hsync: 47.37 kHz; pclk: 72.00 MHz
Modeline "1360x768R" 72.00 1360 1408 1440 1520 768 771 781 790 +hsync -vsync
以上,ubuntu可能使用cvt的1360768@60或者gtf的1360768@60或者使用rb(reduced blanking)的1360*768@60。
而在win8上的1360*768@60则是按照dmt来输出的,因为我是按照dmt中的参数来设置视频采集芯片的。
所以在不改变视频采集芯片的前提下,是想办法让ubuntu可以输出dmt中指定的视频信号。
上面命令Modeline
一行可以用于xorg的配置,至于xorg的配置文件作用和语法请看这个链接: Linux系统中xorg.conf文件简介 ,这里猜想这个东西可以用于规定分辨率相关东东,在Ubuntu14.04中已经没有xorg.conf这个文件,而是分为多个文件了,放在/usr/share/X11/xorg.conf.d
中。
首先搞清楚上面的命令输出的意思:我对照dmt似乎不能找到啥规律:
然后后来我找到一个计算cvt的程序,源文件链接如下:cvt.c
下载后执行gcc cvt.c -O2 -o cvt -lm -Wall
就行了
这个cvt命令能输出更多的信息..借鉴这些信息之后我就知道Modeline
那一行的意义了:
./cvt 1360 768 60 -v
1: [V FIELD RATE RQD] : 60.000000
2: [H PIXELS RND] : 1360.000000
2.5: [ASPECT_RATIO] : 16:9
2.5: [V SYNC] : 5.000000
3: [LEFT MARGIN (PIXELS)] : 0.000000
3: [RIGHT MARGIN (PIXELS)] : 0.000000
4: [TOTAL ACTIVE PIXELS] : 1360.000000
5: [V LINES RND] : 768.000000
6: [TOP MARGIN (LINES)] : 0.000000
6: [BOT MARGIN (LINES)] : 0.000000
7: [INTERLACE] : 0.000000
8: [H PERIOD EST] : 20.903589
9: [Actual V_SYNC_BP] : 26.311272
9: [Estimated V_SYNC_BP] : 27.000000
9: [V_SYNC_BP] : 27.000000
10: [Back porch] : 22.000000
11: [TOTAL V LINES] : 798.000000
12: [IDEAL DUTY CYCLE] : 23.728924
13: [H BLANK] : 416.000000
14: [TOTAL PIXELS] : 1776.000000
15: [Non-rounded PIXEL FREQ] : 84.961487
15: [ACT PIXEL FREQ] : 84.750000
16: [ACT H FREQ] : 47.719593
17: [ACT FIELD RATE] : 59.798988
18: [ACT FRAME RATE] : 59.798988
20: [H BACK PORCH] : 208.000000
21: [H SYNC RND] : 136.000000
22: [H FRONT PORCH] : 72.000000
23: [V FRONT PORCH] : 3.000000
# 1360x768 @ 60.00 Hz (CVT)
# field rate 59.80 Hz; hsync: 47.72 kHz; pclk: 84.75 MHz
Modeline "1360x768_60.00" 84.75 1360 1432 1568 1776 768 771 776 798 -HSync +Vsync
经过对照dmt中的参数,Modeline
那一行中,84.75是像素始终对应dmt中的Pixel Clock
,1360对应Hor Pixels
,1432对应Hor Pixels
+H Front Porch(像素)
,1568对应Hor Pixels
+H Back Porch(像素)
,1766对应Hor Total Time
中对应的象素,768对应Ver Pixels
,771对应Ver Pixels
+V Front Porch(行数)
,
776对应Ver Pixels
+V Front Porch(行数)
+Ver Sync Time(行数)
,798对应Ver Total Time(行数)
,-HSync指的是hs信号为负,+表示为正,对应dmt中的Hor Sync Polarity
和Ver Sync Polarity
有了这些理解,我们就可以创造出自己的Modeline
了.根据dmt中的1360*768@60 normal blanking描述:得到这样Modeline
:
Modeline "1360x768_60.00" 85.50 1360 1424 1616 1792 768 771 777 795 +hsync +vsync
看吧和cvt计算出来的差别还是有滴,hs极性都不同...
怎么将这个分辨率添加到vga输出呢,有一种临时的方法(注销后失效),还有一种永久性的方法(就是xorg配置文件)。
先介绍临时方法,主要命令是xrandr
命令,
xrandr - primitive command line interface to RandR extension
其中RandR是:
RandR is a communications protocol written as an extension to the X11[2] and Wayland[3] protocols for display servers. Both, XRandR and WRandR facilitate the ability to resize, rotate and reflect the root window of a screen.
反正就是控制display server的命令就对啦...它能控制屏幕分辨率,旋转大小等...当然显示服务器的下面必须有显卡驱动,显卡驱动下面必须有显卡这个硬件,显示服务器上面必须有显示器或者其它视频接收设备,不然这个命令不会起作用。
执行xrandr输出相关硬件信息:
xrandr
Screen 0: minimum 8 x 8, current 1366 x 768, maximum 16384 x 16384
VGA-0 disconnected (normal left inverted right x axis y axis)
LVDS-0 connected primary 1366x768+0+0 (normal left inverted right x axis y axis) 310mm x 174mm
1366x768 60.0*+
1024x768 60.0
960x540 60.0
840x525 59.9
800x600 60.3
800x512 60.2
720x450 59.9
700x525 60.0
680x384 60.0 59.8
640x512 60.0
640x480 59.9 60.0
576x432 60.1
512x384 60.0
400x300 60.3
320x240 60.1
HDMI-0 disconnected (normal left inverted right x axis y axis)
上面说明了,我的笔记本有一个显示器处于连接状态(废话==!),还有一个VGA口和hdmi口处于未连接状态,这和我的硬件是相符合的,在输出信息中欧你那个需要记住:Screen 0,VGA-0和LVDS-0这样的名字。
加新分辨率的一般过程如下:
# 得到某一分辨率的modeline
cvt 1680 1050 60
# 1680x1050 59.95 Hz (CVT 1.76MA) hsync: 65.29 kHz; pclk: 146.25 MHz
Modeline "1680x1050_60.00" 146.25 1680 1784 1960 2240 1050 1053 1059 1089 -hsync +vsync
# 增加一个模式
sudo xrandr --newmode "1680x1050_60.00" 146.25 1680 1784 1960 2240 1050 1053 1059 1089 -hsync +vsync
# 将这个模式添加到硬件上,注意VGA-0可根据需要改成LCDS-0或者HDMI-0等
sudo xrandr --addmode VGA-0 "1680x1050_60.00"
#在指定硬件输出指定模式
xrandr --output VGA --mode 1680x1050_60.00
关于1360*768,上面命令中只需要改变modeline参数和模式名字,就行了,实践结果是吻合上面猜想的.
接下来让它用久生效:
在/usr/share/X11/xorg.conf.d
新建一个文件:10-monitor.conf然后输入以下内容,保存然后注销,然后测试:
#Modeline 像素时钟 HP HP+HFP HP+HBP HTP VP VP+VFP VP+VFP+VSW VTL HS有效电平 VS信号的有效电平
Section "Monitor"
Identifier "Monitor0"
HorizSync 30.0 - 83.0
VertRefresh 56.0 - 75.0
Option "DPMS"
Option "VendorName" "Nvidia Proprietary Driver"
Modeline "1366x768_60.00" 85.50 1366 1436 1579 1792 768 771 774 798 +hsync +vsync
Modeline "1360x768_60.00" 85.50 1360 1424 1616 1792 768 771 777 795 +hsync +vsync
Modeline "1920x1080_60.00" 148.50 1920 2008 2068 2200 1080 1084 1089 1125 +hsync +vsync
Modeline "1440x900_60.00" 106.50 1440 1528 1672 1904 900 903 909 934 -hsync +vsync
Modeline "1600x1200_60.00" 162.00 1600 1664 1904 2160 1200 1201 1204 1250 +hsync +vsync
Modeline "1280x720_60.00" 74.25 1280 1390 1500 1650 720 725 730 750 +hsync +vsync
Modeline "1600x900_60R" 108.00 1600 1624 1696 1800 900 901 904 1000 +hsync +vsync
EndSection
Section "Screen"
Identifier "Screen0"
Device "VGA-0"
Monitor "Monitor0"
Option "ModeValidation" "AllowNonEdidModes, NoVirtualSizeCheck, NoMaxPClkCheck, NoWidthAlignmentCheck, NoExtendedGpuCapabilitiesCheck"
DefaultDepth 24
SubSection "Display"
Depth 24
Modes "1366x768_60.00" "1360x768_60.00" "1920x1080_60.00" "1440x900_60.00" "1600x1200_60.00" "1280x720_60.00" "1600x900_60R"
EndSubSection
EndSection
Section "Screen"
Identifier "Screen0"
Device "LVDS-0"
Monitor "Monitor0"
Option "ModeValidation" "AllowNonEdidModes, NoVirtualSizeCheck, NoMaxPClkCheck, NoWidthAlignmentCheck, NoExtendedGpuCapabilitiesCheck"
DefaultDepth 24
SubSection "Display"
Depth 24
Modes "1366x768_60.00"
EndSubSection
EndSection
注销后会发现VGA输出了多了好多分辨率,而且我指定的分辨率都是我想要的时序,也就是你能随意的创造出自己的想要的视频信号时序,这就是ubuntu的魅力!!!
嘿嘿,最后还是要泼下冷水,英伟达的确区别对待了Linux和windwos...在ubuntu中的nvidia的控制面板上找不到任何关于添加自定义分辨率的选项,而在win8上却找到了,而且是傻瓜式,也就是说上面说的,win8也可以做到嘿嘿.:
但是,起码证明了一点ubuntu也可以做到..而且在折腾过程中学到更多...
一些截图: