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
166.12k stars 27.43k forks source link

[camera_android_camerax] Camera Image Stream is randomly stopping #152763

Open RishabhK12 opened 3 months ago

RishabhK12 commented 3 months ago

What package does this bug report belong to?

camera

What target platforms are you seeing this bug on?

Android

Have you already upgraded your packages?

Yes

Steps to reproduce

  1. Execute flutter run on the code below. This is using the latest version 0.11.0+1.
  2. Wait and watch for the platform exception below to appear in the terminal. It usually happens after running it for a while. You may have to tap your phone every little bit to prevent it from falling asleep. Move the phone around a bit so the camera does some work.

Expected results

No exception is output and the image stream never stops.

Actual results

The image stream stops and the platform exception shown below in the log is output. This happens randomly, sometimes after running it for a few minutes, other times after running it for longer like 8ish minutes. This has been run on an s23 ultra. It happens quicker if I do something with the image that the stream is giving me. It doesn't happen if I comment out the startImageStream line.

Code sample

Code sample ```dart import 'package:camera/camera.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; void main() async { WidgetsFlutterBinding.ensureInitialized(); await SystemChrome.setPreferredOrientations([DeviceOrientation.portraitUp]); runApp(const MyApp()); } class MyApp extends StatelessWidget { const MyApp({super.key}); @override Widget build(BuildContext context) => MaterialApp( title: 'Stream Test', theme: ThemeData( primarySwatch: Colors.blue, visualDensity: VisualDensity.adaptivePlatformDensity, ), home: const CameraWidget(), ); } class CameraWidget extends StatefulWidget { const CameraWidget({super.key}); @override State createState() => _CameraWidgetState(); } class _CameraWidgetState extends State with WidgetsBindingObserver { late List cameras; CameraController? _cameraController; get _controller => _cameraController; @override void initState() { super.initState(); WidgetsBinding.instance.addObserver(this); _initStateAsync(); } void _initStateAsync() async { _initializeCamera(); } void _initializeCamera() async { cameras = await availableCameras(); _cameraController = CameraController( cameras[0], ResolutionPreset.high, enableAudio: false, )..initialize().then((_) async { await _controller.startImageStream(onLatestImageAvailable); setState(() {}); }); } @override Widget build(BuildContext context) { if (_cameraController == null || !_controller.value.isInitialized) { return const SizedBox.shrink(); } var aspect = 1 / _controller.value.aspectRatio; return Stack( children: [ AspectRatio( aspectRatio: aspect, child: CameraPreview(_controller), ) ], ); } void onLatestImageAvailable(CameraImage cameraImage) async { } @override void didChangeAppLifecycleState(AppLifecycleState state) async { switch (state) { case AppLifecycleState.inactive: _cameraController?.stopImageStream(); break; case AppLifecycleState.resumed: _initStateAsync(); break; default: } } @override void dispose() { WidgetsBinding.instance.removeObserver(this); _cameraController?.dispose(); super.dispose(); } } ```

Screenshots or Videos

Screenshots / Video demonstration [Upload media here]

Logs

