1.0 CameraManage
CameraManager 是一个负责查询和建立相机连接的系统服务,它的功能不多,这里列出几个 CameraManager 的关键功能:
将相机信息封装到 CameraCharacteristics中,并提获取CameraCharacteristics实例的方式。根据指定的相机ID连接相机设备。提供将闪光灯设置成手电筒模式的快捷方式。
CameraManager cameraManager =(CameraManager) getSystemService(CAMERA_SERVICE);
cameraManager.getCameraIdList();
//打开指定相机id 默认打开后置摄像头
for (String id : cameraIdList) {
CameraCharacteristics cameraCharacteristics = cameraManager.getCameraCharacteristics(id);
Integer facing = cameraCharacteristics.get(CameraCharacteristics.LENS_FACING);
if (facing == cameraFacing) {
cameraId = id;
this.cameraCharacteristics = cameraCharacteristics;
}
}
2.0 CameraCharacteristics
描述 CameraDevice的属性,也就是摄像设备的一些信息,比如:帧率,camera方向等信息.并且得到的这些属性是不可变的.
//获取camera的朝向
cameraCharacteristics.get(CameraCharacteristics.SENSOR_ORIENTATION);
//获取camera支持的最大最小尺寸
StreamConfigurationMap streamConfigurationMap = cameraCharacteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
Size[] savePicSize = streamConfigurationMap.getOutputSizes(ImageFormat.JPEG);
Size[] previewSize = streamConfigurationMap.getOutputSizes(SurfaceTexture.class);
3.0 CameraDevice.StateCallback
用于接收有关摄像头设备状态的更新。并在回调当中得到CameraDevice对象,
CameraDevice 代表当前连接的相机设备,并根据指定的参数创建 CameraCaptureSession以及创建 CaptureRequest
cameraManager.openCamera(cameraId, stateCallback, cameraHandler);
CameraDevice.StateCallback stateCallback = new CameraDevice.StateCallback() {
@Override
public void onOpened(@NonNull CameraDevice camera) {
cameraDevice = camera;
createCaptureSession(camera);
}
@Override
public void onDisconnected(@NonNull CameraDevice camera) {
}
@Override
public void onError(@NonNull CameraDevice camera, int error) {
}
};
private void createCaptureSession(CameraDevice camera) {
try {
captureRequestBuilder = cameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
Surface surface = new Surface(txt_view.getSurfaceTexture());
captureRequestBuilder.addTarget(surface);
//加上这一句获取实时帧数据,只是拍照的话可以屏蔽这一句
//captureRequestBuilder.addTarget(imageReader.getSurface());
captureRequestBuilder.set(CaptureRequest.CONTROL_AE_MODE, CaptureRequest.CONTROL_AE_MODE_ON_AUTO_FLASH); // 闪光灯
captureRequestBuilder.set(CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE); // 自动对焦
cameraDevice.createCaptureSession(Arrays.asList(surface, imageReader.getSurface()), createCaptureSession, cameraHandler);
} catch (CameraAccessException e) {
e.printStackTrace();
}
}
4.0 CaptureRequest
CaptureRequest 是向 CameraCaptureSession 提交 Capture
请求时的信息载体,其内部包括了本次 Capture 的参数配置和接收图像数据的
Surface。CaptureRequest 可以配置的信息非常多,包括图像格式、图像分辨率、传感器控制
、闪光灯控制、3A 控制等等,可以说绝大部分的相机参数都是通过
CaptureRequest 配置的。值得注意的是每一个 CaptureRequest
表示一帧画面的操作,这意味着你可以精确控制每一帧的 Capture 操作。
5.0 CameraCaptureSession
置捕获会话CameraDevice,用于从相机捕获图像或重新处理先前在同一会话中
从相机捕获的图像。通过为CameraDevice#createCaptureSession,或为可重
新处理的捕获会话提供目标输出表面提供InputConfiguration一组目标输出表
面, CameraDevice#createReprocessableCaptureSession来创建
CameraCaptureSession。创建会话后,会话将一直处于活动状态,直到摄像头
设备创建新会话或关闭摄像头设备为止。所有捕获会话均可以用于从相机捕获
图像,但是只有可重新处理的捕获会话才能重新处理先前在同一会话中从相机
捕获的图像。
6.0 完整代码
{
rotation = getWindow().getWindowManager().getDefaultDisplay().getRotation();
HandlerThread cameraThread = new HandlerThread("camera_thread");
cameraThread.start();
cameraHandler = new Handler(cameraThread.getLooper());
txt_view.setSurfaceTextureListener(new TextureView.SurfaceTextureListener() {
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
@Override
public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) {
//TODO:初始化相机
try {
surfaceTexture = surface;
initCamera();
} catch (CameraAccessException e) {
e.printStackTrace();
}
}
@Override
public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) {
}
@Override
public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) {
releaseCamera();
return true;
}
@Override
public void onSurfaceTextureUpdated(SurfaceTexture surface) {
}
});
}
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
private void initCamera() throws CameraAccessException {
//获取cameramanage
cameraManager = (CameraManager) getSystemService(CAMERA_SERVICE);
//获取相机idCameraDevice
String[] cameraIdList = getCameraId();
if (cameraIdList == null && cameraIdList.length == 0) {
Log.e("camera", "camera初始化失败");
return;
}
//打开指定相机id 默认打开后置摄像头
for (String id : cameraIdList) {
CameraCharacteristics cameraCharacteristics = cameraManager.getCameraCharacteristics(id);
Integer facing = cameraCharacteristics.get(CameraCharacteristics.LENS_FACING);
if (facing == cameraFacing) {
cameraId = id;
this.cameraCharacteristics = cameraCharacteristics;
}
}
cameraSensorOrientation = cameraCharacteristics.get(CameraCharacteristics.SENSOR_ORIENTATION);
StreamConfigurationMap streamConfigurationMap = cameraCharacteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
Size[] savePicSize = streamConfigurationMap.getOutputSizes(ImageFormat.JPEG);
Size[] previewSize = streamConfigurationMap.getOutputSizes(SurfaceTexture.class);
exchange = exchangeWidthAndHeight(rotation, cameraSensorOrientation);
savePicSizeList = getBestSize(savePicSize, SAVE_MAX_WIDTH, SAVE_MAX_HEIGHT);
previewSizeList = getBestSize(previewSize, PREVIEW_MAX_WIDTH, PREVIEW_MAX_HEIGHT);
surfaceTexture.setDefaultBufferSize(previewSizeList.getWidth(), previewSizeList.getHeight());
imageReader = ImageReader.newInstance(previewSizeList.getWidth(), previewSizeList.getHeight(), ImageFormat.JPEG, 1);
imageReader.setOnImageAvailableListener(onImageAvailableListener, cameraHandler);
if (ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) {
return;
}
cameraManager.openCamera(cameraId, stateCallback, cameraHandler);
}
CameraDevice.StateCallback stateCallback = new CameraDevice.StateCallback() {
@Override
public void onOpened(@NonNull CameraDevice camera) {
cameraDevice = camera;
createCaptureSession(camera);
}
@Override
public void onDisconnected(@NonNull CameraDevice camera) {
}
@Override
public void onError(@NonNull CameraDevice camera, int error) {
}
};
private void createCaptureSession(CameraDevice camera) {
try {
captureRequestBuilder = cameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
Surface surface = new Surface(txt_view.getSurfaceTexture());
captureRequestBuilder.addTarget(surface);
captureRequestBuilder.set(CaptureRequest.CONTROL_AE_MODE, CaptureRequest.CONTROL_AE_MODE_ON_AUTO_FLASH); // 闪光灯
captureRequestBuilder.set(CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE); // 自动对焦
cameraDevice.createCaptureSession(Arrays.asList(surface, imageReader.getSurface()), createCaptureSession, cameraHandler);
} catch (CameraAccessException e) {
e.printStackTrace();
}
}
CameraCaptureSession.StateCallback createCaptureSession = new CameraCaptureSession.StateCallback() {
@Override
public void onConfigured(@NonNull CameraCaptureSession session) {
cameraCaptureSession = session;
try {
session.setRepeatingRequest(captureRequestBuilder.build(), new CameraCaptureSession.CaptureCallback() {
}, cameraHandler);
} catch (CameraAccessException e) {
e.printStackTrace();
}
}
@Override
public void onConfigureFailed(@NonNull CameraCaptureSession session) {
}
};
CameraCaptureSession.CaptureCallback captureCallback = new CameraCaptureSession.CaptureCallback() {
@Override
public void onCaptureCompleted(@NonNull CameraCaptureSession session, @NonNull CaptureRequest request, @NonNull TotalCaptureResult result) {
super.onCaptureCompleted(session, request, result);
canExchangeCamera = true;
canTakePic = true;
}
@Override
public void onCaptureFailed(@NonNull CameraCaptureSession session, @NonNull CaptureRequest request, @NonNull CaptureFailure failure) {
super.onCaptureFailed(session, request, failure);
}
};
ImageReader.OnImageAvailableListener onImageAvailableListener = new ImageReader.OnImageAvailableListener() {
@Override
public void onImageAvailable(ImageReader reader) {
Image image = reader.acquireNextImage();
if (image==null){
return;
}
Log.e(TAG,"拍照回调");
Image.Plane[] planes = image.getPlanes();
ByteBuffer buffer = planes[0].getBuffer();
byte[] imageByte = new byte[buffer.remaining()];
buffer.get(imageByte);
try {
File file = new File(Environment.getExternalStorageDirectory().getPath()+"/camer.jpeg");
Log.e(TAG,Environment.getExternalStorageDirectory().getPath()+"/camer.jepg");
FileOutputStream fileOutputStream = new FileOutputStream(file);
fileOutputStream.write(imageByte);
fileOutputStream.close();
Intent intent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
Uri uri = Uri.fromFile(file);
intent.setData(uri);
MainActivity.this.sendBroadcast(intent);
} catch (Exception e) {
e.printStackTrace();
}
}
};
private Size getBestSize(Size[] previewSize, int maxWidth, int maxHeight) {
float aspectRatio = (float) maxWidth / maxHeight;
List<Size> sizes = new ArrayList<>();
for (Size size : previewSize) {
if ((float) size.getWidth() / size.getHeight() == aspectRatio && size.getWidth() <= maxWidth && size.getHeight() <= maxHeight) {
sizes.add(size);
}
}
return Collections.max(sizes, new Comparator<Size>() {
@Override
public int compare(Size o1, Size o2) {
return o1.getHeight() - o2.getHeight();
}
});
}
private boolean exchangeWidthAndHeight(int rotation, Integer cameraSensorOrientation) {
boolean exchange = false;
switch (rotation) {
case Surface.ROTATION_0:
case Surface.ROTATION_180:
if (cameraSensorOrientation == 90 || cameraSensorOrientation == 270) {
exchange = true;
}
break;
case Surface.ROTATION_90:
case Surface.ROTATION_270:
if (cameraSensorOrientation == 0 || cameraSensorOrientation == 180) {
exchange = true;
}
break;
}
return exchange;
}
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
private String[] getCameraId() {
String[] cameraIdList = null;
try {
cameraIdList = cameraManager.getCameraIdList();
} catch (Exception e) {
e.printStackTrace();
}
return cameraIdList;
}
public void releaseCamera(){
if (cameraCaptureSession!=null){
cameraCaptureSession.close();
cameraCaptureSession = null;
}
if (cameraDevice!=null){
cameraDevice.close();
cameraDevice=null;
}
if (imageReader!=null){
imageReader.close();
imageReader=null;
}
}
@Override
protected void onDestroy() {
super.onDestroy();
releaseCamera();
}
public void takPic() {
if (cameraDevice == null) return;
// 创建拍照需要的CaptureRequest.Builder
final CaptureRequest.Builder captureRequestBuilder;
try {
captureRequestBuilder = cameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE);
// 将imageReader的surface作为CaptureRequest.Builder的目标
captureRequestBuilder.addTarget(imageReader.getSurface());
// 自动对焦
captureRequestBuilder.set(CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE);
// 自动曝光
captureRequestBuilder.set(CaptureRequest.CONTROL_AE_MODE, CaptureRequest.CONTROL_AE_MODE_ON_AUTO_FLASH);
// 获取手机方向
int rotation = getWindowManager().getDefaultDisplay().getRotation();
// 根据设备方向计算设置照片的方向
captureRequestBuilder.set(CaptureRequest.JPEG_ORIENTATION, cameraSensorOrientation);
//拍照
CaptureRequest mCaptureRequest = captureRequestBuilder.build();
cameraCaptureSession.capture(mCaptureRequest, null, cameraHandler);
} catch (CameraAccessException e) {
e.printStackTrace();
}
}
public void changeCamera(View view) {
try {
if (cameraDevice==null||!txt_view.isAvailable()){
return;
}
if (cameraFacing == CameraCharacteristics.LENS_FACING_FRONT){
cameraFacing =CameraCharacteristics.LENS_FACING_BACK;
}else if (cameraFacing == CameraCharacteristics.LENS_FACING_BACK){
cameraFacing =CameraCharacteristics.LENS_FACING_FRONT;
}
releaseCamera();
initCamera();
} catch (CameraAccessException e) {
e.printStackTrace();
}
}