好的,有几种方法可以做到这一点。但是,性能存在重大问题。如果您想显示它,则来自相机的字节[]位于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是缓慢的。您可以尝试使用本地代码和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,但是没有一个好的解决方案...
你说YUV数据需要转换为RGB数据才能显示,这会给出8fps左右。什么是Android框架如何获得如此高的显示速度(不应用过滤器)?你认为他们正在包装所有的东西来打开GL ES以获得接近20帧/秒的速度吗? :) – poitroae
更可能的是,他们没有使用Android API :)它可能是用本地代码或类似的东西编写的(这只是猜测)......但Android是开源的,因此您可以尝试查找代码的实际内容作品:) –
Jaa-c,我想知道是否可以使用上面编写的代码发布示例(不是openGL)。我无法弄清楚如何将它们全部加在一起才能正确工作,并且我知道这是一个较老的问题,但我在Google上找不到这件事。或者你可以制作一个迷你教程,说明为实现这个目的需要制作哪些类? –