Skip to content

[camera]fix a crash when switching camera while recording due to disconnected capturePhotoOputput - #13248

Merged
auto-submit[bot] merged 1 commit into
flutter:mainfrom
hellohuanlin:switch_camera_while_recording_crash
Oct 16, 2026
Merged

auto-submit[bot] merged 1 commit into
flutter:mainfrom
hellohuanlin:switch_camera_while_recording_crash

Conversation

@hellohuanlin

Copy link
Copy Markdown
Contributor

This PR fixes one of the test failures here flutter/flutter#191202. This failure is not iOS 27 specific. However, since it requires physical device (switch between front/back camera), it is not run on our CI, so we didn't catch it.

How was it broken

Before switching camera, the capture session has:

Inputs:       [ backCameraInput ]
Outputs:      [ captureVideoOutput, capturePhotoOutput ]
Connections:
  Wire 1: backCameraInput  -> captureVideoOutput   (created manually via addConnection)
  Wire 2: backCameraInput  -> capturePhotoOutput   (created automatically via addOutput)

When switching camera input (from back camera to front camera), we remove video input and output, but left photo output untouched. So at this point the capture session has:

Inputs:       [ ]
Outputs:      [ capturePhotoOutput ]   <-- still in the session, but unplugged!
Connections:  [ ]                      <-- both Wire 1 and Wire 2 were deleted!

Now when adding back the camera input, we simply do:

videoCaptureSession.addInputWithNoConnections(captureVideoInput)
videoCaptureSession.addOutputWithNoConnections(captureVideoOutput.avOutput)

So our capture session ends up with:

Inputs:       [ frontCameraInput ]
Outputs:      [ capturePhotoOutput, newVideoOutput ]
Connections:
  Wire 1: frontCameraInput -> newVideoOutput
  Wire 2: (MISSING! capturePhotoOutput has no wire to frontCameraInput!)

Then a subsequent code calls

capturePhotoOutput.maxPhotoDimensions = maxSupportedDimensions

Which throws NSInvalidArgumentException because it has no connection.

The fix is simply to use addInput rather than addInputWithNoConnections, which would automatically add the frontCameraInput -> capturePhotoOutput connection.

Fixes flutter/flutter#194344

List which issues are fixed by this PR. You must list at least one issue.

Pre-Review Checklist

If you need help, consider asking for advice on the #hackers-new channel on Discord.

Note: The Flutter team is currently trialing the use of Gemini Code Assist for GitHub. Comments from the gemini-code-assist bot should not be taken as authoritative feedback from the Flutter team. If you find its comments useful you can update your code accordingly, but if you are unsure or disagree with the feedback, please feel free to wait for a Flutter team member's review for guidance on which automated comments should be addressed.

Footnotes

  1. Regular contributors who have demonstrated familiarity with the repository guidelines only need to comment if the PR is not auto-exempted by repo tooling. ↩ ↩2

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Code Review

This pull request addresses a crash when switching cameras during video recording by ensuring the photo output is reconnected. Specifically, DefaultCamera.swift is updated to use addInput instead of addInputWithNoConnections when switching video inputs. To support this, mock classes for the capture session and photo output are enhanced, and a new test is added to verify the reconnection and updating of photo dimensions. The review feedback points out a missing return statement in the error handling blocks of DefaultCamera.swift which could trigger multiple completion calls, and suggests refining the mock removeInput implementation to only remove connections associated with the removed input.

Comment on lines 1247 to +1251
}
videoCaptureSession.addInputWithNoConnections(captureVideoInput)

// Do not use addInputWithNoConnections. The session still has the disconnected
// capturePhotoOutput, and we need to reconnect it to the captureVideoInput.
videoCaptureSession.addInput(captureVideoInput)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

high

There is a missing return statement inside the if !videoCaptureSession.canAddInput(captureVideoInput) block. Without an early return, the method will continue executing, attempting to add the input and eventually calling completion(.success(())) even after a failure has already been reported. This violates the platform channel protocol (calling the completion handler multiple times) and can lead to unexpected behavior or crashes.

Please also apply this fix to the subsequent canAddOutput and canAddConnection checks in this method, as they suffer from the same missing return issue.

Suggested change
}
videoCaptureSession.addInputWithNoConnections(captureVideoInput)
// Do not use addInputWithNoConnections. The session still has the disconnected
// capturePhotoOutput, and we need to reconnect it to the captureVideoInput.
videoCaptureSession.addInput(captureVideoInput)
return
}
// Do not use addInputWithNoConnections. The session still has the disconnected
// capturePhotoOutput, and we need to reconnect it to the captureVideoInput.
videoCaptureSession.addInput(captureVideoInput)

