Android自定義Camera2 拍照,用SurfaceView預覽。

NO IMAGE
  • 佈局檔案不用說了,就它了SurfaceView。其他花裡古哨的佈局,自己想著加吧!
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<SurfaceView
android:id="@ id/surfaceview"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</RelativeLayout>
  • surfaceView的findViewById()的事就不說了,直接開始預覽的程式碼
    //6.0開始
private CameraManager manager;
private Handler childHandler, mainHandler;
private CameraDevice mCamera;
private CaptureRequest.Builder mPreviewBuilder;
private CameraCaptureSession mSession;
private ImageReader mImageReader;
// 建立拍照需要的CaptureRequest.Builder
private CaptureRequest.Builder captureRequestBuilder;
//6.0結束
//很多過程都變成了非同步的了,所以這裡需要一個子執行緒的looper
HandlerThread handlerThread = new HandlerThread("Camera2");
handlerThread.start();
childHandler = new Handler(handlerThread.getLooper());
mainHandler = new Handler(getMainLooper());
manager = (CameraManager) getSystemService(Context.CAMERA_SERVICE);
holder = surfaceView.getHolder();
holder.setKeepScreenOn(true);
holder.addCallback(new SurfaceHolder.Callback() {
@Override
public void surfaceCreated(SurfaceHolder surfaceHolder) {
try {
//需要相機許可權
if (ActivityCompat.checkSelfPermission(getPageContext(), Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) {
return;
}
//獲取可用相機裝置列表
String[] CameraIdList = manager.getCameraIdList();
//開啟相機
manager.openCamera(CameraIdList[0], mCameraDeviceStateCallback, mainHandler);
} catch (CameraAccessException e) {
e.printStackTrace();
}
}
@Override
public void surfaceChanged(SurfaceHolder surfaceHolder, int i, int i1, int i2) {
}
@Override
public void surfaceDestroyed(SurfaceHolder surfaceHolder) {
//釋放資源
if (mCamera != null) {
mCamera.close();
mCamera = null;
}
}
});
//設定照片的大小
mImageReader = ImageReader.newInstance(3264, 1840, ImageFormat.JPEG, 2);
mImageReader.setOnImageAvailableListener(new ImageReader.OnImageAvailableListener() {
@Override
public void onImageAvailable(ImageReader imageReader) {
// 拿到拍照照片資料
Image image = imageReader.acquireNextImage();
ByteBuffer buffer = image.getPlanes()[0].getBuffer();
byte[] bytes = new byte[buffer.remaining()];
buffer.get(bytes);//由緩衝區存入位元組陣列
image.close();
//saveBitmap(bytes);//儲存照片的處理
}
}, mainHandler);
/**
* 攝像頭建立監聽
*/
private CameraDevice.StateCallback mCameraDeviceStateCallback = new CameraDevice.StateCallback() {
@Override
public void onOpened(CameraDevice camera) {//開啟攝像頭
try {
//開啟預覽
mCamera = camera;
startPreview(camera);
} catch (CameraAccessException e) {
e.printStackTrace();
}
}
@Override
public void onDisconnected(CameraDevice camera) {
//關閉攝像頭
if (mCamera != null) {
mCamera.close();
mCamera = null;
}
}
@Override
public void onError(CameraDevice camera, int error) {
//發生錯誤
}
};
//開始預覽,主要是camera.createCaptureSession這段程式碼很重要,建立會話
private void startPreview(final CameraDevice camera) throws CameraAccessException {
try {
// 建立預覽需要的CaptureRequest.Builder
mPreviewBuilder = camera.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
// 將SurfaceView的surface作為CaptureRequest.Builder的目標
mPreviewBuilder.addTarget(holder.getSurface());
mPreviewBuilder.set(CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_MODE_OFF);
mPreviewBuilder.set(CaptureRequest.CONTROL_AE_MODE, CaptureRequest.CONTROL_AE_MODE_OFF);
//設定拍攝影象時相機裝置是否使用光學防抖(OIS)。
mPreviewBuilder.set(CaptureRequest.LENS_OPTICAL_STABILIZATION_MODE, CaptureRequest.LENS_OPTICAL_STABILIZATION_MODE_ON);
//感光靈敏度
mPreviewBuilder.set(CaptureRequest.SENSOR_SENSITIVITY, 1600);
//曝光補償//
mPreviewBuilder.set(CaptureRequest.CONTROL_AE_EXPOSURE_COMPENSATION, 0);
// 建立CameraCaptureSession,該物件負責管理處理預覽請求和拍照請求
camera.createCaptureSession(Arrays.asList(holder.getSurface(), mImageReader.getSurface()), mSessionStateCallback, childHandler);
} catch (CameraAccessException e) {
e.printStackTrace();
}
}
/**
* 會話狀態回撥
*/
private CameraCaptureSession.StateCallback mSessionStateCallback = new CameraCaptureSession.StateCallback() {
@Override
public void onConfigured(CameraCaptureSession session) {
mSession = session;
if (mCamera != null && captureRequestBuilder == null) {
try {
captureRequestBuilder = mCamera.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE);
// 將imageReader的surface作為CaptureRequest.Builder的目標
captureRequestBuilder.addTarget(mImageReader.getSurface());
//關閉自動對焦
captureRequestBuilder.set(CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_MODE_OFF);
captureRequestBuilder.set(CaptureRequest.CONTROL_AE_MODE, CaptureRequest.CONTROL_AE_MODE_OFF);
//設定拍攝影象時相機裝置是否使用光學防抖(OIS)。
captureRequestBuilder.set(CaptureRequest.LENS_OPTICAL_STABILIZATION_MODE, CaptureRequest.LENS_OPTICAL_STABILIZATION_MODE_ON);
captureRequestBuilder.set(CaptureRequest.SENSOR_SENSITIVITY, valueISO);
//曝光補償//
captureRequestBuilder.set(CaptureRequest.CONTROL_AE_EXPOSURE_COMPENSATION, 0);
} catch (CameraAccessException e) {
e.printStackTrace();
}
}
try {
updatePreview(session);
} catch (CameraAccessException e) {
e.printStackTrace();
}
}
@Override
public void onConfigureFailed(CameraCaptureSession session) {
}
};
/**
* 更新會話,開啟預覽
*
* @param session
* @throws CameraAccessException
*/
private void updatePreview(CameraCaptureSession session) throws CameraAccessException {
session.setRepeatingRequest(mPreviewBuilder.build(), mCaptureCallback, childHandler);
}
  • 預覽已經OK了。簡單至極吧。
  • 下面是一個camera拍照的方法:
    /**
* 單拍照片
*/
private void takePicture() {
if (mCamera == null) {
return;
}
if (mSession != null && captureRequestBuilder != null) {
//拍照
try {
CaptureRequest cr = captureRequestBuilder.build();
mSession.capture(cr, null, null);//單拍API,也可以調連拍的哦
} catch (CameraAccessException e) {
e.printStackTrace();
}
}
}
  • OK拍照也可以了,再來就是單獨控制閃光燈的開啟和關閉了
/**
* 6.0開
*/
public void openLight6() {
try {
mPreviewBuilder.set(CaptureRequest.FLASH_MODE,
CaptureRequest.FLASH_MODE_TORCH);
updatePreview(mSession);
} catch (CameraAccessException e) {
e.printStackTrace();
}
}
/**
* 6.0關
*/
public void closeLight6() {
try {
mPreviewBuilder.set(CaptureRequest.FLASH_MODE,
CaptureRequest.FLASH_MODE_OFF);
updatePreview(mSession);
} catch (CameraAccessException e) {
e.printStackTrace();
}
}
  • OK,自定義camera2 拍照預覽就完成了。