前言
在API级别21中不
推荐使用该类。我们建议[android.hardware.camera2](https://developer.android.com/reference/android/hardware/camera2/package-summary)
对新应用程序使用新的API。
Camera类用于设置图像捕获设置,开始/停止预览,快照和检索帧以对视频进行编码。此类是Camera服务的客户端,该服务管理实际的相机硬件。
Camera1的使用
一、权限
要访问设备相机,您必须[Manifest.permission.CAMERA](https://developer.android.com/reference/android/Manifest.permission#CAMERA)
在Android清单中声明该 权限。另外,请确保包含 <uses-feature> 清单元素,以声明应用程序使用的相机功能。例如,如果您使用相机和自动对焦功能,则清单应包括以下内容:
<uses-permission android:name="android.permission.CAMERA" />
<uses-feature android:name="android.hardware.camera" />
<uses-feature android:name="android.hardware.camera.autofocus" />
如果是6.0以上的手机还要动态申请权限,关于权限这块大家可以使用PermissionUtil全局管理。
二、相机的初始化
1.摄像头数量确定
/** Check if this device has a camera */
private boolean checkCameraHardware(Context context) {
if (context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_CAMERA)){
// this device has a camera
return true;
} else {
// no camera on this device
return false;
}
}
- 从中获取Camera的实例Camera.open(camera_Id);设置参数,getParameters()获取已有参数,如果有必要对返回的参数进行修改,然后调用setParameters();
private void openCamera(int cameraType, int width, int height) {
if (mCamera != null) {
throw new RuntimeException("camera already initialized");
}
Camera.CameraInfo info = new Camera.CameraInfo();
int numCameras = Camera.getNumberOfCameras();
for (int i = 0; i < numCameras; i++) {
Camera.getCameraInfo(i, info);
if (info.facing == cameraType) {
CAMERA_ID = i;
mCamera = Camera.open(i);
break;
}
}
if (mCamera == null) {
throw new RuntimeException("unable to open camera");
}
final Camera.Parameters params = mCamera.getParameters();
// 帧率设置
final List<int[]> supportedFpsRange = params.getSupportedPreviewFpsRange();
final int[] max_fps = supportedFpsRange.get(supportedFpsRange.size() - 1);
params.setPreviewFpsRange(max_fps[0], max_fps[1]);
// 优化后的camera FPS设置方法
int framerate = 30 * 1000;
List<int[]> rates = params.getSupportedPreviewFpsRange();
int[] closetFramerate = rates.get(0);
for (int i = 0; i < rates.size(); i++) {
int[] rate = rates.get(i);
int curDelta = Math.abs(rate[1] - framerate);
int bestDelta = Math.abs(closetFramerate[1] - framerate);
if (curDelta < bestDelta) {
closetFramerate = rate;
} else if (curDelta == bestDelta) {
closetFramerate = closetFramerate[0] < rate[0] ? rate : closetFramerate;
}
}
params.setPreviewFpsRange(closetFramerate[0], closetFramerate[1]);
// 请求最近支持的预览大小
final Camera.Size closestSize = getClosestSupportedSize(params.getSupportedPreviewSizes(), width, height);
params.setPreviewSize(closestSize.width, closestSize.height);
// 在Nexus7上请求最接近的图片大小以解决纵横比问题
final Camera.Size pictureSize = getClosestSupportedSize(params.getSupportedPictureSizes(), width, height);
params.setPictureSize(pictureSize.width, pictureSize.height);
//根据设备方向旋转相机预览
setRotation(params);
mCamera.setParameters(params);
}
3.调用setDisplayOrientation(int) 确保正确的预览和照片方向
private final void setRotation(final Camera.Parameters params) {
final CameraGLSurfaceView parent = mWeakParent.get();
if (parent == null) return;
final Display display = ((WindowManager) parent.getContext().getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay();
final int rotation = display.getRotation();
int degrees = 0;
switch (rotation) {
case Surface.ROTATION_0:
degrees = 0;
break;
case Surface.ROTATION_90:
degrees = 90;
break;
case Surface.ROTATION_180:
degrees = 180;
break;
case Surface.ROTATION_270:
degrees = 270;
break;
}
//获取摄像头是前置摄像头还是后置摄像头
final Camera.CameraInfo info = new android.hardware.Camera.CameraInfo();
android.hardware.Camera.getCameraInfo(CAMERA_ID, info);
int orientation = info.orientation;
mIsFrontFace = (info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT);
if (mIsFrontFace) { // front camera
degrees = (orientation + degrees) % 360;
degrees = (360 - degrees) % 360; // reverse
} else { // back camera
degrees = (orientation - degrees + 360) % 360;
}
// 设置方向
mCamera.setDisplayOrientation(degrees);
parent.mPreviewRotation = orientation;
parent.mRotation = degrees;
}
4.预览 ,调用startPreview(),开始更新预览图 ,将相机与SurfaceHolde或者texturer绑定Camera.setPreviewDisplay(surfaceHolder)
Camera.setPreviewTexture(surfaceTexture)
/**
* start camera preview
*
* @param width
* @param height
*/
private void startPreview(final int width, final int height, final SurfaceTexture surfaceTexture, int cameraId) {
mViewWidth = width;
mViewHeight = height;
CAMERA_ID = cameraId;
if (mCamera == null) {
try {
openCamera(width, height);
final Camera.Size previewSize = mCamera.getParameters().getPreviewSize();
CameraManager.getInstance().getFirstCameraPreviewListener().onBeforeStartPreviewWithChained(previewSize.width, previewSize.height, true);
byte[] preAllocedBuffer = new byte[previewSize.width * previewSize.height * ImageFormat.getBitsPerPixel(ImageFormat.NV21)];
mCamera.addCallbackBuffer(preAllocedBuffer);
mCamera.setPreviewCallbackWithBuffer(this);
} catch (final RuntimeException e) {
if (mCamera != null) {
mCamera.release();
mCamera = null;
}
}
if (mCamera != null) {
try {
mCamera.startPreview();
} catch (Exception e) {
}
CameraManager.getInstance().getFirstCameraPreviewListener().onAfterStartPreviewWithChained();
}
}
if (surfaceTexture != null) {
setPreviewTexture(surfaceTexture);
}
}
private void setPreviewTexture(SurfaceTexture surfaceTexture) {
if (mCamera != null && surfaceTexture != null) {
mSurfaceTexture = surfaceTexture;
try {
mCamera.setPreviewTexture(surfaceTexture);
} catch (IOException e) {
}
}
}
5.获取实时NV21格式的数据
mCamera.setPreviewCallbackWithBuffer(new Camera.PreviewCallback() {
@Override
public void onPreviewFrame(byte[] data, Camera camera) {
}
});
onPreview回调回来的data就是实时的帧数据,我们可以对数据进行处理,比如加美颜等等。