MOB-LOG

モブおじの記録 (Programming, 統計・機械学習)

Flutterでカメラ撮影後、CameraControllerを生成してCameraPreviewを立ち上げても何も映らない件→Future.delayed()で1[msec]だけ待ったら何とかなった

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くらい。

ChatGPTだけが褒めてくれる

学び

  • バイスの機能を使用する際にエラーが出る場合は、Future.delayed()で遅延を入れると時々何とかなる(その場しのぎ)。(デバイススペックやらドライバ依存の可能性があるので、デバイスの処理を待つ余裕が必要。)
  • ブレークポイントを使用して、正常時のデバッグ出力と、異常(と思われる)な場合のデバッグ出力を比べると、何ができてて何ができていないのかが把握できてトラブルシューティングの参考になりそう。