2016-08-24 30 views
2

我的應用程序使用camera2 API管理設備相機的預覽。但問題是,我的設備是Nexus 5x,具有翻轉傳感器和衆所周知的反向景觀「問題」。我在某處讀到camera2 api會「自動」處理這個問題,但我認爲只有在設置捕獲會話時指定Surface View對象的表面時,這纔是真實的。但相反,我的目標是建立在表面紋理上的表面,我進一步使用它來渲染預覽以獲得立體視圖,並且採用這種方法,問題仍然存在,我得到的是顛倒的框架。這裏是代碼,幾乎是使用camera2 API時的傳統工作流程。如何使用camera2修復Nexus 5x上的「反向風景」問題API

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

由於您使用的是表面紋理和ImageReader的你將不得不自己處理的旋轉。當與SurfaceView或TextureView結合使用時,Camera2 API會自動處理旋轉。

也就是說,一旦通過ImageReader.OnImageAvailableListener回調獲取它們,您可以手動旋轉幀的字節,或者直接在GPU上執行OpenGL紋理上的動作。

注意,旋轉180°等效於一次垂直翻轉字節,並且一旦水平,這基於OpenGL意味着可以:

  • 旋轉180°的平面由-1繪製相機紋理
  • 量表飛機的X和Y拉絲質感的相機
  • 更改相機平面
+1

的UV隨着表面紋理,則需要從https://developer.android.com/reference/an使用值droid/graphics/SurfaceTexture.html#getTransformMatrix(float [])從GL紋理讀取;那麼您將使用camera2獲得正確的方向(這是TextureView如何正確)。藉助ImageReader,您需要查看相機設備的傳感器方向https://developer.android.com/reference/android/hardware/camera2/CameraCharacteristics.html#SENSOR_ORIENTATION,並以正確的順序訪問像素。 –