web-dev-qa-db-ja.com

Camera2のプレビューコールバックはCamera1よりも大幅に遅くなります

2017年になり、ようやくCamera1からCamera2への切り替えを開始しました。 Camera1では、リアルタイムフレーム処理を実行するためにsetPreviewCallbackWithBuffer()に大きく依存していましたが、Camera2では、これははるかに遅く、ほとんど使用できなくなります。

比較すると、Moto G3ではCamera1は30〜40 FPSを簡単に生成できますが、Camera2では10〜15FPSを超えることはできませんでした。

これが私がImageReaderを作成する方法です

imageReader = ImageReader
  .newInstance(
    previewSize.width,        // size is around 1280x720
    previewSize.height,
    ImageFormat.YUV_420_888,  // note, it is not JPEG
    2 // max number of images, does not really affect performance
  );

imageReader.setOnImageAvailableListener(
  callback,
  CameraThread.getInstance().createHandler()
);

コールバック自体は、可能な限り最小限の仕事をします。

Image image = reader.acquireNextImage();
image.close();

これ などの同様の回答をすでに確認しました。ただし、問題は、YUV_420_888ではなくJPEG画像形式を使用していることです。

Camera1と同様のパフォーマンスを実現するにはどうすればよいですか?

27
Dmitry Zaytsev

Camera1APIとCamera2APIの両方をサポートするアプリで同じパフォーマンスの問題が発生しました。 AndroidバージョンがLollipopを上回っていたとき、以前はCamera2 APIに切り替えていたため、パフォーマンスが非常に悪くなりました(ImageReaderとSurfaceの2つのターゲットがありました)。

電話でハードウェアが完全にサポートされている場合にのみ、Camera2APIを使用することになりました。 CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVELを使用して確認できます。

それが役に立てば幸い

3
Josef Grunig

これは単なる観察ですが、とにかく投稿します。

OnImageAvailableListener を登録していると言います。このリスナーは画像を配信しませんが、サブスクライブした同じImageReaderへの参照を配信します。次に、実際の画像を取得するには、acquireLatestImageまたはacquireNextImageのいずれかを呼び出す必要があります。

docs には、何が起こっているのかを理解するのに役立つ可能性のある段落があります。

画像データはImageオブジェクトにカプセル化され、maxImagesコンストラクターパラメーターで指定された数まで、複数のそのようなオブジェクトに同時にアクセスできます。 Surfaceを介してImageReaderに送信された新しい画像は、acquireLatestImage()またはacquireNextImage()呼び出しを介してアクセスされるまでキューに入れられます。 メモリの制限により、ImageReaderが画像を取得および解放しない場合、画像ソースは最終的に画像を停止またはドロップしてサーフェスにレンダリングしようとします。生産率。

だから役立つかもしれないいくつかのこと:

  • マニフェストで大容量メモリを要求する
  • 十分な大きさのmaxImages引数をImageReaderコンストラクターに渡します(とにかくキューを使い果たすと、IllegalStateExceptionを取得します)。
  • リアルタイム処理にはacquireLatestImageよりもacquireNextImageを優先します。この方法では古い画像が自動的に解放されますが、他の方法では解放されないため、誤ってacquireNextImageを使用すると、メモリが不足するまで画像の配信がますます遅くなります。
2
Mister Smith