前言:

  • 在上一篇文章中给小伙伴们介绍了进行Camera预览,如果你还没有看过的话,建议先去看上一篇文章《Android 短视频开发之摄像头预览(二》

  • 本篇文章会介绍如何实现摄像头预览画面实时美颜

原理:

废话就不多啰嗦了,要达到 摄像头实时美颜的效果,从原理上来讲很简单,只要保证每一帧画面经过美颜处理后显示在界面上就完了。

实现思路:

前面的预览过程就不罗嗦了,不懂可以看上一篇文章。

这里有两种方式实现

  1. 在Camera.PreviewCallback回调中直接获取图片数据,然后经过OpengGL处理后再显示出来
  2. 直接让Camera的预览画面渲染在OpengGL的OES纹理中,通过SurfaceTexture把数据交给OpengGL渲染后再渲染到屏幕上

当然第一种缺点很明显就是渲染速度太慢会导致预览异常卡顿,帧率也达不到要求,主要问题在于摄像头获取的数据时YUV格式的数据而,OpenGL渲染是RGBA格式的数据,这就导致要渲染首先要先转换颜色空间,这个转换时比较耗时的。二第二种方式刚好能规避这个问题,直接把这已转换过程让GPU做了,速度非常快。预览和渲染效果很好,而且帧率也能达到要求。所以一般美颜相机类应用都会选择第二种方式来处理。

在这里由于后面的模块都涉及到OpengL渲染,所以需要有一定的OpenGL经验,建议对OpenGL不熟的先学习下基础。网上关于OpenGL的文章有很多这里就不列举了。

具体实现

1.创建OpenGL渲染环境,因为使用的时TextureView所以需要自己创建

  /**     * Surface 要显示的TextureView中的surface     */    void surfaceCreated(SurfaceTexture surface) {        //创建OpenGL环境        mEglCore = new EglCore(null, EglCore.FLAG_RECORDABLE);        mDisplaySurface = new WindowSurface(mEglCore, surface);        //切换到当前上下文环境中        mDisplaySurface.makeCurrent();        GLES30.glDisable(GLES30.GL_DEPTH_TEST);        GLES30.glDisable(GLES30.GL_CULL_FACE);        // 渲染器初始化        mRenderManager.init(mContext);        //创建OES纹理        mInputTexture = OpenGLUtils.createOESTexture();                //创建SurfaceTexture供Camera.setPreviewTexture()        //这里时关键把摄像头的数据映射到SurfaceTexture的纹理当中供后面渲染        mSurfaceTexture = new SurfaceTexture(mInputTexture);        mSurfaceTexture.setOnFrameAvailableListener(this);        // 打开相机        openCamera();        Log.d("RenderThread","onSurfaceTextureAvailable="+surface);    }

2.接收SurfaceTexture的OnFrameAvailableListener的回调

 @Override    public void onFrameAvailable(SurfaceTexture surfaceTexture) {        requestRender();    }

3.在接收到数据变化后就开始渲染数据并显示到屏幕

    /**     * 绘制帧     */    void drawFrame() {        if (mSurfaceTexture == null || mDisplaySurface == null) {            return;        }        // 当记录的请求帧数不为时,更新画面        while (mFrameNum > 0) {            // 切换渲染上下文            mDisplaySurface.makeCurrent();            //更新图像数据            mSurfaceTexture.updateTexImage();            mSurfaceTexture.getTransformMatrix(mMatrix);            --mFrameNum;            // 绘制渲染            mCurrentTexture = mRenderManager.drawFrame(mInputTexture, mMatrix);            // 显示到屏幕            mDisplaySurface.swapBuffers();        }    }

关键步骤

// 绘制渲染mCurrentTexture = mRenderManager.drawFrame(mInputTexture, mMatrix);

在这个渲染管理器里完成了图像的渲染

drawFrame干了些什么事情呢?

  /**     * 绘制纹理     * @param inputTexture     * @param mMatrix     * @return     */    public int drawFrame(int inputTexture, float[] mMatrix) {        int currentTexture = inputTexture;        if (mFilterArrays.get(VideoRenderIndex.CameraIndex) == null                || mFilterArrays.get(VideoRenderIndex.DisplayIndex) == null) {            return currentTexture;        }        if (mFilterArrays.get(VideoRenderIndex.CameraIndex) instanceof GLImageOESInputFilter) {            ((GLImageOESInputFilter)mFilterArrays.get(VideoRenderIndex.CameraIndex)).setTextureTransformMatrix(mMatrix);        }        currentTexture = mFilterArrays.get(VideoRenderIndex.CameraIndex)                .drawFrameBuffer(currentTexture, mVertexBuffer, mTextureBuffer);        // 如果处于对比状态,不做处理        if (!mCameraParam.showCompare) {            // 美颜滤镜            if (mFilterArrays.get(VideoRenderIndex.BeautyIndex) != null) {                if (mFilterArrays.get(VideoRenderIndex.BeautyIndex) instanceof IBeautify                        && mCameraParam.beauty != null) {                    ((IBeautify) mFilterArrays.get(VideoRenderIndex.BeautyIndex)).onBeauty(mCameraParam.beauty);                }                currentTexture = mFilterArrays.get(VideoRenderIndex.BeautyIndex).drawFrameBuffer(currentTexture, mVertexBuffer, mTextureBuffer);            }            //LUT 颜色查找表滤镜            if (mFilterArrays.get(VideoRenderIndex.LookupFilterIndex) != null) {                if(mFilterArrays.get(VideoRenderIndex.LookupFilterIndex) instanceof GLImage512TwoInputLookupTableFilter){                    ((GLImage512TwoInputLookupTableFilter) mFilterArrays.get(VideoRenderIndex.LookupFilterIndex)).updateBitmap();                }                currentTexture = mFilterArrays.get(VideoRenderIndex.LookupFilterIndex).drawFrameBuffer(currentTexture, mVertexBuffer, mTextureBuffer);            }        }        // 显示输出,需要调整视口大小        mFilterArrays.get(VideoRenderIndex.DisplayIndex).drawFrame(currentTexture, mDisplayVertexBuffer, mDisplayTextureBuffer);        return currentTexture;    }

其实这里就到了滤镜渲染了。对每帧图片进行了渲染处理。每一个滤镜渲染完交给下一个滤镜渲染达到滤镜组合显示的效果

到此就完成了相机预览画面实时渲染了。

 

更多相关文章

  1. Android多点触控实现图片缩放预览
  2. [置顶] High Performance Canvas Game for Android(高性能Android
  3. 【Android】多图选择器(支持图片预览 高效加载不怕OOM)
  4. Android检查GPU呈现速度和过度绘制
  5. Android(安卓)OpenGLES2.0(十二)——FBO离屏渲染
  6. Skia深入分析9——延迟渲染和显示列表
  7. Android学习-----Android(安卓)Studio 2.0 预览版下载
  8. Android(安卓)实现人脸检测
  9. Android--多媒体

随机推荐

  1. android 常用布局有哪些
  2. Android(安卓)Debug certificate expired
  3. Android横竖屏切换小结
  4. Android(安卓)ellipsize属性(多余文字用
  5. 利用 Android(安卓)Keystore 系统 加密存
  6. android实现服务器图片本地缓存
  7. android ListView 示例1 entries 指定一
  8. Android(安卓)TextView全属性
  9. Android:解决ListView按下后上下滑动背景
  10. Android(安卓)Studio开发基础之AutoCompl