前言:本片记录下纯Java下打开摄像头预览,介绍下Camera1的使用方法。
工程:andriod 4,Camera1
安卓调用摄像头有两种方案,一种是调用intent方法使用摄像头(直接调用系统),另一种是通过camera类使用摄像头(自己写),笔者这里使用第二种方案。
本来想把camera1和camera2的使用都放在一篇文章中写,后来发现审核不过,所以就分两篇介绍了。
一、新建工程
二、权限设置
AndroidManifest.xml设置CAMERA权限,不设置权限的话,会闪退或者报错,这里是安卓4.0,不需要去动态权限申请,5.0后需要。
三、界面设置
.xml中添加
有个红线,下面文章中说了原因,不用管暂时This view is not constrained. It only has designtime positions, so it will jump to (0,0) ..._哒哒呵的博客-CSDN博客
四、Camera1
4.1 Camera类的相关方法
Camera.open(); 打开设备摄像头,并返回一个Camera对象。可以通过返回的对象管理摄像头。
Camera.setPreviewDisplay(SurfaceHolder holder); 设置显示摄像头内容的surfaceView,参数为显示surfaceVIew所对应的surfaceHolder。
Camera.startPreview(); 开始预览摄像头。即在surfaceView上显示摄像头拍摄信息。
Camera.stopPreview(); 关闭摄像头。
Camera.release(); 放开摄像头。
4.2 SurfaceView类的相关方法
SurfaceView.getHolder(); 获得surfaceHolder对象,surfaceHolder能够对surfaceView进行控制,且能够添加回调函数来监控surfaceView的变化,同时我们也需要获得surfaceHolder来作为Camera.setPreviewDisplay();方法的参数。
public abstract void addCallback (SurfaceHolder.Callback callback) ; 为surfaceHolder添加回调方法,我们可以直接在使用方法的时候new 一个callback或者实现callback的接口SurfaceHolder.Callback;
public abstract void setType (int type); 在早期的安卓中,我们需要这个方法来设置surfaceView的类型,一般值设置为SURFACE_TYPE_PUSH_BUFFERS; 但是在API 11中该方法已经过时,系统会默认为其设置值。这点还需要再实际开发中再进行验证。
SurfaceHolder的三个回调函数
public void surfaceChanged(SurfaceHolder arg0, int arg1, int arg2, int arg3) ;
public void surfaceCreated(SurfaceHolder arg0) ;
public void surfaceDestroyed(SurfaceHolder arg0);
4.3 使用
private SurfaceView surfaceview;
private SurfaceHolder holder;
private Camera mCamera;
private Camera.Size size;
private int facingBack = Camera.CameraInfo.CAMERA_FACING_BACK;
private Camera.CameraInfo mFrontCameraInfo = null;
private Camera.CameraInfo mBackCameraInfo = null;
private int mFrontCameraId = -1;
private int mBackCameraId = -1;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
surfaceview=findViewById(R.id.surfaceView);
holder= surfaceview.getHolder();
holder.addCallback(new SurfaceHolder.Callback() {
@Override
public void surfaceCreated(SurfaceHolder surfaceHolder) {
int numberOfCameras = Camera.getNumberOfCameras();
for (int cameraId = 0; cameraId < numberOfCameras ; cameraId++){
Camera.CameraInfo cameraInfo = new Camera.CameraInfo();
Camera.getCameraInfo(cameraId, cameraInfo);
if (cameraInfo.facing == Camera.CameraInfo.CAMERA_FACING_BACK) {
// 后置摄像头信息
mBackCameraId = cameraId;
mBackCameraInfo = cameraInfo;
} else if (cameraInfo.facing == Camera.CameraInfo.CAMERA_FACING_FRONT){
// 前置摄像头信息
mFrontCameraId = cameraId;
mFrontCameraInfo = cameraInfo;
}
}
if(mCamera==null){
//mCamera.setDisplayOrientation(90);
mCamera=Camera.open();
}
try {
//setCameraParameters();设置camera参数
//默认情况下camera在surfaceview中的方向与正常方向差了90度,
// 所以需要使用Camera.setDisplayOrientation(90);来调整。
//还必须在这里设置,其他地方会闪退,
mCamera.setDisplayOrientation(90);
mCamera.setPreviewDisplay(holder);
mCamera.startPreview();//开始预览
} catch (IOException e){
e.printStackTrace();
Toast.makeText(MainActivity.this, "打开相机失败", Toast.LENGTH_SHORT).show();
}
}
@Override
public void surfaceChanged(@NonNull SurfaceHolder surfaceHolder, int i, int i1, int i2) {
}
@Override
public void surfaceDestroyed(@NonNull SurfaceHolder surfaceHolder) {
}
});
}
上面代码中将下面设置camera代码注释掉了,只是在开启预览前调整了下显示方向,如果调用这个函数,就不用调显示方向了,因为这里面都设置好了。
private void setCameraParameters() {
if (mCamera == null) {
return;
}
Camera.Parameters parameters = mCamera.getParameters();
mCamera.setDisplayOrientation(90);//220214 komla 摄像机的预览角度
//增加对聚焦模式的判断,没有它会很模糊
List<String> focusModesList = parameters.getSupportedFocusModes();
if (focusModesList.contains(Camera.Parameters.FOCUS_MODE_CONTINUOUS_VIDEO)) {
parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_VIDEO);
} else if (focusModesList.contains(Camera.Parameters.FOCUS_MODE_AUTO)) {
parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_AUTO);
}
parameters.setRecordingHint(true);
mCamera.setParameters(parameters);
mCamera.getParameters().getSupportedVideoSizes();
if (size == null) {
//所有支持的宽高的集合
List<Camera.Size> mSupportedPreviewSizes = parameters.getSupportedPreviewSizes();
//从小到大排序
Collections.sort(mSupportedPreviewSizes, (o1, o2) -> Integer.compare(o1.width, o2.width));
//因为尺寸太大也不好,容量也就太大,所以只要满足要求就行,要求是宽大于1000或者高大于800的最小的一个
for (int num = 0; num < mSupportedPreviewSizes.size(); num++) {
Camera.Size size1 = mSupportedPreviewSizes.get(num);
if (size1.width >= 1000 && size1.height >= 800) {
size = size1;
break;
}
}
}
parameters.setPreviewSize(640, 480);
}