Back to React Native Vision Camera

Multi-Camera

docs/content/docs/multi-camera.mdx

5.0.114.3 KB
Original Source

import { Tab, Tabs } from 'fumadocs-ui/components/tabs'

A CameraSession allows attaching multiple connections to stream from multiple CameraDevices at the same time (e.g. Picture-in-Picture mode via front + back Camera) - if the system supports it.

Creating a Multi-Camera Session

To create a multi-camera CameraSession, use createCameraSession(true). Make sure supportsMultiCamSessions is true:

ts
if (VisionCamera.supportsMultiCamSessions) {
  const session = await VisionCamera.createCameraSession(true)
}

Getting Multi-Cam capable CameraDevices

Due to hardware constraints, not every CameraDevice can be paired with every other CameraDevice, therefore VisionCamera exposes a list of supported device combinations via supportedMultiCamDeviceCombinations upfront:

A combination contains one or more logical CameraDevices. On iOS, a combination can contain a single virtual Camera, such as a Dual- or Triple-Camera, because that one Camera is backed by multiple physical Cameras. Pass the returned Cameras directly to configure(...), and use physicalDevices only for inspection. If you need multiple independent previews, choose a combination with at least two Cameras.

ts
const deviceFactory = await VisionCamera.createDeviceFactory()
const frontAndBackCombination =
  deviceFactory.supportedMultiCamDeviceCombinations.find((devices) => {
    return (
      devices.some((d) => d.position === 'front') &&
      devices.some((d) => d.position === 'back')
    )
  })
if (frontAndBackCombination == null)
  return

const frontDevice = frontAndBackCombination.find((d) => d.position === 'front')
const backDevice = frontAndBackCombination.find((d) => d.position === 'back')

Using multiple Connections

Then, knowing frontDevice and backDevice can be used simultaneously in a Multi-Cam session, create the outputs and build the CameraSessionConnections:

ts
const frontPreviewOutput = VisionCamera.createPreviewOutput()
const frontPhotoOutput = VisionCamera.createPhotoOutput({})
const backPreviewOutput = VisionCamera.createPreviewOutput()
const backPhotoOutput = VisionCamera.createPhotoOutput({})

const [frontController, backController] = await session.configure([
  // Front Camera
  {
    input: frontDevice,
    outputs: [
      { output: frontPreviewOutput, mirrorMode: 'on' },
      { output: frontPhotoOutput, mirrorMode: 'off' },
    ],
    constraints: []
  },
  // Back Camera
  {
    input: backDevice,
    outputs: [
      { output: backPreviewOutput, mirrorMode: 'off' },
      { output: backPhotoOutput, mirrorMode: 'off' },
    ],
    constraints: []
  }
])
await session.start()

Each returned CameraController correlates to the connection at that index - e.g. frontController allows zooming/exposure/focus the frontDevice, and vice-versa.

Picture-in-Picture Multi-Previews

Then, ensure you display both frontPreviewOutput and backPreviewOutput in separate <NativePreviewView /> views:

tsx
function App() {
  const frontPreviewOutput = ...
  const backPreviewOutput = ...

  return (
    <View style={StyleSheet.absoluteFill}>
      <NativePreviewView
        style={{ flex: 1 }}
        previewOutput={frontPreviewOutput}
      />
      <NativePreviewView
        style={{ flex: 1 }}
        previewOutput={backPreviewOutput}
      />
    </View>
  )
}