Skip to content

Commit

Permalink
feat: Support setting videoStabilizationMode (#2160)
Browse files Browse the repository at this point in the history
* feat: Support setting `videoStabilizationMode`

* fix: Use `outputs`

* Format

* Set Video Stabilization Mode
  • Loading branch information
mrousavy authored Nov 15, 2023
1 parent e8ebc6e commit abf5538
Show file tree
Hide file tree
Showing 9 changed files with 53 additions and 100 deletions.
8 changes: 8 additions & 0 deletions package/ios/CameraView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,14 @@ public final class CameraView: UIView, CameraSessionDelegate {
config.codeScanner = .disabled
}

// Video Stabilization
if let jsVideoStabilizationMode = videoStabilizationMode as? String {
let videoStabilizationMode = try VideoStabilizationMode(jsValue: jsVideoStabilizationMode)
config.videoStabilizationMode = videoStabilizationMode
} else {
config.videoStabilizationMode = .off
}

// Orientation
if let jsOrientation = orientation as? String {
let orientation = try Orientation(jsValue: jsOrientation)
Expand Down
9 changes: 8 additions & 1 deletion package/ios/Core/CameraConfiguration.swift
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,9 @@ class CameraConfiguration {
var video: OutputConfiguration<Video> = .disabled
var codeScanner: OutputConfiguration<CodeScanner> = .disabled

// Video Stabilization
var videoStabilizationMode: VideoStabilizationMode = .off

// Orientation
var orientation: Orientation = .portrait

Expand Down Expand Up @@ -49,6 +52,7 @@ class CameraConfiguration {
photo = other.photo
video = other.video
codeScanner = other.codeScanner
videoStabilizationMode = other.videoStabilizationMode
orientation = other.orientation
format = other.format
fps = other.fps
Expand All @@ -67,6 +71,7 @@ class CameraConfiguration {
struct Difference {
let inputChanged: Bool
let outputsChanged: Bool
let videoStabilizationChanged: Bool
let orientationChanged: Bool
let formatChanged: Bool
let sidePropsChanged: Bool
Expand All @@ -80,7 +85,7 @@ class CameraConfiguration {
[`inputChanged`, `outputsChanged`, `orientationChanged`]
*/
var isSessionConfigurationDirty: Bool {
return inputChanged || outputsChanged || orientationChanged
return inputChanged || outputsChanged || videoStabilizationChanged || orientationChanged
}

/**
Expand All @@ -96,6 +101,8 @@ class CameraConfiguration {
inputChanged = left?.cameraId != right.cameraId
// photo, video, codeScanner
outputsChanged = inputChanged || left?.photo != right.photo || left?.video != right.video || left?.codeScanner != right.codeScanner
// videoStabilizationMode
videoStabilizationChanged = outputsChanged || left?.videoStabilizationMode != right.videoStabilizationMode
// orientation
orientationChanged = outputsChanged || left?.orientation != right.orientation
// format (depends on cameraId)
Expand Down
11 changes: 11 additions & 0 deletions package/ios/Core/CameraSession+Configuration.swift
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,17 @@ extension CameraSession {
ReactLogger.log(level: .info, message: "Successfully configured all outputs!")
}

// pragma MARK: Video Stabilization
func configureVideoStabilization(configuration: CameraConfiguration) {
captureSession.outputs.forEach { output in
output.connections.forEach { connection in
if connection.isVideoStabilizationSupported {
connection.preferredVideoStabilizationMode = configuration.videoStabilizationMode.toAVCaptureVideoStabilizationMode()
}
}
}
}

// pragma MARK: Orientation

func configureOrientation(configuration: CameraConfiguration) {
Expand Down
6 changes: 5 additions & 1 deletion package/ios/Core/CameraSession.swift
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,11 @@ class CameraSession: NSObject, AVCaptureVideoDataOutputSampleBufferDelegate, AVC
if difference.outputsChanged {
try self.configureOutputs(configuration: config)
}
// 3. Update output orientation
// 3. Update Video Stabilization
if difference.videoStabilizationChanged {
try self.configureVideoStabilization(configuration: config)
}
// 4. Update output orientation
if difference.orientationChanged {
self.configureOrientation(configuration: config)
}
Expand Down
2 changes: 2 additions & 0 deletions package/ios/Extensions/AVCaptureOutput+mirror.swift
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,8 @@ extension AVCaptureOutput {
let cameraOrientation = orientation.rotateBy(orientation: .landscapeLeft)
let degrees = cameraOrientation.toDegrees()

// TODO: Don't rotate the video output because it adds overhead. Instead just use EXIF flags for the .mp4 file if recording.
// Does that work when we flip the camera?
if connection.isVideoRotationAngleSupported(degrees) {
connection.videoRotationAngle = degrees
}
Expand Down

This file was deleted.

This file was deleted.

19 changes: 19 additions & 0 deletions package/ios/Types/VideoStabilizationMode.swift
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,25 @@ enum VideoStabilizationMode: String, JSUnionValue {
}
}

func toAVCaptureVideoStabilizationMode() -> AVCaptureVideoStabilizationMode {
switch self {
case .off:
return .off
case .standard:
return .standard
case .cinematic:
return .cinematic
case .cinematicExtended:
if #available(iOS 13.0, *) {
return .cinematicExtended
} else {
return .cinematic
}
case .auto:
return .auto
}
}

var jsValue: String {
return rawValue
}
Expand Down
8 changes: 0 additions & 8 deletions package/ios/VisionCamera.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,6 @@
B887519625E0102000DB86D6 /* Promise.swift in Sources */ = {isa = PBXBuildFile; fileRef = B887517025E0102000DB86D6 /* Promise.swift */; };
B887519725E0102000DB86D6 /* CameraView+TakePhoto.swift in Sources */ = {isa = PBXBuildFile; fileRef = B887517125E0102000DB86D6 /* CameraView+TakePhoto.swift */; };
B887519825E0102000DB86D6 /* EnumParserError.swift in Sources */ = {isa = PBXBuildFile; fileRef = B887517325E0102000DB86D6 /* EnumParserError.swift */; };
B887519925E0102000DB86D6 /* AVCaptureVideoStabilizationMode+descriptor.swift in Sources */ = {isa = PBXBuildFile; fileRef = B887517425E0102000DB86D6 /* AVCaptureVideoStabilizationMode+descriptor.swift */; };
B887519A25E0102000DB86D6 /* AVVideoCodecType+descriptor.swift in Sources */ = {isa = PBXBuildFile; fileRef = B887517525E0102000DB86D6 /* AVVideoCodecType+descriptor.swift */; };
B887519C25E0102000DB86D6 /* AVCaptureDevice.TorchMode+descriptor.swift in Sources */ = {isa = PBXBuildFile; fileRef = B887517725E0102000DB86D6 /* AVCaptureDevice.TorchMode+descriptor.swift */; };
B887519E25E0102000DB86D6 /* AVCapturePhotoOutput.QualityPrioritization+descriptor.swift in Sources */ = {isa = PBXBuildFile; fileRef = B887517925E0102000DB86D6 /* AVCapturePhotoOutput.QualityPrioritization+descriptor.swift */; };
Expand All @@ -63,7 +62,6 @@
B88751A725E0102000DB86D6 /* CameraView+Zoom.swift in Sources */ = {isa = PBXBuildFile; fileRef = B887518225E0102000DB86D6 /* CameraView+Zoom.swift */; };
B88751A825E0102000DB86D6 /* CameraError.swift in Sources */ = {isa = PBXBuildFile; fileRef = B887518325E0102000DB86D6 /* CameraError.swift */; };
B88751A925E0102000DB86D6 /* CameraView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B887518425E0102000DB86D6 /* CameraView.swift */; };
B88B47472667C8E00091F538 /* AVCaptureSession+setVideoStabilizationMode.swift in Sources */ = {isa = PBXBuildFile; fileRef = B88B47462667C8E00091F538 /* AVCaptureSession+setVideoStabilizationMode.swift */; };
B8994E6C263F03E100069589 /* JSINSObjectConversion.mm in Sources */ = {isa = PBXBuildFile; fileRef = B8994E6B263F03E100069589 /* JSINSObjectConversion.mm */; };
B8A1AEC42AD7EDE800169C0D /* AVCaptureVideoDataOutput+pixelFormat.swift in Sources */ = {isa = PBXBuildFile; fileRef = B8A1AEC32AD7EDE800169C0D /* AVCaptureVideoDataOutput+pixelFormat.swift */; };
B8A1AEC62AD7F08E00169C0D /* CameraView+Focus.swift in Sources */ = {isa = PBXBuildFile; fileRef = B8A1AEC52AD7F08E00169C0D /* CameraView+Focus.swift */; };
Expand Down Expand Up @@ -144,7 +142,6 @@
B887517025E0102000DB86D6 /* Promise.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Promise.swift; sourceTree = "<group>"; };
B887517125E0102000DB86D6 /* CameraView+TakePhoto.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "CameraView+TakePhoto.swift"; sourceTree = "<group>"; };
B887517325E0102000DB86D6 /* EnumParserError.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EnumParserError.swift; sourceTree = "<group>"; };
B887517425E0102000DB86D6 /* AVCaptureVideoStabilizationMode+descriptor.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "AVCaptureVideoStabilizationMode+descriptor.swift"; sourceTree = "<group>"; };
B887517525E0102000DB86D6 /* AVVideoCodecType+descriptor.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "AVVideoCodecType+descriptor.swift"; sourceTree = "<group>"; };
B887517725E0102000DB86D6 /* AVCaptureDevice.TorchMode+descriptor.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "AVCaptureDevice.TorchMode+descriptor.swift"; sourceTree = "<group>"; };
B887517925E0102000DB86D6 /* AVCapturePhotoOutput.QualityPrioritization+descriptor.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "AVCapturePhotoOutput.QualityPrioritization+descriptor.swift"; sourceTree = "<group>"; };
Expand All @@ -158,7 +155,6 @@
B887518325E0102000DB86D6 /* CameraError.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CameraError.swift; sourceTree = "<group>"; };
B887518425E0102000DB86D6 /* CameraView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CameraView.swift; sourceTree = "<group>"; };
B88873E5263D46C7008B1D0E /* FrameProcessorPlugin.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = FrameProcessorPlugin.h; sourceTree = "<group>"; };
B88B47462667C8E00091F538 /* AVCaptureSession+setVideoStabilizationMode.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "AVCaptureSession+setVideoStabilizationMode.swift"; sourceTree = "<group>"; };
B8994E6B263F03E100069589 /* JSINSObjectConversion.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = JSINSObjectConversion.mm; sourceTree = "<group>"; };
B8A1AEC32AD7EDE800169C0D /* AVCaptureVideoDataOutput+pixelFormat.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "AVCaptureVideoDataOutput+pixelFormat.swift"; sourceTree = "<group>"; };
B8A1AEC52AD7F08E00169C0D /* CameraView+Focus.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "CameraView+Focus.swift"; sourceTree = "<group>"; };
Expand Down Expand Up @@ -275,7 +271,6 @@
B887516825E0102000DB86D6 /* AVCaptureOutput+mirror.swift */,
B881D35D2ABC775E009B21C8 /* AVCaptureDevice+toDictionary.swift */,
B887516A25E0102000DB86D6 /* AVCaptureDevice.Format+toDictionary.swift */,
B88B47462667C8E00091F538 /* AVCaptureSession+setVideoStabilizationMode.swift */,
B887516225E0102000DB86D6 /* Collection+safe.swift */,
B881D35F2ABC8E4E009B21C8 /* AVCaptureVideoDataOutput+findPixelFormat.swift */,
B8F127CF2ACF054A00B39EA3 /* CMVideoDimensions+toCGSize.swift */,
Expand All @@ -300,7 +295,6 @@
children = (
B887517325E0102000DB86D6 /* EnumParserError.swift */,
B8DB3BC7263DC28C004C18D7 /* AVAssetWriter.Status+descriptor.swift */,
B887517425E0102000DB86D6 /* AVCaptureVideoStabilizationMode+descriptor.swift */,
B887517525E0102000DB86D6 /* AVVideoCodecType+descriptor.swift */,
B887517725E0102000DB86D6 /* AVCaptureDevice.TorchMode+descriptor.swift */,
B887517925E0102000DB86D6 /* AVCapturePhotoOutput.QualityPrioritization+descriptor.swift */,
Expand Down Expand Up @@ -457,7 +451,6 @@
B88685E72AD698DF00E93869 /* CameraConfiguration.swift in Sources */,
B887518725E0102000DB86D6 /* CameraViewManager.m in Sources */,
B88751A925E0102000DB86D6 /* CameraView.swift in Sources */,
B887519925E0102000DB86D6 /* AVCaptureVideoStabilizationMode+descriptor.swift in Sources */,
B80E06A0266632F000728644 /* AVAudioSession+updateCategory.swift in Sources */,
B887519425E0102000DB86D6 /* MakeReactError.swift in Sources */,
B887519525E0102000DB86D6 /* ReactLogger.swift in Sources */,
Expand Down Expand Up @@ -504,7 +497,6 @@
B8F127D02ACF054A00B39EA3 /* CMVideoDimensions+toCGSize.swift in Sources */,
B8994E6C263F03E100069589 /* JSINSObjectConversion.mm in Sources */,
B8A1AEC62AD7F08E00169C0D /* CameraView+Focus.swift in Sources */,
B88B47472667C8E00091F538 /* AVCaptureSession+setVideoStabilizationMode.swift in Sources */,
B88103E32AD7065C0087F063 /* CameraSessionDelegate.swift in Sources */,
B887519E25E0102000DB86D6 /* AVCapturePhotoOutput.QualityPrioritization+descriptor.swift in Sources */,
);
Expand Down

1 comment on commit abf5538

@vercel
Copy link

@vercel vercel bot commented on abf5538 Nov 15, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.