2015-06-01 83 views
1

我正在開發示例應用程序,該應用程序通過android中的相機爲我提供了指向圖像或對象的顏色代碼。我的應用程序與此應用程序類似,我正在使用this應用程序代碼。如何在每500ms後獲取相機預覽幀

使用此應用程序代碼,我可以連續獲取相機預覽幀,併爲我提供當前預覽幀的顏色代碼。我想讓它延遲一些。每500ms後我只想得到1個相機預覽幀。

我該怎麼做,我需要在這段代碼中做些什麼修改。

代碼:

class Preview extends SurfaceView implements SurfaceHolder.Callback, PreviewCallback { 

    public interface PreviewListener { 
     public void OnPreviewUpdated(int[] pixels, int width, int height); 
    } 

    PreviewListener listener; 
    SurfaceHolder mHolder; 
    Camera mCamera = null; 
    byte[] buffer; 
    int bufferSize; 
    private boolean isFrontCamera = false; 
    boolean lightOn = false; 

    private boolean isPaused = false; 

    //This variable is responsible for getting and setting the camera settings 
    private Parameters parameters; 
    //this variable stores the camera preview size 
    private Size previewSize; 
    //this array stores the pixels as hexadecimal pairs 
    private int[] pixels; 

    Preview(Context context) { 
     super(context); 

     // Install a SurfaceHolder.Callback so we get notified when the 
     // underlying surface is created and destroyed. 
     mHolder = getHolder(); 
     mHolder.addCallback(this); 
     mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS); 

