为OpenCV启用NVIDIA GPU加速视频解码
将CPU从高负载中解放出来
如今CPU的多媒体运算能力今非昔比,但是在某些特定场景下,还是需要将视频解码这样的“重活”分担给GPU去做。这篇文章记载了为OpenCV启用GPU加速解码的过程。
硬件与环境
- GPU: Nvidia RTX 20/30系列
- OS: Ubuntu 20.04
- CUDA: 11.3
- OpenCV: 4.5.4
在正式开始之前,请确保安装了合适的驱动程序与CUDA。
实现硬件加速的整个过程大致可以分为三个阶段。
第一,编译启用CUDA支持的FFMPEG
OpenCV本身没有视频解码能力,它依赖第三方库来实现这一功能。在Linux下最常用的为FFMPEG。所以,首先要为FFMPEG启用GPU加速。
NVIDIA在官网提供了FFMPEG编译指南:
按照该指南,你需要首先安装FFMPEG解码头文件。
git clone -b sdk/11.0 --depth 1 https://git.videolan.org/git/ffmpeg/nv-codec-headers.git
cd nv-codec-headers && sudo make install && cd –然后获取FFMPEG源代码。注意OpenCV对FFMPEG有版本要求。我当前测试通过的版本为4.3.3。下方是官方给出的示例,我推荐自行获取指定版本的源码。
git clone -b n4.3.3 --depth 1 https://git.ffmpeg.org/ffmpeg.git ffmpeg/正式编译前,安装必要的依赖项。
sudo apt-get install build-essential pkg-config yasm cmake libtool libc6 libc6-dev unzip wget libnuma1 libnuma-dev libx264-dev libx265-dev然后开始配置编译选项。这里的选项是我根据Nvidia与FFMPEG的指南合并得到的。
./configure \
--prefix=/usr/local \ # 指定安装位置
--extra-cflags=-I/usr/local/cuda/include \
--extra-ldflags=-L/usr/local/cuda/lib64 \
--extra-libs=-lpthread \
--disable-static --enable-shared --enable-pic \ # 编译动态库
--disable-ffplay \ # 服务器端可以省略显示功能
--disable-doc \ # 省略文档
--enable-cuda --enable-cuvid --enable-nvenc \ # 启用NVIDIA加速
--enable-libx264 --enable-libx265 \ # 启用H264/265支持
--enable-gpl --enable-nonfree配置完成后,开始编译。
make -j 8编译完成后,安装到系统目录。
sudo make install手动执行下ldconfig。
sudo ldconfig至此第一步结束。
第二步,编译启用CUDA支持的OpenCV
首先获取源码,注意除了 opencv 外,你还需要 opencv-contrib 模块。如果通过git获取源码,检出对应的tag 4.5.4。这个是我测试通过的版本。
获取源码后,使用cmake配置编译选项。如果条件允许,可以使用cmake-gui,更加方便。
使用cmake-gui
除了常规的配置,启用GPU支持需要开启以下选项。
- 额外模块位置,对应cmake选项名
OPENCV_EXTRA_MODULES_PATH。 - 开启CUDA支持,对应cmake选项
WITH_CUDA。
此时按下 configure ,执行第一次配置。
第一次配置完成后,需要手动启用硬件加速解码,对应cmake选项 WITH_NVCUVID 。
然后再次按下 configure ,完成第二次配置。
到这一步不应有任何报错。如果有错误需要按照提示修复后继续。
最后按下 generate 生成makefile,退出cmake,并开始编译OpenCV。
make -j 8使用cmake
# 源码
OPENCV_SRC=/home/robin/download/opencv-4.5.4
# 额外组件
OPENCV_EXTRA_MODULES=/home/robin/download/opencv_contrib-4.5.4/modules
# 下载缓存地址
DOPENCV_DOWNLOAD_PATH=/home/robin/download/opencv_dependencies-4.5.4
# 安装目录
PREFIX=/home/robin/download/opencv-install
# 配置
mkdir opencv-build && cd opencv-build
cmake \
-DCMAKE_INSTALL_PREFIX=${PREFIX} \
-DOPENCV_EXTRA_MODULES_PATH=${OPENCV_EXTRA_MODULES} \
-DOPENCV_DOWNLOAD_PATH=${DOPENCV_DOWNLOAD_PATH} \
-DWITH_CUDA=ON \
-DWITH_NVCUVID=ON \
-DCUDA_ARCH_BIN=6.0,6.1,7.0,7.5,8.0,8.6 \
-DBUILD_opencv_highgui=OFF \
-DWITH_GTK=OFF \
-DHIGHGUI_ENABLE_PLUGINS=OFF \
${OPENCV_SRC}
# 构建
make -j12
# 安装
make install
第三步,配置环境变量
在你的Python代码中添加环境变量强制启用GPU解码。
import os
os.environ["OPENCV_FFMPEG_CAPTURE_OPTIONS"]="hw_decoders_any;cuda"
import cv2
cap = cv2.VideoCapture("input.mp4",
apiPreference=cv2.CAP_FFMPEG,
params=[cv2.CAP_PROP_HW_ACCELERATION, cv2.VIDEO_ACCELERATION_ANY]))
while True:
r, img = cap.read()
if r is False:
break
cv2.imshow('preview', img)
cv2.waitKey(27)在解码视频时,可以使用 nvidia-smi 工具查看硬件状况:
watch -n1 nvidia-smi -q --display=UTILIZATION显示示例如下:
Attached GPUs : 1
GPU 00000000:01:00.0
Utilization
Gpu : 2 %
Memory : 0 %
Encoder : 0 %
Decoder : 2 %其中的 Decoder 即为解码器利用率。
总结
我实际测试中发现,在未启用GPU解码加速时,OpenCV会把视频解码任务分配给CPU的多个核心执行,一路全高清视频占用CPU资源合计约300%,FPS大约为500。在启用GPU加速后,运算被限制在一个核心,CPU的利用率100%。此时GPU的利用率约5%。FPS大约为170。所以,如何将硬件资源的利用最大化,还需要视具体任务合理分配。
以上就是全部内容。如果你有其它需求,可以参考下FFMPEG的编译指南:

祝解码顺利!
有AI相关的想法,但不知道怎么落地?
我是国冰,独立AI开发者。十多年技术一线——半导体显示、智慧城市到自动驾驶;现在一个人+AI,接AI落地项目,从梳理需求到系统落地,陪你走通。
看我能做什么
评论 ()