Android camera2 opens two physical cameras at the same time

Posted by anindya23 on Fri, 12 Jun 2020 10:04:23 +0200

Due to business requirements, two physical cameras need to be opened at the same time. According to Camera2 api, SdkVersion 28 supports this function. But I have to say that api documents are not friendly, or that I am really a dish.

Let's take a picture of the structure of Camera2, which I don't know its name.

From this picture, we need to know what camera0 and Camera1... In HAL layer are and what they contain. From the official documents, it can be understood as

These cameras are logical cameras. What is a logic Camera? That's the software level Camera. No matter what your physical Camera (the real Camera on your mobile phone) looks like, you don't need to think about it. All you get is this logical Camera.   

Here comes the question. Now I want to open two physical cameras at the same time. What's the use of giving me a bunch of logical cameras?

Don't worry.. Go on..

This logical camera is a package of physical cameras. This means that the logical camera will contain one or more physical cameras. The camera client can call getPhysicalCameraIds() You can get the physical camera under the logical camera (of course, it may not be available, that is, it is not provided). When this getPhysicalCameraIds() The number of returned physical camera IDS is greater than 2. That is to say, there are more than two physical cameras under this logical camera, which means there is an opportunity to open these two physical cameras together. It can only be measured if there is a chance.

No more bullshit. Let's go through the process

1, Select logical cameras with multiple physical cameras

Binoculars

public class DualCamera {

    //Logical camera ID (assigned by manufacturer)
    private String logicCameraId;

    //Camera physical id 1
    private String physicsCameraId1;

    //Camera physical 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;
    }
}

Get a camera with two mirrors

 public static DualCamera getDualCamera(Context context){
        DualCamera dualCamera = new DualCamera();
        //Get management class
        CameraManager manager = (CameraManager) context.getSystemService(Context.CAMERA_SERVICE);
        assert manager != null;
        try {
            //Get all logical ID S
            String[] cameraIdList = manager.getCameraIdList();

            //Obtain the class with multiple physical cameras under the logic camera as the double mirror class
            for (String id : cameraIdList) {
                try {
                    CameraCharacteristics cameraCharacteristics = manager.getCameraCharacteristics(id);
                    Set<String> physicalCameraIds = cameraCharacteristics.getPhysicalCameraIds();
                    Log.d(TAG, "logic ID: " + id + " Physics under ID: " + Arrays.toString(physicalCameraIds.toArray()));
                    if (physicalCameraIds.size() >= 2) {
                        dualCamera.setLogicCameraId(id);
                        Object[] objects = physicalCameraIds.toArray();
                        //Take the first two physical cameras as two lenses
                        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;
    }

2, Turn on multiple physical cameras

First, turn on the corresponding logic camera

  //Turn on the camera
    public void openCamera(){
        HandlerThread thread = new HandlerThread("DualCamera");
        thread.start();
        handler = new Handler(thread.getLooper());
        CameraManager manager = (CameraManager) context.getSystemService(Context.CAMERA_SERVICE);
        try {
            //Authority check
            if (ActivityCompat.checkSelfPermission(context, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) {
                //Otherwise, ask for camera permission
                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();
        }
    }

Step 2: specify to open the corresponding physical camera in the open callback

    //When the camera is turned on, the listener can get an instance of the camera, which can be used to create a request builder
    private CameraDevice.StateCallback cameraOpenCallBack = new CameraDevice.StateCallback() {
        @Override
        public void onOpened(CameraDevice cameraDevice) {
            Log.d(TAG, "Camera is on");
            //When the logic camera is on, configure the parameters of the physical camera
            config(cameraDevice);
        }

        @Override
        public void onDisconnected(@NonNull CameraDevice cameraDevice) {
            Log.d(TAG, "Camera disconnected");
        }

        @Override
        public void onError(@NonNull CameraDevice cameraDevice, int i) {
            Log.d(TAG, "Camera open failed");
        }
    };

    /**
     * Configure camera parameters
     * @param cameraDevice
     */
    public void config(CameraDevice cameraDevice){
        try {
            //Build output parameters set physical camera in parameters
            List<OutputConfiguration> configurations = new ArrayList<>();
            CaptureRequest.Builder mPreViewBuidler = cameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);

            //Configure the first physical camera
            SurfaceTexture texture = textureView1.getSurfaceTexture();
            OutputConfiguration outputConfiguration = new OutputConfiguration(new Surface(texture));
            outputConfiguration.setPhysicalCameraId(dualCamera.getPhysicsCameraId1());
            configurations.add(outputConfiguration);
            mPreViewBuidler.addTarget(Objects.requireNonNull(outputConfiguration.getSurface()));

            //Configure 2nd physical camera
            SurfaceTexture texture2 = textureView2.getSurfaceTexture();
            OutputConfiguration outputConfiguration2 = new OutputConfiguration(new Surface(texture2));
            outputConfiguration2.setPhysicalCameraId(dualCamera.getPhysicsCameraId2());
            configurations.add(outputConfiguration2);
            mPreViewBuidler.addTarget(Objects.requireNonNull(outputConfiguration2.getSurface()));

            //Register camera
            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();
        }
    }

After completing the above operation, you can basically use camera2 to open two cameras. The article is rough.

Finally, I'll give you a picture of Huawei mate 30's open double mirror

 

 

Topics: Mobile