使用GLSurface绘制相机预览

最近刚刚开始接触安卓,本着输出是最好的学习的想法,把学到的技术点总结一下。

因为公司的一个项目在华为P20手机上遇到了一个诡异的bug,作为一个刚开始接触安卓的小白就义不容辞的担负了查找bug的工作。bug现象:从强制横屏且有渲染相机的Activity跳转到一个强制竖屏的Activity,然后在返回到相机的Activity时会有较大的概率发生一次横竖屏切换的操作。即相机的Activity会先扭成竖屏然后在扭成横屏状态。

为了复现这个问题,我通过GLSurface自己手动渲染了相机的预览,现在通过这篇文章总结下实现流程。

涉及到的主要技术点:

1. 请求权限

2. 使用OpenGLES绘制图像

3. 打开相机并绘制相机画面

一、请求权限

请求权限使用的是别人已经封好的一套代码,还未完整拜读完,这里先不细说。值得注意的一点是要申请的权限需要在AndroidManifest.xml中提前定义。

 

二、使用OpenGLES绘制图像

首先参考借鉴的文章,感谢前人种树。

关于OpenGLES渲染的:https://blog.csdn.net/cassiePython/article/details/51539799

关于绘制相机预览的:https://zhuanlan.zhihu.com/p/35192609

总体思路:

  1. 需要一个GLSurfaceView,可以直接new,也可以在布局文件中中写,我用的方式是在布局文件中写。关键代码如下:

  1. 为GLSurface函数设置渲染版本,添加渲染回调,并设置渲染方式。主要的渲染工作就在渲染回调中完成。
        glSurfaceView = findViewById(R.id.gl);
        //设置渲染GLES版本
        glSurfaceView.setEGLContextClientVersion(2);
        //设置渲染回调
        glSurfaceView.setRenderer(new MyRender(this));
        /*渲染方式,RENDERMODE_WHEN_DIRTY表示被动渲染,只有在调用requestRender或者onResume等方法时才会进行渲染。RENDERMODE_CONTINUOUSLY表示持续渲染*/
        glSurfaceView.setRenderMode(GLSurfaceView.RENDERMODE_WHEN_DIRTY);

  1. 在权限请求成功后创建打开相机
        mCamera = Camera.open(Camera.CameraInfo.CAMERA_FACING_BACK);
        Camera.Parameters parameters=mCamera.getParameters();
        parameters.set("orientation", "portrait");
        parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE);
        parameters.setPreviewSize(1280, 720);
        mCamera.setDisplayOrientation(90);

        mCamera.setParameters(parameters);
  1. 在onFrameAvailable中请求渲染
    @Override
    public void onFrameAvailable(SurfaceTexture surfaceTexture){
        glSurfaceView.requestRender();
    }
  1. 实现渲染回调onRenderer
    public class MyRender implements GLSurfaceView.Renderer{
        private Context context;
        Triangle triangle = null;
        public MyRender(Context context) {
            this.context=context;
        }
        @Override
        public void onSurfaceCreated(GL10 gl10, EGLConfig eglConfig) {
            //todo 只运行一次
            requestPermission();
            //擦除颜色红色
            glClearColor(1.0f, 0.0f, 0.0f, 0.0f);
            mOESTextureId = createOESTextureObject();
            //创建一个渲染图
            mSurfaceTexture = new SurfaceTexture(mOESTextureId);
            //new一个控制GLES渲染的类
            triangle = new Triangle(context);
            try {
                mCamera.setPreviewTexture(mSurfaceTexture);
                mCamera.startPreview();
            } catch (IOException e) {
                e.printStackTrace();
            }
            //添加帧可用监听,通知GLSurface渲染
            mSurfaceTexture.setOnFrameAvailableListener(CameraActivity.this);
        }

        @Override
        public void onSurfaceChanged(GL10 gl10, int width, int height) {
            //todo 渲染窗口大小发生改变的处理
            Log.e(TAG, "onSurfaceChanged232323232323232 width:" + width + "  height" + height);
            triangle.Change(width, height);
        }


        @Override
        public void onDrawFrame(GL10 gl10) {
            //todo 执行渲染工作
            glClear(GL_COLOR_BUFFER_BIT);
            mSurfaceTexture.updateTexImage();
            triangle.draw();
        }
    }
  1. Triangle类的实现是借用参考链接中的实现做的修改。主要思路是读取glsl代码文本编译并链接到程序中,大概流程为Camera->SurfaceTexture->GLES外部纹理->GLSurfaceView

关键绑定代码:

Camera同SurfaceTexture绑定

mCamera.setPreviewTexture(mSurfaceTexture);

SurfaceTexture同GLES外部纹理绑定

mSurfaceTexture = new SurfaceTexture(mOESTextureId);
 //new一个控制GLES渲染的类
triangle = new Triangle(context);

GLES同GLSurfaceView绑定

glSurfaceView.setRenderer(new MyRender(this));

详细工程

sample地址:https://github.com/gggab/DrawCamera

你可能感兴趣的:(使用GLSurface绘制相机预览)