-
Notifications
You must be signed in to change notification settings - Fork 3.4k
[camera_avfoundation] Fix crash when streaming while recording #9691
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
[camera_avfoundation] Fix crash when streaming while recording #9691
Conversation
There was a problem hiding this comment.
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 fixes a crash that occurs when streaming is enabled while recording video. The crash was caused by force-unwrapping a nil
value when trying to get a pixel buffer from an audio sample buffer. The fix correctly handles this by using optional binding to check if a pixel buffer exists before processing it. The change is accompanied by a new unit test that verifies audio buffers are ignored during image streaming. My feedback includes a suggestion to also handle a potential nil
value for planeAddress
to prevent another potential crash.
let length = bytesPerRow * height | ||
let bytes = Data(bytes: planeAddress!, count: length) | ||
|
||
let planeBuffer: [String: Any] = [ | ||
"bytesPerRow": bytesPerRow, | ||
"width": width, | ||
"height": height, | ||
"bytes": FlutterStandardTypedData(bytes: bytes), | ||
] | ||
planes.append(planeBuffer) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There's a potential crash here if planeAddress
is nil
. The !
force-unwraps it when creating Data
. It's safer to use optional binding (if let
or guard let
) to ensure planeAddress
is not nil before using it.
if let planeAddress = planeAddress {
let length = bytesPerRow * height
let bytes = Data(bytes: planeAddress, count: length)
let planeBuffer: [String: Any] = [
"bytesPerRow": bytesPerRow,
"width": width,
"height": height,
"bytes": FlutterStandardTypedData(bytes: bytes),
]
planes.append(planeBuffer)
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The only case in which we should get nil planeAddress is if we use incorrect function CVPixelBufferGetBaseAddress
or CVPixelBufferGetBaseAddressOfPlane
for a given buffer. We are checking the whether buffer is planar so this should never happen. I don't think failing silently is necessarily better in this case
bytesPerRow = CVPixelBufferGetBytesPerRow(pixelBuffer) | ||
height = CVPixelBufferGetHeight(pixelBuffer) | ||
width = CVPixelBufferGetWidth(pixelBuffer) | ||
if let pixelBuffer = CMSampleBufferGetImageBuffer(sampleBuffer) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
can you use guard here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We couldn't use guard there because this method also handled recording later, so an early return would break audio recording. I've extracted the whole streaming part to handleSampleBufferStreaming
and replaced all nested ifs
with guards
. I left the pixel buffer guard separate so that I can comment on it
In
captureOutput
, we receive both pixel and audio buffers (audio only during recording with audio enabled, when streaming alone is enabled, everything works correctly). Currently, the streaming part of this method doesn't handle non-pixel buffers properly, causing a crash because of force unwrapping of nil.This PR changes the logic to ignore non-pixel buffers for purposes of streaming.
Resolves flutter/flutter#172894.
Pre-Review Checklist
[shared_preferences]
pubspec.yaml
with an appropriate new version according to the pub versioning philosophy, or I have commented below to indicate which version change exemption this PR falls under1.CHANGELOG.md
to add a description of the change, following repository CHANGELOG style, or I have commented below to indicate which CHANGELOG exemption this PR falls under1.///
).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
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 ↩3