FFmpeg iOS 集成过程

记录最新FFmpeg-ios集成过程,方便查看。

FFmpeg 官网 : http://ffmpeg.org/download.html
FFmpeg 源码 : https://github.com/FFmpeg/FFmpeg
FFmpeg doc : http://www.ffmpeg.org/documentation.html
FFmpeg wiki : https://trac.ffmpeg.org/wiki
Homebrew 安装网站 : http://brew.sh/index_zh-cn.html
FFmpeg官方安装教程 : https://trac.ffmpeg.org/wiki/CompilationGuide/MacOSX

安装过程Homebrew

ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"

如果之前装过Homebrew,查是否装过,命令输入

brew

要是报Version value must be a string; got a NilClass () (TypeError),则执行命令brew update-reset。

Error: homebrew-core is a shallow clone.
删除homebrew-core后更新即可

cd /usr/local/Homebrew/Library/Taps/homebrew
rm -rf homebrew-core
brew upgrade

fatal: unable to access 'https://github.com/homebrew/brew/':
解决方案:

git config --global --unset http.proxy
git config --global --unset https.proxy

安装过程ffmpeg

安装好Homebrew,然后终端执行

brew install ffmpeg

等待完成即可。
执行结束,在终端中输入

ffmpeg

验证是否安装成功。

安装 gas-preprocessor

后面运行 FFmpeg-iOS-build-script 这个自动编译脚本需要 gas-preprocessor,将 gas-preprocessor.pl 文件复制到/usr/local/bin/ 目录下,然后为文件开启可执行权限,删掉下载的文件

sudo git clone https://github.com/bigsen/gas-preprocessor.git /usr/local/bin/gas
sudo cp /usr/local/bin/gas/gas-preprocessor.pl /usr/local/bin/gas-preprocessor.pl
sudo chmod 777 /usr/local/bin/gas-preprocessor.pl
sudo rm -rf /usr/local/bin/gas/

安装 yams

yasm是汇编编译器,因为ffmpeg中为了提高效率用到了汇编指令,所以编译时需要安装

brew install yasm

检测是否已安装 yasm

brew info yasm

配置 FFmpeg 编译脚本

编译FFmpeg可使用一个脚本:FFmpeg-iOS-build-script.sh。
FFmpeg-iOS-build-script 是一个外国人写的自动编译的脚本,脚本则会自动从github中把ffmpeg源码下到本地并开始编译出iOS可用的库,支持各种架构。
脚本下载地址:

git clone https://github.com/kewlbear/FFmpeg-iOS-build-script.git

