android GPUImage性能升级成纯GPU + GPUImageRenderer解析 (一)

GPUImage 是我滤镜相机的启蒙框架  但是用着用着发现这个框架在相机方面有点慢    opengl不该这么慢的    至于原因一起看GPUImage核心类GPUImageRenderer  

首先我们到这个类先command+f搜一下onPreviewFrame   做过相机的小伙伴都知道这个是相机的回调方法    当新出现一帧图片的时候数据就会返回到第一个参数(byte[] data)里

    @Override
    public void onPreviewFrame(final byte[] data, final Camera camera) {

        final Size previewSize = camera.getParameters().getPreviewSize();
        if (mGLRgbBuffer == null) {
            mGLRgbBuffer = IntBuffer.allocate(previewSize.width * previewSize.height);
        }
        if (mRunOnDraw.isEmpty()) {
            runOnDraw(new Runnable() {
                @Override
                public void run() {
                    GPUImageNativeLibrary.YUVtoRBGA(data, previewSize.width, previewSize.height,
                            mGLRgbBuffer.array());
                    mGLTextureId = OpenGlUtils.loadTexture(mGLRgbBuffer, previewSize, mGLTextureId);
                    camera.addCallbackBuffer(data);
                    if (mImageWidth != previewSize.width) {
                        mImageWidth = previewSize.width;
                        mImageHeight = previewSize.height;
                        adjustImageScaling();
                    }
                }
            });
        }
    }
 

看了这个回调  我们就知道GPUImage做了什么   把每一帧拿出来  拿出来的是YUV格式的图  转化成RBGA的图然后  扔到纹理缓存中  返回一个纹理id就是mGLTextureId 

然后我们搜下一个方法 

    @Override
    public void onDrawFrame(final GL10 gl) {
        。。。
        mFilter.onDraw(mGLTextureId, mGLCubeBuffer, mGLTextureBuffer);
        。。。
    }

这个方法就是GlSurfaceView每次显示新的图片的时候回调的方法  在这里使用了上面的相机每帧图片数据  就是这个纹理mGLTextureId  


好到了这里我发现逻辑很通顺啊   没什么问题    但是我拿着我的红米700元手机就是很卡  没有自带相机快咋办   查了一些资料后我对他作出了优化


先分析问题为什么很卡     应为每一帧图片他都拿了出来在用cpu把YUV转化BGRA的图片  再转成纹理ID给mFiler用  人眼每秒识别24帧  再加上相机分辨率暂定1600*1200 就意味着cpu每秒至少要跑24*1600*1200大小的数组   哪能不慢吗 

接着就是解决方案 

/**
     * 创建OES纹理id
     *
     * @return
     */
    public static int createOESTextureID() {
        final int[] tex = new int[1];
        GLES20.glGenTextures(1, tex, 0);
        GLES20.glBindTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, tex[0]);
        GLES20.glTexParameteri(GLES11Ext.GL_TEXTURE_EXTERNAL_OES,
                GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_CLAMP_TO_EDGE);
        GLES20.glTexParameteri(GLES11Ext.GL_TEXTURE_EXTERNAL_OES,
                GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_CLAMP_TO_EDGE);
        GLES20.glTexParameteri(GLES11Ext.GL_TEXTURE_EXTERNAL_OES,
                GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_NEAREST);
        GLES20.glTexParameteri(GLES11Ext.GL_TEXTURE_EXTERNAL_OES,
                GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_NEAREST);

        return tex[0];
    }

这个纹理属性很关键
GLES11Ext.GL_TEXTURE_EXTERNAL_OES
就是个外部输入设备属性


    public void initCamera(final Camera camera, SurfaceTexture.OnFrameAvailableListener listener) {
        // 生成纹理Id
        mGLTextureId = GLTextureUtil.createOESTextureID();
        mGLTextureIdText = GLTextureUtil.createOESTextureID();

        // 通过纹理Id,创建SurfaceTexture(该mSurfaceTexture与Camera进行绑定)
        mSurfaceTexture = new SurfaceTexture(mGLTextureId);
        mSurfaceTexture.setOnFrameAvailableListener(listener);
        try {
            camera.setPreviewTexture(mSurfaceTexture);
        } catch (IOException e) {
            e.printStackTrace();
        }
        camera.startPreview();
    }

这是我重载的设置Camera的方法   创建个oes的纹理id再生成SurfaceTexture塞给Camera    之后每次新的一帧图片生成就会直接写在这个纹理ID里  不用去cpu再转一次   
setOnFrameAvailableListener
里的listener我这么写的
new SurfaceTexture.OnFrameAvailableListener() {
            @Override
            public void onFrameAvailable(SurfaceTexture surfaceTexture) {
                mGlSurfaceView.requestRender();
            }
        }

就是通知GLSurafecView更新视图


下一章讲OES属性的纹理ID对应的着色器怎么写


最后你的滤镜相机就会快的飞起  

http://blog.csdn.net/u010831488/article/details/71404412

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 8
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值