2016-12-15 2 views
2

Я пытаюсь обновить камеру proyect до Android N и в соответствии с ней Im перемещение моего старого CameraCaptureSession в ReprocessableCaptureSession. Я сделал это, и он работает нормально, но с этой новой функцией я могу использовать шаблон CameraDevice.TEMPLATE_ZERO_SHUTTER_LAG в своем устройстве, и я могу перерабатывать кадры с помощью reprocessCaptureRequest.Как использовать repcessCaptureRequest с camera2 API

Здесь я вижу проблему. Потому что я не нахожу ни одного примера, и я не очень понимаю мало документации о том, как использовать reprocessCaptureRequest:

Каждый CaptureRequest обрабатывает повторно обработать один буфер от входной поверхности CameraCaptureSession для всех выходных поверхностей, включенных в Reprocess захвата. Образцы входного изображения должны быть сгенерированы из одного или нескольких выходных изображений, снятых с одного и того же устройства камеры. Приложение может предоставлять входные изображения в устройство камеры через queueInputImage (Image). Приложение должно использовать результат захвата одного из этих выходных изображений для создания запроса на захват репроцесса, чтобы устройство камеры могло использовать эту информацию для достижения оптимального качества изображения. Для устройств камеры, которые поддерживают только 1 выходную поверхность, отправка запроса CaptureRequest с несколькими выходными целями приведет к CaptureFailure.

Я попытался взглянуть на тесты CTS относительно камеры в google.sources, но они делают то же, что и я. Используя кратные imageReaders, сохраняя TotalCaptureResult из фотографий в LinkedBlockingQueue<TotalCaptureResult> А потом просто звоню:

TotalCaptureResult totalCaptureResult = state.captureCallback.getTotalCaptureResult(); 
CaptureRequest.Builder reprocessCaptureRequest = cameraStore.state().cameraDevice.createReprocessCaptureRequest(totalCaptureResult); 
reprocessCaptureRequest.addTarget(state.yuvImageReader.getSurface()); 
sessionStore.state().session.capture(reprocessCaptureRequest.build(), null, this.handlers.bg()); 

Но это всегда бросить меня RuntimeException: java.lang.RuntimeException: Capture failed: Reason 0 in frame 170,

Я просто wan't знать, что право способ работать с ReprocessableCaptureSession, я уже пробовал все, и я не знаю, что я делаю неправильно. Надеюсь, что кто-то сможет мне помочь!

Спасибо большое

+1

Что вы пытаетесь сделать с перерабатывающими здесь? Он предназначен для выполнения окончательной высококачественной обработки изображений (и, возможно, сжатия JPEG) на изображении, снятом камерой ранее в том же сеансе, поэтому он полезен для режимов нулевого спуска затвора. –

+0

То, что я хочу, это добиться режима задержки затвора в нулевом режиме. Но я не нашел в документации способ сделать это. –

+1

. Пожалуйста, добавьте больше вывода logcat, включая всю систему, а не только ваше приложение. Там, скорее всего, больше объясняется провал там. Во-первых, вы отправили изображение в ImageWriter для переработки? –

ответ

2

Наконец я нашел решение, чтобы сделать мою reprocessableCaptureSession работу. Я использую с архитектурой Flux, поэтому не путайте, когда вы видите Dispatcher.dispatch(action), просто посмотрите как обратный вызов. Итак, вот мой код:

Первые Как создается сессия:

//Configure preview surface 
    Size previewSize = previewState.previewSize; 
    previewState.previewTexture.setDefaultBufferSize(previewSize.getWidth(), previewSize.getHeight()); 

    ArrayList<Surface> targets = new ArrayList<>(); 
    for (SessionOutputTarget outputTarget : state.outputTargets) { 
     Surface surface = outputTarget.getSurface(); 
     if (surface != null) targets.add(surface); 
    } 
    targets.add(previewState.previewSurface); 
    CameraCharacteristics cameraCharacteristics = cameraStore.state().availableCameras.get(cameraStore.state().selectedCamera); 
    Size size = CameraCharacteristicsUtil.getYuvOutputSizes(cameraCharacteristics).get(0); 

    InputConfiguration inputConfiguration = new InputConfiguration(size.getWidth(), 
     size.getHeight(), ImageFormat.YUV_420_888); 

    CameraCaptureSession.StateCallback sessionStateCallback = new CameraCaptureSession.StateCallback() { 
     @Override 
     public void onConfigured(@NonNull CameraCaptureSession session) { 
      if (sessionId != currentSessionId) { 
       Timber.e("Session opened for an old open request, skipping. Current %d, Request %d", currentSessionId, sessionId); 
       //performClose(session); 
       return; 
      } 

      try { 
       session.getInputSurface(); 
       //This call is irrelevant, 
       //however session might have closed and this will throw an IllegalStateException. 
       //This happens if another camera app (or this one in another PID) takes control 
       //of the camera while its opening 
      } catch (IllegalStateException e) { 
       Timber.e("Another process took control of the camera while creating the session, aborting!"); 
      } 

      Dispatcher.dispatchOnUi(new SessionOpenedAction(session)); 
     } 

     @Override 
     public void onConfigureFailed(@NonNull CameraCaptureSession session) { 
      if (sessionId != currentSessionId) { 
       Timber.e("Configure failed for an old open request, skipping. Current %d, request %d", currentSessionId, sessionId); 
       return; 
      } 

      Timber.e("Failed to configure the session"); 
      Dispatcher.dispatchOnUi(new SessionFailedAction(session, new IllegalStateException("onConfigureFailed"))); 
     } 
    }; 

    if (state.outputMode == OutputMode.PHOTO) { 
     cameraState.cameraDevice.createReprocessableCaptureSession(inputConfiguration, targets, sessionStateCallback, handlers.bg()); 
    } else if (state.outputMode == OutputMode.VIDEO) { 
     cameraState.cameraDevice.createCaptureSession(targets, sessionStateCallback, handlers.bg()); 
    } 

    } catch (IllegalStateException | IllegalArgumentException e) { 
    Timber.e(e, "Something went wrong trying to start the session"); 
    } catch (CameraAccessException e) { 
    //Camera will throw CameraAccessException if another we try to open/close the 
    //session very fast. 
    Timber.e("Failed to access camera, it was closed"); 
    } 

