camera: pin macOS connections to 0° rotation (sensor-native landscape)

Diagnostic from a fresh build with NSLog confirmed the rotation
behaviour on macOS: with `videoRotationAngle = 90`
(`.portrait`), `AVCapturePhoto.cgImageRepresentation()` returned a
720x1280 CGImage — *physical* portrait pixels, not just an EXIF
tag. So Apple's AVCaptureSession.h docs claiming
"AVCapturePhotoOutput uses EXIF only" don't hold on macOS. The
data-output connection on macOS also honors the same setter, which
is why preview + video flipped to rotated as soon as the photo fix
landed.

Pin macOS to 0° rotation (`.landscapeRight`):
  - Photo: 1280x720 (sensor-native landscape, matches what the user
    sees on screen).
  - Preview: 1280x720 (matches the new desktop 4:3 page aspect).
  - Video: 1280x720 (was already correct before the .portrait
    change; back to that state).

The snapshot orientation argument is still ignored on macOS —
desktop cameras don't rotate. The argument carries through for iOS
where the camera page passes the device orientation.
This commit is contained in:
agra
2026-05-13 21:24:52 +03:00
parent 0b5618948a
commit 4c10604cb8

View File

@@ -16,23 +16,25 @@ import AVFoundation
/// available, fall back to the deprecated one for older macOS.
extension AVCaptureConnection {
func applyUxCaptureOrientation(_ orientation: DeviceOrientationFlutter) {
// macOS `AVCapturePhotoOutput`'s photo connection captures in
// landscape natively when its rotation hint is `.portrait`
// (90°). Counter-intuitive vs iOS where `.portrait` rotates
// the landscape sensor to portrait, but verified empirically
// setting `.landscapeRight` / `videoRotationAngle = 0` left
// the JPEG rotated 90° CW. The data output's connection on
// macOS doesn't honor `videoOrientation` / `videoRotationAngle`
// (or returns supported = false), so this setter is a no-op
// there and preview + video stay correct.
// Pin to 0° rotation (`.landscapeRight`) on macOS desktop
// cameras are physically landscape and any non-zero rotation
// physically rotates the buffer. Diagnostic build confirmed
// a 720x1280 CGImage (portrait) when this was set to 90°,
// proving Apple's docs ("AVCapturePhotoOutput uses EXIF only,
// no physical rotation") don't apply on macOS and the data
// output's connection honors the same setter, so preview +
// video also rotate.
//
// The Flutter snapshot is always `portraitUp` on macOS
// (desktops don't rotate); we ignore it and force landscape.
if #available(macOS 14.0, *) {
if isVideoRotationAngleSupported(90) {
videoRotationAngle = 90
if isVideoRotationAngleSupported(0) {
videoRotationAngle = 0
return
}
}
if isVideoOrientationSupported {
videoOrientation = .portrait
videoOrientation = .landscapeRight
}
}
}