2、硬件解码核心原理:GPU/VPU硬件单元、视频编解码标准(H.264/H.265/AV1)、码流解析与硬件加速接口

好,咱们进入正题。这一章聊的是硬解码的「硬」在哪里。说白了,就是搞清楚车机里那块芯片到底是怎么把视频流「吃进去、吐出来」的。

我最早接触车载硬解码时,有个误区——以为只要SoC支持4K解码,随便什么视频都能流畅播。结果呢?一上实车,H.265的10bit视频直接卡成PPT。后来才明白,硬件解码远不止「支持格式」那么简单。

2.1 GPU与VPU:谁在干活?

先区分两个概念:GPU和VPU。

  • GPU(图形处理器):擅长并行计算,做图像渲染、UI合成。但让它去解码视频流,效率其实不高。
  • VPU(视频处理单元):专用硬件,专门为编解码算法设计的。我习惯叫它「视频加速器」。

在车机里,通常是VPU负责解码,GPU负责显示。两者通过内存交换数据。嗯,这里要注意:如果VPU和GPU共用同一块DDR带宽,高码率视频就可能抢资源。我在项目中遇到过,4K 60fps的视频一播放,导航地图就卡顿——后来发现是内存带宽瓶颈。

关键点:VPU是解码主力,GPU是显示辅助。别指望GPU软解高码率视频,车机功耗扛不住。

2.2 视频编解码标准:H.264、H.265、AV1

这三个标准,是当前车载视频的主流选择。我按实际使用场景聊聊。

H.264(AVC)

老将了。兼容性最好,几乎所有的车机VPU都支持。但压缩率一般,同样的画质,码率比H.265高30%-50%。

我个人习惯:如果车机平台比较老(比如2018年前的),优先用H.264。省心,不出兼容问题。

H.265(HEVC)

现在的主流。压缩率比H.264高一倍,4K视频用H.265能省不少存储和带宽。但解码复杂度也高,对VPU算力要求更大。

避坑指南:我曾经遇到过H.265的10bit色深视频,在部分车机VPU上解码失败。原因是VPU只支持8bit。所以选型时一定要确认VPU的色深支持范围。

AV1

新秀。压缩率比H.265再高30%,但解码复杂度也更高。目前车载VPU支持AV1的还不多,主要是高通SA8295、SA8255这些新平台才开始集成。

我的建议:如果你做的是2025年后的车型,可以开始考虑AV1。但现阶段,H.265仍是性价比最高的选择。

标准 压缩率 解码复杂度 车载普及度 我的推荐
H.264 基准 极高 老平台首选
H.265 比H.264高50% 当前主流
AV1 比H.265高30% 低(新平台开始支持) 未来趋势

2.3 码流解析:VPU到底在解什么?

你想想看,视频文件在存储时是一堆二进制数据。VPU要解码,得先知道这些数据怎么组织的。这就是码流解析的活。

一个典型的视频码流包含:

  • 序列参数集(SPS):分辨率、帧率、编码档次等全局信息
  • 图像参数集(PPS):编码工具开关、量化参数等
  • NAL单元:真正的视频帧数据

VPU拿到码流后,第一步就是解析SPS/PPS。如果解析失败,整个解码流程就卡住了。我遇到过一种情况:某些视频的SPS里写了「帧率30fps」,但实际码流里帧间隔不均匀。VPU按30fps去解码,结果显示时一卡一卡的。

经验之谈:码流解析阶段,一定要做「帧率一致性校验」。别完全相信SPS里的声明,要实际统计一下帧间隔。

2.4 硬件加速接口:怎么让VPU干活?

VPU不是直接暴露给应用层的。你得通过硬件加速接口去调用它。主流的有三种:

2.4.1 V4L2 M2M(Linux平台)

这是Linux内核里最常用的视频加速接口。M2M的意思是Memory-to-Memory,即从内存读码流,解码后输出到内存。

使用流程大致是:

  1. 打开VPU设备节点(如/dev/video0)
  2. 设置输入格式(码流类型、分辨率等)
  3. 设置输出格式(解码后的YUV格式)
  4. 循环:把码流数据送入输入队列,从输出队列取解码后的帧
// 伪代码示意
int fd = open("/dev/video0", O_RDWR);
struct v4l2_format fmt = {0};
fmt.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
fmt.fmt.pix_mp.pixelformat = V4L2_PIX_FMT_H264;
ioctl(fd, VIDIOC_S_FMT, &fmt);

// 设置输出格式
fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
fmt.fmt.pix_mp.pixelformat = V4L2_PIX_FMT_NV12;
ioctl(fd, VIDIOC_S_FMT, &fmt);

// 开始解码循环
while (1) {
    // 送码流数据
    // 取解码帧
}

嗯,这里要注意:V4L2 M2M的缓冲区管理很关键。缓冲区太少,解码会卡顿;缓冲区太多,内存占用大。我一般设4-6个缓冲区,够用。

2.4.2 OMX IL(OpenMAX Integration Layer)

这是比较老的接口了,主要用于Android平台。OMX IL定义了一套组件化的解码流程。但说实话,现在Android平台也慢慢转向Codec2了。

2.4.3 Codec2(Android平台)

Android 10之后主推的硬件解码接口。比OMX IL更简洁,支持异步操作。如果你做Android车机,建议直接用Codec2。

注意:Codec2虽然好用,但不同厂商的VPU驱动实现有差异。比如高通和联发科的Codec2实现,在缓冲区管理策略上就不一样。跨平台移植时,一定要做充分的兼容性测试。

2.5 实战中的坑与对策

最后,我总结几个实际项目中踩过的坑:

  • 坑1:VPU不支持某些编码工具。比如H.265的SAO(样点自适应补偿),部分老VPU不支持。结果就是解码花屏。对策:编码时禁用高级工具,或者用软件回退。
  • 坑2:码流解析超时。有些视频的SPS/PPS放在文件末尾,VPU要等到解析完才能开始解码。对策:解码前先预解析一遍码流,提取SPS/PPS。
  • 坑3:帧率不稳定。VPU解码速度跟不上码流帧率,导致丢帧。对策:监控解码队列深度,如果队列持续为空,说明VPU过载,需要降低码率或分辨率。

好了,这一章的核心就这些。硬件解码不是「插上就能用」的,你得理解VPU怎么工作、码流怎么组织、接口怎么调用。下一章,我们聊聊帧率稳定的具体方案——那才是真正让视频「丝滑」的关键。