Android camera2 同时打开两颗物理摄像头

因业务需求,需要同时打开两颗物理摄像头。 从Camera2 api来看 SdkVersion 28 以后已经支持此功能。 但是不得不说api文档不友好,又或者说我实在是菜。

先来一张 这个我也不知道叫什么的  Camera2 的结构图吧。

 从这张图中,我们需要知道的其实就是  HAL层中的 Camera0,Camera1......是什么,又包含了什么。从官方的文档中,可以理解为

这些Camera 为逻辑摄像头。 什么是逻辑摄像头?   那就是软件层面的摄像头。  无论你的物理摄像头(手机上真实的摄像头)是什么样 你不需要考虑, 反正你拿到的只是这个逻辑摄像头。  

问题就来了  我现在要同时打开两颗物理摄像头啊 , 给我一堆逻辑摄像头有什么用?

不急 。。 继续讲。。

这个逻辑摄像头是对物理摄像头的封装。 意思就是  这个逻辑摄像头中会包含一个 或者多个物理摄像头。摄像头客户端可以通过调用 getPhysicalCameraIds() 就可以得到这颗逻辑摄像头下的物理摄像头(当然,也可能没有,也就是不提供)。  当这个getPhysicalCameraIds()返回的物理摄像头Id个数大于2  也就是这个逻辑摄像头下有两颗以上的物理摄像头, 那么就说明有机会将这两科物理摄像头一起打开。 只能是有机会啊 实测。

不多说废话了。  下面直接走流程

一、选出有多个物理摄像头的逻辑摄像头

双镜类

public class DualCamera {

    //逻辑相机ID(厂商分配)
    private String logicCameraId;

    //相机物理id 1
    private String physicsCameraId1;

    //相机物理id 2
    private String physicsCameraId2;


    public String getLogicCameraId() {
        return logicCameraId;
    }

    public void setLogicCameraId(String logicCameraId) {
        this.logicCameraId = logicCameraId;
    }

    public String getPhysicsCameraId1() {
        return physicsCameraId1;
    }

    public void setPhysicsCameraId1(String physicsCameraId1) {
        this.physicsCameraId1 = physicsCameraId1;
    }

    public String getPhysicsCameraId2() {
        return physicsCameraId2;
    }

    public void setPhysicsCameraId2(String physicsCameraId2) {
        this.physicsCameraId2 = physicsCameraId2;
    }
}

得到可以开双镜的摄像头 

 public static DualCamera getDualCamera(Context context){
        DualCamera dualCamera = new DualCamera();
        //获取管理类
        CameraManager manager = (CameraManager) context.getSystemService(Context.CAMERA_SERVICE);
        assert manager != null;
        try {
            //获取所有逻辑ID
            String[] cameraIdList = manager.getCameraIdList();

            //获取逻辑摄像头下拥有多个物理摄像头的类 作为双镜类
            for (String id : cameraIdList) {
                try {
                    CameraCharacteristics cameraCharacteristics = manager.getCameraCharacteristics(id);
                    Set<String> physicalCameraIds = cameraCharacteristics.getPhysicalCameraIds();
                    Log.d(TAG, "逻辑ID:" + id + " 下的物理ID: " + Arrays.toString(physicalCameraIds.toArray()));
                    if (physicalCameraIds.size() >= 2) {
                        dualCamera.setLogicCameraId(id);
                        Object[] objects = physicalCameraIds.toArray();
                        //获取前两个物理摄像头作为双镜头
                        dualCamera.setPhysicsCameraId1(String.valueOf(objects[0]));
                        dualCamera.setPhysicsCameraId2(String.valueOf(objects[1]));
                        return dualCamera;
                    }
                } catch (CameraAccessException e) {
                    e.printStackTrace();
                }
            }
        } catch (CameraAccessException e) {
            e.printStackTrace();
        }
        return null;
    }

二、打开多个物理摄像头

