简介《全志v3s音视频开发.pdf》面向具备Linux与嵌入式基础的研发人员及音视频方向工程师围绕全志V3S平台梳理从系统环境搭建到音视频应用落地的完整开发链路。资源包共1个PDF文件大小约12.26MB便于集中查阅与按章节实践。内容覆盖源码准备、交叉编译器配置、U-Boot与Linux 5.4.31内核配置、Buildroot根文件系统制作并逐步展开2.4寸TFT-LED屏、按键、声卡、摄像头等外设驱动配置。后半部分重点讲解SDL2与Qt5的移植方法以及基于Qt5设计音乐播放器、图片显示、视频播放器和摄像头模块结合FFmpeg理解音视频解码处理。文中保留设备树修改、menuconfig选项和编译命令等关键细节适合按顺序搭建实验环境、对照配置外设并完成GUI综合项目。已有329人学习。1. 全志 V3S 音视频开发卡住人的从来不是 Qt 代码全志 V3S 音视频开发这套环境我第一次搭的时候在交叉编译器和设备树上耗了整整两天。板子能上电串口也有输出但一敲make就是arm-linux-gnueabihf-gcc: not found再往后以太网 PHY 又认不出来ping 不通宿主机TFTP 拉不到内核整条链路就卡死在第一步。这套环境一共六份源码buildroot-2021.02.1、gcc-linaro-6.5.0-2018.12 交叉编译器、linux-5.4.31、u-boot-v3s-current、alsa-lib/alsa-utils 1.2.2以及宿主机上的 Qt 5.14.2。它们之间版本互相咬合错一个后面全是连锁反应。适合手上已经有 V3S 板子、想从零把音视频界面跑起来的人也适合之前装到一半放弃、想回来把环境补完整的人。2. 源码与交叉编译器gcc-linaro-6.5.0 的路径不能凭感觉写2.1 六份源码先摆齐版本对不上就别急着解压先把要用的东西列成一张表贴在自己项目的 README 里比记在脑子里靠谱。版本之间有明确的对应关系内核是 5.4.31交叉编译器就得选内核头文件系列能对上的 6.5-2018.12buildroot 2021.02.1 的 Toolchain 选项里正好能选5.4.x的头文件系列选早了或选晚了后面编 Qt 时都会以各种奇怪的方式报错。文件版本用途放置位置buildroot-2021.02.1.tar.xz2021.02.1生成根文件系统~/qz/toolsgcc-linaro-6.5.0-2018.12-x86_64_arm-linux-gnueabihf.tar.xz6.5.0-2018.12交叉编译器~/qz/toolslinux-5.4.31.tar.gz5.4.31内核~/qz/kernelu-boot-v3s-current.zipcurrent引导程序~/qz/toolsalsa-lib-1.2.2.tar.bz21.2.2音频库后续交叉编译alsa-utils-1.2.2.tar.bz21.2.2aplay/amixer 等工具后续交叉编译qt-opensource-linux-x64-5.14.2.run5.14.2宿主机 Qt Creator宿主机安装宿主机的编译依赖要一并装上常见做法是提前装齐省得编到一半再回来补sudo apt update sudo apt install -y build-essential bison flex libssl-dev \ libncurses5-dev device-tree-compiler unzip bc \ lib32z1 lib32stdc6 rsyncbison、flex是 U-boot 和内核 Kconfig 解析要用的libssl-dev影响内核模块签名相关配置device-tree-compiler提供dtc编译 dtb 时会调用lib32z1、lib32stdc6是跑 32 位工具链辅助程序时要的。少装一个报错信息通常不会直接告诉你缺的是哪个包。2.2 目录约定好后面所有路径都好写交叉编译环境的路径会出现在~/.bashrc、内核 Makefile、buildroot 的 Toolchain path 三个地方目录不统一改起来一定漏。我习惯在用户目录下建一套固定结构mkdir -p ~/qz/driver # 自己写的应用程序 mkdir -p ~/qz/tools # U-boot、交叉编译器、buildroot 压缩包 mkdir -p ~/qz/kernel # 内核源码 cd ~/qz/tools tar -xvf gcc-linaro-6.5.0-2018.12-x86_64_arm-linux-gnueabihf.tar.xzx86_64表示这是跑在 64 位宿主机上的版本arm-linux-gnueabihf表示产出的是 ARM 架构、Linux 系统、gnueabihf硬浮点 ABI 的可执行程序。V3S 是 Cortex-A7 带 VFPv3 硬浮点单元所以后面所有配置里浮点策略都要选VFPv3选软浮点会出现程序能跑但音视频解码慢到没法用的情况。解压完成后~/qz/tools下会多出一个长名字目录这就是工具链的根。后面一律以$HOME/qz/tools/gcc-linaro-6.5.0-2018.12-x86_64_arm-linux-gnueabihf表示不要从别人文章里抄带用户名的绝对路径。2.3 拿到 pwd 输出环境变量只能照它写很多人环境变量配错就是因为抄了教程里的/home/xxx/...。正确做法是进到 bin 目录让pwd告诉你真实路径cd ~/qz/tools/gcc-linaro-6.5.0-2018.12-x86_64_arm-linux-gnueabihf/bin pwd # 输出示例/home/dev/qz/tools/gcc-linaro-6.5.0-2018.12-x86_64_arm-linux-gnueabihf/bin拿到这一行之后再往~/.bashrc末尾追加vim ~/.bashrc # 文件末尾追加路径换成上一步 pwd 的真实输出 export PATH$PATH:/home/dev/qz/tools/gcc-linaro-6.5.0-2018.12-x86_64_arm-linux-gnueabihf/bin source ~/.bashrcexport PATH$PATH:...是把新路径追加到原有 PATH 后面原命令一个不丢。如果你把$PATH:写掉了变成export PATH/xxx/bin当前终端里ls、vim会全部失效只能重开一个终端。source ~/.bashrc是让改动立刻在当前 shell 生效不 source 就得关掉终端重开。改完立刻自检which arm-linux-gnueabihf-gcc arm-linux-gnueabihf-gcc -v要看到两样东西才算过which指到~/qz/tools/...下的 bin 目录-v输出里带gcc version 6.5.0 201812xx以及--with-archarmv7-a --with-fpuvfpv3-d16这类字样。如果-v显示的是宿主机自带的 gcc说明 PATH 没生效或者写错了。2.4 编一个 hello 验证工具链真的产出 ARM 程序环境变量能查到不等于能编译这一步别省cd ~/qz/driver cat hello.c EOF #include stdio.h int main(void) { puts(v3s toolchain ok); return 0; } EOF arm-linux-gnueabihf-gcc hello.c -o hello file hellofile的输出应该是ELF 32-bit LSB executable, ARM, EABI5 version 1, dynamically linked。如果看到x86-64说明调用到了宿主机 gcc回头查 PATH 顺序如果提示找不到libc.so一般是没有加-static后面往板子上跑时用hello的静态版本验证更省事arm-linux-gnueabihf-gcc -static hello.c -o hello_static-static把 glibc 一起链进可执行文件板子上根文件系统还没做好的阶段静态程序是最省心的验证手段。动态链接版本依赖目标板的libc根文件系统做好之后再验证不迟。3. U-boot 与内核 5.4.31一份设备树决定以太网能不能用3.1 U-boot 解压并跑一遍 defconfigcd ~/qz/tools unzip u-boot-v3s-current.zip cd u-boot-v3s-current make ARCHarm CROSS_COMPILEarm-linux-gnueabihf- LicheePi_Zero_defconfig三个参数各有分工ARCHarm告诉构建系统按 ARM 架构挑源码目录CROSS_COMPILEarm-linux-gnueabihf-指定工具链前缀末尾那个短横不能漏因为构建规则是$(CROSS_COMPILE)gcc拼出来的少一个短横就会去找一个叫arm-linux-gnueabihf的可执行文件LicheePi_Zero_defconfig是这块板子的默认配置模板。终端打出# configuration written to .config才算成功其它输出都可以先放着。3.2 设备树里补 emac两处都要改U-boot 默认配置里没把以太网打开得自己补。第一处在板级 dts/* arch/arm/dts/sun8i-v3s-licheepi-zero.dts */ aliases { serial0 uart0; ethernet0 emac; /* 让 U-boot 的 net 子系统能找到这块网卡 */ }; /* 文件末尾追加 */ emac { phy phy0; phy-mode mii; allwinner,use-internal-phy; /* 使用芯片内部 PHY不走外部 PHY 芯片 */ allwinner,leds-active-low; status okay; phy0: ethernet-phy0 { reg 1; /* 内部 PHY 的 MDIO 地址是 1不是 0 */ }; };第二处在arch/arm/dts/sun8i-v3s.dtsi补 pinctrl 引脚组和 emac 控制器节点/* soc 节点内增加引脚复用 */ emac_rgmii_pins: emac00 { allwinner,pins PD0, PD1, PD2, PD3, PD4, PD5, PD7, PD8, PD9, PD10, PD12, PD13, PD15, PD16, PD17; allwinner,function emac; allwinner,drive SUN4I_PINCTRL_40_MA; allwinner,pull SUN4I_PINCTRL_NO_PULL; }; emac: ethernet1c30000 { compatible allwinner,sun8i-h3-emac; reg 0x01c30000 0x104, 0x01c00030 0x4; reg-names emac, syscon; interrupts GIC_SPI 82 IRQ_TYPE_LEVEL_HIGH; resets ccu RST_BUS_EMAC, ccu RST_BUS_EPHY; reset-names ahb, ephy; clocks ccu CLK_BUS_EMAC, ccu CLK_BUS_EPHY; clock-names ahb, ephy; status disabled; };phy-mode mii是最关键的一项写成rgmii会出现链路协商不上、ping全是 timeout 的现象。allwinner,use-internal-phy是 Allwinner 这套绑定的私有属性别拿掉。reg 1对应内部 PHY 的 MDIO 地址写成 0 的话 U-boot 会去总线上扫一个不存在的设备。3.3 menuconfig 打开 sun8i GMAC 驱动make ARCHarm menuconfig路径是Device Drivers→Network device support→Ethernet driver support→ 勾上*Allwinner sun8i GMAC support。星号是编进内核镜像M是编成模块——U-boot 阶段没有模块加载机制必须选星号。3.4 编译并用 dd 烧到 SD 卡make ARCHarm CROSS_COMPILEarm-linux-gnueabihf- lsblk # 先确认哪块盘是 SD 卡务必看清楚 sudo dd ifu-boot-sunxi-with-spl.bin of/dev/sdc bs1024 seek8 syncseek8表示从设备第 8KB 处开始写这是 sunxi 平台 SPL 的固定位置约定改了板子起不来。/dev/sdc千万别凭记忆写lsblk看清楚容量和挂载点写错盘号的后果不用多说。sync是保证缓冲区落盘拔卡前执行一下。3.5 串口里配网络ping 通宿主机才算过接上串口上电进 U-boot 命令行把四个网络变量配齐 setenv ipaddr 192.168.10.202 # 开发板自身地址 setenv gatewayip 192.168.10.1 # 网关 setenv serverip 192.168.10.201 # 宿主机TFTP/NFS 服务器地址 setenv netmask 255.255.255.0 saveenv ping 192.168.10.201saveenv会把变量写进 MMC 的环境分区下次上电还在。ping成功时输出是Using ethernet1c30000 device加host 192.168.10.201 is alive如果只打印No ethernet found说明 3.2 和 3.3 里至少有一处没生效回上一节逐条对。宿主机侧要有对应配置网线和板子直连或者同一交换机下宿主机192.168.10.201这个地址要真的配在网卡上防火墙别拦 ICMP。3.6 内核 Makefile 改架构与编译器cd ~/qz/kernel tar -xvf linux-5.4.31.tar.gz cd linux-5.4.31 vim Makefile找到这两行没有就补上ARCH ? arm CROSS_COMPILE ? arm-linux-gnueabihf-?的意思是“变量没定义才赋值”所以更稳妥的习惯是不改 Makefile在命令行传参make ARCHarm CROSS_COMPILEarm-linux-gnueabihf- ...。改 Makefile 的好处是后面敲命令短坏处是万一哪天要编 x86 版本会莫名其妙出问题。两种都行别混着用。3.7 sunxi_defconfig 之后补 GMAC 和 NFSmake ARCHarm CROSS_COMPILEarm-linux-gnueabihf- sunxi_defconfig make ARCHarm menuconfigdefault 配置里网卡和 NFS 都不全逐项确认Device Drivers→Network device support→Ethernet driver support→*Allwinner sun8i GMAC support同时*Generic driver for DWMACNetworking support→Networking options→*NFS client support勾上 version 2 / 3 / 4[*]Root file system on NFSNFS 根文件系统是调试阶段最省时间的做法改一个应用重新编不用重新烧卡重启板子就生效。等界面调试稳定了再考虑把根文件系统固化到 SD 卡或者 SPI Flash。3.8 内核设备树写法与 U-boot 不一样这是最容易翻车的地方U-boot 用phy phy0内核 5.4 用的是phy-handle加 mdio-mux 的组合两种写法不能互相抄。板级 dts 里/* arch/arm/boot/dts/sun8i-v3s-licheepi-zero.dts */ aliases { serial0 uart0; ethernet0 emac; }; /* 文件末尾追加 */ emac { phy-handle int_mii_phy; phy-mode mii; allwinner,leds-active-low; status okay; };sun8i-v3s.dtsi里补 emac、mdio、mdio-mux 和 sysconemac: ethernet1c30000 { compatible allwinner,sun8i-v3s-emac; syscon syscon; reg 0x01c30000 0x10000; interrupts GIC_SPI 82 IRQ_TYPE_LEVEL_HIGH; interrupt-names macirq; resets ccu RST_BUS_EMAC; reset-names stmmaceth; clocks ccu CLK_BUS_EMAC; clock-names stmmaceth; phy-handle int_mii_phy; phy-mode mii; status disabled; mdio: mdio { compatible snps,dwmac-mdio; }; mdio_mux: mdio-mux { compatible allwinner,sun8i-h3-mdio-mux; mdio-parent-bus mdio; internal_mdio: mdio1 { compatible allwinner,sun8i-h3-mdio-internal; reg 1; int_mii_phy: ethernet-phy1 { compatible ethernet-phy-ieee802.3-c22; reg 1; clocks ccu CLK_BUS_EPHY; resets ccu RST_BUS_EPHY; }; }; }; };mdio-mux是这一版内核挂内部 PHY 的必需节点缺了它启动日志里会出现no phy at addr -1之类的字样eth0怎么也起不来。int_mii_phy的reg 1和 U-boot 里的phy0: ethernet-phy0 { reg 1; }是同一个地址两边必须一致。3.9 编 uImage 与 dtb拷进 tftp 目录make ARCHarm CROSS_COMPILEarm-linux-gnueabihf- -j12 uImage LOADADDR0x41000040 make ARCHarm CROSS_COMPILEarm-linux-gnueabihf- dtbs mkdir -p /tftpboot cp arch/arm/boot/uImage /tftpboot/ cp arch/arm/boot/dts/sun8i-v3s-licheepi-zero.dtb /tftpboot/LOADADDR0x41000040是内核加载地址不同文档给出的值可能不一样跟着自己这套源码的约定走改错的表现是板子跑到加载内核那一步直接重启。-j12是并行编译核数按宿主机 CPU 核数调到一半左右内存小的虚拟机建议降到-j4否则容易在链接阶段被 OOM kill 掉。4. buildroot-2021.02.1外部工具链路径手抄必错4.1 解压与 Target options 五个选项cd ~/qz/tools tar -xvf buildroot-2021.02.1.tar.xz cd buildroot-2021.02.1 make ARCHarm menuconfigTarget options里逐项对齐Target ArchitectureARM (little endian)Target Binary FormatELFTarget Architecture Variantcortex-A7Target ABIEABIhfFloating point strategyVFPv3ARM instruction setARM这六项和 2.2 里提到的硬浮点 ABI 是一一对应的。cortex-A7选成cortex-A9虽然通常还能跑但生成的指令集不完全匹配EABIhf选成EABI就会和宿主机上的工具链 ABI 冲突最终表现是程序编译通过、板子上一跑就Illegal instruction。4.2 Toolchain 必须选 External CustomToolchain菜单里改动最多也最容易错Toolchain type (External toolchain) # 不用 buildroot 自己编工具链 Toolchain (Custom toolchain) # 用我们自己装的那套 Toolchain origin (Pre-installed toolchain) # 已经装在宿主机上 Toolchain path (/home/dev/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) [*] Toolchain has SSP support? [*] Toolchain has RPC support? [*] Toolchain has C support? # 编 Qt 必须勾 [*] Enable MMU supportToolchain path填到工具链根目录不要带/bin。写成.../bin的后果是 buildroot 拼出.../bin/arm-linux-gnueabihf-gcc这种路径去探测探测失败时错误信息藏在output/build/toolchain-external-custom/下的日志里翻半天才能定位。Toolchain prefix填arm-linux-gnueabihf不要带末尾短横buildroot 自己会拼。这一项和CROSS_COMPILE的写法刚好相反不少人在这里翻车。kernel headers series选5.4.x跟 5.4.31 内核对齐。选低版本会导致 glibc 编出来的东西调用不到某些系统调用选高版本可能引入 5.4.31 里不存在的接口。C support必须勾上后面 Qt 5.14.2 要用到 C11 甚至部分 C14 特性。4.3 生成的根文件系统在哪怎么用配置好之后make -j8产物在output/images/下常见的是rootfs.tar、rootfs.ext4、rootfs.ext2几种格式。用 NFS 挂载调试时把output/target/整个目录作为 NFS 导出目录即可# 宿主机 /etc/exports /home/dev/qz/tools/buildroot-2021.02.1/output/target 192.168.10.0/24(rw,sync,no_root_squash,no_subtree_check) sudo exportfs -rano_root_squash让开发板上的 root 用户保留 root 权限做应用调试时不用反复 chmodno_subtree_check关掉子树检查减少 NFS 路径变更后的异常。这两项在正式发布环境里都该关掉调试阶段图省事。4.4 alsa-lib、alsa-utils 与 Qt 5.14.2 各归各位这里有个容易误解的点源码清单里那份qt-opensource-linux-x64-5.14.2.run是x64 宿主机版本装在自己电脑上写代码、做交叉编译工程用的它不能装到 V3S 板子上。板子上的 Qt 库有两个来源要么在 buildroot 的Package Selection for the target里勾 Qt5要么自己用交叉编译器单独编一份 Qt 5.14.2 再放到根文件系统里。音频侧同理。alsa-lib-1.2.2是应用层要链接的库alsa-utils-1.2.2提供aplay、arecord、amixer这些命令。调试顺序上我一般先编 alsa-lib再编 alsa-utils最后跑 Qtcd ~/qz/driver tar -xjf ~/qz/tools/alsa-lib-1.2.2.tar.bz2 cd alsa-lib-1.2.2 ./configure --hostarm-linux-gnueabihf --prefix$HOME/qz/driver/alsa-out \ --disable-python --disable-static make -j8 make install--hostarm-linux-gnueabihf让 configure 用交叉编译器而不是宿主机 gcc--prefix指到一个临时输出目录方便统一拷到板子上--disable-python关掉 Python 绑定目标板上用不到关掉能省下不少交叉编译的麻烦。5. 避坑与排查这几处报错我踩过不止一次5.1 现象终端提示arm-linux-gnueabihf-gcc: command not found原因~/.bashrc里写的是别人电脑上的路径比如/home/farsight/...或者只在一个终端里export PATH...新开终端就丢了。解决回到 2.3 节在工具链 bin 目录下执行pwd拿真实路径~/.bashrc里改成自己的改完source ~/.bashrc然后which arm-linux-gnueabihf-gcc确认。长期做法是把这套路径写进项目里的env.sh每次开终端source env.sh不依赖个人家目录。5.2 现象U-boot 启动后敲ping提示No ethernet found原因两种可能。一是 3.3 节 menuconfig 里Allwinner sun8i GMAC support没勾成星号二是 dts 里emac节点的status还是disabled或者aliases里没加ethernet0 emac;。解决先看menuconfig里那项是不是*再grep -n status arch/arm/dts/sun8i-v3s-licheepi-zero.dts确认okay重新make之后重新dd烧录。改完 dts 一定要重烧只重新编不烧是最常见的“改了没效果”。5.3 现象内核启动日志里出现no phy at addr -1eth0起不来原因把 U-boot 的 dts 写法直接抄进了内核。U-boot 用phy phy0加allwinner,use-internal-phy内核 5.4 用的是phy-handle int_mii_phy加mdio-mux套internal_mdio。解决按 3.8 节把mdio、mdio_mux、internal_mdio、int_mii_phy四个节点补全phy-handle指到int_mii_phy。改完make dtbs只换 dtb 文件就能验证不用重编整个内核。5.4 现象内核挂载 NFS 根文件系统时卡住最后报VFS: Unable to mount root fs on unknown-block原因menuconfig里Root file system on NFS没勾或者宿主机serverip和 NFS 服务不在同一网段也可能是/etc/exports改完没exportfs -ra。解决按 3.7 节把 NFS 三项勾全宿主机上showmount -e 192.168.10.201看导出列表是否包含目标目录再rpcinfo -p确认nfs服务在跑。交叉验证顺序是“U-boot 能 ping 通 → 能 tftp 拉到文件 → 再谈 NFS 挂载”前两步没过就别折腾 NFS。5.5 现象buildroot 编到一半报 toolchain 探测失败日志里全是No such file原因Toolchain path手抄成了带/bin的路径或者Toolchain prefix末尾多了短横。buildroot 的探测脚本拿到这种路径拼出来的命令一定不存在。解决Toolchain path填到gcc-linaro-6.5.0-2018.12-x86_64_arm-linux-gnueabihf这一层为止Toolchain prefix填arm-linux-gnueabihf不带短横。改完先make clean再重新make menuconfig保存一次让探测脚本重跑。这类错误不看日志很难猜output/build/toolchain-external-custom/下的config.log是唯一线索。6. 装完怎么验证从 ping 通到屏幕出声的四步验收环境装没装好不看编译有没有报错看板子跑起来之后这四步能不能连续过。第一步串口有完整的启动日志。打开串口工具115200 8N1上电后应能看到 U-boot 的U-Boot 20xx.xx版本号然后Hit any key to stop autoboot倒计时。能停在这里说明 3.4 节的dd偏移写对了。第二步U-boot 里网络通。按 3.5 节配完四个变量执行 ping 192.168.10.201 Using ethernet1c30000 device host 192.168.10.201 is alive tftp 0x41000000 uImageis alive和 tftp 的Bytes transferred ...都出现了说明 U-boot 侧设备树、驱动、网络配置三项全对。后面就算内核起不来也能靠 tftp 反复换镜像调试不至于每次都要拔卡。第三步内核起来、网卡就绪、根文件系统挂上。启动日志里应该出现类似下面的行[ 0.000000] Booting Linux on physical CPU 0x0 [ 1.2xxxxx] sun8i-v3s-emac 1c30000.ethernet: PHY ID xxxxxxxx at 0 IRQ POLL [ 2.1xxxxx] VFS: Mounted root (nfs filesystem) on device 0:14.第一行证明内核加载地址正确第二行证明内部 PHY 挂上了并且认到了 ID第三行证明 NFS 根文件系统挂载成功。登录进系统后ip addr看到eth0有地址ifconfig里 RX/TX 计数会随 ping 增长。第四步声卡与图形界面。这一步直接决定音视频开发能不能往下走# 板子上执行 aplay -l cat /proc/asound/cardsaplay -l能列出 card 0 及 playback 设备说明 alsa-lib 和内核声卡驱动都到位。然后插一张 48kHz 的 wavaplay test.wav耳机口有声音。最后跑 Qt 程序验证export QT_QPA_PLATFORMlinuxfb ./your_qt_app -platform linuxfbQT_QPA_PLATFORMlinuxfb让 Qt 走 framebuffer不需要 X11 或者 WaylandV3S 这类资源有限的板子基本都是这个跑法。屏幕上出画面、触摸或按键有响应、音频同步出声这套全志 V3S 音视频开发环境才算真正验收完。从那以后我每次拿到一块新板子都先把“串口日志 → ping 通 → aplay -l”这三步强制走一遍再动 Qt 和音视频代码中间少走的路比多写几行业务代码省时间得多。希望帮到你。本文还有配套的精品资源点击获取
阅读完成 · 觉得有帮助?