Logs ```console I/CameraManagerGlobal( 8806): Camera 0 facing CAMERA_FACING_BACK state now CAMERA_STATE_CLOSED for client com.example.lamp API Level 2 User Id 0 I/CameraManagerGlobal( 8806): Camera 1 facing CAMERA_FACING_FRONT state now CAMERA_STATE_CLOSED for client com.snapchat.android API Level 2 User Id 0 I/CameraManagerGlobal( 8806): Camera 2 facing CAMERA_FACING_BACK state now CAMERA_STATE_CLOSED for client android.system API Level 2 User Id 0 I/CameraManagerGlobal( 8806): Camera 20 facing CAMERA_FACING_BACK state now CAMERA_STATE_CLOSED for client com.sec.android.app.camera API Level 2 User Id 0 I/CameraManagerGlobal( 8806): Camera 21 facing CAMERA_FACING_BACK state now CAMERA_STATE_CLOSED for client android.system API Level 2 User Id 0 I/CameraManagerGlobal( 8806): Camera 23 facing CAMERA_FACING_BACK state now CAMERA_STATE_CLOSED for client android.system API Level 2 User Id 0 I/CameraManagerGlobal( 8806): Camera 3 facing CAMERA_FACING_FRONT state now CAMERA_STATE_CLOSED for client android.system API Level 2 User Id 0 I/CameraManagerGlobal( 8806): Camera 4 facing CAMERA_FACING_FRONT state now CAMERA_STATE_CLOSED for client android.system API Level 2 User Id 0 I/CameraManagerGlobal( 8806): Camera 52 facing CAMERA_FACING_BACK state now CAMERA_STATE_CLOSED for client android.system API Level 2 User Id 0 I/CameraManagerGlobal( 8806): Camera 54 facing CAMERA_FACING_BACK state now CAMERA_STATE_CLOSED for client android.system API Level 2 User Id 0 I/CameraManagerGlobal( 8806): Camera 56 facing CAMERA_FACING_BACK state now CAMERA_STATE_CLOSED for client com.sec.android.app.camera API Level 2 User Id 0 I/CameraManagerGlobal( 8806): Camera 58 facing CAMERA_FACING_BACK state now CAMERA_STATE_CLOSED for client android.system API Level 2 User Id 0 I/CameraManagerGlobal( 8806): Camera 90 facing CAMERA_FACING_FRONT state now CAMERA_STATE_CLOSED for client android.system API Level 2 User Id 0 D/CameraRepository( 8806): Added camera: 0 I/Camera2CameraInfo( 8806): Device Level: INFO_SUPPORTED_HARDWARE_LEVEL_3 I/CameraManager( 8806): registerAvailabilityCallback: Is device callback = false I/CameraManagerGlobal( 8806): postSingleUpdate device: camera id 0 status STATUS_PRESENT I/CameraManagerGlobal( 8806): postSingleUpdate device: camera id 1 status STATUS_PRESENT I/CameraManagerGlobal( 8806): postSingleUpdate device: camera id 2 status STATUS_PRESENT I/CameraManagerGlobal( 8806): postSingleUpdate device: camera id 3 status STATUS_PRESENT D/CameraRepository( 8806): Added camera: 1 I/Camera2CameraInfo( 8806): Device Level: INFO_SUPPORTED_HARDWARE_LEVEL_FULL I/CameraManager( 8806): registerAvailabilityCallback: Is device callback = false I/CameraManagerGlobal( 8806): postSingleUpdate device: camera id 0 status STATUS_PRESENT I/CameraManagerGlobal( 8806): postSingleUpdate device: camera id 1 status STATUS_PRESENT I/CameraManagerGlobal( 8806): postSingleUpdate device: camera id 2 status STATUS_PRESENT I/CameraManagerGlobal( 8806): postSingleUpdate device: camera id 3 status STATUS_PRESENT D/CameraRepository( 8806): Added camera: 2 I/Camera2CameraInfo( 8806): Device Level: INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED I/CameraManager( 8806): registerAvailabilityCallback: Is device callback = false I/CameraManagerGlobal( 8806): postSingleUpdate device: camera id 0 status STATUS_PRESENT I/CameraManagerGlobal( 8806): postSingleUpdate device: camera id 1 status STATUS_PRESENT I/CameraManagerGlobal( 8806): postSingleUpdate device: camera id 2 status STATUS_PRESENT I/CameraManagerGlobal( 8806): postSingleUpdate device: camera id 3 status STATUS_PRESENT D/CameraRepository( 8806): Added camera: 3 I/Camera2CameraInfo( 8806): Device Level: INFO_SUPPORTED_HARDWARE_LEVEL_FULL I/CameraManager( 8806): registerAvailabilityCallback: Is device callback = false I/CameraManagerGlobal( 8806): postSingleUpdate device: camera id 0 status STATUS_PRESENT I/CameraManagerGlobal( 8806): postSingleUpdate device: camera id 1 status STATUS_PRESENT I/CameraManagerGlobal( 8806): postSingleUpdate device: camera id 2 status STATUS_PRESENT I/CameraManagerGlobal( 8806): postSingleUpdate device: camera id 3 status STATUS_PRESENT D/CameraValidator( 8806): Verifying camera lens facing on dm3q, lensFacingInteger: null I/BLASTBufferQueue( 8806): [SurfaceView[com.example.lamp/com.example.live_object_detection_ssd_mobilenet.MainActivity]@0#1](f:0,a:0,s:0) onFrameAvailable the first frame is available D/SurfaceView@98475c0( 8806): 159675840 setAlpha: alpha=1.0 I/SurfaceView( 8806): 159675840 Changes: creating=false format=false size=false visible=false alpha=true hint=false visible=false left=false top=false z=false attached=true lifecycleStrategy=false I/SurfaceView@98475c0( 8806): 159675840 Cur surface: Surface(name=null)/@0xafedb05 I/SurfaceView@98475c0( 8806): updateSurface: mVisible = true mSurface.isValid() = true I/SurfaceView@98475c0( 8806): updateSurface: mSurfaceCreated = true surfaceChanged = false visibleChanged = false I/SurfaceView( 8806): 159675840 surfaceRedrawNeeded I/SurfaceView( 8806): 159675840 finishedDrawing V/SurfaceView@98475c0( 8806): Layout: x=0 y=0 w=1440 h=3032, frame=Rect(0, 0 - 1440, 3032) I/ViewRootImpl@70d56ee[MainActivity]( 8806): Setup new sync=wmsSync-ViewRootImpl@70d56ee[MainActivity]#2 I/ViewRootImpl@70d56ee[MainActivity]( 8806): Creating new active sync group ViewRootImpl@70d56ee[MainActivity]#3 I/ViewRootImpl@70d56ee[MainActivity]( 8806): registerCallbacksForSync syncBuffer=false D/SurfaceView( 8806): 159675840 updateSurfacePosition RenderWorker, frameNr = 1, position = [0, 0, 1440, 3032] surfaceSize = 1440x3032 I/SurfaceView@98475c0( 8806): uSP: rtp = Rect(0, 0 - 1440, 3032) rtsw = 1440 rtsh = 3032 I/SurfaceView@98475c0( 8806): onSSPAndSRT: pl = 0 pt = 0 sx = 1.0 sy = 1.0 I/SurfaceView@98475c0( 8806): aOrMT: ViewRootImpl@70d56ee[MainActivity] t = android.view.SurfaceControl$Transaction@809abf8 fN = 1 android.view.SurfaceView.-$$Nest$mapplyOrMergeTransaction:0 android.view.SurfaceView$SurfaceViewPositionUpdateListener.positionChanged:1666 android.graphics.RenderNode$CompositePositionUpdateListener.positionChanged:369 I/ViewRootImpl@70d56ee[MainActivity]( 8806): mWNT: t=0xb4000079b4d5a880 mBlastBufferQueue=0xb4000079b5b31d00 fn= 1 mRenderHdrSdrRatio=1.0 caller= android.view.SurfaceView.applyOrMergeTransaction:1598 android.view.SurfaceView.-$$Nest$mapplyOrMergeTransaction:0 android.view.SurfaceView$SurfaceViewPositionUpdateListener.positionChanged:1666 I/ViewRootImpl@70d56ee[MainActivity]( 8806): Received frameDrawingCallback syncResult=0 frameNum=1. I/ViewRootImpl@70d56ee[MainActivity]( 8806): mWNT: t=0xb4000079b4d9b680 mBlastBufferQueue=0xb4000079b5b31d00 fn= 1 mRenderHdrSdrRatio=1.0 caller= android.view.ViewRootImpl$8.onFrameDraw:13841 android.view.ThreadedRenderer$1.onFrameDraw:792 I/ViewRootImpl@70d56ee[MainActivity]( 8806): Setting up sync and frameCommitCallback I/BLASTBufferQueue( 8806): [ViewRootImpl@70d56ee[MainActivity]#0](f:0,a:0,s:0) onFrameAvailable the first frame is available I/ViewRootImpl@70d56ee[MainActivity]( 8806): Received frameCommittedCallback lastAttemptedDrawFrameNum=1 didProduceBuffer=true D/OpenGLRenderer( 8806): CFMS:: SetUp Pid : 8806 Tid : 8871 I/ViewRootImpl@70d56ee[MainActivity]( 8806): reportDrawFinished seqId=0 D/CameraOrientationUtil( 8806): getRelativeImageRotation: destRotationDegrees=0, sourceRotationDegrees=90, isOppositeFacing=true, result=90 I/ViewRootImpl@70d56ee[MainActivity]( 8806): handleWindowFocusChanged: 1 0 call from android.view.ViewRootImpl.-$$Nest$mhandleWindowFocusChanged:0 D/ViewRootImpl@70d56ee[MainActivity]( 8806): mThreadedRenderer.initializeIfNeeded()#2 mSurface={isValid=true 0xb400007a41542000} D/InputMethodManagerUtils( 8806): startInputInner - Id : 0 I/InputMethodManager( 8806): startInputInner - IInputMethodManagerGlobalInvoker.startInputOrWindowGainedFocus D/CameraOrientationUtil( 8806): getRelativeImageRotation: destRotationDegrees=0, sourceRotationDegrees=270, isOppositeFacing=false, result=270 D/CameraOrientationUtil( 8806): getRelativeImageRotation: destRotationDegrees=0, sourceRotationDegrees=90, isOppositeFacing=true, result=90 D/CameraOrientationUtil( 8806): getRelativeImageRotation: destRotationDegrees=0, sourceRotationDegrees=270, isOppositeFacing=false, result=270 D/InputMethodManagerUtils( 8806): startInputInner - Id : 0 I/InsetsController( 8806): onStateChanged: host=com.example.lamp/com.example.live_object_detection_ssd_mobilenet.MainActivity, from=android.view.ViewRootImpl$ViewRootHandler.handleMessageImpl:7209, state=InsetsState: {mDisplayFrame=Rect(0, 0 - 1440, 3088), mDisplayCutout=DisplayCutout{insets=Rect(0, 100 - 0, 0) waterfall=Insets{left=0, top=0, right=0, bottom=0} boundingRect={Bounds=[Rect(0, 0 - 0, 0), Rect(685, 0 - 756, 100), Rect(0, 0 - 0, 0), Rect(0, 0 - 0, 0)]} cutoutPathParserInfo={CutoutPathParserInfo{displayWidth=1440 displayHeight=3088 physicalDisplayWidth=1440 physicalDisplayHeight=3088 density={3.75} cutoutSpec={M 0,0 H -9.466666666666667 V 26.66666666666667‬ H 9.466666666666667 V 0 H 0 Z @dp} rotation={0} scale={1.0} physicalPixelDisplaySizeRatio={1.0}}}}, mRoundedCorners=RoundedCorners{[RoundedCorner{position=TopLeft, radius=15, center=Point(15, 15)}, RoundedCorner{position=TopRight, radius=15, center=Point(1425, 15)}, RoundedCor ner{position=BottomRight, radius=15, center=Point(1425, 3073)}, RoundedCorner{position=BottomLeft, radius=15, center=Point(15, 3073)}]} mRoundedCornerFrame=Rect(0, 0 - 1440, 3088), mPrivacyIndicatorBounds=PrivacyIndicatorBounds {static bounds=Rect(1275, 0 - 1440, 100) rotation=0}, mDisplayShape=DisplayShape{ spec=-311912193 displayWidth=1440 displayHeight=3088 physicalPixelDisplaySizeRatio=1.0 rotation=0 offsetX=0 offsetY=0 scale=1.0}, mSources= { InsetsSource: {fdc30000 mType=statusBars mFrame=[0,0][1440,100] mVisible=true mFlags=[]}, InsetsSource: {fdc30005 mType=mandatorySystemGestures mFrame=[0,0][1440,145] mVisible=true mFlags=[]}, InsetsSource: {fdc30006 mType=tappableElement mFrame=[0,0][1440,100] mVisible=true mFlags=[]}, InsetsSource: {3 mType=ime mFrame=[0,0][0,0] mVisible=false mFlags=[]}, InsetsSource: {27 mType=displayCutout mFrame=[0,0][1440,100] mVisible=true mFlags=[]}, InsetsSource: {46700001 mType=navigationBars mFrame=[0,3032][1440,3088] mVisible=true mFlags=[SUPPRESS_SCRIM]}, InsetsSource: {46700004 mType=systemGestures mFrame=[0,0][112,3088] mVisible=true mFlags=[]}, InsetsSource: {46700005 mType=mandatorySystemGestures mFrame=[0,2968][1440,3088] mVisible=true mFlags=[]}, InsetsSource: {46700006 mType=tappableElement mFrame=[0,0][0,0] mVisible=true mFlags=[]}, InsetsSource: {46700024 mType=systemGestures mFrame=[1328,0][1440,3088] mVisible=true mFlags=[]} } I/InsetsSourceConsumer( 8806): applyRequestedVisibilityToControl: visible=false, type=ime, host=com.example.lamp/com.example.live_object_detection_ssd_mobilenet.MainActivity D/CameraOrientationUtil( 8806): getRelativeImageRotation: destRotationDegrees=0, sourceRotationDegrees=90, isOppositeFacing=true, result=90 D/CameraOrientationUtil( 8806): getRelativeImageRotation: destRotationDegrees=0, sourceRotationDegrees=90, isOppositeFacing=true, result=90 D/CameraOrientationUtil( 8806): getRelativeImageRotation: destRotationDegrees=0, sourceRotationDegrees=90, isOppositeFacing=true, result=90 D/CameraOrientationUtil( 8806): getRelativeImageRotation: destRotationDegrees=0, sourceRotationDegrees=90, isOppositeFacing=true, result=90 D/CameraOrientationUtil( 8806): getRelativeImageRotation: destRotationDegrees=0, sourceRotationDegrees=90, isOppositeFacing=true, result=90 D/DynamicRangeResolver( 8806): Resolved dynamic range for use case androidx.camera.core.Preview-8e6bdcb0-6edb-464f-b7ac-41df85f444e2 to no compatible HDR dynamic ranges. D/DynamicRangeResolver( 8806): DynamicRange@b98fc00{encoding=UNSPECIFIED, bitDepth=0} D/DynamicRangeResolver( 8806): -> D/DynamicRangeResolver( 8806): DynamicRange@b271283{encoding=SDR, bitDepth=8} D/CameraOrientationUtil( 8806): getRelativeImageRotation: destRotationDegrees=0, sourceRotationDegrees=90, isOppositeFacing=true, result=90 D/DeferrableSurface( 8806): Surface created[total_surfaces=1, used_surfaces=0](androidx.camera.core.processing.SurfaceEdge$SettableSurface@3fea2f5} D/DeferrableSurface( 8806): Surface created[total_surfaces=2, used_surfaces=0](androidx.camera.core.SurfaceRequest$2@4e37971} D/DeferrableSurface( 8806): New surface in use[total_surfaces=2, used_surfaces=1](androidx.camera.core.SurfaceRequest$2@4e37971} D/DeferrableSurface( 8806): use count+1, useCount=1 androidx.camera.core.SurfaceRequest$2@4e37971 D/CameraOrientationUtil( 8806): getRelativeImageRotation: destRotationDegrees=0, sourceRotationDegrees=90, isOppositeFacing=true, result=90 D/ImageCapture( 8806): createPipeline(cameraId: 0, streamSpec: StreamSpec{resolution=1280x720, dynamicRange=DynamicRange@b271283{encoding=SDR, bitDepth=8}, expectedFrameRateRange=[0, 0], implementationOptions=androidx.camera.camera2.impl.Camera2ImplConfig@d174ee2}) D/CompatibilityChangeReporter( 8806): Compat change id reported: 236825255; UID 10071; state: ENABLED D/DeferrableSurface( 8806): Surface created[total_surfaces=3, used_surfaces=1](androidx.camera.core.impl.ImmediateSurface@1c1a273} D/Camera2CameraImpl( 8806): {Camera@3ecadf1[id=0]} Use case androidx.camera.core.ImageCapture-08246426-0a49-416d-96c3-0c6cb8ac64bf259810770 ACTIVE D/UseCaseAttachState( 8806): Active and attached use case: [] for camera: 0 D/CameraOrientationUtil( 8806): getRelativeImageRotation: destRotationDegrees=0, sourceRotationDegrees=90, isOppositeFacing=true, result=90 D/CameraOrientationUtil( 8806): getRelativeImageRotation: destRotationDegrees=0, sourceRotationDegrees=90, isOppositeFacing=true, result=90 D/DeferrableSurface( 8806): Surface created[total_surfaces=4, used_surfaces=1](androidx.camera.core.impl.ImmediateSurface@c89f2cf} D/Camera2CameraImpl( 8806): {Camera@3ecadf1[id=0]} Use case androidx.camera.core.Preview-8e6bdcb0-6edb-464f-b7ac-41df85f444e243639047 ACTIVE D/UseCaseAttachState( 8806): Active and attached use case: [] for camera: 0 D/Camera2CameraImpl( 8806): {Camera@3ecadf1[id=0]} Use case androidx.camera.core.ImageCapture-08246426-0a49-416d-96c3-0c6cb8ac64bf259810770 ACTIVE D/UseCaseAttachState( 8806): Active and attached use case: [] for camera: 0 D/Camera2CameraImpl( 8806): {Camera@3ecadf1[id=0]} Use case androidx.camera.core.ImageAnalysis-67e5fe33-bd23-419f-91ab-2c0f74c15589101068192 INACTIVE D/UseCaseAttachState( 8806): Active and attached use case: [] for camera: 0 D/UseCaseAttachState( 8806): Active and attached use case: [] for camera: 0 D/Camera2CameraImpl( 8806): {Camera@3ecadf1[id=0]} Use cases [androidx.camera.core.Preview-8e6bdcb0-6edb-464f-b7ac-41df85f444e243639047, androidx.camera.core.ImageCapture-08246426-0a49-416d-96c3-0c6cb8ac64bf259810770, androidx.camera.core.ImageAnalysis-67e5fe33-bd23-419f-91ab-2c0f74c15589101068192] now ATTACHED D/UseCaseAttachState( 8806): All use case: [androidx.camera.core.ImageCapture-08246426-0a49-416d-96c3-0c6cb8ac64bf259810770, androidx.camera.core.Preview-8e6bdcb0-6edb-464f-b7ac-41df85f444e243639047, androidx.camera.core.ImageAnalysis-67e5fe33-bd23-419f-91ab-2c0f74c15589101068192] for camera: 0 D/UseCaseAttachState( 8806): Active and attached use case: [androidx.camera.core.ImageCapture-08246426-0a49-416d-96c3-0c6cb8ac64bf259810770, androidx.camera.core.Preview-8e6bdcb0-6edb-464f-b7ac-41df85f444e243639047] for camera: 0 D/Camera2CameraImpl( 8806): {Camera@3ecadf1[id=0]} Resetting Capture Session D/Camera2CameraImpl( 8806): {Camera@3ecadf1[id=0]} Releasing session in state INITIALIZED D/Camera2CameraImpl( 8806): {Camera@3ecadf1[id=0]} Attempting to force open the camera. D/CameraStateRegistry( 8806): tryOpenCamera(Camera@3ecadf1[id=0]) [Available Cameras: 1, Already Open: false (Previous state: null)] --> SUCCESS D/CameraStateRegistry( 8806): Recalculating open cameras: D/CameraStateRegistry( 8806): Camera State D/CameraStateRegistry( 8806): ------------------------------------------------------------------- D/CameraStateRegistry( 8806): Camera@6d4a0e0[id=3] UNKNOWN D/CameraStateRegistry( 8806): Camera@ad080c8[id=2] UNKNOWN D/CameraStateRegistry( 8806): Camera@2322a29[id=1] UNKNOWN D/CameraStateRegistry( 8806): Camera@3ecadf1[id=0] OPENING D/CameraStateRegistry( 8806): ------------------------------------------------------------------- D/CameraStateRegistry( 8806): Open count: 1 (Max allowed: 1) D/Camera2CameraImpl( 8806): {Camera@3ecadf1[id=0]} Opening camera. D/Camera2CameraImpl( 8806): {Camera@3ecadf1[id=0]} Transitioning camera internal state: INITIALIZED --> OPENING D/CameraStateMachine( 8806): New public camera state CameraState{type=OPENING, error=null} from OPENING and null D/CameraStateMachine( 8806): Publishing new public camera state CameraState{type=OPENING, error=null} D/UseCaseAttachState( 8806): All use case: [androidx.camera.core.ImageCapture-08246426-0a49-416d-96c3-0c6cb8ac64bf259810770, androidx.camera.core.Preview-8e6bdcb0-6edb-464f-b7ac-41df85f444e243639047, androidx.camera.core.ImageAnalysis-67e5fe33-bd23-419f-91ab-2c0f74c15589101068192] for camera: 0 D/CameraOrientationUtil( 8806): getRelativeImageRotation: destRotationDegrees=0, sourceRotationDegrees=90, isOppositeFacing=true, result=90 I/CameraManagerGlobal( 8806): Camera 0 facing CAMERA_FACING_BACK state now CAMERA_STATE_OPENING for client com.example.lamp API Level 2 User Id 0 I/CameraManagerGlobal( 8806): postSingleUpdate device: camera id 0 status STATUS_NOT_AVAILABLE I/CameraManagerGlobal( 8806): postSingleUpdate device: camera id 0 status STATUS_NOT_AVAILABLE I/CameraManagerGlobal( 8806): postSingleUpdate device: camera id 0 status STATUS_NOT_AVAILABLE I/CameraManagerGlobal( 8806): postSingleUpdate device: camera id 0 status STATUS_NOT_AVAILABLE I/CameraManagerGlobal( 8806): Camera 0 facing CAMERA_FACING_BACK state now CAMERA_STATE_OPEN for client com.example.lamp API Level 2 User Id 0 D/Camera2CameraImpl( 8806): {Camera@3ecadf1[id=0]} Use case androidx.camera.core.Preview-8e6bdcb0-6edb-464f-b7ac-41df85f444e243639047 ACTIVE D/UseCaseAttachState( 8806): Active and attached use case: [androidx.camera.core.ImageCapture-08246426-0a49-416d-96c3-0c6cb8ac64bf259810770, androidx.camera.core.Preview-8e6bdcb0-6edb-464f-b7ac-41df85f444e243639047] for camera: 0 D/Camera2CameraImpl( 8806): {Camera@3ecadf1[id=0]} Use case androidx.camera.core.ImageCapture-08246426-0a49-416d-96c3-0c6cb8ac64bf259810770 ACTIVE D/UseCaseAttachState( 8806): Active and attached use case: [androidx.camera.core.ImageCapture-08246426-0a49-416d-96c3-0c6cb8ac64bf259810770, androidx.camera.core.Preview-8e6bdcb0-6edb-464f-b7ac-41df85f444e243639047] for camera: 0 D/Camera2CameraImpl( 8806): {Camera@3ecadf1[id=0]} Use case androidx.camera.core.ImageAnalysis-67e5fe33-bd23-419f-91ab-2c0f74c15589101068192 INACTIVE D/UseCaseAttachState( 8806): Active and attached use case: [androidx.camera.core.ImageCapture-08246426-0a49-416d-96c3-0c6cb8ac64bf259810770, androidx.camera.core.Preview-8e6bdcb0-6edb-464f-b7ac-41df85f444e243639047] for camera: 0 D/Camera2CameraImpl( 8806): {Camera@3ecadf1[id=0]} Use case androidx.camera.core.ImageAnalysis-67e5fe33-bd23-419f-91ab-2c0f74c15589101068192 ACTIVE D/UseCaseAttachState( 8806): Active and attached use case: [androidx.camera.core.ImageCapture-08246426-0a49-416d-96c3-0c6cb8ac64bf259810770, androidx.camera.core.Preview-8e6bdcb0-6edb-464f-b7ac-41df85f444e243639047, androidx.camera.core.ImageAnalysis-67e5fe33-bd23-419f-91ab-2c0f74c15589101068192] for camera: 0 D/Camera2CameraImpl( 8806): {Camera@3ecadf1[id=0]} CameraDevice.onOpened() D/Camera2CameraImpl( 8806): {Camera@3ecadf1[id=0]} Transitioning camera internal state: OPENING --> OPENED D/CameraStateRegistry( 8806): Recalculating open cameras: D/CameraStateRegistry( 8806): Camera State D/CameraStateRegistry( 8806): ------------------------------------------------------------------- D/CameraStateRegistry( 8806): Camera@6d4a0e0[id=3] UNKNOWN D/CameraStateRegistry( 8806): Camera@ad080c8[id=2] UNKNOWN D/CameraStateRegistry( 8806): Camera@2322a29[id=1] UNKNOWN D/CameraStateRegistry( 8806): Camera@3ecadf1[id=0] OPEN D/CameraStateRegistry( 8806): ------------------------------------------------------------------- D/CameraStateRegistry( 8806): Open count: 1 (Max allowed: 1) D/CameraStateMachine( 8806): New public camera state CameraState{type=OPEN, error=null} from OPEN and null D/CameraStateMachine( 8806): Publishing new public camera state CameraState{type=OPEN, error=null} D/UseCaseAttachState( 8806): All use case: [androidx.camera.core.ImageCapture-08246426-0a49-416d-96c3-0c6cb8ac64bf259810770, androidx.camera.core.Preview-8e6bdcb0-6edb-464f-b7ac-41df85f444e243639047, androidx.camera.core.ImageAnalysis-67e5fe33-bd23-419f-91ab-2c0f74c15589101068192] for camera: 0 D/UseCaseAttachState( 8806): Active and attached use case: [androidx.camera.core.ImageCapture-08246426-0a49-416d-96c3-0c6cb8ac64bf259810770, androidx.camera.core.Preview-8e6bdcb0-6edb-464f-b7ac-41df85f444e243639047, androidx.camera.core.ImageAnalysis-67e5fe33-bd23-419f-91ab-2c0f74c15589101068192] for camera: 0 D/SyncCaptureSessionBase( 8806): [androidx.camera.camera2.internal.SynchronizedCaptureSessionBaseImpl@a1489f9] getSurface...done D/CaptureSession( 8806): Opening capture session. D/DeferrableSurface( 8806): use count+1, useCount=2 androidx.camera.core.SurfaceRequest$2@4e37971 D/DeferrableSurface( 8806): New surface in use[total_surfaces=4, used_surfaces=2](androidx.camera.core.impl.ImmediateSurface@1c1a273} D/DeferrableSurface( 8806): use count+1, useCount=1 androidx.camera.core.impl.ImmediateSurface@1c1a273 D/DeferrableSurface( 8806): New surface in use[total_surfaces=4, used_surfaces=3](androidx.camera.core.impl.ImmediateSurface@c89f2cf} D/DeferrableSurface( 8806): use count+1, useCount=1 androidx.camera.core.impl.ImmediateSurface@c89f2cf Syncing files to device SM S918U1... 407ms D/CaptureSession( 8806): Attempting to send capture request onConfigured D/CaptureSession( 8806): Issuing request for session. D/Camera2CaptureRequestBuilder( 8806): createCaptureRequest D/CaptureSession( 8806): CameraCaptureSession.onConfigured() mState=OPENED D/CaptureSession( 8806): CameraCaptureSession.onReady() OPENED I/CameraManagerGlobal( 8806): Camera 0 facing CAMERA_FACING_BACK state now CAMERA_STATE_ACTIVE for client com.example.lamp API Level 2 User Id 0 I/ViewRootImpl@70d56ee[MainActivity]( 8806): onDisplayChanged oldDisplayState=2 newDisplayState=2 Flutter run key commands. r Hot reload. R Hot restart. h List all available interactive commands. d Detach (terminate "flutter run" but leave application running). c Clear the screen q Quit (terminate the application on the device). A Dart VM Service on SM S918U1 is available at: http://127.0.0.1:57305/r_4lx0bGKWc=/ I/om.example.lamp( 8806): EglImage dataspace changed, need recreate W/qdgralloc( 8806): getInterlacedFlag: getMetaData returned 3, defaulting to interlaced_flag = 0 I/om.example.lamp( 8806): EglImage dataspace changed, need recreate W/qdgralloc( 8806): getInterlacedFlag: getMetaData returned 3, defaulting to interlaced_flag = 0 The Flutter DevTools debugger and profiler on SM S918U1 is available at: http://127.0.0.1:9102?uri=http://127.0.0.1:57305/r_4lx0bGKWc=/ I/om.example.lamp( 8806): EglImage dataspace changed, need recreate W/qdgralloc( 8806): getInterlacedFlag: getMetaData returned 3, defaulting to interlaced_flag = 0 I/om.example.lamp( 8806): EglImage dataspace changed, need recreate W/qdgralloc( 8806): getInterlacedFlag: getMetaData returned 3, defaulting to interlaced_flag = 0 I/om.example.lamp( 8806): Background concurrent mark compact GC freed 88369(10MB) AllocSpace objects, 77(53MB) LOS objects, 49% free, 12MB/24MB, paused 80us,6.677ms total 32.733ms I/om.example.lamp( 8806): EglImage dataspace changed, need recreate W/qdgralloc( 8806): getInterlacedFlag: getMetaData returned 3, defaulting to interlaced_flag = 0 I/om.example.lamp( 8806): EglImage dataspace changed, need recreate W/qdgralloc( 8806): getInterlacedFlag: getMetaData returned 3, defaulting to interlaced_flag = 0 I/om.example.lamp( 8806): EglImage dataspace changed, need recreate W/qdgralloc( 8806): getInterlacedFlag: getMetaData returned 3, defaulting to interlaced_flag = 0 I/om.example.lamp( 8806): Background concurrent mark compact GC freed 363(252KB) AllocSpace objects, 12(9036KB) LOS objects, 53% free, 5389KB/11MB, paused 35us,13.950ms total 24.327ms I/om.example.lamp( 8806): EglImage dataspace changed, need recreate W/qdgralloc( 8806): getInterlacedFlag: getMetaData returned 3, defaulting to interlaced_flag = 0 I/om.example.lamp( 8806): Background concurrent mark compact GC freed 1770(353KB) AllocSpace objects, 38(27MB) LOS objects, 64% free, 3449KB/9593KB, paused 35us,8.766ms total 18.005ms I/InsetsSourceConsumer( 8806): applyRequestedVisibilityToControl: visible=true, type=statusBars, host=com.example.lamp/com.example.live_object_detection_ssd_mobilenet.MainActivity D/ProfileInstaller( 8806): Installing profile for com.example.lamp I/ViewRootImpl@70d56ee[MainActivity]( 8806): ViewPostIme pointer 0 I/ViewRootImpl@70d56ee[MainActivity]( 8806): ViewPostIme pointer 1 I/om.example.lamp( 8806): Background concurrent mark compact GC freed 425(252KB) AllocSpace objects, 12(9036KB) LOS objects, 53% free, 5301KB/11MB, paused 65us,5.532ms total 17.876ms I/om.example.lamp( 8806): Background concurrent mark compact GC freed 320(252KB) AllocSpace objects, 12(9036KB) LOS objects, 53% free, 5314KB/11MB, paused 33us,7.136ms total 17.282ms I/ViewRootImpl@70d56ee[MainActivity]( 8806): ViewPostIme pointer 0 I/ViewRootImpl@70d56ee[MainActivity]( 8806): ViewPostIme pointer 1 I/ViewRootImpl@70d56ee[MainActivity]( 8806): ViewPostIme pointer 0 I/ViewRootImpl@70d56ee[MainActivity]( 8806): ViewPostIme pointer 1 I/ViewRootImpl@70d56ee[MainActivity]( 8806): ViewPostIme pointer 0 I/ViewRootImpl@70d56ee[MainActivity]( 8806): ViewPostIme pointer 1 E/flutter ( 8806): [ERROR:flutter/runtime/dart_vm_initializer.cc(41)] Unhandled Exception: PlatformException(java.lang.NullPointerException, NullPointerException, Cause: null, Stacktrace: java.lang.NullPointerException E/flutter ( 8806): at java.util.Objects.requireNonNull(Objects.java:207) E/flutter ( 8806): at io.flutter.plugins.camerax.ImageProxyHostApiImpl.getImageProxyInstance(ImageProxyHostApiImpl.java:80) E/flutter ( 8806): at io.flutter.plugins.camerax.ImageProxyHostApiImpl.close(ImageProxyHostApiImpl.java:73) E/flutter ( 8806): at io.flutter.plugins.camerax.GeneratedCameraXLibrary$ImageProxyHostApi.lambda$setup$1(GeneratedCameraXLibrary.java:3455) E/flutter ( 8806): at io.flutter.plugins.camerax.GeneratedCameraXLibrary$ImageProxyHostApi$$ExternalSyntheticLambda1.onMessage(Unknown Source:2) E/flutter ( 8806): at io.flutter.plugin.common.BasicMessageChannel$IncomingMessageHandler.onMessage(BasicMessageChannel.java:261) E/flutter ( 8806): at io.flutter.embedding.engine.dart.DartMessenger.invokeHandler(DartMessenger.java:292) E/flutter ( 8806): at io.flutter.embedding.engine.dart.DartMessenger.lambda$dispatchMessageToQueue$0$io-flutter-embedding-engine-dart-DartMessenger(DartMessenger.java:319) E/flutter ( 8806): at io.flutter.embedding.engine.dart.DartMessenger$$ExternalSyntheticLambda0.run(Unknown Source:12) E/flutter ( 8806): at android.os.Handler.handleCallback(Handler.java:958) E/flutter ( 8806): at android.os.Handler.dispatchMessage(Handler.java:99) E/flutter ( 8806): at android.os.Looper.loopOnce(Looper.java:230) E/flutter ( 8806): at android.os.Looper.loop(Looper.java:319) E/flutter ( 8806): at android.app.ActivityThread.main(ActivityThread.java:8919) E/flutter ( 8806): at java.lang.reflect.Method.invoke(Native Method) E/flutter ( 8806): at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:578) E/flutter ( 8806): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1103) E/flutter ( 8806): , null) E/flutter ( 8806): #0 ImageProxyHostApi.close (package:camera_android_camerax/src/camerax_library.g.dart:2764:7) E/flutter ( 8806): E/flutter ( 8806): #1 AndroidCameraCameraX._configureImageAnalysis.analyze (package:camera_android_camerax/src/android_camera_camerax.dart:1236:7) E/flutter ( 8806): E/flutter ( 8806): ```

