Skip to content

CameraView fix for iOS: orientation and video recording#3167

Open
zhitaop wants to merge 6 commits intoCommunityToolkit:mainfrom
zhitaop:fix/camera-update-ios
Open

CameraView fix for iOS: orientation and video recording#3167
zhitaop wants to merge 6 commits intoCommunityToolkit:mainfrom
zhitaop:fix/camera-update-ios

Conversation

@zhitaop
Copy link
Contributor

@zhitaop zhitaop commented Mar 20, 2026

Description of Change

  • This PR fixes a bug on iOS where camera preview is stopped after video recording, and attempting to capture an image would crash the app. This is done by fixing video recording clean up logic so only recording-specific resources (audioInput, videoOutput) are added and removed.

  • Simplifies video recording session management by removing the separate video input and reusing the existing capture input

  • Improves iOS camera orientation handling for both photo capture and video recording. Centralized orientation handling logic in ConfigureAVCaptureConnection():

    • Uses AVCaptureDeviceRotationCoordinator on iOS 17+
    • Falls back to CMMotionManager on iOS 16 and below

Linked Issues

PR Checklist

  • Has a linked Issue, and the Issue has been approved(bug) or Championed (feature/proposal)
  • Has tests (if omitted, state reason in description)
  • Has samples (if omitted, state reason in description)
  • Rebased on top of main at time of PR
  • Changes adhere to coding standard
  • Documentation created or updated: https://github.com/MicrosoftDocs/CommunityToolkit/pulls

Additional information

Copilot AI review requested due to automatic review settings March 20, 2026 09:14
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR improves iOS CameraView behavior by centralizing orientation configuration for photo/video capture and refining video recording resource management to prevent post-recording crashes.

Changes:

  • Centralizes photo/video orientation configuration via a new ConfigureAVCaptureConnection() helper (iOS 17+ rotation coordinator; iOS ≤16 accelerometer fallback).
  • Simplifies iOS video recording by reusing the existing camera input and only adding/removing recording-specific resources (audioInput, videoOutput).
  • Adds lifecycle cleanup for rotation coordinator and motion manager resources in Dispose().

Comment on lines +180 to 185
captureInput = new AVCaptureDeviceInput(captureDevice, out NSError? error);
if (error is not null)
{
throw new CameraException($"Error creating capture device input: {error.LocalizedDescription}");
}
captureSession.AddInput(captureInput);
Copy link

Copilot AI Mar 20, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

captureSession.BeginConfiguration() is called before creating AVCaptureDeviceInput, but when error is non-null this method throws without calling captureSession.CommitConfiguration(). This can leave the session in a configuration state and break subsequent preview/recording setup. Consider wrapping the configuration block in a try/finally (always commit), and also validate captureSession.CanAddInput(captureInput) before calling AddInput, disposing captureInput and committing before throwing if it cannot be added.

Copilot uses AI. Check for mistakes.
Comment on lines +83 to 88
if (!UIDevice.CurrentDevice.CheckSystemVersion(17, 0))
{
motionManager ??= new();
motionManager.StartAccelerometerUpdates();
}
orientationDidChangeObserver = UIDevice.Notifications.ObserveOrientationDidChange((_, _) => UpdateVideoOrientation());
Copy link

Copilot AI Mar 20, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

CMMotionManager.StartAccelerometerUpdates() is started in CreatePlatformView() (iOS 16 and below) but is only stopped in Dispose(). If the camera preview is stopped while the view stays alive, accelerometer updates will continue indefinitely, impacting battery/perf. Consider stopping updates in PlatformStopCameraPreview() (and restarting when starting preview), or tying it to connect/disconnect lifecycle instead of view creation.

Copilot uses AI. Check for mistakes.
{
captureConnection.AutomaticallyAdjustsVideoMirroring = false;
captureConnection.VideoMirrored = true;
}
Copy link

Copilot AI Mar 20, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ConfigureAVCaptureConnection only forces mirroring when the selected camera is front-facing, but it never resets mirroring when switching back to a rear camera. Because photoOutput is reused across camera switches, this can leave AutomaticallyAdjustsVideoMirroring disabled and VideoMirrored still true for subsequent rear-camera captures/recordings. Consider adding an else branch to re-enable automatic mirroring (or explicitly set VideoMirrored = false) when the camera is not front-facing.

Suggested change
}
}
else if (captureConnection.SupportsVideoMirroring)
{
captureConnection.AutomaticallyAdjustsVideoMirroring = true;
captureConnection.VideoMirrored = false;
}

Copilot uses AI. Check for mistakes.
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 1 out of 1 changed files in this pull request and generated 1 comment.

Comment on lines +444 to +447
if (cameraView.SelectedCamera?.Position is CameraPosition.Front && captureConnection.SupportsVideoMirroring)
{
captureConnection.AutomaticallyAdjustsVideoMirroring = false;
captureConnection.VideoMirrored = true;
Copy link

Copilot AI Mar 20, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ConfigureAVCaptureConnection only enables mirroring for the front camera, but never explicitly disables it for non-front cameras. Since outputs/connections can be reused across camera switches, this can leave the back camera unexpectedly mirrored. Set mirroring explicitly for both cases (and restore AutomaticallyAdjustsVideoMirroring as appropriate) based on the selected camera position.

Suggested change
if (cameraView.SelectedCamera?.Position is CameraPosition.Front && captureConnection.SupportsVideoMirroring)
{
captureConnection.AutomaticallyAdjustsVideoMirroring = false;
captureConnection.VideoMirrored = true;
if (captureConnection.SupportsVideoMirroring)
{
if (cameraView.SelectedCamera?.Position is CameraPosition.Front)
{
captureConnection.AutomaticallyAdjustsVideoMirroring = false;
captureConnection.VideoMirrored = true;
}
else
{
captureConnection.AutomaticallyAdjustsVideoMirroring = true;
captureConnection.VideoMirrored = false;
}

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

2 participants