Фотосессия, как было создано с 4-мя поверхности (Preview, YUV (вход), JPEG и RAW). После этого, я могу настроить ImageWriter:

Dispatcher.subscribe(Dispatcher.VERY_HIGH_PRIORITY, SessionOpenedAction.class) 
    .filter(a -> isInPhotoMode()) 
    .subscribe(action -> { 
      PhotoState newState = new PhotoState(state()); 
      newState.zslImageWriter = ImageWriter.newInstance(action.session.getInputSurface(), MAX_REPROCESS_IMAGES); 
      setState(newState); 
    }); 

Хорошо, теперь у нас есть ImageWriter и сеанс создан. Нет мы начинаем вытекание с повторяющейся запроса:

  CaptureRequest.Builder captureRequestBuilder = 
      cameraStore.state().cameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_ZERO_SHUTTER_LAG); 

     captureRequestBuilder.addTarget(previewStore.state().previewSurface); 
     captureRequestBuilder.addTarget(photoStore.state().yuvImageReader.getSurface()); 
     state.session.setRepeatingRequest(captureRequestBuilder.build(), state.zslCaptureCallback, handlers.bg()); 

Чтобы не добавлять много кода, просто сказать, что zslCaptureCallback обычай обратного вызова, которые сохраняют в LinkedBlockingQueue<TotalCaptureRequest> Х-последние TotalCaptureRequests. Кроме того, я делаю то же самое с yuvImageReader (входной), сохраняя последние X-изображения в очереди.

Наконец вот моя «сфотографировать» метод:

try { 
     //Retrieve the last image stored by the zslImageReader 
     Image image = zslImageReaderListener.getImage(); 
     //Retrieve the last totalCaptureResult from the zslCaptureCallback and create a reprocessableCaptureRequest with it 
     TotalCaptureResult captureResult = sessionStore.state().zslCaptureCallback.getCaptureResult(image.getTimestamp()); 
     CaptureRequest.Builder captureRequest = cameraStore.state().cameraDevice.createReprocessCaptureRequest(captureResult); 
     //Add the desired target and values to the captureRequest 
     captureRequest.addTarget(state().jpegImageReader.getSurface()); 
     //Queued back to ImageWriter for future consumption. 
     state.zslImageWriter.queueInputImage(image); 
     //Drain all the unused and queued CapturedResult from the CaptureCallback 
     sessionStore.state().zslCaptureCallback.drain(); 
     //Capture the desired frame 
     CaptureRequest futureCaptureResult = captureRequest.build(); 
     sessionStore.state().session.capture(futureCaptureResult, new CameraCaptureSession.CaptureCallback() { 
      @Override 
      public void onCaptureCompleted(@NonNull CameraCaptureSession session, 
              @NonNull CaptureRequest request, 
              @NonNull TotalCaptureResult result) { 
       Dispatcher.dispatchOnUi(new PhotoStatusChangedAction(PhotoState.Status.SUCCESS)); 
      } 

      @Override 
      public void onCaptureFailed(@NonNull CameraCaptureSession session, 
             @NonNull CaptureRequest request, 
             @NonNull CaptureFailure failure) { 
       super.onCaptureFailed(session, request, failure); 
       Exception captureFailedException = new RuntimeException(
       String.format("Capture failed: Reason %s in frame %d, was image captured? -> %s", 
        failure.getReason(), 
        failure.getFrameNumber(), 
        failure.wasImageCaptured())); 
       Timber.e(captureFailedException, "Cannot take mediaType, capture failed!"); 

       Dispatcher.dispatchOnUi(new PhotoStatusChangedAction(PhotoState.Status.ERROR, captureFailedException)); 
      } 
     }, this.handlers.bg()); 

     //Capture did not blow up, we are taking the photo now. 
     newState.status = PhotoState.Status.TAKING; 

    } catch (CameraAccessException | InterruptedException| IllegalStateException | IllegalArgumentException | SecurityException e) { 
     Timber.e(e, "Cannot take picture, capture error!"); 
     newState.status = PhotoState.Status.ERROR; 
    } 
Смежные вопросы