之前自己从未考虑过这个问题。每次手动编译 OpenCV 的时候,cmake 后面的 -D xxx对我来说只是添加某个支持,但我并不知道 OpenCV 编译本身也是依靠 CMake 配置完成的,而 CMake 找到这些依赖,很多时候又依靠 pkg-config 工具。

文章最下方是我在编译 OpenCV 时使用的 cmake 命令。最开始的命令里没有正确添加对 FFmpeg 的支持。

完全编译并 sudo make install 后,我的 OpenCV 甚至不能读取视频。这是因为 OpenCV 主要用于图像处理,而视频文件、视频流的采集、封装、解封装、编解码通常需要依赖额外的视频 I/O 后端。

cv::VideoCapture 可以读取视频流,是因为 OpenCV 提供了多个后端,例如 FFmpeg、GStreamer、V4L2 等。

既然如此,我在 cmake 命令中增加了:-D WITH_FFMPEG=ON

我寻思着大功告成力,于是开始摸鱼。编译完后,程序依旧运行不起来。

在 terminal 中输入 ffmpeg,能够正确显示版本,而且两台设备的版本也一致,看起来系统事先已经预装了 FFmpeg。但这里需要注意,命令行 ffmpeg 可用,只能说明 FFmpeg 命令行工具可用,不代表 OpenCV 编译时能够通过 CMake / pkg-config 找到 FFmpeg 的开发库、头文件和链接依赖。

如果确认需要重装 FFmpeg,可以先卸载系统版本:sudo apt purge ffmpeg

不过这一步有风险,可能会卸载系统包版本 FFmpeg,并影响其他依赖它的软件。尽量不要直接使用 autoremove,否则可能会卸载掉额外依赖。更稳妥的做法,是先确认当前 OpenCV 编译失败的原因,再决定是否真的需要卸载。

所以我找到了 jocover/jetson-ffmpeg 仓库,按照其中的方法安装。

在第二步 ./configure --enable-nvmpi 时一直报错,而 nvmpi 这个依赖确实存在于设备上。不过 nvmpi 主要用于 NVIDIA 硬件加速视频解码和转码,如果当前项目不依赖 GPU 视频解码,暂时舍弃也可以。

Note 1:FFmpeg make 完成后,执行安装:sudo make install

否则后续仍然可能找不到这个库。

Note 2:接下来编译 OpenCV 时,可以在 cmake 结果中确认是否支持 FFmpeg,关键输出类似:FFMPEG: YES

Note 3:编译 OpenCV 时如果出现和 shared / static lib 相关的报错,可以在编译 FFmpeg 的 ./configure 阶段添加:

--disable-static --enable-shared

Note 4:有教程提到编译 FFmpeg 前要下载 FFmpeg 依赖,比如 avcodec-dev、libswscale-dev 等。这里要分情况看:如果从源码完整编译 FFmpeg,通常不需要额外安装这些系统 dev 包;但如果希望 OpenCV 直接链接系统包版本的 FFmpeg,则需要安装相应开发包,或者至少确保 CMake / pkg-config 能找到对应的 .pc 文件和链接库。

Note 5:可能报错:

libavdevice.so.58: cannot open shared object file: No such file or directory

这是因为运行时动态链接器没有找到对应库。不要直接改坏系统配置,更稳妥的做法是在 /etc/ld.so.conf.d/ 下新增一个配置文件,例如:

echo "/usr/local/lib" | sudo tee /etc/ld.so.conf.d/local-lib.conf
sudo ldconfig

下面是我当时编译 OpenCV 使用的 cmake 命令示例。需要注意,这里面包含很多个人环境路径,例如 Anaconda 路径、CUDA / cuDNN 路径、CUDA_ARCH_BIN 等,不要直接复制。

sudo cmake -D CMAKE_BUILD_TYPE=RELEASE \
-D CMAKE_INSTALL_PREFIX=/usr/local \
-D CMAKE_C_COMPILER=/usr/bin/gcc-9 \
-D INSTALL_PYTHON_EXAMPLES=ON \
-D INSTALL_C_EXAMPLES=ON \
-D OPENCV_ENABLE_NONFREE=ON \
-D BUILD_opencv_python3=ON \
-D WITH_CUDA=ON \
-D WITH_CUDNN=ON \
-D WITH_TBB=ON \
-D WITH_FFMPEG=ON \
-D OPENCV_DNN_CUDA=ON \
-D ENABLE_FAST_MATH=1 \
-D CUDA_FAST_MATH=1 \
-D CUDA_ARCH_BIN=8.9 \
-D WITH_CUBLAS=1 \
-D OPENCV_GENERATE_PKGCONFIG=ON \
-D OPENCV_EXTRA_MODULES_PATH=/home/funnywii/opencv_contrib-4.7.0/modules \
-D PYTHON3_EXECUTABLE=/home/funnywii/Anaconda3/bin/python3.10 \
-D PYTHON3_INCLUDE_DIR=/home/funnywii/Anaconda3/include/python3.10 \
-D PYTHON3_LIBRARY=/home/funnywii/Anaconda3/lib/libpython3.10.so \
-D PYTHON3_NUMPY_INCLUDE_DIRS=/home/funnywii/Anaconda3/lib/python3.10/site-packages/numpy/core/include \
-D PYTHON3_PACKAGES_PATH=/home/funnywii/Anaconda3/lib/python3.10/site-packages \
-D PYTHON_DEFAULT_EXECUTABLE=/home/funnywii/Anaconda3/bin/python3.10 \
-D CUDNN_LIBRARY=/usr/lib/x86_64-linux-gnu/libcudnn.so.8.9.2 \
-D CUDNN_INCLUDE_DIR=/usr/include \
-D CUDA_CUDA_LIBRARY=/usr/lib/x86_64-linux-gnu/libcuda.so.535.43.02 \
-D OPENCV_PYTHON3_INSTALL_PATH=/home/funnywii/Anaconda3/lib/python3.10/site-packages \
-D WITH_WEBP=OFF \
-D WITH_OPENCL=OFF \
-D ETHASHLCL=OFF \
-D ENABLE_CXX11=ON \
-D BUILD_EXAMPLES=OFF \
-D WITH_OPENGL=ON \
-D WITH_GSTREAMER=ON \
-D WITH_V4L=ON \
-D WITH_QT=OFF \
-D BUILD_opencv_python2=OFF \
-D HAVE_opencv_python3=ON ..

参考文章

[1] OpenCV 编译添加 FFmpeg 支持

[2] Ubuntu 编译 OpenCV 添加 FFmpeg 支持

[3] LinusCDE/mad-jetson-ffmpeg

[4] jocover/jetson-ffmpeg