Flutter Doctor output

Doctor output ```console [√] Flutter (Channel stable, 3.22.2, on Microsoft Windows [Version 10.0.19045.4651], locale en-US) • Flutter version 3.22.2 on channel stable at C:\dev\flutter • Upstream repository https://github.com/flutter/flutter.git • Framework revision 761747bfc5 (8 weeks ago), 2024-06-05 22:15:13 +0200 • Engine revision edd8546116 • Dart version 3.4.3 • DevTools version 2.34.3 [√] Windows Version (Installed version of Windows is version 10 or higher) [√] Android toolchain - develop for Android devices (Android SDK version 34.0.0) • Android SDK at C:\Users\Administrator\AppData\Local\Android\sdk • Platform android-34, build-tools 34.0.0 • Java binary at: C:\Program Files\Android\Android Studio\jbr\bin\java • Java version OpenJDK Runtime Environment (build 17.0.10+0--11572160) • All Android licenses accepted. [√] Chrome - develop for the web • Chrome at C:\Program Files\Google\Chrome\Application\chrome.exe [!] Visual Studio - develop Windows apps (Visual Studio Build Tools 2019 16.11.36) • Visual Studio at C:\Program Files (x86)\Microsoft Visual Studio\2019\BuildTools • Visual Studio Build Tools 2019 version 16.11.34902.97 X The current Visual Studio installation is incomplete. Please use Visual Studio Installer to complete the installation or reinstall Visual Studio. [√] Android Studio (version 2023.3) • Android Studio at C:\Program Files\Android\Android Studio • 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 17.0.10+0--11572160) [√] VS Code (version 1.91.1) • VS Code at C:\Users\Administrator\AppData\Local\Programs\Microsoft VS Code • Flutter extension version 3.92.0 [√] Connected device (4 available) • SM S918U1 (mobile) • R3CW50M09SD • android-arm64 • Android 14 (API 34) • Windows (desktop) • windows • windows-x64 • Microsoft Windows [Version 10.0.19045.4651] • Chrome (web) • chrome • web-javascript • Google Chrome 127.0.6533.73 • Edge (web) • edge • web-javascript • Microsoft Edge 127.0.2651.74 [√] Network resources • All expected network resources are available. ```
iapicca commented 3 months ago

