2017-04-06 114 views
0

我試圖處理使用ImageReader的幀,同時還在SurfaceView上顯示視頻相機預覽。如果我添加的唯一目標曲面是SurfaceView,則預覽很平滑,但如果我將ImageReader添加爲第二個目標,則預覽開始嚴重滯後。爲什麼會這樣?我試圖創建一個HandlerThread和一個Handler並使用它們,但它並沒有改變一件事情。我現在唯一想到的是獲取並關閉下一張圖片。Camera2API添加ImageReader作爲目標表面滯後我的相機預覽

public void startBackgroundThread() { 
    handlerThread = new HandlerThread("Image Processing Thread"); 
    handlerThread.start(); 
    handler = new Handler(handlerThread.getLooper()); 
} 

配置攝像頭的位置:

public void configureCamera() { 
    try { 
     CameraCharacteristics characteristics = cameraManager.getCameraCharacteristics(cameraId); 
     StreamConfigurationMap configs = characteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP); 

     Size[] sizes = configs.getOutputSizes(ImageFormat.YUV_420_888); 
     imageReader = ImageReader.newInstance(sizes[0].getWidth(), sizes[0].getHeight(), ImageFormat.YUV_420_888, 1); 

     Range<Integer>[] ranges = characteristics.get(CameraCharacteristics.CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES); 
     fpsRange = ranges[ranges.length - 1]; 

     imageReader.setOnImageAvailableListener(this, handler); 

     cameraSurfaceView.getHolder().setFixedSize(sizes[0].getWidth(), sizes[0].getHeight()); 
    } catch (CameraAccessException | NullPointerException e) { 
     e.printStackTrace(); 
    } 
} 

啓動相機預覽:

private void startCamera() { 
    try { 
     cameraManager.openCamera("0", new CameraDevice.StateCallback() { 
      @Override 
      public void onOpened(@NonNull CameraDevice camera) { 
       cameraDevice = camera; 

       try { 
        cameraDevice.createCaptureSession(Arrays.asList(cameraSurfaceView.getHolder().getSurface(), imageReader.getSurface()), 
          new CameraCaptureSession.StateCallback() { 
           @Override 
           public void onConfigured(@NonNull CameraCaptureSession session) { 
            captureSession = session; 
            try { 
             requestBuilder = cameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW); 

             requestBuilder.addTarget(cameraSurfaceView.getHolder().getSurface()); 
             requestBuilder.addTarget(imageReader.getSurface()); 

             requestBuilder.set(CaptureRequest.FLASH_MODE, CaptureRequest.FLASH_MODE_TORCH); 
             requestBuilder.set(CaptureRequest.CONTROL_AE_TARGET_FPS_RANGE, fpsRange); 

             captureRequest = requestBuilder.build(); 
             cameraReady = true; 

             captureSession.setRepeatingRequest(captureRequest, null, handler); 

             onStartButtonClick(startButton); 
            } catch (CameraAccessException e) { 
             e.printStackTrace(); 
            } 
           } 

           @Override 
           public void onConfigureFailed(@NonNull CameraCaptureSession session) { 

           } 
          }, null); 
       } catch (CameraAccessException e) { 
        e.printStackTrace(); 
       } 
      } 

這裏來的ImageReader的OnImageAvailableListener(這是我目前的主要活動):

@Override 
public void onImageAvailable(ImageReader reader) { 
    reader.acquireNextImage().close(); 
} 

這些代碼片段都存在於我目前的主要活動中。我使用的手機是用於測試目的的摩托羅拉Moto X Play。 cameraSurfaceView只是一個簡單的SurfaceView,沒有任何自定義。

+0

我管理:

manager.openCamera(mCameraId, mStateCallback, mBackgroundHandler); 

這是一個單獨的線程啓動通過降低預覽的分辨率來獲得更高的fps數量,但這不是一個理想的解決方案 – masm64

回答

0

這看起來有點難以看到縮進,但它看起來像是在代碼片段的當前線程上運行相機處理程序。

cameraManager.openCamera中的最後一個參數告訴它要使用哪個線程 - 如果它爲null,則它只使用當前線程。從Android文檔:

參數 cameraId字符串:攝像設備的唯一標識符來打開

回調CameraDevice.StateCallback:一旦相機開啓

處理程序處理程序被調用的回調:應該在其上調用回調的處理程序,或者使用null來使用當前線程的活套。

如果您在GitHub上的Camera2Basic()的例子看,你可以看到他們指定單獨的處理程序:

/** 
    * Starts a background thread and its {@link Handler}. 
    */ 
    private void startBackgroundThread() { 
     mBackgroundThread = new HandlerThread("CameraBackground"); 
     mBackgroundThread.start(); 
     mBackgroundHandler = new Handler(mBackgroundThread.getLooper()); 
    } 
+0

感謝您的提示,但我已經嘗試了這一點,它不會傷心。 – masm64

+0

在上面的代碼提取中,您創建了一個處理程序,但它並未在openCamera調用中使用 - 請參見末尾的null。這將導致回調在主線程上運行。 – Mick

+0

我知道,但在代碼我目前正在運行給定的值不是null,但處理程序對象本身 – masm64