好的,有几种方法可以做到这一点。但是性能方面存在重大问题。来自相机的 byte[] 位于 YUV format 中,如果要显示它,必须将其转换为某种 RGB 格式。这种转换是非常昂贵的操作,并且会显着降低输出 fps。
这取决于您对相机预览的实际操作。因为最好的解决方案是在没有回调的情况下绘制相机预览,并在相机预览上做一些效果。这是处理有争议的现实事物的常用方法。
但如果您真的需要手动显示输出,有几种方法可以做到这一点。您的示例不起作用有几个原因。首先,您根本没有显示图像。如果你这样称呼:
mCamera.setPreviewCallback(new CameraGreenFilter());
mCamera.setPreviewDisplay(null);
您的相机根本不显示预览,您必须手动显示。而且你不能在 onPreviewFrame 方法中做任何昂贵的操作,因为数据的生命周期是有限的,它会在下一帧被覆盖。一个提示,使用setPreviewCallbackWithBuffer,它更快,因为它重用一个缓冲区并且不必在每一帧上分配新内存。
所以你必须这样做:
private byte[] cameraFrame;
private byte[] buffer;
@Override
public void onPreviewFrame(byte[] data, Camera camera) {
cameraFrame = data;
addCallbackBuffer(data); //actually, addCallbackBuffer(buffer) has to be called once sowhere before you call mCamera.startPreview();
}
private ByteOutputStream baos;
private YuvImage yuvimage;
private byte[] jdata;
private Bitmap bmp;
private Paint paint;
@Override //from SurfaceView
public void onDraw(Canvas canvas) {
baos = new ByteOutputStream();
yuvimage=new YuvImage(cameraFrame, ImageFormat.NV21, prevX, prevY, null);
yuvimage.compressToJpeg(new Rect(0, 0, width, height), 80, baos); //width and height of the screen
jdata = baos.toByteArray();
bmp = BitmapFactory.decodeByteArray(jdata, 0, jdata.length);
canvas.drawBitmap(bmp , 0, 0, paint);
invalidate(); //to call ondraw again
}
要完成这项工作,您需要在类构造函数或其他地方调用setWillNotDraw(false)。
在 onDraw 中,如果您想修改颜色,例如可以应用 paint.setColorFilter(filter)。如果你愿意,我可以发布一些例子。
所以这会起作用,但性能会很低(低于 8fps),因为 BitmapFactory.decodeByteArray 很慢。你可以尝试使用native code和android NDK将数据从YUV转换为RGB,但这相当复杂。
另一种选择是使用 openGL ES。您需要 GLSurfaceView,在其中将相机帧绑定为纹理(在 GLSurfaceView 中实现 Camera.previewCallback,因此您使用 onPreviewFrame 的方式与常规表面相同)。但是有同样的问题,需要转换 YUV 数据。有一次机会 - 您可以非常快速地仅显示预览(灰度图像)中的亮度数据,因为 YUV 中字节数组的前半部分只是没有颜色的亮度数据。因此,在 onPreviewFrame 上,您使用 arraycopy 复制数组的前半部分,然后像这样绑定纹理:
gl.glGenTextures(1, cameraTexture, 0);
int tex = cameraTexture[0];
gl.glBindTexture(GL10.GL_TEXTURE_2D, tex);
gl.glTexImage2D(GL10.GL_TEXTURE_2D, 0, GL10.GL_LUMINANCE,
this.prevX, this.prevY, 0, GL10.GL_LUMINANCE,
GL10.GL_UNSIGNED_BYTE, ByteBuffer.wrap(this.cameraFrame)); //cameraFrame is the first half od byte[] from onPreviewFrame
gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MIN_FILTER, GL10.GL_LINEAR);
您无法通过这种方式获得大约 16-18 fps,您可以使用 openGL 制作一些过滤器。如果您愿意,我可以向您发送更多代码,但这里太长了...
更多信息,你可以看我的simillar question,但也没有好的解决方案...