提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档

文章目录

  • 系统配置
  • 前言`
  • 一、NVCODEC是什么?
  • 二、OpenCV编译
    • 1.安装Driver&CUDA
    • 2.编译OpenCV
  • 总结

系统配置

操作系统:Ubuntu18.04
硬件架构:x86_64
OpenCV:4.5.1
FFmpeg:4.4.2
CUDA:11.2

前言`

最近遇到一个新项目,AI推理在CUDA上,为了方便和节省成本的考虑决定研究下NVCODEC模块。根据NVIDIA官网的说法显卡具有独立的编码解码模块,所以理论上编码解码是独立互不干涉的。以前的项目都只是把显卡当成推理工具,没有将它的编解码功能利用起来,本身也是一种浪费。事实真的有这么丝滑吗?看到这里,如果你真的觉得黄一刀是白叫的那就真的是too young to simple了,事实究竟如何,请听我娓娓道来。


一、NVCODEC是什么?

NVCODEC全称是 NVIDIA VIDEO CODEC,是NVIDIA为绝大多数显卡配置的硬件编解码单元。不一定是所有显卡都有,一般来讲越新的显卡硬件编解码就越强,支持的格式也就越新。比如,拿消费端的显卡来讲,只有RTX3000以上的显卡才支持AV1这种新格式,像RTX2000以下的显卡目前无缘。当然以后还有可能会出更多格式。目前我所知道的NVIDIA解码支持两种方式:

1、NVCODEC编解码

这种解码方式是我们这篇文章要讲的主角,也就是硬件编解码。这里的硬件编解码指的是利用专门运算单元来完成编解码过程,这种专门运算单元被设计出来就是固定只干这一种活的硬件,跟软解码最大的差别是,软编解码是利用通用运算单元硬算

2、CUDA编解码
通常情况下CUDA是拿来做AI推理的,但是有些特殊情况下CUDA也是可以直接拿来编解码的,这个时候CUDA就是通用运算单元了,因为它不是专门设计来做编解码工作的,属于被迫上岗。

我们看看NVIDIA自己怎么介绍自家的东西的:

NVIDIA GPUs contain one or more hardware-based decoder and encoder(s) (separate from the CUDA cores) which provides fully-accelerated hardware-based video decoding and encoding for several popular codecs. With decoding/encoding offloaded, the graphics engine and the CPU are free for other operations.

GPU hardware accelerator engines for video decoding (referred to as NVDEC) and video encoding (referred to as NVENC) support faster than real-time video processing which makes them suitable to be used for transcoding applications, in addition to video playback.


从上图我们看出,CUDA编解码是独立的硬件,所以他们是分别独立工作的,不会相互干扰。

好了,闲话已经说的差不多了,接下来我们进入正题。将opencvnvcodec结合起来完成视频的解码,并将解码后的GpuMat送入CUDA推理。

二、OpenCV编译

1.安装Driver&CUDA

这个地方要重点讲一下,安装CUDA的时候是可以顺手把Driver装上的,这里我推荐用这种方式,因为这种方式安装的驱动自带NVCODEC的库和头文件,这样的话我们就不用专门去下载NVIDIA VIDEO CODEC SDK了。而且我发现NVIDIA VIDEO CODEC SDKDriver有版本依赖,弄不好会出各种奇葩问题。所以,这里讲的所有教程都是基于同时安装CUDA+Driver的,至于怎么安装CUDADriver请大家自行搜索教程,由于篇幅有限这里不做详述。

驱动安装好之后需要检验是否正确,如果Driver安装正确执行nvidia-smi会出现Driver的详细信息,如下图所示:

这里我们说说最关键的两个信息Driver Version:460.27.04,这个意思是你安装的显卡驱动版本是460.27.04CUDA Version:11.2,这个的意思是和Driver配套的CUDA版本是11.2,就算你不装CUDA这个信息也会显示的。我建议你接受它的建议,就装那个版本的·CUDA·,除非有特殊需要,你就需要去NVIDIA的官网查询下具体支持的CUDA版本了。众所周知,DriverCUDA版本是存在依赖关系的,乱装是要出事情的。

接下来验证CUDA是不是装好了,命令行输入nvcc -V会看到以下的提示信息,说明CUDA安装成功了,

nvcc: NVIDIA (R) Cuda compiler driver
Copyright (c) 2005-2020 NVIDIA Corporation
Built on Mon_Nov_30_19:08:53_PST_2020
Cuda compilation tools, release 11.2, V11.2.67
Build cuda_11.2.r11.2/compiler.29373293_0

如果报了类似于command not fount一类的错误就说明CUDA没有装对或者环境变量没配置对,请检查下操作是否正确。

差点忘了,CuDNN也是需要的,千万别忘了装。CuDNN的验证比较简单,那就是不需要验证,你从官网下载3个deb包全部成功安装后就说明CuDNN安装成功了,不要有所怀疑。

2.编译OpenCV

下载opencv源代码这一步就不赘述了,这里我下载的是opencv-4.5.1.zip或者opencv-4.5.1.tar.gz两个包本质没有差别,只是压缩方式有差别罢了,没有影响。我们这里是需要opencv_contrib的,所以需要下载opencv_contrib-4.5.1.zipopencv_contrib-4.5.1.tar.gz,这两个压缩包也是一样的,一样用。

在这里要特别注意下opencv和opencv_contrib是有版本对应关系的,不能下错。

opencv的编译我不在这里详述了,网络上一抓一大把,这里我贴出来我的配置。

cmake -D CMAKE_BUILD_TYPE=RELEASE \-D CMAKE_INSTALL_PREFIX=/usr/local \-D ENABLE_PRECOMPILED_HEADERS=OFF \-D INSTALL_C_EXAMPLES=OFF \-D INSTALL_PYTHON_EXAMPLES=OFF \-D BUILD_opencv_python2=OFF \-D BUILD_opencv_python3=ON \-D PYTHON_DEFAULT_EXECUTABLE=$(python3 -c "import sys; print(sys.executable)")   \-D PYTHON3_EXECUTABLE=$(python3 -c "import sys; print(sys.executable)")   \-D PYTHON3_NUMPY_INCLUDE_DIRS=$(python3 -c "import numpy; print (numpy.get_include())") \-D PYTHON3_PACKAGES_PATH=$(python3 -c "from distutils.sysconfig import get_python_lib; print(get_python_lib())") \-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_GTK_2_X=ON \-D WITH_NVCUVID=ON \-D WITH_OPENGL=ON \-D WITH_FFMPEG=ON  \-D CUDA_ARCH_BIN=7.5 \-D OPENCV_EXTRA_MODULES_PATH=../../opencv_contrib-4.5.1/modules .

由于这里我用到了python cv2所以我编译了python模块。我的需求里面有拉流的需要,编译了ffmpeg模块。CUDA_ARCH_BIN=7.5不同的显卡不一样,我的显卡是RTX2080Ti,我是7.5,具体值都可以在NVIDIA官网查到。WITH_NVCUVID=ON这个一定要加上,这个就是编解码模块。

友情提示:
有个问题需要特别注意下,这种方式OpenCV是找不到NVCUVID的,原因是以前NVCUVIDCUDA放在一起的,后来NVIDIANVCUVID独立出来了,OpenCV的检测方式还是老的方式,所以找不到NVCUVID,解决方法也很简单,你只需要到opencv-4.5.1/cmake文件夹里找到OpenCVDetectCUDA.cmake

  if(WITH_NVCUVID)macro(ocv_cuda_SEARCH_NVCUVID_HEADER _filename _result)# place header file under CUDA_TOOLKIT_TARGET_DIR or CUDA_TOOLKIT_ROOT_DIRfind_path(_header_result${_filename}PATHS "${CUDA_TOOLKIT_TARGET_DIR}" "${CUDA_TOOLKIT_ROOT_DIR}"ENV CUDA_PATHENV CUDA_INC_PATHPATH_SUFFIXES includeNO_DEFAULT_PATH)if("x${_header_result}" STREQUAL "x_header_result-NOTFOUND")set(${_result} 0)else()set(${_result} 1)endif()unset(_header_result CACHE)endmacro()ocv_cuda_SEARCH_NVCUVID_HEADER("nvcuvid.h" HAVE_NVCUVID_HEADER)ocv_cuda_SEARCH_NVCUVID_HEADER("dynlink_nvcuvid.h" HAVE_DYNLINK_NVCUVID_HEADER)find_cuda_helper_libs(nvcuvid)if(WIN32)find_cuda_helper_libs(nvcuvenc)endif()if(CUDA_nvcuvid_LIBRARY AND (${HAVE_NVCUVID_HEADER} OR ${HAVE_DYNLINK_NVCUVID_HEADER}))# make sure to have both header and library before enablingset(HAVE_NVCUVID 1)endif()if(CUDA_nvcuvenc_LIBRARY)set(HAVE_NVCUVENC 1)endif()endif()

注意这一句

PATHS "${CUDA_TOOLKIT_TARGET_DIR}" "${CUDA_TOOLKIT_ROOT_DIR}"

是不是感觉很熟悉,这就是CUDA的安装目录,由于现在NVCUVIDCUDA不在一个目录了,所以只需要改成下面这样

PATHS "${CUDA_TOOLKIT_TARGET_DIR}" "${CUDA_TOOLKIT_ROOT_DIR}" "/usr/include"

/usr/include是NVCUVID的头文件位置,你的在哪里就写什么目录就行了,改完执行cmake配置

如果cmake出错就缺什么安装什么就行了,这个我是亲身体验的,没有问题的。假如没有任何错误,你看到的应该是这样的:

Video I/O:DC1394:                      NOFFMPEG:                      YESavcodec:                   YES (58.134.100)avformat:                  YES (58.76.100)avutil:                    YES (56.70.100)swscale:                   YES (5.9.100)avresample:                YES (4.0.0)GStreamer:                   YES (1.14.5)v4l/v4l2:                    YES (linux/videodev2.h)
NVIDIA CUDA:                   YES (ver 11.2, CUFFT CUBLAS NVCUVID FAST_MATH)NVIDIA GPU arch:             75NVIDIA PTX archs:cuDNN:                         YES (ver 8.1.0)Python 3:Interpreter:                 /usr/bin/python3 (ver 3.6.9)Libraries:                   /usr/lib/x86_64-linux-gnu/libpython3.6m.so (ver 3.6.9)numpy:                       /usr/local/lib/python3.6/dist-packages/numpy/core/include (ver 1.19.5)install path:                /usr/lib/python3/dist-packages/cv2/python-3.6Python (for build):            /usr/bin/python3

FFMPEG一定都要是YES,不能是NONVIDIA CUDA: YES (ver 11.2, CUFFT CUBLAS NVCUVID FAST_MATH)这一行一定要有NVCUVID ,不然就是错误了。配置好后执行make -j$(nproc)等待编译完成执行sudo make install就可以了。这里有个地方需要注意,一定要把旧的opencv卸载干净,不然就会引发冲突或者未知错误。

注:ffmpeg的安装可以参考这篇文章
解决opencv源代码编译找不到ffmpeg

到这里我们的教程就算完了,如果一切顺利的话就可以使用NVCODEC来处理视频流了,RTSP格式的实时视频也是支持的,取出来的帧保存在GpuMat里面,可以送进去推理了。实测CPU解码帧率只有30左右(和CPU性能相关),GPU解码帧率7600多(和解码器性能相关),差距还是蛮大的。下面贴出测试代码:

opencv_test.cpp

#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
#include <numeric>
#include "opencv2/opencv_modules.hpp"
#include <opencv2/core/utility.hpp>
#include <opencv2/core.hpp>
#include <opencv2/core/opengl.hpp>
#include <opencv2/cudacodec.hpp>
#include <opencv2/highgui.hpp>int main(int argc, const char* argv[])
{std::cout<<cv::getBuildInformation()<<std::endl;//将这个流改成你自己的const std::string fname = "rtsp://admin:Wat0ne123@10.0.20.249";cv::cuda::setGlDevice();//cv::cuda::setGlDevice(1);cv::Mat frame;cv::VideoCapture reader(fname);cv::cuda::GpuMat d_frame;cv::Ptr<cv::cudacodec::VideoReader> d_reader = cv::cudacodec::createVideoReader(fname);cv::TickMeter tm;std::vector<double> cpu_times;std::vector<double> gpu_times;for (int i = 0;i<100;i++){tm.reset(); tm.start();if (!reader.read(frame))break;tm.stop();cpu_times.push_back(tm.getTimeMilli());tm.reset(); tm.start();if (!d_reader->nextFrame(d_frame))break;tm.stop();gpu_times.push_back(tm.getTimeMilli());}if (!cpu_times.empty() && !gpu_times.empty()){std::cout << std::endl << "Results:" << std::endl;std::sort(cpu_times.begin(), cpu_times.end());std::sort(gpu_times.begin(), gpu_times.end());double cpu_avg = std::accumulate(cpu_times.begin(), cpu_times.end(), 0.0) / cpu_times.size();double gpu_avg = std::accumulate(gpu_times.begin(), gpu_times.end(), 0.0) / gpu_times.size();std::cout << "CPU : Avg : " << cpu_avg << " ms FPS : " << 1000.0 / cpu_avg << std::endl;std::cout << "GPU : Avg : " << gpu_avg << " ms FPS : " << 1000.0 / gpu_avg << std::endl;}return 0;
}
// #endif

CMakeLists.txt

cmake_minimum_required(VERSION 3.0.2)
project(opencv_test)
SET(CMAKE_BUILD_TYPE "Debug")
include_directories(include)
find_package( OpenCV REQUIRED )
#find_package(OpenGL REQUIRED)
include_directories(${OpenCV_INCLUDE_DIRS}#${OPENGL_INCLUDE_DIR})
add_executable( opencv_test opencv_test.cpp )
#add_executable( opencv_test gpu_mat.cpp )
target_link_libraries( opencv_test${OpenCV_LIBS}#${OPENGL_LIBRARIES})
mkdir build && cd build
cmake ..
make
./opencv_test

特别说明:

 //默认执行设备,如果是单显卡请忽略,如果多显卡需要指定哪一个设备执行,默认是0cv::cuda::setGlDevice();//cv::cuda::setGlDevice(1);

总结

写到这里不得不感叹下,虽然只有区区几行命令却足足搞了一个星期。期间什么奇葩的错误都遇到了,甚至有些我认为是不必要出现的。

最典型的一个例子就是NVCODEC SDK,很多博主都说要从官网下载然后复制到系统目录,一开始我是这么做的,看起来好像全程没有遇到问题,直到最后一步跑程序的时候,终于所有的错误都来了,甚至遇到的最奇葩的问题是每次执行程序返回的错误码都是不一样的,这种BUG我也是生平仅见。最后甚至连Deiver都需要重新安装来解决。

事实真的如此吗?我真的需要每一步都照抄别人吗?实际上下载的CUDA Driver里面就有NVCODEC的SDK,不需要去官方下。只不过安装位置被从CUDA目录移除出来了,只需要修改opencv的检测方式就行了。

opencv+nvcodec实现视频硬解码相关推荐

  1. MediaCodec在Android视频硬解码组件的应用

    https://yq.aliyun.com/articles/632892 云栖社区> 博客列表> 正文 MediaCodec在Android视频硬解码组件的应用 cheenc 2018- ...

  2. android硬编码封装mp4,【Android 音视频开发打怪升级:音视频硬解码篇】四、音视频解封和封装:生成一个MP4...

    [声 明] 首先,这一系列文章均基于自己的理解和实践,可能有不对的地方,欢迎大家指正. 其次,这是一个入门系列,涉及的知识也仅限于够用,深入的知识网上也有许许多多的博文供大家学习了. 最后,写文章过程 ...

  3. 如何使用ffmpeg为Mac进行视频硬解码/硬编码(在Qt环境)

    如何使用ffmpeg为Mac进行视频硬解码/硬编码(在Qt环境) 科普 前期准备 安装ffmpeg 将ffmpeg的库文件添加到Qt项目的.pro文件中 在源文件用引入头文件 第一步:先查看本机支持哪 ...

  4. 【Android 音视频开发-音视频硬解码篇】1.音视频基础知识

    这是一个入门系列,涉及的知识也仅限于够用. 最后,写文章过程中,会借鉴参考其他人分享的文章,会在文章最后列出,感谢这些作者的分享. 本文你可以了解到 作为开篇的文章,我们先来看看音视频由什么构成的,以 ...

  5. 音视频硬解码篇——音视频基础知识

    时至今日,短视频App可谓是如日中天,一片兴兴向荣.随着短视频的兴起,音视频开发也越来越受到重视,但是由于音视频开发涉及知识面比较广,入门门槛相对较高,让许许多多开发者望而生畏. 一.视频是什么? 不 ...

  6. 全志linux视频硬解码,全志V5人工智能视频处理开发板

    原标题:全志V5人工智能视频处理开发板 一.应用场合 全志V5是一款高性价比的人工智能视频处理开发板. 基于全志V5 V100设计,接口丰富,运行于Linux操作系统. 内置人工智能加速引擎和全志IS ...

  7. 手机视频硬解码和软解码的区别

    在手机评测视频播放能力的时候经常会提到"硬解码"和"软解码",但是很多人不太明白是什么意思,其实问题很简单.大家都知道PC都有CPU和GPU(显卡),在手机上也 ...

  8. [RK3568 Android12] MPP视频硬解码

    1: RK文档中对gstreamer以及插件介绍

  9. ffmpeg + cuda(cuvid) 硬解码+像素格式转换(cpu主导)实战

    注意: VAAPI 是inter gpu 提供的硬编解码接口 VDPAU 是 video decode present api for unix nvdec / ncvid 都是nivida产出的硬解 ...

最新文章

  1. 【云安全与同态加密_调研分析(3)】国内云安全组织及标准——By Me
  2. html点击旋转180,关于点击三角丝滑旋转180度css3 jq处理方法
  3. io读取一个文件再写入socket技术_JAVA中IO与NIO面试题
  4. 操作系统(4) -- 文件管理
  5. oracle startup作用,【学习笔记】Oracle打补丁后startup migrate、startup upgrade区别分析...
  6. ramfs, rootfs and initramfs
  7. list删除重复元素
  8. AndroidStudio_排坑指南_随时更新---Android原生开发工作笔记231
  9. MySQL----获取当前日期当月第一天,最后一天
  10. 2021年5月9日,是第108个母亲节,祝福所有的母亲节日快乐
  11. Struts 2中文件上传
  12. .NET企业级应用架构设计的技术选型
  13. 搞科研身体才是革命的本钱。
  14. JavaScript 启动性能瓶颈分析与解决方案
  15. 诺基亚n1平板电脑刷机教程_诺基亚n1平板电脑刷机教程_诺基亚N1 完整包线刷升级或救砖教程(不分台版;国行)......
  16. 怎么查oa系统的服务器地址,oa系统服务器地址如何查
  17. php 批量上传多个文件,小白浅析PHP中的单文件、多文件、批量上传
  18. HTML5CSS3知识点总结(1)
  19. jQuery简易的购物车
  20. 华丽而实用的Java图表应用

热门文章

  1. HLS:矩阵乘法单元设计与SDK测试
  2. python注册登陆程序_python的简单的登陆和注册功能实现
  3. SharePoint 常用开发工具
  4. python连接传感器_关于树莓派Pi2通过UART连接攀藤G5传感器的python
  5. 关于eclipse项目中项目上直接出现大红感叹号的问题
  6. 中国石油大学《化工设计概论》第一阶段在线作业
  7. 如何查询一个域名的子域名
  8. 用html中表单标签实现QQ登录注册静态页面
  9. 【正点原子FPGA连载】第十二章呼吸灯实验 -摘自【正点原子】新起点之FPGA开发指南_V2.1
  10. drf路由组件Routers