Formats

Understanding different Camera Formats

A CameraDevice can capture content in different resolutions, frame-rates (FPS), dynamic ranges (HDR), output formats (JPEG vs RAW), and more - a specific supported combination of these specifications is called a CameraFormat.

Accessing a Camera Device's available Formats

To get all available CameraFormats, use CameraDevice.formats:

const device = ...
for (const format of device.formats) {
  const { width, height } = format.videoResolution
  console.log(`${width} x ${height} @ ${format.maxFps} FPS`)
}
// Output:
//   4096 x 2160 @ 30 FPS
//   3840 x 2160 @ 60 FPS
//   1920 x 1080 @ 60 FPS
//    720 x  480 @ 60 FPS

Key-facts of a Format

Video Resolution

Each CameraFormat specifies its native Video Resolution, which is the resolution that affects all video/streaming outputs:

Video FPS

In addition to the Video's Resolution, a CameraFormat also specifies all available FPS ranges at this video resolution via CameraFormat.supportedFpsRanges, with the maximum available frame rate being CameraFormat.maxFps.

Similar to Video Resolution, FPS affects Video-, Frame-, and Preview-Outputs, whereas the Preview's refresh rate is limited to the screen's refresh rate.

Photo Resolution

Each CameraFormat specifies a list of available Photo Resolutions it can capture Photos in, with the highest available Photo Resolution accessible via CameraFormat.photoResolution. Photo Resolution affects the following outputs:

Depth Formats

Each CameraFormat specifies a list of available Depth Formats via CameraFormat.depthDataFormats.

If the CameraDevice (or CameraFormat) does not support Depth, this will be an empty array ([]). Depth Formats affect the following outputs:

Selecting a Format

You can select a Format using VisionCamera's format-filter APIs, which compare individual formats using the given FormatFilter and rank them by priority:

const device = ...
const format = useCameraFormat(device, [
  { videoResolution: 'max' },
  { fps: 60 }
])
const device = ...
const format = getCameraFormat(device, [
  { videoResolution: 'max' },
  { fps: 60 }
])

Here, videoResolution is listed before fps, so it has higher priority. Assuming our Device has the following Formats:

  1. 4096 x 2160 @ 30 FPS
  2. 3840 x 2160 @ 60 FPS
  3. 1920 x 1080 @ 60 FPS
  4. 720 x 480 @ 60 FPS

...VisionCamera will select the first format (4096x2160 @ 30 FPS), since videoResolution was more important than fps in our filter. If 60 FPS is more important for your use-case, flip the order of your filters:

const device = ...
const format = useCameraFormat(device, [
  { fps: 60 },
  { videoResolution: 'max' }
])
const device = ...
const format = getCameraFormat(device, [
  { fps: 60 },
  { videoResolution: 'max' }
])

Now VisionCamera will select the second format (3840x2160 @ 60 FPS), since fps was more important than videoResolution, but since videoResolution is still a criterion for us, VisionCamera chooses the next best resolution.

See FormatFilter for a list of all available filters.

Using Format Templates

To quickly choose a suitable CameraFormat, use one of the predefined Templates - for example, for 60 FPS Video Recordings, you can choose Video60Fps:

const device = ...
const format = useCameraFormat(device, Templates.Video60Fps)
const device = ...
const format = getCameraFormat(device, Templates.Video60Fps)

Manually selecting a Format

If the useCameraFormat(...) hook does not grant you enough control, you may also manually select a Format via your own filtering/reducer;

const device = ...
const format = device.formats.find((f) => f.isHighestPhotoFormat)

Selecting a Depth Format

You can select a Depth Format via the CameraFormat.depthDataFormats property:

const device = ...
const format = device.formats.find((f) => f.isHighestPhotoFormat)
const depthFormat = format.depthDataFormats[0]

Using the Format

To use your CameraFormat, pass it to your Camera's Configuration:

const device = useCameraDevice("external")

As an external Camera is plugged in or plugged out from the device, the useCameraDevice(...) hook automatically updates.

const devices = getAllCameraDevices()
let device = getCameraDevice(devices, "external")
addOnCameraDevicesChangedListener((d) => {
  device = getCameraDevice(d, "external")
})

As an external Camera is plugged in or plugged out from the device, the addOnCameraDevicesChangedListener(...) listener fires and you can call getCameraDevice(...) again to possibly detect new devices, or avoid using removed devices.

Using the Camera Device

To use your CameraDevice, pass it to your Camera's Configuration:

function App() {
  const device = useCameraDevice('back')
  const format = useCameraFormat(device, [
    { videoResolution: 'max' },
    { fps: 60 }
  ])

  return (
    <Camera
      style={StyleSheet.absoluteFill}
      isActive={true}
      device={device}
      format={format}
    />
  )
}
function App() {
  const device = useCameraDevice('back')
  const format = useCameraFormat(device, [
    { videoResolution: 'max' },
    { fps: 60 }
  ])
  const camera = useCamera({
    isActive: true,
    device: device,
    format: format
  })
}
const session = await HybridCameraFactory.createCameraSession(false)
const device = await getDefaultCameraDevice('back')
const format = getCameraDevice(device, [
  { videoResolution: 'max' },
  { fps: 60 }
])
await session.configure([
  {
    input: device,
    config: {
      format: format
    }
  }
], {})
await session.start()