需求:将FFmpeg编译成动态库解决引入第三方SDK中包含FFmpeg以至于本项目中FFmpeg冲突的问题,可以引申为解决所有第三方库冲突问题
实现原理: 将FFmpeg编译好的静态库放入Xcode创建的动态库中重新编译以重新生成动态库
阅读前提:
- 已经有FFmpeg编译好的静态库
- 懂得如何灵活根据自身ffmpeg增加部分系统库或其他依赖库
GitHub地址(附代码) :
简书地址 :
博客地址 :
掘金地址 :
实现
1. 利用Xcode创建动态库
2. 项目设置
添加Other link flags
-
-ObjC: 这个flag告诉链接器把库中定义的Objective-C类和Category都加载进来。这样编译之后的app会变大(因为加载了其他的objc代码进来)。但是如果静态库中有类和category的话只有加入这个flag才行。
-
-all_load: 这个flag是专门处理-ObjC的一个bug的。用了-ObjC以后,如果类库中只有category没有类的时候这些category还是加载不进来。变通方法就是加入-all_load或者-force-load。-all_load会强制链接器把目标文件都加载进来,即使没有objc代码。-force_load在xcode3.2后可用。但是-force_load后面必须跟一个只想静态库的路径。
注意:在本例中,-all_load是指将ffmpeg静态库注入动态库,否则若SDK中没有调用相关函数,编译出来的动态库则无法调用。
- -read_only_relocs:重定位
- suppress: 压制,不显示重定位错误。
Enable Bitcode
如果项目中有支持 Bitcode,要么让第三方库支持 Bitcode;要么关闭 Bitcode 功能, ffmpeg中需要我们关闭bitcode.
bitcode是被编译程序的一种中间形式的代码。包含bitcode配置的程序将会在App store上被编译和链接。bitcode允许苹果在后期重新优化我们程序的二进制文件,而不需要我们重新提交一个新的版本到App store上。
3. 将FFmpeg头文件导入SDK Header中,手动拖入即可
因为我们在项目中都是使用类似下面的代码导入FFmpeg
#import "libavformat/avformat.h"#import "libswscale/swscale.h"#import "libavcodec/avcodec.h"#import "libavutil/avutil.h"#import "libswresample/swresample.h"#import "libavresample/avresample.h"#import "libavfilter/avfilter.h"#import "libavdevice/avdevice.h"复制代码
想要将头文件也按照文件夹形式放入SDK编出来的目录中的话只能使用引用的形式,否则打包出来的库无法以一个个文件夹的形式。
将ffmpeg相关的头文件夹拖入SDK header的Public文件中,创建引用即可
然后创建一个虚拟目录存放FFmpeg头文件,调整文件目录目录结构
最终,项目中目录结构如下图
4. 添加依赖的系统库或第三方库
ffmpeg中本身会依赖一些系统库,这一方面取决于你在编译FFmpeg源码时所打开的flag,如何开启的越多可能依赖的越多,而本例中仅仅该版本ffmpeg所依赖的系统库,所以,你编译出来仍然报错,需要自己灵活添加系统库或其他依赖的第三方库
PS:有的版本或flag标志开启后可能需要苹果的VideoToolbox....
5. 编译成功,并拷贝Framework
此时可使用下面指令可进入Framework中查看当前Framework是否为动态库 $ file 二进制文件名
6. 新建项目,关闭Bitcode,引入上面编译好的SDK
7. 配置项目Build Setting
在Header Search Paths中添加FFmpeg文件夹集合的目录,以至于我们可以使用通用的方式去调用FFmpeg,兼容项目中的代码
8.此时可在主控制器中测试,如下
经测试程序可正常运行
#import "ViewController.h"#import "libavformat/avformat.h"#import "libswscale/swscale.h"#import "libavcodec/avcodec.h"#import "libavutil/avutil.h"#import "libswresample/swresample.h"#import "libavresample/avresample.h"#import "libavfilter/avfilter.h"#import "libavdevice/avdevice.h"@interface ViewController ()@end@implementation ViewController- (void)viewDidLoad { [super viewDidLoad]; // Do any additional setup after loading the view, typically from a nib. avdevice_register_all(); }@end复制代码