首先你明白 Android 中的相关控件的定义和区别吗?
SurfaceView: 因此它本质上是一个View。但与普通View不同的是,它有自己的Surface
GLSurfaceView:作为SurfaceView的补充。它可以看作是SurfaceView的一种典型使用模式。
SurfaceTexture: 和SurfaceView不同的是,它对图像流的处理并不直接显示,而是转为GL外部纹理,因此可用于图像流数据的二次处理(如Camera滤镜,桌面特效等). Android中,Camera设备、视频解码器等都可以产生图像流,SurfaceTexture从图像流中捕获视频帧并转换成GLES纹理。SurfaceTexture在创建的时候需要一个texture对象,捕获到的视频帧会更新到纹理,然后就可以利用GPU的能力进行高效的图像处理。SurfaceTexture将Surface和Texture结合在了一起:SurfaceTexture的构造需要texture对象;利用SurfaceTexture对象可以创建Surface;对Surface进行渲染同样可以把内容更新到对应的texture上。
TextureView:它可以将内容流直接投影到View中,可以用于实现Live preview等功能。和SurfaceView不同,它不会在WMS中单独创建窗口,而是作为View hierachy中的一个普通View,因此可以和其它普通View一样进行移动,旋转,缩放,动画等变化。
Android的图形系统底层使用BufferQueue作为基础组件。Surface通常与一个BufferQueue关联,当渲染到Surface上时,结果最终将出现在传送给消费者的缓冲区中。可以把Surface理解成图像生产者一侧的接口,图像生产者通过渲染的动作把图像传递给与Buffer的消费者。
EGL 的一些API
Opengl ES中我们使用最多的有两种类型的纹理:
TEXTURE_2D: 标准的RGB格式图像数据
TEXTURE_EXTERNAL_OES,Android特有的OES纹理,预览相机或者视频使用此纹理,通过SurfaceTexture来转换得到,而摄像头采集获得的数据一般是YUV格式的,事实上,通过查看Opengl的源码我们知道,Android底层对TEXTURE_EXTERNAL_OES这种类型的纹理是经过特殊转换的
Texture 使用的大概流程
// 1. create texure
final int texture[] = new int[i];
glGenTextures(1, texture, 0);
final int texId = texture[0];
glBindTexture(GL_TEXTURE_EXTERNAL_OES, texId);
// 2. create SurfaceTexture
SurfaceTexture st = new SurfaceTexture(texId);
// 3. set listener
st.setOnFrameAvailableListener(new SurfaceTexture.OnFrameAvailableListener() {
@Override
public void onFrameAvailable(SurfaceTexture surfaceTexture) {
// notify new Frame arrival
a. surfaceTexture.updateTexImage();
b. OES | 2D -> ProvideCameraTexture
}
}, handler); // specify a thread for onFrameAvailable execution
// 4. use SurfaceTexture to capture camera preview frame
mCamera.setPreviewTexture(st);
编码
Surface inputSurface = mediaCodec.createInputSurface();
eglBase.createSurface(inputSurface);
1. Create TextureID -> SurfaceTexture(texture ID) -> camera.setPreviewTexture (surfaceTexutre) (surfaceTexture 不会显示图像)
2. Get share EGLContext -> mediaCodec.createInputSurface() -> eglBase.createSurface & new GlRectDrawer
3. EglBase.makeCurrent -> GlRectDrawer.drawRgb/Oes by TextureID , 则 Texture Data 会进入 mediaCodec
4. DequeueOutputBuffer ( releaseOutputBuffer.false) -> network send
Video Downlink:
1. OpenGl ES create Texture ID, SurfaceTexture(id) 绑定这个ID
2. Surface init with surfaceTexture
3. MediaCodec.create with Surface
4. Set listener with { onTextureFrameAvailable ... oes -> copy and save | 2d -> textureCopy RGB data bigger than yuv }
5. releaseOutputBuffer -> render:false
6. eglBase.makeCurrent(); && eglBase.makeCurrent();
7. GlRectDrawer.drawRgb or drawOes -> eglBase.swapBuffers();