@RishabhK12 I suspect the issue might have something to do with async initialization and update I cannot test it myself, but maybe you can try with the code sample below?

code sample ```dart import 'package:camera/camera.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; void main() async { WidgetsFlutterBinding.ensureInitialized(); await SystemChrome.setPreferredOrientations( [DeviceOrientation.portraitUp], ); runApp( const AppLifecycleWidget(child: Mypp()), ); } class Mypp extends StatelessWidget { const Mypp({super.key}); @override Widget build(context) => MaterialApp( title: 'Stream Test', theme: ThemeData( primarySwatch: Colors.blue, visualDensity: VisualDensity.adaptivePlatformDensity, ), home: const MyHomePage(), ); } class MyHomePage extends StatelessWidget { const MyHomePage({super.key}); @override Widget build(context) => Scaffold( body: Stack( children: [ CameraWidget( enableAudio: false, builder: (context, controller) => CameraStramImageLifecycle( controller: controller, child: AspectRatio( aspectRatio: 1 / controller.value.aspectRatio, child: CameraPreview(controller), ), ), ), ], ), ); } /// Under the hood stuff /// ... typedef AppLifecycleStateNotifier = ValueNotifier; typedef CameraBuilder = Widget Function( BuildContext, CameraController, ); typedef AvailableCamerasBuilder = Widget Function( BuildContext, List, ); typedef OnStateCallback = void Function(T state); typedef OnAvailableCameraImage = void Function(CameraImage); class AppLifecycleWidget extends StatefulWidget { final Widget child; const AppLifecycleWidget({ super.key, required this.child, }); @override State createState() => _AppLifecycleWidgetState(); } class _AppLifecycleWidgetState extends State with WidgetsBindingObserver { late final AppLifecycleStateNotifier appLifecycleStateNotifier; @override void initState() { WidgetsBinding.instance.addObserver(this); appLifecycleStateNotifier = ValueNotifier(WidgetsBinding.instance.lifecycleState); super.initState(); } @override void dispose() { WidgetsBinding.instance.removeObserver(this); appLifecycleStateNotifier.dispose(); super.dispose(); } @override void didChangeAppLifecycleState(state) { appLifecycleStateNotifier.value = state; } @override Widget build(context) => InheritedAppLifecycleStateNotifier( appLifecycleStateNotifier: appLifecycleStateNotifier, child: Builder(builder: (context) => widget.child), ); } class CameraWidget extends StatelessWidget { final CameraBuilder builder; final int cameraIndex; final bool enableAudio; final int? fps; final int? videoBitrate; final int? audioBitrate; final ImageFormatGroup? imageFormatGroup; final ResolutionPreset resolutionPreset; final Widget loadingWidget; const CameraWidget({ super.key, required this.builder, this.fps, this.videoBitrate, this.audioBitrate, this.imageFormatGroup, this.loadingWidget = const Center( child: CircularProgressIndicator(), ), this.cameraIndex = 0, this.enableAudio = true, this.resolutionPreset = ResolutionPreset.high, }); @override Widget build(context) => AvailableCamerasWidget( loadingWidget: loadingWidget, builder: (context, cameras) => CameraWidgetBuilder( loadingWidget: loadingWidget, cameras: cameras, builder: builder, cameraIndex: cameraIndex, enableAudio: enableAudio, resolutionPreset: resolutionPreset, appLifecycleStateNotifier: InheritedAppLifecycleStateNotifier.of(context), ), ); } class CameraWidgetBuilder extends StatefulWidget { final CameraBuilder builder; final int cameraIndex; final bool enableAudio; final int? fps; final int? videoBitrate; final int? audioBitrate; final Widget loadingWidget; final AppLifecycleStateNotifier appLifecycleStateNotifier; final ImageFormatGroup? imageFormatGroup; final ResolutionPreset resolutionPreset; final List cameras; const CameraWidgetBuilder({ super.key, required this.builder, required this.cameras, this.fps, this.videoBitrate, this.audioBitrate, this.imageFormatGroup, required this.cameraIndex, required this.enableAudio, required this.resolutionPreset, required this.loadingWidget, required this.appLifecycleStateNotifier, }); @override State createState() => _CameraWidgetBuilderState(); } class _CameraWidgetBuilderState extends State { late final ValueNotifier _controllerNotifier; CameraController _controller() => CameraController( widget.cameras[widget.cameraIndex], widget.resolutionPreset, enableAudio: widget.enableAudio, fps: widget.fps, videoBitrate: widget.videoBitrate, audioBitrate: widget.audioBitrate, imageFormatGroup: widget.imageFormatGroup, ); void _listener() { _controllerNotifier.value = _controller(); } @override void initState() { _controllerNotifier = ValueNotifier(_controller()); widget.appLifecycleStateNotifier.addListener(_listener); super.initState(); } @override void dispose() { widget.appLifecycleStateNotifier.removeListener(_listener); _controllerNotifier ..value.dispose() ..dispose(); super.dispose(); } @override Widget build(context) => ValueListenableBuilder( valueListenable: _controllerNotifier, builder: (context, controller, _) => FutureBuilder( future: controller.initialize(), builder: (context, snapshot) { switch (snapshot.connectionState) { case ConnectionState.done: if (snapshot.hasError) { throw Exception('CameraController failed to initialize'); } return widget.builder(context, controller); default: return widget.loadingWidget; } }, ), ); } class InheritedAppLifecycleStateNotifier extends InheritedWidget { const InheritedAppLifecycleStateNotifier({ super.key, required super.child, required this.appLifecycleStateNotifier, }); final AppLifecycleStateNotifier appLifecycleStateNotifier; static AppLifecycleStateNotifier of(BuildContext context) { final maybeInheritedWidget = context.dependOnInheritedWidgetOfExactType< InheritedAppLifecycleStateNotifier>(); if (maybeInheritedWidget == null) { throw Exception('no InheritedAppLifecycleStateNotifier found in context'); } return maybeInheritedWidget.appLifecycleStateNotifier; } @override bool updateShouldNotify(oldWidget) => false; } class AvailableCamerasWidget extends StatelessWidget { final AvailableCamerasBuilder builder; final Widget loadingWidget; const AvailableCamerasWidget({ super.key, required this.builder, required this.loadingWidget, }); @override Widget build(context) => FutureBuilder>( future: availableCameras(), builder: (context, snapshot) { switch (snapshot.connectionState) { case ConnectionState.done: return snapshot.hasError || snapshot.data == null || snapshot.data!.isEmpty ? () { throw Exception('no camera available'); }() : builder(context, snapshot.data!); default: return loadingWidget; } }, ); } class CameraStramImageLifecycle extends StatefulWidget { final Widget child; final CameraController controller; final OnAvailableCameraImage? onAvailable; const CameraStramImageLifecycle({ super.key, required this.child, required this.controller, this.onAvailable, }); @override State createState() => _CameraStramImageLifecycleState(); } class _CameraStramImageLifecycleState extends State { late CameraController? _controller; late CameraController? _newController; @override void initState() { _controller = widget.controller; super.initState(); } @override void didChangeDependencies() { _newController = widget.controller; super.didChangeDependencies(); } @override void dispose() { _controller = null; _newController = null; super.dispose(); } @override Widget build(context) => AppLifecycleStateListener( onInit: () => widget.controller.startImageStream(widget.onAvailable ?? (_) {}), onDispose: () { if (_controller.hashCode != _newController.hashCode) { return; } widget.controller.stopImageStream(); }, listener: (AppLifecycleState? state) { if (_controller.hashCode != _newController.hashCode) { _controller = _newController; return; } if (state == null) { return; } switch (state) { case AppLifecycleState.inactive: _controller!.stopImageStream(); case AppLifecycleState.resumed: _controller!.startImageStream(widget.onAvailable ?? (_) {}); default: return; } }, listenable: InheritedAppLifecycleStateNotifier.of(context), child: widget.child, ); } class AppLifecycleStateListener extends ValueListenableListener { const AppLifecycleStateListener({ super.key, required super.child, required super.listener, required super.listenable, super.onInit, super.onDispose, }); } abstract class ValueListenableListener extends StatefulWidget { final Widget child; final OnStateCallback listener; final ValueNotifier listenable; final VoidCallback? onInit; final VoidCallback? onDispose; const ValueListenableListener({ super.key, required this.child, required this.listener, required this.listenable, this.onInit, this.onDispose, }); @override State createState() => _ValueListenableListenerState(); } class _ValueListenableListenerState extends State { void _listener() => widget.listener(widget.listenable.value); @override void initState() { widget.onInit?.call(); widget.listenable.addListener(_listener); super.initState(); } @override void dispose() { widget.listenable.removeListener(_listener); widget.onDispose?.call(); super.dispose(); } @override Widget build(context) => widget.child; } ``` ```yaml name: issue_152763 description: "A new Flutter project." publish_to: 'none' version: 1.0.0+1 environment: sdk: '>=3.4.4 <4.0.0' dependencies: flutter: sdk: flutter camera: ^0.11.0 dev_dependencies: flutter_test: sdk: flutter flutter_lints: ^3.0.0 flutter: uses-material-design: true ```
RishabhK12 commented 3 months ago

