一,概念解释
什么是渲染?这是高大上的说法,翻译成正常语言,就是把图像缓冲区的数据显示到屏幕的过程,就是渲染。
原理说白了很简单,但实际操作中有太多因素需要考量。
OS/硬件提供的加速机制/解码后图像数据格式/字幕数据的格式。。。。
刚开始查找资料时,我总是试图找到所有的渲染方式,后来发现这实在错的比较离谱。因为说到底,这是一个图形学的问题:如何在计算机屏幕上绘图。不同的图形库有不同的绘图接口,太多的厂商有自己的图形库,根本不可能穷举出所有的图形库。我们只能讨论一些相对主流的方式。另外去找所有的图形渲染方式也是没有意义的,因为他们的理念大体上又是差不多的,只是API不同。唯一的要求是,你要画的足够快,因为如果你想一张张图像看起来是连续的,那么速度要达到24帧以上。当然,对于一些特殊应用,比如视频会议,15帧的速度不会让人有卡顿感,这个帧数也完全Ok。
二,问题的概念空间与一些解决方案
说完了,回到开始的问题,如何渲染。
这里又有两个问题需要解释:
1.图像缓冲区里面的数据是什么样的?RGB还是YUV,又是哪种RGB,哪种YUV?
2.如何把缓冲区的数据搬到屏幕?CPU,普通的2D加速,还是GPU,用GPU时,是OpenGL还是D3D?
第一个问题:
这里我们只说几个常见的。这里的图像缓冲区,特指解码后的数据,而非对应屏幕显示的那块。因为对于目前的真彩色显示器来说,屏幕对应的数据只有一种,就是RGB888。无论你给到的数据如何,传输到屏幕点亮色点的数据都会被驱动/硬件/总线给处理成这种格式。这是由屏幕的物理属性决定的,物理屏幕就是TTL电路点亮的一堆小灯。
常见的有RGB888/RGB565/YV12/I420p。
ps:实际解码器出来的都是YUV数据,如果得到RGB数据,通常也都是解码器后面加了一步YUV2RGB的转换,不过通常我们也会把这块功能算成是解码器的。不过不绝对,需要看lib的作者如何看待这个问题。
第二个问题:
1.纯粹的CPU(现在貌似很少有这种了),就是一个一个的往屏幕上画点了,一个pixel一个pixel的画,不太常见,也比较慢,因为操作内存太过频繁。有些库封装了overlay/bitblt等操作,虽然看起来像CPU在做,实际上已经调用了2D加速了。
2.用2D加速的
Overlay
以前看资料,老看到Overlay什么的东东,找了很久,似乎也没有谁专门给出一个标准定义,说什么才叫Overlay。说下我的理解,Overlay通常是一个硬件意义上的名词,因为屏幕上的东西,通常有很多层次,Overlay可以做的就是直接把这层放到所有图层上面。通常的用法是YUV数据直接给屏幕,Overlay硬件会替你做YUV2RGB转换。这个词貌似来自ms的directshow,有什么主表面,离屏表面,overlay之分,实际上就是硬件图层的意思。貌似有些硬件可以支持RGB Overlay,很少见。有些图形硬件可以支持多个Overlay图层,也就是说,你可以使用Overlay同时在屏幕上显示几个不同的视频。视频监控的宫格多半就是这样来的。
嵌入式里面,Overlay还有一种常见做法,比如:一些有很高优先级的提示,要给用户,这时就得把普通的提示框做成YUV的,然后提示显示出来,可以直接盖到所有的图层上去。
关于模拟Overlay,呵呵,凌乱了吧,实际上就是接口叫xxxOverlay,实际上是把YUV转成RGB,然后画点的方式显示,SDL中有这种接口。
最常见的Overlay类型是YV12,一是数据量小,二视频压缩的标准有关,因为Mpeg2/h264等标准,都强制要求这种格式,当然这两点是相符相成的。
优点就是快,缺点也比较明显,如果要做视频图像后处理,比如放大缩小,人脸识别等操作,会比较麻烦。
Bitblt
比较常见的2d加速方式,把内存数据的数据直接传输到屏幕,或者搬到另一块内存中(内存拷贝)。
blit是个有渊源的词语,这个词的本意就是块(block)移动(transfer)的缩写blt,因为这个缩写缺少元音不好读,所以后来加上了i,就变成blit。
实际上我搞不清这和DMA有什么区别,希望有人指点一下区别。难道区别仅仅是BitBlt可以同时缩放/旋转,而DMA不能?
另外与Android提出的CopyBit有区别么?我看没啥区别啊。
优点是在内存拷贝时,可以同时做缩放/旋转,缺点是只能用RGB格式。
(2014.03.30更新:
1.查了一些资料,看了一下bitblt实现原理,除去缩放/旋转的算法之外,涉及到内存搬移的应该是调用memcpy实现的,从这个角度来看,是用到了dma功能的,看来是没有什么区别的。只是memcpy的实现通常是考验硬件性能和程序员水平的地方。
2.从copybit规定的interface来看,实际就是bitblt,估计只是bitlt这个单词是ms提出的,google觉得不爽,起个新名子而已。
实际android到了4.0之后,已经取消掉了copybit HAL module,2d加速全部采用了GPU操作。在android 2.3代码里还残存着一些痕迹。)
3.GPU
其实OpenGL和D3D就是GPU在软件接口层面上的抽象。用opengl和d3d显示视频通常都是用texture方式来实现的,把一帧一帧图像生成纹理数据,然后贴到vertex上去。
简单解释一下就是,先建立顶点坐标,再建立纹理坐标,再把顶点坐标与纹理坐标一一映射,完成贴图。具体的要看一下OpenGL编程书籍了,这实在是一个复杂的题目。
先把屏幕四个点当成两个三角形(因为3d api用三角形来表示平面,当然多边形也支持,但遇到不支持的情况,用两个三角形就可以组成一个矩形),把数据的一个点一个点对应到这个矩形上,就显示了一帧。因为GPU通常是并行操作,像素生成率通常也足够高。
这块了解不够多。不多说了。
三,常见的库
这个通常又与OS有关系了,讨厌死了。
先说Windows,又分几个层次。先从底层说起。
纯api就是
Windows GDI,windows平台对图形硬件的抽象,很多年了,比较成熟,效率应该比较OK。
DirectDraw,这个封装的就是Overlay的操作接口,但是微软已经停止支持了,不建议使用。
D3D,微软的3D API,门槛比较高一些。
Direct2D,层级和GDI貌似差不多,Win7时代出现新玩意,看过一些资料,说这套API是取代GDI的,不过貌似微软已经尾大不调了。
上述几个API,VLC播放器里面都有一些具体的实现,可以看一下下。
另外就是DirectShow中的filter级别的。
VMR7,底层用DirectDraw封装的,资料说只有XP好用,更老更新的平台都不支持。
VMR9,底层用D3D实现,还在支持。
EVR,vista时代出现的东西,好像也是D3D做的(微软你到底要闹哪样。。。。这么多选择)
其实dshow还有什么overlay mixer,video render之类的filter,我觉得都没有跑出我上面说的范围。
说Linux吧。
X-window的api算一种,虽然一直用X,但对X的超多bug也很不满,从来没看过。。。(吐血)
DirectFB,通常在嵌入式平台才会使用,桌面平台上极少见到,抽象了几乎所有的2D加速机制,接口操作和DirectDraw几乎一模一样。
直接用FrameBuffer提供的接口,嵌入式多见,不过通常这些接口里面已经封装了Overlay/BitBlt接口,不要只见树木不见森林就好。
跨平台的
SDL,算是比较常用的,API的使用还比较简单,但是看代码真心觉得太乱了,不过人家是跨平台的,代码乱真心是难以避免。
最后有个比较惨痛的事实,因为你在写播放器时,这些API可能都没用,因为。。。。。你的图形库会再给你提供一套。。。。好吧,懂得原理,很多事情会简单一些。