Repository navigation
Description
Steps to reproduce
Take a picture while a video recording is in progress — a combination explicitly supported since camera_android 0.10.8+3 ("Adds support for concurrently capturing images and image streaming/recording").
final List<CameraDescription> cameras = await availableCameras();
final CameraController controller = CameraController(
cameras.first,
ResolutionPreset.high,
enableAudio: false,
);
await controller.initialize();
await controller.startVideoRecording();
await Future<void>.delayed(const Duration(seconds: 3));
// Supported since 0.10.8+3.
await controller.takePicture();
await Future<void>.delayed(const Duration(seconds: 3));
final XFile video = await controller.stopVideoRecording();
print(video.path);
// .../cache/CAP7719046239.jpg <-- a JPEG, not the recording
final Uint8List head = (await File(video.path).readAsBytes()).sublist(0, 4);
print(head);
// [255, 216, 255, 225] <-- ff d8 ff e1 = JPEG SOI + APP1
Expected results
stopVideoRecording() returns the path of the REC*.mp4 created by startVideoRecording().
Actual results
It returns the path of the CAP*.jpg created by the intervening takePicture().
No exception is thrown. MediaRecorder finalizes the real REC*.mp4 correctly — the recording is fine, only the returned path is wrong, and that file is left orphaned in the cache directory with nothing referencing it.
Because the returned XFile is a plausible, non-empty, fully-written file, size- or readability-based validation does not catch it. An app that saves or uploads whatever stopVideoRecording() hands back will silently store a photo in place of the video. We hit this in production: a recording was stored and served as video/mp4 while the bytes were a complete JPEG, and the real video was lost when the OS reclaimed the cache directory.
Root cause
// Camera.java uses a single field for both still capture and video recording, and nothing saves or restores it:
private File captureFile; // line 138
// takePicture() — line 640
captureFile = File.createTempFile("CAP", ".jpg", outputDir);
// prepareRecording() — line 1303
captureFile = File.createTempFile("REC", ".mp4", outputDir);
// stopVideoRecording() — line 922
String path = captureFile.getAbsolutePath(); // whichever was set last
captureFile = null;
return path;
takePicture() also has no recordingVideo guard — its only precondition is cameraCaptureCallback.getCameraState() != CameraState.STATE_PREVIEW, which an in-progress video recording passes — so it neither declines nor warns; it simply overwrites the field.
The only captureFile = null after a picture sits in startVideoRecording()'s catch block, so the JPEG path persists until stopVideoRecording() reads it.
Line numbers above are from 0.10.11+1; the same code exists in 0.10.10 at lines 131 / 620 / 1241 / 868.
Suggested fix
Separate the two paths — e.g. a dedicated videoRecordingFile field set by prepareRecording() and read by stopVideoRecording(), leaving captureFile to still capture. A narrower fix would be to save and restore captureFile around takePicture().
Code sample
See "Steps to reproduce" above.
Logs / evidence
The returned file's header, read straight from the path stopVideoRecording() returned:
magic bytes : ff d8 ff e1 -> JPEG SOI + APP1
trailer : ff d9 -> complete, valid JPEG
EXIF : samsung, SM-X205, Software Version v1.1.0
The EXIF capture timestamp matches the moment takePicture() was called, ~8 minutes before stopVideoRecording() was invoked — confirming it is the picture's file and not a truncated recording.
Affected versions
Reproduced on camera_android 0.10.10, and the same code is present in 0.10.11+1 (latest, published 2026-08-28). Nothing in the changelog between those versions touches it.
Note camera_android_camerax is not a workaround for apps that need bitrate/fps control: android_camera_camerax.dart calls proxy.newRecorder(qualitySelector: ...) without targetVideoEncodingBitRate, and has no fps handling at all (see #187149).
Related: #96676 (proposal to take a picture while video recording is in progress — the feature this bug breaks).
Device
Samsung SM-X205 (Galaxy Tab A8), Android.
flutter doctor
[√] Flutter (Channel stable, 3.27.0, on Microsoft Windows [Version 10.0.26200.8246], locale en-IN)
[√] Windows Version (Installed version of Windows is version 10 or higher)
[√] Android toolchain - develop for Android devices (Android SDK version 36.1.0)
[√] Chrome - develop for the web
[√] Visual Studio - develop Windows apps (Visual Studio Community 2022 17.14.35)
[√] Android Studio (version 2025.3.1)
[√] VS Code
[√] Connected device (4 available)
[√] Network resources
• No issues found!
Activity
mbcorona commentedon Sep 17, 2026
hi @raggi , thanks for reporting.
takePicture and video recording share one captureFile field, so a picture taken mid recording overwrites it and stopVideoRecording returns the JPEG path instead of the mp4.
https://github.com/flutter/packages/blob/485671d24a9088fe8dfff850242ccf0ffc0b6b9a/packages/camera/camera_android/android/src/main/java/io/flutter/plugins/camera/Camera.java#L138
Routing to team-android.
[camera_android] Fix stopVideoRecording returning JPEG path during re…
[camera_android] Fix stopVideoRecording returning JPEG path during re…
[camera_android] Fix stopVideoRecording returning JPEG path during re…
[camera_android] Fix stopVideoRecording returning JPEG path during re…
[camera_android] Fix stopVideoRecording returning JPEG when takePictu…