或者进入 gitHub 网站,下载 FFmpeg-iOS-build-script (https://github.com/kewlbear/FFmpeg-iOS-build-script)。
下载好压缩包,编译脚本,打包出我们需要的 iOS 的 ffmpeg 库

To build everything:
  ./build-ffmpeg.sh

To build arm64 libraries:
  ./build-ffmpeg.sh arm64

To build fat libraries for armv7 and x86_64 (64-bit simulator):
  ./build-ffmpeg.sh armv7 x86_64

To build fat libraries from separately built thin libraries:
  ./build-ffmpeg.sh lipo

此时我们选择 ./build-ffmpeg.sh 编译arm64 armv7 x86_64 i386

iOS 下 集成 FFmpeg

新建一个空项目,在Link Binary With Libraries 里添加

libz.tbd
libbz2.tbd
libiconv.tbd
CoreMedia.framework
VideoToolbox.framework
AudioToolbox.framework
AVFoundation.framework

将目录下的 include 和 lib文件夹 拖拽进项目中,设置 Header Search Paths 路径,指向 项目中include目录(如

"$(SRCROOT)/FFmpegTest/FFmpeg-iOS/include"

没加双引号,路径中间有空格会就成两个路径,没空格加不加引号都一样) 。
然后导入

 #import "avformat.h"

在代码中 写

av_register_all();

然后进行编译,如果没有报错,代表编译成功( av_register_all()已经过时了,但是还可以验证是不是引用ffmpeg对了)。
到这一步其实已经可以使用library库了,如果要对音视频进行操作,需要手动写C++代码去调用 API 使用FFmpeg。

iOS 运行 FFmpeg Tool

如果想要使用Tool工具来调用 FFmpg 的话,就是直接通过调用传参的方式执行ffmpeg 命令的话,就需要:
把剩下的 ffmpeg.h ffmpeg.c 等依赖的文件拖进项目中,并导入

#import "ffmpeg.h"

文件。
然后进行调用 ffmpeg_main 函数传递参数,执行 ffmpeg 命令即可。
FFmpeg Tool 相关文件:
cmdutils.c
cmdutils.h
config.h
ffmpeg_filter.c
ffmpeg_hw.c
ffmpeg_opt.c
ffmpeg_videotoolbox.c
ffmpeg.c
ffmpeg.h
9个文件
config.h 文件 (在scratch目录下四个文件都有 )
把这几个文件拖入对应文件到工程


image.jpeg

如果把相关其他文件导入后,编译的时候会发现有一些头文件找不到,如

#include "libavutil/thread.h"
#include "libavutil/reverse.h"
#include "libavutil/libm.h"
#include "libpostproc/postprocess.h"
#include "libpostproc/version.h"
#include "libavformat/os_support.h"
#include "libavcodec/mathops.h"

去相应的ffmpeg目录找,还有一些比如

#include "libavresample/avresample.h"
#include "compat/va_copy.h" 
#include "libavutil/internal.h"

注释掉就可以了。

解决main函数重复问题
FFmpeg也有个main函数,如果不改名就会冲突报错。
打开 ffmpeg.c 文件,找到main函数,修改为 ffmpeg_main。
并在 ffmpeg.h 中声明。

最终引入的如下图


image.jpeg

优化解决集成后问题

编译成功了,但是还有一些小问题,比如重复执行ffmpeg报的bug,需要修改下。

  1. 计数器置零问题 (ffmpeg.c的代码中会访问空属性导致程序崩溃)
    解决方法:
    在 ffmpeg.c 中 找到 ffmpeg_cleanup 方法,在 term_exit() 前,将各个计数器置零:
nb_filtergraphs=0;
nb_output_files=0;
nb_output_streams=0;
nb_input_files=0;
nb_input_streams=0;
  1. 命令执行结束崩溃问题
    1)第一种方案:
    改关闭进程为关闭线程
    网上流传的方法的方法都是找到 exit_program 函数,然后注释掉结束进程的代码,然后调用 pthread_exit 结束线程来代替结束进程,进行解决。
    这种方法的缺点:
    执行完 ffmpeg 的 main 函数后会回调一个code,这个回调是用于判断命令指定过程中是否执行错误的回调。但是我们如果在退出的时候调用了pthread_exit 这样线程就结束了,然后也不会走执行是否成功的回调了。
    并且这样的话,想要监听到命令结束,必须要注册一个通知,进行监听线程结束。也可以用下面的方式去掉av_noreturn,会执行回调。
    cmdutils.h
void exit_program(int ret);//后面的av_noreturn去掉,这个是给编译器的注解。

cmdutils.c

void exit_program(int ret)
{
    if (program_exit)
        program_exit(ret);

    //通知OC
    //dosomething();
    
    //把下面退出进程的注释
//    exit(ret);
    //只结束线种
    //关闭线程需要导入#include <pthread.h>
//    pthread_exit("all thread");
}

结束主线程会把主线程关掉了,所以想再次执行FFmpeg时就不会执行了,所以都注释掉不要关闭进程线程了。

第二种方案:
在命令执行完不进行结束线程和进程,只进行 cleanup。
具体做法:
在 ffmpeg.c 的 ffmpeg_main 函数中,把所有调用 exit_program 函数 ,改为调用 ffmpeg_cleanup 函数就可以了,

exit_program(1);

替换为

ffmpeg_cleanup(1);

测试视频转gif

导入头文件

#import "ffmpeg.h"
    NSString *fromFile = [[NSBundle mainBundle]pathForResource:@"abc.mp4" ofType:nil];
    
    NSString *toFile = @"/Users/limuyi/MyWork/aa/video.gif";
    
    NSFileManager *fileManager = [NSFileManager defaultManager];
    if ([fileManager fileExistsAtPath:toFile]) {
        [fileManager removeItemAtPath:toFile error:nil];
    }
    
    
//    int argc = 4;
//    char **arguments = calloc(argc, sizeof(char*));
//    if(arguments != NULL)
//    {
//        arguments[0] = "ffmpeg";
//        arguments[1] = "-i";
//        arguments[2] = (char *)[fromFile UTF8String];
//        arguments[3] = (char *)[toFile UTF8String];
//        if (!ffmpeg_main(argc, arguments)) {
//            NSLog(@"生成成功");
//        }
//    }
    
    char *a[] = {
        "ffmpeg", "-i", (char *)[fromFile UTF8String], (char *)[toFile UTF8String]
    };

    int result = ffmpeg_main(sizeof(a)/sizeof(*a), a);
    NSLog(@"生成结果 %d",result);

最后输出路径就有gif图啦


图片.png

DEMO
链接: https://pan.baidu.com/s/1hio5oa78HrrJPBFEmp0Tpw 提取码: 5i7z 复制这段内容后打开百度网盘手机App,操作更方便哦

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

推荐阅读更多精彩内容