使用CameraX VideoCapture API录制视频时遇错误,求解决方法
解决CameraX VideoCapture录制视频时的"Albums cannot be directly modified"错误
错误原因
从日志关键信息collectionUri=content://media/external/audio/albums可以看出:你创建MediaStoreOutputOptions时传入了音频专辑的URI,但录制视频需要使用视频媒体对应的存储URI,导致系统尝试修改音频专辑目录,触发了UnsupportedOperationException。
修复步骤
1. 替换正确的MediaStore URI
将创建MediaStoreOutputOptions时的EXTERNAL_CONTENT_URI替换为MediaStore.Video.Media.EXTERNAL_CONTENT_URI,这是视频文件的合法存储URI。
修复后的关键代码片段:
val options = MediaStoreOutputOptions.Builder(requireContext().contentResolver, MediaStore.Video.Media.EXTERNAL_CONTENT_URI) .setContentValues(contentValues) .build()
2. 检查权限配置
确保AndroidManifest.xml中声明了必要权限:
<!-- Android 10及以下需要 --> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> <!-- Android 13+需单独声明视频权限 --> <uses-permission android:name="android.permission.READ_MEDIA_VIDEO" /> <!-- 如果需要录制带音频的视频,添加此权限 --> <uses-permission android:name="android.permission.RECORD_AUDIO" />
运行时需动态申请这些权限(Android 10+使用Scoped Storage可自动处理部分存储权限,但低版本仍需手动申请)。
3. 可选:修正日期格式
你使用的SimpleDateFormat格式"yyy-MM-dd-HH-mm-ss-SSS"少一个y,会导致年份显示错误,建议改为"yyyy-MM-dd-HH-mm-ss-SSS"。
完整修复后的recordVideo函数
private fun recordVideo() { binding.buttonCapture.setImageResource(R.drawable.baseline_stop_24) val currentRecording = recording if (currentRecording != null) { // 停止正在进行的录制 currentRecording.stop() recording = null binding.buttonCapture.setImageResource(R.drawable.baseline_camera_24) return } val name: String = SimpleDateFormat( "yyyy-MM-dd-HH-mm-ss-SSS", // 修正年份格式 Locale.getDefault() ).format(System.currentTimeMillis()) val contentValues = ContentValues().apply { put(MediaStore.MediaColumns.DISPLAY_NAME, name) put(MediaStore.MediaColumns.MIME_TYPE, "video/mp4") put(MediaStore.MediaColumns.RELATIVE_PATH, "Movies/CameraX-Recorder") } // 使用视频对应的MediaStore URI val options = MediaStoreOutputOptions.Builder(requireContext().contentResolver, MediaStore.Video.Media.EXTERNAL_CONTENT_URI) .setContentValues(contentValues) .build() recording = videoCapture?.output?.prepareRecording(requireContext(), options) ?.start(ContextCompat.getMainExecutor(requireContext())) { videoRecordEvent -> when (videoRecordEvent) { is VideoRecordEvent.Start -> { binding.buttonCapture.setImageResource(R.drawable.baseline_stop_24) } is VideoRecordEvent.Pause -> { // 处理暂停逻辑 } is VideoRecordEvent.Resume -> { // 处理恢复逻辑 } is VideoRecordEvent.Finalize -> { val finalizeEvent = videoRecordEvent as VideoRecordEvent.Finalize val error = finalizeEvent.error if (error != VideoRecordEvent.Finalize.ERROR_NONE) { Toast.makeText( requireContext(), "视频录制完成时出错: ${videoRecordEvent.error}", Toast.LENGTH_SHORT ).show() } else { Toast.makeText( requireContext(), "视频录制成功", Toast.LENGTH_SHORT ).show() } binding.buttonCapture.setImageResource(R.drawable.baseline_camera_24) } } val recordingStats = videoRecordEvent.recordingStats } }
内容的提问来源于stack exchange,提问作者Patrick Renaud
相关产品推荐
相关产品推荐

