OpenCV4.7.0、FFmpeg5.1 Nvidia GPU视频硬解码

2024-01-11 22:59

本文主要是介绍OpenCV4.7.0、FFmpeg5.1 Nvidia GPU视频硬解码,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

1.环境

操作系统:Ubuntu18.04

GPU:Nvidia GeForce RTX 2080TI

2.安装2080TI驱动

请参考文章(158条消息) NVIDIA-GPU 驱动程序安装_洪流之源的博客-CSDN博客

3.安装cuda

请参考文章(158条消息) CUDA安装与卸载_洪流之源的博客-CSDN博客

4.安装cudnn

请参考文章(158条消息) cuDNN安装_洪流之源的博客-CSDN博客

5.安装nvidia-video-codec-sdk

nvidia-video-codec-sdk下载链接如下:

https://developer.nvidia.com/nvidia-video-codec-sdk/download

下载得到Video_Codec_SDK_12.0.16.zip的压缩包,解压后的目录有Read_Me.pdf文档,文档中有该版本SDK对驱动与CUDA最低版本的要求,比如12.0版本要求如下:

如果驱动版本或者CUDA不满足要求,可更新版本或者下载更低版本的nvidia-video-codec-sdk。

接下来安装nvidia-video-codec-sdk,其实在GPU驱动安装过程中,已经将nvidai-video-codec-sdk的库文件进行了安装,一般安装在/usr/lib/x86_64-linux-gnu/目录下,比如525.89.02版本的GPU驱动安装后,在/usr/lib/x86_64-linux-gnu/目录下存在libnvcuvid.so.525.89.02、libnvidia-encode.so.525.89.02的库文件。因此只需要安装头文件即可,如下命令将头文件拷贝至cuda/目录:

cp Video_Codec_SDK_12.0.16/Interface/* /usr/local/cuda/include/

注:上述只用了nvidia-video-codec-sdk中的头文件,而没有使用nvidia-video-codec-sdk中的libnvcuvid.so、libnvidia-encode.so库,原因是在安装显卡驱动的时候会默认安装与驱动版本兼容的libnvcuvid.so、libnvidia-encode.so,而nvidia-video-codec-sdk中的库很可能与我们安装的显卡驱动版本不一致,如果使用了nvidia-video-codec-sdk中的libnvcuvid.so、ibnvidia-encode.so编译的时候,可能不会有问题,但是运行时很可能会因为与驱动版本不兼容而报错,因为,拒绝使用nvidia-video-codec-sdk中的libnvcuvid.so、ibnvidia-encode.so库。这个可谓是Nvidia的天坑,一定要注意。

6.编译FFmpeg

opencv硬解码依赖nvidia-video-codec-sdk,如果不安装ffmpeg也不会影响opencv的硬解码,但是opencv软解码依赖ffmpeg,如果未安装ffmpeg的话,opencv无法进行软解码,因此为了保证opencv既能硬解码也能软件,接下来也安装ffmpeg,并且提供了ffmpeg英伟达硬解码的编译方式进行安装,这样ffmpeg也可通过Nvidia GPU进行硬解码。

安装依赖

sudo apt update
sudo apt install autoconf \
automake \
build-essential \
cmake \
git-core \
libass-dev \
libfreetype6-dev \
libgnutls28-dev \
libsdl2-dev \
libtool \
libva-dev \
libvdpau-dev \
libvorbis-dev \
libxcb1-dev \
libxcb-shm0-dev \
libxcb-xfixes0-dev \
pkg-config \
texinfo \
wget \
yasm \
zlib1g-dev

注意:

如果要在docker中编译ffmpeg nvidia硬解码,需要将在安装显卡驱动的时候安装的libnvcuvid.so、libnvidia-encode.so库,从宿主机拷贝到docker中,这两个库在宿主机的路径一般在/usr/lib/x86_64-linux-gnu/目录下,可提前将上述两个库拷贝至docker中,然后拷贝到docker的/lib64目录下,(一定要从宿主机目录进行拷贝,不要使用Video_Codec_SDK中的库,因为Video_Codec_SDK中的库很可能与本机安装的驱动不匹配,即便编译通过,但是运行时会出现驱动不兼容的问题)比如两个库是libnvcuvid.so.525.89.02、libnvidia-encode.so.525.89.02,在docker中操作如下:

cp libnvcuvid.so.525.89.02 /lib64/
cp libnvidia-encode.so.525.89.02 /lib64/
ln -s /lib64/libnvcuvid.so.525.89.02 /lib64/libnvcuvid.so.1
ln -s /lib64/libnvidia-encode.so.525.89.02 /lib64/libnvidia-encode.so.1
echo '/lib64' >> /etc/ld.so.conf
ldconfig

下载FFMPEG

考虑到opencv4.7.0开始支持ffmpeg5.x版本,因此下载了ffmpeg 5.1版本:

git clone https://github.com/FFmpeg/FFmpeg.git -b release/5.1

克隆ffnvcodec

ffnvcodec是ffmpeg英伟达硬解码的头文件,需要下载

git clone https://git.videolan.org/git/ffmpeg/nv-codec-headers.git

下载的nv-codec-header目录下有README的文件,内容如下:

这个文件中指明了当前的nv-codec-header需要与Video Code SDK 12.0.6匹配(Video Code SDK即为上述下载的nvidia-video-codec-sdk,上述下载的也为12.0.6版本,满足要求),以及需要的最低驱动版本,如果驱动版本不满足要求,可更新驱动版本。

安装 ffnvcodec:

cd nv-codec-headers && sudo make install

编译ffmpeg脚本如下:

#!/bin/bash./configure --enable-nonfree --enable-cuda-nvcc --enable-libnpp --extra-cflags=-I/usr/local/cuda/include --extra-ldflags=-L/usr/local/cuda/lib64 --disable-static --enable-sharedmake -j$(nproc)sudo make installecho '/usr/local/ffmpeg/lib' >> /etc/ld.so.confldconfig

测试ffmpeg硬解码支持:

分别执行如下两条命令,查看ffmpeg硬件访问与cuvid解码器:

ffmpeg -hwaccels
ffmpeg -codecs | grep cuvid

如下:

测试硬解码,执行如下命令:

ffmpeg -y -vsync 0 -hwaccel cuda -hwaccel_output_format cuda -extra_hw_frames 5 -i 1.mp4 -c:a copy -c:v h264_nvenc -b:v 5M output.mp4

在执行上述命令的过程中,出现如下报错:

不清楚是什么原因导致的,但是好在依然能够正常解码,如果有知道原因的同学,可留言告知。

7.编译OpenCV

opencv的编译请参考文章(163条消息) Ubuntu20.04 编译opencv-4.5.0与opencv-contrib-4.5.0_洪流之源的博客-CSDN博客,中的1、2、3步骤。

假定你已经按照上述文章,执行了1、2、3步骤(注意opencv的源码都要换成4.7.0版本),接下来进行如下步骤:

安装Qt依赖

后续cmake配置命令开启了WITH_OPENGL选项,但是单纯的开启这个选项并不能真正的进行OPENGL的编译,需要安装Qt,因为OPENGL的编译依赖Qt,如果系统没有安装Qt,即便开启了OPENGL编译选项,因为找不到Qt,也不会进行OPENGL的编译,Qt的安装比较简单,如果安装Qt5,可直接执行如下命令:

sudo apt install qt5-default

配置cmake

因为Nvidia GPU是2080TI,需要设置CUDA_ARCH_BIN=7.5,如果是其它型号的GPU可在如下链接进行查询:

https://developer.nvidia.com/zh-cn/cuda-gpus#compute

配置命令如下:

mkdir build
cd build
cmake -D CMAKE_BUILD_TYPE=RELEASE \-D CMAKE_INSTALL_PREFIX=install \-D WITH_TBB=ON \-D BUILD_TBB=ON  \-D ENABLE_FAST_MATH=1 \-D CUDA_FAST_MATH=1 \-D WITH_CUBLAS=1 \-D WITH_V4L=ON \-D WITH_LIBV4L=ON \-D WITH_CUDA=ON \-D WITH_CUDNN=ON \-D WITH_CUDEV=ON \-D WITH_GTK_2_X=ON \-D WITH_NVCUVID=ON \-D CUDA_ARCH_BIN=7.5 \-D OPENCV_EXTRA_MODULES_PATH=../opencv_contrib-4.7.0/modules \-D WITH_QT=ON \-D WITH_OPENGL=ON \-D WITH_FFMPEG=ON \..

配置完成后,注意如下红框配置选项是否为“YES",否则可能之前的依赖选项有问题,需要重新安装依赖,重新配置:

opencv是否支持Nvidia GPU硬解码,注意如下红框选项一定要是“YES”,并且NVIDIA CUDA选项括号中必须包含NVCUVID NVCUENV,否则编译出的opencv用Nvidia GPU硬解码时会报错:

注:如果NVDIA CUDA不包含NVCUVID NVCUENV的选项,考虑是不是没有把libnvcuvid.so、libnvidia-encode.so追加到库的搜索路径路径下,一般docker环境中会出现这种问题,可从宿主机/usr/lib/x86_64-linux-gnu目录下拷贝上述的库(一定要从宿主机目录进行拷贝,不要使用Video_Codec_SDK中的库,因为Video_Codec_SDK中的库很可能与本机安装的驱动不匹配,即便编译通过,但是运行时会出现驱动不兼容的问题),比如libnvcuvid.so.525.89.02、libnvidia-encode.so.525.89.02拷贝到docker中的/usr/lib/x86_64-linux-gnu目录下,并创建软连接,创建软连接脚本如下:

#!/bin/bashsopath=/usr/lib/x86_64-linux-gnuif [ ! -L ${sopath}/libcuda.so ]; thenfiles=(`find $sopath/libcuda.so*`)raw_so=${files[0]}echo Create soft link ${raw_so}ln -s ${raw_so} ${sopath}/libcuda.so
fiif [ ! -L ${sopath}/libnvcuvid.so ]; thenecho Create soft link ${sopath}/libnvcuvid.so.1ln -s ${sopath}/libnvcuvid.so.1 ${sopath}/libnvcuvid.so
fiif [ ! -L ${sopath}/libnvidia-encode.so ]; thenecho Create soft link ${sopath}/libnvidia-encode.so.1ln -s ${sopath}/libnvidia-encode.so.1 ${sopath}/libnvidia-encode.so
fi
ldconfig

配置完成后,分别执行如下命令编译、安装

make -j$(nproc)make install

8. 测试opencv 硬解码与软件

代码如下:

#include <opencv2/opencv.hpp>
#include <opencv2/cudacodec.hpp>
#include <chrono>int gpu_test() 
{cv::cuda::printCudaDeviceInfo(cv::cuda::getDevice());int count = cv::cuda::getCudaEnabledDeviceCount();printf("GPU Device Count : %d \n", count);const std::string filename = "videos/1.mp4";// const std::string filename = "rtsp://172.17.0.1:554/1.mp4";cv::Ptr<cv::cudacodec::VideoReader> reader = cv::cudacodec::createVideoReader(filename);cv::cuda::GpuMat gpu_frame;int frame_id = 0;std::chrono::steady_clock::time_point start = std::chrono::steady_clock::now();while (reader->nextFrame(gpu_frame)) {frame_id = frame_id + 1;}std::chrono::steady_clock::time_point end = std::chrono::steady_clock::now();std::chrono::duration<double> time_useds = std::chrono::duration_cast<std::chrono::duration<double>>(end - start);double time_ms = time_useds.count() * 1000.0f;double fps = double(frame_id) / time_ms * 1000.0f;printf("GPU test took time: %f ms, frames: %d , FPS: %f\n", time_ms, frame_id, fps);reader.release();return 0;
}int cpu_test()
{const std::string filename = "videos/1.mp4";// const std::string filename = "rtsp://172.17.0.1:554/1.mp4";cv::VideoCapture capture;capture.open(filename);if (!capture.isOpened()){printf("Open video failed !!! \n");return -1;}int width = (int)capture.get(cv::CAP_PROP_FRAME_WIDTH);int height = (int)capture.get(cv::CAP_PROP_FRAME_HEIGHT);printf("src video width: %d , %d \n", width, height);cv::Mat frame;int frame_id = 0;std::chrono::steady_clock::time_point start = std::chrono::steady_clock::now();while (capture.read(frame)){frame_id = frame_id + 1;}std::chrono::steady_clock::time_point end = std::chrono::steady_clock::now();std::chrono::duration<double> time_useds = std::chrono::duration_cast<std::chrono::duration<double>>(end - start);double time_ms = time_useds.count() * 1000.0f;double fps = double(frame_id) / time_ms * 1000.0f;printf("CPU test took time: %f ms, frames: %d , FPS: %f\n", time_ms, frame_id, fps);capture.release();return 0;
}int main(int argc, char const *argv[])
{gpu_test();cpu_test();return 0;
}

CMakeLists.txt:

cmake_minimum_required(VERSION 3.4)project(MoveDetection)set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g -fPIC -O3 -std=c++11")include_directories(opencv/include/opencv4
)link_directories(opencv/lib
)set(OPENCV_LIBSopencv_coreopencv_highguiopencv_imgprocopencv_imgcodecsopencv_videoopencv_videoioopencv_cudaimgprocopencv_cudacodecopencv_cudafiltersopencv_cudabgsegmopencv_cudaarithmopencv_cudawarpingopencv_gapi
)add_executable(pro  src/main.cpp)target_link_libraries(pro${OPENCV_LIBS}
)

测试结果:

1920x1080分辨率的视频,GPU解码帧率是1565FPS,CPU解码帧率是441FPS,GPU解码效率是CPU的4倍。

这篇关于OpenCV4.7.0、FFmpeg5.1 Nvidia GPU视频硬解码的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/595986

相关文章

conda安装GPU版pytorch默认却是cpu版本

《conda安装GPU版pytorch默认却是cpu版本》本文主要介绍了遇到Conda安装PyTorchGPU版本却默认安装CPU的问题,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的... 目录一、问题描述二、网上解决方案罗列【此节为反面方案罗列!!!】三、发现的根本原因[独家]3.1 p

如何在Ubuntu上安装NVIDIA显卡驱动? Ubuntu安装英伟达显卡驱动教程

《如何在Ubuntu上安装NVIDIA显卡驱动?Ubuntu安装英伟达显卡驱动教程》Windows系统不同,Linux系统通常不会自动安装专有显卡驱动,今天我们就来看看Ubuntu系统安装英伟达显卡... 对于使用NVIDIA显卡的Ubuntu用户来说,正确安装显卡驱动是获得最佳图形性能的关键。与Windo

判断PyTorch是GPU版还是CPU版的方法小结

《判断PyTorch是GPU版还是CPU版的方法小结》PyTorch作为当前最流行的深度学习框架之一,支持在CPU和GPU(NVIDIACUDA)上运行,所以对于深度学习开发者来说,正确识别PyTor... 目录前言为什么需要区分GPU和CPU版本?性能差异硬件要求如何检查PyTorch版本?方法1:使用命

基于Python和MoviePy实现照片管理和视频合成工具

《基于Python和MoviePy实现照片管理和视频合成工具》在这篇博客中,我们将详细剖析一个基于Python的图形界面应用程序,该程序使用wxPython构建用户界面,并结合MoviePy、Pill... 目录引言项目概述代码结构分析1. 导入和依赖2. 主类:PhotoManager初始化方法:__in

Python使用自带的base64库进行base64编码和解码

《Python使用自带的base64库进行base64编码和解码》在Python中,处理数据的编码和解码是数据传输和存储中非常普遍的需求,其中,Base64是一种常用的编码方案,本文我将详细介绍如何使... 目录引言使用python的base64库进行编码和解码编码函数解码函数Base64编码的应用场景注意

用js控制视频播放进度基本示例代码

《用js控制视频播放进度基本示例代码》写前端的时候,很多的时候是需要支持要网页视频播放的功能,下面这篇文章主要给大家介绍了关于用js控制视频播放进度的相关资料,文中通过代码介绍的非常详细,需要的朋友可... 目录前言html部分:JavaScript部分:注意:总结前言在javascript中控制视频播放

Python基于wxPython和FFmpeg开发一个视频标签工具

《Python基于wxPython和FFmpeg开发一个视频标签工具》在当今数字媒体时代,视频内容的管理和标记变得越来越重要,无论是研究人员需要对实验视频进行时间点标记,还是个人用户希望对家庭视频进行... 目录引言1. 应用概述2. 技术栈分析2.1 核心库和模块2.2 wxpython作为GUI选择的优

Java如何获取视频文件的视频时长

《Java如何获取视频文件的视频时长》文章介绍了如何使用Java获取视频文件的视频时长,包括导入maven依赖和代码案例,同时,也讨论了在运行过程中遇到的SLF4J加载问题,并给出了解决方案... 目录Java获取视频文件的视频时长1、导入maven依赖2、代码案例3、SLF4J: Failed to lo

Python实现多路视频多窗口播放功能

《Python实现多路视频多窗口播放功能》这篇文章主要为大家详细介绍了Python实现多路视频多窗口播放功能的相关知识,文中的示例代码讲解详细,有需要的小伙伴可以跟随小编一起学习一下... 目录一、python实现多路视频播放功能二、代码实现三、打包代码实现总结一、python实现多路视频播放功能服务端开

Python实现视频转换为音频的方法详解

《Python实现视频转换为音频的方法详解》这篇文章主要为大家详细Python如何将视频转换为音频并将音频文件保存到特定文件夹下,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录1. python需求的任务2. Python代码的实现3. 代码修改的位置4. 运行结果5. 注意事项