From 3a20c44a31136ebae39437a331c5adba943dba5b Mon Sep 17 00:00:00 2001 From: Rui Rodrigues Date: Fri, 2 Aug 2024 14:39:23 +0100 Subject: [PATCH] fix preview and recording orientation fix - add onCameraConfigurationChanged to CameraSessionDelegate to notify CameraView when configuration changes - when orientatin change update CameraView.PreviewView.videoPreviewLayer.connection orientation value --- package/ios/CameraView.swift | 9 ++++ package/ios/Core/CameraSession.swift | 1 + package/ios/Core/CameraSessionDelegate.swift | 2 + .../Extensions/AVCaptureOutput+mirror.swift | 52 +++++++++++-------- package/ios/TestRecorder/ViewController.swift | 14 +++++ 5 files changed, 56 insertions(+), 22 deletions(-) diff --git a/package/ios/CameraView.swift b/package/ios/CameraView.swift index cdb664d..ffbfbc9 100644 --- a/package/ios/CameraView.swift +++ b/package/ios/CameraView.swift @@ -303,6 +303,15 @@ public final class CameraView: UIView, CameraSessionDelegate { } onInitialized([:]) } + + func onCameraConfigurationChanged(_ configuration: CameraConfiguration?, _ difference: CameraConfiguration.Difference?) { + guard let configuration, let difference else { return } + + if difference.orientationChanged, let connection = previewView.videoPreviewLayer.connection { + let videoPreviewLayer = previewView.videoPreviewLayer + connection.setOrientation(configuration.orientation) + } + } func onCameraStarted() { ReactLogger.log(level: .info, message: "Camera started!") diff --git a/package/ios/Core/CameraSession.swift b/package/ios/Core/CameraSession.swift index 7952a0e..8d9faff 100644 --- a/package/ios/Core/CameraSession.swift +++ b/package/ios/Core/CameraSession.swift @@ -195,6 +195,7 @@ class CameraSession: NSObject, AVCaptureVideoDataOutputSampleBufferDelegate, AVC self.delegate?.onSessionInitialized() } + self.delegate?.onCameraConfigurationChanged(config, difference) // After configuring, set this to the new configuration. self.configuration = config } catch { diff --git a/package/ios/Core/CameraSessionDelegate.swift b/package/ios/Core/CameraSessionDelegate.swift index b72c2ec..8a1f059 100644 --- a/package/ios/Core/CameraSessionDelegate.swift +++ b/package/ios/Core/CameraSessionDelegate.swift @@ -21,6 +21,8 @@ protocol CameraSessionDelegate: AnyObject { Called when the [CameraSession] successfully initializes */ func onSessionInitialized() + + func onCameraConfigurationChanged(_ configuration: CameraConfiguration?, _ difference: CameraConfiguration.Difference?) /** Called when the [CameraSession] starts streaming frames. (isActive=true) */ diff --git a/package/ios/Extensions/AVCaptureOutput+mirror.swift b/package/ios/Extensions/AVCaptureOutput+mirror.swift index 63910cd..b1b0e49 100644 --- a/package/ios/Extensions/AVCaptureOutput+mirror.swift +++ b/package/ios/Extensions/AVCaptureOutput+mirror.swift @@ -32,28 +32,36 @@ extension AVCaptureOutput { func setOrientation(_ orientation: Orientation) { // Set orientation for each connection for connection in connections { - #if swift(>=5.9) - if #available(iOS 17.0, *) { - // Camera Sensors are always in landscape rotation (90deg). - // We are setting the target rotation here, so we need to rotate by landscape once. - 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 - } - } else { - if connection.isVideoOrientationSupported { - connection.videoOrientation = orientation.toAVCaptureVideoOrientation() - } - } - #else - if connection.isVideoOrientationSupported { - connection.videoOrientation = orientation.toAVCaptureVideoOrientation() - } - #endif + connection.setOrientation(orientation) } } } + + + +extension AVCaptureConnection { + func setOrientation(_ orientation: Orientation) { + #if swift(>=5.9) + if #available(iOS 17.0, *) { + // Camera Sensors are always in landscape rotation (90deg). + // We are setting the target rotation here, so we need to rotate by landscape once. + 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 isVideoRotationAngleSupported(degrees) { + videoRotationAngle = degrees + } + } else { + if isVideoOrientationSupported { + videoOrientation = orientation.toAVCaptureVideoOrientation() + } + } + #else + if isVideoOrientationSupported { + videoOrientation = orientation.toAVCaptureVideoOrientation() + } + #endif + } +} diff --git a/package/ios/TestRecorder/ViewController.swift b/package/ios/TestRecorder/ViewController.swift index 9245565..a80b43c 100644 --- a/package/ios/TestRecorder/ViewController.swift +++ b/package/ios/TestRecorder/ViewController.swift @@ -113,5 +113,19 @@ class ViewController: UIViewController { } } + override func viewWillTransition(to size: CGSize, with coordinator: any UIViewControllerTransitionCoordinator) { + switch UIDevice.current.orientation { + case .landscapeLeft: + cameraView.orientation = "landscape-right" + case .landscapeRight: + cameraView.orientation = "landscape-left" + default: + cameraView.orientation = "portrait" + } + + cameraView.didSetProps([]) + super.viewWillTransition(to: size, with: coordinator) + } + }