camera: use videoRotationAngle on macOS 14+ to pin photo to landscape

Setting `videoOrientation = .landscapeRight` had no effect on
macOS 14+ — Apple deprecated it in favour of `videoRotationAngle`
(a `CGFloat` in degrees) and the old setter is silently ignored
in newer versions. The captured JPEG stayed rotated 90° CW even
with our previous fix.

Try `videoRotationAngle = 0` first (macOS 14+) — that's "no
rotation from the sensor's natural orientation", which is landscape
on desktop cameras. Fall back to `videoOrientation = .landscapeRight`
for macOS 13 and older.

Same `applyUxCaptureOrientation` entry point — no caller changes.
iOS extension untouched; iOS still uses the per-snapshot
`videoOrientation` set (deprecated on iOS 17+ too, but still
functions there).
This commit is contained in:
agra
2026-05-13 19:43:44 +03:00
parent f0a7f0b3a1
commit c5a1b50982

View File

@@ -2,19 +2,26 @@ import AVFoundation
/// macOS counterpart of `AVCaptureConnection+iOS.swift`. /// macOS counterpart of `AVCaptureConnection+iOS.swift`.
/// ///
/// macOS desktop cameras are physically fixed landscape. AVFoundation /// macOS desktop cameras are physically fixed landscape, but
/// initialises `connection.videoOrientation` to `.portrait` by /// `AVCapturePhotoOutput`'s connection defaults to a setting that
/// default though same as iOS which on macOS *also* rotates the /// rotates the captured JPEG 90° CW. We pin the connection to
/// sensor frame 90° CW (manifested as a 90° CW selfie photo + a /// landscape (or 0° rotation, depending on the available API) so
/// rotated preview). So we *do* set the orientation on macOS, but /// the JPEG matches what the preview shows.
/// pin it to `.landscapeRight` regardless of the snapshot Flutter ///
/// passes (which is always `portraitUp` on macOS desktops don't /// `videoOrientation` was deprecated in macOS 14 / iOS 17 in favour
/// rotate). That tells AVFoundation "leave the sensor frame alone"; /// of `videoRotationAngle` (a `CGFloat` in degrees). On macOS 14+
/// captured JPEG ends up landscape with EXIF orientation = 1 (no /// `videoOrientation` may be silently ignored that's exactly the
/// rotation), and preview data-output buffers flow at the sensor's /// symptom we hit ("photo still rotated 90° CW even after setting
/// native aspect. /// videoOrientation = .landscapeRight"). Prefer the new API where
/// available, fall back to the deprecated one for older macOS.
extension AVCaptureConnection { extension AVCaptureConnection {
func applyUxCaptureOrientation(_ orientation: DeviceOrientationFlutter) { func applyUxCaptureOrientation(_ orientation: DeviceOrientationFlutter) {
if #available(macOS 14.0, *) {
if isVideoRotationAngleSupported(0) {
videoRotationAngle = 0
return
}
}
if isVideoOrientationSupported { if isVideoOrientationSupported {
videoOrientation = .landscapeRight videoOrientation = .landscapeRight
} }