android 相机预览拉伸问题

相机拉升 是因为 SurfaceView预览 与 相机分辨率不一致导致的

        
public class MatcherActivity{
    .....
    @Override
    protected void onStart() {
        cameraView.setListener(this);
        cameraView.startPreview(Camera.CameraInfo.CAMERA_FACING_BACK, CameraManager.PREVIEW_SIZE_480P);
    }

    @Override
    protected void onPause() {
        super.onPause();
        cameraView.stopPreview();
    }
}

CameraView 讲解

设置 SurfaceView 的大小和 camera 的大小一致;
onMeasure 是重点,根据camera 大 设置 surfaceView大小

public class CameraView extends SurfaceView implements SurfaceHolder.Callback, CameraManager.OnCameraManagerListener {
    .....
    private CameraManager mCameraManager;
    ....
    public CameraView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init();
    }

    private void init() {
        getHolder().addCallback(this);
        mCameraManager = new CameraManager();
        mCameraManager.setListener(this);
    }

    onMeasure 是重点,根据camera 大 设置 surfaceView大小

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        int width = resolveSize(0, widthMeasureSpec);
        int height = resolveSize(width * mCameraSize.width / mCameraSize.height, heightMeasureSpec);
        setMeasuredDimension(width, height);
        L.d("onMeasure");
    }

    @Override
    public void onCamera(Camera camera) {
        L.d("onCamera");
        mCameraSize = camera.getParameters().getPreviewSize();
    }

   public void startPreview(int cameraId, int dpi) {
        mCameraManager.openCamera(cameraId, dpi);
        if (mSurfaceHolder != null) {
            mCameraManager.startPreview(mSurfaceHolder);
        }
    }

    @Override
    public void surfaceDestroyed(SurfaceHolder holder) {
        mCameraManager.releaseCamera();
    }
}

CameraManager 代码讲解

public class CameraManager implements Camera.PreviewCallback {
    ....
    private int previewSize = PREVIEW_SIZE_720P;
    public static final int PREVIEW_SIZE_1080P = 1080;
    public static final int PREVIEW_SIZE_960P = 960;
    public static final int PREVIEW_SIZE_720P = 720;
    public static final int PREVIEW_SIZE_480P = 480;

    public void openCamera(int cameraId) {
        openCamera(cameraId, PREVIEW_SIZE_720P);
    }

    /**
     * @param cameraId    前后摄像头Id
     * @param previewSize def PREVIEW_SIZE_720P
     */
    public void openCamera(int cameraId, int previewSize) {
       ....
       获取相机硬件预览大小
        mParameters = mCamera.getParameters();
        mPictureSizes = mParameters.getSupportedPictureSizes();
        mPreviewSizes = mParameters.getSupportedPreviewSizes();
        Collections.reverse(mPictureSizes);
        Collections.reverse(mPreviewSizes);

        //选择合适的分辨率
        Camera.Size size = calculateCameraFrameSize(mPreviewSizes, previewSize, 0);
        Log.i(TAG, "Camera.Size:" + size.width + "x" + size.height);
        //设置预览 与 照片
        setParameters(previewSize, size.width, size.height);
        addCameraCallBack();
    }

    private void addCameraCallBack() {
        ....
        返回相机
        if (mListener != null)
            mListener.onCamera(mCamera);
    }

    private void setParameters(int pictureSize, int width, int height) {
        float rate = (float) width / height;//比例
        rate = Float.valueOf(String.format(Locale.getDefault(), "%.2f", rate));
        Log.i(TAG, "相机预览:" + width + "x" + height + "--" + pictureSize + " dpi----rate:" + rate + "---");
        Camera.Size size;

        .....
        设置预览大小
        size = calculateCameraFrameSize(mPreviewSizes, pictureSize, rate);
        mParameters.setPreviewSize(size.width, size.height);
        Log.i(TAG, "设置预览:w = " + size.width + "x" + size.height + "--rate:" + (float) size.width / size.height);
        mParameters.setPreviewFormat(ImageFormat.NV21);
        .....
    }

     protected Camera.Size calculateCameraFrameSize(List supportedSizes, int previewSize, float rate) {
        int k = 0;
        int calcWidth = 0;
        int calcHeight = 0;
        for (int i = 0; i < supportedSizes.size(); i++) {
            Camera.Size size = supportedSizes.get(i);
            int width = size.width;
            int height = size.height;
            if (equalRate(size, rate)) {
                Log.i(TAG, "CameraSize:" + width + "x" + height + "--rate:" + (float) width / height);
                //1088 这个像素容易出错
                if (width >= calcWidth && height >= calcHeight && height <= previewSize && height != 1088) {//960
                    calcWidth = width;
                    calcHeight = height;
                    k = i;
                }
            }
        }
        return supportedSizes.get(k);
    }
}

完整的 CameraManager 代码

import android.graphics.ImageFormat;
import android.hardware.Camera;
import android.os.Build;
import android.util.Log;
import android.util.Size;
import android.view.SurfaceHolder;

import com.android.opencvapplication.util.L;

import java.io.IOException;
import java.util.Collections;
import java.util.List;
import java.util.Locale;

/**
 * Created by My on 2017/12/13.
 * 相机管理
 */

public class CameraManager implements Camera.PreviewCallback {
    private String TAG = CameraManager.class.getSimpleName();

    private int previewSize = PREVIEW_SIZE_720P;
    public static final int PREVIEW_SIZE_1080P = 1080;
    public static final int PREVIEW_SIZE_960P = 960;
    public static final int PREVIEW_SIZE_720P = 720;
    public static final int PREVIEW_SIZE_480P = 480;

    private int numCameras = Camera.getNumberOfCameras(); // 初始化摄像头数量
    private Camera mCamera;
    private Camera.Parameters mParameters;
    private List mPictureSizes;
    private List mPreviewSizes;
    private Camera.Parameters parameters;
    private byte[] mBuffer;
    private boolean previewing;
    private OnCameraManagerListener mListener;

    public void setListener(OnCameraManagerListener listener) {
        mListener = listener;
    }

    public boolean isPreviewing() {
        return previewing;
    }

    public void openCamera(int cameraId) {
        openCamera(cameraId, PREVIEW_SIZE_720P);
    }

    /**
     * @param cameraId    前后摄像头Id
     * @param previewSize def PREVIEW_SIZE_720P
     */
    public void openCamera(int cameraId, int previewSize) {
        this.previewSize = previewSize;
        if (mCamera != null) {
            mCamera.stopPreview();
            mCamera.release();
            mCamera = null;
        }
        //有效的 cameraId 时,打开当前摄像头,否则打开后置摄像头
        cameraId = cameraId >= 0 && cameraId < numCameras ? cameraId : Camera.CameraInfo.CAMERA_FACING_BACK;
        mCamera = Camera.open(cameraId);

        mCamera.setDisplayOrientation(90);//设置旋转90度

        mParameters = mCamera.getParameters();
        mPictureSizes = mParameters.getSupportedPictureSizes();
        mPreviewSizes = mParameters.getSupportedPreviewSizes();
        Collections.reverse(mPictureSizes);
        Collections.reverse(mPreviewSizes);

        //选择合适的分辨率
        Camera.Size size = calculateCameraFrameSize(mPreviewSizes, previewSize, 0);
        Log.i(TAG, "Camera.Size:" + size.width + "x" + size.height);
        //设置预览 与 照片
        setParameters(previewSize, size.width, size.height);
        addCameraCallBack();
    }

    public void startPreview(SurfaceHolder surfaceHolder) {
        if (previewing)
            stopPreview();
        try {
            mCamera.setPreviewCallback(this);
            mCamera.setPreviewDisplay(surfaceHolder);
            mCamera.startPreview();
            previewing = true;
            Log.d(TAG, "startPreview");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public void stopPreview() {
        if (mCamera != null && previewing) {
            mCamera.stopPreview();
            mCamera.setPreviewCallback(null);  // Camera is being used after Camera.release() was called
            previewing = false;
            Log.d(TAG, "stopPreview");
        }
    }

    private void setParameters(int pictureSize, int width, int height) {
        float rate = (float) width / height;//比例
        rate = Float.valueOf(String.format(Locale.getDefault(), "%.2f", rate));
        Log.i(TAG, "相机预览:" + width + "x" + height + "--" + pictureSize + " dpi----rate:" + rate + "---");
        Camera.Size size;
        if (pictureSize > 0) {
            size = calculateCameraFrameSize(mPictureSizes, pictureSize, rate);
        } else {
            size = mPictureSizes.get(mPictureSizes.size() - 1);
        }
        mParameters.setPictureSize(size.width, size.height);
        Log.i(TAG, "设置图片:w = " + size.width + "x" + size.height + "--rate:" + (float) size.width / size.height);

        size = calculateCameraFrameSize(mPreviewSizes, pictureSize, rate);
        mParameters.setPreviewSize(size.width, size.height);
        Log.i(TAG, "设置预览:w = " + size.width + "x" + size.height + "--rate:" + (float) size.width / size.height);

        mParameters.setPreviewFormat(ImageFormat.NV21);

        List FocusModes = mParameters.getSupportedFocusModes();
        if (FocusModes != null && FocusModes.contains(Camera.Parameters.FOCUS_MODE_CONTINUOUS_VIDEO)) {
            mParameters.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_VIDEO);
        }
        //mParameters.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE);//连续对焦

        //以下两句 影响 小米5 自动对焦
//        mParameters.setSceneMode(Camera.Parameters.SCENE_MODE_STEADYPHOTO);
//        mParameters.setWhiteBalance(Camera.Parameters.WHITE_BALANCE_AUTO);

        try {
            mCamera.setParameters(mParameters);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private void addCameraCallBack() {
        Camera.Parameters params = mCamera.getParameters();
        int mFrameWidth = params.getPreviewSize().width;
        int mFrameHeight = params.getPreviewSize().height;

        int pxSize = mFrameWidth * mFrameHeight;
        pxSize = pxSize * ImageFormat.getBitsPerPixel(params.getPreviewFormat()) / 8;
        mBuffer = new byte[pxSize];

        mCamera.addCallbackBuffer(mBuffer);
        mCamera.setPreviewCallbackWithBuffer(this);

        if (mListener != null)
            mListener.onCamera(mCamera);
    }

    protected Camera.Size calculateCameraFrameSize(List supportedSizes, int previewSize, float rate) {
        int k = 0;
        int calcWidth = 0;
        int calcHeight = 0;
        for (int i = 0; i < supportedSizes.size(); i++) {
            Camera.Size size = supportedSizes.get(i);
            int width = size.width;
            int height = size.height;
            if (equalRate(size, rate)) {
                Log.i(TAG, "CameraSize:" + width + "x" + height + "--rate:" + (float) width / height);
                //1088 这个像素容易出错
                if (width >= calcWidth && height >= calcHeight && height <= previewSize && height != 1088) {//960
                    calcWidth = width;
                    calcHeight = height;
                    k = i;
                }
            }
        }
        return supportedSizes.get(k);
    }

    /**
     * 比例
     *
     * @param size
     * @param rate 16:9 1.777777
     * @return
     */
    private boolean equalRate(Camera.Size size, float rate) {
        if (rate <= 0)
            return true;
        return (double) Math.abs((float) size.width / (float) size.height - rate) <= 0.2D;
    }

    public void releaseCamera() {
        synchronized (this) {
            if (mCamera != null) {
                mCamera.stopPreview();
                mCamera.setPreviewCallback(null);
                mCamera.release();
            }
            mCamera = null;
            if (mListener != null)
                mListener.onReleaseCamera();
        }
    }

    /**
     * 聚焦
     */
    public void doAutoFocus() {
        try {
            mCamera.cancelAutoFocus();
            parameters = mCamera.getParameters();
            parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_AUTO);
            mCamera.setParameters(parameters);
            mCamera.autoFocus(new Camera.AutoFocusCallback() {
                @Override
                public void onAutoFocus(boolean success, Camera camera) {
                    if (success) {
                        camera.cancelAutoFocus();// 只有加上了这一句,才会自动对焦。
                        if (!Build.MODEL.equals("KORIDY H30")) {
                            parameters = camera.getParameters();
                            parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_VIDEO);// 1连续对焦
//                            parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE);// 1连续对焦
                            camera.setParameters(parameters);
                        } else {
                            parameters = camera.getParameters();
                            parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_AUTO);
                            camera.setParameters(parameters);
                        }
                    }
                }
            });
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public synchronized boolean isOpen() {
        return mCamera != null;
    }

    @Override
    public void onPreviewFrame(byte[] bytes, Camera camera) {
        if (mListener != null)
            mListener.onPreviewFrame(bytes, camera);
        if (mCamera != null)
            mCamera.addCallbackBuffer(mBuffer);
    }

    public interface OnCameraManagerListener {
        void onCamera(Camera camera);

        void onReleaseCamera();

        void onPreviewFrame(byte[] bytes, Camera camera);
    }

}

你可能感兴趣的:(android 相机预览拉伸问题)