首先說明一下,標題中的“相機”指的是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都可以
}
});
上面的方式就是內部做了轉換。
注:歡迎掃碼關注