配置编译带cuda版本并支持cudacodec硬编解码opencv库笔记

写这个笔记主要是记录配置编译opencv+cuda+cudacodec的过程核经历,这里面的坑实在太多。
参考文章:https://note.youdao.com/ynoteshare1/index.html?id=700052b0a49301059a34f20a00a830ca&type=note,但这份笔记很多东西没有讲清楚,导致我按照这个笔记配置编译opencv的时候,怎么弄都不能正确的编译处cudacodec,而我需要使用GPU实现编解码,必须得使用这个库。
简单记录过程如下。
基础环境:
1、硬件环境:GPU服务器8张Tesla V100,CPU是12个物理核心,48个逻辑核心
2、软件:docker+nvidia 440+cuda10.2+cudnn
一、基础包安装
按照以上笔记内容,安装好ffmpeg,并配置cuvid硬件编解码(参见我的另一篇文章,这里面也有很多坑)
按照以上笔记内容,配置好基础依赖包(不多说了)
二、配置cmake
    根据以上笔记内容,配置好依赖包后执行cmake,在出来的报告中没有出现NVCUVID,只有CUFFT等内容。先没有在意,开始编译安装,结果运行cv2.cudacodec.createVideoReader()的时候,出现错误,提示没有安装nvcuvid相关的库。由于我是在docker中安装,按照上面笔记的内容,折腾了一番docker中的libnvcuvid.so,libnvidia-encode.so等库文件,重新编译安装,依然没有。
    于是开始网上各种百度,csdn、知乎等到处找资料,所有内容都试过了,没有一个能解决问题,真是头大。冷静下来一想,配置中没有出现NVCUVID,是不是CMakeLists文件中哪里除了问题了?于是查看CMake的运行记录,发现里面果然有一个判断变量HAVE_NVCUVID,配置记录中显示的是0,也就是没有打开NVCUVID选项。可我配置的时候明明指定了 -D WITH_CUDA=ON -D WITH_NVCUVID=ON。 打开opencv的CMakeLists.txt文件,发现第262行有这么一句:
VERIFY HAVE_NVCUVID
第1532行有显示的语句:
IF HAVE_NVCUVID THEN "NVCUVID"
很明显,cmake没有找到NVCUVID。
    进一步跟踪HAVE_NVCUVID变量的判断语句,发现在cmake目录下的OpenCVDetectCUDA.cmake文件中,第74行和75行:
    ocv_cuda_SEARCH_NVCUVID_HEADER("nvcuvid.h" HAVE_NVCUVID_HEADER)
    ocv_cuda_SEARCH_NVCUVID_HEADER("dynlink_nvcuvid.h" HAVE_DYNLINK_NVCUVID_HEADER)
    分别是判断有没有nvcuvid.h和dynlink_nvcuvid.h两个文件。这两个文件第一个位于/usr/include中,第二个位于/usr/local/include/ffnvcodec中(安装nv-codec-headers-sdk-9.1.zip时自动安装到这个位置)。
    跟踪发现HAVE_NVCUVID_HEADER和HAVE_DYNLINK_NVCUVID_HEADER这两个变量都是0,说明cmake没有找对地方。找这两个变量是通过ocv_cuda_SEARCH_NVCUVID_HEADER宏执行的,这个marco在OpenCVDetectCUDA.cmake文件中第57行。该宏中定义搜索路径为第59行到66行:
    find_path(_header_result
        ${_filename}
        PATHS "${CUDA_TOOLKIT_TARGET_DIR}" "${CUDA_TOOLKIT_ROOT_DIR}"
        ENV CUDA_PATH
        ENV CUDA_INC_PATH
        PATH_SUFFIXES include
        NO_DEFAULT_PATH
        )
    路径中显然没有包含这两个文件的目录,于是在PATHS中增加了路径,第61行变成这样:
    PATHS "${CUDA_TOOLKIT_TARGET_DIR}" "${CUDA_TOOLKIT_ROOT_DIR}" "/usr/include" "/usr/local/include/ffnvcodec"
    再次跟踪HAVE_NVCUVID_HEADER和HAVE_DYNLINK_NVCUVID_HEADER,果然都变成了1
    HAVE_NVCUVID变量中还有一个判断,要求CUDA_nvcuvid_LIBRARY变量也必须为1,这个变量定义在cmake/FindCUDA.cmake中,也就是执行cmake时会判断系统中有没有libnvcuvid.so这个库文件,检查/usr/lib/x86_64-linux-gnu下,有libnvcuvid.so.1.440.so(docker中可能不一样)和libnvcuvid.so.1,没有libnvcuvid.so,于是做个软连接
    sudo ln -s /usr/lib/x86_64-linux-gnu/libnvcuvid.so.1 /usr/lib/x86_64-linux-gnu/libnvcuvid.so
    再次跟踪,发现CUDA_nvcuvid_LIBRARY正确指向了该库。
    再次以之前的配置运行cmake,在NVIDIA一拦中果然出现了NVCUVID,至此第一个巨坑顺利躺过。

三、编译
    完成了配置之后,本来以为接下来的都应该很顺利了,哪知道编译到cudacodec库的时候,出现一大堆XXX not declared错误,这是典型的c++头文件没有包含,或者包含的位置不对,导致编译的时候找不到相应的函数。
    进入opencv_contribc/modules/cudacodec目录中,关于cudacodec库的源文件应该都在这个里面,在该目录下的CMakeLists.txt文件中直接添加如下一行:
    include_directories(/usr/local/include/ffnvcodec)
    注意不要在 if(HAVE_NVCUVID)的判断语句中添加,我先在if中添加,发现没起作用,于是直接在外面添加
    再次编译,发现依然报错。看了一下src目录下的源码,发现多半都包含了precomp.hpp这个文件,于是干脆在这个文件中直接添加下面这行
    #inculude
    再次编译,终于顺利通过,成功了!

四、安装以及python
    没什么好说的了,sudo make install,然后把生成的python库cv2.****.so拷贝到当前执行python环境的中的site-packages中,就可以在python中顺利import cv2了。
 

你可能感兴趣的:(opencv,ffmpeg,gpu,cuda)