Skip to content

[camera] Low Resolution in Camera Image Stream, ResolutionPreset Constructor Parameter is ignored #78247

Open

Description

@Joshua27

Hi,
I would like to process images from the camera while previewing the camera images using the camera plugin. I do not want to transform the preview image or draw anything on the previewed image.
From my understanding the function CameraController#startImageStream() is supposed to be used for such tasks.
This works as expected except of the point that the images send to the image stream only have 720p resolution or lower regardless what ResolutionPreset is set when constructing the CameraController

Steps to Reproduce

Goal: Process images from the camera in best available resolution (send to isolates to not block the main isolate) while previewing the camera images.

Most important parts of the implementation:

Create controller:

_controller = CameraController(
  cameraDescription,
  ResolutionPreset.max,
  enableAudio: false,
);

Show camera preview using widget:

CameraPreview(_controller)

Listen to image stream:

_controller.startImageStream((image) {
        print("Image size: ${image.width}x${image.height}");
      });

The CameraDescription is provided by onNewCameraSelected() as demonstrated in the example provided along with this camera plugin.
To reproduce this issue you can run the example provided in this package and listen to the image stream while previewing the camera images.

Expected results: Maximum available image resolution in the image stream. My devices should have 4k resolution (or at least Full-HD).

Actual results: Always 720p (or lower if requested).

Tested Devices: Samsung Galaxy S10 and S10e

The constructor parameter of CameraController defining ResolutionPreset is ignored/overwritten if it is greater than ResolutionPreset.high.
As already pointed out in issue #49420, the following function in the camera plugin is the reason for this behavior:

static Size computeBestPreviewSize(String cameraName, ResolutionPreset preset) {
    if (preset.ordinal() > ResolutionPreset.high.ordinal()) {
      preset = ResolutionPreset.high;
    }
    CamcorderProfile profile =
        getBestAvailableCamcorderProfileForResolutionPreset(cameraName, preset);
    return new Size(profile.videoFrameWidth, profile.videoFrameHeight);
  }

I see the point that the resolution has to be scaled down for preview.
However, there should be a possibility to process the camera images in the specified resolution.
It should be up to the developer to not block the main thread when listening to an image stream.

My current workaround is to build the camera plugin locally and change CameraUtils#computeBestPreviewSize() as follows:

static Size computeBestPreviewSize(String cameraName, ResolutionPreset preset) {
    //if (preset.ordinal() > ResolutionPreset.high.ordinal()) {
    //  preset = ResolutionPreset.high;
    //}
    CamcorderProfile profile =
        getBestAvailableCamcorderProfileForResolutionPreset(cameraName, preset);
    return new Size(profile.videoFrameWidth, profile.videoFrameHeight);
  }

Of course, this now slows down the camera preview on older devices or is really slow if 4K resolution is used.
Yet, I couldn't find a way to downscale the image before being previewed using above initialization.
I was able to improve performance for previewing a little by changing line 35 of camera_preview.dart from

CameraPlatform.instance.buildPreview(controller.cameraId)

to

Texture(textureId: controller.cameraId, filterQuality: FilterQuality.none)

The default setting of the parameter filterQuality is FilterQuality.low, which is currently used.
According to the documentation of FilterQuality the setting FilterQuality.none is faster.

Summary: Is it currently possible to process the camera images with the requested resolution while previewing the camera images in a lower resolution?

If this is not the case, I would like to request the feature to add another image stream to CameraController which is not used for previewing as described above. The images in the stream used for previewing can be downscaled, that's fine.
Alternatively, one might be able to add an additional constructor parameter and field to CameraController which defines the preview size (use to downscale before actual preview) while the images send to the single image stream have the requested resolution.
Of course, if I select a large preview size the performance is bad. But this decision should be adjustable and up to the developer.

Output of `flutter-doctor -v`
[✓] Flutter (Channel stable, 2.0.2, on Linux, locale de_DE.UTF-8) • Flutter version 2.0.2 at /home/joshua/snap/flutter/common/flutter • Framework revision 8962f6d (vor 4 Tagen), 2021-03-11 13:22:20 -0800 • Engine revision 5d8bf81 • Dart version 2.12.1

[!] Android toolchain - develop for Android devices (Android SDK version 30.0.2)
• Android SDK at /home/joshua/Android/Sdk
• Platform android-30, build-tools 30.0.2
• Java binary at: /usr/lib/jvm/java-8-oracle/bin/java
• Java version Java(TM) SE Runtime Environment (build 1.8.0_201-b09)
! Some Android licenses not accepted. To resolve this, run: flutter doctor --android-licenses

