编译FFmpeg4.1

8月26日更新: 由于之前编译后得到的包体积过大(增加了40M)左右 , 整个包有很多暂时使用不到的组件 , 因此需要对FFmpeg的编译库进行轻量化配置 , 经过选项配置 , 编译后库的大小减少了30M左右!~

配置CONFIGURE_FLAGS参数 , 把ffprobe、ffplay、avresample、sdl2都给关掉 , 这样在编译时就不会把这些组件增加进去

CONFIGURE_FLAGS="--enable-cross-compile --disable-debug --disable-programs --disable-doc --enable-pic --disable-shared --disable-ffprobe --disable-ffplay --disable-avresample --disable-sdl2"

关于Configure_flags的配置参数可以通过命令行ffmpeg -help查看支持的组件命令 , 再选择裁剪 , 这里有篇较新的参考文档,比较全面而且分类清晰

前言

之所以要采用FFmpeg , 是因为原本使用系统原生api进行压缩转码时 , 发现某部分视频会转码失败或者转码出来的格式阿里云不支持 , 导致无法正常播放

安装步骤

0.去https://github.com/bigsen/gas-preprocessor.git 下载gas-preprocessor, 编译时需要用到, 然后把它放到/usr/local/bin/ 下面 , 并且执行命令给与权限
sudo chmod 777 /usr/local/bin/gas-preprocessor.pl

  1. 首先安装下yasm
    brew install yasm
  2. 下载ffmpeg的编译脚本(如果自己编译的话难度很大 , 所幸已经有脚本帮助我们走流程)

(3-5 是编译 x264和 fdk-aac 插件步骤, 为了让FFmpeg支持更多的指令)

  1. ①从[官网] https://www.videolan.org/developers/x264.html] 直接下载最新版源码。
    ②从 https://github.com/kewlbear/x264-ios 下载编译脚本build-x264.sh
    ③把源码解压到x264目录,把编译脚本build-x264.sh放到x264同级目录,根据需要编译的archs修改脚本。(注意脚本里面SOURCE变量的目录名称对不对)
    ④然后执行 ./build-x264.sh
  2. ①从[官网http://www.linuxfromscratch.org/blfs/view/svn/multimedia/fdk-aac.html] 直接下载最新版源码。
    ②从https://github.com/kewlbear/fdk-aac-build-script-for-iOS下载编译脚本build-fdk-aac.sh
    ③把源码解压,把编译脚本 build-fdk-aac.sh 放到解压出来的fdk-aac-2.0.0同级目录根据需要编译的archs 及fdk-aac源码目录修改脚本。(注意脚本里面SOURCE变量的目录名称对不对)
    ④然后执行 ./build-x264.sh
    !!! 编译x264和fdk-aac的时候, 如果需要编译模拟器架构的话, 有可能会报错
    Minimum version is NASM version 2.13

这时候是因为系统自带的nasm汇编编译器太旧了, 直接用brew reinstall nasm 重装, 升级到最新的2.14版本

  1. 把编译好的x264和fdk-aac 库和头文件放到build-ffmpeg.sh脚本同级目录下, 打开修改 build-ffmpeg.sh 脚本的配置
# 把变量修改成对应的目录名称
X264=`pwd`/x264-iOS  
FDK_AAC=`pwd`/fdk-aac-ios
  1. 编译前可以打开build-ffmpeg.sh脚本, 配置一下裁剪参数CONFIGURE_FLAGS 和支持平台ARCHS 打开文件在根目录下打开终端运行脚本 build-ffmpeg.sh , 脚本会自动下载ffmpeg4.x(反正会下载最新的) , 然后编译生成各个平台的静态库和对应平台的相关代码
    image.png
  2. 为了能真机和模拟器都能使用 , 执行完脚本后再执行一遍 , 会把所有平台的.a文件合并成fat包
    ./build-ffmpeg.sh lipo
  3. 将FFmpeg-iOS整个文件夹拖进项目中 , 在build setting 中搜索search path , 配置Library Search Paths和 Header Search Paths , 为对应的lib和include路径(一般拖进项目时lib路径会自动填充好)
  4. 添加依赖库
libz.tbd
libbz2.tbd
libiconv.tbd
videoToolbox.framework
  1. 然后随便找个.m文件导入 , 写几行代码编译看看会不会报错(后面删掉!)
#import <libavformat/avformat.h>
#import <libavcodec/avcodec.h>
#import <libswscale/swscale.h>
#import <libavutil/avutil.h>
#import <libswresample/swresample.h>
#import <libavdevice/avdevice.h>
#import <libavfilter/avfilter.h>
{
    av_register_all();
    avcodec_register_all();
    avformat_network_init();
}

到这里已经可以直接通过c++api使用库了 , 但是如果要用命令则需要添加其他依赖文件

  1. 打开FFmpeg-4.1(源码目录),在fftools中找到除了config.h的其他8个文件(网上较旧的文章都不需要 ffmpeg_hw.c文件, 但是在4.1中需要 , 不然会报错)
    image.png
  1. 打开ffmpeg.c , 把main函数修改一下 , 因为一个程序不能有两个main函数 , 还有在.h把这个方法声明一下
ffmpeg.h ----
    int ffmpeg_main(int argc, char **argv);
ffmpeg.m ----
    int ffmpeg_main(int argc, char **argv){
}
  1. 打开cmdutils.c文件 , 把exit_program函数改一下 , 因为这个函数会退出进程 , 我们先直接啥都不干 , 后面改成其他操作
    void exit_program(int ret)
    {
        //if (program_exit)
        //    program_exit(ret);
        //exit(ret);
}
  1. 接下就是编译看看报什么错误 , 然后去源码目录中找到相应的头文件,放到include目录下相应的文件夹中
    处理完错误之后会发现在真机上已经可以运行了 , 但是在模拟器上还是会报SDL相关错误 , 但是我们已经合并了多平台静态库 , 为什么还会报错呢 ?

既然报SDL错误, 那么我们就给他SDL库

  1. 去SDL官网下载2.0的源码包

  2. 下载好后解压 , 在根目录中找到Xcode-iOS-SDL-SDL.xcodeproj , 打开项目 , 在Public Headers中找到SDL_main.h , 添加一行宏定义 , 因为SDL本身有main函数 , 如果定义了SDL_MAIN_HANDLED , 就说明自己有main函数, 不需要使用SDL的
    #define SDL_MAIN_HANDLED

  3. 分别选择模拟器和真机编译一下 , 在products目录就有对应的.a文件 , 右键打开Finder , 用lipo命令把他们合并起来
    lipo -create xxx/.a xxx/.a -output xxx/libSDL2.a

    image.png

  4. 在项目中新建SDL文件夹 , 再新建lib文件夹 , 把SDL2.a丢进去 , 再从源码目录中找到include头文件拖入SDL目录 , 配置对应的Header Search 路径 , 添加两个需要的库

GameController
CoreMotion

到这里已经可以开始使用了 , 但是有一些地方的代码还需要修改下

  1. ffmpeg.c中的 ffmpeg_cleanup方法 , 需要把一些计数变量清空 , 否则会导致下一次转码崩溃 !!!!后面发现, 把这一部分代码移到exit_program 中更加适合
    avformat_network_deinit();
    //在👆这行代码之前的逻辑所有内存后  添加清空计数代码
    //这里不清空会导致下一个视频转码崩溃  
    nb_filtergraphs = 0;
    nb_input_files = 0;
    nb_input_streams = 0;
    nb_output_files = 0;
    nb_output_streams = 0;
    //    nb_frames_dup = 0;
    //    nb_frames_drop = 0;
    //    run_as_daemon = 0;
  1. 想获取转码进度的话 , 需要些一个桥接类 , 创建任意一个cocoa touch类,把.h文件中所有东西都删除掉,.m中只留下头文件导入的代码 。 这样在.h 中就可以声明c函数 在点m中调用 就能完成C和OC之间的通信
//声明这几个方法
// 转换停止回调
void stopRuning(void);
// 获取总时间长度
void setDuration(long long int time);
// 获取当前时间
void setCurrentTime(char info[1024]);
  1. 再新建一个用来管理转码的类
➕(VSFFmpegManager *)sharedManager;
/**
 转换视频
 @param inputPath 输入视频路径
 @param outpath 输出视频路径
 @param processBlock 进度回调
 @param completionBlock 结束回调
 */
➖ (void)converWithInputPath:(NSString *)inputPath
                 outputPath:(NSString *)outpath
               processBlock:(void (^)(long long spendTime , long long totalTime))processBlock
            completionBlock:(void (^)(NSError *error))completionBlock;
// 设置总时长
➕(void)setDuration:(long long)time;
// 设置当前时间
➕(void)setCurrentTime:(long long)time;
// 转换停止
➕(void)stopRuning;
  1. 监控转码的开始和完成状态 , 在C++函数中调用OC方法,来传递状态信息 , cmdutils.c 中的 exit_program 结束线程前调用stopRuning()结束方法 , 并且把原本的结束进程方法改为退出线程
//需要导入
#include <pthread.h>
#include “VSFFmpegConverOC.h"
void exit_program(int ret){
    //标记为转换完成
    stopRuning();
    if (program_exit)
        program_exit(ret);
    //这个是结束进程的方法,让ffmpeg进行完转码以后不至于退出程序
    //exit(ret);
    //所以将退出进程的方法改造为退出线程
    pthread_exit(NULL);
}
  1. 要获取视频文件总时间长度 , ffmpeg_opt.copen_input_file方法中会有时长信息 ic->duration , 为long long int类型数据
#include “VSFFmpegConverOC.h"
    //获取文件总时长信息
    setDuration(ic->duration);
    //👇在这行代码前 , 其实也就是尽量在加载完文件之后去获取就行了
    input_stream_potentially_available = 1;
  1. 定时获取当前进度时间 , ffmpeg.c的print_report方法中会输出Log,从log中获取当前的进度信息,为char info[1024]类型数据
#include “VSFFmpegConverOC.h”
//4.1中的buf改成了一个结构体 , 里面的str是char *类型
av_log(NULL, AV_LOG_INFO, "%s    %c", buf.str, end);
//在打印之后获取转码的当前时间
 setCurrentTime(buf.str);
  1. 转换百分比为当前进度除以总时长。注意事项:更改进度条的时候,是在非主线程,所以无法更改UI,需要在主线程执行更改UI操作

到这里就完成了ffmpeg的编译和静态库的相关配置

然后就可以使用了!!!

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,117评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,328评论 1 293
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,839评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,007评论 0 206
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,384评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,629评论 1 219
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,880评论 2 313
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,593评论 0 198
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,313评论 1 243
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,575评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,066评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,392评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,052评论 3 236
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,082评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,844评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,662评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,575评论 2 270

推荐阅读更多精彩内容