Каков правильный способ получения кадров предварительного просмотра с помощью Android NDK Camera2

#android #c #android-ndk #android-camera2 #image-reader

#Android #c #android-ndk #android-camera2 #программа чтения изображений

Вопрос:

На основе образца текстуры камеры NDK я хочу создать, чтобы получить кадры предварительного просмотра ImageReader .

Что я сделал

Создайте сеанс ImageReader и камеру:

 yuvReader_ = new ImageReader(amp;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(amp;outputContainer_));
    for (autoamp; req : requests_) {
        if (!req.outputNativeWindow_) continue;

        ANativeWindow_acquire(req.outputNativeWindow_);
        CALL_OUTPUT(create(req.outputNativeWindow_, amp;req.sessionOutput_));
        CALL_CONTAINER(add(outputContainer_, req.sessionOutput_));
        CALL_TARGET(create(req.outputNativeWindow_, amp;req.target_));
        CALL_DEV(createCaptureRequest(cameras_[activeCameraId_].device_,
                                      req.template_, amp;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(),
                                  amp;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 amp;amp; 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
            );
 

Я также попробовал один запрос с двумя целевыми значениями вывода. Но код вызвал замораживание экрана:

 void NDKCamera::CreateSession(ANativeWindow* textureViewWindow, ANativeWindow* imgReaderWindow) {
    autoamp; req = requests_[PREVIEW_REQUEST_IDX];
    req.outputNativeWindow_ = textureViewWindow;
    req.yuvWindow = imgReaderWindow;
    req.template_ = TEMPLATE_PREVIEW;

    ACaptureSessionOutputContainer_create(amp;outputContainer_);
    CALL_DEV(createCaptureRequest(cameras_[activeCameraId_].device_,
                                          req.template_, amp;req.request_));
    
    // Add the texture view surface to the container
    ANativeWindow_acquire(req.outputNativeWindow_);
    CALL_OUTPUT(create(req.outputNativeWindow_, amp;req.sessionOutput_));
    CALL_CONTAINER(add(outputContainer_, req.sessionOutput_));
    CALL_TARGET(create(req.outputNativeWindow_, amp;req.target_));
    CALL_REQUEST(addTarget(req.request_, req.target_));

    // Add the image reader surface to the container
    ANativeWindow_acquire(req.yuvWindow);
    CALL_OUTPUT(create(req.yuvWindow, amp;req.yuvOutput));
    CALL_CONTAINER(add(outputContainer_, req.yuvOutput));
    CALL_TARGET(create(req.yuvWindow, amp;req.yuvTarget));
    CALL_REQUEST(addTarget(req.request_, req.yuvTarget));

    captureSessionState_ = CaptureSessionState::READY;
    ACameraDevice_createCaptureSession(cameras_[activeCameraId_].device_,
                                  outputContainer_, GetSessionListener(),
                                  amp;captureSession_);
}

void NDKCamera::StartPreview(bool start) {
  if (start) {
    ACaptureRequest* requests[] = { requests_[PREVIEW_REQUEST_IDX].request_};
    ACameraCaptureSession_setRepeatingRequest(captureSession_, nullptr, 1,
                                     requests,
                                     nullptr);
  } else if (!start amp;amp; captureSessionState_ == CaptureSessionState::ACTIVE) {
    ACameraCaptureSession_stopRepeating(captureSession_);
  }
}
 

Вот журнал:

 2021-12-14 08:42:20.316 24536-24556/com.sample.textureview D/ACameraDevice: Device error received, code 3, frame number 13, request ID 0, subseq ID 0
2021-12-14 08:42:21.319 24536-24556/com.sample.textureview D/ACameraDevice: Device error received, code 3, frame number 14, request ID 0, subseq ID 0
2021-12-14 08:42:22.321 24536-24584/com.sample.textureview D/ACameraDevice: Device error received, code 3, frame number 15, request ID 0, subseq ID 0
2021-12-14 08:42:23.323 24536-24584/com.sample.textureview D/ACameraDevice: Device error received, code 3, frame number 16, request ID 0, subseq ID 0
2021-12-14 08:42:24.325 24536-24556/com.sample.textureview D/ACameraDevice: Device error received, code 3, frame number 17, request ID 0, subseq ID 0
2021-12-14 08:42:25.328 24536-24584/com.sample.textureview D/ACameraDevice: Device error received, code 3, frame number 18, request ID 0, subseq ID 0
2021-12-14 08:42:26.330 24536-24584/com.sample.textureview D/ACameraDevice: Device error received, code 3, frame number 19, request ID 0, subseq ID 0
 

Кто-нибудь знает почему? Спасибо!

Ответ №1:

Я не знаю, как вы настроили свой Java-код для сравнения, но то, что вы делаете в коде NDK, снизит вашу частоту кадров вдвое. Если вы хотите получать как кадры предварительного просмотра, так и кадры в собственный ImageReader со скоростью 30 кадров в секунду, вам необходимо включить обе цели в один запрос на захват, а не чередовать два запроса на захват, каждый из которых нацелен только на один вывод. Последнее в лучшем случае даст вам 15 кадров в секунду для каждого вывода.

Итак, просто создайте один запрос и дважды вызовите addTarget для него как с окнами предварительного просмотра, так и с окнами YUV. Существуют ограничения на количество целей, которые вы можете добавить к одному запросу, но обычно это равно количеству целей, которые вы можете настроить за один сеанс, что зависит от аппаратных возможностей устройства и разрешения каждого вывода.

Однако всегда должны работать 2 потока, один предварительный просмотр и один привязанный к приложению YUV.

Комментарии:

1. На самом деле я попробовал один запрос с двумя целями. Но экран был заморожен после получения одного кадра камеры. Я получил сообщение D/ACameraDevice: Device error received, code 3, frame number 13, request ID 0, subseq ID 0 .

2. Какое разрешение выходных данных вы запрашиваете?

3. Разрешение 1664×768.