解决opencv源代码编译找不到ffmpeg

系统环境:

操作系统:Ubuntu18.04
硬件架构:X86_64
OpenCV版本:4.5.1或3.4.16

项目场景:

最近在研究OpenCV结合CUVIDEC解码视频流,就使用OpenCV源代码编译。结果发现无论如何都找不到ffmpeg。经过一系列研究终于找到了原因,记录如下。


问题描述

OpenCV4和OpenCV3编译当选择WITH_FFMPEG选项的时候不能找到ffmpeg模块。


原因分析:

OpenCV-3.4.16和OpenCV-4.5.1两个版本略有差别,这个问题的答案我们可以在OpenCVcmake文件里面找到答案。

先来看看opencv-3.4.16cmake文件,在opencv-3.4.16cmake文件夹下面找到OpenCVFindLibsVideo.cmake

# --- FFMPEG ---
ocv_clear_vars(HAVE_FFMPEG)
if(WITH_FFMPEG)  # try FFmpeg autodetection
  if(OPENCV_FFMPEG_USE_FIND_PACKAGE)
    if(OPENCV_FFMPEG_USE_FIND_PACKAGE STREQUAL "1" OR OPENCV_FFMPEG_USE_FIND_PACKAGE STREQUAL "ON")
      set(OPENCV_FFMPEG_USE_FIND_PACKAGE "FFMPEG")
    endif()
    find_package(${OPENCV_FFMPEG_USE_FIND_PACKAGE}) # Required components: AVCODEC AVFORMAT AVUTIL SWSCALE
    if(FFMPEG_FOUND OR FFmpeg_FOUND)
      set(HAVE_FFMPEG TRUE)
    else()
      message(STATUS "Can't find FFmpeg via find_package(${OPENCV_FFMPEG_USE_FIND_PACKAGE})")
    endif()
  elseif(WIN32 AND NOT ARM AND NOT OPENCV_FFMPEG_SKIP_DOWNLOAD)
    include("${OpenCV_SOURCE_DIR}/3rdparty/ffmpeg/ffmpeg.cmake")
    download_win_ffmpeg(FFMPEG_CMAKE_SCRIPT)
    if(FFMPEG_CMAKE_SCRIPT)
      set(HAVE_FFMPEG TRUE)
      set(HAVE_FFMPEG_WRAPPER 1)
      include("${FFMPEG_CMAKE_SCRIPT}")
    endif()
  elseif(PKG_CONFIG_FOUND)
    ocv_check_modules(FFMPEG libavcodec libavformat libavutil libswscale)
    ocv_check_modules(FFMPEG_libavresample libavresample)
    if(FFMPEG_libavresample_FOUND)
      ocv_append_build_options(FFMPEG FFMPEG_libavresample)
    endif()
  else()
    message(STATUS "Can't find ffmpeg - 'pkg-config' utility is missing")
  endif()
endif()
if(HAVE_FFMPEG
    AND NOT HAVE_FFMPEG_WRAPPER
)
  try_compile(__VALID_FFMPEG
      "${OpenCV_BINARY_DIR}"
      "${OpenCV_SOURCE_DIR}/cmake/checks/ffmpeg_test.cpp"
      CMAKE_FLAGS "-DINCLUDE_DIRECTORIES:STRING=${FFMPEG_INCLUDE_DIRS}"
                  "-DLINK_DIRECTORIES:STRING=${FFMPEG_LIBRARY_DIRS}"
                  "-DLINK_LIBRARIES:STRING=${FFMPEG_LIBRARIES}"
      OUTPUT_VARIABLE TRY_OUT
  )
  if(NOT __VALID_FFMPEG)
    #message(FATAL_ERROR "FFMPEG: test check build log:\n${TRY_OUT}")
    message(STATUS "WARNING: Can't build ffmpeg test code")
    set(HAVE_FFMPEG FALSE)
  else()
    ocv_append_build_options(VIDEOIO FFMPEG)
  endif()
endif()

注意看find_package(${OPENCV_FFMPEG_USE_FIND_PACKAGE})这句,这个是核心,它是通过pkg-config来查找指定的包的,可以把它理解成一个linux包管理器。我们这里不去过多探究它的原理,感兴趣的小伙伴可以私下里拓展下。

这个时候我们打开/usr/lib/x86_64-linux-gnu/pkgconfig这个文件夹下面,这个就是pkg-config的文件夹,里面有libavcodec.pclibavformat.pclibavutil.pc等等.pc文件,所有借助pkg-config查询的包信息都在这里面。

