You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用CameraX录制视频后,无法通过getSavedUri获取视频绝对路径

CameraX获取录制视频绝对路径问题解决

你的代码核心问题

  • 回调调用错误:你在start()方法后直接调用onVideoSaved(outputFileResults = androidx.camera.core.VideoCapture.OutputFileResults)完全错误,OutputFileResults是录制完成后系统返回的实例,不能直接传类。正确做法是把onVideoSaved作为start()的回调参数传入。
  • Uri转路径误区:Android 10(API 29)及以上启用分区存储,savedUri无法直接通过常规方法转为绝对路径,需要通过ContentResolver查询获取。

修正后的完整代码

private fun captureVideo() {
    val videoCapture = this.videoCapture ?: return
    val curRecording = recording
    if (curRecording != null) {
        // 停止当前录制
        curRecording.stop()
        recording = null
        return
    }

    // 生成视频文件名
    val name = SimpleDateFormat(FILENAME_FORMAT, Locale.US)
        .format(System.currentTimeMillis())
    val contentValues = ContentValues().apply {
        put(MediaStore.MediaColumns.DISPLAY_NAME, name)
        put(MediaStore.MediaColumns.MIME_TYPE, "video/mp4")
        if (Build.VERSION.SDK_INT > Build.VERSION_CODES.P) {
            put(MediaStore.Video.Media.RELATIVE_PATH, "Movies/CameraX-Video")
        }
    }
    
    val mediaStoreOutputOptions = MediaStoreOutputOptions
        .Builder(contentResolver, MediaStore.Video.Media.EXTERNAL_CONTENT_URI)
        .setContentValues(contentValues)
        .build()

    recording = videoCapture.output
        .prepareRecording(this, mediaStoreOutputOptions)
        .apply {
            if (PermissionChecker.checkSelfPermission(this@MainActivity,
                    Manifest.permission.RECORD_AUDIO) ==
                PermissionChecker.PERMISSION_GRANTED)
            {
                withAudioEnabled()
            }
        }
        // 正确传入录制完成回调
        .start(ContextCompat.getMainExecutor(this)) { outputFileResults ->
            onVideoSaved(outputFileResults)
        }
}

@SuppressLint("RestrictedApi")
private fun onVideoSaved(outputFileResults: androidx.camera.core.VideoCapture.OutputFileResults) {
    val savedUri = outputFileResults.savedUri ?: return
    
    // 获取视频绝对路径
    val videoPath = getRealPathFromUri(savedUri)
    // 这里可对videoPath做后续操作
}

// 通过ContentResolver查询Uri对应的真实路径
private fun getRealPathFromUri(uri: Uri): String? {
    val projection = arrayOf(MediaStore.Video.Media.DATA)
    contentResolver.query(uri, projection, null, null, null)?.use { cursor ->
        return if (cursor.moveToFirst()) {
            val columnIndex = cursor.getColumnIndexOrThrow(MediaStore.Video.Media.DATA)
            cursor.getString(columnIndex)
        } else {
            null
        }
    }
    return null
}

关键说明

  1. 回调修正:将onVideoSaved放在start()的lambda参数中,录制完成后系统会自动传入OutputFileResults实例。
  2. 路径获取:
    • Android 10以下:MediaStore.Video.Media.DATA字段直接返回绝对路径。
    • Android 10及以上:虽然分区存储限制了直接访问,但通过ContentResolver查询仍能获取真实路径(建议优先使用Uri操作文件,而非依赖绝对路径)。
  3. 权限检查:确保已申请WRITE_EXTERNAL_STORAGE(兼容低版本)和RECORD_AUDIO权限。

内容的提问来源于stack exchange,提问作者Hassaan Zahid

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.13 06:35:48