What AVCaptureDevice does Camera.app use?

Viewed 1046

I have a camera in my app. It's been carefully implemented following a lot of documentation, but it still has a major annoyance; the field of view is significantly smaller than the stock camera app. Here's two screenshots taken at approx the same distance for reference. My app is on the right, showing the entire preview stream from the camera.

enter image description here

Apple docs suggest using AVCaptureDevice.default or AVCaptureDevice.DiscoverySession, and my app uses the former;

AVCaptureDevice.default(.builtInWideAngleCamera, for: .video, position: .back)

I've tried many of the different capture devices, and none of them give me the same wide preview as the stock Camera app.

What am I doing wrong?

1 Answers

First of all, you need to expand the view bounds in your example to compare like for like.

Then you'll notice that in your left image, the capture mode is set to "PHOTO", not "VIDEO". If you switch tabs to the "VIDEO" mode in Camera.app you'll see that the zoom for both sessions is the same.

To enable this is a minor change:

let session = AVCaptureSession()
session.beginConfiguration()
session.sessionPreset = AVCaptureSession.Preset.photo

Usually, I would caution against using the Photo preset however you are capturing photos.. so reduced video stabilisation is tolerable. There is also a consideration of video quality as the .hd1920x1080 session preset produces higher resolution video and also is optimised for video.

let session = AVCaptureSession()
session.beginConfiguration()
session.sessionPreset = AVCaptureSession.Preset.photo

// Add a video input
guard session.canAddInput(deviceInput) else {
  print("Couldn't add device input")
  return
}
session.addInput(deviceInput) 

session.startRunning()

DiscoverySession approach could replace this if you want to have a cleaner solution for backup device option in case wide angle is not available. But with default, get the device input as follows:

guard let videoDevice = AVCaptureDevice.default(.builtInWideAngleCamera, for: .video, position: .back) else {
  print("Couldn't find wide angle camera")
  return
}

guard let deviceInput = try? AVCaptureDeviceInput(device: videoDevice) else {
  print("Could not create video device input.")
  return
}

If you're using AVCaptureVideoPreviewLayer it's better to use input device dimensions for the view to avoid resizing with previewLayer.videoGravity = .resizeAspect even though it works compared to previewLayer.videoGravity = .resize (it has performance overheads).

Related