技术沉思录

Android Camera-Camera1使用

字数统计: 1.1k阅读时长: 5 min
2020/01/17

Android Camera API和Android版本一样,也是碎片化比较严重,所以Google官方推出了CameraView,提供给开发者参考和学习,现在最新的可以使用Jetpack CameraX来开发,大大简化了开发的复杂度。本系列从Camera1->Camera2->CameraView->CameraX,一步步讲解Camera的进化过程,本篇先介绍Camera1的使用。

相机开发的流程:

  1. 检测设备摄像头,打开相机
  2. 创建预览画面,显示实时预览画面
  3. 设置相机参数,进行拍照监听
  4. 监听中,保存图片资源或者直接操作原始数据
  5. 释放相机资源

上面的是基本的相机开发流程,不同的Camera API在实现上会有不同,整体流程上还是统一的。

Camera1使用

权限声明

1
2
3
4
5
<uses-feature
android:name="android.hardware.camera"
android:required="true" />

<uses-permission android:name="android.permission.CAMERA" />

相机必须声明CAMERA权限,在Android6.0上,你还需要在代码中动态申请权限

1
2
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.CAMERA},
REQUEST_CAMERA_PERMISSION);

开发流程

下图是一个开发流程的导览:
Camera1开发流程

打开相机

1
Camera.open()

该方法的系统源码实现

1
2
3
4
5
6
7
8
9
10
11
public static Camera open() {
int numberOfCameras = getNumberOfCameras();
CameraInfo cameraInfo = new CameraInfo();
for (int i = 0; i < numberOfCameras; i++) {
getCameraInfo(i, cameraInfo);
if (cameraInfo.facing == CameraInfo.CAMERA_FACING_BACK) {
return new Camera(i);
}
}
return null;
}

这里会检查可用的摄像头,默认使用的CameraInfo.CAMERA_FACING_BACK后置摄像头

创建预览画面

这里使用的是SurfaceView

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
private SurfaceView mSurfaceView;
private SurfaceHolder mSurfaceHolder;
...
mSurfaceHolder = mSurfaceView.getHolder();
mSurfaceHolder.addCallback(new SurfaceHolder.Callback() {
@Override
public void surfaceCreated(SurfaceHolder holder) {
...
startPreview();
}

@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {

}

@Override
public void surfaceDestroyed(SurfaceHolder holder) {
releaseCamera();
}
});
...
private void startPreview() {
try {
//设置实时预览
mCamera.setPreviewDisplay(mSurfaceHolder);
//Orientation
setCameraDisplayOrientation();
//开始预览
mCamera.startPreview();

startFaceDetect();
} catch (Exception e) {
e.printStackTrace();
}
}

设置预览的时候,可以设置setPreviewCallback监听预览数据的回调

1
void onPreviewFrame(byte[] data, Camera camera);

设置相机参数

设置相机参数后,需要重新启动预览,这边在初始化的时候,已经设置好了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
private void initParameters(final Camera camera) {
mParameters = camera.getParameters();
mParameters.setPreviewFormat(ImageFormat.NV21); //default

if (isSupportFocus(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE)) {
mParameters.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE);
} else if (isSupportFocus(Camera.Parameters.FOCUS_MODE_AUTO)) {
mParameters.setFocusMode(Camera.Parameters.FOCUS_MODE_AUTO);
}

//设置预览图片大小
setPreviewSize();
//设置图片大小
setPictureSize();

camera.setParameters(mParameters);
}

Camera.Parameters可以设置的参数非常多,这里就介绍几个比较常用的
Camera.Parameters

1.setFocusMode

设置对焦模式

  • FOCUS_MODE_AUTO:自动对焦
  • FOCUS_MODE_INFINITY:无穷远
  • FOCUS_MODE_MACRO:微距
  • FOCUS_MODE_FIXED:固定焦距
  • FOCUS_MODE_EDOF:景深扩展
  • FOCUS_MODE_CONTINUOUS_PICTURE:持续对焦(针对照片)
  • FOCUS_MODE_CONTINUOUS_VIDEO:(针对视频)

