一、声明必要的权限
在 Android 项目中,需要在AndroidManifest.xml文件中添加相机使用权限:
| |
二、创建管理器
在 Java 或 Kotlin 代码中,创建一个CameraManager实例来管理相机设备:
在java中:
1CameraManager cameraManager = (CameraManager)getSystemService(Context.CAMERA_SERVICE);在Kotlin中:
1val cameraManager = getSystemService(Context.CAMERA_SERVICE) as CameraManager
三、获取相机信息
查询相机列表,找到要打开的目标相机:
在java中:
1 2 3 4 5 6 7 8 9 10String[] cameraIds = cameraManager.getCameraIdList(); String rearCameraId = null; for (String id : cameraIds) { CameraCharacteristics characteristics = cameraManager.getCameraCharacteristics(id); Integer facing = characteristics.get(CameraCharacteristics.LENS_FACING); if (facing!= null && facing == CameraCharacteristics.LENS_FACING_BACK) { rearCameraId = id; break; } }在Kotlin中:
1 2 3 4 5 6 7 8 9 10val cameraIds = cameraManager.cameraIdList var rearCameraId: String? = null for (id in cameraIds) { val characteristics = cameraManager.getCameraCharacteristics(id) val facing = characteristics.get(CameraCharacteristics.LENS_FACING) if (facing!= null && facing == CameraCharacteristics.LENS_FACING_BACK) { rearCameraId = id break } }
四、打开相机
通过管理器,打开指定的相机:
在java中:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17CameraDevice.StateCallback stateCallback = new CameraDevice.StateCallback() { @Override public void onOpened(CameraDevice camera) { // 相机已打开,可以进行后续操作 } @Override public void onDisconnected(CameraDevice camera) { camera.close(); } @Override public void onError(CameraDevice camera, int error) { camera.close(); } }; cameraManager.openCamera(rearCameraId, stateCallback, null);在Kotlin中:
1 2 3 4 5 6 7 8 9 10 11 12 13 14val stateCallback = object : CameraDevice.StateCallback() { override fun onOpened(camera: CameraDevice) { // 相机已打开,可以进行后续操作 } override fun onDisconnected(camera: CameraDevice) { camera.close() } override fun onError(camera: CameraDevice, error: Int) { camera.close() } } cameraManager.openCamera(rearCameraId, stateCallback, null)
五、开启相机会话,并配置相机参数,获取YUV数据
打开相机成功后(在onOpened方法中),开始配置相机参数以获取 YUV 数据。
在java中:
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 41CameraDevice cameraDevice; // 已打开的相机设备 CameraCaptureSession.StateCallback sessionCallback = new CameraCaptureSession.StateCallback() { @Override public void onConfigured(CameraCaptureSession session) { try { CaptureRequest.Builder builder = cameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW); // 设置输出格式为YUV_420_888 builder.set(CaptureRequest.COLOR_CORRECTION_MODE, CaptureRequest.COLOR_CORRECTION_MODE_TRILINEAR); ImageReader imageReader = ImageReader.newInstance(width, height, ImageFormat.YUV_420_888, 2); imageReader.setOnImageAvailableListener(new ImageReader.OnImageAvailableListener() { @Override public void onImageAvailable(ImageReader reader) { Image image = reader.acquireLatestImage(); if (image!= null) { // 在这里处理YUV数据 ByteBuffer yBuffer = image.getPlanes()[0].getBuffer(); ByteBuffer uBuffer = image.getPlanes()[1].getBuffer(); ByteBuffer vBuffer = image.getPlanes()[2].getBuffer(); byte[] yData = new byte[yBuffer.remaining()]; byte[] uData = new byte[uBuffer.remaining()]; byte[] vData = new byte[vBuffer.remaining()]; yBuffer.get(yData); uBuffer.get(uData); vBuffer.get(vData); image.close(); } } }, null); builder.addTarget(imageReader.getSurface()); session.setRepeatingRequest(builder.build(), null, null); } catch (CameraAccessException e) { e.printStackTrace(); } } @Override public void onConfigureFailed(CameraCaptureSession session) { // 配置失败处理 } }; cameraDevice.createCaptureSession(Arrays.asList(imageReader.getSurface()), sessionCallback, null);在Kotlin中:
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 36val cameraDevice: CameraDevice // 已打开的相机设备 val sessionCallback = object : CameraCaptureSession.StateCallback() { override fun onConfigured(session: CameraCaptureSession) { try { val builder = cameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW) // 设置输出格式为YUV_420_888 builder.set(CaptureRequest.COLOR_CORRECTION_MODE, CaptureRequest.COLOR_CORRECTION_MODE_TRILINEAR) val imageReader = ImageReader.newInstance(width, height, ImageFormat.YUV_420_888, 2) imageReader.setOnImageAvailableListener({ reader -> val image = reader.acquireLatestImage() if (image!= null) { // 在这里处理YUV数据 val yBuffer = image.planes[0].buffer val uBuffer = image.planes[1].buffer val vBuffer = image.planes[2].buffer val yData = ByteArray(yBuffer.remaining()) val uData = ByteArray(uBuffer.remaining()) val vData = ByteArray(vBuffer.remaining()) yBuffer.get(yData) uBuffer.get(uData) vBuffer.get(vData) image.close() } }, null) builder.addTarget(imageReader.surface) session.setRepeatingRequest(builder.build(), null, null) } catch (e: CameraAccessException) { e.printStackTrace() } } override fun onConfigureFailed(session: CameraCaptureSession) { // 配置失败处理 } } cameraDevice.createCaptureSession(listOf(imageReader.surface), sessionCallback, null)
六、注意事项
- 内存管理:在处理 YUV 数据时,要注意及时释放相关的
ByteBuffer和Image对象,以避免内存泄漏。 - 设备兼容性:不同的 Android 设备可能对
Camera2API 的支持存在差异,可能需要进行一些兼容性处理。 - 性能优化:获取和处理 YUV 数据可能会消耗较多的系统资源,特别是在高分辨率或高帧率的情况下。可以根据实际需求调整相机参数(如分辨率、帧率等)来优化性能。