首先说明一下,标题中的“相机”指的是Android原生接口Camera,“回调数据”指的是通过对Camera实例设置预览回调获取的数据:
camera.setPreviewCallback(new Camera.PreviewCallback() {
@Override
public void onPreviewFrame(byte[] data, Camera camera) {
}
});
“解析”是指这里的byte[]数据无法直接保存为图片供我们使用,所以需要转码为我们常用的图片编码数据。这里先给出方法,再说明原因
YuvImage image = new YuvImage(data, ImageFormat.NV21, width, height, null);
ByteArrayOutputStream stream = new ByteArrayOutputStream();
image.compressToJpeg(new Rect(0, 0, width, height), value, stream);
byte[] newData=stream.toByteArray();
注:上述中的data就是回调的原始数据,newData就是转换后的数据。宽高对应为预览的宽高数据,value是图片质量数值;这样转换之后就可以通过新的数据进行各种操作,保存为图片,转为bitmap等等。
下面说明一下原因,可以选择不看;我们知道,Camera在使用的时候,我们可以通过获取Camera中的支持的各种参数用于我们的个性化设置:
Camera.Parameters params = mCamera.getParameters();
我们从params中可以读取当前Camera支持的预览尺寸列表,预览格式,拍照格式,闪光灯模式,白平衡,颜色效果等等,如:
params.getSupportedPictureFormats();
params.getSupportedPreviewFormats();
params.getColorEffect();
params.getWhiteBalance();
params.getFlashMode();
.........
ok,我们重点关注数据类型,我们知道上面的原始数据来源于预览回调,所以我们重点查看Camera支持的预览数据格式,也即:
List list = params.getSupportedPreviewFormats();
返回的是一个List列表,其中的元素是整形,其中的数值对应到ImageFormat类中定义的常量,我们调用上述方法可以查看当前摄像头支持的预览数据格式,可以通过下面的接口方法修改摄像头支持的预览格式:
params.setPreviewFormat(ImageFormat.NV21);
mCamera.setParameters(params);
默认的格式就是NV21的,因为基本所以摄像头都支持该种格式,我们这个时候再回到上面的处理逻辑上:
YuvImage image = new YuvImage(data, ImageFormat.NV21, width, height, null);
这里的YuvImage API专门用于处理YUV编码的数据,我们先看一下文档介绍:
* YuvImage contains YUV data and provides a method that compresses a region of * the YUV data to a Jpeg. The YUV data should be provided as a single byte * array irrespective of the number of image planes in it. * Currently only ImageFormat.NV21 and ImageFormat.YUY2 are supported.YuvImage内部包含有YUV编码数据,并且提供方法把这种转换为一张Jpeg图片。目前只支持ImageFormat.NV21与ImageFormat.YUY2类型的YUV数据
我们知道YUV编码指的是一个类别,其中有很多种颜色编码格式,主要用于视频处理上,关于这块可以自行百度一下。上述通过预览的元素数据以及预览的宽高和格式就可以构建出一个YuvImage实例,我们在上面的文档中了解到,这个类中提供了把YUV数据转换为Jpeg图片的方法:
image.compressToJpeg(new Rect(0, 0, width, height), value, stream);
这个就实现了原始YUV数据到图片数据流的转换功能。其实到这里我们一直有一个疑惑,那就是我们可以把byte[]数据通过BitmapFactory中接口直接转为Bitmap数据,或者直接把原始的YUV数据data写到图片文件中,实际上这样操作的结果就是下列接口获取的Bitmap为空,图片文件也不能正常使用:
Bitmap bitmap = BitmapFactory.decodeByteArray(data, 0, data.length);
private void bytesToImageFile(byte[] data) {
try {
File file = new File(Environment.getExternalStorageDirectory().getAbsolutePath() + "/why.jpeg");
FileOutputStream fos = new FileOutputStream(file);
fos.write(data, 0, bytes.length);
fos.flush();
fos.close();
} catch (Exception e) {
e.printStackTrace();
}
主要原因还是编码的问题,就好比是写了一篇作文,转化为16进制字符串保存为文件传给你的老师,他在没有转码的情况下觉得你的作文有问题;或者我用base64对其解码肯定也是不行的。本篇内容其实很单薄也很简单,但是在不了解的情况下还是会遇到这样的问题,一般遇到之后我们都会搜索byte[]数据与Bitmap,File等等之间的转换实现,但是在原始数据不转码的情况下,网上的工具类方法都是无法使用的。其实这里还有一种方法获取JPEG的byte数据,那就是通过回调回来的Camera的takePicture()接口实现:
camera.takePicture(new Camera.ShutterCallback() {
@Override
public void onShutter() {
}
}, new Camera.PictureCallback() {
@Override
public void onPictureTaken(byte[] data, Camera camera) {
//data和预览的data一样
}
}, new Camera.PictureCallback() {
@Override
public void onPictureTaken(byte[] data, Camera camera) {
//data可以直接保存jpeg类型图片或者转为Bitmap都可以
}
});
上面的方式就是内部做了转换。
注:欢迎扫码关注