Android自定义Camera2 拍照,用SurfaceView预览。

  • 布局文件不用说了,就它了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);
    }

    private CameraCaptureSession.CaptureCallback mCaptureCallback = new CameraCaptureSession.CaptureCallback() {
        @Override
        public void onCaptureCompleted(@NonNull CameraCaptureSession session, @NonNull CaptureRequest request, @NonNull TotalCaptureResult result) {
            super.onCaptureCompleted(session, request, result);
            //需要连拍时,循环保存图片就可以了
        }
    };
  • 预览已经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 拍照预览就完成了。
  • 1
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 5
    评论
### 回答1: 使用 camera2 API 可以更加灵活、可定制和高效地完成 Android 相机应用开发,其相比 camera1 API 的性能有大幅提升。 在使用 camera2 API 完成预览拍照前,需要进行以下几个步骤: 1. 获取 CameraManager 对象,查找可用的摄像头列表,并选择需要打开的摄像头。 2. 创建 CameraCaptureSession 对象,用于处理相机触发器的请求,并连接 CameraDevice 和 Surface。 3. 匹配预览和图片输出的 Surface,设置相应的尺寸和格式。 4. 创建 CaptureRequest 对象,设置相应的参数,如自动对焦模式、曝光模式等。 5. 使用 CameraCaptureSession 进行预览拍照。 在预览时,可以使用 TextureView 或 SurfaceView 进行实时数据渲染,比如显示相机预览画面、拍照后处理和显示等,同时可以通过设置监听器动态获取相机输出的图像流数据。 在拍照时,需要创建 ImageReader 对象,设置输出数据的格式和尺寸,同时需要建立对应的 Surface,将其传入 CaptureRequest.Builder,设置请求类型并发起拍照请求。通过设置 ImageReader 的 OnImageAvailableListener 接口,即可接收到图片数据,并进行后续处理和保存。 以上是使用 camera2 API 完成预览拍照的基本流程,实际开发中需要根据具体需求进行优化和调整。 ### 回答2: Android Camera2 API 是 Android 系统中相机功能的一种全新的 API,使用 Camera2 可以更灵活地操作相机设备并获得更高质量的照片。 使用 Camera2 实现预览非常简单,我们只需要实现一个 CameraDevice.StateCallback 接口实现类和一个 SurfaceView 主界面。在 StateCallback 的 onOpened 回调中获得 CameraDevice 的实例,然后通过 ImageReader 创建 SurfaceHolder,最后将 SurfaceHolder 通过 CameraDevice.createCaptureSession 接口跟 CameraDevice 进行绑定即可实现预览拍照实现过程与预览类似,首先获得 CameraDevice 实例,然后创建一个 CaptureRequest.Builder 对象,将拍照设置参数通过 CaptureRequest.Builder.set 方法设置到 CaptureRequest.Builder 对象中,最后通过 CameraCaptureSession.capture 接口启动拍照操作即可。 当然,在使用 Camera2 API 进行操作相机时,还需要注意一些其他问题,比如不同的相机设备有不同的特性,需要针对不同的设备进行优化和适配,还需要保证应用的流畅性和稳定性,以达到更好的用户体验。 总之,使用 Camera2 API 实现预览拍照Android 开发的一个重要技能,需要开发者深入了解该 API 的机制和使用方式,才能更好地实现优秀的相机应用。 ### 回答3: Android中的camera2是一种相机应用程序接口(API),旨在提高相机应用程序的功能和性能。相较于早期版本的camera API,camera2 API提供了更多的控制选项,允许开发者定制相机应用程序的功能,从而实现更好的用户体验。 使用camera2 API实现预览拍照需要以下步骤: 1. 获取CameraManager对象。使用该对象可以获取系统中可用的相机列表,并在需要的时候打开指定相机。 2. 打开指定相机。调用CameraManager.openCamera()方法打开相机。 3. 创建CaptureSession。CaptureSession是与相机关联的一组输出Surface的集合。 4. 创建CaptureRequest。CaptureRequest是一个指定相机操作和设置的重要对象,可以通过它来设置各种模式、参数和目标Surface。 5. 创建Preview Request。处理预览界面。 6. 启动相机预览。启动前,可以使用CaptureRequest.Builder设置其他预览参数。 7. 拍照。当用户点击拍照按钮时,调用CaptureSession.capture()方法,即可拍照并接收回调。 8. 关闭相机。释放所有占用的资源,以便其他应用程序可以使用相机。 总之,在使用camera2 API实现预览拍照时,需要使用许多类和方法。但只要开发者掌握了API中的基本概念和流程,就可以自由地使用该API,设计新型的相机应用程序,提供更好的功能和性能。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

帅气的铅笔

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值