【笔记】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
原创粉丝点击