视频流传输:H.264/H.265编码、MediaCodec硬编解码、RTP/RTSP协议、低延迟传输方案

车机互联中,视频流传输是最核心也最棘手的一环。你想啊,手机屏幕要投射到车机上,还得实时响应触摸操作,延迟稍微高一点,用户体验就崩了。我最早做这个模块时,踩了不少坑,今天就把这些经验掰开揉碎讲给你听。

为什么视频流传输这么重要?

说白了,车机互联的本质就是「手机的画面搬到车机上」。无论是导航、音乐还是视频通话,底层都是视频流在跑。如果编码选不对、协议不合适,画面卡顿、延迟高、花屏,用户直接骂娘。

我见过不少团队,上来就选H.264,觉得成熟稳定。但实际跑起来,车机芯片解码能力参差不齐,有的老芯片解码1080p都费劲。所以,选编码方案前,先摸清目标车机的硬件底牌。

H.264 vs H.265:怎么选?

这两个编码标准,是当前视频传输的绝对主力。我直接说结论:

特性 H.264 (AVC) H.265 (HEVC)
压缩率 基准 提升约50%
解码复杂度 高(约2-3倍)
硬件支持 几乎所有车机芯片 较新芯片才支持
延迟表现 优秀 略高(编码更耗时)
带宽需求 较高 低(同等画质)

我的建议:如果车机芯片支持H.265硬解码,优先用H.265。带宽省一半,画质还更好。但如果是老车机(比如2018年前的),老老实实用H.264,别折腾。

我记得有一次,客户非要上H.265,结果车机解码一帧要30ms,直接导致端到端延迟飙到200ms+。后来切回H.264,延迟降到80ms,客户才满意。嗯,技术选型不能只看纸面参数。

MediaCodec硬编解码实战

Android上做视频编解码,绕不开MediaCodec。它支持硬件加速,性能远好于软编软解。我直接给一段核心代码,你照着用就行。

// 创建编码器
MediaCodec encoder = MediaCodec.createEncoderByType(MediaFormat.MIMETYPE_VIDEO_AVC);
MediaFormat format = MediaFormat.createVideoFormat(
    MediaFormat.MIMETYPE_VIDEO_AVC, 1280, 720);
format.setInteger(MediaFormat.KEY_BIT_RATE, 2000000); // 2Mbps
format.setInteger(MediaFormat.KEY_FRAME_RATE, 30);
format.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, 1); // 关键帧间隔1秒
format.setInteger(MediaFormat.KEY_COLOR_FORMAT,
    MediaCodecInfo.CodecCapabilities.COLOR_FormatSurface);

encoder.configure(format, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE);
encoder.start();

// 输入数据(从Surface获取)
Surface inputSurface = encoder.createInputSurface();
// ... 渲染画面到inputSurface ...

// 获取编码后的数据
MediaCodec.BufferInfo info = new MediaCodec.BufferInfo();
int outputIndex = encoder.dequeueOutputBuffer(info, 10000);
if (outputIndex >= 0) {
    ByteBuffer outputData = encoder.getOutputBuffer(outputIndex);
    // 这里outputData就是H.264/H.265码流
    // 可以封装成RTP包发送
    encoder.releaseOutputBuffer(outputIndex, false);
}

避坑指南:我曾经把KEY_I_FRAME_INTERVAL设成0,结果编码器只在场景切换时生成关键帧。车机端解码器等不到关键帧,画面一直花屏。后来改成1秒一个关键帧,问题解决。记住,车机互联场景下,关键帧间隔不要超过2秒。

RTP/RTSP协议:传输层的选择

视频流编码好了,怎么传过去?RTP/RTSP是经典方案。RTP负责传数据,RTSP负责控制(播放、暂停、快进)。

为什么选RTP?因为它支持实时传输,有时间戳和序列号,能抗丢包。你想想看,车机互联时网络环境复杂,Wi-Fi信号不稳定、蓝牙干扰,丢包是常态。RTP的序列号机制,能帮解码器判断哪些包丢了,做丢包隐藏。

RTSP则用来建立会话。流程很简单:

  1. 手机端启动RTSP Server,监听端口(比如554)
  2. 车机端发送DESCRIBE请求,获取媒体描述
  3. 车机端发送SETUP请求,建立传输通道
  4. 车机端发送PLAY请求,开始接收RTP流
  5. 手机端持续发送RTP包,车机端解码渲染

我习惯用libVLC或自定义的轻量RTSP库。Android上可以用android.net.rtp包,但功能有限,建议用第三方库。

低延迟传输方案:核心优化点

车机互联对延迟极其敏感。我定个标准:端到端延迟(从手机触摸到车机画面响应)不超过100ms,否则用户能明显感觉到卡顿。

怎么做到?我总结几个关键优化点:

  • 编码参数调优:关闭B帧(只保留I帧和P帧),B帧会引入延迟。设置KEY_LATENCY为0,强制低延迟模式。
  • 网络传输优化:使用UDP而非TCP。TCP重传机制会引入延迟,UDP丢包就丢包,解码器做丢包隐藏。
  • 解码渲染优化:车机端使用SurfaceView而非TextureView,SurfaceView有独立的渲染线程,延迟更低。
  • 缓冲区控制:解码器缓冲区不要太大。我一般设成3帧,再多就丢帧。缓冲区越大,延迟越高。

注意:低延迟和高画质是矛盾的。你追求低延迟,就得牺牲画质。我一般把码率控制在2-4Mbps,分辨率1080p,帧率30fps。这个配置在大多数车机上都能跑出80ms左右的延迟。

知识体系总览

下面这张图,把视频流传输的核心逻辑串起来了。你对照着看,心里就有谱了。

视频流传输知识体系 手机端(编码) MediaCodec硬编码 H.264/H.265 编码后码流 传输层 RTP/RTSP协议 UDP传输 / 低延迟 RTP包 车机端(解码) MediaCodec硬解码 SurfaceView渲染 关键优化点 • 编码:关闭B帧,强制低延迟模式 • 传输:UDP + RTP,避免TCP重传延迟 • 解码:缓冲区设3帧,SurfaceView渲染

实战中的坑与解法

最后分享几个我踩过的坑,你遇到了直接抄答案:

  • 花屏问题:车机端解码器收到不完整的关键帧,画面花掉。解法:手机端发送关键帧时,用RTP的MARKER位标记帧结束,车机端等收到完整帧再解码。
  • 音画不同步:视频流和音频流各自走RTP,时间戳没对齐。解法:用NTP时间戳同步,手机端和车机端都参考同一时钟源。
  • Wi-Fi干扰:车机连了车载Wi-Fi,手机开热点,两者互相干扰。解法:用5GHz频段,或者走USB有线连接(延迟最低,能到20ms)。

嗯,视频流传输这块,说难不难,说简单也不简单。核心就是编码选对、协议选对、参数调优。你按我上面说的做,基本不会出大问题。如果遇到具体报错,欢迎来公众号找我聊。

公众号:蓝海资料掘金营,微信deep3321