ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

Zynq UltraScale+ EV的4K60 H.265解码与HDMI 2.0输出实战

Zynq UltraScale+ EV的4K60 H.265解码与HDMI 2.0输出实战 在嵌入式视觉领域摸爬滚打久了你会发现一个很现实的问题4K60帧的H.265视频解码从来都不是跑个软解就能轻松搞定的。CPU软解4K60的HEVC流哪怕是在Xeon上也得吃满好几个核放到Zynq这种嵌入式平台更是想都别想。而用纯FPGA逻辑去写H.265解码器那工程量属于毕业设计做到退休级别的——CAVLC/CABAC熵编码、运动补偿、去块滤波、SAO补偿任何一个模块拿出来都能让人掉一层头发。我自己在Zynq UltraScale EV系列FPGA上做完这套4K60 H.265解码 HDMI 2.0输出方案后最大的感受是方向选对了项目就成功了一半。EV系列最核心的价值就是把VCUVideo Coding Unit这个视频编解码硬核直接集成进了芯片里——它不是Vivado里的软核IP而是芯片里物理存在的硬核逻辑跟ARM核一样是固定电路。这意味着解码4K60 HEVC串流这件事芯片硬件自己就能干而且只消耗极少的LUT和FF资源。这篇东西不是翻译Xilinx手册也不是照抄UG1251是我实际操作中一点点趟出来的经验。从方案选型、VCU IP配置、HDMI TX链路搭建到PetaLinux里的驱动适配、GStreamer管线调优全程保姆级还原。你如果是刚接触EV系列的嵌入式工程师或者正准备上4K视频解码项目的同学这篇应该能帮你省下至少两周的摸索时间。1. 为什么是Zynq UltraScale EV而不是别的方案1.1 EV系列到底特殊在哪Zynq UltraScale家族分三个子系列CG低功耗通用、EG通用GPU、EV视频GPU。EV系列和EG系列最大的区别就是多了一个叫VCU的硬核视频编解码单元以及配套的VPU时钟、专用视频DDR端口。具体到芯片型号以最常见的XCZU7EV为例它内部包含四核ARM Cortex-A53PS侧应用处理器双核ARM Cortex-R5实时处理器Mali-400 GPUVCU硬核支持H.264/H.265编码和解码最大4K60PL侧可编程逻辑资源VCU这个硬核说白了就是一块完整的视频编解码SoC只不过以硬核IP的形式集成在芯片里通过AXI接口和中断跟PS侧交互。它不支持像软核那样自由改内部逻辑但换来的是极佳的性能功耗比——4K60 H.265解码VCU的典型功耗只有几瓦。提示如果你选的是CG系列比如XCZU3CG或者EG系列比如XCZU9EG那芯片里根本不存在VCU后面这一整套方案就无从谈起。选型的时候务必确认后缀是EV。1.2 4K60解码方案的横评对比做4K60 H.265解码业内大概有这几条路。我把它们放在一个表里方便你对照着选。方案优点缺点适合场景X86 CPU软解开发简单FFmpeg直接跑功耗高体积大嵌入式不现实服务器转码、PC播放NVIDIA Jetson硬解性能强CUDA生态好成本高视频输入输出接口定制性弱边缘AI视频分析纯FPGA逻辑解码定制化自由度高时延最低开发量巨大验证周期长高等人才难招特种行业、科研验证Zynq UltraScale EV VCU硬核解码零逻辑消耗PS/PL协同灵活视频接口定制性强VCU不支持AV1等新一代编码配置有一定学习成本广播级视频处理、医疗影像、机器视觉我当时的项目需求是能解码标准H.265 Main10 4K60流同时要输出HDMI 2.0给显示器还要预留一些FPGA逻辑做图像增强。X86软解功耗压不住、Jetson的HDMI输出配置不够灵活、纯逻辑开发周期不可控——最终选了EVVCU这条路线几乎是唯一解。1.3 VCU硬核到底干了多少活很多人第一次接触VCU都会问一个问题既然叫IP核为什么在Vivado里配置完、综合完资源报告里几乎看不到它占LUT答案很简单VCU不是由LUT构成的它是芯片里的ASIC硬核。你在Vivado里添加VCU IP做的事情其实只是把一个已经存在于芯片上的硬核通过IP封装把它暴露出来并接好到PS侧的接口和时钟。真正干活的电路早在芯片出厂时就固化在硅片上了。VCU本身支持的编解码能力我整理了一份参数速查这是配置IP时的基准编码H.264AVC/ H.265HEVC最高4K60解码H.264AVC/ H.265HEVC最高4K60支持8-bit和10-bitMain/Main10 Profile支持4:2:0色度采样多实例单VCU可同时跑编码解码或两个解码实例帧缓冲全部放在DDR里由内部的微码调度也就是说H.265最复杂的熵编码、变换量化、环路滤波、运动估计全部在VCU内部硬件完成。你要做的是喂给它压缩码流HEVC Annex B格式然后它把解码后的YUV帧写回DDR的指定地址。至于这个YUV怎么变成HDMI信号那就是PL侧和PS驱动的活了。2. 系统总体架构从码流到HDMI出画的完整链路2.1 端到端数据通路设计整个系统的数据流可以简化成下面这条单向管道H.265文件/网络流 ── PS侧Linux ── VCU硬核解码 ── DDR帧缓冲 ── PL侧VDMA读取 ── 视频时序生成 ── HDMI TX IP ── 物理PHY ── 显示器每一步拆开看第一步码流进入PS侧。文件流就用GStreamer的filesrc读取网络UDP/RTP流就用udpsrc接收RTSP就用rtspsrc。这一步是标准Linux操作没什么特殊。第二步VCU解码。GStreamer通过v4l2video*dec插件调用VCU驱动这是Kernel的V4L2 video node把压缩码流交给VCU。VCU固件通过firmware加载调度硬核完成解码解码后的YUV帧写回DDR。这里的DDR不是普通的内存区是专用的视频内存池需要在设备树里预留后面会详细讲。第三步VDMA搬运。这是整个链路里最关键的PL侧模块。VCU把帧写到DDR的某个物理地址VDMA按Video Timing ControllerVTC产生的时序节奏定频定帧地从DDR读帧数据通过AXI4-Stream接口送给下游。第四步HDMI TX输出。AXI4-Stream视频数据进入HDMI TX IP插入消隐、同步信号、数据岛InfoFrame加上音频辅助数据最终通过GTGigabit Transceiver高速串行通道输出TMDS信号。物理层如果需要驱动长线再加一颗HDMI retimer/redriver芯片。这个链路设计有个好处VCU和HDMI之间通过DDR解耦。VCU解码速率不稳定的抖动由帧缓冲来吸收HDMI输出则严格按像素时钟走两边互不阻塞。这就是为什么系统能稳定住4K60而不丢帧的核心原因。2.2 时钟和复位方案设计Zynq UltraScale EV的时钟树在VCU相关设计里有个专门的坑——VCU的时钟不是随便从PL侧给的它需要从PS侧的VIDEO_CLK引脚输入。通常我会在PS配置界面里把视频PLLVPLL使能输出一个专用的VCU时钟典型值是100MHz左右具体频率根据编解码格式和分辨率查UG1251里的表格。PL侧的视频链路时钟更直接HDMI像素时钟4K60 4:4:4 8bit需要594MHz4:4:2 8bit/10bit需要297MHz4:2:0 8bit/10bit是297MHzAXI4-Stream时钟一般取150MHz~300MHz取决于VDMA的带宽余量GT参考时钟HDMI TX IP的GT参考时钟通常用125MHz或150MHzIP内部会做PLL倍频注意事项时钟域交叉是这类设计最容易出问题的地方。VDMA读侧的AXI时钟150MHz和写侧的视频时序时钟297MHz是异步的中间靠FIFO缓冲和帧缓存跨时钟域。调时序约束时务必把VDMA的异步FIFO路径设成false path否则综合工具会报一堆乱七八糟的违例。2.3 DDR带宽计算与内存分配4K60视频系统对DDR带宽的需求超出很多人的直觉。我做一个粗略计算4K60 8bit 4:2:0的YUV帧每帧数据量 3840 × 2160 × 1.5字节 12,441,600字节 ≈ 11.9MB帧率60fps单向吞吐 11.9MB × 60 714MB/s但VCU解码时参考帧读写非常频繁H.265解码的内存带宽开销一般是输出带宽的3~5倍也就是VCU本身需要约2.1~3.5GB/s加上VDMA读帧到HDMI输出的714MB/s总带宽大约4~5GB/sZCU106板卡上的DDR4是64bit位宽频率2400MT/s理论带宽19.2GB/s实际效率按70%~80%算也有13~15GB/s所以带宽余量是够的。但注意VDMA的AXI端口和VCU的AXI端口如果都挤在同一个DDR控制器上会互相争抢带宽。我的做法是把DDR地址空间做个划分VCU使用一段连续的物理内存VDMA使用另一段两个端口尽量走不同的DDR slice降低冲突。计划内存分配如下Region大小用途0x0000_0000 - 0x0700_0000112MBLinux内核系统0x0700_0000 - 0x1000_0000144MBVCU帧缓冲池carveout0x1000_0000 - 0x1800_0000128MBVDMA/HDMI帧缓冲dma_heap0x1800_0000以上剩余应用程序2.4 PS和PL的分工边界这个系统的灵魂在于PS和PL各干各擅长的部分千万别混着来。PS侧负责的文件解析、网络协议栈、VCU驱动、GStreamer框架、显示管理DRM/KMS、系统控制。PL侧负责的视频时序生成VTC、帧缓冲搬运VDMA、像素格式封装AXI4-Stream、HDMI协议、TMDS物理层。我见过有人试图用PS侧GPIO模拟视频时序或者用软核在PL里跑GStreamer的——这种什么都想自己扛的思路在做4K60系统时一定会吃大亏。ARM核干好管理的事FPGA逻辑干好数据通路的事VCU干好解码的事各司其职才能稳住4K60。3. Vivado工程实操把VCU和HDMI TX搭起来3.1 环境准备与工程创建我个人长期用的版本组合是Vivado 2021.2 PetaLinux 2021.2 ZCU106评估板XCZU7EV。这套组合出来两年多了社区踩坑记录多稳定可靠不推荐一上来就追最新版。新建RTL工程在创建Block Design时器件型号务必确认是xczu7ev-ffvc1156-2-e这一类以ev结尾的型号。如果选成eg后面的VCU IP根本搜不到。工程创建过程中需要特别注意的一个设置是Board Part选择ZCU106。这样板载的HDMI接口、DDR4、GT引脚、时钟源等预定义信息都会自动带出来省掉大量手动约束的工作。3.2 VCU IP核参数怎么填在BD里添加VCU IP后双击打开配置界面需要认真看的参数有几组编码器/解码器实例配置我的场景只需要解码所以实例1设为Decoder实例2保持Disabled注意这里有个小坑即使你不用编码器VCU IP在Vivado里依然会生成编码器的部分逻辑接口只是为了保持总线接口一致性综合时不用管那些悬空引脚最大编解码能力选择4096×216060。这里选4K60后VCU内部会自动调整数据通路位宽和时钟要求如果你只需要1080p选1920×108060即可这样能省一点内部FIFO面积帧缓冲控制打开Frame Buffer相关选项确保使用内部分帧缓冲模式。VCU的帧缓冲存在于DDR但控制逻辑走内部路径输出的像素深度选择8-bit或10-bit。这里要注意10-bit解码Main10 profile需要VCU工作在10-bit模式输出YUV格式会是NV12_10LE之类的变体HDMI侧如果只能吃8bit还需要做一次色调映射/位深截断我建议前期先用8bit打通流程再考虑10bit时钟配置VCU IP的ACLKAXI时钟接150MHz建议至少100MHz以上VCU_PLL输入时钟vcu_pll_clk接来自PS的视频PLL输出配置为约100MHz提示VCU IP的时钟不是配完就完事了VCU固件vcu_fw.bin对时钟频率有严格要求。如果你的VCU时钟频率不在固件允许的范围内解码时会出现莫名奇妙的超时错误。所以时钟配置一定要查UG1251的时钟表别自己随便定。3.3 HDMI 2.0 TX子系统配置在BD中添加HDMI 2.0 Transmitter SubsystemIP。先把关键参数确定下来Video Interface选择AXI4-Stream这样可以直接对接VDMA的video output接口Max Bit Rate按需要的视频参数选。4K60 8bit 4:2:0或4:2:2最大TMDS时钟697MHz对应4K60 4:4:4深色模式的18Gbps链路这一步很关键直接决定了GT资源占用Number of ChannelsHDMI 2.0标准里有2个数据通道FRL模式下支持更多但常见板卡走TMDS模式就够。多数场景选2个数据通道1个时钟通道Include DDC必须开启。显示器EDID读取靠的就是DDC通道I2C没有EDIDHDMI链路无法完成信号协商Include HPD建议开启。HPDHot Plug Detect用于检测显示器连接和拔出接下来是GT引脚分配。在ZCU106上HDMI的GT引脚在FMC HPC0接口或板载专用接口上。Block Design会自动根据Board Part约束GTH位置和参考时钟。手动添加时重点检查参考时钟引脚是否选对了——通常需要一个专用参考时钟输入比如125MHz。HDMI TX IP配置完别忘了加上Video Timing ControllerVTC它负责产生视频同步时序。VTC的配置要和HDMI TX的模式深度绑定分辨率、刷新率、消隐参数、同步极性都要一一对应。这里最容易混淆的是H/V同步极性的设置HDMI规范里4K60的同步极性是负极性Active Low如果你在VTC里配反了显示器会直接黑屏或者画面撕裂。3.4 VDMA、VTC与数据通路连线数据通路按下面的结构在BD里连线顺序别搞反AXI VDMA (read channel) S_AXI - PS M_AXI_HPM0_FPD (控制通道) M_AXI - DDR (帧缓冲读) M_AXIS - Video Timing Controller - HDMI TX IP - GT - HDMI物理接口核心的寄存器配置流程是VTC产生VSYNC/HSYNC/DE等同步信号AXI4-Stream接口携带有效像素数据和DE信号HDMI TX IP根据DE和同步信号把数据打包成HDMI规范的TMDS字符流GT把TMDS字符流串行化发送连线时要特别关注VDMA的s2mm/mm2s中断信号记得都引出到PS的PL-PS中断端口上。后面Linux侧的VDMA驱动全靠这些中断来判断一帧传输完成。3.5 综合布局布线的注意事项整套设计做到综合布线阶段有件让我印象极深的事第一次layout完时序违例一大堆大部分集中在GT的TXUSRCLK2和HDMI TX IP的接口时序上。排查发现是GT参考时钟的网络没有设成PROPER约束综合工具把125MHz参考时钟当成一般时钟乱优化了一通。解决方式是set_property PACKAGE_PIN AC12 [get_ports hdmi_gt_refclk_p] set_property PACKAGE_PIN AD12 [get_ports hdmi_gt_refclk_n] set_property IOSTANDARD LVDS [get_ports hdmi_gt_refclk_p] set_property IOSTANDARD LVDS [get_ports hdmi_gt_refclk_n] create_clock -name hdmi_gt_refclk -period 8.000 [get_ports hdmi_gt_refclk_p]另外VCU相关的约束无需手动写Vivado会根据IP自动生成XDC。但建议检查一下VCU IP是否导出了vcu_pll_clk的正确约束有时候版本升级会漏掉这个。布局时如果布线压力大可以给HDMI TX IP加一个pblock把GT和HDMI逻辑约束在对应的GT Quad附近。虽然这一步不是必须的但对于4K60系统GT的位置直接影响参考时钟网络走线长度约束一下更保险。4. PetaLinux系统配置让Linux认出VCU和HDMI4.1 创建PetaLinux工程导出Vivado的XSA文件后用PetaLinux创建工程petalinux-create -t project --name vcu_hdmi_demo cd vcu_hdmi_demo petalinux-config --get-hw-description../vivado/vcu_hdmi_demo.xsa然后进入内核配置界面需要确认以下内核选项已开启CONFIG_VIDEO_XILINXXilinx视频驱动框架CONFIG_VIDEO_XILINX_VCUVCU解码器驱动CONFIG_DMABUF_HEAPSDMA缓冲区堆VDMA和VCU帧缓冲用CONFIG_DRM_XILINXXilinx DRM显示驱动CONFIG_XILINX_VIDEO_HDMIHDMI TX的DRM bridge驱动4.2 VCU固件与驱动配置VCU能工作的前提是固件加载成功。PetaLinux的rootfs里默认包含vcu_fw.bin和allegro_decode_fw.bin等文件但需要配置让系统启动时自动加载petalinux-config -c rootfs # 在 Filesystem Packages - lib - libvcu 里勾选 # xlnx-vcu 或 vcu-firmware 相关包版本不同名称会有差异启动后检查dmesg | grep vcu正常输出类似[ 3.246712] xlnx-vcu 0xa0040000.vcu: VCU cores present: encoder0 decoder1 [ 3.253531] xlnx-vcu 0xa0040000.vcu: bitrate: max32000 min1同时设备节点会出现/dev/video0这个video0就是VCU解码器实例。4.3 HDMI显示驱动配置HDMI TX链路通过DRM子系统枚举启动后查看/sys/class/drm/应该能看到card0-HDMI-A-1之类的显示接口。如果看不到多半是设备树里HDMI bridge节点没配对。在设备树中HDMI TX子系统的drm bridge节点通常会i2c总线关联DDC的EDID读取。ZCU106上EDID通过I2C读取确认对应的i2c节点正确常见问题是设备树里i2c总线号跟实际硬件对不上。配置完成后用modetest检查当前显示模式modetest -M xlnx能看到4K60的模式列表里出现类似3840x2160 60.00 3840 4080 4488 4576 2160 2164 2168 2227 flags: nhsync, nvsync这个模式就说明HDMI链路已经协商好了。4.4 设备树里预留内存的技巧VCU和VDMA都需要连续物理内存而且必须在内核启动阶段就预留这是最容易出错的地方之一。我通常在PetaLinux的设备树里用reserved-memory节点reserved-memory { #address-cells 2; #size-cells 2; ranges; vcu_fw_buf: vcu_fw_buf0xa0000000 { no-map; reg 0x0 0xa0000000 0x0 0x4000000; }; vcu_frame_buf: vcu_frame_buf0xa4000000 { no-map; reg 0x0 0xa4000000 0x0 0x9000000; }; vdma_buf: vdma_buf0xb0000000 { compatible shared-dma-pool; reusable; size 0x0 0x8000000; }; };用reusable而不是no-map让内核在内存压力大的时候可以使用这块区域VDMA按需分配就行。5. GStreamer解码管线从文件到HDMI出画5.1 GStreamer视频管线组成到了这一步硬件链路已经全部打通剩下的工作就是指挥数据流动了。GStreamer插件栈大致是这样videotestsrc/filesrc/udpsrc数据源qtdemux/matroskademux/h265parse解封装和码流解析v4l2video0decVCU解码器注意设备号根据实际系统可能video0/video1不等videoconvert可选像素格式转换kmssink输出到DRM/KMS显示最终走HDMI5.2 本地文件解码播放我先用本地文件把链路跑通。假设有一个H.265编码的MP4文件gst-launch-1.0 filesrc location/home/root/test_4k60.hevc \ ! h265parse \ ! video/x-h265,stream-formatbyte-stream \ ! v4l2video0dec \ ! video/x-raw,formatNV12,width3840,height2160 \ ! queue max-size-buffers3 \ ! kmssink这里有几个关键设计h265parse不能省略。VCU解码器需要标准的Annex B字节流格式而MP4里的H.265是Length-Prefixed格式每个NALU前有长度字段h265parse负责转换。格式协商里明确video/x-raw的format、width、height避免GStreamer在不同插件间做隐式转换隐式转换会引入不可控的CPU开销。queue max-size-buffers3队列缓冲调小目的是限制解码器和显示之间的帧数积压减少延迟。如果发现画面卡顿可以适当调大。运行后如果HDMI显示器上出现流畅的4K60画面处理器占用率应该极低——VCU硬解ARM核几乎不用干活。5.3 网络流低延迟解码要处理UDP/RTP传输的TS流gst-launch-1.0 udpsrc port5004 capsapplication/x-rtp,mediavideo,encoding-nameH265 \ ! rtpjitterbuffer latency200 \ ! rtph265depay \ ! h265parse \ ! v4l2video0dec \ ! video/x-raw,formatNV12 \ ! queue max-size-buffers2 \ ! kmssink这里用rtpjitterbuffer把网络抖动吸收掉latency200表示缓冲200ms的数据。如果是局域网实时监控场景latency可以降低到80~100ms代价是网络抖动时可能出现花屏。5.4 VCU解码性能验证用gst-launch自带的fpsdisplaysink或者直接观察VCU内部的帧率计数器可以验证是否真的达到了4K60gst-launch-1.0 filesrc location/home/root/test_4k60.hevc \ ! h265parse ! v4l2video0dec \ ! video/x-raw,formatNV12,width3840,height2160 \ ! fpsdisplaysink video-sinkfakesink text-overlayfalse输出里看到rendered: 60.0 fps就说明解码性能达标了。注意如果帧率只有50甚至30优先检查VCU的时钟配置是否正确其次检查DDR带宽是否被挤占不要一上来就怀疑VCU性能不够。我碰过一次帧率上不去查了半天发现是DDR controller的QoS配置把VCU的AXI端口优先级设低了。6. 常见问题排查与避坑经验6.1 显示器黑屏或无信号这是做HDMI输出时最磨人的问题。按下面的顺序查能快速定位检查项操作方法排查结果HPD信号确认显示器已连接测量HPD引脚电平低电平说明显示器未检测到EDID读取i2cdetect检查DDC I2C总线看不到EDID器件地址说明I2C没通DRM modemodetest查看显示模式列表无4K60模式说明时序配置有问题GT链路检查GT参考时钟是否锁定lock信号拉低说明参考时钟异常像素时钟用示波器量HDMI TX输出时钟无时钟输出说明IP配置有误有次我黑屏排查了很久最后发现是HDMI TX IP里的Default Color Space配置和显示器EDID要求的颜色空间不一致导致显示器握手失败。这种问题光看时序看不出必须结合EDID里的色彩属性逐一比对。6.2 VCU固件加载失败启动日志里出现类似[ 3.123456] xlnx-vcu 0xa0040000.vcu: failed to load firmware大概率是固件文件路径问题或者固件版本与驱动不兼容。确认顺序检查/lib/firmware下vcu_fw.bin存在且权限正确确认内核驱动版本Xilinx VCU驱动和固件版本配套确认VCU IP的AXI接口在设备树里地址和BD设计一致遇到过最隐蔽的一种情况VCU固件文件本身损坏了但文件系统检查没报错。重新从Xilinx官网对应版本下载覆盖一次就好了。6.3 画面花屏或出现绿条绝大多数情况是帧缓冲对齐问题。VCU输出的帧缓冲要求对齐到256字节而VDMA的每个scanline也要对齐。如果画面持续花屏先停掉管线用gst-launch把解码输出存成YUV文件gst-launch-1.0 filesrc location/home/root/test_4k60.hevc \ ! h265parse ! v4l2video0dec \ ! filesink locationout.yuv然后用FFmpeg在电脑上验证这个YUV文件ffplay -f rawvideo -pixel_format nv12 -video_size 3840x2160 -framerate 60 out.yuv如果文件本身花屏问题在VCU侧如果文件正常但HDMI输出花屏问题在VDMA/HDMI侧。这个二分定位法能省不少时间。6.4 色彩偏绿或偏紫色彩错误最经典的原因是YUV转RGB的系数不一致。HDMI TX IP内部做YUV到RGB转换时用的是BT.601还是BT.709系数直接决定色彩是否正常。4K60视频基本都按BT.709编码而HDMI规范里视频信号默认也是BT.709。如果配置不对整体画面会偏色尤其是肤色部分特别明显。解决办法在HDMI TX IP的配置界面里把Color Space Conversion选项明确设为BT.709。如果画面依然偏色用显示器自带的输入源信息很多显示器可以按信息键查看色深和色彩空间确认当前HDMI链路跑的是什么格式。6.5 音画不同步VCU只处理视频音频要么通过PS侧I2S/SPDIF输出要么复用到HDMI里。做音画同步时时钟源是两个系统一定会有偏差。我的做法是把音频的时钟基准锁定到HDMI TX的像素时钟上用硬件方式让音频采样率跟随视频帧率。具体到实现Xilinx HDMI TX IP支持从外部接收音频时钟把音频的I2S位时钟与HDMI像素时钟绑定在一起这样音画时钟同源同步问题从根本上消除。7. 最后的几点心得做完这个项目我最大的体会是Zynq UltraScale EV这套系统真正的门槛不在FPGA逻辑设计而在软硬协同这四个字上。VCU硬核把最重的视频解码吃掉了但你要懂Linux驱动、懂DMA内存管理、懂GStreamer的buffer流转、懂DRM显示框架才能把硬件的威力完整释放出来。这不是一个纯粹的FPGA工程师能干好的活也不是一个纯粹的上层应用工程师能干好的活——它是一个系统工程。再分享一个小技巧调试这种软硬结合的系统一定要学会分段打点。先用GStreamer的fakesink把解码段单独验证再用videotestsrc把HDMI输出段单独验证。两段各自都通了再拼起来。如果一上来就端到端联调出了问题根本不知道是该改RTL还是该改GStreamer管线。这套方案在我手头已经稳定跑了大半年每天连续8小时解码4K60 H.265流没有掉过链子。后续如果想扩展VCU还支持编码实例可以在一颗芯片上做转码器也可以把PL侧的资源用来跑AI推理DPU核这就是后话了。
返回列表