简介:面向具备一定Linux与嵌入式基础的研发人员,这份PDF围绕全志V3S芯片梳理音视频开发的完整链路,从交叉编译环境搭建、U-boot与Linux内核配置、Buildroot根文件系统制作,到TFT屏幕、按键、声卡、摄像头等外设驱动,再到SDL2与QT5的移植及音乐播放器、图片显示、视频播放与摄像头模块的界面实现,帮助读者打通从底层驱动到上层GUI的实践路径。资源包内为1个PDF文件,约12.26MB,内容按章节顺序组织,便于对照源码与配置逐步推进。目前已有329人学习,适合希望系统掌握V3S平台音视频开发流程、补齐驱动移植与QT5应用开发经验的工程师参考。
1. 从一块 V3S 板子到能跑 QT 的音视频终端:这份 PDF 到底值不值得拆
手上有一块全志 V3S 的板子,屏幕、声卡、摄像头都焊上去了,结果卡在“内核起来了但网口不通”“buildroot 编出来的根文件系统一挂就 panic”“QT 程序交叉编译过去一跑就报找不到显示设备”——这类问题在嵌入式音视频开发里几乎是必经之路。这份《全志v3s音视频开发.pdf》走的是完整链路:从交叉编译器、U-boot、Linux 5.4.31 内核、buildroot 根文件系统,一路做到 TFT 屏、按键、声卡、摄像头驱动,再移植 SDL2 和 QT5,最后用 QT5 写音乐播放器、图片浏览、视频播放和摄像头预览。它适合已经会用 Linux、但没把“从零到能跑音视频界面”这条链走通过一次的工程师,也适合拿它当一份可对照的检查清单——每一步该改哪个文件、该开哪个 config,文档里都留了痕迹。
2. 交叉编译环境与源码清单:先把工具链钉死再谈别的
嵌入式音视频项目翻车,十次里有六次不是代码问题,是工具链和源码版本对不上。这份文档开头就把源码清单列全了,这一点比很多只给半截的教程靠谱。先把“要准备什么”和“为什么是这些版本”讲清楚,后面每一步才有依据。
2.1 源码与工具清单逐项对照
文档给出的物料大致是这几类,我按用途重新归了一下,方便你对着下载:
| 类别 | 文件 | 用途 | 版本约束说明 |
|---|---|---|---|
| 交叉编译器 | gcc-linaro-6.5.0-2018.12-x86_64_arm-linux-gnueabihf | 编译 U-boot、内核、应用 | 6.5 系列,glibc,硬浮点 |
| Bootloader | u-boot-v3s-current | 引导内核、网络调试 | 需支持 sun8i GMAC |
| 内核 | linux-5.4.31 | 系统内核 | 文档明确用 5.4.31 |
| 根文件系统 | buildroot-2021.02.1 | 制作 rootfs | 与内核头文件版本要对齐 |
| 音频库 | alsa-lib-1.2.2 / alsa-utils-1.2.2 | 声卡控制与测试 | 与内核 ALSA 版本匹配 |
| 图形界面 | t-opensource-linux-x64-5.14.2.run | QT5 开发环境 | 宿主机 x64 安装 |
这里有个容易被忽略的点:交叉编译器选的是arm-linux-gnueabihf,hf是硬浮点,意味着目标板的 ABI 必须是 EABIhf、浮点策略 VFPv3。后面 buildroot 里如果 Target ABI 选成 EABI(软浮点),编出来的库和编译器产出的对象文件 ABI 不一致,链接阶段就会冒出一堆uses VFP register arguments, output does not之类的报错。所以工具链一旦定下,buildroot 的 Target options 必须跟着它走,不能各选各的。
2.2 目录规划与编译器落地
文档建议在家目录建一个项目根目录,再分driver、tools、kernel三个子目录。这个习惯值得抄:应用、工具链和 bootloader、内核源码物理隔离,后面make clean、换内核版本都不会互相污染。落地命令如下:
# 建立项目工作区,三个子目录各司其职 mkdir -p ~/qz/{driver,tools,kernel} # 交叉编译器解压到 tools 下 cd ~/qz/tools tar -xvf gcc-linaro-6.5.0-2018.12-x86_64_arm-linux-gnueabihf.tar.xz # 进入 bin 目录拿到真实绝对路径,后面写进 PATH cd gcc-linaro-6.5.0-2018.12-x86_64_arm-linux-gnueabihf/bin pwdpwd输出的路径就是你要写进环境变量的路径,每个人家目录不同,别照抄文档里的示例路径。拿到路径后写进~/.bashrc:
# 追加到 ~/.bashrc 末尾,路径替换成上一步 pwd 的结果 export PATH=$PATH:/home/<你的用户名>/qz/tools/gcc-linaro-6.5.0-2018.12-x86_64_arm-linux-gnueabihf/bin # 让配置立即生效 source ~/.bashrc # 验证:能打印版本号才算成功 arm-linux-gnueabihf-gcc -v参数说明:export PATH是把编译器 bin 目录前置或后置到搜索路径,文档用的是后置$PATH:追加,问题不大,但如果系统里已有同名工具,建议前置成export PATH=<路径>:$PATH,避免被旧版本截胡。source ~/.bashrc只对当前终端生效,新开终端会自动读取。验证那一步别省,arm-linux-gnueabihf-gcc -v打不出东西,后面所有make都会以“command not found”收场。
2.3 为什么先配工具链再动 U-boot
顺序不是随便排的。U-boot 的make命令里要显式传CROSS_COMPILE=arm-linux-gnueabihf-,内核 Makefile 里也要写CROSS_COMPILE ?= arm-linux-gnueabihf-,buildroot 里还要填 Toolchain path 和 prefix。这三处引用的都是同一个编译器,先把它装好、路径确认,后面三处填的是同一个字符串,出错概率最低。我见过有人 U-boot 用一套、内核用另一套,结果内核解压后启动到一半挂死,查了两天才发现是编译器版本差异导致的指令集问题——这种坑,靠“先钉死工具链”就能绕开。
3. U-boot 与内核移植:网口不通多半是设备树没配对
这一章是整份文档里技术密度最高的部分,也是实际最容易卡住的地方。V3S 的网口用的是内部 PHY,U-boot 和内核两边的设备树写法还不一样,文档把两套都给了,这点很关键。
3.1 U-boot 编译与 GMAC 设备树配置
U-boot 解压进tools后,先做 defconfig 初始化:
cd ~/qz/tools/u-boot-v3s-current # 用 LicheePi_Zero 的默认配置初始化 make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- LicheePi_Zero_defconfig看到configuration written to .config才算初始化成功。接着改设备树,这是网口能不能通的核心。在arch/arm/dts/sun8i-v3s-licheepi-zero.dts的 aliases 里加ethernet0 = &emac;,文件末尾补上 emac 节点,关键几行是phy-mode = "mii"、allwinner,use-internal-phy、status = "okay",以及phy0子节点的reg = <1>。然后在sun8i-v3s.dtsi的 soc 节点里补emac_rgmii_pins的引脚复用和emac: ethernet@1c30000控制器节点。
引脚列表里 PD0 到 PD17 这一串不是随便写的,V3S 的 EMAC 引脚就固定在这些 PD 口上,少写一个,PHY 初始化就会失败。allwinner,drive = <SUN4I_PINCTRL_40_MA>是驱动电流,pull = <SUN4I_PINCTRL_NO_PULL>是不上拉,这两个值跟硬件设计相关,照文档给的值走一般没问题。
配置菜单里要确认 GMAC 驱动被编进去:
make ARCH=arm menuconfig # Device Drivers -> Network device support -> Ethernet driver support # 选中 <*> Allwinner sun8i GMAC support然后编译并烧录:
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- # 烧到 SD 卡,/dev/sdX 换成你实际的卡设备,seek=8 是 sunxi 的固定偏移 sudo dd if=u-boot-sunxi-with-spl.bin of=/dev/sdX bs=1024 seek=8seek=8这个偏移是 sunxi 平台 SPL 的约定位置,写错位置板子直接不启动。of=后面的设备名一定要用lsblk确认,写错盘符的后果不用多说。
3.2 U-boot 下验证网络
烧录后进串口,配好网络参数再 ping 宿主机:
# U-boot 命令行里逐条设置 setenv ipaddr 192.168.10.202 # 开发板地址 setenv gatewayip 192.168.10.1 # 网关 setenv serverip 192.168.10.201 # 宿主机(Ubuntu)地址 setenv netmask 255.255.255.0 saveenv # 验证链路 ping 192.168.10.201看到host 192.168.10.201 is alive说明 U-boot 阶段网口已经通了。这一步通了,后面用 TFTP 下内核、用 NFS 挂根文件系统才有基础。如果 ping 不通,先回头查设备树里phy-mode是不是mii、reg = <1>对不对,再看硬件上 PHY 的供电和复位引脚。
3.3 内核编译与 NFS 根文件系统支持
内核解压进kernel目录后,先改 Makefile 里的架构和编译器:
# linux-5.4.31/Makefile 中确认或补充 ARCH ?= arm CROSS_COMPILE ?= arm-linux-gnueabihf-然后引入 sunxi 默认配置并进菜单开网络和 NFS:
make sunxi_defconfig make ARCH=arm menuconfig菜单里要开的项比较多,按文档给的路径走:Device Drivers -> Network device support -> Ethernet driver support下选中Allwinner sun8i GMAC support;Networking support -> Networking options下选中NFS client support及 v2/v3/v4,以及Root file system on NFS。NFS 根文件系统是调试阶段最省事的方式,改应用不用反复烧卡,这一点对音视频这种要频繁调界面的场景尤其重要。
内核设备树和 U-boot 那套不一样,sun8i-v3s-licheepi-zero.dts里 emac 节点用phy-handle = <&int_mii_phy>,sun8i-v3s.dtsi里要补syscon、mdio、mdio_mux和int_mii_phy的完整层级。文档把这段贴全了,照抄时注意缩进和括号闭合,dts 编译报错往往就是少个分号或括号。
编译并拷贝到 TFTP 目录:
# 生成 uImage,LOADADDR 是 sunxi 的加载地址 make ARCH=arm -j12 uImage LOADADDR=0x41000040 # 编译设备树 make ARCH=arm dtbs # 拷到 tftp 根目录供 U-boot 下载 cp arch/arm/boot/uImage /tftpboot/ cp arch/arm/boot/dts/sun8i-v3s-licheepi-zero.dtb /tftpboot/LOADADDR=0x41000040这个地址是 V3S 上 uImage 的约定加载地址,写错内核解压会失败。-j12按你机器核数调,别盲目拉高。
4. buildroot 根文件系统:ABI 和工具链路径是两道坎
根文件系统这一章,文档给的是 buildroot 2021.02.1 的完整配置路径。buildroot 的好处是把 alsa-lib、alsa-utils、SDL2、QT5 这些依赖一起编进去,省得手工交叉编译一堆库。但它的配置项多,两个地方最容易翻车:Target ABI 和外部工具链路径。
4.1 Target options 与工具链对齐
进 buildroot 目录后make ARCH=arm menuconfig,Target options 里按文档配:
- Target Architecture 选
ARM (little endian) - Target Binary Format 选
ELF - Target Architecture Variant 选
cortex-A7 - Target ABI 选
EABIhf - Floating point strategy 选
VFPv3 - ARM instruction set 选
ARM
EABIhf和VFPv3必须跟交叉编译器的硬浮点 ABI 一致,这是前面反复强调的那条线。V3S 是 Cortex-A7 核,带 NEON 和 VFPv3,选错浮点策略,编出来的 QT 库在板子上跑起来会直接 illegal instruction。
4.2 外部工具链配置
Toolchain 菜单里选External toolchain,再选Custom toolchain,origin 选Pre-installed toolchain,然后填三样东西:
Toolchain path: /home/<用户名>/qz/tools/gcc-linaro-6.5.0-2018.12-x86_64_arm-linux-gnueabihf Toolchain prefix: arm-linux-gnueabihf External toolchain gcc version: 6.x External toolchain kernel headers series: 5.4.x External toolchain C library: glibc/eglibc路径要填到编译器根目录,不是 bin 目录,这点跟PATH里填的不一样,很多人在这里填错。prefix 不带结尾的横杠,buildroot 会自己拼。gcc 版本和内核头文件版本要跟实际编译器对得上,选错了 buildroot 会在配置阶段就报错退出。下面几个勾选项SSP support、RPC support、C++ support、Enable MMU support按文档全勾上,QT5 依赖 C++ 支持,不勾编不出 QT。
4.3 把音视频依赖一起编进去
根文件系统里要跑 ALSA 和 QT,buildroot 的 Package 菜单里得把对应包选上。常见做法是在Target packages -> Audio and video applications下选alsa-utils,在Libraries -> Audio/Sound下选alsa-lib,图形库那边选SDL2和QT5。文档正文里 alsa-lib 和 alsa-utils 是单独列在源码清单里的,说明作者也走过手工交叉编译这条路;用 buildroot 的话可以省掉手工步骤,但版本要跟内核 ALSA 对得上,1.2.2 这个版本跟 5.4 内核是匹配的。
编完make之后,output/images/下会出rootfs.tar或rootfs.ext4,挂到 NFS 或烧进分区都行。第一次编建议先只选最小系统跑通启动,再逐步加 ALSA、SDL2、QT5,一次全选编出来的镜像出了问题很难定位是哪一层。
5. 避坑排查:这几处翻车点我替你踩过了
5.1 内核启动后网口 still not alive
现象:U-boot 阶段 ping 得通,内核起来后ifconfig看不到 eth0,或者看到了但 ping 不通。原因多半是内核设备树和 U-boot 设备树写法混用了——U-boot 用allwinner,use-internal-phy,内核用phy-handle = <&int_mii_phy>加mdio_mux层级,两套不能互换。解决:确认sun8i-v3s.dtsi里syscon、mdio、mdio_mux、int_mii_phy四层节点齐全,emac节点status = "okay",重新make dtbs并替换板上的 dtb。
5.2 buildroot 编译报 toolchain 路径无效
现象:make一开始就报找不到编译器或Toolchain path does not exist。原因:Toolchain path 填成了 bin 目录,或者路径里有空格、软链接没解析。解决:填编译器根目录(含bin、lib的那一层),用绝对路径,别用~,buildroot 不展开波浪号。
5.3 QT 程序在板子上报找不到显示设备
现象:交叉编译好的 QT 程序拷到板子上运行,报This application failed to start because no Qt platform plugin could be initialized。原因:QT5 的 platform plugin(如libqlinuxfb.so或libqeglfs.so)没编进根文件系统,或者QT_QPA_PLATFORM环境变量没设。解决:buildroot 里确认 QT5 的 platform 插件被选中,运行时设export QT_QPA_PLATFORM=linuxfb,并确认 framebuffer 设备/dev/fb0存在。
5.4 声卡有设备节点但没声音
现象:/dev/snd/下有 pcm 节点,aplay也能跑,但喇叭没声。原因:V3S 的音频 codec 需要正确的引脚复用和 mixer 配置,默认音量可能是静音或 0。解决:用amixer把对应控件 unmute 并调高音量,确认设备树里 codec 节点status = "okay",aplay -l能看到声卡才算链路通。
5.5 SD 卡烧录后板子不启动
现象:dd写完插卡上电,串口无输出。原因:seek=8偏移写错,或者of=写到了分区设备(如/dev/sdX1)而不是整盘。解决:用lsblk确认整盘设备名,dd目标必须是整盘不是分区,seek=8保持不变,写完sync再拔卡。
6. 从能启动到能播视频:SDL2 与 QT5 的衔接技巧
把系统跑起来只是及格线,这份文档真正的价值在后半段——SDL2 和 QT5 的移植,以及用 QT5 做音乐播放器、图片显示、视频播放和摄像头预览。这里分享一个我反复验证过的衔接思路:SDL2 负责底层音视频输出,QT5 负责界面和事件循环,两者不要抢同一个 framebuffer。
具体做法是,QT5 用linuxfb平台插件接管/dev/fb0做界面渲染,SDL2 在 QT 的窗口句柄里做视频层渲染,音频走 ALSA 直出。验证顺序建议这样走:先用alsa-utils的aplay确认声卡能出声,再用一个最小 SDL2 程序确认能打开 fb 和音频设备,最后才把 QT5 界面叠上去。每层单独验证,出问题能立刻定位是哪一层。
交叉编译 QT5 应用时,qmake要用 buildroot 产出的那份,不是宿主机装的 x64 版。在.pro文件里确认QT += multimedia multimediawidgets,链接时库路径指向 buildroot 的output/staging/usr/lib。摄像头模块常见做法是用 V4L2 取流,经 FFmpeg 解码后送 SDL2 纹理或 QT 的QVideoWidget,文档里提到的 FFmpeg 解码就是干这个的。
有个参数值得单独说:视频播放的帧缓冲如果直接写 fb0,会和 QT 界面撕裂,正确做法是让 QT 管理窗口,视频帧通过QImage转纹理后由 QT 合成。我一般会在播放器初始化时打印一次QT_QPA_PLATFORM和 fb 的bits_per_pixel,确认是 16 位还是 32 位,颜色格式对不上会出现花屏或偏色——这种问题不看日志纯靠猜,能耗掉一整天。
从那以后我每次搭这类音视频板子,都强制按“工具链版本 → U-boot 网口 → 内核 NFS 启动 → buildroot 最小系统 → ALSA → SDL2 → QT5”这个顺序逐层验证,任何一层没过就不往上叠。这份 PDF 的价值就在于它把这条链的每一步该改哪个文件、该开哪个 config 都留了记录,照着走一遍,比零散搜帖子省太多时间。希望帮到你。
本文还有配套的精品资源,点击获取