It seems like your code sample doesn't image stream at all. I am facing an issue with the image streaming. When I comment out startImageStream, I don't have any errors.

huycozy commented 2 months ago

Hi @RishabhK12 I have waited 5 minutes but didn't see the exception as yours. I see this code on your sample code, is there any action on the device to fall into one of these cases?

@override
void didChangeAppLifecycleState(AppLifecycleState state) async {
  switch (state) {
    case AppLifecycleState.inactive:
      _cameraController?.stopImageStream();
      break;
    case AppLifecycleState.resumed:
      _initStateAsync();
      break;
    default:
  }
}

It would be better if you could provide clearer and concrete steps to reproduce this. Thanks!

iapicca commented 2 months ago

@huycozy

I can reproduce the issue exactly as @RishabhK12 described, (just start remember to "move the phone around" to make the camera do some work)

please find below a very minimal code sample below (reproduces with the code above as well)

you can find the device details in the doctor

minimal code sample ```dart import 'package:camera/camera.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; void main() async { WidgetsFlutterBinding.ensureInitialized(); await SystemChrome.setPreferredOrientations( [DeviceOrientation.portraitUp], ); final cameras = await availableCameras(); final controller = CameraController( cameras[0], enableAudio: true, ResolutionPreset.high, ); int? hash; await controller.initialize(); await controller.startImageStream((_) { if (hash == null) { print(''' ################ ${controller.hashCode} ################ '''); hash = controller.hashCode; } }); runApp( MaterialApp( home: Scaffold( body: Center( child: CameraPreview(controller), ), ), ), ); } ```
pubspec ```yaml name: issue_152763 description: "A new Flutter project." publish_to: 'none' version: 1.0.0+1 environment: sdk: '>=3.4.4 <4.0.0' dependencies: flutter: sdk: flutter camera: ^0.11.0 dev_dependencies: flutter_test: sdk: flutter flutter_lints: ^3.0.0 flutter: uses-material-design: true ```
doctor ```console [!] Flutter (Channel stable, 3.22.3, on macOS 14.5 23F79 darwin-arm64, locale en-US) • Flutter version 3.22.3 on channel stable at /Users/francesco/fvm/versions/stable ! Warning: `dart` on your path resolves to /opt/homebrew/Cellar/dart/3.4.4/libexec/bin/dart, which is not inside your current Flutter SDK checkout at /Users/francesco/fvm/versions/stable. Consider adding /Users/francesco/fvm/versions/stable/bin to the front of your path. • Upstream repository https://github.com/flutter/flutter.git • Framework revision b0850beeb2 (3 weeks ago), 2024-07-16 21:43:41 -0700 • Engine revision 235db911ba • Dart version 3.4.4 • DevTools version 2.34.3 • If those were intentional, you can disregard the above warnings; however it is recommended to use "git" directly to perform update checks and upgrades. [✓] Android toolchain - develop for Android devices (Android SDK version 34.0.0) • Android SDK at /Users/francesco/Library/Android/sdk • Platform android-34, build-tools 34.0.0 • Java binary at: /Applications/Android Studio.app/Contents/jbr/Contents/Home/bin/java • Java version OpenJDK Runtime Environment (build 17.0.6+0-17.0.6b829.9-10027231) • All Android licenses accepted. [✓] Xcode - develop for iOS and macOS (Xcode 15.4) • Xcode at /Applications/Xcode.app/Contents/Developer • Build 15F31d • CocoaPods version 1.15.2 [✓] Chrome - develop for the web • Chrome at /Applications/Google Chrome.app/Contents/MacOS/Google Chrome [✓] Android Studio (version 2022.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 17.0.6+0-17.0.6b829.9-10027231) [✓] VS Code (version 1.92.0) • VS Code at /Applications/Visual Studio Code.app/Contents • Flutter extension version 3.94.0 [✓] Connected device (4 available) • SM A556B (mobile) • RZCX318VHFK • android-arm64 • Android 14 (API 34) • macOS (desktop) • macos • darwin-arm64 • macOS 14.5 23F79 darwin-arm64 • Mac Designed for iPad (desktop) • mac-designed-for-ipad • darwin • macOS 14.5 23F79 darwin-arm64 • Chrome (web) • chrome • web-javascript • Google Chrome 120.0.6099.71 [✓] Network resources • All expected network resources are available. ! Doctor found issues in 1 category. ```

