Android 8下使用CameraX无预览录制视频失败问题求助
Android 8 下 CameraX 无预览录制视频失败问题
我需要在Android 8系统中使用CameraX实现无预览界面的视频录制,但当前代码无法正常工作,日志显示录制状态从PENDING_RECORDING回退到INITIALIZING,没有生成有效视频文件。
现有代码
private fun Recording() { val selector = QualitySelector .from( Quality.UHD, FallbackStrategy.higherQualityOrLowerThan(Quality.SD) ) // build a recorder, which can: // - record video/audio to MediaStore(only shown here), File, ParcelFileDescriptor // - be used create recording(s) (the recording performs recording) val recorder = Recorder.Builder() .setQualitySelector(selector) .build() videoCapture = VideoCapture.withOutput(recorder) val name = getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS)?.absolutePath + "/recording.mp4" val contentValues = ContentValues().apply { put(MediaStore.Video.Media.DISPLAY_NAME, name) } Log.i("WEE",contentValues.toString()) val mediaStoreOutput = MediaStoreOutputOptions.Builder( contentResolver, MediaStore.Video.Media.EXTERNAL_CONTENT_URI) .setContentValues(contentValues) .build() // configure Recorder and Start recording to the mediaStoreOutput. currentRecording = videoCapture.output.prepareRecording(applicationContext,mediaStoreOutput).withAudioEnabled().start(mainThreadExecutor, captureListener) Log.i("TAG", "Recording started") sleep(4000) currentRecording!!.stop() currentRecording = null } private val captureListener = Consumer<VideoRecordEvent> { event -> // cache the recording state Log.i("TAG",event.toString()) if(event is VideoRecordEvent.Start){ } }
日志信息
2022-08-23 14:46:53.838 3348-3348/com.example.simplecamerax D/Recorder: Transitioning Recorder internal state: INITIALIZING --> PENDING_RECORDING 2022-08-23 14:46:53.838 3348-3348/com.example.simplecamerax I/TAG: Recording started 2022-08-23 14:46:57.838 3348-3348/com.example.simplecamerax D/Recorder: Transitioning Recorder internal state: PENDING_RECORDING --> INITIALIZING
问题原因及解决方法
1. CameraX 未绑定生命周期且未启动相机会话
CameraX 的 VideoCapture 必须绑定到生命周期所有者(如 Activity/Fragment),并通过 ProcessCameraProvider 启动相机会话,否则录制流程无法正常初始化。无预览场景下,相机会话的启动是录制的前提。
修复代码:
private lateinit var cameraProvider: ProcessCameraProvider private lateinit var videoCapture: VideoCapture<Recorder> private var currentRecording: Recording? = null private fun initCameraAndRecord() { val cameraProviderFuture = ProcessCameraProvider.getInstance(this) cameraProviderFuture.addListener({ cameraProvider = cameraProviderFuture.get() // 配置录制器 val selector = QualitySelector.from( Quality.UHD, FallbackStrategy.higherQualityOrLowerThan(Quality.SD) ) val recorder = Recorder.Builder() .setQualitySelector(selector) .build() videoCapture = VideoCapture.withOutput(recorder) // 绑定相机到生命周期,选择后置相机 val cameraSelector = CameraSelector.DEFAULT_BACK_CAMERA try { cameraProvider.unbindAll() // 绑定VideoCapture,启动相机会话 cameraProvider.bindToLifecycle(this, cameraSelector, videoCapture) // 相机会话启动后开始录制 startRecording() } catch(exc: Exception) { Log.e("TAG", "相机绑定失败", exc) } }, ContextCompat.getMainExecutor(this)) } private fun startRecording() { // 使用FileOutputOptions简化私有目录存储 val outputFile = File(getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS), "recording.mp4") val outputOptions = FileOutputOptions.Builder(outputFile).build() currentRecording = videoCapture.output .prepareRecording(this, outputOptions) .withAudioEnabled() .start(mainThreadExecutor, captureListener) Log.i("TAG", "Recording started") // 用Handler替代sleep,避免阻塞主线程 Handler(Looper.getMainLooper()).postDelayed({ currentRecording?.stop() currentRecording = null // 录制完成后解绑相机 cameraProvider.unbindAll() }, 4000) }
2. 主线程被 sleep() 阻塞导致录制异常
原代码中 sleep(4000) 会直接阻塞主线程,而 CameraX 的状态回调、相机操作都依赖主线程运行,这会打断录制流程,导致状态回退。
修复方法:
使用 Handler.postDelayed() 替代 sleep(),保证主线程正常处理相机事件。
3. MediaStoreOutputOptions 路径配置错误
原代码把完整文件路径作为 DISPLAY_NAME 传入,不符合 MediaStore 的规范——DISPLAY_NAME 应该仅为文件名,而非完整路径,这会导致输出目标无法正确创建。
修复方案:
- 若存储到应用私有目录,直接用
FileOutputOptions(如上述代码)更简单可靠; - 若需存储到公共目录,修正
ContentValues:
val contentValues = ContentValues().apply { put(MediaStore.Video.Media.DISPLAY_NAME, "recording.mp4") put(MediaStore.Video.Media.MIME_TYPE, "video/mp4") put(MediaStore.Video.Media.RELATIVE_PATH, Environment.DIRECTORY_DOWNLOADS) }
4. 缺少必要权限
Android 8 下录制视频需要 CAMERA、RECORD_AUDIO 权限,存储到公共目录还需 WRITE_EXTERNAL_STORAGE 权限。确保清单文件声明权限,并在运行时请求。
清单文件权限声明:
<uses-permission android:name="android.permission.CAMERA" /> <uses-permission android:name="android.permission.RECORD_AUDIO" /> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" android:maxSdkVersion="28" /> <uses-feature android:name="android.hardware.camera" /> <uses-feature android:name="android.hardware.camera.autofocus" />
总结
核心问题是相机未绑定生命周期、主线程被阻塞、路径配置错误三者共同导致录制流程中断。按照上述步骤修复后,即可实现 Android 8 下无预览的 CameraX 视频录制。
内容的提问来源于stack exchange,提问作者Gregor
相关产品推荐
相关产品推荐

