簡體   English   中英

使用 Android NDK Camera2 獲取預覽幀的正確方法是什么

[英]What is the correct way to get Preview Frames using Android NDK Camera2

基於 NDK 相機示例texture-view ,我想創建一個ImageReader來獲取預覽幀。

我做了什么

創建ImageReader和相機 session:

yuvReader_ = new ImageReader(&compatibleCameraRes_, AIMAGE_FORMAT_YUV_420_888);
camera_->CreateSession(ANativeWindow_fromSurface(env_, surface), yuvReader_->GetNativeWindow());

void NDKCamera::CreateSession(ANativeWindow* previewWindow, ANativeWindow* yuvWindow) {
    // Create output from this app's ANativeWindow, and add into output container
    requests_[PREVIEW_REQUEST_IDX].outputNativeWindow_ = previewWindow;
    requests_[PREVIEW_REQUEST_IDX].template_ = TEMPLATE_PREVIEW;
    requests_[YUV_REQUEST_IDX].outputNativeWindow_ = yuvWindow;
    requests_[YUV_REQUEST_IDX].template_ = TEMPLATE_PREVIEW;

    CALL_CONTAINER(create(&outputContainer_));
    for (auto& req : requests_) {
        if (!req.outputNativeWindow_) continue;

        ANativeWindow_acquire(req.outputNativeWindow_);
        CALL_OUTPUT(create(req.outputNativeWindow_, &req.sessionOutput_));
        CALL_CONTAINER(add(outputContainer_, req.sessionOutput_));
        CALL_TARGET(create(req.outputNativeWindow_, &req.target_));
        CALL_DEV(createCaptureRequest(cameras_[activeCameraId_].device_,
                                      req.template_, &req.request_));
        CALL_REQUEST(addTarget(req.request_, req.target_));
    }

    // Create a capture session for the given preview request
    captureSessionState_ = CaptureSessionState::READY;
    CALL_DEV(createCaptureSession(cameras_[activeCameraId_].device_,
                                  outputContainer_, GetSessionListener(),
                                  &captureSession_));
}

然后開始預覽:

void NDKCamera::StartPreview(bool start) {
  if (start) {
    ACaptureRequest* requests[] = { requests_[PREVIEW_REQUEST_IDX].request_, requests_[YUV_REQUEST_IDX].request_};
    CALL_SESSION(setRepeatingRequest(captureSession_, nullptr, 2,
                                     requests,
                                     nullptr));
  } else if (!start && captureSessionState_ == CaptureSessionState::ACTIVE) {
    ACameraCaptureSession_stopRepeating(captureSession_);
  }
}

我在setRepeatingRequest中設置了兩個請求。 一個用於TextureView顯示,另一個用於接收 C++ 中的預覽幀。

現在,問題是設置兩個輸出后,預覽性能下降(看起來像播放幻燈片),這在 Java 中不會出現:

mCameraDevice.createCaptureSession(Arrays.asList(surface, mImageReader.getSurface()),
                    new CameraCaptureSession.StateCallback() {

                        @Override
                        public void onConfigured(@NonNull CameraCaptureSession cameraCaptureSession) {
                            // The camera is already closed
                            if (null == mCameraDevice) {
                                return;
                            }

                            mCaptureSession = cameraCaptureSession;
                            startPreview();
                        }

                        @Override
                        public void onConfigureFailed(
                                @NonNull CameraCaptureSession cameraCaptureSession) {
                            showToast("Failed");
                        }
                    }, null
            );

有人知道為什么嗎? 謝謝!

相比之下,我不知道您是如何設置 Java 代碼的,但是您在 NDK 代碼中所做的事情會使您的幀速率降低一半。 如果您希望以 30fps 的速度將預覽幀和幀都發送到本機 ImageReader,則需要在單個捕獲請求中包含兩個目標,而不是在每個僅針對一個 output 的兩個捕獲請求之間交替。 后者最多可為每個 output 提供 15fps。

因此,只需創建一個請求,然后使用預覽和 YUV windows 在其上調用 addTarget 兩次。 單個請求可以添加多少個目標是有限制的,但通常等於單個 session 中可以配置的目標數量,這取決於設備的硬件能力,以及每個 output 的分辨率。

但是,2 個流,一個預覽和一個應用綁定的 YUV,應該始終有效。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM