完整代码查看# AndroidShaderDemo下的SplitScreenOneActivity
想要的效果如下,上下两个屏幕显示相机预览图像:
这里给出分屏预览的一种方式,在布局里使用GLSurfaceView和SurfaceView两个View分别展示相机预览,缺点是录制视频时不能保持画面的分屏特效,如果要想录制时也要分屏,那么分屏后的画面应该在一张图片纹理上,这个以后再说,这里先看两个View展示的效果。
在看这篇之前,最好先看之前的Camera开发和Android java层封装EGL
分屏显示原理是,GLSurfaceView通过SurfaceTexture接收相机传来的数据显示预览图像,这时预览图像是个纹理,把纹理传给SurfaceView,这样就达到分屏显示的效果。当然因为SurfaceView没有OpenGL的运行环境,还要封装个离屏Render。
GLSurfaceView怎么显示相机预览图像就不重复了,重点看第二步,把纹理传给SurfaceView显示。
首先要为SurfaceView建立渲染线程,HandlerThread可以帮忙,简化不少工作。
handlerThread = new HandlerThread("preview");
handlerThread.start();
previewHandler = new Handler(handlerThread.getLooper());
之后就可以通过previewHandler来post渲染线程的指令了。
在GLSurfaceView的render回调里,初始化SurfaceView的Callback:
surfaceView.getHolder().addCallback(new SurfaceHolder.Callback() {
@Override
public void surfaceCreated(SurfaceHolder surfaceHolder) {
previewHandler.post(new Runnable() {
@Override
public void run() {
offScreenRender = new OffScreenRender(eglContext, surfaceView.getHolder().getSurface());
}
});
}
......
}
这里在preview线程里生成一个offScreenRender离屏render,render有了,下面在相机每帧回调时取得纹理,用offScreenRender画出来:
@Override
public void onFrameAvailableCallback(final VideoFrameData frameData) {
previewHandler.post(new Runnable() {
@Override
public void run() {
if(offScreenRender != null){
offScreenRender.draw(frameData.getFilter(), frameData.getMatrix(), frameData.getTextureId()
,frameData.getTimestamp());
}
}
});
}
可见offScreenRender做了主要工作,GLSurfaceView和SurfaceView共享一个EGLContext:
1.建立OpenGL环境
2.发送OpenGL渲染指令
建立OpenGL环境的工作用到了之前的Android java层封装EGL,这里不再累述,重点是把SurfaceView的Surface传递给EglCore,这样EglCore才知道往哪里绘制。
发送OpenGL渲染指令封装成了:
public void draw(CameraInputFilter cameraInputFilter, float[] matrix, int textureId, long time) {
cameraInputFilter.onDrawFrame(textureId);
offSreenSurface.swapBuffers();
}
这里主要关注其中两个参数cameraInputFilter和textureId,textureId就是传来的纹理,cameraInputFilter这里直接显示,当然这里也可以做些特效,这样分屏后,上下两个画面显示就不一样了。
网友评论