相机拉升 是因为 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);
}
}