here are the error logs

#

note that the issue does not occur w/o startImageStream as the reporter pointed out

RishabhK12 commented 2 months ago

@huycozy My device isn't falling into any of the cases in the didChangeAppLifecycleState method.

Thanks

huycozy commented 2 months ago

(just start remember to "move the phone around" to make the camera do some work)

I did but still couldn't reproduce this on my device Pixel 7, Android 14 using the latest packages:

camera:
  dependency: "direct main"
  description:
    name: camera
    sha256: "2170a943dcb67be2af2c6bcda8775e74b41d4c02d6a4eb10bdc832ee185c4eea"
    url: "https://pub.dev"
  source: hosted
  version: "0.11.0+1"
camera_android_camerax:
  dependency: transitive
  description:
    name: camera_android_camerax
    sha256: "8bd9cab67551642eb33ceb33ece7acc0890014fc90ddfae637c7e2b683657e65"
    url: "https://pub.dev"
  source: hosted
  version: "0.6.7+2"

Can you both share the fetched camera_android_camerax version from pubspec.lock file?

AndroidCameraCameraX._configureImageAnalysis.analyze (package:camera_android_camerax/src/android_camera_camerax.dart:1236:7)

Checking the error trace, it seems to fall analyze method here but doesn't match the line of code. So it's worth checking on the latest version of package.

iapicca commented 2 months ago

Can you both share the fetched camera_android_camerax version from pubspec.lock file?

@huycozy sure

pubspec.lock ```lock # Generated by pub # See https://dart.dev/tools/pub/glossary#lockfile packages: async: dependency: transitive description: name: async sha256: "947bfcf187f74dbc5e146c9eb9c0f10c9f8b30743e341481c1e2ed3ecc18c20c" url: "https://pub.dev" source: hosted version: "2.11.0" boolean_selector: dependency: transitive description: name: boolean_selector sha256: "6cfb5af12253eaf2b368f07bacc5a80d1301a071c73360d746b7f2e32d762c66" url: "https://pub.dev" source: hosted version: "2.1.1" camera: dependency: "direct main" description: name: camera sha256: "2170a943dcb67be2af2c6bcda8775e74b41d4c02d6a4eb10bdc832ee185c4eea" url: "https://pub.dev" source: hosted version: "0.11.0+1" camera_android_camerax: dependency: transitive description: name: camera_android_camerax sha256: "8bd9cab67551642eb33ceb33ece7acc0890014fc90ddfae637c7e2b683657e65" url: "https://pub.dev" source: hosted version: "0.6.7+2" camera_avfoundation: dependency: transitive description: name: camera_avfoundation sha256: "80fe7454d681f971abfbc566d95fecde629a2040d4a951950749df837f43e94e" url: "https://pub.dev" source: hosted version: "0.9.17+2" camera_platform_interface: dependency: transitive description: name: camera_platform_interface sha256: b3ede1f171532e0d83111fe0980b46d17f1aa9788a07a2fbed07366bbdbb9061 url: "https://pub.dev" source: hosted version: "2.8.0" camera_web: dependency: transitive description: name: camera_web sha256: b9235ec0a2ce949daec546f1f3d86f05c3921ed31c7d9ab6b7c03214d152fc2d url: "https://pub.dev" source: hosted version: "0.3.4" characters: dependency: transitive description: name: characters sha256: "04a925763edad70e8443c99234dc3328f442e811f1d8fd1a72f1c8ad0f69a605" url: "https://pub.dev" source: hosted version: "1.3.0" clock: dependency: transitive description: name: clock sha256: cb6d7f03e1de671e34607e909a7213e31d7752be4fb66a86d29fe1eb14bfb5cf url: "https://pub.dev" source: hosted version: "1.1.1" collection: dependency: transitive description: name: collection sha256: ee67cb0715911d28db6bf4af1026078bd6f0128b07a5f66fb2ed94ec6783c09a url: "https://pub.dev" source: hosted version: "1.18.0" cross_file: dependency: transitive description: name: cross_file sha256: "7caf6a750a0c04effbb52a676dce9a4a592e10ad35c34d6d2d0e4811160d5670" url: "https://pub.dev" source: hosted version: "0.3.4+2" fake_async: dependency: transitive description: name: fake_async sha256: "511392330127add0b769b75a987850d136345d9227c6b94c96a04cf4a391bf78" url: "https://pub.dev" source: hosted version: "1.3.1" flutter: dependency: "direct main" description: flutter source: sdk version: "0.0.0" flutter_lints: dependency: "direct dev" description: name: flutter_lints sha256: "9e8c3858111da373efc5aa341de011d9bd23e2c5c5e0c62bccf32438e192d7b1" url: "https://pub.dev" source: hosted version: "3.0.2" flutter_plugin_android_lifecycle: dependency: transitive description: name: flutter_plugin_android_lifecycle sha256: "9d98bd47ef9d34e803d438f17fd32b116d31009f534a6fa5ce3a1167f189a6de" url: "https://pub.dev" source: hosted version: "2.0.21" flutter_test: dependency: "direct dev" description: flutter source: sdk version: "0.0.0" flutter_web_plugins: dependency: transitive description: flutter source: sdk version: "0.0.0" leak_tracker: dependency: transitive description: name: leak_tracker sha256: "7f0df31977cb2c0b88585095d168e689669a2cc9b97c309665e3386f3e9d341a" url: "https://pub.dev" source: hosted version: "10.0.4" leak_tracker_flutter_testing: dependency: transitive description: name: leak_tracker_flutter_testing sha256: "06e98f569d004c1315b991ded39924b21af84cf14cc94791b8aea337d25b57f8" url: "https://pub.dev" source: hosted version: "3.0.3" leak_tracker_testing: dependency: transitive description: name: leak_tracker_testing sha256: "6ba465d5d76e67ddf503e1161d1f4a6bc42306f9d66ca1e8f079a47290fb06d3" url: "https://pub.dev" source: hosted version: "3.0.1" lints: dependency: transitive description: name: lints sha256: cbf8d4b858bb0134ef3ef87841abdf8d63bfc255c266b7bf6b39daa1085c4290 url: "https://pub.dev" source: hosted version: "3.0.0" matcher: dependency: transitive description: name: matcher sha256: d2323aa2060500f906aa31a895b4030b6da3ebdcc5619d14ce1aada65cd161cb url: "https://pub.dev" source: hosted version: "0.12.16+1" material_color_utilities: dependency: transitive description: name: material_color_utilities sha256: "0e0a020085b65b6083975e499759762399b4475f766c21668c4ecca34ea74e5a" url: "https://pub.dev" source: hosted version: "0.8.0" meta: dependency: transitive description: name: meta sha256: "7687075e408b093f36e6bbf6c91878cc0d4cd10f409506f7bc996f68220b9136" url: "https://pub.dev" source: hosted version: "1.12.0" path: dependency: transitive description: name: path sha256: "087ce49c3f0dc39180befefc60fdb4acd8f8620e5682fe2476afd0b3688bb4af" url: "https://pub.dev" source: hosted version: "1.9.0" plugin_platform_interface: dependency: transitive description: name: plugin_platform_interface sha256: "4820fbfdb9478b1ebae27888254d445073732dae3d6ea81f0b7e06d5dedc3f02" url: "https://pub.dev" source: hosted version: "2.1.8" sky_engine: dependency: transitive description: flutter source: sdk version: "0.0.99" source_span: dependency: transitive description: name: source_span sha256: "53e943d4206a5e30df338fd4c6e7a077e02254531b138a15aec3bd143c1a8b3c" url: "https://pub.dev" source: hosted version: "1.10.0" stack_trace: dependency: transitive description: name: stack_trace sha256: "73713990125a6d93122541237550ee3352a2d84baad52d375a4cad2eb9b7ce0b" url: "https://pub.dev" source: hosted version: "1.11.1" stream_channel: dependency: transitive description: name: stream_channel sha256: ba2aa5d8cc609d96bbb2899c28934f9e1af5cddbd60a827822ea467161eb54e7 url: "https://pub.dev" source: hosted version: "2.1.2" stream_transform: dependency: transitive description: name: stream_transform sha256: "14a00e794c7c11aa145a170587321aedce29769c08d7f58b1d141da75e3b1c6f" url: "https://pub.dev" source: hosted version: "2.1.0" string_scanner: dependency: transitive description: name: string_scanner sha256: "556692adab6cfa87322a115640c11f13cb77b3f076ddcc5d6ae3c20242bedcde" url: "https://pub.dev" source: hosted version: "1.2.0" term_glyph: dependency: transitive description: name: term_glyph sha256: a29248a84fbb7c79282b40b8c72a1209db169a2e0542bce341da992fe1bc7e84 url: "https://pub.dev" source: hosted version: "1.2.1" test_api: dependency: transitive description: name: test_api sha256: "9955ae474176f7ac8ee4e989dadfb411a58c30415bcfb648fa04b2b8a03afa7f" url: "https://pub.dev" source: hosted version: "0.7.0" vector_math: dependency: transitive description: name: vector_math sha256: "80b3257d1492ce4d091729e3a67a60407d227c27241d6927be0130c98e741803" url: "https://pub.dev" source: hosted version: "2.1.4" vm_service: dependency: transitive description: name: vm_service sha256: "3923c89304b715fb1eb6423f017651664a03bf5f4b29983627c4da791f74a4ec" url: "https://pub.dev" source: hosted version: "14.2.1" web: dependency: transitive description: name: web sha256: d43c1d6b787bf0afad444700ae7f4db8827f701bc61c255ac8d328c6f4d52062 url: "https://pub.dev" source: hosted version: "1.0.0" sdks: dart: ">=3.4.4 <4.0.0" flutter: ">=3.22.0" ```
RishabhK12 commented 2 months ago