[✗] Chrome - develop for the web (Cannot find Chrome executable at google-chrome)
! Cannot find Chrome. Try setting CHROME_EXECUTABLE to a Chrome executable.

[!] Android Studio (not installed)
• Android Studio not found; download from https://developer.android.com/studio/index.html
(or visit https://flutter.dev/docs/get-started/install/linux#android-setup for detailed instructions).

[✓] IntelliJ IDEA Ultimate Edition (version 2019.1)
• IntelliJ at /home/joshua/.local/share/JetBrains/Toolbox/apps/IDEA-U/ch-0/191.6183.87
• Flutter plugin can be installed from:
🔨 https://plugins.jetbrains.com/plugin/9212-flutter
• Dart plugin can be installed from:
🔨 https://plugins.jetbrains.com/plugin/6351-dart

[✓] IntelliJ IDEA Ultimate Edition (version 2020.3)
• IntelliJ at /home/joshua/.local/share/JetBrains/Toolbox/apps/IDEA-U/ch-0/203.7148.57
• Flutter plugin can be installed from:
🔨 https://plugins.jetbrains.com/plugin/9212-flutter
• Dart plugin can be installed from:
🔨 https://plugins.jetbrains.com/plugin/6351-dart

[✓] VS Code (version 1.52.1)
• VS Code at /usr/share/code
• Flutter extension can be installed from:
🔨 https://marketplace.visualstudio.com/items?itemName=Dart-Code.flutter

[✓] Connected device (2 available)
• SM G970F (mobile) • RF8M20WXQAA • android-arm64 • Android 10 (API 29)
• SM G973F (mobile) • RF8N40DYR5Y • android-arm64 • Android 11 (API 30)

! Doctor found issues in 3 categories.

The issue #58163 seems to be related as well.

Greetings,
Joshua

Activity

  1. darshankawar commented on Mar 16, 2021

    @darshankawar
    Member

    Thanks @Joshua27 for a detailed report. It'd be great if you could also provide a minimal reproducible code sample that we can directly use alongwith actual vs expected behavior to properly address this issue.

  2. added
    waiting for responseThe Flutter team cannot make further progress on this issue until the original reporter responds
    on Mar 16, 2021
  3. Joshua27 commented on Mar 16, 2021

    @Joshua27
    Author

    Thank you for the quick response. I created a minimum reproducible example which you can find here: https://github.com/Joshua27/flutter_issue_78247

  4. removed
    waiting for responseThe Flutter team cannot make further progress on this issue until the original reporter responds
    on Mar 16, 2021
  5. darshankawar commented on Mar 16, 2021

    @darshankawar
    Member

    Thanks for repo.

    flutter doctor -v
    Downloading darwin-x64/font-subset tools...                        292ms
    [✓] Flutter (Channel stable, 2.0.2, on Mac OS X 10.15.4 19E2269 darwin-x64,
        locale en-GB)
        • Flutter version 2.0.2 at /Users/dhs/documents/Fluttersdk/flutter
        • Framework revision 8962f6dc68 (4 days ago), 2021-03-11 13:22:20 -0800
        • Engine revision 5d8bf811b3
        • Dart version 2.12.1
    
    [!] Xcode - develop for iOS and macOS
        • Xcode at /Applications/Xcode.app/Contents/Developer
        • Xcode 12.3, Build version 12C33
        ! CocoaPods 1.9.3 out of date (1.10.0 is recommended).
            CocoaPods is used to retrieve the iOS and macOS platform side's plugin
            code that responds to your plugin usage on the Dart side.
            Without CocoaPods, plugins will not work on iOS or macOS.
            For more info, see https://flutter.dev/platform-plugins
          To upgrade see
          https://guides.cocoapods.org/using/getting-started.html#installation for
          instructions.
    
    [✓] Chrome - develop for the web
        • Chrome at /Applications/Google Chrome.app/Contents/MacOS/Google Chrome
    
    [✓] VS Code (version 1.54.1)
        • VS Code at /Applications/Visual Studio Code.app/Contents
        • Flutter extension version 3.18.1
    
    [✓] Connected device (3 available)
        • iPhone 12 Pro Max (mobile) • A5473606-0213-4FD8-BA16-553433949729 • ios
          • com.apple.CoreSimulator.SimRuntime.iOS-14-3 (simulator)
        • macOS (desktop)            • macos                                •
          darwin-x64     • Mac OS X 10.15.4 19E2269 darwin-x64
        • Chrome (web)               • chrome                               •
          web-javascript • Google Chrome 89.0.4389.82
    
    ! Doctor found issues in 1 category.
    
    
  6. added
    has reproducible stepsThe issue has been confirmed reproducible and is ready to work on
    and removed
    in triagePresently being triaged by the triage team
    on Mar 16, 2021
  7. added
    P2Important issues not at the top of the work list
    on Mar 18, 2021
  8. mamuseferha commented on Oct 26, 2021

    @mamuseferha

    Hi @Joshua27
    Thanks for filing the issue, I verified this on the latest stable and the master channel with camera: ^0.9.4+3 and the issue is reproducible.

    code sample
    import 'package:camera/camera.dart';
    import 'package:flutter/material.dart';
    import 'package:flutter/services.dart';
    
    /// The current device's available cameras.
    List<CameraDescription> cameras = [];
    
    /// Init available cameras once on startup.
    Future<void> init() async {
      WidgetsFlutterBinding.ensureInitialized();
      try {
        cameras = await availableCameras();
      } on CameraException catch (e) {
        _logError(e.code, e.description ?? '');
      }
    }
    
    void main() {
      init();
      SystemChrome.setPreferredOrientations([DeviceOrientation.portraitUp])
          .then((_) {
        runApp(MyApp());
      });
    }
    
    /// Minimal reproducible example showing that we can't get a better resolution
    /// than 720p in the image stream provided by the camera plugin.
    class MyApp extends StatelessWidget {
      // This widget is the root of your application.
      @override
      Widget build(BuildContext context) {
        return MaterialApp(
          title: 'Camera Plugin Low Resolution',
          theme: ThemeData(
            primarySwatch: Colors.blue,
          ),
          home: CameraExampleHome(),
        );
      }
    }
    
    /// Stateful widget.
    class CameraExampleHome extends StatefulWidget {
      @override
      _CameraExampleHomeState createState() {
        return _CameraExampleHomeState();
      }
    }
    
    /// Returns a suitable camera icon for [direction].
    IconData getCameraLensIcon(CameraLensDirection direction) {
      switch (direction) {
        case CameraLensDirection.back:
          return Icons.camera_rear;
        case CameraLensDirection.front:
          return Icons.camera_front;
        case CameraLensDirection.external:
          return Icons.camera;
      }
    }
    
    void _logError(String code, String message) => print("Error #$code: $message");
    
    class _CameraExampleHomeState extends State<CameraExampleHome>
        with WidgetsBindingObserver {
      final GlobalKey<ScaffoldState> _scaffoldKey = GlobalKey<ScaffoldState>();
    
      CameraController? _controller;
    
      @override
      void initState() {
        super.initState();
        WidgetsBinding.instance?.addObserver(this);
      }
    
      @override
      void dispose() {
        WidgetsBinding.instance?.removeObserver(this);
        _controller?.dispose();
        super.dispose();
      }
    
      @override
      void didChangeAppLifecycleState(AppLifecycleState state) {
        if (_controller == null || !_controller!.value.isInitialized) {
          return;
        }
        if (state == AppLifecycleState.inactive) {
          _controller?.dispose();
        } else if (state == AppLifecycleState.resumed) {
          if (_controller != null) {
            onNewCameraSelected(_controller!.description);
          }
        }
      }
    
      Widget _cameraPreviewWidget() {
        if (_controller == null || !_controller!.value.isInitialized) {
          return TextButton(
              onPressed: () {},
              child: Text('Select a camera',
                  style: TextStyle(
                    color: Colors.black,
                    fontSize: 24.0,
                    fontWeight: FontWeight.w900,
                  )));
        } else {
          return Stack(
            fit: StackFit.expand,
            children: <Widget>[CameraPreview(_controller!)],
          );
        }
      }
    
      Widget _cameraTogglesRowWidget() {
        final List<Widget> toggles = <Widget>[];
    
        if (cameras.isEmpty) {
          return Text("No Camera Found");
        } else {
          for (CameraDescription cameraDescription in cameras) {
            toggles.add(Expanded(
                flex: 1,
                child: RadioListTile<CameraDescription>(
                  title: Icon(getCameraLensIcon(cameraDescription.lensDirection)),
                  groupValue: _controller?.description,
                  value: cameraDescription,
                  onChanged: (CameraDescription? value) {
                    onNewCameraSelected(value!);
                  },
                )));
          }
        }
        return Row(children: toggles, mainAxisAlignment: MainAxisAlignment.start);
      }
    
      void onNewCameraSelected(final CameraDescription cameraDescription) async {
        await _controller?.dispose();
    
        // TODO: here we request max resolution
        _controller = CameraController(cameraDescription, ResolutionPreset.max,
            enableAudio: false);
    
        try {
          await _controller?.initialize();
        } on CameraException catch (e) {
          _logError(e.code, e.description ?? '');
        }
    
        if (mounted) {
          setState(() {});
          await _controller?.startImageStream((image) {
            // TODO: the maximum we receive here is 720p
            print("Actual image size: ${image.width}x${image.height}");
          });
        }
      }
    
      @override
      Widget build(BuildContext context) {
        return Scaffold(
            key: _scaffoldKey,
            appBar: AppBar(
                title: Text("Camera Plugin Low Resolution"),
                backgroundColor: Colors.white),
            body: Column(children: <Widget>[
              Expanded(
                  child: Container(
                      child: Padding(
                          padding: const EdgeInsets.all(5.0),
                          child: Center(
                            child: _cameraPreviewWidget(),
                          )))),
              Padding(
                  padding: const EdgeInsets.all(5.0),
                  child: Center(
                    child: _cameraTogglesRowWidget(),
                  ))
            ]));
      }
    }
    
    flutter doctor -v
    [✓] Flutter (Channel stable, 2.5.3, on macOS 11.5.2 20G95 darwin-x64, locale en-US)
        • Flutter version 2.5.3 at /Users/flo/development/flutter
        • Upstream repository https://github.com/flutter/flutter.git
        • Framework revision 18116933e7 (10 days ago), 2021-10-15 10:46:35 -0700
        • Engine revision d3ea636dc5
        • Dart version 2.14.4
    
    [!] Android toolchain - develop for Android devices (Android SDK version 31.0.0)
        • Android SDK at /Users/flo/Library/Android/sdk
        • Platform android-31, build-tools 31.0.0
        • Java binary at: /Applications/Android Studio.app/Contents/jre/Contents/Home/bin/java
        • Java version OpenJDK Runtime Environment (build 11.0.10+0-b96-7281165)
        ! Some Android licenses not accepted.  To resolve this, run: flutter doctor --android-licenses
    
    [✓] Xcode - develop for iOS and macOS
        • Xcode at /Applications/Xcode.app/Contents/Developer
        • Xcode 13.0, Build version 13A5212g
        • CocoaPods version 1.11.0
    
    [✓] Chrome - develop for the web
        • Chrome at /Applications/Google Chrome.app/Contents/MacOS/Google Chrome
    
    [✓] Android Studio (version 2020.3)
        • Android Studio at /Applications/Android Studio.app/Contents
        • Flutter plugin can be installed from:
          🔨 https://plugins.jetbrains.com/plugin/9212-flutter
        • Dart plugin can be installed from:
          🔨 https://plugins.jetbrains.com/plugin/6351-dart
        • Java version OpenJDK Runtime Environment (build 11.0.10+0-b96-7281165)
    
    [✓] VS Code (version 1.60.0)
        • VS Code at /Applications/Visual Studio Code.app/Contents
        • Flutter extension version 3.27.0
    
    [✓] Connected device (5 available)
        • SM G975U (mobile)          • R58M95MA95E                          • android-arm64  • Android 11 (API 30)
        • sdk gphone x86 (mobile)    • emulator-5554                        • android-x86    • Android 11 (API 30) (emulator)
        • iPhone 12 Pro Max (mobile) • 98CBBFB1-4069-4A28-B7F7-138911ACBE72 • ios            • com.apple.CoreSimulator.SimRuntime.iOS-15-0
          (simulator)
        • macOS (desktop)            • macos                                • darwin-x64     • macOS 11.5.2 20G95 darwin-x64
        • Chrome (web)               • chrome                               • web-javascript • Google Chrome 93.0.4577.63
    
    ! Doctor found issues in 1 category.
    [✓] Flutter (Channel master, 2.6.0-12.0.pre.470, on macOS 11.5.2 20G95 darwin-x64, locale en-US)
        • Flutter version 2.6.0-12.0.pre.470 at /Users/flo/fvm/versions/master
        • Upstream repository https://github.com/flutter/flutter.git
        • Framework revision 9350a149a6 (8 hours ago), 2021-10-25 16:33:05 -0700
        • Engine revision f9bd71bf13
        • Dart version 2.15.0 (build 2.15.0-250.0.dev)
    
    [!] Android toolchain - develop for Android devices (Android SDK version 31.0.0)
        • Android SDK at /Users/flo/Library/Android/sdk
        • Platform android-31, build-tools 31.0.0
        • Java binary at: /Applications/Android Studio.app/Contents/jre/Contents/Home/bin/java
        • Java version OpenJDK Runtime Environment (build 11.0.10+0-b96-7281165)
        ! Some Android licenses not accepted.  To resolve this, run: flutter doctor --android-licenses
    
    [✓] Xcode - develop for iOS and macOS (Xcode 13.0)
        • Xcode at /Applications/Xcode.app/Contents/Developer
        • CocoaPods version 1.11.0
    
    [✓] Chrome - develop for the web
        • Chrome at /Applications/Google Chrome.app/Contents/MacOS/Google Chrome
    
    [✓] Android Studio (version 2020.3)
        • Android Studio at /Applications/Android Studio.app/Contents
        • Flutter plugin can be installed from:
          🔨 https://plugins.jetbrains.com/plugin/9212-flutter
        • Dart plugin can be installed from:
          🔨 https://plugins.jetbrains.com/plugin/6351-dart
        • Java version OpenJDK Runtime Environment (build 11.0.10+0-b96-7281165)
    
    [✓] VS Code (version 1.60.0)
        • VS Code at /Applications/Visual Studio Code.app/Contents
        • Flutter extension version 3.27.0
    
    [✓] Connected device (5 available)
        • SM G975U (mobile)          • R58M95MA95E                          • android-arm64  • Android 11 (API 30)
        • sdk gphone x86 (mobile)    • emulator-5554                        • android-x86    • Android 11 (API 30) (emulator)
        • iPhone 12 Pro Max (mobile) • 98CBBFB1-4069-4A28-B7F7-138911ACBE72 • ios            • com.apple.CoreSimulator.SimRuntime.iOS-15-0 (simulator)
        • macOS (desktop)            • macos                                • darwin-x64     • macOS 11.5.2 20G95 darwin-x64
        • Chrome (web)               • chrome                               • web-javascript • Google Chrome 93.0.4577.63
    
    ! Doctor found issues in 1 category.

    Thank you

  9. 13 remaining items

  10. talalong commented on Jun 4, 2023

    @talalong
  11. Joshua27 commented on Jun 5, 2023

    @Joshua27
    Author

    Such comments have no effect.
    Please upvote the top level comment to give this issue a higher priority.
    See https://github.com/flutter/flutter/wiki/Issue-hygiene

  12. kishan2612 commented on Nov 11, 2024

    @kishan2612
  13. AwaisQazii commented on Dec 26, 2024

    @AwaisQazii

    This workaround fixed the low-quality image preview issue for me.
    I overrode the camera_android_camerax dependency to the latest version, significantly improving the preview quality.

        dependencies:
          camera: ^0.11.0+2
        dependency_overrides:
          camera_android_camerax: ^0.6.10+3
    
  14. GregUAs commented on Feb 13, 2025

    @GregUAs

    This workaround fixed the low-quality image preview issue for me. I overrode the camera_android_camerax dependency to the latest version, significantly improving the preview quality.

        dependencies:
          camera: ^0.11.0+2
        dependency_overrides:
          camera_android_camerax: ^0.6.10+3
    

    Works for me ! Thank you 💯

  15. changed the title [-]Low Resolution in Camera Image Stream, ResolutionPreset Constructor Parameter is ignored[/-] [+][camera] Low Resolution in Camera Image Stream, ResolutionPreset Constructor Parameter is ignored[/+] on Jul 29, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    P2Important issues not at the top of the work listfound in release: 3.3Found to occur in 3.3found in release: 3.4Found to occur in 3.4has reproducible stepsThe issue has been confirmed reproducible and is ready to work onp: cameraThe camera pluginpackageflutter/packages repository. See also p: labels.team-ecosystemOwned by Ecosystem teamtriaged-ecosystemTriaged by Ecosystem team

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions