目标
前段时间编译了iOS平台的ffmepg,这里记录一下过程。
首先是明确目标:编译的是x264 + fdk-aac + ffmpeg的iOS库
环境准备
安装yasm,brew install yasm
1、编译x264
1、下载x264的源码 https://www.videolan.org/developers/x264.html
2、下载github的编译脚本 https://github.com/kewlbear/x264-ios,根据自己的架构需要,修改脚本
编译成功后,会有一个x264-iOS
的文件夹
build-x264.sh
x264的源码目录
x264-iOS
- include
- lib
2、编译fdk-aac
1、下载fdk-aac源码 https://www.linuxfromscratch.org/blfs/view/svn/multimedia/fdk-aac.html
2、下载github的编译脚本 https://github.com/kewlbear/fdk-aac-build-script-for-iOS根据自己的架构需要,修改脚本
编译成功后,会有一个fdk-aac-ios
的文件夹
build-fdk-aac.sh
fdk-aac-2.0.2的源码目录
fdk-aac-ios
- include
- lib
3、编译ffmpeg
1、下载ffmpeg源码,https://ffmpeg.org/download.html
2、下载github的编译脚本 https://github.com/kewlbear/FFmpeg-iOS-build-script
3、修改脚本的x264-iOS,fdk-aac-ios路径以及ffmpeg版本号
# directories
FF_VERSION="4.3.2" # 这里改为你下载的sdk版本
#FF_VERSION="snapshot-git"
if [[ $FFMPEG_VERSION != "" ]]; then
FF_VERSION=$FFMPEG_VERSION
fi
SOURCE="ffmpeg-$FF_VERSION"
FAT="FFmpeg-iOS"
SCRATCH="scratch"
# must be an absolute path
THIN=`pwd`/"thin"
# absolute path to x264 library
X264=`pwd`/"x264-iOS" # x264的lib目录
FDK_AAC=`pwd`/"fdk-aac-ios" # fdk的lib目录
...
总体的文件目录是这样的
build-ffmpeg.sh
x264-ios # x264的lib文件夹
fdk-aac-ios # fdk的lib文件夹
ffmpeg-4.3.2 # ffmpeg的源码文件夹
FFmpeg-iOS # ffmpeg-iOS编译产物
-include
-lib
demo验证
xcode新建一个工程,将x264-iOS
, fdk-aac-ios
, FFmpeg-iOS
,还有ffmpeg源码目录的的fftools
的以下文件拖入都工程中:
cmdutils.c ffmpeg.h ffmpeg_videotoolbox.c
cmdutils.h ffmpeg_filter.c mathops.h
config.h ffmpeg_hw.c
ffmpeg.c ffmpeg_opt.c
config.h
会根据configure的执行生成,跟fftool
同层
mathops.h
在源码的libavcodec目录下
根据编译提示,注释这些头文件
#include "libavutil/thread.h
#include "libswresample/swresample.h"
#include "compat/va_copy.h"
#include "libavutil/libm.h"
...
一个工程只能有一个main
入口,所以需要修改ffmpeg.c
的main
函数为int ffmpeg_main
,并且在ffmpeg.h
文件声明一下
// ffmpeg.h
int ffmpeg_main(int argc, char **argv);
编译通过后,我们就可以通过xcode来执行ffmpeg的指令,将mp4生成一个gif
ffmpeg -i out.mp4 out.gif
对应的iOS代码,引入ffmpeg.h
头文件,以下路径是在模拟器跑的,真机需要修改一下输出路径
NSString *filePath = [[NSBundle mainBundle] pathForResource:@"out.mp4" ofType:nil];
NSString *outPath = @"/Users/maple/Desktop/out.gif";
int argc = 4;
char **arguments = (char **)calloc(argc, sizeof(char *));
if(arguments != NULL) {
arguments[0] = "ffmpeg";
arguments[1] = "-i";
arguments[2] = (char *)[filePath UTF8String];
arguments[3] = (char *)[outPath UTF8String];
NSLog(@"rescode=%d", ffmpeg_main(argc, arguments));
}
ffmpeg_main(argc, arguments);
或者通过这种方式调用,比较简练
NSString *filePath = [[NSBundle mainBundle] pathForResource:@"out.mp4" ofType:nil];
NSString *outPath = @"/Users/maple/Desktop/out.gif";
NSString *cmmondStr = [NSString stringWithFormat:@"ffmpeg -i %@ %@", filePath, outPath];
NSMutableArray *argv_arr = [cmmondStr componentsSeparatedByString:@" "].mutableCopy;
int argc = (int)argv_arr.count;
char **arguments = (char **)calloc(argc, sizeof(char *));
for(int i = 0; i < argc; i++) {
NSString *str = argv_arr[i];
arguments[i] = (char *)[str UTF8String];
}
ffmpeg_main(argc, arguments);
为了不让ffmpeg_main执行完后退出程序,这里注释了ffmpeg_main函数的最后一行
exit_program(received_nb_signals ? 255 : main_return_code);