     try { 
      // Instantiate the EnterColorListener so we can send events to the host 
      listener = (PreviewListener) context; 
     } catch (ClassCastException e) { 
      // The activity doesn't implement the interface, throw exception 
      throw new ClassCastException(context.toString() 
        + " must implement PreviewListener"); 
     } 
    } 

    public void surfaceCreated(SurfaceHolder holder) { 
     // The Surface has been created, acquire the camera and tell it where 
     // to draw. 
     try { 
      CameraInfo info = new CameraInfo(); 
      Camera.getCameraInfo(0, info); 
      if (info.facing == CameraInfo.CAMERA_FACING_FRONT) { 
       this.isFrontCamera = true; 
      } 
      mCamera = Camera.open(0); // attempt to get a Camera instance. index b/c front cameras are ok too. 

     } 
     catch (Exception e){ 
      // Camera is not available (in use or does not exist) 
      Log.e("camera error", "could not open camera"); 
      return; 
     } 
     try { 
      mCamera.setDisplayOrientation(90); 
      mCamera.setPreviewDisplay(holder); 
     } catch (IOException exception) { 
      mCamera.release(); 
      mCamera = null; 
     } 
    } 

    // thanks [email protected] 
    public void flash() { 
     if (supportsFlash()) { 
      if (!lightOn) { 
       lightOn = true; 
       mCamera.stopPreview(); 
       mCamera.setPreviewCallbackWithBuffer(this);// mCamera.setPreviewCallback(this);//setPreviewCallbackWithBuffer(this); 
       parameters.setFlashMode(Parameters.FLASH_MODE_TORCH); 
       mCamera.setParameters(parameters); 
       mCamera.startPreview(); 
      } else { 
       lightOn = false; 
       mCamera.stopPreview(); 
       mCamera.setPreviewCallbackWithBuffer(this); //setPreviewCallback(this);//setPreviewCallbackWithBuffer(this); 
       parameters.setFlashMode(Parameters.FLASH_MODE_OFF); 
       mCamera.setParameters(parameters); 
       mCamera.startPreview(); 
      } 
     } 
    } 

    // thanks http://ikravchenko.blogspot.com/2013/09/nexus-7-2013-torch-issue.html 
    public boolean supportsFlash() { 
     if (getContext().getPackageManager().hasSystemFeature(PackageManager.FEATURE_CAMERA_FLASH)) { 
      parameters = mCamera.getParameters(); 
      if (parameters.getFlashMode() != null) { 
       List<String> supportedFlashModes = parameters.getSupportedFlashModes(); 
       if (supportedFlashModes == null || supportedFlashModes.isEmpty() || supportedFlashModes.size() == 1 && supportedFlashModes.get(0).equals(Camera.Parameters.FLASH_MODE_OFF)) { 
        return false; 
       } 
       return true; 
      } 
     } 
     return false; 
    } 


    public void surfaceDestroyed(SurfaceHolder holder) { 
     // Surface will be destroyed when we return, so stop the preview. 
     // Because the CameraDevice object is not a shared resource, it's very 
     // important to release it when the activity is paused. 
     if (mCamera != null) { 
      mCamera.stopPreview(); 
      mCamera.setPreviewCallback(null);//setPreviewCallbackWithBuffer(null); 
      mCamera.release(); 
      mCamera = null; 
     } 
    } 

    public boolean isFrontCamera() { 
     return isFrontCamera; 
    } 

    /* TODO: fix the bug with the null pointer exception */ 
    public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) { 
     // Now that the size is known, set up the camera parameters and begin 
     // the preview. 
     if (mCamera != null) { 
      parameters = mCamera.getParameters(); 

      //to do autofocus, need to set the parameters if available 
      //http://stackoverflow.com/questions/11623266/camera-parameters-setfocusmode-is-not-working 
      List<String> focusModes = parameters.getSupportedFocusModes(); 
      if (focusModes != null) { 
       if (focusModes.contains(Parameters.FOCUS_MODE_CONTINUOUS_PICTURE)) 
        parameters.setFocusMode(Parameters.FOCUS_MODE_CONTINUOUS_PICTURE); 
       else if (focusModes.contains(Parameters.FOCUS_MODE_CONTINUOUS_VIDEO)) 
        parameters.setFocusMode(Parameters.FOCUS_MODE_CONTINUOUS_VIDEO); 
       else if (focusModes.contains(Parameters.FOCUS_MODE_AUTO)) 
        parameters.setFocusMode(Parameters.FOCUS_MODE_AUTO); 
      } 

      //have to get previewSizes because not all devices support arbitrary previews 
      //the following is from Stack Overflow 
      int width = this.getWidth(); 
      int height = this.getHeight(); 
      Size best = null; 
      List<Camera.Size> previewSizes = parameters.getSupportedPreviewSizes(); 
      // You need to choose the most appropriate previewSize for your app 
      for (int i = 0; i < previewSizes.size(); i++) { 
       Size size = previewSizes.get(i); 
       if ((size.width <= width && size.height <= height) || (size.height <= width && size.width <= height)) { 
        if (best==null) { 
         best=size; 
        } else { 
         int resultArea=best.width*best.height; 
         int newArea=size.width*size.height; 

         if (newArea>resultArea) { 
          best=size; 
         } 
        } 
       } 
      } 

      // make sure something is picked. previewSizes is guarenteed to have at least one thing. 
      if (best != null) { 
       previewSize = best; 
      } else { 
       previewSize = previewSizes.get(0); 
      } 

      parameters.setPreviewSize(previewSize.width, previewSize.height); 
      pixels = new int[previewSize.width * previewSize.height]; 
      mCamera.setParameters(parameters); 

      //sets the camera callback to be the one defined in this class 
      mCamera.setPreviewCallbackWithBuffer(this);//setPreviewCallback(this);//setPreviewCallbackWithBuffer(this); 
      bufferSize = previewSize.width*previewSize.height*ImageFormat.getBitsPerPixel(parameters.getPreviewFormat())/8; 
      buffer = new byte[bufferSize]; 
      resetBuffer(); 

      if (!isPaused) mCamera.startPreview(); 

     } 
    } 

    public void pause(boolean isPaused) { 
     this.isPaused = isPaused; 
     if (isPaused) { 
      parameters.setFlashMode(Parameters.FLASH_MODE_OFF); 
      mCamera.setParameters(parameters); 
      mCamera.stopPreview(); 
     } else { 
      if (mCamera != null) { 
       mCamera.setPreviewCallbackWithBuffer(this);//setPreviewCallback(this);//setPreviewCallbackWithBuffer(this); 

       if(lightOn) 
        parameters.setFlashMode(Parameters.FLASH_MODE_TORCH); 

       mCamera.setParameters(parameters); 
       mCamera.startPreview(); 
      } 
     } 
    } 

    public void resetBuffer() { 
     if (mCamera != null) { 
      mCamera.addCallbackBuffer(buffer); 
     } 
    } 


    @Override 
    public void onPreviewFrame(byte[] data, Camera camera) { 
     //transforms NV21 pixel data into RGB pixels 
     decodeYUV420SP(pixels, data, previewSize.width, previewSize.height); 
     listener.OnPreviewUpdated(pixels, previewSize.width, previewSize.height); 
    } 

    //Method from Ketai project! Not mine! See below... 
    void decodeYUV420SP(int[] rgb, byte[] yuv420sp, int width, int height) { 

      final int frameSize = width * height; 

      for (int j = 0, yp = 0; j < height; j++) {  int uvp = frameSize + (j >> 1) * width, u = 0, v = 0; 
       for (int i = 0; i < width; i++, yp++) { 
       int y = (0xff & ((int) yuv420sp[yp])) - 16; 
       if (y < 0) 
        y = 0; 
       if ((i & 1) == 0) { 
        v = (0xff & yuv420sp[uvp++]) - 128; 
        u = (0xff & yuv420sp[uvp++]) - 128; 
       } 

       int y1192 = 1192 * y; 
       int r = (y1192 + 1634 * v); 
       int g = (y1192 - 833 * v - 400 * u); 
       int b = (y1192 + 2066 * u); 

       if (r < 0)     r = 0;    else if (r > 262143) 
        r = 262143; 
       if (g < 0)     g = 0;    else if (g > 262143) 
        g = 262143; 
       if (b < 0)     b = 0;    else if (b > 262143) 
        b = 262143; 

       rgb[yp] = 0xff000000 | ((r << 6) & 0xff0000) | ((g >> 2) & 0xff00) | ((b >> 10) & 0xff); 
       } 
     } 
    } 

} 
+0