接下来我们看看opencv-4.5.1cmake文件,和opencv-3.4.16不同的是opencv-4.5.1cmake不在OpenCVFindLibsVideo.cmake这个文件里面了,移到了别的地方。还是老样子先去OpenCV官网下载源代码并解压,接着打开opencv-4.5.1/modules/videoio/cmake/detect_ffmpeg.cmake,你会看到以下内容:

# --- FFMPEG ---
if(NOT HAVE_FFMPEG AND OPENCV_FFMPEG_USE_FIND_PACKAGE)
  if(OPENCV_FFMPEG_USE_FIND_PACKAGE STREQUAL "1" OR OPENCV_FFMPEG_USE_FIND_PACKAGE STREQUAL "ON")
    set(OPENCV_FFMPEG_USE_FIND_PACKAGE "FFMPEG")
  endif()
  find_package(${OPENCV_FFMPEG_USE_FIND_PACKAGE}) # Required components: AVCODEC AVFORMAT AVUTIL SWSCALE
  if(FFMPEG_FOUND OR FFmpeg_FOUND)
    set(HAVE_FFMPEG TRUE)
  endif()
endif()

if(NOT HAVE_FFMPEG AND WIN32 AND NOT ARM AND NOT OPENCV_FFMPEG_SKIP_DOWNLOAD)
  include("${OpenCV_SOURCE_DIR}/3rdparty/ffmpeg/ffmpeg.cmake")
  download_win_ffmpeg(FFMPEG_CMAKE_SCRIPT)
  if(FFMPEG_CMAKE_SCRIPT)
    include("${FFMPEG_CMAKE_SCRIPT}")
    set(FFMPEG_libavcodec_VERSION ${FFMPEG_libavcodec_VERSION} PARENT_SCOPE) # info
    set(FFMPEG_libavformat_VERSION ${FFMPEG_libavformat_VERSION} PARENT_SCOPE) # info
    set(FFMPEG_libavutil_VERSION ${FFMPEG_libavutil_VERSION} PARENT_SCOPE) # info
    set(FFMPEG_libswscale_VERSION ${FFMPEG_libswscale_VERSION} PARENT_SCOPE) # info
    set(FFMPEG_libavresample_VERSION ${FFMPEG_libavresample_VERSION} PARENT_SCOPE) # info
    set(HAVE_FFMPEG TRUE)
    set(HAVE_FFMPEG_WRAPPER TRUE)
  endif()
endif()

set(_required_ffmpeg_libraries libavcodec libavformat libavutil libswscale)
set(_used_ffmpeg_libraries ${_required_ffmpeg_libraries})
if(NOT HAVE_FFMPEG AND PKG_CONFIG_FOUND)
  ocv_check_modules(FFMPEG libavcodec libavformat libavutil libswscale)
  if(FFMPEG_FOUND)
    ocv_check_modules(FFMPEG_libavresample libavresample) # optional
    if(FFMPEG_libavresample_FOUND)
      list(APPEND FFMPEG_LIBRARIES ${FFMPEG_libavresample_LIBRARIES})
      list(APPEND _used_ffmpeg_libraries libavresample)
    endif()
    set(HAVE_FFMPEG TRUE)
  else()
    set(_missing_ffmpeg_libraries "")
    foreach (ffmpeg_lib ${_required_ffmpeg_libraries})
      if (NOT FFMPEG_${ffmpeg_lib}_FOUND)
        list(APPEND _missing_ffmpeg_libraries ${ffmpeg_lib})
      endif()
    endforeach ()
    message(STATUS "FFMPEG is disabled. Required libraries: ${_required_ffmpeg_libraries}."
            " Missing libraries: ${_missing_ffmpeg_libraries}")
    unset(_missing_ffmpeg_libraries)
  endif()
endif()

#=================================
# Versions check.
if(HAVE_FFMPEG AND NOT HAVE_FFMPEG_WRAPPER)
  set(_min_libavcodec_version 54.35.0)
  set(_min_libavformat_version 54.20.4)
  set(_min_libavutil_version 52.3.0)
  set(_min_libswscale_version 2.1.1)
  set(_min_libavresample_version 1.0.1)
  foreach(ffmpeg_lib ${_used_ffmpeg_libraries})
    if(FFMPEG_${ffmpeg_lib}_VERSION VERSION_LESS _min_${ffmpeg_lib}_version)
      message(STATUS "FFMPEG is disabled. Can't find suitable ${ffmpeg_lib} library"
              " (minimal ${_min_${ffmpeg_lib}_version}, found ${FFMPEG_${ffmpeg_lib}_VERSION}).")
      set(HAVE_FFMPEG FALSE)
    endif()
  endforeach()
  if(NOT HAVE_FFMPEG)
    message(STATUS "FFMPEG libraries version check failed "
            "(minimal libav release 9.20, minimal FFMPEG release 1.1.16).")
  endif()
  unset(_min_libavcodec_version)
  unset(_min_libavformat_version)
  unset(_min_libavutil_version)
  unset(_min_libswscale_version)
  unset(_min_libavresample_version)
endif()

#==================================

if(HAVE_FFMPEG AND NOT HAVE_FFMPEG_WRAPPER AND NOT OPENCV_FFMPEG_SKIP_BUILD_CHECK)
  try_compile(__VALID_FFMPEG
      "${OpenCV_BINARY_DIR}"
      "${OpenCV_SOURCE_DIR}/cmake/checks/ffmpeg_test.cpp"
      CMAKE_FLAGS "-DINCLUDE_DIRECTORIES:STRING=${FFMPEG_INCLUDE_DIRS}"
                  "-DLINK_LIBRARIES:STRING=${FFMPEG_LIBRARIES}"
      OUTPUT_VARIABLE TRY_OUT
  )
  if(NOT __VALID_FFMPEG)
    # message(FATAL_ERROR "FFMPEG: test check build log:\n${TRY_OUT}")
    message(STATUS "WARNING: Can't build ffmpeg test code")
    set(HAVE_FFMPEG FALSE)
  endif()
endif()

#==================================
unset(_required_ffmpeg_libraries)
unset(_used_ffmpeg_libraries)

if(HAVE_FFMPEG_WRAPPER)
  ocv_add_external_target(ffmpeg "" "" "HAVE_FFMPEG_WRAPPER")
elseif(HAVE_FFMPEG)
  ocv_add_external_target(ffmpeg "${FFMPEG_INCLUDE_DIRS}" "${FFMPEG_LIBRARIES}" "HAVE_FFMPEG")
endif()

set(HAVE_FFMPEG ${HAVE_FFMPEG} PARENT_SCOPE)

我们不去逐行分析这个文件,我们只分析重点。还是那句话find_package(${OPENCV_FFMPEG_USE_FIND_PACKAGE})opencv-4.5.1这个版本还是通过pkg-config来查找计算机上的ffmpeg的,包括ffmpeg依赖的库,所以问题就找到了。


解决方案:

这里直接说我自己的解决方案,解决方案有可能不止一个。
1、OpenCV-3.4.16
照理说3.4.2版本或者其他版本也是通用的,我没有测试所有的版本。如果你的电脑可以联网可以通过apt安装ffmpeg方法是:

sudo apt update
sudo apt install -y ffmpeg

只安装ffmpeg还是不够的,我们还需要安装libavcodec-devlibavformat-devlibavutil-devlibavfilter-devlibavresample-devlibswresample-devlibswscale-dev开发环境,注意一定要是开发环境,而不是运行库,运行库是不带头文件的,不能用于编译源代码。

这个时候我们去/usr/include找到刚刚安装的这些运行库的头文件,在/usr/include里面创建一个文件夹ffmpeg,将刚才的诸如libavcodec这些文件夹下面的所有头文件都复制到/usr/include/ffmpeg文件夹下面,注意不要复制整个文件夹,要复制文件夹里面的所有头文件。完了之后再编译OpenCV并加上WITH_FFMPEG如果出现下图所示,说明对了。

解决opencv源代码编译找不到ffmpeg_第1张图片
注:必须是YES,不能是NO,如果是NO就检查下操作是不是有误。这个版本是ffmpeg-4.4.2的版本,Ubuntu18.04原生安装的是ffmpeg-3.4.8或ffmpeg-3.4.6版本,对于我来说用起来没影响。

2、OpenCV-4.5.1

这个版本的OpenCV编译比较麻烦点,这里我没有用apt去安装ffmpeg而是选择用ffmpeg-4.4.2的源代码编译ffmpeg。关于ffmpeg的源代码编译这里我不详述了,大家可以自行去查询下资料。我这里只编译我用到的功能。

首先到ffmpeg的官网下载源代码,这里我选的是ffmpeg-4.4.2,其他的版本我没有测试过,大家可以自行测试,理论上4.x.x的版本应该都是可以的。

./configure --enable-shared --enable-avresample --prefix=/usr/
make -j$(nproc)
sudo make install

注:--prefix=/usr/ 这句话一定要这么写,不能安装到/usr/local目录下,OpenCV可能会找不到ffmpeg

最后编译OpenCV并加上WITH_FFMPEG如果出现下图所示,说明对了。
解决opencv源代码编译找不到ffmpeg_第2张图片

写在最后

大体的方法就是上面那些了,有疑问的童鞋可以在下面提问。

你可能感兴趣的:(ubuntu,linux,opencv,人工智能)