TL;DR
FlutterでCameraController.takePicture()
後にCameraPreview
を再起動するため、CameraControllerインスタンスを再生成・initialize()
していたらAndroidでの実機デバッグ中にinitialize()
が失敗してしまった。よくわからないが、インスタンスの生成→initialize()の間にほんの少しの遅延(今回はFuture.delayed(Duration(milliseconds: 1))
で十分だった)を入れることで解決した。多分デバイスのスペックの所為。スペック依存の問題は遅延を入れてデバイスに余裕を与えると、ときにその場しのぎだが問題が解決することがある。
事の起こり・問題
CameraController.takePicture()
でカメラから画像を取得したら、CameraPreview
によるプレビューが停まってしまった。プレビューを再開するために、以下の様にCameraController
を再生成してカメラのコントロールを再取得していた。
controller.dispose(); controller = CameraController( widget.cameras[camIndex], ResolutionPreset.medium, ); await controller.initialize();23323 setState(() { // 色々 }); /// 画面の再構築
しかし、Androidでの実機デバッグの際、controller.initialize()
の時点で以下のエラーが発生し、その後、CameraPreview(controller)
をウィジェットに返してもPreviewは起動せず再度撮影しても失敗しnull
が返ってくる問題が発生した。ちなみにinitialize()
後の setState(() {})
は一切実行されていない(ここが中断されたことに対するエラーは発生していない)。
E/hoge_project(31744): [SurfaceTexture-0-31744-3] setDefaultBufferSize: SurfaceTexture is abandoned! E/BufferQueueProducer(31744): [](id:7c000000000b,api:0,p:-1,c:31744) query: BufferQueue has been abandoned E/Camera-SurfaceUtils-JNI(31744): **SurfaceUtils_nativeDetectSurfaceDimens: Error while querying surface width No such device (-19).**
撮影→Previewの失敗→撮影の失敗→再度initialize()
を行うとCameraPreveiwが復活した。ダメもとで、CameraControllerの再生成とinitialize()
の間に遅延を入れると、エラーは吐かなくなった。。。(デバイスのスペック依存でドライバーの処理が間に合ってないのかな)
その場しのぎにしかなっていないが、CameraController.initialize()
だとかの
controller.dispose(); controller = CameraController( widget.cameras[camIndex], ResolutionPreset.medium, ); **await Future.delayed(Duration(milliseconds: 200));** await controller.initialize();
余談
時系列を分けてデバッグ出力を追っていくと、initialize()
とCameraPreview()
の間で以下のような出力がされていた。
/// CameraController.initialize() 後 I/Camera ( 3468): close I/Camera ( 3468): open | onClosed D/BufferQueueConsumer( 3468): [ImageReader-640x480f21m1-3468-0](id:d8c00000003,api:0,p:-1,c:3468) disconnect D/BufferQueueConsumer( 3468): [ImageReader-640x480f23m1-3468-1](id:d8c00000004,api:0,p:-1,c:3468) disconnect D/BufferQueueConsumer( 3468): [](id:d8c00000005,api:0,p:-1,c:3468) connect: controlledByApp=true I/Camera ( 3468): dispose I/Camera ( 3468): close D/BufferQueueConsumer( 3468): [SurfaceTexture-0-3468-1](id:d8c00000005,api:0,p:-1,c:3468) disconnect /// CameraPreview 後(Preveiwは表示されず) D/BufferQueueConsumer(31744): [](id:7c000000003f,api:0,p:-1,c:31744) connect: controlledByApp=true W/Camera (31744): The selected imageFormatGroup is not supported by Android. Defaulting to yuv420 D/BufferQueueConsumer(31744): [](id:7c0000000040,api:0,p:-1,c:31744) connect: controlledByApp=true I/Camera (31744): startPreview E/lighting_device(31744): [SurfaceTexture-0-31744-20] setDefaultBufferSize: SurfaceTexture is abandoned! E/BufferQueueProducer(31744): [](id:7c000000003e,api:0,p:-1,c:31744) query: BufferQueue has been abandoned E/Camera-SurfaceUtils-JNI(31744): SurfaceUtils_nativeDetectSurfaceDimens: Error while querying surface width No such device (-19). I/Camera (31744): open | onOpened error: Surface was abandoned
そしてdelayした後Previewが成功する場合、CameraController.initialize()後は以下のデバッグ出力が出る。先ほどの失敗する場合と全く異なるので、正常時のデバッグ出力と比較するのは参考になりそう。
I/Camera ( 3468): close D/BufferQueueConsumer( 3468): [](id:d8c0000000b,api:0,p:-1,c:3468) connect: controlledByApp=true D/BufferQueueConsumer( 3468): [](id:d8c0000000c,api:0,p:-1,c:3468) connect: controlledByApp=true W/Camera ( 3468): The selected imageFormatGroup is not supported by Android. Defaulting to yuv420 D/BufferQueueConsumer( 3468): [](id:d8c0000000d,api:0,p:-1,c:3468) connect: controlledByApp=true I/Camera ( 3468): startPreview I/Camera ( 3468): CameraCaptureSession onConfigured I/Camera ( 3468): Updating builder settings D/Camera ( 3468): Updating builder with feature: ExposureLockFeature D/Camera ( 3468): Updating builder with feature: ExposurePointFeature D/Camera ( 3468): Updating builder with feature: ZoomLevelFeature D/Camera ( 3468): Updating builder with feature: AutoFocusFeature D/Camera ( 3468): Updating builder with feature: NoiseReductionFeature I/Camera ( 3468): updateNoiseReduction | currentSetting: fast D/Camera ( 3468): Updating builder with feature: FocusPointFeature D/Camera ( 3468): Updating builder with feature: ResolutionFeature D/Camera ( 3468): Updating builder with feature: SensorOrientationFeature D/Camera ( 3468): Updating builder with feature: FlashFeature D/Camera ( 3468): Updating builder with feature: ExposureOffsetFeature D/Camera ( 3468): Updating builder with feature: FpsRangeFeature I/Camera ( 3468): refreshPreviewCaptureSession
遅延を入れたら解決したゾ、とChatGPTに報告したら「おめでとうございます!」と労わられた(もちろんその場しのぎだから調子に乗るなと嗜められる)。バグ取りして褒めてくれるのはChatGPTくらい。