轻松玩转Camera,使用CameraView来拍照,修改CameraView 实现自定义拍照分辨率

前言

对于拍照功能来说,Android 由于版本不同可以使用不同的书写方式,光API就有Camera和Camera2两套,其余的区别还有

API Level Camera API Preview View
9-13 Camera1 SurfaceView
14-20 Camera1 TextureView
21-23 Camera2 TextureView
24 Camera2 SurfaceView


虽然Android能够向下兼容,但是谁不想使用更新的API和技术,另一方面,Camera API调用起来也不方便,所以对Camera调用的封装势在必行。

github上面有一些,但是使用时经常出现兼容性,适配等问题,直到发现了Google自己封装的CameraView,地址:
https://github.com/google/cameraview

但是使用的时候,你会发现一个问题我怎么设置我拍出照片的分辨率?
官方提供了Ratio,宽高比的属性,但是没有提供设置分辨率的API和属性。

下面我就会介绍怎么修改代码来实现这个,当然你要是不想自己改,可以直接使用我修改好的,地址:
https://github.com/DiskyZhs/CameraView
直接作为lib导入就可以了。

修改源码

查看源码结构

轻松玩转Camera,使用CameraView来拍照,修改CameraView 实现自定义拍照分辨率_第1张图片

你会发现找到CameraViewImp这个CameraView的接口封装,这里面封装了CameraView对外的接口封装,如下

abstract class CameraViewImpl {

    protected final Callback mCallback;

    protected final PreviewImpl mPreview;

    CameraViewImpl(Callback callback, PreviewImpl preview) {
        mCallback = callback;
        mPreview = preview;
    }

    View getView() {
        return mPreview.getView();
    }

    /**
     * @return {@code true} if the implementation was able to start the camera session.
     */
    abstract boolean start();

    abstract void stop();

    abstract boolean isCameraOpened();

    abstract void setFacing(int facing);

    abstract int getFacing();

    abstract Set getSupportedAspectRatios();

    /**
     * @return {@code true} if the aspect ratio was changed.
     */
    abstract boolean setAspectRatio(AspectRatio ratio);

    abstract AspectRatio getAspectRatio();

    abstract void setAutoFocus(boolean autoFocus);

    abstract boolean getAutoFocus();

    abstract void setFlash(int flash);

    abstract int getFlash();

    abstract void takePicture();

    abstract void setDisplayOrientation(int displayOrientation);

    interface Callback {

        void onCameraOpened();

        void onCameraClosed();

        void onPictureTaken(byte[] data);

    }

}

我们添加接口

     /**
     * 设置拍摄出来照片的分辨率
     */
    abstract void setPictureSize(int width,int height);

然后修改Camer1.java文件,实现Camera1 API下面接口的实现 ,如下:

