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

Android如何获取摄像头录制时的实时视频数据以实现实时传输?

安卓摄像头实时视频传输:获取数据并发送的实现方案

要实现类似视频通话的实时效果,核心是高效获取摄像头帧数据→编码压缩→低延迟网络传输→接收端解码渲染,以下是具体步骤:

一、获取摄像头预览帧数据(转为byte[])

推荐用Google的CameraX库(兼容性更好),通过ImageAnalysis组件获取实时预览帧:

  1. 添加CameraX依赖(在build.gradle中配置):
dependencies {
    def camerax_version = "1.3.0"
    implementation "androidx.camera:camera-core:$camerax_version"
    implementation "androidx.camera:camera-camera2:$camerax_version"
    implementation "androidx.camera:camera-lifecycle:$camerax_version"
    implementation "androidx.camera:camera-view:$camerax_version"
}
  1. 实现帧数据获取逻辑:
    CameraX默认输出YUV_420_888格式的Image,可将其转为byte[]:
val imageAnalyzer = ImageAnalysis.Builder()
    .setTargetResolution(Size(640, 480)) // 降低分辨率减少带宽压力
    .setBackpressureStrategy(ImageAnalysis.STRATEGY_KEEP_ONLY_LATEST) // 只保留最新帧,保证实时性
    .build()

imageAnalyzer.setAnalyzer(Executors.newSingleThreadExecutor()) { image ->
    // 提取YUV各平面数据并合并为byte[]
    val yBuffer = image.planes[0].buffer
    val uBuffer = image.planes[1].buffer
    val vBuffer = image.planes[2].buffer

    val ySize = yBuffer.remaining()
    val uSize = uBuffer.remaining()
    val vSize = vBuffer.remaining()

    val byteArray = ByteArray(ySize + uSize + vSize)
    yBuffer.get(byteArray, 0, ySize)
    uBuffer.get(byteArray, ySize, uSize)
    vBuffer.get(byteArray, ySize + uSize, vSize)

    // 拿到原始YUV数据后,编码再发送
    encodeAndSendFrame(byteArray, image.width, image.height)

    image.close() // 必须关闭Image,否则会阻塞后续帧采集
}

// 将Analyzer绑定到页面生命周期
CameraX.bindToLifecycle(this, cameraProvider, preview, imageAnalyzer)

二、视频编码(必做:原始数据带宽无法支撑实时传输)

原始YUV数据体积极大(640x480单帧约900KB),必须用硬编码压缩为H.264格式,用MediaCodec实现:

private lateinit var mediaCodec: MediaCodec
private var codecConfigured = false

fun initEncoder(width: Int, height: Int) {
    val format = MediaFormat.createVideoFormat(MediaFormat.MIMETYPE_VIDEO_AVC, width, height)
    format.setInteger(MediaFormat.KEY_BIT_RATE, 1000000) // 1Mbps码率,可根据网络调整
    format.setInteger(MediaFormat.KEY_FRAME_RATE, 25) // 25帧/秒,平衡流畅度与带宽
    format.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, 5) // 每5帧生成一个关键帧,优化丢包恢复
    format.setInteger(MediaFormat.KEY_COLOR_FORMAT, MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420Flexible)

    mediaCodec = MediaCodec.createEncoderByType(MediaFormat.MIMETYPE_VIDEO_AVC)
    mediaCodec.configure(format, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE)
    mediaCodec.start()
    codecConfigured = true
}

fun encodeAndSendFrame(yuvData: ByteArray, width: Int, height: Int) {
    if (!codecConfigured) initEncoder(width, height)

    // 喂数据到编码器
    val inputBufferIndex = mediaCodec.dequeueInputBuffer(1000)
    if (inputBufferIndex >= 0) {
        val inputBuffer = mediaCodec.getInputBuffer(inputBufferIndex)
        inputBuffer?.clear()
        inputBuffer?.put(yuvData)
        mediaCodec.queueInputBuffer(inputBufferIndex, 0, yuvData.size, System.nanoTime() / 1000, 0)
    }

    // 获取编码后的数据并发送
    val bufferInfo = MediaCodec.BufferInfo()
    var outputBufferIndex = mediaCodec.dequeueOutputBuffer(bufferInfo, 1000)
    while (outputBufferIndex >= 0) {
        val outputBuffer = mediaCodec.getOutputBuffer(outputBufferIndex)
        val encodedData = ByteArray(bufferInfo.size)
        outputBuffer?.get(encodedData)

        sendEncodedData(encodedData)

        mediaCodec.releaseOutputBuffer(outputBufferIndex, false)
        outputBufferIndex = mediaCodec.dequeueOutputBuffer(bufferInfo, 0)
    }
}

三、网络传输(低延迟优先选UDP)

实时视频通话优先用UDP协议(延迟低,少量丢包不影响观感),用DatagramSocket实现发送:

private lateinit var datagramSocket: DatagramSocket
private val targetAddress = InetAddress.getByName("192.168.1.100") // 接收端IP
private val targetPort = 8888 // 接收端监听端口

fun initSocket() {
    datagramSocket = DatagramSocket()
    datagramSocket.soTimeout = 1000
}

fun sendEncodedData(data: ByteArray) {
    val packet = DatagramPacket(data, data.size, targetAddress, targetPort)
    try {
        datagramSocket.send(packet)
    } catch (e: IOException) {
        e.printStackTrace()
    }
}

四、接收端核心逻辑

接收端收到H.264格式的byte[]后,需完成:

  1. 初始化MediaCodec解码器,配置H.264格式
  2. 接收UDP数据包,将数据喂给解码器
  3. 获取解码后的Surface帧,渲染到TextureView或SurfaceView

关键实时性优化点

  • 降低摄像头分辨率(如640x480)和帧率(20-25帧/秒)
  • 动态调整编码码率:网络差时降低码率,保证流畅度
  • 用UDP+RTP封装视频流:规范传输格式,方便处理丢包与时序
  • 所有帧处理、编码、发送逻辑放在子线程,避免阻塞主线程

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.15 17:50:44