flutter / flutter

Flutter makes it easy and fast to build beautiful apps for mobile and beyond
https://flutter.dev
BSD 3-Clause "New" or "Revised" License
165.4k stars 27.29k forks source link

iPhone 16 takePicture() with ResolutionPreset.max and camera `built-in_video:5` throw CameraException #156373

Open ming-chu opened 4 days ago

ming-chu commented 4 days ago

Steps to reproduce

  1. create a new flutter project flutter create example
  2. copy the code from sample code to main.dart
  3. update camera & microphone usage description in Info.plist
  4. build the project and run in real device iPhone 16 (iOS Version: 18.0)
  5. click the take picture button at bottom right
  camera: ^0.11.0+2

only camera com.apple.avfoundation.avcapturedevice.built-in_video:5 has problem. It throws exception CameraException(Error -11800, The operation could not be completed).

Maybe related code to set the preset on iOS platform: camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/FLTCam.m image

Error from objective-c code:

  // camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/FLTCam.m

  __weak typeof(self) weakSelf = self;
  FLTSavePhotoDelegate *savePhotoDelegate = [[FLTSavePhotoDelegate alloc]
           initWithPath:path
                ioQueue:self.photoIOQueue
      completionHandler:^(NSString *_Nullable path, NSError *_Nullable error) {
        typeof(self) strongSelf = weakSelf;
        if (!strongSelf) return;
        dispatch_async(strongSelf.captureSessionQueue, ^{
          // cannot use the outter `strongSelf`
          typeof(self) strongSelf = weakSelf;
          if (!strongSelf) return;
          [strongSelf.inProgressSavePhotoDelegates removeObjectForKey:@(settings.uniqueID)];
        });

        NSLog(@">>> error: %@", error);
        if (error) {
          completion(nil, FlutterErrorFromNSError(error));
        } else {
          NSAssert(path, @"Path must not be nil if no error.");
          completion(path, nil);
        }
      }];
>>> error: Error Domain=AVFoundationErrorDomain Code=-11800 "The operation could not be completed" UserInfo={NSUnderlyingError=0x3031fe760 {Error Domain=NSOSStatusErrorDomain Code=-73720 "(null)"}, NSLocalizedFailureReason=An unknown error occurred (-73720), AVErrorRecordingFailureDomainKey=4, NSLocalizedDescription=The operation could not be completed}

Thank you for your tremendous help and contributions to the project!

Expected results

Expect return an image file after calling _contoller.takePicture() without exceptions.

Actual results

when calling _controller.takePicture() it throws exception CameraException(Error -11800, The operation could not be completed).

Code sample

Code sample ```dart import 'dart:async'; import 'dart:io'; import 'package:camera/camera.dart'; import 'package:flutter/material.dart'; Future main() async { WidgetsFlutterBinding.ensureInitialized(); final cameras = await availableCameras(); final firstCamera = cameras.firstWhere( (c) => c.name.endsWith(':5'), orElse: () => cameras.first, ); for (final camera in cameras) { debugPrint('Available camera: ${camera.name}'); } debugPrint('Using camera: ${firstCamera.name}'); // com.apple.avfoundation.avcapturedevice.built-in_video:5 runApp( MaterialApp( theme: ThemeData.dark(), home: TakePictureScreen( camera: firstCamera, ), ), ); } class TakePictureScreen extends StatefulWidget { const TakePictureScreen({ super.key, required this.camera, }); final CameraDescription camera; @override TakePictureScreenState createState() => TakePictureScreenState(); } class TakePictureScreenState extends State { late CameraController _controller; late Future _initializeControllerFuture; @override void initState() { super.initState(); _controller = CameraController(widget.camera, ResolutionPreset.max); _initializeControllerFuture = _controller.initialize(); } @override void dispose() { _controller.dispose(); super.dispose(); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: const Text('Take a picture')), body: FutureBuilder( future: _initializeControllerFuture, builder: (context, snapshot) { if (snapshot.connectionState == ConnectionState.done) { return CameraPreview(_controller); } else { return const Center(child: CircularProgressIndicator()); } }, ), floatingActionButton: FloatingActionButton( onPressed: () async { try { await _initializeControllerFuture; final image = await _controller.takePicture(); if (!context.mounted) return; await Navigator.of(context).push( MaterialPageRoute( builder: (context) => DisplayPictureScreen( imagePath: image.path, ), ), ); } catch (e) { print(e); } }, child: const Icon(Icons.camera_alt), ), ); } } class DisplayPictureScreen extends StatelessWidget { final String imagePath; const DisplayPictureScreen({super.key, required this.imagePath}); @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: const Text('Display the Picture')), body: Image.file(File(imagePath)), ); } } ```

Screenshots or Video

Screenshots / Video demonstration The preview was fine, but when tap the button on bottom right to take a picture will throw exception. ![IMG_0003](https://github.com/user-attachments/assets/49e62eae-22a8-4112-b822-6bf66f91bbc7)

Logs

Logs ```console Launching lib/main.dart on iPhone16 in debug mode... Automatically signing iOS for device deployment using specified development team in Xcode project: ********** Running Xcode build... Xcode build done. 9.8s Installing and launching... You may be prompted to give access to control Xcode. Flutter uses Xcode to run your app. If access is not allowed, you can change this through your Settings > Privacy & Security > Automation. Debug service listening on ws://127.0.0.1:64936/***********=/ws Syncing files to device iPhone16... flutter: Available camera: com.apple.avfoundation.avcapturedevice.built-in_video:0 flutter: Available camera: com.apple.avfoundation.avcapturedevice.built-in_video:1 flutter: Available camera: com.apple.avfoundation.avcapturedevice.built-in_video:2 flutter: Available camera: com.apple.avfoundation.avcapturedevice.built-in_video:5 flutter: Using camera: com.apple.avfoundation.avcapturedevice.built-in_video:5 flutter: CameraException(Error -11800, The operation could not be completed) ```

Flutter Doctor output

Doctor output ```console > flutter doctor Doctor summary (to see all details, run flutter doctor -v): [✓] Flutter (Channel stable, 3.24.1, on macOS 15.0.1 24A348 darwin-arm64, locale en-CA) [✓] Android toolchain - develop for Android devices (Android SDK version 35.0.0) [✓] Xcode - develop for iOS and macOS (Xcode 16.0) [✓] Chrome - develop for the web [✓] Android Studio (version 2024.1) [✓] Connected device (6 available) [✓] Network resources • No issues found! > flutter --version Flutter 3.24.1 • channel stable • https://github.com/flutter/flutter.git Framework • revision 5874a72aa4 (7 weeks ago) • 2024-08-20 16:46:00 -0500 Engine • revision c9b9d5780d Tools • Dart 3.5.1 • DevTools 2.37.2 ```
huycozy commented 4 days ago

Thank you for the report! I don't have such a device to give this a test. Marking this as a device-specific issue for other's input.

ming-chu commented 3 days ago

well, Code=-11800 is AVErrorUnknown

I have no clue for it so far...🫠