第一步  先开对应的逻辑摄像头

  //开启摄像头
    public void openCamera(){
        HandlerThread thread = new HandlerThread("DualCamera");
        thread.start();
        handler = new Handler(thread.getLooper());
        CameraManager manager = (CameraManager) context.getSystemService(Context.CAMERA_SERVICE);
        try {
            //权限检查
            if (ActivityCompat.checkSelfPermission(context, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) {
                //否则去请求相机权限
                ActivityCompat.requestPermissions(context,new String[]{Manifest.permission.CAMERA},PERMISSIONS_REQUEST_CODE);
                return;
            }
            manager.openCamera(dualCamera.getLogicCameraId(),AsyncTask.SERIAL_EXECUTOR, cameraOpenCallBack);
        } catch (CameraAccessException e) {
            e.printStackTrace();
        }
    }

第二步、在开启的回调中指定打开对应的物理摄像头


    //打开相机时候的监听器,通过他可以得到相机实例,这个实例可以创建请求建造者
    private CameraDevice.StateCallback cameraOpenCallBack = new CameraDevice.StateCallback() {
        @Override
        public void onOpened(CameraDevice cameraDevice) {
            Log.d(TAG, "相机已经打开");
            //当逻辑摄像头开启后, 配置物理摄像头的参数
            config(cameraDevice);
        }

        @Override
        public void onDisconnected(@NonNull CameraDevice cameraDevice) {
            Log.d(TAG, "相机连接断开");
        }

        @Override
        public void onError(@NonNull CameraDevice cameraDevice, int i) {
            Log.d(TAG, "相机打开失败");
        }
    };

    /**
     * 配置摄像头参数
     * @param cameraDevice
     */
    public void config(CameraDevice cameraDevice){
        try {
            //构建输出参数  在参数中设置物理摄像头
            List<OutputConfiguration> configurations = new ArrayList<>();
            CaptureRequest.Builder mPreViewBuidler = cameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);

            //配置第一个物理摄像头
            SurfaceTexture texture = textureView1.getSurfaceTexture();
            OutputConfiguration outputConfiguration = new OutputConfiguration(new Surface(texture));
            outputConfiguration.setPhysicalCameraId(dualCamera.getPhysicsCameraId1());
            configurations.add(outputConfiguration);
            mPreViewBuidler.addTarget(Objects.requireNonNull(outputConfiguration.getSurface()));

            //配置第2个物理摄像头
            SurfaceTexture texture2 = textureView2.getSurfaceTexture();
            OutputConfiguration outputConfiguration2 = new OutputConfiguration(new Surface(texture2));
            outputConfiguration2.setPhysicalCameraId(dualCamera.getPhysicsCameraId2());
            configurations.add(outputConfiguration2);
            mPreViewBuidler.addTarget(Objects.requireNonNull(outputConfiguration2.getSurface()));

            //注册摄像头
            SessionConfiguration sessionConfiguration = new SessionConfiguration(
                    SessionConfiguration.SESSION_REGULAR,
                    configurations,
                    AsyncTask.SERIAL_EXECUTOR,
                    new CameraCaptureSession.StateCallback() {
                        @Override
                        public void onConfigured(@NonNull CameraCaptureSession cameraCaptureSession) {
                            try {
                                cameraSession = cameraCaptureSession;
                                cameraCaptureSession.setRepeatingRequest(mPreViewBuidler.build(), null, handler);
                            } catch (CameraAccessException e) {
                                e.printStackTrace();
                            }
                        }
                        @Override
                        public void onConfigureFailed(@NonNull CameraCaptureSession cameraCaptureSession) {

                        }
                    }
            );
            cameraDevice.createCaptureSession(sessionConfiguration);
        } catch (CameraAccessException e) {
            e.printStackTrace();
        }
    }

完成上面的操作,基本上就可以用camera2 打开两颗摄像头了, 文章写的比较粗略。

 

附上一份demo.    https://download.csdn.net/download/qq_32503365/12542520 

这个demo貌似有点问题, 授相机权限后需要重启应用才可以开启相机, 不过很明显我不准备修复它了。

最后付上一张 Huawei Mate30 的开双镜

 

 

  • 6
    点赞
  • 56
    收藏
    觉得还不错? 一键收藏
  • 18
    评论
Android系统中,可以通过使用Camera2 API来打开并使用两个USB摄像头。 首先,需要在AndroidManifest.xml文件中添加相应的权限,如下所示: ```xml <uses-permission android:name="android.permission.CAMERA" /> <uses-feature android:name="android.hardware.camera.any" /> <uses-feature android:name="android.hardware.usb.host" /> ``` 接下来,在代码中获取CameraManager对象,并使用getCameraIdList()方法获取可用的摄像头设备列表。然后,遍历列表找到对应的USB摄像头,即包含"usb"字符串的摄像头ID。 ```java CameraManager cameraManager = (CameraManager) getSystemService(Context.CAMERA_SERVICE); String[] cameraIds = cameraManager.getCameraIdList(); String usbCameraId = null; for (String cameraId : cameraIds) { CameraCharacteristics characteristics = cameraManager.getCameraCharacteristics(cameraId); Integer facing = characteristics.get(CameraCharacteristics.LENS_FACING); if (facing != null && facing == CameraCharacteristics.LENS_FACING_EXTERNAL) { usbCameraId = cameraId; break; } } ``` 接下来,可以使用usbCameraId来打开USB摄像头,并进行预览或拍照等操作。 ```java if (usbCameraId != null) { cameraManager.openCamera(usbCameraId, new CameraDevice.StateCallback() { @Override public void onOpened(@NonNull CameraDevice camera) { // 在这里可以进行相应的操作,如设置预览,拍照等 } @Override public void onDisconnected(@NonNull CameraDevice camera) { // 当相机断开连接时调用 camera.close(); } @Override public void onError(@NonNull CameraDevice camera, int error) { // 发生错误时调用 camera.close(); } }, null); } ``` 如此,我们就可以通过使用Camera2 API来打开并使用两个USB摄像头

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值