ubuntu下Cmake链接ffmpeg库

该博客主要讲述在Ubuntu系统下,使用Cmake链接FFmpeg库的相关内容,涉及信息技术中后端开发与音视频编解码领域。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

cmake_minimum_required(VERSION 3.0)
project(player)

set(CMAKE_C_STANDARD 99)
set(CMAKE_CXX_FLAGS "-D__STDC_CONSTANT_MACROS")

set(CMAKE_FIND_LIBRARY_SUFFIXES ".a")

find_path(AVCODEC_INCLUDE_DIR libavcodec/avcodec.h)
find_library(AVCODEC_LIBRARY avcodec)

find_path(AVFORMAT_INCLUDE_DIR libavformat/avformat.h)
find_library(AVFORMAT_LIBRARY avformat)

find_path(AVUTIL_INCLUDE_DIR libavutil/avutil.h)
find_library(AVUTIL_LIBRARY avutil)
set(CMAKE_CXX_FLAGS "-D__STDC_CONSTANT_MACROS")
find_path(AVDEVICE_INCLUDE_DIR libavdevice/avdevice.h)
find_library(AVDEVICE_LIBRARY avdevice)

include_directories(

       /usr/local/include/
)

link_directories(
  #     /home/rui/repos/ffmpeg/
        /usr/local/lib
#       /home/rui/repos/ffmpeg/libswscale
#       /home/rui/repos/ffmpeg/libavformat
)
INCLUDE(FindPkgConfig)
PKG_SEARCH_MODULE(SDL2 REQUIRED sdl2)

add_executable(player main.c)
message(STATUS ${AVCODEC_LIBRARY})
target_include_directories(ffmpeg_c  PRIVATE ${AVCODEC_INCLUDE_DIR} ${AVFORMAT_INCLUDE_DIR} ${AVUTIL_INCLUDE_DIR} ${AVDEVICE_INCLUDE_DIR})
target_link_libraries(ffmpeg_c PRIVATE ${AVCODEC_LIBRARY} ${AVFORMAT_LIBRARY} ${AVUTIL_LIBRARY} ${AVDEVICE_LIBRARY} ${SDL2_LIBRARIES}  pthread   swresample m swscale
        avcodec avutil avfilter avdevice postproc z lzma  rt)

 

<think>我们正在处理的问题是在CMake项目中正确链接FFmpeg,以解决'av_fifo'相关类型和函数的未定义引用错误。根据错误信息,问题主要包括:1.'AVFifo'类型未定义2.一些函数(如av_fifo_alloc2,av_fifo_can_read,av_fifo_read,av_fifo_freep2)未声明解决方案:1.确保包含正确的头文件:在代码中,我们已经包含了<libavutil/fifo.h>,这应该是正确的。2.检查FFmpeg版本:因为AVFifo结构以及av_fifo_alloc2等函数是在较新的FFmpeg版本中引入的(例如av_fifo_alloc2是在FFmpeg4.0以后引入的)。如果使用的FFmpeg版本较旧,则可能没有这些函数和类型。因此,需要确认FFmpeg版本。如果FFmpeg版本过低,我们可以采取两种方式:a.升级FFmpeg到至少4.0版本。b.使用旧的AVFifoBuffer类型和旧函数(如av_fifo_alloc,av_fifo_generic_read等)进行替代。3.在CMakeLists.txt中正确配置FFmpeg链接。根据引用[2]中的错误信息,当出现未定义引用时,可能是因为链接顺序不正确或未链接到相应的。我们的项目需要链接avformat,avcodec,avutil等。具体步骤:步骤1:检查系统中安装的FFmpeg版本在终端运行:$ffmpeg-version步骤2:如果版本低于4.0,考虑升级。或者修改代码使用旧版的fifoAPI。步骤3:在CMakeLists.txt中,确保我们正确地找到了FFmpeg,并且正确链接。目前CMakeLists.txt中使用了pkg_check_modules来查找FFmpeg。但是,在链接时,我们使用了${FFMPEG_LIBRARIES},这应该是一个包含了所有FFmpeg(如avcodec,avformat,avutil等)的变量。但是,根据错误信息,我们使用了avutil中的函数,所以确保avutil被链接。步骤4:修改代码以兼容旧版FFmpeg(可选,如果无法升级)如果使用旧版FFmpeg,我们需要将AVFifo*替换为AVFifoBuffer*,并且使用旧的函数:-av_fifo_alloc2替换为av_fifo_alloc(注意参数不同,av_fifo_alloc只接受一个参数,即缓冲区大小)-av_fifo_read替换为av_fifo_generic_read-av_fifo_write替换为av_fifo_generic_write-av_fifo_can_read可能没有直接替代,但可以通过av_fifo_size和av_fifo_space计算-av_fifo_freep2替换为av_fifo_freep(注意av_fifo_freep接受AVFifoBuffer**)步骤5:在代码中,根据FFmpeg版本进行条件编译(可选)例如:#ifLIBAVUTIL_VERSION_INT>=AV_VERSION_INT(56,0,0)//使用新的AVFifo#else//使用旧的AVFifoBuffer#endif但是,考虑到项目复杂性,如果可能,升级FFmpeg是最简单的。步骤6:重新组织CMakeLists.txt,确保头文件路径和路径正确根据引用[4],我们可以参考一个目录结构,将FFmpeg的头文件和文件放在特定目录,并在CMakeLists.txt中指定。由于我们已经使用了pkg_check_modules,通常这是正确的方式,但有时pkg-config可能没有正确配置,那么我们可以手动指定:例如:find_path(FFMPEG_INCLUDE_DIRlibavcodec/avcodec.h)find_library(AVCODEC_LIBRARYavcodec)然后使用include_directories和target_link_libraries。但是,根据当前错误,我们的主要问题是代码中使用了新版本的API,而链接可能是旧版本,或者根本没有链接到avutil。因此,首先尝试升级FFmpeg,然后确保CMake正确找到。针对当前CMakeLists.txt,我们可以尝试以下修改:1.确保pkg_check_modules包含了libavutil。2.在target_link_libraries中明确链接avutil。修改后的CMakeLists.txt中关于FFmpeg的部分:```cmakepkg_check_modules(FFMPEGREQUIREDlibavcodeclibavformatlibavutillibswscalelibavdevice)```链接:```cmaketarget_link_libraries(capture_testpthread${FFMPEG_LIBRARIES}log)```步骤7:清理构建目录并重新编译执行以下命令:cdbuildrm-rf*cmake..make如果仍然出现函数未定义,则可能是FFmpeg的版本问题,或者pkg-config没有返回正确的路径。如果问题依旧,可以尝试使用下面的方法手动指定:```cmakefind_package(PkgConfigREQUIRED)pkg_check_modules(FFMPEGREQUIREDlibavutil)#然后单独链接avutiltarget_link_libraries(capture_test${FFMPEG_LIBRARIES}#其他...)```或者更具体地,我们可以单独检查每个:```cmakefind_library(LIBAVUTILavutil)if(LIBAVUTIL)target_link_libraries(capture_test${LIBAVUTIL})endif()```但是,推荐使用pkg-config,因为它会解决依赖关系。结论:1.首要检查FFmpeg版本,确保版本>=4.0(因为av_fifo_alloc2是在avutil56.0.0中引入的)。2.确保在代码中包含了<libavutil/fifo.h>。3.确保CMakeLists.txt中正确配置了FFmpeg链接。如果FFmpeg版本确实过低,考虑升级或者修改代码使用旧版fifoAPI。下面给出修改代码使用旧版API的示例(仅当无法升级FFmpeg时):将:AVFifo*fifo=av_fifo_alloc2(10*1024*1024,1,0);改为:AVFifoBuffer*fifo=av_fifo_alloc(10*1024*1024);//注意:旧版av_fifo_alloc只有一个参数将:av_fifo_write(fifo,&frame,1);改为:av_fifo_generic_write(fifo,&frame,sizeof(AVFrame*),NULL);将:av_fifo_read(fifo,&frame,1);改为:av_fifo_generic_read(fifo,&frame,sizeof(AVFrame*),NULL);删除av_fifo_can_read,因为旧版没有这个函数。我们可以用:if(av_fifo_size(fifo)>=sizeof(AVFrame*))//表示可以读将:av_fifo_freep2(&fifo);改为:av_fifo_free(fifo);//注意,这个函数不会将fifo置为NULL,所以后面需要手动置NULLfifo=NULL;或者使用:av_fifo_freep(&fifo);//这个函数会接收AVFifoBuffer**,并将指针置NULL。注意:av_fifo_freep是旧版就存在的,它用于释放AVFifoBuffer*,并置空指针。但是,av_fifo_freep在新版中已经被av_fifo_freep2取代,所以我们可以在旧版中直接使用av_fifo_freep。为了兼容,我们可以这样写条件编译:```c#include<libavutil/fifo.h>#include<libavutil/avutil.h>#ifLIBAVUTIL_VERSION_INT< AV_VERSION_INT(56,0,0)//使用旧的AVFifoBuffertypedefAVFifoBufferAVFifo;#defineav_fifo_alloc2(size,elem_size,flags)av_fifo_alloc(size)#defineav_fifo_write(fifo,data,nb_elems)av_fifo_generic_write(fifo,data,(nb_elems)*sizeof(*data),NULL)#defineav_fifo_read(fifo,data,nb_elems)av_fifo_generic_read(fifo,data,(nb_elems)*sizeof(*data),NULL)#defineav_fifo_freep2av_fifo_freep#defineav_fifo_can_read(fifo)(av_fifo_size(fifo)>0)#endif```但是,这种做法需要仔细处理,因为旧版的av_fifo_generic_write和av_fifo_generic_read在写入和读取时可能需要不同的处理(比如,我们传递的是指针数组,即AVFrame*,那么写入和读取应该是指针的复制)。而新的av_fifo_write/read则直接按元素数量进行。在旧版中,我们传递的data是一个指向指针的指针(即AVFrame**),但我们实际要存储的是一个指针(AVFrame*)。因此,在使用av_fifo_generic_write时,我们传递的应该是sizeof(AVFrame*)的大小。因此,在旧版中,我们可以这样:AVFrame*frame=...;av_fifo_generic_write(fifo,&frame,sizeof(AVFrame*),NULL);而新版本可以直接:av_fifo_write(fifo,&frame,1);但是,如果我们使用宏定义,那么对于旧版的av_fifo_write,我们传递的nb_elems为1,那么展开后就是:av_fifo_generic_write(fifo,&frame,sizeof(*&frame)*1,NULL);//sizeof(*&frame)就是sizeof(AVFrame*)这可以工作。所以上述宏定义可以用于兼容。最后,我们修改代码,使用条件编译的方式同时支持新旧FFmpeg版本。但是,考虑到项目复杂度,如果升级FFmpeg更方便,那么升级FFmpeg是更好的选择。建议:1.如果条件允许,升级FFmpeg到4.0以上。2.或者修改CMakeLists.txt,让其自动检测版本并设置宏定义。根据问题中的错误信息,错误发生在编译阶段(类型未定义),而不是链接阶段。所以,如果类型未定义,说明头文件中没有这个类型,也就是FFmpeg版本过低。因此,我们首先解决FFmpeg版本问题。如果升级FFmpeg后,问题依旧,则可能是因为在包含头文件时未定义__STDC_FORMAT_MACROS等宏,但这种情况较少见。我们专注于版本和链接问题。请按照以下步骤操作:1.检查FFmpeg版本:运行`ffmpeg-version`或`pkg-config--modversionlibavutil`。2.如果版本低于56.0.0,则升级或修改代码使用旧版API。3.在CMakeLists.txt中确保找到正确的FFmpeg。最后,清理构建并重新编译。</think> ### 解决 CMake 项目中 FFmpeg 链接问题的完整方案 #### 1. **升级 FFmpeg (关键步骤) 错误根源在于项目中使用了 **FFmpeg 4.0+ 新增的 AVFifo API**(如 `av_fifo_alloc2()`): ```bash # 安装最新 FFmpeg 开发包(Ubuntu 示例) sudo add-apt-repository ppa:savoury1/ffmpeg4 sudo apt update sudo apt install libavformat-dev libavcodec-dev libavutil-dev ``` > 验证版本:`pkg-config --modversion libavutil` 至少需 ≥ 56.0.0[^1] #### 2. **修改 CMakeLists.txt 配置** ```cmake{12-24} # 1. 确保包含FFmpeg所有必要组件 pkg_check_modules(FFMPEG REQUIRED libavformat libavcodec libavutil libswscale libavdevice ) # 2. 显式添加头文件路径(解决类型未定义) include_directories( ${FFMPEG_INCLUDE_DIRS} ${CMAKE_SOURCE_DIR}/include /usr/local/include ) # 3. 精确链接所有FFmpeg(解决函数未定义) target_link_libraries(capture_test pthread ${FFMPEG_LIBRARIES} # 必须放在首位 avformat avcodec avutil swscale avdevice log ) ``` #### 3. **修复 C++ 头文件引用** 在 `capturerunner.h` 和 `capt_test.cpp` 中添加: ```cpp extern "C" { #include <libavutil/fifo.h> // 声明AVFifo类型 } ``` #### 4. **解决成员访问保护错误** 使用公共接口替代直接访问保护成员: ```cpp{4-6} // capt_test.cpp 修改示例 int capt_write::Init(CaptureRunnerParam* par) { this->fifo = par->fifo; // 替换直接访问保护成员 this->width = par->capt->GetWidth(); // 添加GetWidth()到Capture类 this->height = par->capt->GetHeight(); // 添加GetHeight() this->pix_fmt = par->capt->GetPixelFmt(); // 添加GetPixelFmt() } ``` 在 `capture.h` 中添加公共接口: ```cpp class Capture { public: int GetWidth() const { return m_width; } int GetHeight() const { return m_height; } AVPixelFormat GetPixelFmt() const { return m_pixel_fmt; } protected: // 原有保护成员保持不变... }; ``` #### 5. **兼容旧版 FFmpeg 的替代方案(如无法升级)** ```cpp #if LIBAVUTIL_VERSION_INT < AV_VERSION_INT(56, 0, 0) // 使用旧版API AVFifoBuffer* fifo = av_fifo_alloc(10 * 1024 * 1024); av_fifo_generic_write(fifo, data, size, NULL); av_fifo_free(fifo); #else // 使用新版API AVFifo* fifo = av_fifo_alloc2(10 * 1024 * 1024, 1, 0); av_fifo_write(fifo, &frame, 1); av_fifo_freep2(&fifo); #endif ``` #### 6. **验证编译配置** ```bash # 清理并重新构建 cd build cmake -DCMAKE_VERBOSE_MAKEFILE=ON .. # 显示详细链接信息 make ``` 检查输出中是否包含: ```log -L/usr/local/lib -lavformat -lavcodec -lavutil ... ``` #### 7. **调试符号缺失问题** 若仍出现函数未定义错误: ```bash # 检查符号是否存在 nm -D /usr/local/lib/libavutil.so | grep av_fifo_alloc2 # 预期输出:包含"T av_fifo_alloc2" (T表示已导出) ``` > **经验法则**:FFmpeg 链接顺序应为: > `avformat → avcodec → avutil → 其他`[^2] > 错误顺序会导致未定义符号问题
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值