@huycozy Here's mine, it has some older versions of some packages compared to @iapicca. When I update I still get the issue.

pubspec.lock ```yaml # Generated by pub # See https://dart.dev/tools/pub/glossary#lockfile packages: async: dependency: transitive description: name: async sha256: "947bfcf187f74dbc5e146c9eb9c0f10c9f8b30743e341481c1e2ed3ecc18c20c" url: "https://pub.dev" source: hosted version: "2.11.0" boolean_selector: dependency: transitive description: name: boolean_selector sha256: "6cfb5af12253eaf2b368f07bacc5a80d1301a071c73360d746b7f2e32d762c66" url: "https://pub.dev" source: hosted version: "2.1.1" camera: dependency: "direct main" description: name: camera sha256: "2170a943dcb67be2af2c6bcda8775e74b41d4c02d6a4eb10bdc832ee185c4eea" url: "https://pub.dev" source: hosted version: "0.11.0+1" camera_android_camerax: dependency: transitive description: name: camera_android_camerax sha256: "7abb0faddbf103c59365e805ad9a30ab4d602b2eb7a8de469697945fd4a69daa" url: "https://pub.dev" source: hosted version: "0.6.5+6" camera_avfoundation: dependency: transitive description: name: camera_avfoundation sha256: "7d021e8cd30d9b71b8b92b4ad669e80af432d722d18d6aac338572754a786c15" url: "https://pub.dev" source: hosted version: "0.9.16" camera_platform_interface: dependency: transitive description: name: camera_platform_interface sha256: a250314a48ea337b35909a4c9d5416a208d736dcb01d0b02c6af122be66660b0 url: "https://pub.dev" source: hosted version: "2.7.4" camera_web: dependency: transitive description: name: camera_web sha256: "9e9aba2fbab77ce2472924196ff8ac4dd8f9126c4f9a3096171cd1d870d6b26c" url: "https://pub.dev" source: hosted version: "0.3.3" characters: dependency: transitive description: name: characters sha256: "04a925763edad70e8443c99234dc3328f442e811f1d8fd1a72f1c8ad0f69a605" url: "https://pub.dev" source: hosted version: "1.3.0" clock: dependency: transitive description: name: clock sha256: cb6d7f03e1de671e34607e909a7213e31d7752be4fb66a86d29fe1eb14bfb5cf url: "https://pub.dev" source: hosted version: "1.1.1" collection: dependency: transitive description: name: collection sha256: ee67cb0715911d28db6bf4af1026078bd6f0128b07a5f66fb2ed94ec6783c09a url: "https://pub.dev" source: hosted version: "1.18.0" cross_file: dependency: transitive description: name: cross_file sha256: "7caf6a750a0c04effbb52a676dce9a4a592e10ad35c34d6d2d0e4811160d5670" url: "https://pub.dev" source: hosted version: "0.3.4+2" fake_async: dependency: transitive description: name: fake_async sha256: "511392330127add0b769b75a987850d136345d9227c6b94c96a04cf4a391bf78" url: "https://pub.dev" source: hosted version: "1.3.1" flutter: dependency: "direct main" description: flutter source: sdk version: "0.0.0" flutter_plugin_android_lifecycle: dependency: transitive description: name: flutter_plugin_android_lifecycle sha256: "9d98bd47ef9d34e803d438f17fd32b116d31009f534a6fa5ce3a1167f189a6de" url: "https://pub.dev" source: hosted version: "2.0.21" flutter_test: dependency: "direct dev" description: flutter source: sdk version: "0.0.0" flutter_web_plugins: dependency: transitive description: flutter source: sdk version: "0.0.0" leak_tracker: dependency: transitive description: name: leak_tracker sha256: "7f0df31977cb2c0b88585095d168e689669a2cc9b97c309665e3386f3e9d341a" url: "https://pub.dev" source: hosted version: "10.0.4" leak_tracker_flutter_testing: dependency: transitive description: name: leak_tracker_flutter_testing sha256: "06e98f569d004c1315b991ded39924b21af84cf14cc94791b8aea337d25b57f8" url: "https://pub.dev" source: hosted version: "3.0.3" leak_tracker_testing: dependency: transitive description: name: leak_tracker_testing sha256: "6ba465d5d76e67ddf503e1161d1f4a6bc42306f9d66ca1e8f079a47290fb06d3" url: "https://pub.dev" source: hosted version: "3.0.1" matcher: dependency: transitive description: name: matcher sha256: d2323aa2060500f906aa31a895b4030b6da3ebdcc5619d14ce1aada65cd161cb url: "https://pub.dev" source: hosted version: "0.12.16+1" material_color_utilities: dependency: transitive description: name: material_color_utilities sha256: "0e0a020085b65b6083975e499759762399b4475f766c21668c4ecca34ea74e5a" url: "https://pub.dev" source: hosted version: "0.8.0" meta: dependency: transitive description: name: meta sha256: "7687075e408b093f36e6bbf6c91878cc0d4cd10f409506f7bc996f68220b9136" url: "https://pub.dev" source: hosted version: "1.12.0" path: dependency: transitive description: name: path sha256: "087ce49c3f0dc39180befefc60fdb4acd8f8620e5682fe2476afd0b3688bb4af" url: "https://pub.dev" source: hosted version: "1.9.0" plugin_platform_interface: dependency: transitive description: name: plugin_platform_interface sha256: "4820fbfdb9478b1ebae27888254d445073732dae3d6ea81f0b7e06d5dedc3f02" url: "https://pub.dev" source: hosted version: "2.1.8" sky_engine: dependency: transitive description: flutter source: sdk version: "0.0.99" source_span: dependency: transitive description: name: source_span sha256: "53e943d4206a5e30df338fd4c6e7a077e02254531b138a15aec3bd143c1a8b3c" url: "https://pub.dev" source: hosted version: "1.10.0" stack_trace: dependency: transitive description: name: stack_trace sha256: "73713990125a6d93122541237550ee3352a2d84baad52d375a4cad2eb9b7ce0b" url: "https://pub.dev" source: hosted version: "1.11.1" stream_channel: dependency: transitive description: name: stream_channel sha256: ba2aa5d8cc609d96bbb2899c28934f9e1af5cddbd60a827822ea467161eb54e7 url: "https://pub.dev" source: hosted version: "2.1.2" stream_transform: dependency: transitive description: name: stream_transform sha256: "14a00e794c7c11aa145a170587321aedce29769c08d7f58b1d141da75e3b1c6f" url: "https://pub.dev" source: hosted version: "2.1.0" string_scanner: dependency: transitive description: name: string_scanner sha256: "556692adab6cfa87322a115640c11f13cb77b3f076ddcc5d6ae3c20242bedcde" url: "https://pub.dev" source: hosted version: "1.2.0" term_glyph: dependency: transitive description: name: term_glyph sha256: a29248a84fbb7c79282b40b8c72a1209db169a2e0542bce341da992fe1bc7e84 url: "https://pub.dev" source: hosted version: "1.2.1" test_api: dependency: transitive description: name: test_api sha256: "9955ae474176f7ac8ee4e989dadfb411a58c30415bcfb648fa04b2b8a03afa7f" url: "https://pub.dev" source: hosted version: "0.7.0" vector_math: dependency: transitive description: name: vector_math sha256: "80b3257d1492ce4d091729e3a67a60407d227c27241d6927be0130c98e741803" url: "https://pub.dev" source: hosted version: "2.1.4" vm_service: dependency: transitive description: name: vm_service sha256: "3923c89304b715fb1eb6423f017651664a03bf5f4b29983627c4da791f74a4ec" url: "https://pub.dev" source: hosted version: "14.2.1" web: dependency: transitive description: name: web sha256: d43c1d6b787bf0afad444700ae7f4db8827f701bc61c255ac8d328c6f4d52062 url: "https://pub.dev" source: hosted version: "1.0.0" sdks: dart: ">=3.4.0 <4.0.0" flutter: ">=3.22.0" ```
huycozy commented 2 months ago

Thank you. I can see the same camera_android_camerax version as mine (0.6.7+2) on @iapicca comment. I still can't reproduce this issue but will label this for further input from others.

PerLycke commented 2 months ago

I've experienced the same issue on my Samsung S24 Ultra. Unfortunately, there aren't any specific steps to reproduce the problem, which I understand makes it challenging to address.

iapicca commented 2 months ago

I've experienced the same issue on my Samsung S24 Ultra. Unfortunately, there aren't any specific steps to reproduce the problem, which I understand makes it challenging to address.

@PerLycke what version? (both flutter and camera)

PerLycke commented 2 months ago

