From 0da71825cba997fb54e1e0f8e82d940aed28ecff Mon Sep 17 00:00:00 2001 From: Radek Czemerys Date: Mon, 22 Jun 2026 20:07:22 +0100 Subject: [PATCH] =?UTF-8?q?test(video):=20failing=20repro=20=E2=80=94=20se?= =?UTF-8?q?tOutputSettings({=20codec=20})=20crashes=20when=20a=20targetBit?= =?UTF-8?q?Rate=20is=20set?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Calling `videoOutput.setOutputSettings({ codec })` after `targetBitRate` was configured aborts the process with an uncatchable Objective-C NSInvalidArgumentException (SIGTRAP). `HybridCameraVideoOutput.setOutputSettings` reads the fully-expanded `output.outputSettings(for: connection)` dict and writes it back. When `targetBitRate` is set, that dict already contains AVVideoCompressionPropertiesKey plus width/height/color keys. `AVCaptureMovieFileOutput.setOutputSettings:forConnection:` rejects the non-codec/compression keys, raising an ObjC exception Swift cannot catch, so the whole app aborts. No JS try/catch can prevent it. Adds a harness test that configures a targetBitRate, then calls setOutputSettings({ codec: 'h264' }) and expects it to resolve without crashing. Expected to crash the harness app on current main. --- .../__tests__/visioncamera.video.harness.ts | 40 +++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/apps/simple-camera/__tests__/visioncamera.video.harness.ts b/apps/simple-camera/__tests__/visioncamera.video.harness.ts index bfbe141d56..e8a24d3ca9 100644 --- a/apps/simple-camera/__tests__/visioncamera.video.harness.ts +++ b/apps/simple-camera/__tests__/visioncamera.video.harness.ts @@ -34,6 +34,46 @@ describe('VisionCamera - Video', () => { backDevice = back }) + // Reproduces a hard, uncatchable crash: calling setOutputSettings({ codec }) + // after a `targetBitRate` was configured aborts the process (SIGTRAP), so the + // harness app dies rather than this assertion failing cleanly. + // + // `setOutputSettings` reads the fully-expanded `output.outputSettings(for:)` + // dict and writes it back. When `targetBitRate` is set, that dict already + // contains AVVideoCompressionPropertiesKey plus width/height/color keys. + // `AVCaptureMovieFileOutput.setOutputSettings:forConnection:` rejects the + // non-codec/compression keys with an Objective-C NSInvalidArgumentException, + // which Swift cannot catch — no JS try/catch can prevent the abort. + // + // Expected (fixed) behavior: setOutputSettings resolves without crashing. + it('setOutputSettings({ codec }) does not crash when a targetBitRate is configured', async () => { + const session = await VisionCamera.createCameraSession(false) + const videoOutput = VisionCamera.createVideoOutput({ + targetResolution: CommonResolutions.HD_16_9, + enableAudio: false, + // Populating targetBitRate makes the connection's expanded outputSettings + // include AVVideoCompressionPropertiesKey, which triggers the crash below. + targetBitRate: 2_000_000, + }) + await session.configure([ + { + input: backDevice, + outputs: [{ output: videoOutput, mirrorMode: 'auto' }], + constraints: [], + }, + ]) + await session.start() + + try { + // On current main this aborts the whole process via an uncatchable ObjC + // exception. With the bug fixed, it resolves. + await videoOutput.setOutputSettings({ codec: 'h264' }) + } finally { + await session.stop() + } + // Reaching here without the app crashing means the bug is fixed. + }) + it('records a short clip and finishes with reason "stopped"', async () => { const session = await VisionCamera.createCameraSession(false) const videoOutput = VisionCamera.createVideoOutput({