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