2、开发环境搭建:交叉编译工具链安装、FFmpeg源码编译、SDL库移植

好,咱们正式开始动手了。

这一章,说白了就是搭灶台。没有锅碗瓢盆,你后面再好的菜也炒不出来。嵌入式音视频开发,最烦人的就是环境搭建。我当年刚入行时,光配交叉编译链就折腾了两天,后来发现是路径写错了……嗯,这种坑咱们今天一次性填平。

2.1 交叉编译工具链:为什么非得用这个?

你想想看,你的开发电脑是 x86 架构,但目标板子是 ARM 架构。代码在 x86 上编译出来,ARM 板子根本跑不了。交叉编译链,就是让你在 PC 上生成 ARM 可执行文件的桥梁。

我个人习惯用 Linaro 提供的 GCC 工具链,稳定且社区活跃。以 ARM Cortex-A7 为例,安装步骤其实就三步:

  1. 下载:从 Linaro 官网获取 gcc-linaro-7.5.0-2019.12-x86_64_arm-linux-gnueabihf.tar.xz
  2. 解压:扔到 /opt/toolchains 目录下
  3. 配置环境变量:把 bin 目录加到 PATH 里
# 解压
sudo tar -xvf gcc-linaro-7.5.0-2019.12-x86_64_arm-linux-gnueabihf.tar.xz -C /opt/toolchains/

# 配置环境变量(写到 ~/.bashrc 里)
export PATH=/opt/toolchains/gcc-linaro-7.5.0-2019.12-x86_64_arm-linux-gnueabihf/bin:$PATH
export CROSS_COMPILE=arm-linux-gnueabihf-
export ARCH=arm

# 验证
arm-linux-gnueabihf-gcc --version
⚠️ 我曾经踩过的坑: 解压路径不要带中文或空格!还有,记得 source ~/.bashrc 让配置生效。我当时忘了这一步,愣是查了半天为什么 gcc 找不到。

2.2 FFmpeg 源码编译:别怕,没那么玄乎

FFmpeg 是音视频领域的瑞士军刀。但嵌入式平台不能直接用 apt-get 装,必须自己交叉编译。为什么?因为你要裁剪功能、优化尺寸、适配硬件编解码器。

我建议你下载 FFmpeg 4.4 版本,这个版本稳定且文档齐全。编译前先配好 configure 参数,核心就这几项:

参数 说明
--cross-prefix 指定交叉编译工具链前缀
--enable-cross-compile 开启交叉编译模式
--target-os 目标操作系统,比如 linux
--arch 目标架构,比如 arm
--disable-xxx 按需裁剪,减少体积

下面是我实际项目里用过的编译脚本,你可以直接参考:

#!/bin/bash
export PATH=/opt/toolchains/gcc-linaro-7.5.0-2019.12-x86_64_arm-linux-gnueabihf/bin:$PATH

./configure \
    --cross-prefix=arm-linux-gnueabihf- \
    --enable-cross-compile \
    --target-os=linux \
    --arch=arm \
    --disable-doc \
    --disable-ffplay \
    --disable-ffprobe \
    --disable-ffserver \
    --disable-network \
    --disable-encoders \
    --disable-muxers \
    --enable-decoder=h264 \
    --enable-decoder=aac \
    --enable-demuxer=mov \
    --enable-demuxer=flv \
    --enable-protocol=file

make -j4
make install
💡 小技巧: 第一次编译时,先只保留最少的解码器和解复用器。等后面跑通了,再慢慢加功能。这样出错了也好排查。我当年一股脑全编译,结果报错信息刷了满屏,根本不知道哪里出了问题。

2.3 SDL 库移植:让画面显示出来

FFmpeg 负责解码,但解码出来的数据怎么显示到屏幕上?这就轮到 SDL 出场了。SDL 是一个跨平台的多媒体库,说白了就是帮你操作 framebuffer 或 OpenGL ES。

嵌入式平台移植 SDL,重点在于配置显示后端。对于大多数 ARM Linux 板子,我们使用 fbcon(framebuffer console)驱动。

编译 SDL 2.0.20 的步骤:

# 配置
./configure \
    --host=arm-linux-gnueabihf \
    --prefix=/opt/sdl2_arm \
    --disable-video-x11 \
    --disable-video-wayland \
    --enable-video-fbcon \
    --enable-video-opengles

make -j4
make install

这里有个关键点:--enable-video-fbcon 必须打开。否则 SDL 找不到显示设备,你的画面就黑屏了。

🔑 核心验证方法:

编译完成后,写一个简单的测试程序:

#include <SDL2/SDL.h>

int main() {
    if (SDL_Init(SDL_INIT_VIDEO) < 0) {
        printf("SDL Init failed: %s\n", SDL_GetError());
        return -1;
    }
    SDL_Window *win = SDL_CreateWindow("test", 0, 0, 640, 480, SDL_WINDOW_FULLSCREEN);
    if (!win) {
        printf("Window create failed: %s\n", SDL_GetError());
        return -1;
    }
    SDL_Delay(3000);
    SDL_DestroyWindow(win);
    SDL_Quit();
    return 0;
}

交叉编译后扔到板子上跑。如果屏幕亮了3秒然后退出,说明环境搭建成功。

2.4 整合验证:让 FFmpeg 和 SDL 握手

工具链、FFmpeg、SDL 都装好了,怎么知道它们能协同工作?我习惯写一个最简单的播放器雏形:FFmpeg 解码一帧,SDL 显示一帧。

编译时链接参数要特别注意:

arm-linux-gnueabihf-gcc \
    -I/opt/ffmpeg_arm/include \
    -I/opt/sdl2_arm/include/SDL2 \
    -L/opt/ffmpeg_arm/lib \
    -L/opt/sdl2_arm/lib \
    test_player.c \
    -lavformat -lavcodec -lavutil -lswscale \
    -lSDL2 \
    -o test_player
⚠️ 链接顺序有讲究: -lSDL2 要放在最后。GCC 链接器是从右向左解析符号的,顺序错了会报 undefined reference。我因为这个错误浪费了整整一个下午。

把生成的 test_player 拷贝到板子上,运行。如果能看到画面在动,恭喜你,开发环境搭建成功了!

说实话,环境搭建这一步最磨人。但只要你按照上面的步骤来,把每个组件的编译日志都仔细看一遍,基本不会出大问题。后面章节咱们就开始真正写代码了——从打开一个视频文件,到解码、缩放、渲染,一步步把管道搭起来。

嗯,下一章见。