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