2.setPreviewSize

设置预览图片大小

3.setPreviewFormat

支持的格式:

  • ImageFormat.NV16
  • ImageFormat.NV21
  • ImageFormat.YUY2
  • ImageFormat.YV12
  • ImgaeFormat.RGB_565
  • ImageFormat.JPEG
    如果不设置,默认返回NV21的数据

4.setPictureSize

设置保存图片的大小

5.setPictureFormat

设置保存图片的格式,格式和setPreviewFormat一样

6.setDisplayOrientation

设置相机预览画面旋转的角度,degress取值0,90,180,270

7.setPreviewDisplay

设置实时预览SurfaceHolder

8.setPreviewCallback

监听相机预览数据回调

9.setParameters

设置相机的Parameters
其他一些设置,大家可以查看Android文档进行相应的设置

设置方向

设置相机的预览方向,orientation比较详细的介绍

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
private void setCameraDisplayOrientation() {
Camera.CameraInfo cameraInfo = new Camera.CameraInfo();
Camera.getCameraInfo(mCameraId, cameraInfo);
int rotation = getWindowManager().getDefaultDisplay().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;
}

int result;
//cameraInfo.orientation 图像传感方向
if (cameraInfo.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {
result = (cameraInfo.orientation + degrees) % 360;
result = (360 - result) % 360;
} else {
result = (cameraInfo.orientation - degrees + 360) % 360;
}

mOrientation = result;
//相机预览方向
mCamera.setDisplayOrientation(result);
}

拍照

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
private void takePicture() {
if (null != mCamera) {
mCamera.takePicture(new Camera.ShutterCallback() {
@Override
public void onShutter() {

}
}, new Camera.PictureCallback() {
@Override
public void onPictureTaken(byte[] data, Camera camera) {
//base data
}
}, new Camera.PictureCallback() {
@Override
public void onPictureTaken(final byte[] data, Camera camera) {
mCamera.startPreview();
//save data
}
});
}
}

takePicture的源码实现:

1
2
3
4
public final void takePicture(ShutterCallback shutter, PictureCallback raw,
PictureCallback jpeg) {
takePicture(shutter, raw, null, jpeg);
}
  • shutter(ShutterCallback):快门按下后的回调
  • raw(PictureCallback):raw图像数据
  • jpeg(PictureCallback):jpeg图像生成以后的回调

释放相机资源

在使用完成后,onPause或者onDestory中进行相机资源的释放

1
2
3
4
5
6
7
8
9
private void releaseCamera() {
if (null != mCamera) {
mCamera.stopPreview();
mCamera.stopFaceDetection();
mCamera.setPreviewCallback(null);
mCamera.release();
mCamera = null;
}
}
  • stopPreview:停止预览
  • release:释放资源

Camera1的开发上,还是相对比较简单的,需要定制的功能项比较少,下面一篇开始介绍Camera2的使用。
文章中涉及到的代码

参考

CATALOG
  1. 1. Camera1使用
    1. 1.1. 权限声明
    2. 1.2. 开发流程
      1. 1.2.1. 打开相机
      2. 1.2.2. 创建预览画面
      3. 1.2.3. 设置相机参数
        1. 1.2.3.1. 1.setFocusMode
        2. 1.2.3.2. 2.setPreviewSize
        3. 1.2.3.3. 3.setPreviewFormat
        4. 1.2.3.4. 4.setPictureSize
        5. 1.2.3.5. 5.setPictureFormat
        6. 1.2.3.6. 6.setDisplayOrientation
        7. 1.2.3.7. 7.setPreviewDisplay
        8. 1.2.3.8. 8.setPreviewCallback
        9. 1.2.3.9. 9.setParameters
      4. 1.2.4. 设置方向
      5. 1.2.5. 拍照
      6. 1.2.6. 释放相机资源
  2. 2. 参考