/** * 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; }
/** * 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; }