> 硬编/解码,软编/解码
硬编解码:使用非CPU进行编码,如显卡GPU、专用的DSP、FPGA、ASIC芯片等。性能高,低码率下通常质量低于软编码器,但部分产品在GPU硬件平台移植了优秀的软编码算法(如X264)的,质量基本等同于软编码。
软编解码:使用CPU进行编码,实现直接、简单,参数调整方便,升级易,但CPU负载重,性能较硬编码低,低码率下质量通常比硬编码要好一点。
> CPU与GPU绘图/渲染视频
CPU级别的解码(软编软解)和GPU级别的解码(硬编硬解);CPU级别的运算,GPU级别的运算。
输入的YUV420P像素数据通过一个普通的函数转换为RGB数据后,传送给OpenGL播放。也就是像素的转换是通过CPU完成的。输入的YUV420P像素数据通过Shader转换为YUV数据,传送给OpenGL播放。像素的转换是通过显卡上的GPU完成的。
-- cpu绘图采用的skia.硬件加速直接调用opengl绘图。依赖CPU实现的软件渲染,依赖GPU实现的硬件渲染。Android绘制时可采用两种方式:Canvas和OpenGL。
android.graphics.Canvas 是Android中的2D绘制API,如果不开硬件加速,就是软件渲染;
如果开了硬件加速,就是硬件渲染,内部是通过OpenGLRenderer这个类将Canvas的绘制过程交给GPU的。而Android 4.0之后默认开启了硬件加速,不过目前4.0之前的手机已经占有率已经很低。
渲染操作通常依赖于两个核心组件:CPU与GPU。CPU负责包括Measure,Layout,Record,Execute的计算操作,GPU负责Rasterization(栅格化)操作。CPU通常存在的问题的原因是存在非必需的视图组件,它不仅仅会带来重复的计算操作,而且还会占用额外的GPU资源。
了解Android是如何利用GPU进行画面渲染有助于我们更好的理解性能问题。一个很直接的问题是:activity的画面是如何绘制到屏幕上的?那些复杂的XML布局文件又是如何能够被识别并绘制出来的?Resterization栅格化是绘制那些Button,Shape,Path,String,Bitmap等组件最基础的操作。它把那些组件拆分到不同的像素上进行显示。这是一个很费时的操作,GPU的引入就是为了加快栅格化的操作。CPU负责把UI组件计算成Polygons,Texture纹理,然后交给GPU进行栅格化渲染。
然而每次从CPU转移到GPU是一件很麻烦的事情,所幸的是OpenGL ES可以把那些需要渲染的纹理Hold在GPU Memory里面,在下次需要渲染的时候直接进行操作。所以如果你更新了GPU所hold住的纹理内容,那么之前保存的状态就丢失了。
Android中GPU硬件加速控制及其在2D图形绘制上的局限- http://blog.youkuaiyun.com/iispring/article/details/49835061
Android 如何使用GPU硬件加速- http://blog.youkuaiyun.com/mandagod/article/details/48436123
-- 硬件加速提高了Android系统显示和刷新的速度,但它也不是万能的,它有三个缺陷:
1.兼容性(部分绘制函数不支持或不完全硬件加速,参见文章尾);
2.内存消耗(OpenGL API调用就会占用8MB,而实际上会占用更多内存);
3.电量消耗(GPU耗电);
> 安卓有2种绘制模型(软件绘制、硬件绘制):
一.软件绘制模型(CPU,skia),这里由CPU主导绘图,视图按照以下2个步骤绘图。
1.让视图结构(view hierarchy)失效。
2.绘制整个视图结构。
当应用程序需要更新它的部分UI时,都会调用内容发生改变的View对象的invalidate()方法。无效(invalidation)消息请求会在View对象层次结构中传递,以便计算出需要重绘的屏幕区域(脏区)。然后,Android系统会在View层次结构中绘制所有的跟脏区相交的区域。
-- 但是,这种方法有两个缺点:
1.绘制了不需要重绘的视图(与脏区域相交的区域)
2.掩盖了一些应用的bug(由于会重绘与脏区域相交的区域)
注意:在View对象的属性发生变化时,如背景色或TextView对象中的文本等,Android系统会自动的调用该View对象的invalidate()方法。
二.硬件加速绘制模型(GPU,opengl),这里由GPU主导绘图,视图按照以下3个步骤绘图。
1.让视图结构失效。
2.记录和更新显示列表(Display List)。
3.绘制显示列表。
这种模式下,Android系统依然会使用invalidate()方法和draw()方法来请求屏幕更新和展现View对象。但Android系统并不是立即执行绘制命令,而是首先把这些View的绘制函数作为绘制指令记录一个显示列表中,然后再读取显示列表中的绘制指令调用OpenGL相关函数完成实际绘制。另一个优化是,Android系统只需要针对由invalidate()方法调用所标记的View对象的脏区进行记录和更新显示列表。没有失效的View对象就简单重用先前显示列表记录的绘制指令来进行简单的重绘工作。
使用显示列表的目的是,把视图的各种绘制函数翻译成绘制指令保存起来,对于没有发生改变的视图把原先保存的操作指令重新读取出来重放一次就可以了,提高了视图的显示速度。而对于需要重绘的View,则更新显示列表,然后再调用OpenGL完成绘制。在这种绘制模型下,我们不能依赖一个视图与脏区(dirty region)相交而导致它的draw()方法被自动调用,所以必须要手动调用该视图的invalidate()方法去更新显示列表。如果忘记这么做可能导致视图在改变后不会发生变化。
-- 硬件加速提高了Android系统显示和刷新的速度,但它也不是万能的,它有三个缺陷:
a.兼容性(部分绘制函数不支持或不完全硬件加速)
b.内存消耗(OpenGL API调用就会占用8MB,而实际上会占用更多内存)
c.电量消耗(GPU耗电)