feat: Support setting videoStabilizationMode
(#2160)
* feat: Support setting `videoStabilizationMode` * fix: Use `outputs` * Format * Set Video Stabilization Mode
This commit is contained in:
parent
e8ebc6ee9f
commit
abf5538bb0
@ -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)
|
||||
|
@ -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
|
||||
|
||||
@ -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
|
||||
@ -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
|
||||
@ -80,7 +85,7 @@ class CameraConfiguration {
|
||||
[`inputChanged`, `outputsChanged`, `orientationChanged`]
|
||||
*/
|
||||
var isSessionConfigurationDirty: Bool {
|
||||
return inputChanged || outputsChanged || orientationChanged
|
||||
return inputChanged || outputsChanged || videoStabilizationChanged || orientationChanged
|
||||
}
|
||||
|
||||
/**
|
||||
@ -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)
|
||||
|
@ -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) {
|
||||
|
@ -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)
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -1,28 +0,0 @@
|
||||
//
|
||||
// AVCaptureSession+setVideoStabilizationMode.swift
|
||||
// VisionCamera
|
||||
//
|
||||
// Created by Marc Rousavy on 02.06.21.
|
||||
// Copyright © 2021 Facebook. All rights reserved.
|
||||
//
|
||||
|
||||
import AVFoundation
|
||||
import Foundation
|
||||
|
||||
extension AVCaptureSession {
|
||||
/**
|
||||
Set the given video stabilization mode for all capture connections.
|
||||
*/
|
||||
func setVideoStabilizationMode(_ mode: String) {
|
||||
if #available(iOS 13.0, *) {
|
||||
guard let mode = try? AVCaptureVideoStabilizationMode(withString: mode) else {
|
||||
return
|
||||
}
|
||||
connections.forEach { connection in
|
||||
if connection.isVideoStabilizationSupported {
|
||||
connection.preferredVideoStabilizationMode = mode
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,62 +0,0 @@
|
||||
//
|
||||
// AVCaptureVideoStabilizationMode+descriptor.swift
|
||||
// mrousavy
|
||||
//
|
||||
// Created by Marc Rousavy on 29.12.20.
|
||||
// Copyright © 2020 mrousavy. All rights reserved.
|
||||
//
|
||||
|
||||
import AVFoundation
|
||||
|
||||
extension AVCaptureVideoStabilizationMode {
|
||||
init(withString string: String) throws {
|
||||
switch string {
|
||||
case "auto":
|
||||
self = .auto
|
||||
return
|
||||
case "cinematic":
|
||||
self = .cinematic
|
||||
return
|
||||
case "cinematic-extended":
|
||||
if #available(iOS 13.0, *) {
|
||||
self = .cinematicExtended
|
||||
return
|
||||
} else {
|
||||
self = .cinematic
|
||||
return
|
||||
}
|
||||
case "off":
|
||||
self = .off
|
||||
return
|
||||
case "standard":
|
||||
self = .standard
|
||||
return
|
||||
default:
|
||||
throw EnumParserError.invalidValue
|
||||
}
|
||||
}
|
||||
|
||||
var descriptor: String {
|
||||
if #available(iOS 13.0, *) {
|
||||
switch self {
|
||||
case .cinematicExtended:
|
||||
return "cinematic-extended"
|
||||
default:
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
switch self {
|
||||
case .auto:
|
||||
return "auto"
|
||||
case .cinematic:
|
||||
return "cinematic"
|
||||
case .off:
|
||||
return "off"
|
||||
case .standard:
|
||||
return "standard"
|
||||
default:
|
||||
fatalError("AVCaptureVideoStabilizationMode has unknown state.")
|
||||
}
|
||||
}
|
||||
}
|
@ -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
|
||||
}
|
||||
|
@ -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 */; };
|
||||
@ -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 */; };
|
||||
@ -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>"; };
|
||||
@ -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>"; };
|
||||
@ -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 */,
|
||||
@ -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 */,
|
||||
@ -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 */,
|
||||
@ -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 */,
|
||||
);
|
||||
|
Loading…
Reference in New Issue
Block a user