如何使用CameraX VideoCapture暂停/恢复视频录制?
Android 视频录制暂停/恢复功能实现方案
Android原生的MediaRecorder或Camera2 API并没有提供直接的pause()/resume()方法来暂停视频录制,常用的实现思路是分段录制多个视频文件,最后将这些片段合并成一个完整视频。以下是具体实现步骤:
核心思路
- 暂停录制时,调用
stopRecording()结束当前片段录制并保存为临时文件 - 恢复录制时,重新初始化
MediaRecorder,开始录制新的片段 - 录制完成后,将所有临时视频片段合并为一个最终视频文件
关键代码实现
(1)定义核心变量
private var mediaRecorder: MediaRecorder? = null private var isRecording = false private var isPaused = false private val videoSegments = mutableListOf<File>() // 存储所有录制片段 private var currentSegmentFile: File? = null
(2)开始/恢复录制
fun startOrResumeRecording() { if (isPaused) { // 恢复录制:创建新临时片段文件 currentSegmentFile = createTempVideoFile() initMediaRecorder(currentSegmentFile!!) mediaRecorder?.start() isPaused = false isRecording = true } else if (!isRecording) { // 首次启动录制 currentSegmentFile = createTempVideoFile() initMediaRecorder(currentSegmentFile!!) mediaRecorder?.start() isRecording = true } } // 创建临时视频文件 private fun createTempVideoFile(): File { val storageDir = getExternalFilesDir(Environment.DIRECTORY_MOVIES) return File.createTempFile( "RECORD_SEGMENT_${System.currentTimeMillis()}", ".mp4", storageDir ).apply { videoSegments.add(this) } } // 初始化MediaRecorder(根据你的Camera配置调整参数) private fun initMediaRecorder(outputFile: File) { mediaRecorder?.release() mediaRecorder = MediaRecorder().apply { setAudioSource(MediaRecorder.AudioSource.MIC) setVideoSource(MediaRecorder.VideoSource.SURFACE) setOutputFormat(MediaRecorder.OutputFormat.MPEG_4) setOutputFile(outputFile.absolutePath) setVideoEncoder(MediaRecorder.VideoEncoder.H264) setAudioEncoder(MediaRecorder.AudioEncoder.AAC) // 配置分辨率、帧率等参数 setVideoSize(1280, 720) setVideoFrameRate(30) prepare() } }
(3)暂停录制
fun pauseRecording() { if (isRecording && !isPaused) { mediaRecorder?.stop() mediaRecorder?.release() mediaRecorder = null isPaused = true isRecording = false } }
(4)停止录制并合并片段
fun stopAndMergeRecording() { if (isRecording) { mediaRecorder?.stop() mediaRecorder?.release() mediaRecorder = null isRecording = false } when (videoSegments.size) { 0 -> return 1 -> videoSegments[0].renameTo(getFinalOutputFile()) else -> mergeVideoSegments(videoSegments, getFinalOutputFile()) } // 清理临时片段 videoSegments.forEach { it.delete() } videoSegments.clear() isPaused = false } // 获取最终输出文件 private fun getFinalOutputFile(): File { val storageDir = getExternalFilesDir(Environment.DIRECTORY_MOVIES) return File(storageDir, "FINAL_RECORD_${System.currentTimeMillis()}.mp4") }
(5)原生API实现视频合并
使用Android自带的MediaMuxer完成片段合并,无需第三方库:
private fun mergeVideoSegments(segments: List<File>, outputFile: File) { val mediaMuxer = MediaMuxer(outputFile.absolutePath, MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4) var videoTrackIndex = -1 var audioTrackIndex = -1 val buffer = ByteBuffer.allocate(1024 * 1024) segments.forEach { segment -> val extractor = MediaExtractor() extractor.setDataSource(segment.absolutePath) // 定位视频、音频轨道 for (i in 0 until extractor.trackCount) { val format = extractor.getTrackFormat(i) val mime = format.getString(MediaFormat.KEY_MIME) when { mime?.startsWith("video/") == true && videoTrackIndex == -1 -> { videoTrackIndex = mediaMuxer.addTrack(format) extractor.selectTrack(i) } mime?.startsWith("audio/") == true && audioTrackIndex == -1 -> { audioTrackIndex = mediaMuxer.addTrack(format) extractor.selectTrack(i) } } } // 写入片段数据 if (videoTrackIndex != -1 || audioTrackIndex != -1) { mediaMuxer.start() var sampleSize: Int while (extractor.readSampleData(buffer, 0).also { sampleSize = it } != -1) { val trackIndex = if (extractor.getTrackFormat(extractor.selectedTrackIndex) .getString(MediaFormat.KEY_MIME)?.startsWith("video/") == true ) videoTrackIndex else audioTrackIndex mediaMuxer.writeSampleData( trackIndex, buffer, MediaCodec.BufferInfo().apply { offset = 0 size = sampleSize presentationTimeUs = extractor.sampleTime flags = extractor.sampleFlags } ) extractor.advance() } } extractor.release() } mediaMuxer.stop() mediaMuxer.release() }
注意事项
- 确保申请必要权限:
RECORD_AUDIO、CAMERA,Android 10+无需WRITE_EXTERNAL_STORAGE,使用Scoped Storage即可 - 临时文件需及时清理,避免占用冗余存储空间
- 合并视频时需保证音视频同步,可通过调整
presentationTimeUs参数优化过渡效果 - 若使用Camera2 API,需适配
MediaRecorder的Surface配置,配合Camera2的预览流程
内容的提问来源于stack exchange,提问作者khushhal goyal
相关产品推荐
相关产品推荐

