john smith
john smith

Reputation: 117

How to switch from front camera to back camera in AVFoundation

I have CaptureDelegate that has a method setupCaptureDevice that I call from .task:

class CaptureDelegate: NSObject, AVCaptureVideoDataOutputSampleBufferDelegate, ObservableObject {
    
    
    let captureSession = AVCaptureSession()         // For capturing what comes in from the device's camera
    let captureSessionQueue = DispatchQueue(label: "captureSessionQueue")   // For processing images
    

    @Published var cameraIsActive: Bool = false 


    func setupCaptureSession(captureDevice: AVCaptureDevice?) {

        
        let videoCaptureDevice: AVCaptureDevice
        
        if let captureDevice {
            videoCaptureDevice = captureDevice
        } else {
            //will pick the best camera or the only camera(for iphone SE)
            if let device = AVCaptureDevice.default(.builtInDualCamera,
                                                    for: .video, position: .back) {
                videoCaptureDevice = device
            } else if let device = AVCaptureDevice.default(.builtInWideAngleCamera,
                                                           for: .video, position: .back) {
                videoCaptureDevice = device
            } else {
                fatalError("Missing expected back camera device.")
            }

        }
                
        guard let videoDeviceInput = try? AVCaptureDeviceInput(device: videoCaptureDevice) else {      //input from the back Camera
            print( "Failed to create AVCaptureDeviceInput")
            return
        }
        
        let videoOutput = AVCaptureVideoDataOutput()                //the output that camera catches
        videoOutput.setSampleBufferDelegate(self, queue: captureSessionQueue)
        
        captureSession.beginConfiguration( )
        
        if captureSession.canAddInput(videoDeviceInput) {
            captureSession.addInput(videoDeviceInput)
        } else {
            print("Failed to add input to capture session")
        }
        
        if captureSession.canAddOutput(videoOutput) {
            captureSession.addOutput(videoOutput)
        } else {
            print("Failed to add output to capture session")
        }
        
        captureSession.sessionPreset = .high
        
        captureSession.commitConfiguration()    //commit the new frames to CaptureSession
        
        
        DispatchQueue.global().async {
            self.captureSession.startRunning()
        }
        

it takes an optional AVCaptureDevice so that the first time the app runs it initiates with the back camera. I want to allow the user to toggle from back to front and vice verse so I am attempting to have a published property that the user can toggle via a method call In CaptureDelegate:

@Published var currentCamera: AVCaptureDevice?


//Switch from front to back camera etc
func toggleCaptureDevice() {
captureSession.stopRunning()

//Now define the AVCapturedevice, switch to back cam if it is front and switch to front cam if its back

//Now call setupCaptureSession but this time actually pass in that device
}
    }

My problem is how do I know if the App is currently using the front or back camera to be able to toggle it and update my currentCamera?

Upvotes: 1

Views: 21

Answers (1)

Kiryl Famin
Kiryl Famin

Reputation: 335

I think what you need is: AVCaptureDeviceInput.position

@Published var currentCameraPosition: AVCaptureDevice.Position = .back

func toggleCaptureDevice() {
    captureSessionQueue.async { [weak self] in
        guard let self = self else { return }
        
        self.captureSession.beginConfiguration()
        
        if let currentInput = self.captureSession.inputs.first as? AVCaptureDeviceInput {
            self.captureSession.removeInput(currentInput)
        }
        
        let newPosition: AVCaptureDevice.Position = (self.currentCameraPosition == .back) ? .front : .back
        
        guard let newDevice = AVCaptureDevice.default(.builtInWideAngleCamera, for: .video, position: newPosition) else {
            print("Failed to get new camera device")
            return
        }
        
        do {
            let newInput = try AVCaptureDeviceInput(device: newDevice)
            
            if self.captureSession.canAddInput(newInput) {
                self.captureSession.addInput(newInput)
                self.currentCameraPosition = newPosition // Update camera state
            } else {
                print("Failed to add new input to capture session")
            }
        } catch {
            print("Error switching camera: \(error)")
        }
        
        self.captureSession.commitConfiguration()
        self.captureSession.startRunning()
    }
}

Upvotes: 1

Related Questions