2016-08-24 13 views
2

Мое приложение управляет предварительным просмотром с камеры устройства с помощью API камеры2. Но проблема в том, что мое устройство - Nexus 5x, с перевернутым датчиком и хорошо известным обратным пейзажем. Я где-то читал, что camera2 api обрабатывает это «автоматически», но я думаю, что это верно только до тех пор, пока вы нацеливаете поверхность объекта Surface View при настройке сеанса захвата. Но вместо этого я нацеливаюсь на поверхность, построенную на поверхностной текстуре, которую я использую для предварительного просмотра, чтобы получить стереоскопическое представление, и при таком подходе проблема сохраняется, я получаю перевернутые рамки. Вот код, в значительной степени обычный рабочий процесс при работе с API камеры2.Как исправить проблему «обратного пейзажа» на Nexus 5x с помощью API камеры2

private void openCamera() { 
    CameraManager manager = (CameraManager) getSystemService(Context.CAMERA_SERVICE); 
    Log.e(TAG, "is camera open"); 
    try { 
     cameraId = manager.getCameraIdList()[CAMERA_SOURCE]; 
     CameraCharacteristics characteristics = manager.getCameraCharacteristics(cameraId); 
     StreamConfigurationMap map = characteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP); 
     assert map != null; 
     imageDimension = map.getOutputSizes(SurfaceTexture.class)[CAMERA_SOURCE]; 
     // Add permission for camera and let user grant the permission 
     if (ActivityCompat.checkSelfPermission(this, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) { 
      ActivityCompat.requestPermissions(MainActivity.this, new String[]{Manifest.permission.CAMERA, Manifest.permission.WRITE_EXTERNAL_STORAGE}, REQUEST_CAMERA_PERMISSION); 
      return; 
     } 
     manager.openCamera(cameraId, stateCallback, null); 

    } catch (CameraAccessException e) { 
     e.printStackTrace(); 
    } 
    Log.e(TAG, "openCamera X"); 
} 

private final CameraDevice.StateCallback stateCallback = new CameraDevice.StateCallback() { 
    @Override 
    public void onOpened(CameraDevice camera) { 
     //This is called when the camera is open 
     Log.e(TAG, "onOpened"); 
     cameraDevice = camera; 
     createCameraPreview(); 
    } 
    @Override 
    public void onDisconnected(CameraDevice camera) { 
     cameraDevice.close(); 
    } 
    @Override 
    public void onError(CameraDevice camera, int error) { 
     cameraDevice.close(); 
     cameraDevice = null; 
    } 
}; 

protected void createCameraPreview() { 
    try { 

     // Create ImageReader Surface 
     int max = 2; 
     mReader = ImageReader.newInstance(mWidth, mHeight, ImageFormat.YUV_420_888, max); 
     ImageReader.OnImageAvailableListener readerListener = new ImageReader.OnImageAvailableListener() { 
      @Override 
      public void onImageAvailable(ImageReader mReader) { 
       Image image = null; 
       image = mReader.acquireLatestImage(); 
       if (image == null) { 
        return; 
       }       

       byte[] bytes = convertYUV420ToNV21(image); 

       nativeVideoFrame(bytes); 
       image.close(); 
      } 
     };  

     mReader.setOnImageAvailableListener(readerListener, mBackgroundHandler); 

     // Create Texture Surface 
     texture = createTexture(); 
     mSurfaceTexture = new SurfaceTexture(texture); 
     mSurfaceTexture.setOnFrameAvailableListener(this); 
     mSurfaceTexture.setDefaultBufferSize(imageDimension.getWidth(), imageDimension.getHeight()); 
     mSurface = new Surface(mSurfaceTexture); 

     //Attach surfaces to CaptureRequest 
     List<Surface> outputSurfaces = new ArrayList<Surface>(2); 
     outputSurfaces.add(mReader.getSurface()); 
     outputSurfaces.add(mSurface); 
     captureRequestBuilder = cameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW); 
     captureRequestBuilder.addTarget(mSurface); 
     captureRequestBuilder.addTarget(mReader.getSurface()); 

     //Define the capture request 
     cameraDevice.createCaptureSession(outputSurfaces, new CameraCaptureSession.StateCallback(){ 
        @Override 
        public void onConfigured(@NonNull CameraCaptureSession cameraCaptureSession) { 
         //The camera is already closed 
         if (null == cameraDevice) { 
          return; 
         } 
         // When the session is ready, we start displaying the preview. 
         cameraCaptureSessions = cameraCaptureSession; 
         updatePreview(); 
        } 
        @Override 
        public void onConfigureFailed(@NonNull CameraCaptureSession cameraCaptureSession) { 
         Toast.makeText(MainActivity.this, "Configuration change", Toast.LENGTH_SHORT).show(); 
        } 
       }, null); 
     } catch (CameraAccessException e) { 
      e.printStackTrace(); 
     } 
} 

protected void updatePreview() { 
    if(null == cameraDevice) { 
     Log.e(TAG, "updatePreview error, return"); 
    } 
    captureRequestBuilder.set(CaptureRequest.CONTROL_MODE, CameraMetadata.CONTROL_MODE_AUTO); 
    try { 
     cameraCaptureSessions.setRepeatingRequest(captureRequestBuilder.build(), null, mBackgroundHandler); 
    } catch (CameraAccessException e) { 
     e.printStackTrace(); 
    } 
} 

Мой вопрос: Что мне делать, чтобы самостоятельно решить проблему ландшафта? Какую строку кода и где я должен добавить?

Спасибо,

JM

ответ

1

Поскольку вы используете SurfaceTexture и ImageReader вам придется обрабатывать вращения самостоятельно. API Camera2 автоматически обрабатывает вращение при использовании совместно с SurfaceView или TextureView.

Это означает, что вы можете вручную поворачивать байты кадра, как только вы получите их через обратный вызов ImageReader.OnImageAvailableListener, или даже лучше непосредственно на GPU, выполняющем действие в OpenGL Texture.

Обратите внимание, что вращение 180 ° эквивалентно переворачивать байты один раз по вертикали и по горизонтали один раз, что на OpenGL означает, что может либо:

  • Поворот на 180 ° в плоскости чертежа текстуры камеры
  • Scale на -1 х и у плоскости чертежа текстуры камеры
  • Изменения УФ плоскость камеры
+1

с SurfaceTexture, вам нужно использовать значение из https://developer.android.com/reference/an droid/graphics/SurfaceTexture.html # getTransformMatrix (float []) для чтения из текстуры GL; то вы получите правильную ориентацию (так выглядит TextureView) с камерой2. С помощью ImageReader вам нужно посмотреть ориентацию датчика камеры на https://developer.android.com/reference/android/hardware/camera2/CameraCharacteristics.html#SENSOR_ORIENTATION и получить доступ к пикселям в правильном порядке. –