1 前言
本文介绍下在macOS上将ffmpeg的fftools目录下的ffmpeg.c程序,也就是ffmpeg的命令行程序,编译成framework的方法。编译成.a或.dylib亦是类似。
编译环境如下:
- xcode15.3;
- ffmpeg branch release/6.1;
2 编译ffmpeg
首先clone我们的FFmpeg代码仓到本地,并更名为ffmpeg,切换分支为release/6.1:
git clone https://github.com/FFmpeg/FFmpeg.git ffmpeg && git checkout release/6.1
然后在ffmpeg的根目录执行如下命令,由于是学习使用,configure配置的是缺省选项,编译后安装目录在根目录下的mac_build目录下:
mkdir -p mac_build && ./configure --prefix=./mac_build
然后执行如下命令,编译并安装ffmpeg:
make -j8 && make install
configure并编译安装完成之后,会在根目录下生成如下文件:
- configure配置完毕,会在根目录产生config.h和config_components.h文件;
- 生成了ffmpeg/ffplay/ffprobe可执行文件;
- mac_build目录是ffmpeg的bin/include/lib/share文件;
其中,mac_build目录结构如下:
xxxxxx@localhost:~/Applications/workspace/av/ffmpeg/mac_build$tree -L 2
.
├── bin
│ ├── ffmpeg
│ ├── ffplay
│ └── ffprobe
├── include
│ ├── libavcodec
│ ├── libavdevice
│ ├── libavfilter
│ ├── libavformat
│ ├── libavutil
│ ├── libswresample
│ └── libswscale
├── lib
│ ├── libavcodec.a
│ ├── libavdevice.a
│ ├── libavfilter.a
│ ├── libavformat.a
│ ├── libavutil.a
│ ├── libswresample.a
│ ├── libswscale.a
│ └── pkgconfig
└── share├── ffmpeg└── man15 directories, 10 files
编译安装完成之后,就可以拿该目录下的include和lib下的文件引入到工程使用了。
3 编译ffmpeg.c
3.1 新建xcode工程
打开xcode新建一个xcode的app工程:
然后,新建一个target,FFmpegFramework,然后把ffmpeg相关c程序拖进来编译:
然后在FFmpegFramework => Build Settings => Search Paths里加入ffmpeg的include和lib以及config.h的搜索路径:
到此,xcode工程和FFmpegFramework的创建和初始化工作完成,接下来就是将FFmpegFramework编译成framework了。
3.2 改写ffmpeg.c的接口方法
- 在ffmpeg.h文件中,将int main(int argc, char* argv[])方法名改成ffmpeg;
- ffmpeg.c对应文件的main方法名按以上同步修改;
ffmpeg.h头文件中修改方法名:
int ffmpeg(int argc, char* argv[]);
ffmpeg.c同步修改方法名:
// 将main方法名改为ffmpeg
int ffmpeg(int argc, char **argv)
{int ret, err_rate_exceeded;BenchmarkTimeStamps ti;init_dynload();setvbuf(stderr,NULL,_IONBF,0); /* win32 runtime needs this */av_log_set_flags(AV_LOG_SKIP_REPEATED);parse_loglevel(argc, argv, options);#if CONFIG_AVDEVICEavdevice_register_all();
#endifavformat_network_init();show_banner(argc, argv, options);/* parse options and open all input/output files */ret = ffmpeg_parse_options(argc, argv);if (ret < 0)goto finish;if (nb_output_files <= 0 && nb_input_files == 0) {show_usage();av_log(NULL, AV_LOG_WARNING, "Use -h to get full help or, even better, run 'man %s'\n", program_name);ret = 1;goto finish;}if (nb_output_files <= 0) {av_log(NULL, AV_LOG_FATAL, "At least one output file must be specified\n");ret = 1;goto finish;}current_time = ti = get_benchmark_time_stamps();ret = transcode(&err_rate_exceeded);if (ret >= 0 && do_benchmark) {int64_t utime, stime, rtime;current_time = get_benchmark_time_stamps();utime = current_time.user_usec - ti.user_usec;stime = current_time.sys_usec - ti.sys_usec;rtime = current_time.real_usec - ti.real_usec;av_log(NULL, AV_LOG_INFO,"bench: utime=%0.3fs stime=%0.3fs rtime=%0.3fs\n",utime / 1000000.0, stime / 1000000.0, rtime / 1000000.0);}ret = received_nb_signals ? 255 :err_rate_exceeded ? 69 : ret;finish:if (ret == AVERROR_EXIT)ret = 0;ffmpeg_cleanup(ret);return ret;
}
3.3 将ffmpeg.c编译成Framework
接下来就是将ffmpeg.c编译成framework了,期间遇到了很多问题,但基本是一类问题,那就是链接时的undefined symbol。
解决方式就是将ffmpeg.c所依赖的macOS系统framework和基础.a或者.dylib库链接到本framework即可。如下,总共依赖了39个库,其中SDL2必须用dylib库:
4 使用framework
贴出main.c调用ffmpeg.c的代码:
#include "libavutil/log.h"
#include "libavformat/avformat.h"
#include "libavcodec/avcodec.h"
#include "libavutil/opt.h"
#include "ffmpeg.h"static void test_ffmpeg(int argc, const char* argv[]) {ffmpeg(argc, argv);
}int main(int argc, const char * argv[]) {@autoreleasepool {// Setup code that might create autoreleased objects goes here.av_log_set_level(AV_LOG_DEBUG);av_log(NULL, AV_LOG_INFO, "hello ffmpeg");test_ffmpeg(argc, argv);}return NSApplicationMain(argc, argv);
}
选中learn-ffmpeg target,在learn-ffmpeg => Build Settings => Search Paths => Header Search Paths/Library Search Paths中指定ffmpeg及其framework相关的include和lib文件:
include搜索路径:
lib搜索路径:
在learn-ffmpeg target中 Build Settings => Link Binary with Library中加入FFmpegFramework:
接下来就可以顺利编译self-ffmpeg程序,并开始调试ffmpeg.c程序了: