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都可以  
                    }
                });

上面的方式就是內部做了轉換。

注:歡迎掃碼關注

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章