【笔记】Android5.0前后的Camera和Camera2 预览、拍照、摄像头切换
来源:互联网 发布:局域网协作软件 编辑:程序博客网 时间:2024/06/04 18:43
上篇在做相机桌面的时候用的是5.0之前的Camera,但Camera在5.0之后已经被淘汰了,官方也是推荐使用Camera2,这两天也分别尝试了下Camera和Camera2的使用。
因为新的API换了加购,让开发者用起来更麻烦了。虽然按照官网的说法可能逻辑更加清晰,理解起来也更容易懂了,但是个人使用后的感觉还是觉得太麻烦了。如果仅仅只是拍个照预览下什么的还是乖乖使用Camera吧,用Camera2实在太麻烦。
android6.0之后要动态请求权限,相机使用需要相机权限,拍照保存图片需要文件读写权限。Android6.0之后权限请求工具类
Camera使用
1、打开相机
可传入cameraId来打开前置或后置摄像头
Camera.open()
2、设置预览并取景
用SurfaceView显示预览,由于相机方向是横屏的,需要旋转90度
try { camera.setDisplayOrientation(90); camera.setPreviewDisplay(surfaceHolder); camera.startPreview(); } catch (IOException e) { e.printStackTrace(); }
3、拍照
takePicture第三个参数回调方法是拍照传回来的二进制数据,可以进行图片保存,拍完照之后需要再次打开预览,不然就定格在拍照的画面
camera.takePicture(new Camera.ShutterCallback() { @Override public void onShutter() { //按下快门 } }, new Camera.PictureCallback() { @Override public void onPictureTaken(byte[] data, Camera camera) { } }, new Camera.PictureCallback() { @Override public void onPictureTaken(byte[] data, Camera camera) { savePicture(data); startPreview(camera, surfaceHolder); } });
4、切换摄像头
遍历所有摄像头,前置后置切换,切换前停止预览,再打开相应摄像头
/** * 切换摄像头 */ private void switchCamera() { int count = Camera.getNumberOfCameras(); Camera.CameraInfo cameraInfo = new Camera.CameraInfo(); for (int i = 0; i < count; i++) { Camera.getCameraInfo(i, cameraInfo); if (currentCameraId == Camera.CameraInfo.CAMERA_FACING_BACK && cameraInfo.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) { //后置变前置 stopPreview(); currentCameraId = Camera.CameraInfo.CAMERA_FACING_FRONT; openCamera(); break; } else if (currentCameraId == Camera.CameraInfo.CAMERA_FACING_FRONT && cameraInfo.facing == Camera.CameraInfo.CAMERA_FACING_BACK) { //前置变后置 stopPreview(); currentCameraId = Camera.CameraInfo.CAMERA_FACING_BACK; openCamera(); break; } } }
Camera2使用
Camera2用管道的概念将安卓设备和摄像头之间连通,应用向设备发送请求,设备返回结果,再由应用处理结果。
1、CameraManager
CameraManager是所有CameraDevice的管理者。
CameraManager cameraManager = (CameraManager) getSystemService(Context.CAMERA_SERVICE);
2、打开摄像头
//第一个参数指定哪个摄像头,第二个参数打开摄像头的状态回调,第三个参数是运行在哪个线程(null是当前线程) cameraManager.openCamera(String.valueOf(currentCameraId), stateCallback, handler);打开相机的回调
//打开相机回调 private CameraDevice.StateCallback stateCallback = new CameraDevice.StateCallback() { @Override public void onOpened(@NonNull CameraDevice camera) { Log.i(TAG, "onOpened"); //相机开启,打开预览 cameraDevice = camera; startPreview(); } @Override public void onDisconnected(@NonNull CameraDevice camera) { Log.i(TAG, "onDisconnected"); //相机关闭 camera.close(); cameraDevice = null; } @Override public void onError(@NonNull CameraDevice camera, int error) { Log.i(TAG, "onError"); //相机报错 camera.close(); cameraDevice = null; finish(); } };
3、预览
相机打开后创建CameraBuilder,再创建CameraCaptireSession,最后调用CameraCaptureSession#setRepeatingRequest预览
/** * 开始预览 */ private void startPreview() { try { previewBuilder = cameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW); //设置预览数据输出界面 previewBuilder.addTarget(surfaceHolder.getSurface()); //创建相机捕获会话, //第一个参数是捕获数据的输出Surface列表,第二个参数是CameraCaptureSession状态回调接口,第三个参数是在哪个线程(null是当前线程) cameraDevice.createCaptureSession(Arrays.asList(surfaceHolder.getSurface(), imageReader.getSurface()), sessionStateCallback, handler); } catch (CameraAccessException e) { e.printStackTrace(); } }CameraCaptureSession会话
//创建session回调 private CameraCaptureSession.StateCallback sessionStateCallback = new CameraCaptureSession.StateCallback() { @Override public void onConfigured(@NonNull CameraCaptureSession session) { try { cameraCaptureSession = session; //自动对焦 previewBuilder.set(CaptureRequest.CONTROL_AF_MODE, CameraMetadata.CONTROL_AF_MODE_CONTINUOUS_PICTURE); cameraCaptureSession.setRepeatingRequest(previewBuilder.build(), null, handler); } catch (CameraAccessException e) { e.printStackTrace(); } } @Override public void onConfigureFailed(@NonNull CameraCaptureSession session) { session.close(); cameraCaptureSession = null; cameraDevice.close(); cameraDevice = null; } };
4、拍照
/** * 拍照 */ private void takePhoto() { try { captureBuilder = cameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE); captureBuilder.addTarget(imageReader.getSurface()); //自动对焦 captureBuilder.set(CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE); cameraCaptureSession.stopRepeating(); //拍照 cameraCaptureSession.capture(captureBuilder.build(), captureCallback, handler); } catch (CameraAccessException e) { e.printStackTrace(); } }拍完照后回调,重新打开预览
//拍完照回调 private CameraCaptureSession.CaptureCallback captureCallback = new CameraCaptureSession.CaptureCallback() { @Override public void onCaptureProgressed(@NonNull CameraCaptureSession session, @NonNull CaptureRequest request, @NonNull CaptureResult partialResult) { super.onCaptureProgressed(session, request, partialResult); } @Override public void onCaptureCompleted(@NonNull CameraCaptureSession session, @NonNull CaptureRequest request, @NonNull TotalCaptureResult result) { super.onCaptureCompleted(session, request, result); try { //自动对焦 captureBuilder.set(CaptureRequest.CONTROL_AF_TRIGGER, CaptureRequest.CONTROL_AF_TRIGGER_CANCEL); //重新打开预览 session.setRepeatingRequest(previewBuilder.build(), null, handler); } catch (CameraAccessException e) { e.printStackTrace(); } } @Override public void onCaptureFailed(@NonNull CameraCaptureSession session, @NonNull CaptureRequest request, @NonNull CaptureFailure failure) { super.onCaptureFailed(session, request, failure); cameraCaptureSession.close(); cameraCaptureSession = null; cameraDevice.close(); cameraDevice = null; } };拍照处理器
/** * 初始化拍照处理器 */ private void initImageReader() { imageReader = ImageReader.newInstance(previewSize.getWidth(), previewSize.getHeight(), ImageFormat.JPEG, 1); //监听ImageReader时间,有图像数据可用时回调,参数就是帧数据 imageReader.setOnImageAvailableListener(new ImageReader.OnImageAvailableListener() { @Override public void onImageAvailable(ImageReader reader) { Image image = reader.acquireLatestImage(); //将帧数据转换成字节数组 ByteBuffer byteBuffer = image.getPlanes()[0].getBuffer(); byte[] data = new byte[byteBuffer.remaining()]; byteBuffer.get(data); //保存照片 savePicture(data); image.close(); } }, handler); }
5、切换摄像头
遍历所有cameraId,前置后置互相切换,切换前先关闭CameraDevice,再打开对应摄像头
/** * 切换摄像头 */ private void switchCamera() { try { for (String cameraId : cameraManager.getCameraIdList()) { CameraCharacteristics characteristics = cameraManager.getCameraCharacteristics(cameraId); StreamConfigurationMap map = characteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP); Size maxSize = getMaxSize(map.getOutputSizes(SurfaceHolder.class)); if (currentCameraId == CameraCharacteristics.LENS_FACING_BACK && characteristics.get(CameraCharacteristics.LENS_FACING) == CameraCharacteristics.LENS_FACING_FRONT) { //前置转后置 previewSize = maxSize; currentCameraId = CameraCharacteristics.LENS_FACING_FRONT; cameraDevice.close(); openCamera(); break; } else if (currentCameraId == CameraCharacteristics.LENS_FACING_FRONT && characteristics.get(CameraCharacteristics.LENS_FACING) == CameraCharacteristics.LENS_FACING_BACK) { //后置转前置 previewSize = maxSize; currentCameraId = CameraCharacteristics.LENS_FACING_BACK; cameraDevice.close(); openCamera(); break; } } } catch (CameraAccessException e) { e.printStackTrace(); } }
权限
<uses-permission android:name="android.permission.CAMERA" /> <uses-feature android:name="android.hardware.camera" /> <uses-feature android:name="android.hardware.camera.autofocus" />
简单使用Demo
阅读全文
0 0
- 【笔记】Android5.0前后的Camera和Camera2 预览、拍照、摄像头切换
- Android 实例讲解自定义Camera拍照和预览以及前后置摄像头切换
- Android实例讲解自定义Camera拍照和预览以及前后置摄像头切换
- Camera2.0 控制摄像头拍照
- cocos2d-x嵌入android的camera 实现前后摄像头的预览和保存
- 自定义照相机实现前后切换摄像头以及拍照预览各种问题解决
- Android Camera2 拍照(三)——切换摄像头,延时拍摄和闪光模式
- Camera的前后摄像头调换
- Camera和Camera2的应用
- metlab控制摄像头操作笔记(二)简单的预览和拍照功能
- Android 自定义Camera全屏拍照,支持前后摄像头
- 摄像头拍照功能5.0 Camera2
- android Camera摄像头-Surface view 预览拍照 并将拍的照片插入到系统图库
- Android开发Camera类照相机,前后摄像头切换,分辨率读取和调节
- 【Android】自定义相机的实现(支持连续拍照、前后摄像头切换、连续对焦)
- Camera2.0新API下的摄像头预览、原始图像数据获取等
- Android -- Camera2(Android5.0)
- Android -- Camera2(Android5.0)
- Shader相关知识
- Centos、Debian/Ubuntu系统下搭建SS服务器,超简单的操作
- CodeForces 359A Table
- 栈和队列——设计一个有getMin功能的栈(二)
- hello,world
- 【笔记】Android5.0前后的Camera和Camera2 预览、拍照、摄像头切换
- 详解一个ThreadLocal 的谜题
- CodeFroces 175B. Plane of Tanks: Pro (构造)
- Unity_给滚动视图动态添加子物体_066
- redis-cli远程连接redis-server服务器的问题
- onMeasure的宽高生成解析
- rbd export V2
- Linux下查看二进制文件的工具
- Handle消息机制