Android 相机回调原始数据解析

首先说明一下,标题中的“相机”指的是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<Integer> 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都可以  
                    }
                });

上面的方式就是内部做了转换。

注:欢迎扫码关注

 

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值