作者:_小河馬
連結:http://www.jianshu.com/p/73fed068a795
本文由作者投稿。
最近在做自定義相機相關的項目,網上查了資料都是有關android.hardware.Camera的資料,開始使用的才發現這個類已經廢棄了。Camera2主要的類說明
CameraManager:攝像頭管理器。這是一個全新的系統管理器,專門用於檢測系統攝像頭、打開系統攝像頭。除此之外,調用CameraManager的getCameraCharacteristics(String)方法即可獲取指定攝像頭的相關特性。
CameraCharacteristics:攝像頭特性。該對象通過CameraManager來獲取,用於描述特定攝像頭所支持的各種特性。
CameraDevice:代表系統攝像頭。該類的功能類似於早期的Camera類。
CameraCaptureSession:這是一個非常重要的API,當程序需要預覽、拍照時,都需要先通過該類的實例創建Session。而且不管預覽還是拍照,也都是由該對象的方法進行控制的,其中控制預覽的方法為setRepeatingRequest();控制拍照的方法為capture()。
CameraRequest和CameraRequest.Builder:當程序調用setRepeatingRequest()方法進行預覽時,或調用capture()方法進行拍照時,都需要傳入CameraRequest參數。CameraRequest代表了一次捕獲請求,用於描述捕獲圖片的各種參數設置,比如對焦模式、曝光模式……總之,程序需要對照片所做的各種控制,都通過CameraRequest參數進行設置。CameraRequest.Builder則負責生成CameraRequest對象。
開啟相機請一定添加相關的相機權限,判斷6.0以後添加動態權限的獲取。如果相機預覽出現黑屏多半就是因為沒有相機權限而導致的
<uses-permission android:name="android.permission.CAMERA" /><uses-feature android:name="android.hardware.camera" /><uses-feature android:name="android.hardware.camera.autofocus" />
首頁我們要設置相機相關的參數
通過getSystemService(Context.CAMERA_SERVICE);拿到了CameraManager 返回當前可用的相機列表,在這裡你可以選擇使用前置還是後置攝像頭。
CameraCharacteristics characteristics = manager.getCameraCharacteristics(cameraId);可以拿到當前相機的相關參數,在這裡你可以進行相關的參數檢查,例如檢查閃光燈是否支持等。在這裡我們拿到當前相機的cameraId後面使用。
拿到cameraId我們就可以調用CameraManager的openCamera(String cameraId, CameraDevice.StateCallback callback, Handler handler)打開相機了
添加 CameraDevice.StateCallback 監聽我們需要對相機狀態就行監聽,以便在相機狀態發生改變的時候做相應的操作。openCamera(String cameraId, CameraDevice.StateCallback callback, Handler handler)中CameraDevice.StateCallback就是對相機的狀態改變的Callback
創建 CameraCaptureSession在onOpened()中我們可以拿到CameraDevice對象,在相機打開後需要創建CameraCaptureSession。
CameraCaptureSession是什麼呢?由於Camera2是一套全新的API,所以它引用了管道的概念將安卓設備和攝像頭之間聯通起來,系統向攝像頭髮送 Capture 請求,而攝像頭會返回 CameraMetadata。這一切建立在一個叫作 CameraCaptureSession的會話中。如下圖:
圖片來自http://wiki.jikexueyuan.com/project/android-actual-combat-skills/android-hardware-camera2-operating-guide.html
這裡我們需要預覽相機的內容就需要創建CameraCaptureSession向相機發送Capture請求預覽相機內容
首先我們創建了一個CaptureRequest 上面說過了我們需要跟相機通信只有通過CameraCaptureSession。而要和CameraCaptureSession通信就是發送請求。這裡我們相當於在創建請求的一些參數。
createCaptureRequest(int); 也有很多參數可選。
這裡我們發送的是CameraDevice.TEMPLATE_PREVIEW也就是告訴相機我們只需要預覽。更多參數如下:
TEMPLATE_RECORD 創建適合錄像的請求。
TEMPLATE_PREVIEW 創建一個適合於相機預覽窗口的請求。
TEMPLATE_STILL_CAPTURE 創建適用於靜態圖像捕獲的請求
TEMPLATE_VIDEO_SNAPSHOT 在錄製視頻時創建適合靜態圖像捕獲的請求。
詳細信息可以參考官網的API文檔。
調用創建方法createCaptureSession(List<Surface> outputs, CameraCaptureSession.StateCallback callback, Handler handler) 第一參數就是我們需要輸出到的Surface列表,這裡我們可以輸出到一個SurfaceView中或者TextureView中。
第二參數是對創建過程的一個回調方法,當onConfigured回調的時候說明CameraCaptureSession創建成功了。
現在我們可以向CameraCaptureSession發送前面創建的好的預覽相機請求了。調用mCaptureSession.setRepeatingRequest(mPreviewRequest,null, mBackgroundHandler); 這樣我們就開啟的相機的預覽,在剛才添加的輸出Surface對應的控制項中我們可以看到攝像頭的預覽內容了。
當我們需要拍照並且得到相應的照片數據的時候和開啟相機預覽相同的操作,我們只需要向CameraCaptureSession發送我們創建好的請求就行,就像我們請求網絡數據一樣,封裝好參數直接告訴CameraCaptureSession需要做什麼由它去和相機建立通信並執行相應的操作。
對焦對焦完成後我們就可以向CameraCaptureSession發送請求可以拍照了
相信看到這裡代碼已經不複雜了,組裝好我們的請求然後用CameraCaptureSession發送這個請求就可以了。
這裡需要注意的是我們怎麼拿到圖片數據呢? 這裡要說回在創建CameraCaptureSession時參數不是有一個輸出的Surface列表麼,在列表中添加一個ImageReader的Surface用戶獲取圖片數據
mCameraDevice .createCaptureSession( Arrays.asList(surface, mImageReader.getSurface()),null)
在ImageReader中對圖片獲取就行監聽
調用reader.acquireNextImage()我們就可以拿到當前的圖片數據了。拍完後我們需要解鎖焦點讓相機回到預覽狀態,同樣的我們發送請求就可以了
效果
之前看了鴻神推送的Android 仿火螢視頻桌面 神奇的LiveWallPaper 一文中提到了用相機來做壁紙也就是透明屏幕,項目地址https://github.com/songixan/Wallpaper 查看源碼發現還是用的舊的CameraAPI,所以我在Demo中用Camera2API做了透明屏幕,有興趣的可以去看下。
PS:後來在同事的小米2S(5.1.1)中測試發現出錯了,初步猜測是解析度的原因,目前正在解決中。有問題大家可以私信我 謝謝~
到此Camera2的學習就結束了,同樣的如果你想用相機就行拍攝視頻也是如此,用CameraCaptureSession發送相應的請求了就可以了,大家有興趣可以做一做視頻的拍攝。現在做微信的小10秒小視頻拍攝也很簡單了,思路很簡單當用戶按下拍攝按鈕用CameraCaptureSession發送拍攝視頻的請求,鬆開手指的時候相機恢復到預覽狀態。so easy~ 大家有興趣可以嘗試下。如果你有想學習的文章直接留言,我會整理徵稿。如果你有好的文章想和大家分享歡迎投稿,直接向我投遞文章連結即可。
歡迎長按下圖->識別圖中二維碼或者掃一掃關注我的公眾號: