起因是一次交付。我们给客户部署一套视频处理服务,对方给的是几台老机器:CentOS 7,glibc 2.17,没有 root 权限,只有我自己的一个普通账号,机器上预装的 ffmpeg 是 3.x 的残血版——
ffmpeg -encoders一查,libx264 有,libx265 没有,fdk_aac 没有,libvpx 没有,openssl 更是别想,下载 https 的流直接报Protocol not found。换机器不可能,装系统包也不可能(没权限,内网也没源)。最后能走的路只剩一条:自己编一个静态链接的 ffmpeg,编译完 scp 过去,chmod +x 就能跑。
这件事听起来简单,实际写了三天。第一天在跟依赖打架,第二天在跟链接器打架,第三天在跟体积打架。这篇文章把这三天的记录整理出来,包括完整的命令、每个参数的含义、报错原文和我的处理方式。
TL;DR:静态 ffmpeg 的核心是
--pkg-config-flags="--static"+--extra-ldflags="-static"+--disable-shared --enable-static,外加把依赖库(x264/x265/fdk-aac/openssl…)全部以静态库形式编到$HOME/ffmpeg-build下。三个高频坑:静态链接 glibc 时 getaddrinfo/dlopen 的告警(可用 musl 或放弃 openssl 规避);x265 需要-lstdc++ -lnuma;体积失控要用--disable-everything按白名单开。最后拿ldd和干净容器验证,别只在编译机上跑通就交付。
目录
- 一、先想清楚:静态编译到底解决什么问题
- 二、环境准备与目录约定
- 三、把依赖一个个编成静态库
- 四、configure ffmpeg:参数逐条解释
- 五、链接阶段:那些让人怀疑人生的报错
- 六、从 78MB 裁到 16MB
- 七、验证:别只在编译机上跑通就交付
- 八、musl 路线:什么时候该换赛道
- 九、想带 NVENC 硬件加速怎么办
- 十、我踩过的坑清单
- 十一、交付与合规
一、先想清楚:静态编译到底解决什么问题
在动手前,我先把"为什么非要静态"这件事想清楚,因为这决定了后面要不要吃这些苦。
所谓静态,就是把 libx264.a、libx265.a、libcrypto.a 这些 .a 文件在链接阶段直接塞进最终的可执行文件,运行的时候不再找系统的 .so。对比一下三种常见方案:
| 方案 | 优点 | 缺点 | 适合场景 |
|---|---|---|---|
| 系统包管理器装(apt/yum) | 最省事 | 版本旧、编码器被砍、需要 root | 自己的机器、有网有权限 |
| 官方 static build(johnvansickle 那种) | 直接下载、省事 | 里面带了什么不受你控制,更新节奏看人家 | 快速验证、个人使用 |
| Docker 镜像 | 环境最干净 | 客户环境不一定有 docker,运维不一定配合 | 自有服务器、K8s |
| 自己编静态 | 编码器、协议、体积全可控,单文件丢过去就跑 | 折腾,编译链要求高 | 交付给第三方、老系统、无 root |
我这次是第四种。判断标准其实就一条:目标机器的 glibc 版本比编译机老,或者目标机器你不能装东西。反过来,如果目标机器跟你编译机同系统同版本,直接把动态链接的 ffmpeg 连同它 ldd 出来的一堆 .so 打个 tar 一起丢过去,往往更省事——我后来给另一台 Ubuntu 22.04 就这么干的,5 分钟完事。
判断 glibc 版本:
ldd --version | head -1
# ldd (GNU libc) 2.17
黄金法则:在目标机器上,或者比目标机器更老的系统上编译。在 Ubuntu 24.04(glibc 2.39)上编出来的东西,拿到 CentOS 7(2.17)上大概率报:
./ffmpeg: /lib64/libc.so.6: version `GLIBC_2.28' not found (required by ./ffmpeg)
我一开始就是在本机 Ubuntu 上编的,scp 过去直接报这个,白等了 40 分钟传输。后来找了台 CentOS 7 的虚拟机重编。
二、环境准备与目录约定
目录约定我沿用了 ffmpeg 官方编译文档的习惯,别乱改,后面所有命令都依赖它:
mkdir -p ~/ffmpeg-sources ~/ffmpeg-build ~/bin
ffmpeg-sources:放各个依赖的源码ffmpeg-build:所有依赖的安装前缀(.a 和头文件都在这里)bin:最终 ffmpeg/ffprobe 二进制落在这里
编译工具链(Ubuntu/Debian):
sudo apt-get update && sudo apt-get install -y \
build-essential cmake git pkg-config yasm nasm \
autoconf automake libtool meson ninja-build \
python3 python3-pip texinfo wget curl
CentOS 7 上对应的是:
sudo yum groupinstall -y "Development Tools"
sudo yum install -y cmake3 git yasm nasm pkgconfig autoconf automake libtool
CentOS 7 的 cmake 是 2.8,编 x265 会失败,要用 cmake3,或者自己装新版 cmake(我选了后者,从 cmake 官网下了 3.28 的 binary tarball 解压到 ~/tools 然后加 PATH,比跟 yum 源较劲快)。
有个小建议:编译目录放 SSD,且保证至少 10GB 剩余。x265 和 aom 编起来临时文件不小,我有一次在还剩 3GB 的盘上编到一半 No space left on device,重来了一遍。
三、把依赖一个个编成静态库
按我的需求,最终要带的是:x264、x265、libvpx(VP9)、fdk-aac、mp3lame、opus、openssl(https)。下面是逐个的命令和坑点。
x264
cd ~/ffmpeg-sources && \
git clone --depth 1 https://code.videolan.org/videolan/x264.git && \
cd x264 && \
PKG_CONFIG_PATH="$HOME/ffmpeg-build/lib/pkgconfig" \
./configure --prefix="$HOME/ffmpeg-build" --bindir="$HOME/bin" \
--enable-static --disable-opencl --disable-cli && \
make -j$(nproc) && make install
--disable-cli 很关键。默认它会编出一个 x264 命令行工具,那玩意儿是动态链接的,编到一半可能因为找不到 .so 报错;我们只要 libx264.a。
x265
cd ~/ffmpeg-sources && \
git clone --depth 1 https://bitbucket.org/multicoreware/x265_git.git && \
cd x265_git/build/linux && \
cmake -G "Unix Makefiles" ../../source \
-DCMAKE_INSTALL_PREFIX="$HOME/ffmpeg-build" \
-DENABLE_SHARED=OFF \
-DENABLE_CLI=OFF \
-DENABLE_PIC=ON && \
make -j$(nproc) && make install
两个坑:
ENABLE_SHARED=OFF必须显式写,默认它是 ON,会编出libx265.so,我们要的是.a。- x265 是 C++ 写的,后面链接 ffmpeg 的时候必须额外给
-lstdc++,否则一堆undefined reference to std::xxx。这个后面第五节会再提一次,因为它坑了我半天。
libvpx(VP8/VP9)
cd ~/ffmpeg-sources && \
git clone --depth 1 https://chromium.googlesource.com/webm/libvpx.git && \
cd libvpx && \
./configure --prefix="$HOME/ffmpeg-build" --disable-examples \
--disable-unit-tests --disable-shared --enable-static \
--enable-vp9-highbitdepth --as=yasm && \
make -j$(nproc) && make install
--enable-vp9-highbitdepth 是我自己加的,因为要处理 10bit 的源。用不到可以去掉,能省一点体积。
fdk-aac
cd ~/ffmpeg-sources && \
git clone --depth 1 https://github.com/mstorsjo/fdk-aac.git && \
cd fdk-aac && \
autoreconf -fiv && \
./configure --prefix="$HOME/ffmpeg-build" --disable-shared --enable-static && \
make -j$(nproc) && make install
许可证提醒:fdk-aac 是 Fraunhofer 的 AAC 编码器,ffmpeg 把它归类为 nonfree。你一旦 --enable-libfdk-aac,编出来的 ffmpeg 二进制在法律上不允许分发给第三方(GPL 不兼容)。我这次是交付给客户内网自己用,属于"给对方编译",我跟客户明确说明了这一点,并给了一个不带 fdk-aac 的备用版本,用它自带的原生 aac 编码器。这个事情第十节还会讲,别嫌我啰嗦,真出事是法务来找你。
如果不想碰 nonfree,把 --enable-libfdk-aac 换成 ffmpeg 原生 aac(--enable-encoder=aac),质量差一点点,但省心。
mp3lame / opus
# lame
cd ~/ffmpeg-sources && \
curl -L -O https://downloads.sourceforge.net/project/lame/lame/3.100/lame-3.100.tar.gz && \
tar xzvf lame-3.100.tar.gz && cd lame-3.100 && \
./configure --prefix="$HOME/ffmpeg-build" --disable-shared --enable-static --enable-nasm && \
make -j$(nproc) && make install
# opus
cd ~/ffmpeg-sources && \
git clone --depth 1 https://github.com/xiph/opus.git && cd opus && \
./autogen.sh && \
./configure --prefix="$HOME/ffmpeg-build" --disable-shared --enable-static && \
make -j$(nproc) && make install
openssl(https/tls 协议)
cd ~/ffmpeg-sources && \
curl -L -O https://www.openssl.org/source/openssl-3.0.15.tar.gz && \
tar xzvf openssl-3.0.15.tar.gz && cd openssl-3.0.15 && \
./config --prefix="$HOME/ffmpeg-build" --openssldir="$HOME/ffmpeg-build/ssl" \
no-shared no-tests && \
make -j$(nproc) && make install_sw
no-shared 是重点,要 .a。install_sw 比 install 快,跳过文档。
openssl 是静态链接时最容易出事的一环,因为它会用到 dlopen、getaddrinfo 这些 glibc 里"静态链接不干净"的东西。具体的报错和处理在第五节。
想再加 dav1d / SVT-AV1?
我这次没编,理由是客户机器上的源全是 H.264/H.265,AV1 解码用不上,编进去白白多 6MB。如果确实需要:
# dav1d(AV1 解码,meson 构建)
cd ~/ffmpeg-sources && git clone --depth 1 https://code.videolan.org/videolan/dav1d.git && \
cd dav1d && meson setup build --prefix="$HOME/ffmpeg-build" \
--default-library=static --libdir=lib && \
ninja -C build && ninja -C build install
四、configure ffmpeg:参数逐条解释
依赖齐了,轮到主角:
cd ~/ffmpeg-sources && \
curl -L -O https://ffmpeg.org/releases/ffmpeg-7.1.tar.xz && \
tar xf ffmpeg-7.1.tar.xz && cd ffmpeg-7.1 && \
PKG_CONFIG_PATH="$HOME/ffmpeg-build/lib/pkgconfig" ./configure \
--prefix="$HOME/ffmpeg-build" \
--pkg-config-flags="--static" \
--extra-cflags="-I$HOME/ffmpeg-build/include" \
--extra-ldflags="-L$HOME/ffmpeg-build/lib -static" \
--extra-libs="-lpthread -lm -ldl -lstdc++" \
--bindir="$HOME/bin" \
--enable-gpl --enable-nonfree \
--enable-libx264 --enable-libx265 --enable-libvpx \
--enable-libfdk-aac --enable-libmp3lame --enable-libopus \
--enable-openssl \
--disable-shared --enable-static \
--disable-doc --disable-debug && \
make -j$(nproc) && make install
逐条说明我为什么这么写:
| 参数 | 作用 | 不写会怎样 |
|---|---|---|
PKG_CONFIG_PATH=... |
让 pkg-config 找到我们自己编的 .pc 文件 | 找不到 x264,configure 报 ERROR: libx264 not found |
--pkg-config-flags="--static" |
让 pkg-config 输出静态链接所需的 -lxxx 全集 |
链接时缺符号 |
--extra-ldflags="... -static" |
强制全静态链接 | 编出来是动态链接,ldd 一堆 .so |
--extra-libs="-lpthread -lm -ldl -lstdc++" |
补齐 pthread、数学库、dl 系列、C++ 标准库 | openssl 的 dlopen 未定义;x265 的 std:: 未定义 |
--enable-gpl |
x264/x265 是 GPL | configure 直接拒绝 |
--enable-nonfree |
fdk-aac 是 nonfree | ERROR: libfdk_aac is nonfree |
--disable-doc |
不编文档 | 多花几分钟,多几十 MB 中间产物 |
--disable-debug |
关调试符号 | 二进制大一圈 |
configure 跑完会打印一大段 "External libraries" 清单,务必扫一眼,确认你要的都在里面:
External libraries:
libfdk_aac libmp3lame libopus libvpx libx264 libx265 openssl
如果某个库显示为 no 或者直接进了 "External libraries providing hardware acceleration" 之外的地方,说明 pkg-config 没找到,去 $HOME/ffmpeg-build/lib/pkgconfig 看看对应的 .pc 在不在。我第一次 x265 就漏了,原因是忘了 make install。
五、链接阶段:那些让人怀疑人生的报错
编译到最后一步 ld 的时候,我遇到了三个报错,贴原文和解法。
报错 1:getaddrinfo / dlopen 告警
WARNING: /usr/bin/ld: ... warning: Using 'getaddrinfo' in statically linked
applications requires at runtime the shared libraries from the glibc version
used for linking
这个不是致命错误,链接会成功,但运行时在 glibc 版本不同的机器上可能炸。我当时硬着头皮用了,在目标机上测 https 下载,确实能跑,但我心里不踏实。
三条路:
- 接受它,但保证编译机 glibc 不高于目标机(我这次的做法);
- 不要 openssl,用
--disable-openssl,只支持 http(省事,但 https 就废了); - 换 musl 静态编译(第八节)。
报错 2:undefined reference to dlclose
/usr/bin/ld: libavformat.a(tls_openssl.o): undefined reference to symbol 'dlclose@@GLIBC_2.2.5'
/usr/bin/ld: /lib/x86_64-linux-gnu/libdl.so.2: error adding symbols: DSO missing from command line
缺 -ldl。加进 --extra-libs 里解决。这个报错很典型:它不告诉你少了什么库,只说 "DSO missing from command line",第一次看真的懵。
报错 3:x265 的 C++ 符号
/usr/bin/ld: libavcodec.a(libx265.o): undefined reference to `std::__cxx11::basic_string...'
/usr/bin/ld: undefined reference to `operator new(unsigned long)'
缺 -lstdc++。同理加进 --extra-libs。另外某些系统上 x265 还依赖 numa,会报 undefined reference to numa_alloc_onnode,两个办法:编 x265 时关掉(cmake 时不带 numa,或源码里 --disable-numa),或者加 -lnuma。
我的 --extra-libs 最终形态:
--extra-libs="-lpthread -lm -ldl -lstdc++ -lnuma"
报错 4(如果你用的是老 gcc):-fPIC 相关
/usr/bin/ld: libavcodec.a(x86/...o): relocation R_X86_64_32S against ... can not be used when making a PIE object
静态链接到非 PIE 时常见。加 --extra-ldflags="-no-pie" 或者 --extra-cflags="-fno-pie"。我在 CentOS 7 上遇到过一次,加上就好了。
六、从 78MB 裁到 16MB
第一版编出来我一看:ls -lh ~/bin/ffmpeg → 78MB。scp 到内网机器慢得要死,而且里面塞了一堆我用不到的东西(几百个 demuxer、几十个 encoder、一堆我从没听说过的协议)。
裁剪的核心思路是白名单:先 --disable-everything 全关,再一个个把要的打开。
PKG_CONFIG_PATH="$HOME/ffmpeg-build/lib/pkgconfig" ./configure \
--prefix="$HOME/ffmpeg-build" \
--pkg-config-flags="--static" \
--extra-cflags="-I$HOME/ffmpeg-build/include" \
--extra-ldflags="-L$HOME/ffmpeg-build/lib -static -no-pie" \
--extra-libs="-lpthread -lm -ldl -lstdc++ -lnuma" \
--bindir="$HOME/bin" \
--enable-gpl --enable-nonfree \
--enable-libx264 --enable-libx265 --enable-libvpx \
--enable-libfdk-aac --enable-libmp3lame --enable-libopus \
--enable-openssl \
--disable-shared --enable-static --disable-doc --disable-debug \
--disable-everything \
--enable-protocol=file,http,https,tls,tcp,udp,pipe \
--enable-demuxer=mov,mp4,m4v,mpegts,matroska,webm,flv,hls,aac,mp3,wav,image2,concat \
--enable-muxer=mp4,mov,mpegts,matroska,webm,flv,mp3,null,image2 \
--enable-decoder=h264,hevc,vp8,vp9,aac,mp3,opus,vorbis,flac,png,mjpeg \
--enable-encoder=libx264,libx265,libvpx_vp9,libfdk_aac,libmp3lame,libopus,aac,png,mjpeg \
--enable-parser=h264,hevc,vp8,vp9,aac,mpegaudio,opus \
--enable-bsf=h264_mp4toannexb,hevc_mp4toannexb,aac_adtstoasc,extract_extradata \
--enable-filter=scale,crop,overlay,concat,trim,format,null,fps,setpts,subtitles,amix,volume \
--enable-swscale --enable-swresample --enable-avformat --enable-avcodec --enable-avutil
体积变化实测(我那台机器上):
| 版本 | 大小 | 说明 |
|---|---|---|
| 默认全量静态 | 78.4 MB | 什么都能干 |
全量 + strip |
71.9 MB | strip 掉符号表,省 6MB |
| 白名单裁剪 | 21.6 MB | 只保留业务要的 |
白名单 + strip |
16.3 MB | 最终交付版 |
strip 别忘了:
strip -s ~/bin/ffmpeg
cp ~/bin/ffmpeg ~/bin/ffmpeg-debug # 建议先留一份带符号的,方便日后 gdb
裁剪最大的风险是漏项,而且它不会在编译期报错,只会在运行时报。我第一版裁剪完,测 HLS 的时候直接:
[hls @ 0x...] Unable to find a suitable output format
查了半天才发现 hls 我只在 demuxer 里开了,muxer 忘了。所以裁剪完一定要跑一遍你所有的真实业务命令,别只测一条。
顺手记一下我常用的"查到底要开哪些组件"的方法:不裁剪的时候用 ffmpeg -formats、-codecs、-protocols、-filters 看全量名字,再从业务命令里反推要哪些。或者直接看编译时 config.h 里的 CONFIG_XXX。
七、验证:别只在编译机上跑通就交付
我吃过这个亏:在编译机上 ffmpeg -version 一切正常,交付过去客户一跑就报缺库。原因是编译机上系统本来就有那些 .so,掩盖了问题。
验证清单(按顺序做):
1. 看是不是真的静态
ldd ~/bin/ffmpeg
# 期望输出:不是动态可执行文件 / not a dynamic executable
如果 ldd 列出一堆 .so,说明没静态成功,回去检查 --disable-shared --enable-static 和 --extra-ldflags。
2. file 看一眼
file ~/bin/ffmpeg
# ffmpeg: ELF 64-bit LSB executable, x86-64, version 1 (GNU/Linux), statically linked, ...
3. 在干净容器里跑真命令
这是我最信任的一招。编译机上装个 docker 或者用目标系统的最小镜像:
docker run --rm -v ~/bin:/ff -w /ff centos:7 ./ffmpeg -version
docker run --rm -v ~/bin:/ff -v /tmp/media:/m -w /ff centos:7 \
./ffmpeg -y -i /m/in.mp4 -c:v libx265 -crf 28 -c:a libfdk_aac -vbr 4 /m/out.mp4
能转码出文件且退出码为 0,才算真的过。顺带一提,这个容器测试还能验证 glibc 兼容性——centos:7 镜像的 glibc 就是 2.17。
4. 检查编码器清单
~/bin/ffmpeg -hide_banner -encoders 2>/dev/null | grep -E 'libx264|libx265|libfdk|libvpx'
5. 跑一遍 HTTPS 拉流(验证 openssl)
~/bin/ffmpeg -hide_banner -i "https://example.com/stream.m3u8" -t 5 -f null -
报 Protocol not found 说明 openssl/tls 协议没进去;报证书问题(内网自签证书)需要 -tls_verify 0 或者给 CA。
6. 别忘了 ffprobe
make install 会一起编出 ffprobe。我一开始就忘了测它,结果客户那边调 ffprobe 报缺库——它也是静态的,但链接参数跟 ffmpeg 不完全一样,务必一起测。
八、musl 路线:什么时候该换赛道
如果你遇到的情况符合下面任意一条,我建议别在 glibc 上死磕:
- 目标机器 glibc 版本比你能拿到的编译机还老;
- 你必须要 openssl/tls,又不想被 getaddrinfo 告警悬着心;
- 你要编的是真的"一个文件走天下",可能扔到各种发行版上跑。
换 musl/ Alpine:
docker run -it --rm -v ~/ffmpeg-out:/out alpine:3.20 sh
# 容器内
apk add --no-cache build-base cmake git pkgconf yasm nasm autoconf automake libtool \
meson ninja python3 linux-headers openssl-dev openssl-libs-static zlib-static \
libstdc++ argp-standalone
musl 下静态链接干净很多,几乎没有 getaddrinfo 那套告警。代价是:
| 对比项 | glibc 静态 | musl 静态 |
|---|---|---|
| 链接告警 | 有(getaddrinfo/dlopen) | 基本没有 |
| 兼容性 | 依赖编译机 glibc 版本 | 极好,扔哪都能跑 |
| 性能 | 略好(尤其多线程 malloc) | 部分场景 malloc 稍慢 |
| 踩坑成本 | 高 | 中(要适应 apk 和 musl 特性) |
我在第二个项目(给一台嵌入式盒子编译)上走的 musl 路线,同样的需求,一天搞定,比第一次省了两天。所以我的建议是:如果目标机器不确定,直接用 musl;如果目标机器明确是某个老 RHEL/CentOS,且你手上有同版本系统,那 glibc 静态也够用。
九、想带 NVENC 硬件加速怎么办
这是另一个高频需求,而且跟"静态"有点冲突,得单独说。
硬件编码要加这些:
--enable-nonfree --enable-cuda --enable-cuda-nvcc --enable-nvenc --enable-cuvid \
--nvccflags="-gencode arch=compute_75,code=sm_75" \
--extra-cflags="-I/usr/local/cuda/include" \
--extra-ldflags="-L/usr/local/cuda/lib64"
arch=compute_75 要按你的显卡架构改:T4/RTX20 系是 75,RTX30 系是 86,A100 是 80,V100 是 70。写错了编得出来但跑不起来,报 no NVIDIA device found 之类。查自己卡的算力:
nvidia-smi --query-gpu=compute_cap,name --format=csv
关键结论:NVENC 这条路不可能做到完全静态。原因有二:
- CUDA runtime 官方早就不提供静态库(
libcudart_static.a虽然还在,但不推荐且兼容坑多); - 更致命的是显卡驱动:NVENC 需要运行时的
libnvidia-encode.so,这个库由驱动提供,版本号必须跟驱动匹配。你把它静态编进去,等于把驱动版本焊死,换台机器驱动版本不对直接Cannot load libnvidia-encode.so.1。
所以带 NVENC 的版本,我的做法是:ffmpeg 本体静态,CUDA/NVENC 部分动态。也就是不写 -static,让它链接系统的 libcudart 和运行时加载 libnvidia-encode。交付的时候附带说明:目标机器必须装 ≥ 某版本的 NVIDIA 驱动。
# 验证 NVENC 可用
ffmpeg -hide_banner -f lavfi -i testsrc=size=1920x1080:rate=30:duration=5 \
-c:v h264_nvenc -preset p4 /tmp/nvenc_test.mp4
跑通不代表生产可用。我一般会再压一段真实素材,对比 h264_nvenc 和 libx264 在相同码率下的质量(用 VMAF 测,这篇不讲,是另一个话题了),确认客户能接受画质损失再上。
十、我踩过的坑清单
按"浪费时间多少"排序,全是真金白银换来的:
- 在高版本系统上编、拿到低版本系统跑 →
GLIBC_2.28 not found。浪费一晚。解法:编译机系统版本 ≤ 目标机。 - 忘了
--disable-cli,x264 编出动态命令行工具报错 → 加--disable-cli。 - x265 用默认参数编出 .so → 加
-DENABLE_SHARED=OFF。 - 链接时缺
-lstdc++→ x265 的 C++ 符号全未定义。 - 链接时缺
-ldl→ openssl 的 dlopen 未定义,报错信息完全不提示是哪个库。 - 裁剪漏了 muxer/demuxer → 编译不报错,运行才报
Unable to find a suitable output format。裁剪后必须全量测一遍业务命令。 make -j$(nproc)在内存小的机器上把编译进程干掉 → 4GB 内存机器编 x265 时 OOM,signal: killed。改-j2或者加 swap。- 改了 configure 参数没
make clean→ 出来一个半新半旧的二进制,行为诡异。改参数后先make distclean(注意distclean会清掉 config,得重新 configure,这是对的)。 - 只测
ffmpeg -version就交付 → 客户一跑真实命令就挂。必须跑真实业务命令。 - 忘了 ffprobe → 它要单独测。
- 没留带符号的版本 →
strip之后出问题没法 gdb。先cp一份再 strip。 - fdk-aac 的许可证没提前说 → 客户法务后来问了一轮。现在我会主动在交付文档里写清楚哪些组件是 nonfree。
十一、交付与合规
最后说说交付这件事,因为技术之外这块最容易翻车。
交付物清单(我现在的固定格式):
ffmpeg # 静态二进制
ffprobe # 静态二进制
BUILD_INFO.txt # 编译命令 + configure 参数原文
VERSION.txt # ffmpeg 版本、依赖版本、编译机系统/glibc 版本
LICENSE_NOTICE.txt # 组件许可证说明
BUILD_INFO.txt 里我把 configure 那条命令原样贴进去,方便半年后有人问"这个 ffmpeg 到底开了啥"时能一秒回答。这个习惯是踩过坑之后养成的——有次线上出奇怪的编码问题,翻了半天才搞清楚是当初少编了一个 bsf。
许可证相关(不是法律建议,是我自己的处理原则):
libx264、libx265是 GPL。开了--enable-gpl编出来的二进制,如果你把它分发给外部,理论上需要提供源码或编译说明。给客户内网部署、自己在服务器上用,一般不构成分发,但我会在文档里附上完整的编译脚本,对方要源码就能复现。libfdk-aac是 nonfree,跟 GPL 不兼容,不能分发。我的做法是默认不带它,除非客户明确要 AAC 的高码率质量,且我确认是他们自己内部使用。- 视频编码本身涉及专利池(H.264/H.265 的 MPEG-LA / HEVC Advance 那套)。商用产品里内置编码器要不要交专利费,这不是技术问题,交给法务判断。
给目标机器的部署建议:
sudo mkdir -p /opt/ffmpeg
sudo cp ffmpeg ffprobe /opt/ffmpeg/
sudo chmod +x /opt/ffmpeg/*
# 不要覆盖系统 ffmpeg,用 alternatives 或者显式 PATH
sudo update-alternatives --install /usr/bin/ffmpeg ffmpeg /opt/ffmpeg/ffmpeg 50
我一般不会直接覆盖 /usr/bin/ffmpeg,因为机器上可能有别的服务依赖系统版本。用 alternatives 或者干脆在业务脚本里写全路径 /opt/ffmpeg/ffmpeg,最省事也最不容易背锅。
回过头看,编译静态 ffmpeg 这件事本身没什么高深技术,绝大部分时间花在了"报错信息看不懂 → 猜 → 试 → 验证"的循环上。真正的收益不是那个 16MB 的二进制,而是我把整条依赖链摸清楚了:现在再遇到"这个格式不支持""那个协议找不到",我基本能立刻判断是 configure 少开了什么,而不是像第一次那样去网上瞎搜。
如果你也在做类似的事,我的建议只有一条:先把目标机器的约束(glibc 版本、有没有 root、要不要 https、要不要硬件编码)写下来,再决定编译策略。这四件事决定了你走 glibc 静态、musl 静态还是干脆上容器,选错了就是几天的返工。