@hellohuanlin hellohuanlin Oct 14, 2026 •

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Good find! This is an existing bug, so filed flutter/flutter#194348

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Also simply adding the return doesn't balance out the beginConfiguration() call, so the suggestion is wrong.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Code Review

This pull request modifies DefaultCamera.swift to use addInput instead of addInputWithNoConnections when switching video inputs during recording, ensuring the disconnected photo output is reconnected. It also enhances mock classes (MockCapturePhotoOutput, MockCaptureSession) and adds a unit test to verify this behavior. Feedback points out a missing return statement in the error handling block for canAddInput (and potentially subsequent checks) in DefaultCamera.swift, which could lead to multiple completion calls and crashes.

@cbracken cbracken left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

LGTM stamp from a Japanese personal seal

@hellohuanlin
hellohuanlin force-pushed the switch_camera_while_recording_crash branch from 1859f73 to ed63b2d Compare October 16, 2026 03:15
@hellohuanlin hellohuanlin added the autosubmit Merge PR when tree becomes green via auto submit App label Oct 16, 2026
@auto-submit
auto-submit Bot merged commit 93eede7 into flutter:main Oct 16, 2026
13 checks passed
gmackall pushed a commit to gmackall/flutter that referenced this pull request Oct 16, 2026
flutter/packages@da40eaf...93eede7

2026-10-16 [email protected] [camera]fix a
crash when switching camera while recording due to disconnected
capturePhotoOputput (flutter/packages#13248)
2026-10-16 [email protected] [various] Update iOS example apps to
the 15.0 deployment target (flutter/packages#13223)
2026-10-16 [email protected] [material_ui]
Add M3E `IconButton` example (flutter/packages#13085)
2026-10-15 [email protected] [ci] Increase deprecation check minimum to
iOS 16 (flutter/packages#13211)
2026-10-15 [email protected] [google_sign_in] Remove the
public iOS handleOpen helper (flutter/packages#13273)
2026-10-15 [email protected] [google_fonts] Make the pendingFonts
test deterministic (flutter/packages#13262)
2026-10-15 [email protected]
[vector_graphics_compiler] Fix tspan transform applied twice
(flutter/packages#13129)
2026-10-15 [email protected] Roll Flutter from
426be96 to 5c7e45a (21 revisions) (flutter/packages#13270)
2026-10-15 [email protected] [flutter_svg]
Add golden widget tests for SVG alpha masks (flutter/packages#13245)

If this roll has caused a breakage, revert this CL and set the roller
to dry run mode using the controls here:
https://autoroll.skia.org/r/flutter-packages-flutter-autoroll
Please CC [email protected] on the revert to ensure that a
human
is aware of the problem.

To file a bug in Flutter:
https://github.com/flutter/flutter/issues/new/choose

To report a problem with the AutoRoller itself, please file a bug:
https://issues.skia.org/issues/new?component=1389291&template=1850622

Documentation for the AutoRoller is here:
https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md
suryaKommana2662 pushed a commit to suryaKommana2662/flutter that referenced this pull request Oct 29, 2026
flutter/packages@da40eaf...93eede7

2026-10-16 [email protected] [camera]fix a
crash when switching camera while recording due to disconnected
capturePhotoOputput (flutter/packages#13248)
2026-10-16 [email protected] [various] Update iOS example apps to
the 15.0 deployment target (flutter/packages#13223)
2026-10-16 [email protected] [material_ui]
Add M3E `IconButton` example (flutter/packages#13085)
2026-10-15 [email protected] [ci] Increase deprecation check minimum to
iOS 16 (flutter/packages#13211)
2026-10-15 [email protected] [google_sign_in] Remove the
public iOS handleOpen helper (flutter/packages#13273)
2026-10-15 [email protected] [google_fonts] Make the pendingFonts
test deterministic (flutter/packages#13262)
2026-10-15 [email protected]
[vector_graphics_compiler] Fix tspan transform applied twice
(flutter/packages#13129)
2026-10-15 [email protected] Roll Flutter from
426be96 to 5c7e45a (21 revisions) (flutter/packages#13270)
2026-10-15 [email protected] [flutter_svg]
Add golden widget tests for SVG alpha masks (flutter/packages#13245)

If this roll has caused a breakage, revert this CL and set the roller
to dry run mode using the controls here:
https://autoroll.skia.org/r/flutter-packages-flutter-autoroll
Please CC [email protected] on the revert to ensure that a
human
is aware of the problem.

To file a bug in Flutter:
https://github.com/flutter/flutter/issues/new/choose

To report a problem with the AutoRoller itself, please file a bug:
https://issues.skia.org/issues/new?component=1389291&template=1850622

Documentation for the AutoRoller is here:
https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

autosubmit Merge PR when tree becomes green via auto submit App CICD Run CI/CD p: camera platform-ios platform-macos

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[camera] changing camera while recording causes a crash due to disconnected AVOutput

2 participants