Android Camera2录像实战:从MediaRecorder配置到视频保存进系统相册的完整避坑指南
Android Camera2录像开发全流程:从参数优化到系统相册整合的工程实践
在移动应用开发领域,视频录制功能的需求日益增长,从社交分享到专业拍摄,Camera2 API为开发者提供了更底层的控制能力。不同于简单的调用系统相机应用,直接使用Camera2实现录像功能可以让应用获得更精细的控制权和更好的用户体验,但同时也带来了更高的复杂度。
1. Camera2录像架构设计与初始化
Camera2 API采用管道(Pipeline)架构设计,将摄像头设备抽象为数据生产者,而应用则作为消费者通过会话(Session)来管理数据流。这种设计相比传统的Camera API提供了更高效的资源利用和更精细的控制能力。
关键初始化步骤:
相机权限检查:确保在AndroidManifest.xml中声明了相机和录音权限:
<uses-permission android:name="android.permission.CAMERA" /> <uses-permission android:name="android.permission.RECORD_AUDIO" /> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />相机特性获取:通过CameraManager获取设备支持的相机特性:
CameraManager manager = (CameraManager) context.getSystemService(Context.CAMERA_SERVICE); String[] cameraIds = manager.getCameraIdList(); CameraCharacteristics characteristics = manager.getCameraCharacteristics(cameraIds[0]);预览Surface准备:为TextureView或SurfaceView创建Surface:
SurfaceTexture texture = textureView.getSurfaceTexture(); texture.setDefaultBufferSize(previewSize.getWidth(), previewSize.getHeight()); Surface previewSurface = new Surface(texture);
注意:现代Android设备通常支持多个摄像头,开发者需要根据LENS_FACING特性选择合适的前置或后置摄像头。
相机能力对比表:
| 特性 | Camera API | Camera2 API |
|---|---|---|
| 控制粒度 | 粗粒度 | 细粒度 |
| 性能 | 一般 | 更高效 |
| 兼容性 | 广泛 | Android 5.0+ |
| 功能支持 | 基本功能 | 高级功能(如手动控制) |
| 架构 | 简单 | 管道模式 |
2. MediaRecorder配置与参数优化
MediaRecorder是Android多媒体框架中的核心组件,负责音视频的编码和封装。在Camera2架构中,它作为数据消费者接收来自相机的视频流。
推荐配置流程:
// 创建临时视频文件 File videoFile = new File(context.getExternalCacheDir(), new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date()) + ".mp4"); MediaRecorder recorder = new MediaRecorder(); recorder.setAudioSource(MediaRecorder.AudioSource.MIC); recorder.setVideoSource(MediaRecorder.VideoSource.SURFACE); recorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4); recorder.setAudioEncoder(MediaRecorder.AudioEncoder.AAC); recorder.setVideoEncoder(MediaRecorder.VideoEncoder.H264); recorder.setVideoEncodingBitRate(bitRate); recorder.setVideoFrameRate(frameRate); recorder.setVideoSize(width, height); recorder.setOrientationHint(orientation); recorder.setOutputFile(videoFile.getAbsolutePath()); // 获取MediaRecorder的Surface Surface recorderSurface = recorder.getSurface();参数优化建议:
编码器选择:
- 视频编码优先选择H.264(兼容性最好)或H.265(更高效)
- 音频编码推荐AAC
比特率设置:
- 计算公式:
比特率 = 分辨率宽度 × 分辨率高度 × 帧率 × 0.1 - 示例:1080p(1920x1080)@30fps建议比特率为6-8Mbps
- 计算公式:
帧率控制:
- 人眼流畅体验需要至少24fps
- 高动态场景建议30fps
- 慢动作拍摄需要60fps或更高
常见设备兼容性问题解决方案:
- 编码器不支持:通过CameraCharacteristics获取设备支持的编码格式
- 分辨率不匹配:使用StreamConfigurationMap检查支持的分辨率
- 方向错误:根据设备旋转设置setOrientationHint
- 音频视频不同步:确保时间戳处理正确,使用同步编码
3. 录制会话管理与异常处理
Camera2的录制会话管理是整个流程中最复杂的部分,需要协调预览、录制和可能的其他数据流(如图像分析)。
完整会话创建流程:
// 1. 停止预览 captureSession.stopRepeating(); // 2. 创建录制请求 previewRequestBuilder = cameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_RECORD); previewRequestBuilder.addTarget(previewSurface); previewRequestBuilder.addTarget(recorderSurface); // 3. 创建新的会话 cameraDevice.createCaptureSession(Arrays.asList(previewSurface, recorderSurface), new CameraCaptureSession.StateCallback() { @Override public void onConfigured(@NonNull CameraCaptureSession session) { captureSession = session; try { // 4. 开始重复请求 captureSession.setRepeatingRequest( previewRequestBuilder.build(), null, backgroundHandler); // 5. 启动MediaRecorder mediaRecorder.start(); } catch (CameraAccessException e) { Log.e(TAG, "Failed to start recording", e); } } }, backgroundHandler);关键异常处理场景:
相机访问冲突:
- 表现:CameraAccessException
- 解决方案:实现适当的重试机制和资源释放
MediaRecorder初始化失败:
- 表现:IllegalStateException
- 解决方案:检查参数合法性,确保正确的状态转换
存储权限问题:
- 表现:IOException
- 解决方案:动态权限检查和用户引导
设备旋转处理:
- 表现:画面方向错误
- 解决方案:监听设备方向变化并调整配置
录制状态机示意图:
[预览状态] ↓ [停止预览] ↓ [配置MediaRecorder] ↓ [创建录制会话] ↓ [开始录制] → [异常] → [错误处理] ↓ [停止录制] ↓ [释放资源] ↓ [恢复预览]4. 视频保存与系统相册整合
录制完成后,正确处理视频文件并使其在系统相册中可见是提升用户体验的关键环节。
视频保存最佳实践:
临时文件管理:
- 使用应用缓存目录存储临时视频文件
- 考虑设置文件大小限制
- 实现清理机制避免存储空间浪费
永久保存到公共目录:
ContentValues values = new ContentValues(); values.put(MediaStore.Video.Media.DISPLAY_NAME, "my_video.mp4"); values.put(MediaStore.Video.Media.MIME_TYPE, "video/mp4"); values.put(MediaStore.Video.Media.RELATIVE_PATH, Environment.DIRECTORY_MOVIES + "/MyApp"); ContentResolver resolver = context.getContentResolver(); Uri uri = resolver.insert(MediaStore.Video.Media.EXTERNAL_CONTENT_URI, values); try (OutputStream out = resolver.openOutputStream(uri); FileInputStream in = new FileInputStream(tempFile)) { byte[] buf = new byte[4096]; int len; while ((len = in.read(buf)) > 0) { out.write(buf, 0, len); } }媒体扫描触发:
MediaScannerConnection.scanFile(context, new String[] { videoFile.getAbsolutePath() }, new String[] { "video/mp4" }, (path, uri) -> { // 扫描完成回调 });
性能优化技巧:
- 使用后台线程处理文件操作
- 实现进度反馈机制
- 考虑使用ContentProviderOperation批量操作
- 针对大文件实现流式传输
用户体验增强建议:
- 提供视频缩略图预览
- 实现保存进度指示器
- 处理存储空间不足的优雅降级
- 支持取消保存操作
- 提供保存成功后的快速分享选项
5. 高级功能实现与性能调优
对于追求更高质量录制的应用,Camera2提供了一系列高级功能和控制选项。
手动控制参数:
曝光控制:
previewRequestBuilder.set(CaptureRequest.CONTROL_AE_MODE, CaptureRequest.CONTROL_AE_MODE_OFF); previewRequestBuilder.set(CaptureRequest.SENSOR_EXPOSURE_TIME, exposureTimeNs);对焦设置:
previewRequestBuilder.set(CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_VIDEO);白平衡控制:
previewRequestBuilder.set(CaptureRequest.CONTROL_AWB_MODE, CaptureRequest.CONTROL_AWB_MODE_AUTO);
扩展功能实现:
视频防抖:
if (characteristics.get(CameraCharacteristics.CONTROL_AVAILABLE_VIDEO_STABILIZATION_MODES) .contains(CameraMetadata.CONTROL_VIDEO_STABILIZATION_MODE_ON)) { previewRequestBuilder.set(CaptureRequest.CONTROL_VIDEO_STABILIZATION_MODE, CameraMetadata.CONTROL_VIDEO_STABILIZATION_MODE_ON); }高帧率录制:
Range<Integer>[] fpsRanges = characteristics.get( CameraCharacteristics.CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES); // 寻找支持的高帧率范围(如60fps)视频质量增强:
- 使用TEMPLATE_VIDEO_SNAPSHOT提高静态帧质量
- 实现HDR视频录制(如果设备支持)
- 应用电子防抖算法
性能监控指标:
| 指标 | 正常范围 | 优化建议 |
|---|---|---|
| 帧率 | ≥目标帧率80% | 降低分辨率/比特率 |
| 延迟 | <100ms | 减少处理管道长度 |
| 内存使用 | <设备内存50% | 优化缓冲区管理 |
| CPU使用 | <70% | 使用硬件加速编码 |
| 温度 | <45°C | 限制录制时长 |
在实际项目中,我们曾遇到录制长时间视频后出现内存泄漏的问题。通过分析发现是未正确释放MediaRecorder和CameraSession资源导致的。解决方案是建立严格的生命周期管理机制,确保所有资源在Activity/Fragment销毁时被正确释放。
