web-dev-qa-db-ja.com

Android camera2キャプチャバーストが遅すぎる

バースト画像をキャプチャするようにAndroid-Camera2Basicコードを変更しようとしています。ただし、L 5.0.1を実行しているNexus5では、画像間の遅延を200〜300ミリ秒より速く取得できません。

私はたくさんのことを試しましたが、これが最も基本的なことです。これは、私が変更したCamera2Basicコードの唯一の部分です。私のプレビューTextureViewは50x50dpだけですが、それは問題ではありませんよね?

価値があるのは、このコードの遅延は、L5.1を搭載したNexus6では約50〜100ミリ秒だけです。

private void captureStillPicture() {
    try {
        List<CaptureRequest> captureList = new ArrayList<CaptureRequest>();
        mPreviewRequestBuilder.addTarget(mImageReader.getSurface());

        for (int i=0;i<10;i++) {
            captureList.add(mPreviewRequestBuilder.build());
        }

        mCaptureSession.stopRepeating();
        mCaptureSession.captureBurst(captureList, cameraCaptureCallback, null);
        mPreviewRequestBuilder.removeTarget(mImageReader.getSurface());
    } catch (CameraAccessException e) {
        e.printStackTrace();
    }
}

CameraCaptureSession.CaptureCallback cameraCaptureCallback = new CameraCaptureSession.CaptureCallback() {
    @Override
    public void onCaptureCompleted(CameraCaptureSession session, CaptureRequest request,
            TotalCaptureResult result) {
        Log.d("camera","saved");
        mPictureCounter++;
        if (mPictureCounter >= 10)
            unlockFocus();
    }
};
12
acheroncaptain

発生している問題は、要求した画像出力形式のアーティファクトです。 JPEGエンコードプロセスでは、カメラパイプラインに大きなストール時間がかかるため、このエンコードが行われている間、1つの露出が終了してから次の露出が開始するまでに多くのダウンタイムが発生します。

引用されている30fpsのレートは、ImageReaderの出力画像形式をYUVとして設定することで実現できます。これは、カメラにとってより「ネイティブな」出力であるためです。これは、キャプチャされた画像を保存する方法であり、その後、カメラのインライン処理とは別に、JPEGエンコーディングを実行する必要があります。

たとえば、Nexus 5では、JPEGエンコーディングの出力ストール時間は243ミリ秒であり、これは観察されています。 _YUV_420_888_出力の場合、0msです。同様に、サイズが大きいため、_RAW_SENSOR_エンコーディングでは200msのストール時間が発生します。

また、「高速」フォーマットを選択してストール時間の障害を取り除いたとしても、出力画像のサイズに応じて、最小フレーム時間が存在することにも注意してください。しかし、Nexus 5のフル解像度出力の場合、これは33ミリ秒であり、これは予想どおりです。

関連情報は、カメラメタデータのStreamConfigurationMapオブジェクト、 ここ にあります。確認のためにgetOutputStallDuration(int format, Size size)メソッドとgetOutputMinFrameDuration(int format, Size size)メソッドを確認してください。

20
rcsumner

次のキャプチャリクエストパラメータを設定してみてください

requestBuilder = camDevice
        .createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE);

requestBuilder.set(CaptureRequest.Edge_MODE,
        CaptureRequest.Edge_MODE_OFF);
requestBuilder.set(
        CaptureRequest.LENS_OPTICAL_STABILIZATION_MODE,
        CaptureRequest.LENS_OPTICAL_STABILIZATION_MODE_ON);
requestBuilder.set(
        CaptureRequest.COLOR_CORRECTION_ABERRATION_MODE,
        CaptureRequest.COLOR_CORRECTION_ABERRATION_MODE_OFF);
requestBuilder.set(CaptureRequest.NOISE_REDUCTION_MODE,
        CaptureRequest.NOISE_REDUCTION_MODE_OFF);
requestBuilder.set(CaptureRequest.CONTROL_AF_TRIGGER,
        CaptureRequest.CONTROL_AF_TRIGGER_CANCEL);

requestBuilder.set(CaptureRequest.CONTROL_AE_LOCK, true);
requestBuilder.set(CaptureRequest.CONTROL_AWB_LOCK, true);

CameraCaptureSession.CaptureCallbackに情報がどのくらいの速さで届くかわかりません。画像データがなく、ImageReader.OnImageAvailableListenerの前または後に呼び出すことができます。 ImageReader.OnImageAvailableListener呼び出し間の時間を測定してみてください。また、バッファがいっぱいで画像が解放されていない場合、新しい画像は利用できないため、画像を読んで解放することを忘れないでください。例えば:

private class imageAvailableListener implements
            ImageReader.OnImageAvailableListener {
        @Override
        public void onImageAvailable(ImageReader ir) {
            Log.i(TAG, "Time = " + System.currentTimeMillis());
            Image im = ir.acquireNextImage();
            im.close();
        }
    }

ImageReader mImageReader = ImageReader.newInstance(imageReaderWidth,
                    imageReaderHeight, ImageFormat.YUV_420_888, 2);
mImageReader.setOnImageAvailableListener(
                    new imageAvailableListener(), null);
7
Maxim Metelskiy