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

Android端如何利用CameraX的Image analysis保存带帧时间戳的视频?

用CameraX Image Analysis保存带时间戳帧的实现方法

完全可以通过Image Analysis组件实现带时间戳的帧保存,核心是利用CameraX提供的硬件级帧时间戳,配合后台线程完成文件存储,具体步骤和代码示例如下:

1. 获取帧的硬件时间戳

在ImageAnalysis.Analyzer的analyze方法中,通过ImageProxy.image?.timestamp可直接获取相机传感器提供的纳秒级时间戳,准确度极高。若image为空,可降级使用System.nanoTime()作为备选。

2. 帧数据转换与保存

CameraX默认输出YUV格式帧,需先转换为JPEG等可保存格式。注意不能在analyze方法内直接执行IO操作,否则会阻塞帧处理线程、降低录制帧率,建议用后台线程(如Coroutine IO调度器、单线程Executor)完成保存。

代码示例

自定义帧分析器

class TimestampedFrameAnalyzer : ImageAnalysis.Analyzer {
    private val yuvConverter = YuvToRgbConverter(ApplicationProvider.getApplicationContext())
    private var outputBitmap: Bitmap? = null

    override fun analyze(imageProxy: ImageProxy) {
        val sourceImage = imageProxy.image ?: run {
            imageProxy.close()
            return
        }

        // 按需初始化Bitmap(仅尺寸变化时创建)
        if (outputBitmap == null || outputBitmap?.width != sourceImage.width || outputBitmap?.height != sourceImage.height) {
            outputBitmap = Bitmap.createBitmap(sourceImage.width, sourceImage.height, Bitmap.Config.ARGB_8888)
        }

        // YUV转Bitmap
        outputBitmap?.let { bitmap ->
            yuvConverter.yuvToRgb(sourceImage, bitmap)
            // 纳秒转毫秒,方便文件名使用
            val timestampMs = sourceImage.timestamp / 1_000_000
            // 后台线程保存帧
            saveFrameToFile(timestampMs, bitmap)
        }

        // 必须关闭ImageProxy,否则CameraX会停止输出新帧
        imageProxy.close()
    }

    private fun saveFrameToFile(timestampMs: Long, bitmap: Bitmap) {
        CoroutineScope(Dispatchers.IO).launch {
            val saveDir = ApplicationProvider.getApplicationContext<Context>().getExternalFilesDir(Environment.DIRECTORY_PICTURES)
            val frameFile = File(saveDir, "recording_frame_${timestampMs}.jpg")
            try {
                FileOutputStream(frameFile).use { outputStream ->
                    bitmap.compress(Bitmap.CompressFormat.JPEG, 90, outputStream)
                }
            } catch (e: IOException) {
                e.printStackTrace()
            }
        }
    }
}

配置并绑定ImageAnalysis用例

// 构建ImageAnalysis用例
val imageAnalysis = ImageAnalysis.Builder()
    // 选择背压策略:STRATEGY_KEEP_ONLY_LATEST适合实时录制(丢弃旧帧);STRATEGY_BLOCK_PRODUCER会阻塞等待处理
    .setBackpressureStrategy(ImageAnalysis.STRATEGY_KEEP_ONLY_LATEST)
    .build()

// 指定专用线程池运行分析器,避免阻塞主线程
imageAnalysis.setAnalyzer(Executors.newSingleThreadExecutor(), TimestampedFrameAnalyzer())

// 绑定到Camera生命周期
val cameraProvider = ProcessCameraProvider.getInstance(context).get()
val cameraSelector = CameraSelector.DEFAULT_BACK_CAMERA
cameraProvider.bindToLifecycle(lifecycleOwner, cameraSelector, imageAnalysis)

注意事项

  • 时间戳单位:Image.timestamp返回纳秒,转换为毫秒(除以1000000)更适合作为文件名或时间记录。
  • 性能优化:若无需Bitmap,直接将YUV数据编码为JPEG可减少内存开销、提升处理速度。
  • 补充说明:其实Video Capture组件也能获取帧时间戳(通过MediaCodec或MediaRecorder回调),但Image Analysis在逐帧自定义处理上更灵活,适合需要精细化操作的场景。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.09 08:15:54