margelo / margelo/react-native-vision-camera

iOS: video output `outputOrientation` reports the set value, not connection state; `currentResolution` returns undefined

Open
#4,178 1 comment 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
TypeScript
Stars
9.6k
Forks
1.4k
Avg merge
1d 28m
Merged PRs (30d)
4

Description

What's happening?

On iOS, CameraVideoOutput.outputOrientation reports the value that was last set, not the connection's actual orientation — so it cannot be used to find out how a recording was oriented. Separately, CameraVideoOutput.currentResolution returns undefined for me even while the session is running.

1. outputOrientation is effectively write-only on a video output

ios/Hybrid Objects/Outputs/HybridCameraVideoOutput.swift:

var outputOrientation: CameraOrientation = .up {
  didSet {
    guard let connection = output.connection(with: .video) else { return }
    try? connection.setOrientation(outputOrientation)
  }
}

It is a stored property whose didSet writes to the connection. Reading it returns the stored value, never the connection state.

The preview output does implement the getter properly, which is what makes this look like an oversight rather than a deliberate choice — HybridCameraPreviewOutput.swift:

var outputOrientation: CameraOrientation {
  get { return previewLayer.connection?.orientation ?? .up }
  set { /* ... */ }
}

AVCaptureConnection.orientation already exists in this repo (AVCaptureConnection+orientation.swift), so the video output could use the same accessor.

I want to be precise about what this would and would not fix: since configure(config:) already calls connection.setOrientation(outputOrientation) with the default .up, a corrected getter would return .up — the connection genuinely is .portrait. It would make the getter honest, but it still would not tell a caller how the resulting file is oriented, which is what I was actually after (see below).

2. currentResolution returns undefined
var currentResolution: Size? {
  guard let connection = output.connection(with: .video) else { return nil }
  return connection.inputStreamResolution
}

I read it both immediately after await session.start() and again at stop time; it was undefined both times, on a running session that was recording successfully. configure(config:) uses the same output.connection(with: .video) lookup and clearly succeeds, since orientation and mirroring are applied — so I have not been able to work out the cause and am reporting it as an observation rather than a diagnosis.

This matters because it is the only way to detect a resolution substitution. Requesting targetResolution: 3024x4224 with a { fps: 120 } constraint was accepted, and the session recorded 3840x2160 instead. Without currentResolution there is no way to learn that from the API.

Context: what I was trying to do

Report the true rotation and dimensions of a finished recording. Rotation turns out to be format-dependent — the same portrait-locked app produced:

Camera Config Stored Rotation Presents
front 1080x1920 @ 30fps 1080x1920 none portrait
rear 4K @ 120fps 3840x2160 -90 portrait

Both present portrait, but only one carries a transform, so no single assumption is correct and no connection-level read reports it. I ended up deriving rotation server-side with ffprobe instead, which works fine — but a recorder-level "what did the finished file actually get" (resolution + rotation) would remove the need.

Environment
  • react-native-vision-camera 5.2.2
  • react-native-nitro-modules 0.36.5
  • react-native 0.81.5, New Architecture, bridgeless
  • Expo SDK 54 (expo 54.0.36), dev client
  • Xcode 26.6, iOS 27.0, iPhone 17 Pro Max (physical device)

Ground truth in the table above is ffprobe on the files pulled off the device.

Contributor guide

No contributing guide indexed for this repository

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with ios/Hybrid Objects/Outputs/HybridCameraVideoOutput.swift and compare its outputOrientation accessor with HybridCameraPreviewOutput.swift and AVCaptureConnection+orientation.swift. Reproduce currentResolution during a running and stopped session, then trace the connection used by configure(config:). Done means the orientation getter reflects connection state and the resolution behavior is either corrected or clearly scoped, with the reported recording cases accounted for.

Written by the indexing model from the issue text.

Assessment

Tech stack
ios, react-native, swift
Domain
mobile, mobile-dev
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Active
Clarity
Mostly clear
Newbie friendliness
48/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.