/**
   * Selects the most suitable preview and picture size, given the desired width and height.
   *
   * <p>Even though we may only need the preview size, it's necessary to find both the preview size
   * and the picture size of the camera together, because these need to have the same aspect ratio.
   * On some hardware, if you would only set the preview size, you will get a distorted image.
   *
   * @param camera the camera to select a preview size from
   * @param desiredWidth the desired width of the camera preview frames
   * @param desiredHeight the desired height of the camera preview frames
   * @return the selected preview and picture size pair
   */
  private static SizePair selectSizePair(Camera camera, int desiredWidth, int desiredHeight) {
    List<SizePair> validPreviewSizes = generateValidPreviewSizeList(camera);

    // The method for selecting the best size is to minimize the sum of the differences between
    // the desired values and the actual values for width and height.  This is certainly not the
    // only way to select the best size, but it provides a decent tradeoff between using the
    // closest aspect ratio vs. using the closest pixel area.
    SizePair selectedPair = null;
    int minDiff = Integer.MAX_VALUE;
    for (SizePair sizePair : validPreviewSizes) {
      Size size = sizePair.previewSize();
      int diff =
          Math.abs(size.getWidth() - desiredWidth) + Math.abs(size.getHeight() - desiredHeight);
      if (diff < minDiff) {
        selectedPair = sizePair;
        minDiff = diff;
      }
    }

    return selectedPair;
  }
예제 #2
0
  /**
   * Opens the camera and applies the user settings.
   *
   * @throws RuntimeException if the method fails
   */
  @SuppressLint("InlinedApi")
  private Camera createCamera() {
    int requestedCameraId = getIdForRequestedCamera(mFacing);
    if (requestedCameraId == -1) {
      throw new RuntimeException(mContext.getString(R.string.no_requested_camera));
    }
    Camera camera = Camera.open(requestedCameraId);

    SizePair sizePair =
        selectSizePair(camera, mRequestedPreviewWidth, mRequestedPreviewHeight, mContext);
    if (sizePair == null) {
      throw new RuntimeException(mContext.getString(R.string.no_suitable_preview_size));
    }
    Size pictureSize = sizePair.pictureSize();
    mPreviewSize = sizePair.previewSize();

    int[] previewFpsRange = selectPreviewFpsRange(camera, mRequestedFps);
    if (previewFpsRange == null) {
      throw new RuntimeException(mContext.getString(R.string.no_suitable_frames_per_second));
    }

    Camera.Parameters parameters = camera.getParameters();

    parameters.setPictureSize(pictureSize.getWidth(), pictureSize.getHeight());
    parameters.setPreviewSize(mPreviewSize.getWidth(), mPreviewSize.getHeight());
    parameters.setPreviewFpsRange(
        previewFpsRange[Camera.Parameters.PREVIEW_FPS_MIN_INDEX],
        previewFpsRange[Camera.Parameters.PREVIEW_FPS_MAX_INDEX]);
    parameters.setPreviewFormat(ImageFormat.NV21);

    setRotation(camera, parameters, requestedCameraId);

    if (mFocusMode != null) {
      if (parameters.getSupportedFocusModes().contains(mFocusMode)) {
        parameters.setFocusMode(mFocusMode);
      } else {
        Log.i(
            TAG,
            mContext.getString(R.string.camera_focus_mode)
                + mFocusMode
                + mContext.getString(R.string.not_supported));
      }
    }

    // setting mFocusMode to the one set in the params
    mFocusMode = parameters.getFocusMode();

    if (mFlashMode != null) {
      if (parameters.getSupportedFlashModes().contains(mFlashMode)) {
        parameters.setFlashMode(mFlashMode);
      } else {
        Log.i(
            TAG,
            mContext.getString(R.string.flash_mode)
                + mFlashMode
                + mContext.getString(R.string.not_supported));
      }
    }

    // setting mFlashMode to the one set in the params
    mFlashMode = parameters.getFlashMode();

    camera.setParameters(parameters);

    // Four frame buffers are needed for working with the camera:
    //
    //   one for the frame that is currently being executed upon in doing detection
    //   one for the next pending frame to process immediately upon completing detection
    //   two for the frames that the camera uses to populate future preview images
    camera.setPreviewCallbackWithBuffer(new CameraPreviewCallback());
    camera.addCallbackBuffer(createPreviewBuffer(mPreviewSize));
    camera.addCallbackBuffer(createPreviewBuffer(mPreviewSize));
    camera.addCallbackBuffer(createPreviewBuffer(mPreviewSize));
    camera.addCallbackBuffer(createPreviewBuffer(mPreviewSize));

    return camera;
  }