2017-02-13 22 views
1

Мне нужно делать снимки непрерывно с помощью Camera2 API. Он отлично работает на высокопроизводительных устройствах (например, Nexus 5X), но на более медленных (например, Samsung Galaxy A3) предварительный просмотр зависает.Камера Android2, делать снимок непрерывно

код немного долго, поэтому я выкладываю только наиболее значимые части:

метод, называемый начать свой предварительный просмотр:

private void startPreview() { 

    SurfaceTexture texture = mTextureView.getSurfaceTexture(); 

    if(texture != null) { 

     try { 

      // We configure the size of default buffer to be the size of camera preview we want. 
      texture.setDefaultBufferSize(mPreviewSize.getWidth(), mPreviewSize.getHeight()); 

      // This is the output Surface we need to start preview. 
      Surface surface = new Surface(texture); 

      // We set up a CaptureRequest.Builder with the output Surface. 
      mPreviewRequestBuilder = mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW); 
      mPreviewRequestBuilder.addTarget(surface); 

      // Here, we create a CameraCaptureSession for camera preview. 
      mCameraDevice.createCaptureSession(Arrays.asList(surface, mImageReader.getSurface()), new CameraCaptureSession.StateCallback() { 

        @Override 
        public void onConfigured(@NonNull CameraCaptureSession cameraCaptureSession) { 

         // If the camera is already closed, return: 
         if (mCameraDevice == null) { return; } 

         // When the session is ready, we start displaying the preview. 
         mCaptureSession = cameraCaptureSession; 

         // Auto focus should be continuous for camera preview. 
         mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE); 
         mPreviewRequest = mPreviewRequestBuilder.build(); 

         // Start the preview 
         try { mCaptureSession.setRepeatingRequest(mPreviewRequest, null, mPreviewBackgroundHandler); } 
         catch (CameraAccessException e) { e.printStackTrace(); } 
        } 

        @Override 
        public void onConfigureFailed(@NonNull CameraCaptureSession cameraCaptureSession) { 
         Log.e(TAG, "Configure failed"); 
        } 
       }, null 
      ); 
     } 
     catch (CameraAccessException e) { e.printStackTrace(); } 
    } 
} 

метод под названием, чтобы сделать снимок:

private void takePicture() { 

    try { 

     CaptureRequest.Builder captureBuilder = mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE); 
     captureBuilder.addTarget(mImageReader.getSurface()); 
     mCaptureSession.capture(captureBuilder.build(), null, mCaptureBackgroundHandler); 
    } 
    catch (CameraAccessException e) { e.printStackTrace(); } 
} 

И вот мой ImageReader:

private final ImageReader.OnImageAvailableListener mOnImageAvailableListener = new ImageReader.OnImageAvailableListener() { 

    @Override 
    public void onImageAvailable(final ImageReader reader) { 

     mSaveBackgroundHandler.post(new Runnable() { 

      @Override 
      public void run() { 

       // Set the destination file: 
       File destination = new File(getExternalFilesDir(null), "image_" + mNumberOfImages + ".jpg"); 
       mNumberOfImages++; 

       // Acquire the latest image: 
       Image image = reader.acquireLatestImage(); 

       // Save the image: 
       ByteBuffer buffer = image.getPlanes()[0].getBuffer(); 
       byte[] bytes = new byte[buffer.remaining()]; 
       buffer.get(bytes); 

       FileOutputStream output = null; 
       try { 
        output = new FileOutputStream(destination); 
        output.write(bytes); 
       } 
       catch (IOException e) { e.printStackTrace(); } 
       finally { 

        image.close(); 

        if (null != output) { 

         try { output.close(); } 
         catch (IOException e) { e.printStackTrace(); } 
        } 
       } 

       // Take a new picture if needed: 
       if(mIsTakingPictures) { 
        takePicture(); 
       } 
      } 
     }); 
    } 
}; 

У меня есть кнопка, которая переключает логику mIsTakingPictures и запускает первый вызов takePicture.

Резюмируя, я использую 3 темы:

  • один для предварительного просмотра
  • один для захвата
  • один для сохранения изображения

Что может быть причиной этого замораживания?

ответ

0

Невозможно избежать кадрирования, потерянного в предварительном просмотре, когда вы все время фотографируете на слабых устройствах. Единственный способ избежать этого - на устройствах, поддерживающих TEMPLATE_ZERO_SHUTTER_LAG и используя reprocessableCaptureSession. Документация об этом довольно ужасна и найти способ ее реализации может быть одиссеей. У меня эта проблема несколько месяцев назад, и, наконец, я нашел способ его реализации:

How to use a reprocessCaptureRequest with camera2 API

В этом ответе вы также можете найти некоторые испытания Google CTS, который также реализует ReprocessableCaptureSession и пострелять взрыв захватывает с шаблоном ZSL ,

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

Я также попытался осуществить захват пакета с помощью обработчика, который отправляет новый вызов capture каждые 100 миллисекунд, этот второй вариант был довольно хорош в производительности и избегал потери частоты кадров, но вы не получите столько кадров в секунду, сколько 2 ImageReader опция.

Надеюсь, что мой ответ вам немного поможет, API 2 все еще немного сложный, и не так много примеров или информации об этом.

1

Одна вещь, которую я заметил на устройствах нижнего уровня: предварительный просмотр останавливается после захвата, даже при использовании камеры 1 api, поэтому ее необходимо перезапустить вручную, создав при этом небольшой предварительный просмотр при захвате изображения с высоким разрешением.

Но камера 2 api обеспечивает возможность получения необработанного изображения при съемке неподвижного изображения (что было невозможно на устройствах, которые у меня есть при использовании камеры 1 (Huawei P7, Sony Xperia E5, wiko UFeel)).Использование этой функции намного быстрее, чем захват JPEG (возможно, из-за сжатия JPEG), поэтому предварительный просмотр можно перезапустить ранее, а предварительный замораживание будет короче. Конечно, используя это решение, вам придется преобразовать изображение из YUV в JPEG в фоновом задании.

 Смежные вопросы

  • Нет связанных вопросов^_^