/*
 * Copyright (C) 2016 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.google.android.cameraview;

import android.annotation.SuppressLint;
import android.graphics.SurfaceTexture;
import android.hardware.Camera;
import android.os.Build;
import android.support.v4.util.SparseArrayCompat;
import android.view.SurfaceHolder;

import java.io.IOException;
import java.util.List;
import java.util.Set;
import java.util.SortedSet;
import java.util.concurrent.atomic.AtomicBoolean;


@SuppressWarnings("deprecation")
class Camera1 extends CameraViewImpl {

    private static final int INVALID_CAMERA_ID = -1;

    private static final SparseArrayCompat FLASH_MODES = new SparseArrayCompat<>();

    static {
        FLASH_MODES.put(Constants.FLASH_OFF, Camera.Parameters.FLASH_MODE_OFF);
        FLASH_MODES.put(Constants.FLASH_ON, Camera.Parameters.FLASH_MODE_ON);
        FLASH_MODES.put(Constants.FLASH_TORCH, Camera.Parameters.FLASH_MODE_TORCH);
        FLASH_MODES.put(Constants.FLASH_AUTO, Camera.Parameters.FLASH_MODE_AUTO);
        FLASH_MODES.put(Constants.FLASH_RED_EYE, Camera.Parameters.FLASH_MODE_RED_EYE);
    }

    private int mCameraId;

    private final AtomicBoolean isPictureCaptureInProgress = new AtomicBoolean(false);

    Camera mCamera;

    private Camera.Parameters mCameraParameters;

    private final Camera.CameraInfo mCameraInfo = new Camera.CameraInfo();

    private final SizeMap mPreviewSizes = new SizeMap();

    private final SizeMap mPictureSizes = new SizeMap();

    private AspectRatio mAspectRatio;

    private boolean mShowingPreview;

    private boolean mAutoFocus;

    private int mFacing;

    private int mFlash;

    private int mDisplayOrientation;

    /**
     * 自定义的设置
     */
    private Size mSettingPictureSize;

    /**
     * 自定义的预览的分辨率
     */
    private Size mSettingPreviewSize;

    Camera1(Callback callback, PreviewImpl preview) {
        super(callback, preview);
        preview.setCallback(new PreviewImpl.Callback() {
            @Override
            public void onSurfaceChanged() {
                if (mCamera != null) {
                    setUpPreview();
                    adjustCameraParameters();
                }
            }
        });
    }

    @Override
    boolean start() {
        chooseCamera();
        openCamera();
        if (mPreview.isReady()) {
            setUpPreview();
        }
        mShowingPreview = true;
        mCamera.startPreview();
        return true;
    }

    @Override
    void stop() {
        if (mCamera != null) {
            mCamera.stopPreview();
        }
        mShowingPreview = false;
        releaseCamera();
    }

    // Suppresses Camera#setPreviewTexture
    @SuppressLint("NewApi")
    void setUpPreview() {
        try {
            if (mPreview.getOutputClass() == SurfaceHolder.class) {
                final boolean needsToStopPreview = mShowingPreview && Build.VERSION.SDK_INT < 14;
                if (needsToStopPreview) {
                    mCamera.stopPreview();
                }
                mCamera.setPreviewDisplay(mPreview.getSurfaceHolder());
                if (needsToStopPreview) {
                    mCamera.startPreview();
                }
            } else {
                mCamera.setPreviewTexture((SurfaceTexture) mPreview.getSurfaceTexture());
            }
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    @Override
    boolean isCameraOpened() {
        return mCamera != null;
    }

    @Override
    void setFacing(int facing) {
        if (mFacing == facing) {
            return;
        }
        mFacing = facing;
        if (isCameraOpened()) {
            stop();
            start();
        }
    }

    @Override
    int getFacing() {
        return mFacing;
    }

    @Override
    Set getSupportedAspectRatios() {
        return mPreviewSizes.ratios();
    }

    @Override
    boolean setAspectRatio(AspectRatio ratio) {
        if (mAspectRatio == null || !isCameraOpened()) {
            // Handle this later when camera is opened
            mAspectRatio = ratio;
            return true;
        } else if (!mAspectRatio.equals(ratio)) {
            final Set sizes = mPreviewSizes.sizes(ratio);
            if (sizes == null) {
                throw new UnsupportedOperationException(ratio + " is not supported");
            } else {
                mAspectRatio = ratio;
                adjustCameraParameters();
                return true;
            }
        }
        return false;
    }

    @Override
    AspectRatio getAspectRatio() {
        return mAspectRatio;
    }

    @Override
    void setAutoFocus(boolean autoFocus) {
        if (mAutoFocus == autoFocus) {
            return;
        }
        if (setAutoFocusInternal(autoFocus)) {
            mCamera.setParameters(mCameraParameters);
        }
    }

    @Override
    boolean getAutoFocus() {
        if (!isCameraOpened()) {
            return mAutoFocus;
        }
        String focusMode = mCameraParameters.getFocusMode();
        return focusMode != null && focusMode.contains("continuous");
    }

    @Override
    void setFlash(int flash) {
        if (flash == mFlash) {
            return;
        }
        if (setFlashInternal(flash)) {
            mCamera.setParameters(mCameraParameters);
        }
    }

    @Override
    int getFlash() {
        return mFlash;
    }

    @Override
    void takePicture() {
        if (!isCameraOpened()) {
            throw new IllegalStateException(
                    "Camera is not ready. Call start() before takePicture().");
        }
        if (getAutoFocus()) {
            mCamera.cancelAutoFocus();
            mCamera.autoFocus(new Camera.AutoFocusCallback() {
                @Override
                public void onAutoFocus(boolean success, Camera camera) {
                    takePictureInternal();
                }
            });
        } else {
            takePictureInternal();
        }
    }

    void takePictureInternal() {
        if (!isPictureCaptureInProgress.getAndSet(true)) {
            mCamera.takePicture(null, null, null, new Camera.PictureCallback() {
                @Override
                public void onPictureTaken(byte[] data, Camera camera) {
                    isPictureCaptureInProgress.set(false);
                    mCallback.onPictureTaken(data);
                    camera.cancelAutoFocus();
                    camera.startPreview();
                }
            });
        }
    }

    @Override
    void setDisplayOrientation(int displayOrientation) {
        if (mDisplayOrientation == displayOrientation) {
            return;
        }
        mDisplayOrientation = displayOrientation;
        if (isCameraOpened()) {
            int cameraRotation = calcCameraRotation(displayOrientation);
            mCameraParameters.setRotation(cameraRotation);
            mCamera.setParameters(mCameraParameters);
            final boolean needsToStopPreview = mShowingPreview && Build.VERSION.SDK_INT < 14;
            if (needsToStopPreview) {
                mCamera.stopPreview();
            }
            mCamera.setDisplayOrientation(cameraRotation);
            if (needsToStopPreview) {
                mCamera.startPreview();
            }
        }
    }

    /**
     * 设置拍摄出来照片的分辨率
     *
     * @param width
     * @param height
     */
    @Override
    void setPictureSize(int width, int height) {
        mSettingPictureSize = new Size(width, height);
        adjustCameraParameters();
    }

    /**
     * This rewrites {@link #mCameraId} and {@link #mCameraInfo}.
     */
    private void chooseCamera() {
        for (int i = 0, count = Camera.getNumberOfCameras(); i < count; i++) {
            Camera.getCameraInfo(i, mCameraInfo);
            if (mCameraInfo.facing == mFacing) {
                mCameraId = i;
                return;
            }
        }
        mCameraId = INVALID_CAMERA_ID;
    }

    private void openCamera() {
        if (mCamera != null) {
            releaseCamera();
        }
        mCamera = Camera.open(mCameraId);
        mCameraParameters = mCamera.getParameters();
        // Supported preview sizes
        mPreviewSizes.clear();
        for (Camera.Size size : mCameraParameters.getSupportedPreviewSizes()) {
            mPreviewSizes.add(new Size(size.width, size.height));
        }
        // Supported picture sizes;
        mPictureSizes.clear();
        for (Camera.Size size : mCameraParameters.getSupportedPictureSizes()) {
            mPictureSizes.add(new Size(size.width, size.height));
        }
        // AspectRatio
        if (mAspectRatio == null) {
            mAspectRatio = Constants.DEFAULT_ASPECT_RATIO;
        }
        adjustCameraParameters();
        mCamera.setDisplayOrientation(calcCameraRotation(mDisplayOrientation));
        mCallback.onCameraOpened();
    }

    private AspectRatio chooseAspectRatio() {
        AspectRatio r = null;
        for (AspectRatio ratio : mPreviewSizes.ratios()) {
            r = ratio;
            if (ratio.equals(Constants.DEFAULT_ASPECT_RATIO)) {
                return ratio;
            }
        }
        return r;
    }

    /**
     * 设置相机参数
     */
    void adjustCameraParameters() {
        SortedSet sizes = mPreviewSizes.sizes(mAspectRatio);
        //根据设置的宽高比来筛选出支持的PreviewSize
        if (sizes == null) { // Not supported
            mAspectRatio = chooseAspectRatio();
            sizes = mPreviewSizes.sizes(mAspectRatio);
        }
        //选取最合适的PreviewSize
        Size size = chooseOptimalSize(sizes);
        final Camera.Size currentSize = mCameraParameters.getPictureSize();
        if (currentSize.width != size.getWidth() || currentSize.height != size.getHeight()) {
            // Largest picture size in this ratio
            //Size pictureSize = mPictureSizes.sizes(mAspectRatio).last();
            //根据宽高比设置实际拍照Size
            Size pictureSize = null;
            SortedSet pictureSizeS = mPictureSizes.sizes(mAspectRatio);
            if (mSettingPictureSize == null) {
                pictureSize = pictureSizeS.last(); //选择最大的Size
            } else {
                pictureSize = chooseSuitableSize(pictureSizeS, mSettingPictureSize);
            }
            if (mShowingPreview) {
                mCamera.stopPreview();
            }
            mCameraParameters.setPreviewSize(size.getWidth(), size.getHeight());
            mCameraParameters.setPictureSize(pictureSize.getWidth(), pictureSize.getHeight());
            mCameraParameters.setRotation(calcCameraRotation(mDisplayOrientation));
            setAutoFocusInternal(mAutoFocus);
            setFlashInternal(mFlash);
            mCamera.setParameters(mCameraParameters);
            if (mShowingPreview) {
                mCamera.startPreview();
            }
        }
    }

    /**
     * 选择合适的pictureSize
     */
    private Size chooseSuitableSize(SortedSet sizes, Size desiredSize) {
        Size result = null;
        for (Size size : sizes) { // Iterate from small to large
            if (desiredSize.getWidth() <= size.getWidth() && desiredSize.getHeight() <= size.getHeight()) {
                return size;

            }
            result = size;
        }
        return result;
    }

    @SuppressWarnings("SuspiciousNameCombination")
    private Size chooseOptimalSize(SortedSet sizes) {
        if (!mPreview.isReady()) { // Not yet laid out
            return sizes.first(); // Return the smallest size
        }
        int desiredWidth;
        int desiredHeight;
        final int surfaceWidth = mPreview.getWidth();
        final int surfaceHeight = mPreview.getHeight();
        if (mDisplayOrientation == 90 || mDisplayOrientation == 270) {
            desiredWidth = surfaceHeight;
            desiredHeight = surfaceWidth;
        } else {
            desiredWidth = surfaceWidth;
            desiredHeight = surfaceHeight;
        }
        Size result = null;
        for (Size size : sizes) { // Iterate from small to large
            if (desiredWidth <= size.getWidth() && desiredHeight <= size.getHeight()) {
                return size;

            }
            result = size;
        }
        return result;
    }

    private void releaseCamera() {
        if (mCamera != null) {
            mCamera.release();
            mCamera = null;
            mCallback.onCameraClosed();
        }
    }

    private int calcCameraRotation(int rotation) {
        if (mCameraInfo.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {
            return (360 - (mCameraInfo.orientation + rotation) % 360) % 360;
        } else {  // back-facing
            return (mCameraInfo.orientation - rotation + 360) % 360;
        }
    }

    /**
     * @return {@code true} if {@link #mCameraParameters} was modified.
     */
    private boolean setAutoFocusInternal(boolean autoFocus) {
        mAutoFocus = autoFocus;
        if (isCameraOpened()) {
            final List modes = mCameraParameters.getSupportedFocusModes();
            if (autoFocus && modes.contains(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE)) {
                mCameraParameters.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE);
            } else if (modes.contains(Camera.Parameters.FOCUS_MODE_FIXED)) {
                mCameraParameters.setFocusMode(Camera.Parameters.FOCUS_MODE_FIXED);
            } else if (modes.contains(Camera.Parameters.FOCUS_MODE_INFINITY)) {
                mCameraParameters.setFocusMode(Camera.Parameters.FOCUS_MODE_INFINITY);
            } else {
                mCameraParameters.setFocusMode(modes.get(0));
            }
            return true;
        } else {
            return false;
        }
    }

    /**
     * @return {@code true} if {@link #mCameraParameters} was modified.
     */
    private boolean setFlashInternal(int flash) {
        if (isCameraOpened()) {
            List modes = mCameraParameters.getSupportedFlashModes();
            String mode = FLASH_MODES.get(flash);
            if (modes != null && modes.contains(mode)) {
                mCameraParameters.setFlashMode(mode);
                mFlash = flash;
                return true;
            }
            String currentMode = FLASH_MODES.get(mFlash);
            if (modes == null || !modes.contains(currentMode)) {
                mCameraParameters.setFlashMode(Camera.Parameters.FLASH_MODE_OFF);
                mFlash = Constants.FLASH_OFF;
                return true;
            }
            return false;
        } else {
            mFlash = flash;
            return false;
        }
    }

}

添加了setPictureSize()函数的实现,修改了adjustCameraParameters()函数,该函数就是在OpenCamera之前设置Camera参数的,其中包括PictureSize,拍照分辨率




接下来完成Camera2中setPictureSize的实现,如下

/*
 * Copyright (C) 2016 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.google.android.cameraview;

import android.Manifest;
import android.annotation.TargetApi;
import android.content.Context;
import android.content.pm.PackageManager;
import android.graphics.ImageFormat;
import android.hardware.camera2.CameraAccessException;
import android.hardware.camera2.CameraCaptureSession;
import android.hardware.camera2.CameraCharacteristics;
import android.hardware.camera2.CameraDevice;
import android.hardware.camera2.CameraManager;
import android.hardware.camera2.CaptureRequest;
import android.hardware.camera2.CaptureResult;
import android.hardware.camera2.TotalCaptureResult;
import android.hardware.camera2.params.StreamConfigurationMap;
import android.media.Image;
import android.media.ImageReader;
import android.support.annotation.NonNull;
import android.support.v4.app.ActivityCompat;
import android.util.Log;
import android.util.SparseIntArray;
import android.view.Surface;
import android.widget.Toast;

import java.nio.ByteBuffer;
import java.util.Arrays;
import java.util.Set;
import java.util.SortedSet;
import java.util.TreeSet;

@TargetApi(21)
class Camera2 extends CameraViewImpl {

    private static final String TAG = "Camera2";

    private static final SparseIntArray INTERNAL_FACINGS = new SparseIntArray();

    static {
        INTERNAL_FACINGS.put(Constants.FACING_BACK, CameraCharacteristics.LENS_FACING_BACK);
        INTERNAL_FACINGS.put(Constants.FACING_FRONT, CameraCharacteristics.LENS_FACING_FRONT);
    }

    /**
     * Max preview width that is guaranteed by Camera2 API
     */
    private static final int MAX_PREVIEW_WIDTH = 1920;

    /**
     * Max preview height that is guaranteed by Camera2 API
     */
    private static final int MAX_PREVIEW_HEIGHT = 1080;

    /**
     * 自定义的设置
     */
    private Size mSettingPictureSize;

    /**
     * 自定义的预览的分辨率
     */
    private Size mSettingPreviewSize;


    private final CameraManager mCameraManager;

    private final CameraDevice.StateCallback mCameraDeviceCallback
            = new CameraDevice.StateCallback() {

        @Override
        public void onOpened(@NonNull CameraDevice camera) {
            mCamera = camera;
            mCallback.onCameraOpened();
            startCaptureSession();
        }

        @Override
        public void onClosed(@NonNull CameraDevice camera) {
            mCallback.onCameraClosed();
        }

        @Override
        public void onDisconnected(@NonNull CameraDevice camera) {
            mCamera = null;
        }

        @Override
        public void onError(@NonNull CameraDevice camera, int error) {
            Log.e(TAG, "onError: " + camera.getId() + " (" + error + ")");
            mCamera = null;
        }

    };

    private final CameraCaptureSession.StateCallback mSessionCallback
            = new CameraCaptureSession.StateCallback() {

        @Override
        public void onConfigured(@NonNull CameraCaptureSession session) {
            if (mCamera == null) {
                return;
            }
            mCaptureSession = session;
            updateAutoFocus();
            updateFlash();
            try {
                mCaptureSession.setRepeatingRequest(mPreviewRequestBuilder.build(),
                        mCaptureCallback, null);
            } catch (CameraAccessException e) {
                Log.e(TAG, "Failed to start camera preview because it couldn't access camera", e);
            } catch (IllegalStateException e) {
                Log.e(TAG, "Failed to start camera preview.", e);
            }
        }

        @Override
        public void onConfigureFailed(@NonNull CameraCaptureSession session) {
            Log.e(TAG, "Failed to configure capture session.");
        }

        @Override
        public void onClosed(@NonNull CameraCaptureSession session) {
            if (mCaptureSession != null && mCaptureSession.equals(session)) {
                mCaptureSession = null;
            }
        }

    };

    PictureCaptureCallback mCaptureCallback = new PictureCaptureCallback() {

        @Override
        public void onPrecaptureRequired() {
            mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER,
                    CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER_START);
            setState(STATE_PRECAPTURE);
            try {
                mCaptureSession.capture(mPreviewRequestBuilder.build(), this, null);
                mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER,
                        CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER_IDLE);
            } catch (CameraAccessException e) {
                Log.e(TAG, "Failed to run precapture sequence.", e);
            }
        }

        @Override
        public void onReady() {
            captureStillPicture();
        }

    };

    private final ImageReader.OnImageAvailableListener mOnImageAvailableListener
            = new ImageReader.OnImageAvailableListener() {

        @Override
        public void onImageAvailable(ImageReader reader) {
            try (Image image = reader.acquireNextImage()) {
                Image.Plane[] planes = image.getPlanes();
                if (planes.length > 0) {
                    ByteBuffer buffer = planes[0].getBuffer();
                    byte[] data = new byte[buffer.remaining()];
                    buffer.get(data);
                    mCallback.onPictureTaken(data);
                }
            }
        }

    };


    private String mCameraId;

    private CameraCharacteristics mCameraCharacteristics;

    CameraDevice mCamera;

    CameraCaptureSession mCaptureSession;

    CaptureRequest.Builder mPreviewRequestBuilder;

    private ImageReader mImageReader;

    private final SizeMap mPreviewSizes = new SizeMap();

    private final SizeMap mPictureSizes = new SizeMap();

    private int mFacing;

    private AspectRatio mAspectRatio = Constants.DEFAULT_ASPECT_RATIO;

    private boolean mAutoFocus;

    private int mFlash;

    private int mDisplayOrientation;

    private Context mContext;

    Camera2(Callback callback, PreviewImpl preview, Context context) {
        super(callback, preview);
        mContext = context;
        mCameraManager = (CameraManager) context.getSystemService(Context.CAMERA_SERVICE);
        mPreview.setCallback(new PreviewImpl.Callback() {
            @Override
            public void onSurfaceChanged() {
                startCaptureSession();
            }
        });
    }

    @Override
    boolean start() {
        if (!chooseCameraIdByFacing()) {
            return false;
        }
        collectCameraInfo();
        prepareImageReader();
        startOpeningCamera();
        return true;
    }

    @Override
    void stop() {
        if (mCaptureSession != null) {
            mCaptureSession.close();
            mCaptureSession = null;
        }
        if (mCamera != null) {
            mCamera.close();
            mCamera = null;
        }
        if (mImageReader != null) {
            mImageReader.close();
            mImageReader = null;
        }
    }

    @Override
    boolean isCameraOpened() {
        return mCamera != null;
    }

    @Override
    void setFacing(int facing) {
        if (mFacing == facing) {
            return;
        }
        mFacing = facing;
        if (isCameraOpened()) {
            stop();
            start();
        }
    }

    @Override
    int getFacing() {
        return mFacing;
    }

    @Override
    Set getSupportedAspectRatios() {
        return mPreviewSizes.ratios();
    }

    @Override
    boolean setAspectRatio(AspectRatio ratio) {
        if (ratio == null || ratio.equals(mAspectRatio) ||
                !mPreviewSizes.ratios().contains(ratio)) {
            // TODO: Better error handling
            return false;
        }
        mAspectRatio = ratio;
        if (mCaptureSession != null) {
            mCaptureSession.close();
            mCaptureSession = null;
            startCaptureSession();
        }
        return true;
    }

    @Override
    AspectRatio getAspectRatio() {
        return mAspectRatio;
    }

    @Override
    void setAutoFocus(boolean autoFocus) {
        if (mAutoFocus == autoFocus) {
            return;
        }
        mAutoFocus = autoFocus;
        if (mPreviewRequestBuilder != null) {
            updateAutoFocus();
            if (mCaptureSession != null) {
                try {
                    mCaptureSession.setRepeatingRequest(mPreviewRequestBuilder.build(),
                            mCaptureCallback, null);
                } catch (CameraAccessException e) {
                    mAutoFocus = !mAutoFocus; // Revert
                }
            }
        }
    }

    @Override
    boolean getAutoFocus() {
        return mAutoFocus;
    }

    @Override
    void setFlash(int flash) {
        if (mFlash == flash) {
            return;
        }
        int saved = mFlash;
        mFlash = flash;
        if (mPreviewRequestBuilder != null) {
            updateFlash();
            if (mCaptureSession != null) {
                try {
                    mCaptureSession.setRepeatingRequest(mPreviewRequestBuilder.build(),
                            mCaptureCallback, null);
                } catch (CameraAccessException e) {
                    mFlash = saved; // Revert
                }
            }
        }
    }

    @Override
    int getFlash() {
        return mFlash;
    }

    @Override
    void takePicture() {
        if (mAutoFocus) {
            lockFocus();
        } else {
            captureStillPicture();
        }
    }

    @Override
    void setDisplayOrientation(int displayOrientation) {
        mDisplayOrientation = displayOrientation;
        mPreview.setDisplayOrientation(mDisplayOrientation);
    }

    /**
     * 设置拍摄出来照片的分辨率
     *
     * @param width
     * @param height
     */
    @Override
    void setPictureSize(int width, int height) {
        mSettingPictureSize = new Size(width, height);
        Log.e(TAG, "camera setPictureSize width =" + width);
        prepareImageReader();
    }

    /**
     * 

Chooses a camera ID by the specified camera facing ({@link #mFacing}).

*

This rewrites {@link #mCameraId}, {@link #mCameraCharacteristics}, and optionally * {@link #mFacing}.

*/
private boolean chooseCameraIdByFacing() { try { int internalFacing = INTERNAL_FACINGS.get(mFacing); final String[] ids = mCameraManager.getCameraIdList(); if (ids.length == 0) { // No camera throw new RuntimeException("No camera available."); } for (String id : ids) { CameraCharacteristics characteristics = mCameraManager.getCameraCharacteristics(id); Integer level = characteristics.get( CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL); if (level == null || level == CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL_LEGACY) { continue; } Integer internal = characteristics.get(CameraCharacteristics.LENS_FACING); if (internal == null) { throw new NullPointerException("Unexpected state: LENS_FACING null"); } if (internal == internalFacing) { mCameraId = id; mCameraCharacteristics = characteristics; return true; } } // Not found mCameraId = ids[0]; mCameraCharacteristics = mCameraManager.getCameraCharacteristics(mCameraId); Integer level = mCameraCharacteristics.get( CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL); if (level == null || level == CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL_LEGACY) { return false; } Integer internal = mCameraCharacteristics.get(CameraCharacteristics.LENS_FACING); if (internal == null) { throw new NullPointerException("Unexpected state: LENS_FACING null"); } for (int i = 0, count = INTERNAL_FACINGS.size(); i < count; i++) { if (INTERNAL_FACINGS.valueAt(i) == internal) { mFacing = INTERNAL_FACINGS.keyAt(i); return true; } } // The operation can reach here when the only camera device is an external one. // We treat it as facing back. mFacing = Constants.FACING_BACK; return true; } catch (CameraAccessException e) { throw new RuntimeException("Failed to get a list of camera devices", e); } } /** * 收集相机信息 *

Collects some information from {@link #mCameraCharacteristics}.

*

This rewrites {@link #mPreviewSizes}, {@link #mPictureSizes}, and optionally, * {@link #mAspectRatio}.

*/
private void collectCameraInfo() { StreamConfigurationMap map = mCameraCharacteristics.get( CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP); if (map == null) { throw new IllegalStateException("Failed to get configuration map: " + mCameraId); } mPreviewSizes.clear(); for (android.util.Size size : map.getOutputSizes(mPreview.getOutputClass())) { mPreviewSizes.add(new Size(size.getWidth(), size.getHeight())); } mPictureSizes.clear(); collectPictureSizes(mPictureSizes, map); if (!mPreviewSizes.ratios().contains(mAspectRatio)) { mAspectRatio = mPreviewSizes.ratios().iterator().next(); } } protected void collectPictureSizes(SizeMap sizes, StreamConfigurationMap map) { for (android.util.Size size : map.getOutputSizes(ImageFormat.JPEG)) { mPictureSizes.add(new Size(size.getWidth(), size.getHeight())); } } /** * 设置ImageReader(拍照的Size) */ private void prepareImageReader() { //根据宽高比设置实际拍照Size Size pictureSize = null; SortedSet pictureSizeS = mPictureSizes.sizes(mAspectRatio); Log.e(TAG, "prepareImageReader mAspectRatio =" + mAspectRatio.toString()); Log.e(TAG, "prepareImageReader pictureSizeS =" + pictureSizeS.toString()); if (mSettingPictureSize == null) { pictureSize = pictureSizeS.last(); //选择最大的Size } else { pictureSize = chooseSuitableSize(pictureSizeS, mSettingPictureSize); } mImageReader = ImageReader.newInstance(pictureSize.getWidth(), pictureSize.getHeight(), ImageFormat.JPEG, /* maxImages */ 2); mImageReader.setOnImageAvailableListener(mOnImageAvailableListener, null); } /** * 选择合适的pictureSize */ private Size chooseSuitableSize(SortedSet sizes, Size desiredSize) { Size result = null; for (Size size : sizes) { // Iterate from small to large if (desiredSize.getWidth() <= size.getWidth() && desiredSize.getHeight() <= size.getHeight()) { return size; } result = size; } return result; } /** *

Starts opening a camera device.

*

The result will be processed in {@link #mCameraDeviceCallback}.

*/
private void startOpeningCamera() { try { if (ActivityCompat.checkSelfPermission(mContext, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) { //Todo处理提示 Toast.makeText(mContext, "相机权限未设置", Toast.LENGTH_SHORT).show(); } else { mCameraManager.openCamera(mCameraId, mCameraDeviceCallback, null); } } catch (CameraAccessException e) { throw new RuntimeException("Failed to open camera: " + mCameraId, e); } } /** *

Starts a capture session for camera preview.

*

This rewrites {@link #mPreviewRequestBuilder}.

*

The result will be continuously processed in {@link #mSessionCallback}.

*/
void startCaptureSession() { if (!isCameraOpened() || !mPreview.isReady() || mImageReader == null) { return; } Size previewSize = chooseOptimalSize(); mPreview.setBufferSize(previewSize.getWidth(), previewSize.getHeight()); Surface surface = mPreview.getSurface(); try { mPreviewRequestBuilder = mCamera.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW); mPreviewRequestBuilder.addTarget(surface); mCamera.createCaptureSession(Arrays.asList(surface, mImageReader.getSurface()), mSessionCallback, null); } catch (CameraAccessException e) { throw new RuntimeException("Failed to start camera session"); } } /** * Chooses the optimal preview size based on {@link #mPreviewSizes} and the surface size. * * @return The picked size for camera preview. */ private Size chooseOptimalSize() { int surfaceLonger, surfaceShorter; final int surfaceWidth = mPreview.getWidth(); final int surfaceHeight = mPreview.getHeight(); if (surfaceWidth < surfaceHeight) { surfaceLonger = surfaceHeight; surfaceShorter = surfaceWidth; } else { surfaceLonger = surfaceWidth; surfaceShorter = surfaceHeight; } SortedSet allCandidates = mPreviewSizes.sizes(mAspectRatio); // Eliminate candidates that are bigger than Camera2 PREVIEW guarantees SortedSet guaranteedCandidates = new TreeSet<>(); for (Size size : allCandidates) { if (size.getWidth() <= MAX_PREVIEW_WIDTH && size.getHeight() <= MAX_PREVIEW_HEIGHT) { guaranteedCandidates.add(size); } } // Pick the smallest of those big enough for (Size size : guaranteedCandidates) { if (size.getWidth() >= surfaceLonger && size.getHeight() >= surfaceShorter) { return size; } } // If no size is big enough, pick the largest one. return guaranteedCandidates.last(); } /** * Updates the internal state of auto-focus to {@link #mAutoFocus}. */ void updateAutoFocus() { if (mAutoFocus) { int[] modes = mCameraCharacteristics.get( CameraCharacteristics.CONTROL_AF_AVAILABLE_MODES); // Auto focus is not supported if (modes == null || modes.length == 0 || (modes.length == 1 && modes[0] == CameraCharacteristics.CONTROL_AF_MODE_OFF)) { mAutoFocus = false; mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_MODE_OFF); } else { mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE); } } else { mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_MODE_OFF); } } /** * Updates the internal state of flash to {@link #mFlash}. */ void updateFlash() { switch (mFlash) { case Constants.FLASH_OFF: mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AE_MODE, CaptureRequest.CONTROL_AE_MODE_ON); mPreviewRequestBuilder.set(CaptureRequest.FLASH_MODE, CaptureRequest.FLASH_MODE_OFF); break; case Constants.FLASH_ON: mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AE_MODE, CaptureRequest.CONTROL_AE_MODE_ON_ALWAYS_FLASH); mPreviewRequestBuilder.set(CaptureRequest.FLASH_MODE, CaptureRequest.FLASH_MODE_OFF); break; case Constants.FLASH_TORCH: mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AE_MODE, CaptureRequest.CONTROL_AE_MODE_ON); mPreviewRequestBuilder.set(CaptureRequest.FLASH_MODE, CaptureRequest.FLASH_MODE_TORCH); break; case Constants.FLASH_AUTO: mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AE_MODE, CaptureRequest.CONTROL_AE_MODE_ON_AUTO_FLASH); mPreviewRequestBuilder.set(CaptureRequest.FLASH_MODE, CaptureRequest.FLASH_MODE_OFF); break; case Constants.FLASH_RED_EYE: mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AE_MODE, CaptureRequest.CONTROL_AE_MODE_ON_AUTO_FLASH_REDEYE); mPreviewRequestBuilder.set(CaptureRequest.FLASH_MODE, CaptureRequest.FLASH_MODE_OFF); break; } } void updatePictureSize() { } /** * Locks the focus as the first step for a still image capture. */ private void lockFocus() { mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AF_TRIGGER, CaptureRequest.CONTROL_AF_TRIGGER_START); try { mCaptureCallback.setState(PictureCaptureCallback.STATE_LOCKING); mCaptureSession.capture(mPreviewRequestBuilder.build(), mCaptureCallback, null); } catch (CameraAccessException e) { Log.e(TAG, "Failed to lock focus.", e); } } /** * Captures a still picture.(并且设置拍摄参数) */ void captureStillPicture() { try { CaptureRequest.Builder captureRequestBuilder = mCamera.createCaptureRequest( CameraDevice.TEMPLATE_STILL_CAPTURE); captureRequestBuilder.addTarget(mImageReader.getSurface()); captureRequestBuilder.set(CaptureRequest.CONTROL_AF_MODE, mPreviewRequestBuilder.get(CaptureRequest.CONTROL_AF_MODE)); switch (mFlash) { case Constants.FLASH_OFF: captureRequestBuilder.set(CaptureRequest.CONTROL_AE_MODE, CaptureRequest.CONTROL_AE_MODE_ON); captureRequestBuilder.set(CaptureRequest.FLASH_MODE, CaptureRequest.FLASH_MODE_OFF); break; case Constants.FLASH_ON: captureRequestBuilder.set(CaptureRequest.CONTROL_AE_MODE, CaptureRequest.CONTROL_AE_MODE_ON_ALWAYS_FLASH); break; case Constants.FLASH_TORCH: captureRequestBuilder.set(CaptureRequest.CONTROL_AE_MODE, CaptureRequest.CONTROL_AE_MODE_ON); captureRequestBuilder.set(CaptureRequest.FLASH_MODE, CaptureRequest.FLASH_MODE_TORCH); break; case Constants.FLASH_AUTO: captureRequestBuilder.set(CaptureRequest.CONTROL_AE_MODE, CaptureRequest.CONTROL_AE_MODE_ON_AUTO_FLASH); break; case Constants.FLASH_RED_EYE: captureRequestBuilder.set(CaptureRequest.CONTROL_AE_MODE, CaptureRequest.CONTROL_AE_MODE_ON_AUTO_FLASH); break; } // Calculate JPEG orientation. @SuppressWarnings("ConstantConditions") int sensorOrientation = mCameraCharacteristics.get( CameraCharacteristics.SENSOR_ORIENTATION); captureRequestBuilder.set(CaptureRequest.JPEG_ORIENTATION, (sensorOrientation + mDisplayOrientation * (mFacing == Constants.FACING_FRONT ? 1 : -1) + 360) % 360); // Stop preview and capture a still picture. mCaptureSession.stopRepeating(); mCaptureSession.capture(captureRequestBuilder.build(), new CameraCaptureSession.CaptureCallback() { @Override public void onCaptureCompleted(@NonNull CameraCaptureSession session, @NonNull CaptureRequest request, @NonNull TotalCaptureResult result) { unlockFocus(); } }, null); } catch (CameraAccessException e) { Log.e(TAG, "Cannot capture a still picture.", e); } } /** * Unlocks the auto-focus and restart camera preview. This is supposed to be called after * capturing a still picture. */ void unlockFocus() { mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AF_TRIGGER, CaptureRequest.CONTROL_AF_TRIGGER_CANCEL); try { mCaptureSession.capture(mPreviewRequestBuilder.build(), mCaptureCallback, null); updateAutoFocus(); updateFlash(); mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AF_TRIGGER, CaptureRequest.CONTROL_AF_TRIGGER_IDLE); mCaptureSession.setRepeatingRequest(mPreviewRequestBuilder.build(), mCaptureCallback, null); mCaptureCallback.setState(PictureCaptureCallback.STATE_PREVIEW); } catch (CameraAccessException e) { Log.e(TAG, "Failed to restart camera preview.", e); } } /** * A {@link CameraCaptureSession.CaptureCallback} for capturing a still picture. */ private static abstract class PictureCaptureCallback extends CameraCaptureSession.CaptureCallback { static final int STATE_PREVIEW = 0; static final int STATE_LOCKING = 1; static final int STATE_LOCKED = 2; static final int STATE_PRECAPTURE = 3; static final int STATE_WAITING = 4; static final int STATE_CAPTURING = 5; private int mState; PictureCaptureCallback() { } void setState(int state) { mState = state; } @Override public void onCaptureProgressed(@NonNull CameraCaptureSession session, @NonNull CaptureRequest request, @NonNull CaptureResult partialResult) { process(partialResult); } @Override public void onCaptureCompleted(@NonNull CameraCaptureSession session, @NonNull CaptureRequest request, @NonNull TotalCaptureResult result) { process(result); } private void process(@NonNull CaptureResult result) { switch (mState) { case STATE_LOCKING: { Integer af = result.get(CaptureResult.CONTROL_AF_STATE); if (af == null) { break; } if (af == CaptureResult.CONTROL_AF_STATE_FOCUSED_LOCKED || af == CaptureResult.CONTROL_AF_STATE_NOT_FOCUSED_LOCKED) { Integer ae = result.get(CaptureResult.CONTROL_AE_STATE); if (ae == null || ae == CaptureResult.CONTROL_AE_STATE_CONVERGED) { setState(STATE_CAPTURING); onReady(); } else { setState(STATE_LOCKED); onPrecaptureRequired(); } } break; } case STATE_PRECAPTURE: { Integer ae = result.get(CaptureResult.CONTROL_AE_STATE); if (ae == null || ae == CaptureResult.CONTROL_AE_STATE_PRECAPTURE || ae == CaptureRequest.CONTROL_AE_STATE_FLASH_REQUIRED || ae == CaptureResult.CONTROL_AE_STATE_CONVERGED) { setState(STATE_WAITING); } break; } case STATE_WAITING: { Integer ae = result.get(CaptureResult.CONTROL_AE_STATE); if (ae == null || ae != CaptureResult.CONTROL_AE_STATE_PRECAPTURE) { setState(STATE_CAPTURING); onReady(); } break; } } } /** * Called when it is ready to take a still picture. */ public abstract void onReady(); /** * Called when it is necessary to run the precapture sequence. */ public abstract void onPrecaptureRequired(); } }

如上,自己封装了prepareImageReader()函数并在,onStart的时候调用,来进行pictureSize设置



综上,修改完毕,你只需要重新编译就可以使用了,进行设置排除照片的分辨率。
PS:了解原理了之后其实你可以按此来添加一些列其他属性的设置。

使用

如下,附上怎么使用

           mCameraView.addCallback(new Callback() {
                @Override
                public void onCameraOpened(CameraView cameraView) {
                    super.onCameraOpened(cameraView);
                        mCameraView.setAspectRatio(AspectRatio.of(1920, 1080));
                        mCameraView.setPictureSize(1920, 1080);
                        mCameraView.setAutoFocus(true);

                }

                @Override
                public void onCameraClosed(CameraView cameraView) {
                    super.onCameraClosed(cameraView);
                }

                @Override
                public void onPictureTaken(CameraView cameraView, byte[] data) {
                    super.onPictureTaken(cameraView, data);
                }

项目lib地址:
https://github.com/DiskyZhs/CameraView
直接导入lib使用

你可能感兴趣的:(android开发)