Skip to content

Commit f0d042a

Browse files
committed
Reapply "feat: Add supportedMultiCamDeviceCombinations" (#3820)
This reverts commit 7586e98.
1 parent c7e3560 commit f0d042a

14 files changed

Lines changed: 219 additions & 17 deletions

File tree

docs/content/docs/multi-camera.mdx

Lines changed: 50 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ description: Using multiple Camera Devices in a single Camera Session
55

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

8-
A [`CameraSession`](/api/react-native-vision-camera/hybrid-objects/CameraSession) allows attaching multiple connections to stream from multiple [`CameraDevice`](/api/react-native-vision-camera/hybrid-objects/CameraDevice)s at the same time - if the system supports it.
8+
A [`CameraSession`](/api/react-native-vision-camera/hybrid-objects/CameraSession) allows attaching multiple connections to stream from multiple [`CameraDevice`](/api/react-native-vision-camera/hybrid-objects/CameraDevice)s at the same time (e.g. Picture-in-Picture mode via front + back Camera) - if the system supports it.
99

1010
### Creating a Multi-Camera Session
1111

@@ -19,14 +19,35 @@ if (VisionCamera.supportsMultiCamSessions) {
1919

2020
### Using multiple Connections
2121

22-
With a multi-cam [`CameraSession`](/api/react-native-vision-camera/hybrid-objects/CameraSession), you can now attach multiple [`CameraSessionConnection`](/api/react-native-vision-camera/interfaces/CameraSessionConnection)s - for example to stream and capture from the Front- and Back-Camera at the same time, attach both devices:
22+
Due to hardware constraints, not every [`CameraDevice`](/api/react-native-vision-camera/hybrid-objects/CameraDevice) can be paired with every other [`CameraDevice`](/api/react-native-vision-camera/hybrid-objects/CameraDevice) - therefore VisionCamera exposes a fixed array of supported combinations via [`CameraDeviceFactory.supportedMultiCamDeviceCombinations`](/api/react-native-vision-camera/hybrid-objects/CameraDeviceFactory#supportedmulticamdevicecombinations) upfront:
2323

2424
```ts
25-
const session = ...
26-
const frontDevice = useCameraDevice('front')
27-
const backDevice = useCameraDevice('back')
28-
const frontPreview = usePreviewOutput()
29-
const backPreview = usePreviewOutput()
25+
if (!VisionCamera.supportsMultiCamSessions)
26+
return
27+
28+
const deviceFactory = await VisionCamera.createDeviceFactory()
29+
const frontAndBackCombination =
30+
deviceFactory.supportedMultiCamDeviceCombinations.find((devices) => {
31+
return (
32+
devices.some((d) => d.position === 'front') &&
33+
devices.some((d) => d.position === 'back')
34+
)
35+
})
36+
if (frontAndBackCombination == null)
37+
return
38+
39+
const frontDevice = frontAndBackCombination.find((d) => d.position === 'front')
40+
const backDevice = frontAndBackCombination.find((d) => d.position === 'back')
41+
```
42+
43+
Then, knowing `frontDevice` and `backDevice` can be used simultaneously in a Multi-Cam session, create the [`CameraSession`](/api/react-native-vision-camera/hybrid-objects/CameraSession), and attach the [`CameraSessionConnection`](/api/react-native-vision-camera/interfaces/CameraSessionConnection)s:
44+
45+
```ts
46+
const session = await VisionCamera.createCameraSession(true)
47+
const frontPreviewOutput = VisionCamera.createPreviewOutput()
48+
const frontPhotoOutput = VisionCamera.createPhotoOutput({})
49+
const backPreviewOutput = VisionCamera.createPreviewOutput()
50+
const backPhotoOutput = VisionCamera.createPhotoOutput({})
3051

3152
const [frontController, backController] = await session.configure([
3253
// Front Camera
@@ -51,6 +72,26 @@ const [frontController, backController] = await session.configure([
5172
await session.start()
5273
```
5374

54-
Then, ensure you display both `frontPreview` and `backPreview` in separate [`<NativePreviewView />`](/api/react-native-vision-camera/views/NativePreviewView) views.
75+
Each returned [`CameraController`](/api/react-native-vision-camera/hybrid-objects/CameraController) correlates to the connection at that index - e.g. `frontController` allows zooming/exposure/focus the `frontDevice`, and vice-versa.
76+
77+
Then, ensure you display both `frontPreviewOutput` and `backPreviewOutput` in separate [`<NativePreviewView />`](/api/react-native-vision-camera/views/NativePreviewView) views:
78+
79+
```tsx
80+
function App() {
81+
const frontPreviewOutput = ...
82+
const backPreviewOutput = ...
5583

56-
Each returned [`CameraController`](/api/react-native-vision-camera/hybrid-objects/CameraController) correlates to the connection at that index.
84+
return (
85+
<View style={StyleSheet.absoluteFill}>
86+
<NativePreviewView
87+
style={{ flex: 1 }}
88+
previewOutput={frontPreviewOutput}
89+
/>
90+
<NativePreviewView
91+
style={{ flex: 1 }}
92+
previewOutput={backPreviewOutput}
93+
/>
94+
</View>
95+
)
96+
}
97+
```

packages/react-native-vision-camera/android/src/main/java/com/margelo/nitro/camera/HybridCameraDeviceFactory.kt

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,13 @@ class HybridCameraDeviceFactory(
3838
override val cameraDevices: Array<HybridCameraDeviceSpec>
3939
get() = cameraProvider.availableCameraInfos.mapToArray { HybridCameraDevice(it) }
4040

41+
override val supportedMultiCamDeviceCombinations: Array<Array<HybridCameraDeviceSpec>>
42+
get() {
43+
return cameraProvider.availableConcurrentCameraInfos.mapToArray { devices ->
44+
return@mapToArray devices.mapToArray { HybridCameraDevice(it) }
45+
}
46+
}
47+
4148
override var userPreferredCamera: HybridCameraDeviceSpec?
4249
get() {
4350
val preferredCameraId =

packages/react-native-vision-camera/ios/Hybrid Objects/HybridCameraDeviceFactory.swift

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,6 @@ import Foundation
99
import NitroModules
1010

1111
class HybridCameraDeviceFactory: HybridCameraDeviceFactorySpec {
12-
let discoverySession: AVCaptureDevice.DiscoverySession
13-
var cameraDevices: [any HybridCameraDeviceSpec] {
14-
return discoverySession.devices.map { HybridCameraDevice(device: $0) }
15-
}
16-
1712
override init() {
1813
self.discoverySession = AVCaptureDevice.DiscoverySession(
1914
deviceTypes: AVCaptureDevice.DeviceType.all,
@@ -22,6 +17,17 @@ class HybridCameraDeviceFactory: HybridCameraDeviceFactorySpec {
2217
super.init()
2318
}
2419

20+
let discoverySession: AVCaptureDevice.DiscoverySession
21+
var cameraDevices: [any HybridCameraDeviceSpec] {
22+
return discoverySession.devices.map { HybridCameraDevice(device: $0) }
23+
}
24+
25+
var supportedMultiCamDeviceCombinations: [[any HybridCameraDeviceSpec]] {
26+
return discoverySession.supportedMultiCamDeviceSets.map { devices in
27+
return devices.map { HybridCameraDevice(device: $0) }
28+
}
29+
}
30+
2531
var userPreferredCamera: (any HybridCameraDeviceSpec)? {
2632
get {
2733
guard #available(iOS 17.0, *) else {
@@ -36,7 +42,7 @@ class HybridCameraDeviceFactory: HybridCameraDeviceFactorySpec {
3642
guard #available(iOS 17.0, *) else {
3743
return
3844
}
39-
guard let hybridDevice = newValue as? HybridCameraDevice else {
45+
guard let hybridDevice = newValue as? any NativeCameraDevice else {
4046
return
4147
}
4248
AVCaptureDevice.userPreferredCamera = hybridDevice.device

packages/react-native-vision-camera/nitrogen/generated/android/c++/JHybridCameraDeviceFactorySpec.cpp

Lines changed: 23 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

packages/react-native-vision-camera/nitrogen/generated/android/c++/JHybridCameraDeviceFactorySpec.hpp

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

packages/react-native-vision-camera/nitrogen/generated/android/kotlin/com/margelo/nitro/camera/HybridCameraDeviceFactorySpec.kt

Lines changed: 4 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

packages/react-native-vision-camera/nitrogen/generated/ios/VisionCamera-Swift-Cxx-Bridge.hpp

Lines changed: 11 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

packages/react-native-vision-camera/nitrogen/generated/ios/c++/HybridCameraDeviceFactorySpecSwift.hpp

Lines changed: 4 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

packages/react-native-vision-camera/nitrogen/generated/ios/swift/HybridCameraDeviceFactorySpec.swift

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

packages/react-native-vision-camera/nitrogen/generated/ios/swift/HybridCameraDeviceFactorySpec_cxx.swift

Lines changed: 22 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)