Android -- Camera2(Android5.0)
Android -- Camera2(Android5.0)
Camera2
Camera2是Android5.0中的其中一個新的特性,新的API。與原來的camera API相比,不同之處在於:
原生支援RAW照片輸出突發拍攝模式
制約拍照速度的不再是軟體而是硬體。以Nexus 5為例,解析度全開下Andorid L的連拍速度可達到30fps。
全手動控制
快門、感光度、對焦、測光、硬體視頻防抖等多種參數都被整合到了新的API內。新的API中添加的手動控制功能列表:
感光度手動對焦/AF開關AE/AF/AWB模式AE/AWB鎖硬體視頻防抖連續幀乾貨
Camera2 程式邏輯與原Camera有很大不同。
CameraManager,系統服務,通過 CameraManager去獲得camera裝置對象。CameraDevices提供描述相機硬體裝置支援可用的和輸出的參數,這些資訊通過 CameraCharacteristics獲得,CameraCharacteristics又是從 getCameraCharacteristics(cameraId)獲得,通過freamwork中的源碼發現,其實這裡就是直接調用的Camera API介面。
通過camera拍照,應用首先要建立由相機裝置的輸出surface組成的拍照會話,createCaptureSession(List, CameraCaptureSession.StateCallback, Handler)。每個surface必須預先設定適當的大小和格式去匹配相機裝置的可支援的大小和格式。一個目標surface可以從不同的類中擷取,包括SurfaceView,SurfaceTexture via Surface(SurfaceTexture), MediaCodec, MediaRecorder, Allocation, and ImageReader.
一旦請求被建立,他可以交給活動的拍照會話:一次拍照(one-shot )或者無止境連續拍照或預覽(Repeating)。兩種方法都有一個其他的方式:接受一系列的請求作為burst拍照/重複burst。
public void openCamera (String cameraId, CameraDevice.StateCallback callback, Handler handler)
使用getCameraIdList()來獲得可用攝像裝置的列表。一旦成功開啟相機,CameraDevice.StateCallback中的onOpened(CameraDevice)將被調用。相機裝置可以通過調用createCaptureSession()和createCaptureRequest()去設定作業。如果開啟相機裝置失敗,那麼裝置回調的onError方法將被調用,和後續調用相機裝置將拋出一個CameraAccessException。
public abstract CaptureRequest.Builder createCaptureRequest (int templateType)
為請求拍照建立一個CaptureRequest.Builder,初始化目標用例的模板。選擇最好的設定為特定的相機裝置,所以不建議為不同的相機裝置重用相同的請求,建立一個builder為具體的裝置和模板和根據需要覆蓋的設定。
public abstract void createCaptureSession (List outputs, CameraCaptureSession.StateCallback callback, Handler handler)
活動著的會話決定了相機的output Surfaces 為每個拍照的要求。給定請求可以使用全部或只有部分的output Surfaces。一旦CameraCaptureSession建立,可以提交capture請求、captureBurst請求,setRepeatingRequest請求或setRepeatingBurst請求。
許可權
布局
核心代碼
public class CameraFragment extends Fragment implements TextureView.SurfaceTextureListener { private TextureView mPreviewView; private Handler mHandler; private HandlerThread mThreadHandler; private Size mPreviewSize; private CaptureRequest.Builder mPreviewBuilder; public static CameraFragment newInstance() { return new CameraFragment(); } @SuppressWarnings(ResourceType) @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View v = inflater.inflate(R.layout.camera_frag, null); initLooper(); initUIAndListener(v); return v; } //很多過程都變成了非同步了,所以這裡需要一個子線程的looper private void initLooper() { mThreadHandler = new HandlerThread(CAMERA2); mThreadHandler.start(); mHandler = new Handler(mThreadHandler.getLooper()); } //可以通過TextureView或者SurfaceView private void initUIAndListener(View v) { mPreviewView = (TextureView) v.findViewById(R.id.textureview); mPreviewView.setSurfaceTextureListener(this); } @SuppressWarnings(ResourceType) @Override public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) { try { //獲得CameraManager CameraManager cameraManager = (CameraManager) getActivity().getSystemService(Context.CAMERA_SERVICE); //獲得屬性 CameraCharacteristics characteristics = cameraManager.getCameraCharacteristics(0); //支援的STREAM CONFIGURATION StreamConfigurationMap map = characteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP); //顯示的size mPreviewSize = map.getOutputSizes(SurfaceTexture.class)[0]; //開啟相機 cameraManager.openCamera(0, mCameraDeviceStateCallback, mHandler); } catch (CameraAccessException e) { e.printStackTrace(); } } @Override public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) { } @Override public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) { return false; } //TextureView.SurfaceTextureListener @Override public void onSurfaceTextureUpdated(SurfaceTexture surface) { } private CameraDevice.StateCallback mCameraDeviceStateCallback = new CameraDevice.StateCallback() { @Override public void onOpened(CameraDevice camera) { try { startPreview(camera); } catch (CameraAccessException e) { e.printStackTrace(); } } @Override public void onDisconnected(CameraDevice camera) { } @Override public void onError(CameraDevice camera, int error) { } }; //開始預覽,主要是camera.createCaptureSession這段代碼很重要,建立會話 private void startPreview(CameraDevice camera) throws CameraAccessException { SurfaceTexture texture = mPreviewView.getSurfaceTexture(); texture.setDefaultBufferSize(mPreviewSize.getWidth(), mPreviewSize.getHeight()); Surface surface = new Surface(texture); try { mPreviewBuilder = camera.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW); } catch (CameraAccessException e) { e.printStackTrace(); } mPreviewBuilder.addTarget(surface); camera.createCaptureSession(Arrays.asList(surface), mSessionStateCallback, mHandler); } private CameraCaptureSession.StateCallback mSessionStateCallback = new CameraCaptureSession.StateCallback() { @Override public void onConfigured(CameraCaptureSession session) { try { updatePreview(session); } catch (CameraAccessException e) { e.printStackTrace(); } } @Override public void onConfigureFailed(CameraCaptureSession session) { } }; private void updatePreview(CameraCaptureSession session) throws CameraAccessException { session.setRepeatingRequest(mPreviewBuilder.build(), null, mHandler); }}