I've experienced the same issue on my Samsung S24 Ultra. Unfortunately, there aren't any specific steps to reproduce the problem, which I understand makes it challenging to address.

@PerLycke what version? (both flutter and camera)

Latest version for both:

camera: ^0.11.0+2

Flutter 3.24.0 stable channel

camsim99 commented 2 months ago

Just ran this on a Pixel 3A for 35 minutes and didn't see a crash. Wondering if this device specific and also if it has to do with https://github.com/flutter/flutter/issues/145893

iapicca commented 2 months ago

Just ran this on a Pixel 3A for 35 minutes and didn't see a crash. Wondering if this device specific and also if it has to do with #145893

@camsim99 I also didn't see crashes while "leaving the phone alone" but as mentioned with the same device the crash occurs quite quickly when "moving around" the phone, it's strange but it happens

(just start remember to "move the phone around" to make the camera do some work)

camsim99 commented 2 months ago

@iapicca Ah okay thanks for the clarification here. Next steps are to try that out and investigate if this is a memory leak.

camsim99 commented 2 months ago

I tried running this on the same device (Pixel 3A) for 15 minutes while moving it, but the stream doesn't stop. May have to try another device.

bartando commented 2 months ago

It happens to me on two devices i have available. Even when the device is stationary but the image in camera is moving. Both devices have same cpu MediaTek Helio G99 but different cameras.

I am on the latest version of camera lib.

camsim99 commented 1 month ago

Tried running this on a Samsung Galaxy S7 for 30ish minutes and still didn't see the issue.

For anyone who can repro and is willing to dig further:

We previously experienced a memory leak with image streaming, see https://github.com/flutter/flutter/issues/145893 for details. The fix for that can be found in https://github.com/flutter/packages/pull/6493. To explain the fix briefly, we have an InstanceManager that tracks native Camera-related objects and so, we increased the rate at which this InstanceManager removes instances it tracks and no longer needs when image streaming is performed.

For anyone willing to take a deeper look and see if it helps, you can increase the interval by lowering the CLEAR_FINALIZED_WEAK_REFERENCES_INTERVAL_FOR_IMAGE_ANALYSIS value. We would definitely appreciate anyone trying this out and would be open to landing a PR if this helps your case!

kwikwag commented 1 month ago

I can confirm this is happening when after upgrading from camera: ^0.10.6 to ^0.11.0+2, both on Android emulator (Windows 10, Pixel 4 API 29 x86 AVD) and on a real Samsung A54 5G.

Mairramer commented 1 month ago

It's been happening a lot to me on tablets from the Samsung A9 family.

Non-fatal Exception: io.flutter.plugins.firebase.crashlytics.FlutterError
PlatformException(java.lang.NullPointerException, NullPointerException, Cause: null, Stacktrace: java.lang.NullPointerException at java.util.Objects.requireNonNull(Objects.java:207) at qb.z5.d(Unknown Source:12) at qb.z5.a(Unknown Source:0) at qb.g3.c(Unknown Source:27) at qb.f3.a(Unknown Source:2) at mb.a$b.a(Unknown Source:17) at ab.c.l(Unknown Source:18) at ab.c.m(Unknown Source:41) at ab.c.i(Unknown Source:0) at ab.b.run(Unknown Source:12) at android.os.Handler.handleCallback(Handler.java:958) at android.os.Handler.dispatchMessage(Handler.java:99) at android.os.Looper.loopOnce(Looper.java:230) at android.os.Looper.loop(Looper.java:319) at android.app.ActivityThread.main(ActivityThread.java:8934) at java.lang.reflect.Method.invoke(Native Method) at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:578) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1103) , null)

ImageProxyHostApi.close (camerax_library.g.dart:2764) AndroidCameraCameraX._configureImageAnalysis.analyze (android_camera_camerax.dart:1236)

Mairramer commented 1 month ago

@camsim99 Superficial analysis: I managed to simulate this error in the emulator by decreasing DEFAULT_CLEAR_FINALIZED_WEAK_REFERENCES_INTERVAL to 500 and kept observing. In some cases, after 1 minute the error occurred and in others it took around 10 to 15 minutes for the error to occur.

One point is that for some reason the error reference always occurred with ImageProxy when trying to search the method:

void analyze(
    int identifier,
    int imageProxyIdentifier,
  ) {
    final Analyzer instance = _instanceManager.getInstanceWithWeakReference(identifier)!;
    final ImageProxy imageProxy = _instanceManager.getInstanceWithWeakReference(imageProxyIdentifier)!;
    instance.analyze(
      imageProxy,
    );
  }

I still need to check other points, but we have something superficial to start with. And must pass a function in startImageStream:

 await cameraController.startImageStream((CameraImage c){
        print('Image Stream');
     });
camsim99 commented 1 month ago

@Mairramer thank you for the analysis! This gives me some clarity.

@bparrishMines Is it possible that a tradeoff of lowering the interval of how often an InstanceManager removes garbage collected weak references to native Android objects (which we did before, see this comment for context) is that they get garbage collected prematurely? In this case, I'm specifically wondering if the ImageProxys that are not being found by the InstanceManager have been garbage collected before the plugin has the chance to close them, causing the error:

E/flutter ( 8806): [ERROR:flutter/runtime/dart_vm_initializer.cc(41)] Unhandled Exception: PlatformException(java.lang.NullPointerException, NullPointerException, Cause: null, Stacktrace: java.lang.NullPointerException
E/flutter ( 8806):      at java.util.Objects.requireNonNull(Objects.java:207)
E/flutter ( 8806):      at io.flutter.plugins.camerax.ImageProxyHostApiImpl.getImageProxyInstance(ImageProxyHostApiImpl.java:80)
E/flutter ( 8806):      at io.flutter.plugins.camerax.ImageProxyHostApiImpl.close(ImageProxyHostApiImpl.java:73)
bparrishMines commented 3 weeks ago

@Mairramer thank you for the analysis! This gives me some clarity.

@bparrishMines Is it possible that a tradeoff of lowering the interval of how often an InstanceManager removes garbage collected weak references to native Android objects (which we did before, see this comment for context) is that they get garbage collected prematurely? In this case, I'm specifically wondering if the ImageProxys that are not being found by the InstanceManager have been garbage collected before the plugin has the chance to close them, causing the error:

E/flutter ( 8806): [ERROR:flutter/runtime/dart_vm_initializer.cc(41)] Unhandled Exception: PlatformException(java.lang.NullPointerException, NullPointerException, Cause: null, Stacktrace: java.lang.NullPointerException
E/flutter ( 8806):      at java.util.Objects.requireNonNull(Objects.java:207)
E/flutter ( 8806):      at io.flutter.plugins.camerax.ImageProxyHostApiImpl.getImageProxyInstance(ImageProxyHostApiImpl.java:80)
E/flutter ( 8806):      at io.flutter.plugins.camerax.ImageProxyHostApiImpl.close(ImageProxyHostApiImpl.java:73)

The FinalizationListener shouldn't be able to remove it prematurely. Since the Dart ImageProxy should have priority that prevents the Java one from being removed. But I would have to check the specific implementation of the InstanceManager in the camera_android_camerax plugin.

However, since all plugins are now using Java 11 from https://github.com/flutter/packages/pull/7795#event-1452762262, we can switch the implementation to use Cleaners instead anyways.

Mairramer commented 3 weeks ago

@Mairramer thank you for the analysis! This gives me some clarity. @bparrishMines Is it possible that a tradeoff of lowering the interval of how often an InstanceManager removes garbage collected weak references to native Android objects (which we did before, see this comment for context) is that they get garbage collected prematurely? In this case, I'm specifically wondering if the ImageProxys that are not being found by the InstanceManager have been garbage collected before the plugin has the chance to close them, causing the error:

E/flutter ( 8806): [ERROR:flutter/runtime/dart_vm_initializer.cc(41)] Unhandled Exception: PlatformException(java.lang.NullPointerException, NullPointerException, Cause: null, Stacktrace: java.lang.NullPointerException
E/flutter ( 8806):      at java.util.Objects.requireNonNull(Objects.java:207)
E/flutter ( 8806):      at io.flutter.plugins.camerax.ImageProxyHostApiImpl.getImageProxyInstance(ImageProxyHostApiImpl.java:80)
E/flutter ( 8806):      at io.flutter.plugins.camerax.ImageProxyHostApiImpl.close(ImageProxyHostApiImpl.java:73)

The FinalizationListener shouldn't be able to remove it prematurely. Since the Dart ImageProxy should have priority that prevents the Java one from being removed. But I would have to check the specific implementation of the InstanceManager in the camera_android_camerax plugin.

However, since all plugins are now using Java 11 from flutter/packages#7795 (comment), we can switch the implementation to use Cleaners instead anyways.

@camsim99 @bparrishMines Although I'm not a Java expert, when performing local tests, I noticed that by replacing the use of HashMap with ConcurrentHashMap, the problem was apparently resolved. There was no significant increase in memory consumption, and the NullPointerException didn't occur anymore. I have a naive and perhaps silly question: could there have been some synchronization issue between the Dart and Java threads (even though they might not have anything to do with each other, I think), and by switching to ConcurrentHashMap, which is thread-safe, was this problem eliminated?

I still need to conduct more tests, but so far, testing the same scenario with just this change, I haven't encountered the problem again.

Update: Putting everything as ConcurrentHashMap the error still occurred, just with a lower frequency. Putting only the strongInstances as ConcurrentHashMap didn't really give an error, but it could just be a coincidence.

camsim99 commented 2 weeks ago

@Mairramer thank you for digging deeply into this!!

@bparrishMines Could what you mentioned about Cleaners be related to those findings? This is the camera's InstanceManger implementation for reference.

bparrishMines commented 2 weeks ago

@Mairramer Based on my understanding of the code, threading shouldn't be the problem. Essentially the issue is that the ImageProxy can't be found in the InstanceManager with the identifier provided. So the ImageProxy was never added, added incorrectly, or removed prematurely. Using the InstanceManager on a background thread could cause another error, but it probably shouldn't cause a NullPointerException.

My guess is that the problem could be a bug in the implementation. @camsim99 Pigeon ProxyApi support for Kotlin has landed, so we should update the plugin to use it. Ideally this should fix this problem and/or provide better debugging errors.

I just attempted to update Android InstanceManagers to use Cleaners, but it looks like it actually requires Android 33. Despite only requiring Java 9:

https://developer.android.com/reference/java/lang/ref/Cleaner