Android 5.0(Lollipop)增加了Camera2 API,并将原有的Camera API标记为废弃。对于原有的Camera API来说,Camera2重新定义了相机的API,也重构了相机API的架构。在Camera2中其主要思想是基于会话模式和事件驱动与相机实现交互,对于预览、拍照、录制等操作都是在会话的基础下请求某种类型的会话操作。
比如一次拍照的操作:
下面一起看下camera2的操作:
- 相机初始化
我们知道要使用相机,首先我们需要获得相关的权限,主要是在manifest中定义,其次在Android6.0还需要动态获取权限。
- 在manifest中定义需要的权限
1
<uses-permission android:name="android.permission.CAMERA" />
如果要保存照片、录制视频,还需要两个权限:1
2
3<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />
相机功能:相机特性,如:1
2<uses-feature android:name="android.hardware.camera" />
<uses-feature android:name="android.hardware.camera.autofocus" />
- 动态权限申请
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22private final String[] VIDEO_PERMISSIONS = {
Manifest.permission.CAMERA,
Manifest.permission.RECORD_AUDIO,
Manifest.permission.WRITE_EXTERNAL_STORAGE,
Manifest.permission.READ_EXTERNAL_STORAGE,
};
//......
if (!hasPermissionsGranted(getApplicationContext(), VIDEO_PERMISSIONS)) {
requestPermissions(VIDEO_PERMISSIONS, 1);
return;
}
//......
hasPermissionsGranted(Context context, String[] permissions) {
for (String permission : permissions) {
if (ActivityCompat.checkSelfPermission(context, permission)
!= PackageManager.PERMISSION_GRANTED) {
return false;
}
}
return true;
}
以上基础工作好了基本可以开始对相机操作了。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
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68//初始化相机设备
private void initCamera() {
//设备管理类
cameraManager = (CameraManager) getSystemService(Context.CAMERA_SERVICE);
try {
//获取相机设备特征类,通过该类可以获取相机的一些特性,如相机的方向
CameraCharacteristics characteristics = cameraManager.getCameraCharacteristics(cameraManager.getCameraIdList()[0]);
mSensorOrientation = characteristics.get(CameraCharacteristics.SENSOR_ORIENTATION);
Log.e(TAG, "sensor_orientation is :" + mSensorOrientation);
StreamConfigurationMap streamConfigurationMap = characteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
//获取录制视屏时的宽高,这个通过MediaRecorder类获取系统支持的录制视频的宽高,主要是防止配置录制适配配置时失败
mVideoSize = chooseVideoSize(streamConfigurationMap.getOutputSizes(MediaRecorder.class));
//根据录制视频支持的宽高和SurfaceTexture支持的宽高,以及当前视图的宽高设置预览视图的宽高
mPreviewSize = chooseOptimalSize(streamConfigurationMap.getOutputSizes(SurfaceTexture.class), surfaceView.getWidth(), surfaceView.getHeight(), mVideoSize);
//imageReader初始化,用于获取拍照信息
imageReader = ImageReader.newInstance(mPreviewSize.getWidth(), mPreviewSize.getHeight(), ImageFormat.JPEG, 2);
imageReader.setOnImageAvailableListener(new ImageReader.OnImageAvailableListener() {
public void onImageAvailable(ImageReader reader) {
imageView.setVisibility(View.VISIBLE);
// 拿到拍照照片数据
Image image = reader.acquireNextImage();
ByteBuffer buffer = image.getPlanes()[0].getBuffer();
byte[] bytes = new byte[buffer.remaining()];
buffer.get(bytes);//由缓冲区存入字节数组
final Bitmap bitmap = BitmapFactory.decodeByteArray(bytes, 0, bytes.length);
if (bitmap != null) {
imageView.setImageBitmap(bitmap);
}
updatePreView();
}
}, mainHandler);
//打开摄像头,stateCallback为相机的状态监听回调
cameraManager.openCamera(cameraManager.getCameraIdList()[0], stateCallback, mainHandler);
mMediaRecorder = new MediaRecorder();
Log.d(TAG, "open camera");
} catch (CameraAccessException e) {
e.printStackTrace();
}
}
//开启相机后有一个回调,stateCallback,该回调是用来返回相机是否正常打开的状态的开启相机后有一个回调,stateCallback,该回调是用来返回相机是否正常打开的状态的
private CameraDevice.StateCallback stateCallback = new CameraDevice.StateCallback() {
public void onOpened(@NonNull CameraDevice cameraDevice) {
Log.d(TAG, "camera open");
mCameraDevice = cameraDevice;
takePreview();
}
public void onDisconnected(@NonNull CameraDevice cameraDevice) {
Log.d(TAG, "camera onDisconnected");
if (null != mCameraDevice) {
mCameraDevice.close();
mCameraDevice = null;
}
}
public void onError(@NonNull CameraDevice cameraDevice, int i) {
Log.d(TAG, "camera onError");
cameraDevice.close();
mCameraDevice = null;
Toast.makeText(ImageShowActivity.this, "摄像头开启失败", Toast.LENGTH_SHORT).show();
}
};
开启相机预览
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
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56/**
* 开始预览,此处创建一个捕获视频信息的请求,以此来获取一个会话session,在获取会话时监听其配置状态,一旦成功,则此时通过会话构建一个重复预览的请求;
*/
private void takePreview() {
try {
closePreviewSession();
SurfaceTexture surfaceTexture = surfaceView.getSurfaceTexture();
surfaceTexture.setDefaultBufferSize(mPreviewSize.getWidth(), mPreviewSize.getHeight());
Log.e(TAG, "preview SurfaceTexture buffer size is width:" + mPreviewSize.getWidth() + " height :" + mPreviewSize.getHeight());
Surface previewSurface = new Surface(surfaceTexture);
List<Surface> surfaces = new ArrayList<>();
surfaces.add(previewSurface);
surfaces.add(imageReader.getSurface());
// 创建CameraCaptureSession,该对象负责管理处理预览请求和拍照请求
mCameraDevice.createCaptureSession(surfaces, new CameraCaptureSession.StateCallback() //
{
public void onConfigured(CameraCaptureSession cameraCaptureSession) {
Log.d("onConfigured", "onConfigured");
if (null == mCameraDevice) return;
// 当摄像头已经准备好时,开始显示预览
mCameraCaptureSession = cameraCaptureSession;
updatePreView();
}
public void onConfigureFailed(CameraCaptureSession cameraCaptureSession) {
Log.d("onConfigureFailed", "onConfigureFailed");
Toast.makeText(ImageShowActivity.this, "配置失败", Toast.LENGTH_SHORT).show();
}
}, childHandler);
} catch (CameraAccessException e) {
e.printStackTrace();
}
}
/**
* 更新预览视图,构建一个TEMPLATE_PREVIEW捕获请求,此时是对会话进行设置!!!setRepeatingRequest!!!
*/
private void updatePreView() {
try {
// 创建预览需要的CaptureRequest.Builder
CaptureRequest.Builder mPreviewBuilder = mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
// 将SurfaceView的surface作为CaptureRequest.Builder的目标
SurfaceTexture surfaceTexture = surfaceView.getSurfaceTexture();
Log.e(TAG, "update preview SurfaceTexture buffer size is width:" + mPreviewSize.getWidth() + " height :" + mPreviewSize.getHeight());
surfaceTexture.setDefaultBufferSize(mPreviewSize.getWidth(), mPreviewSize.getHeight());
Surface previewSurface = new Surface(surfaceTexture);
mPreviewBuilder.addTarget(previewSurface);
mPreviewBuilder.set(CaptureRequest.CONTROL_MODE, CameraMetadata.CONTROL_MODE_AUTO);
mCameraCaptureSession.setRepeatingRequest(mPreviewBuilder.build(), null, childHandler);
} catch (CameraAccessException e) {
e.printStackTrace();
}
}拍照
1 | /** |
- 录制视频
1 | /** |
手机支持的一些分辨率:
width:4608 height:3456
width:4608 height:2304
width:3456 height:3456
width:3840 height:2160
width:3280 height:2448
width:3264 height:2448
width:3264 height:1840
width:3264 height:1632
width:2448 height:2448
width:2592 height:1952
width:2048 height:1536
width:1920 height:1080
width:1440 height:1080
width:1536 height:864
width:1456 height:1456
width:1920 height:960
width:1440 height:720
width:1280 height:960
width:1280 height:720
width:960 height:720
参考地址:
[1].官网示例 https://github.com/googlesamples/android-Camera2Basic
[2]. https://blog.csdn.net/z_x_Qiang/article/details/77600880?locationNum=1&fps=1