|
1 | 1 | import AVFoundation |
| 2 | +import Combine |
2 | 3 | import UIKit |
3 | 4 | import Vision |
4 | 5 |
|
@@ -36,6 +37,8 @@ final class CodeScannerViewController: UIViewController { |
36 | 37 | private let sessionQueue = DispatchQueue(label: "qrlogincamerasession.queue.serial") |
37 | 38 | private let session = AVCaptureSession() |
38 | 39 | private var requests = [VNRequest]() |
| 40 | + private var rotationCoordinator: AVCaptureDevice.RotationCoordinator? |
| 41 | + private var cancellables = Set<AnyCancellable>() |
39 | 42 |
|
40 | 43 | private lazy var throttler: Throttler = Throttler(seconds: 0.1) |
41 | 44 |
|
@@ -187,6 +190,15 @@ private extension CodeScannerViewController { |
187 | 190 | previewLayer.videoGravity = .resizeAspectFill |
188 | 191 | previewLayer.frame = videoOutputImageView.bounds |
189 | 192 | videoOutputImageView.layer.addSublayer(previewLayer) |
| 193 | + rotationCoordinator = AVCaptureDevice.RotationCoordinator(device: captureDevice, previewLayer: previewLayer) |
| 194 | + |
| 195 | + rotationCoordinator?.publisher(for: \.videoRotationAngleForHorizonLevelPreview) |
| 196 | + .sink { [weak self] angle in |
| 197 | + guard let self = self, |
| 198 | + let connection = self.previewLayer?.connection else { return } |
| 199 | + connection.videoRotationAngle = angle |
| 200 | + } |
| 201 | + .store(in: &cancellables) |
190 | 202 |
|
191 | 203 | sessionQueue.async { [weak self] in |
192 | 204 | self?.session.startRunning() |
@@ -290,27 +302,27 @@ private extension CodeScannerViewController { |
290 | 302 | // |
291 | 303 | private extension CodeScannerViewController { |
292 | 304 | func updatePreviewLayerOrientation() { |
293 | | - if let connection = previewLayer?.connection, connection.isVideoOrientationSupported { |
| 305 | + if let connection = previewLayer?.connection { |
294 | 306 | let orientation = view.window?.windowScene?.interfaceOrientation |
295 | | - let videoOrientation: AVCaptureVideoOrientation |
| 307 | + let videoRotationAngle: CGFloat |
296 | 308 | switch orientation { |
297 | 309 | case .portrait: |
298 | | - videoOrientation = .portrait |
| 310 | + videoRotationAngle = 90 |
299 | 311 | case .landscapeRight: |
300 | | - videoOrientation = .landscapeRight |
| 312 | + videoRotationAngle = 0 |
301 | 313 | case .landscapeLeft: |
302 | | - videoOrientation = .landscapeLeft |
| 314 | + videoRotationAngle = 180 |
303 | 315 | case .portraitUpsideDown: |
304 | | - videoOrientation = .portraitUpsideDown |
| 316 | + videoRotationAngle = 270 |
305 | 317 | default: |
306 | | - videoOrientation = .portrait |
| 318 | + videoRotationAngle = 90 |
307 | 319 | } |
308 | | - updatePreviewLayerVideoOrientation(connection: connection, orientation: videoOrientation) |
| 320 | + updatePreviewLayerVideoRotationAngle(connection: connection, angle: videoRotationAngle) |
309 | 321 | } |
310 | 322 | } |
311 | 323 |
|
312 | | - func updatePreviewLayerVideoOrientation(connection: AVCaptureConnection, orientation: AVCaptureVideoOrientation) { |
313 | | - connection.videoOrientation = orientation |
| 324 | + func updatePreviewLayerVideoRotationAngle(connection: AVCaptureConnection, angle: CGFloat) { |
| 325 | + connection.videoRotationAngle = angle |
314 | 326 | } |
315 | 327 | } |
316 | 328 |
|
|
0 commit comments