如何用Camera2 Kotlin API创建MediaRecorder并关联已有TextureView
Android Camera2 结合 TextureView 实现视频录制
下面是基于Camera2 API结合TextureView实现视频录制的完整方案,解决你关联MediaRecorder的问题:
一、先搞定权限
首先在AndroidManifest.xml里声明必要权限:
<uses-permission android:name="android.permission.CAMERA" /> <uses-permission android:name="android.permission.RECORD_AUDIO" /> <!-- Android 13+ 用这两个替代旧存储权限 --> <uses-permission android:name="android.permission.WRITE_MEDIA_VIDEO" /> <uses-permission android:name="android.permission.READ_MEDIA_VIDEO" /> <!-- Android 12及以下保留 --> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" android:maxSdkVersion="32" />
注意:必须动态申请这些权限,确保调用相机前权限已授予。
二、初始化MediaRecorder
写一个方法配置录制参数,指定输出路径、编码格式等:
private fun initMediaRecorder() { mediaRecorder = MediaRecorder().apply { setAudioSource(MediaRecorder.AudioSource.MIC) setVideoSource(MediaRecorder.VideoSource.SURFACE) setOutputFormat(MediaRecorder.OutputFormat.MPEG_4) // 生成视频输出路径(示例:外部存储Movies目录) val outputFile = File( Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_MOVIES), "record_${System.currentTimeMillis()}.mp4" ) setOutputFile(outputFile.absolutePath) setVideoEncoder(MediaRecorder.VideoEncoder.H264) setAudioEncoder(MediaRecorder.AudioEncoder.AAC) setVideoSize(1920, 1080) // 建议和相机支持的分辨率匹配 setVideoFrameRate(30) setVideoEncodingBitRate(10 * 1024 * 1024) // 10Mbps保证视频质量 prepare() // 必须调用prepare完成初始化 } }
三、修改相机会话,同时关联预览和录制Surface
修改你原来的open_camera方法,创建CaptureSession时要同时加入TextureView的预览Surface和MediaRecorder的录制Surface:
@SuppressLint("MissingPermission") fun openCamera() { cameraManager.openCamera(camIdWithFlash, object : CameraDevice.StateCallback() { override fun onOpened(camera: CameraDevice) { cameraDevice = camera // 先初始化MediaRecorder initMediaRecorder() // 获取两个关键Surface:预览(TextureView)、录制(MediaRecorder) val previewSurface = Surface(textureView.surfaceTexture) val recordSurface = mediaRecorder!!.surface // 构建预览请求 capReq = cameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW) capReq.addTarget(previewSurface) // 创建包含双Surface的相机会话 cameraDevice.createCaptureSession( listOf(previewSurface, recordSurface), object : CameraCaptureSession.StateCallback() { override fun onConfigured(session: CameraCaptureSession) { cameraCaptureSession = session // 启动预览 cameraCaptureSession.setRepeatingRequest( capReq.build(), null, handler ) } override fun onConfigureFailed(session: CameraCaptureSession) { // 配置失败的处理,比如弹个提示 } }, handler ) } override fun onDisconnected(camera: CameraDevice) { camera.close() cameraDevice = null } override fun onError(camera: CameraDevice, error: Int) { camera.close() cameraDevice = null } }, handler) }
四、实现开始/停止录制的逻辑
添加两个方法控制录制状态切换:
private var isRecording = false fun startRecording() { if (isRecording || cameraDevice == null || cameraCaptureSession == null) return isRecording = true // 构建录制专用的CaptureRequest,用TEMPLATE_RECORD模板 val recordReq = cameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_RECORD).apply { addTarget(Surface(textureView.surfaceTexture!!)) addTarget(mediaRecorder!!.surface) // 设置自动曝光,保证录制时光线正常 set(CaptureRequest.CONTROL_AE_MODE, CaptureRequest.CONTROL_AE_MODE_ON_AUTO_FLASH) // 需要开闪光灯的话,加这行: // set(CaptureRequest.FLASH_MODE, CaptureRequest.FLASH_MODE_TORCH) } // 启动录制 mediaRecorder?.start() // 切换到录制请求 cameraCaptureSession?.setRepeatingRequest( recordReq.build(), null, handler ) } fun stopRecording() { if (!isRecording || mediaRecorder == null) return isRecording = false // 停止并重置MediaRecorder mediaRecorder?.apply { stop() reset() release() } mediaRecorder = null // 切回预览模式 val previewReq = cameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW).apply { addTarget(Surface(textureView.surfaceTexture!!)) } cameraCaptureSession?.setRepeatingRequest( previewReq.build(), null, handler ) // 重新初始化MediaRecorder,为下次录制做准备 initMediaRecorder() }
五、关键注意事项
- 要在
TextureView.SurfaceTextureListener的onSurfaceTextureAvailable回调里调用openCamera,确保Surface已就绪。 - 页面销毁时记得释放资源:
override fun onDestroy() { super.onDestroy() cameraCaptureSession?.stopRepeating() cameraCaptureSession?.close() cameraDevice?.close() mediaRecorder?.release() }
- Android 10+建议用
MediaStore保存视频,避免存储权限问题。 - 如果遇到分辨率不兼容,可以通过
CameraCharacteristics获取相机支持的最佳分辨率。
内容的提问来源于stack exchange,提问作者Akigomon505
相关产品推荐
相关产品推荐

