简体   繁体   English

使用 Android NDK Camera2 获取预览帧的正确方法是什么

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

Based on NDK camera sample texture-view , I want to create an ImageReader to get preview frames.基于 NDK 相机示例texture-view ,我想创建一个ImageReader来获取预览帧。

What I've done我做了什么

Create the ImageReader and the camera session:创建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_));
}

Then start the preview:然后开始预览:

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_);
  }
}

I set two requests in setRepeatingRequest .我在setRepeatingRequest中设置了两个请求。 One for TextureView display, and the other for receiving the preview frames in C++.一个用于TextureView显示,另一个用于接收 C++ 中的预览帧。

Now, the problem is after setting two outputs, the preview performance goes down (looks like playing slides), which doesn't occur in Java:现在,问题是设置两个输出后,预览性能下降(看起来像播放幻灯片),这在 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
            );

Anybody knows why?有人知道为什么吗? Thanks!谢谢!

I don't know how you've set up your Java code by comparison, but what you're doing in the NDK code will drop your frame rate by half.相比之下,我不知道您是如何设置 Java 代码的,但是您在 NDK 代码中所做的事情会使您的帧速率降低一半。 If you want to get both preview frames and frames to the native ImageReader at 30fps, you need to include both targets in a single capture request, not alternate between two capture requests that each target just one output.如果您希望以 30fps 的速度将预览帧和帧都发送到本机 ImageReader,则需要在单个捕获请求中包含两个目标,而不是在每个仅针对一个 output 的两个捕获请求之间交替。 The latter will get you 15fps to each output at best.后者最多可为每个 output 提供 15fps。

So just create one request, and call addTarget twice on it with both the preview and the YUV windows.因此,只需创建一个请求,然后使用预览和 YUV windows 在其上调用 addTarget 两次。 There are limits on how many targets you can add to a single request, but generally that's equal to the number of targets you can configure in a single session, which depends on the hardware capability of the device, and the resolution of each output.单个请求可以添加多少个目标是有限制的,但通常等于单个 session 中可以配置的目标数量,这取决于设备的硬件能力,以及每个 output 的分辨率。

2 streams, one preview and one app-bound YUV, should always work, however.但是,2 个流,一个预览和一个应用绑定的 YUV,应该始终有效。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM