如何用msvc工具链编译FFmpeg+fdk-aac

1,613 阅读4分钟

前言

网上有很多编译FFmpeg的方法,但是大多都是直接用mingw编译的,在我这里用mingw编译完的FFmpeg会出现0xc000007b问题。我也不知道为什么会这样,也没有去深究。下面说一下如何编译出能在QT(msvc 2017 64位编译工具链)使用的FFmpeg+fdk-aac库。

编译出的库

下面两个图是我已经编译好的FFmpeg+fdk-acc,之前我单独编译过FFmpeg,看到avcodec-58.dll这个文件大了很多,可见fdkaac已经集成进去了

FFmpeg输出1

FFmpeg输出2

编译fdk-aac

fdkaac已经支持了msvc的编译,网上没有很多人说这个事儿。

  • 打开x64 Native Tools Command Prompt for VS 2017
  • 进入到fdkaac的源码目录,我这里是 cd C:\Users\Yu\Documents\fdk-aac-2.0.1
  • 执行 nmake -f Makefile.vc all
  • 等待编译完,最后输出的了fdk-aac.lib,这正是我们需要的

这里有个坑,我先提前提一嘴,编译出来的的只有lib,并没有输出include文件夹,但是这个include后面要用。我当时先在msys2+mingw里编译了一下fdk-aac,编译完输出目录里就有include了,然后我把上面编出来的fdk-aac.lib复制到了输出目录的lib文件夹里,后面会用。当然include这些文件在源码目录里复制出来也是可以的,反正就是几个头文件,详情见下面的图

  • ./autogen.sh
  • ./configure --prefix=你的输出目录(fdk-aac的输出目录需要绝对路径)
  • make
  • make install

fdkaac头文件

编译FFmpeg

首先你需要编辑C:\msys64\msys2_shell.cmd 将 rem set MSYS2_PATH_TYPE=inherit 改为 set MSYS2_PATH_TYPE=inherit

- rem set MSYS2_PATH_TYPE=inherit
+ set MSYS2_PATH_TYPE=inherit

打开x86_x64 Cross Tools Command Prompt for VS 2017, 执行 C:\msys64\msys2_shell.cmd,会弹出msys2的窗口,这时候的cl应该就是msvc的cl,可以在msys2窗口执行 which cl 查看

Yu@DESKTOP-RONCTS2 MSYS ~/ffmpeg
$ which cl
/c/Program Files (x86)/Microsoft Visual Studio/2017/Community/VC/Tools/MSVC/14.16.27023/bin/HostX86/x64/cl

执行./configure

./configure --toolchain=msvc --extra-cflags=-I/home/Yu/fdk-aac-2.0.1/build_out/include --extra-ldflags=-LIBPATH:/home/Yu/fdk-aac-2.0.1/build_out/lib --disable-doc --disable-lzma --disable-programs --enable-shared --enable-libfdk-aac --enable-nonfree --enable-gpl --disable-static --disable-bzlib --disable-libopenjpeg --disable-iconv --disable-zlib --prefix=build_out

解释上面用到的一坨参数,其他更详细的信息可以执行 ./configure --help:

--toolchain=msvc
使用msvc工具链,必须要加上

--extra-cflags=-I/home/Yu/fdk-aac-2.0.1/build_out/include
指向fdk-aac的头文件目录

--extra-ldflags=-LIBPATH:/home/Yu/fdk-aac-2.0.1/build_out/lib
指向fdk-aac.lib保存的文件夹,这里需要注意是 -LIBPATH 而不是 -L,mscv并不支持-L,必须要写全,这个坑是我在ffbuild/config.log里看到的,如果./configure 出了其他问题也可以看这个日志

--disable-doc
不输出文档

--disable-lzma --disable-bzlib --disable-libopenjpeg --disable-iconv --disable-zlib 不要这些特性和依赖库,如果不去掉这些库,编译出来的dll和lib,在QT里使用会提示缺少这些dll

--disable-programs
不编译生成ffmpeg,ffplay,ffprobe

--enable-shared --disable-static
生成动态库,不生成静态库

--enable-libfdk-aac --enable-nonfree --enable-gpl
将fdk-aac编译到FFmpeg库中

--prefix=build_out
make install 输出的位置,我这里指定输出到build_out目录

配置项目可能需要几分钟,没有出错的话就可以make -j8 (8线程同时编译,可以加快速度),完成后make install,可以在build_out目录里查看编译的输出,bin目录里是QT里需要用到lib和dll,头文件是include

你可能并不需要fdk-aac

我之所以编译了带有fdk-aac版本的FFmpeg库,是因为我在尝试将PCM编码成AAC的时候遇到了这个问题:

[ffmpeg] Specified sample format s16 is invalid or not supported

这个问题是因为比较新版本的FFmpeg,通过avcodec_find_encoder(AV_CODEC_ID_AAC)得到的编码器,采样格式并不支持 AV_SAMPLE_FMT_S16 格式,仅支持 AV_SAMPLE_FMT_FLTP 格式。解决方法有两种:

  1. 像我一样用libfdk-aac的编码器,这个编码器是支持AV_SAMPLE_FMT_S16采样格式的,可以直接编码到AAC。那么你的获取编码器的方式就需要变成这个样子:
    AVCodec * audio_codec = avcodec_find_encoder_by_name("libfdk_aac");
    
  2. 第二种方式是先将采样回来的PCM 通过swr_convert()重采样一下,可以将AV_SAMPLE_FMT_S16转换为AV_SAMPLE_FMT_FLTP,然后在进行AAC编码,这种方式是不需要fdk-aac库的,下面是部分代码:
    swr_context = swr_alloc();
    av_opt_set_int(swr_context, "in_channel_layout",  AV_CH_LAYOUT_STEREO, 0);
    av_opt_set_int(swr_context, "out_channel_layout", AV_CH_LAYOUT_STEREO, 0);
    av_opt_set_int(swr_context, "in_sample_rate",     48000, 0);
    av_opt_set_int(swr_context, "out_sample_rate",    48000, 0);
    av_opt_set_sample_fmt(swr_context, "in_sample_fmt",  AV_SAMPLE_FMT_S16, 0);
    av_opt_set_sample_fmt(swr_context, "out_sample_fmt", AV_SAMPLE_FMT_FLTP, 0);
    swr_init(swr_context);
    
    int len2 = swr_convert(swr_context, out_frame_buffer_, 4096 * 4, (const uint8_t **)&data , 4096 / 4);
    

对于方法2的代码我并不能完全的解释明白,我也是初学,这里放一个对于重采样资料的链接:blog.csdn.net/bixinwei22/…