你可以設置儘可能低的幀率,然後只是忽略你不想要的幀? – fadden

+0

由於其設備相關,我無法將幀率設置得儘可能低。所以我不確定其他設備的幀速率 –

+0

將相機設置爲30fps。捕捉一幀,忽略下一個14. – fadden

回答

0

你可以算出onPreviewFrame經過的時間()。例如:

boolean isFirstTime = true; 
    long startTime = 0; 
    PreviewCallback callback = new PreviewCallback() { 
     @Override 
     public void onPreviewFrame(byte[] data, Camera camera) { 
      // TODO Auto-generated method stub 
      if (isFirstTime) { 
       isFirstTime = false; 
       startTime = SystemClock.currentThreadTimeMillis(); 
       decodeYUV420SP(pixels, data, previewSize.width, previewSize.height); 
       listener.OnPreviewUpdated(pixels, previewSize.width, previewSize.height); 
      } 
      else { 
       long currentTime = SystemClock.currentThreadTimeMillis(); 
       long elapsedTime = currentTime - startTime; 
       if (elapsedTime >= 500) { // trigger your event 
        startTime = currentTime; 
        decodeYUV420SP(pixels, data, previewSize.width, previewSize.height); 
        listener.OnPreviewUpdated(pixels, previewSize.width, previewSize.height); 
       } 
      } 
     } 
    }; 

當您切換預覽狀態時,不要忘記重置布爾值和開始時間。

+0

感謝您的回覆,我不能用這樣的代碼: '@覆蓋 公共無效onPreviewFrame(字節[]數據,攝像頭攝像頭){// 轉換NV21的像素數據轉換成RGB像素 嘗試{ 的Thread.sleep (350); (例外e) { } } decodeYUV420SP(pixels,data,previewSize.width,previewSize.height); listener.OnPreviewUpdated(pixels,previewSize.width,previewSize.height); }' –

+0

我在這裏只用了Thread.sleep()函數 –

+0

@sam_k你爲什麼要用Thread.sleep()?該函數將阻塞主線程。 – yushulx

0

沒有什麼能保證精確的500ms - 相機硬件沒有設置爲立即響應。不過,你可以相當接近。首先,從後臺處理程序線程打開相機(請參閱https://stackoverflow.com/a/19154438/192373)。

public void onPreviewFrame(byte[] data, Camera camera) { 
    long releaseTime = SystemClock.currentThreadTimeMillis() + 500; 
    decodeYUV420SP(pixels, data, previewSize.width, previewSize.height); 
    listener.OnPreviewUpdated(pixels, previewSize.width, previewSize.height); 
    resetBuffer(); 
    SystemClock.sleep(releaseTime-SystemClock.currentThreadTimeMillis()); 
} 

這假定decodeYUV420SP()OnPreviewUpdated()一起花太多500ms以內。