iOS开发 - 超详细集成 FFmpeg 步骤

转自:https://blog.csdn.net/qq_30513483/article/details/87860390html

概述

网上充斥着大量的 iOS FFmpeg 编译的教程,有的时间比较早了,有的不少都没有说详细,或者有个别坑做者没有讲到,有的讲到到了一半,没有例子。linux

因此本人参考了网上的编译FFmpeg教程到集成的不少文章,而后加上本人进行了实际操做,总结出了此篇文章,但愿你们若是有用到FFmpeg,之后少走一些坑。c++

此篇文章内容会包含:git

重新建 iOS 工程 -------> 到调用FFmpeg 命令 -------> 直到运行项目成功的本人实操的全部步骤。程序员


目录

  1. FFmpeg 简介
  2. FFmpeg 的编译
  3. iOS 集成 FFmpeg
  4. iOS 集成 FFmpeg Tool
  5. 优化解决集成后问题
  6. iOS 调用 FFmpeg Tool

1、FFmpeg 简介github


1,FFmpeg 是什么 ?算法

你能够把 FFmpeg 理解成一套音视频解决方案,使用 C语言 开发的开源程序,而且免费、开源、跨平台,它提供了录制、转换以及流化音视频,编码,特效,视音频操做等功能,包含了很是先进的音频/视频编解码库。api

(1)FFmpeg 能作什么 ?浏览器

能够实现播放歌曲、视频,甚至经过命令实现对 视频文件的转码、混合、剪辑,采集等各
种复杂处理。
ruby

(2)哪些地方用到了FFmpeg?

使 FFmpeg内核视频播放 : Mplayer,射手播放器 ,暴风影音 ,KMPlayer...
使 FFmpeg做为内核的Direct show Filter 解码 : ffdshow,lav filters...
使 FFmpeg做为内核的转码工具: ffmpeg,格式工厂...

2,FFmpeg 做者

法布里斯·贝拉(FabriceBellard)是一位著名的计算机程序员,1972年生于法国Grenoble,大学就读于巴黎高等综合理工学院,后在国立巴黎高等电信学院攻读。因FFmpeg、QEMU等项目而闻名业内。他也是最快圆周率算法贝拉公式、TCCBOOT和TCC(微型C编译器)等项目的做者。

《我的成就》:

1997年 - 他发现了最快速的计算圆周率的算法。
2000年 - 他化名Gérard Lantau,建立了 FFmpeg 项目。
2004年 - 他编写了一个只有138KB的启动加载程序TCCBOOT,能够在15秒内从源代码编译并启动Linux系统。
2009年 - 他声称打破了圆周率计算的世界纪录,算出小数点后2.7万亿位,仅用一台普通PC机。
2011年 - 他单用JavaScript写了一个PC虚拟机Jslinux,实现能在浏览器里跑Linux 。



3,FFmpeg 项目的组成

(1)基本:

  • ffmpeg :是一个命令行工具,用来对视频文件转换格式;
  • ffsever :是一个HTTP多媒体实时广播流服务器;
  • ffplay :是一个简单的播放器,使用ffmpeg 库解析和解码,经过SDL显示;

(2)其它:

  • libavutil :包含一些公共的工具函数;
  • libavcodec :用于各类类型声音/图像编解码;
  • libswscale :用于视频场景比例缩放、色彩映射转换;
  • libpostproc :用于后期效果处理;
  • libavformat :用于音视频封装格式的生成和解析, 包括获取解码所需信息以生成解码上下文结构和读取音视频帧等功能。

4,FFmpeg 的使用方式 (FFmpeg 代码是包括两部分)

(1)一部分是library

  • 直接调用静态库,c语言的文件。
  • API 都是在library ,若是直接调 api 来操做视频的话,就须要写c或者c++了。

(2)一部分是 Tool

  • 使用的是命令行,则不须要本身去编码来实现视频操做的流程,实际上tool就是把命令行转换为api的操做,不须要使用者懂C++。

本篇文章实践部分,主要是使用 Tool 命令方式。


2、 FFmpeg 的编译

1. 介绍

  • FFmpeg是一个多平台多媒体处理工具,因此也能够在Mac下运行,先说一下Mac下如何安装FFmpeg。

2. 相关地址

3. 编译Mac下可用 FFmpeg

  • 编译Mac下可用 FFmpeg,主要是能够在mac中,使用 FFmpeg 进行操做视频等。

Homebrew介绍

  • 简称brew,是Mac OSX上的软件包管理工具,能在Mac中方便的安装软件或者卸载软件。

Homebrew安装

Homebrew命令

  • 搜索软件:brew search 软件名, 如brew search wget
  • 安装软件:brew install 软件名, 如brew install wget
  • 卸载软件:brew remove 软件名,如brew remove wget

经过Homebrew 安装 FFmpeg

  • 终端执行:执行 brew install ffmpeg --with-libvpx --with-libvorbis --with-ffplay

  • 在终端中执行一下命令,等待安装完成便可:

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

  2.  
  • 安装好Homebrew,而后终端执行 "brew install ffmpeg",等待完成便可。

  • 执行结束,在终端中输入ffmpeg,验证是否安装成功。

  • 若是显示大概如上图,那么说明安装成功

4. 编译 iOS 下 FFmpeg

  • 主要是用于iOS下进行使用FFmpeg

在进行编译以前,咱们首先须要作一些准备工做安装必备文件:

(1)安装 gas-preprocessor

  • 后面运行 FFmpeg-iOS-build-script 这个自动编译脚本须要 gas-preprocessor .

  • 安装步骤(依次执行下面命令):

 
  1. sudo git clone https://github.com/bigsen/gas-preprocessor.git /usr/local/bin/gas

  2. sudo cp /usr/local/bin/gas/gas-preprocessor.pl /usr/local/bin/gas-preprocessor.pl

  3. sudo chmod 777 /usr/local/bin/gas-preprocessor.pl

  4. sudo rm -rf /usr/local/bin/gas/

(2)安装 yams

  • yasm是汇编编译器,由于ffmpeg中为了提升效率用到了汇编指令,因此编译时须要安装

  • 安装步骤(依次执行下面命令):

 
  1. curl http://www.tortall.net/projects/yasm/releases/yasm-1.2.0.tar.gz -o yasm-1.2.0.gz

  2. tar -zxvf yasm-1.2.0.gz

  3. cd yasm-1.2.0

  4. ./configure && make -j 4 && sudo make install

(3)配置 FFmpeg 编译脚本

1. 说明:

  • 编译FFmpeg可以使用一个脚本:FFmpeg-iOS-build-script.sh。
  • FFmpeg-iOS-build-script 是一个外国人写的自动编译的脚本,脚本则会自动从github中把ffmpeg源码下到本地并开始编译出iOS可用的库,支持各类架构。
手动编译FFmpeg网上有一些方法,可是稍显复杂而陈旧, 因此使用这个脚本比较方便。

2. 脚本下载地址:

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

3. 配置FFmpeg版本:

  • 下载完成后咱们可指定编译的FFmpeg版本,修改 FF_VERSION 后面的参数就好了,本篇文章使用2.8版本。

配置裁剪(可选项):

FFmpeg库是一个很是庞大的库,包括编码,解码以及流媒体的支持等,若是不作裁剪所有编译进来的话,最后生成的静态库会很大。而且有不少不须要的东西,均可以禁止掉。

1. 配置裁剪方法:

修改配置 build-ffmpeg.sh 脚本里面 CONFIGURE_FLAGS 后面的内容便可
例如:

配置的一些参数是为了更好的选择本身须要的功能,进行精简和优化ffmpeg。
咱们能够手动看一下,在ffmpeg源码目录下,终端执行 ./configure --help列出所有参数 。下面简单列出部分参数:

标准选项参数

 
  1. --help : // 打印帮助信息 ./configure --help > ffmpegcfg.txt

  2. --prefix=PREFIX :// 安装程序到指定目录[默认:空]

  3. --bindir=DIR : // 安装程序到指定目录[默认:/bin]

  4. --datadir=DIR :// 安装数据文件到指定目录[默认:/share/ffmpeg]

  5. --incdir=DIR :// 安装头文件到指定目录[默认:/include]

  6. --mandir=DIR :// 安装man page到指定路径[默认:/share/man]

2. 配置选项参数

 
  1. --disable-static :// 不构建静态库[默认:关闭]

  2. --enable-shared :// 构建共享库

  3. --enable-gpl : // 容许使用GPL代码。

  4. --enable-nonfree :// 容许使用非免费代码。

  5. --disable-doc : // 不构造文档

  6. --disable-avfilter :// 禁止视频过滤器支持

  7. --enable-small : // 启用优化文件尺寸大小(牺牲速度)

  8. --cross-compile : // 使用交叉编译

  9. --disable-hwaccels :// 禁用全部硬件加速(本机不存在硬件加速器,全部不须要)

  10. --disable-network :// 禁用网络

 
  1. --disable-ffmpeg --disable-ffplay --disable-ffprobe --disable-ffserver

  2. // 禁止ffmpeg、ffplay、ffprobe、ffserver

  3.  
  4. --disable-avdevice --disable-avcodec --disable-avcore

  5. // 禁止libavdevice、libavcodec、libavcore

 
  1. --list-decoders : // 显示全部可用的解码器

  2. --list-encoders : // 显示全部可用的编码器

  3. --list-hwaccels : // 显示全部可用的硬件加速器

  4. --list-protocols : // 显示全部可用的协议

  5. --list-indevs : // 显示全部可用的输入设备

  6. --list-outdevs : // 显示全部可用的输出设备

  7. --list-filters :// 显示全部可用的过滤器

  8. --list-parsers :// 显示全部的解析器

  9. --list-bsfs : // 显示全部可用的数据过滤器

 
  1. --disable-encoder=NAME : // 禁用XX编码器 | disables encoder NAME

  2. --enable-encoder=NAME : // 用XX编码器 | enables encoder NAME

  3. --disable-decoders : // 禁用全部解码器 | disables all decoders

  4.  
  5. --disable-decoder=NAME : // 禁用XX解码器 | disables decoder NAME

  6. --enable-decoder=NAME : // 启用XX解码器 | enables decoder NAME

  7. --disable-encoders : // 禁用全部编码器 | disables all encoders

  8.  
  9. --disable-muxer=NAME : // 禁用XX混音器 | disables muxer NAME

  10. --enable-muxer=NAME : // 启用XX混音器 | enables muxer NAME

  11. --disable-muxers : // 禁用全部混音器 | disables all muxers

  12.  
  13. --disable-demuxer=NAME : // 禁用XX解轨器 | disables demuxer NAME

  14. --enable-demuxer=NAME : // 启用XX解轨器 | enables demuxer NAME

  15. --disable-demuxers : // 禁用全部解轨器 | disables all demuxers

  16.  
  17. --enable-parser=NAME : // 启用XX剖析器 | enables parser NAME

  18. --disable-parser=NAME : // 禁用XX剖析器 | disables parser NAME

  19. --disable-parsers : // 禁用全部剖析器 | disa

运行脚本生成 FFmpeg:

配置好选项参数后就能够运行脚本,等待生成FFmpeg库。

运行完毕就会生成:

  • ffmpeg-2.八、FFmpeg-iOS 、scratch、thin 等这些文件夹。

  • lib:对应的 FFmpeg 静态库

     

  • include:对应的 FFmpeg 头文件

     

3、iOS 下 集成 FFmpeg

生成完FFmpeg库与代码后,咱们就能够集成到iOS项目中进行使用

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

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

2,导入库文件

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

$(SRCROOT)/FFmpeg_iOS/FFmpeg/include

(3)而后导入 #import "avformat.h" 在代码中 写 av_register_all() 而后进行编译,若是没有报错,表明编译成功。

4、iOS 运行 FFmpeg Tool

(1)到这一步其实已经可使用library库了,若是要对音视频进行操做,须要手动写C++代码去调用 API 使用FFmpeg。

(2)若是想要使用Tool工具来调用 FFmpg 的话,就是直接经过调用传参的方式执行ffmpeg 命令的话,就须要:

  • 把剩下的 ffmpeg.h ffmpeg.c 等依赖的文件拖进项目中,并导入ffmpeg.h 文件。
  • 而后进行调用 ffmpeg_main 函数传递参数,执行 ffmpeg 命令便可。

FFmpeg Tool 相关文件:

  • ffmpeg.c
  • ffmpeg.h
  • ffmpeg_opt.c
  • ffmpeg_filter.c
  • cmdutils.c
  • cmdutils.h
  • cmdutils_common_opts.h

  • config.h 文件 (在scratch目录下四个文件都有 ):

示例 - 拖入对应文件到工程

注释掉无关代码:

  • 若是把相关其余文件导入后,编译的时候会发现有一些头文件好比 <avutil/internal.h>找不到。
    不用担忧,在我了解到 应该是 在 iOS 的 arm下不支持,也就不须要了。
  • 那么这时候只须要把报红的地方注释掉就好了,另外若是精简掉某些库,那么依赖的类文件也会找不到,也是直接注释掉相关报错没问题的。

头文件

 
  1. #include "compat/va_copy.h"

  2. #include "libavresample/avresample.h"

  3. #include "libpostproc/postprocess.h"

  4. #include "libavutil/libm.h"

  5. #include "libavutil/time_internal.h"

  6. #include "libavutil/internal.h"

  7. #include "libavutil/libm.h"

  8. #include "libavformat/network.h"

  9. #include "libavcodec/mathops.h"

  10. #include "libavformat/os_support.h"

宏定义调用

FF_DISABLE_DEPRECATION_WARNINGS

函数调用

 
  1. nb0_frames = nb_frames = mid_pred(ost->last_nb0_frames[0],

  2. ost->last_nb0_frames[1],

  3. ost->last_nb0_frames[2]);

  4.  
  5. ff_dlog(NULL, "force_key_frame: n:%f n_forced:%f prev_forced_n:%f t:%f prev_forced_t:%f -> res:%f\n",

  6. ost->forced_keyframes_expr_const_values[FKF_N],

  7. ost->forced_keyframes_expr_const_values[FKF_N_FORCED],

  8. ost->forced_keyframes_expr_const_values[FKF_PREV_FORCED_N],

  9. ost->forced_keyframes_expr_const_values[FKF_T],

  10. ost->forced_keyframes_expr_const_values[FKF_PREV_FORCED_T],

  11. res);

  12.  
  13. PRINT_LIB_INFO(avresample, AVRESAMPLE, flags, level);

  14. PRINT_LIB_INFO(postproc, POSTPROC, flags, level);

其它

 
  1. { "videotoolbox_pixfmt", HAS_ARG | OPT_STRING | OPT_EXPERT, { &videotoolbox_pixfmt}, "" },

  2.  
  3. { "videotoolbox", videotoolbox_init, HWACCEL_VIDEOTOOLBOX, AV_PIX_FMT_VIDEOTOOLBOX },

解决导入后编译问题:

  • GIF文件大小有限制,分开上传了

(1)解决编译问题1:

  •  

(2)解决编译问题2:

若是提示如下错误,还需注释如下代码

 
  1. { "videotoolbox_pixfmt", HAS_ARG | OPT_STRING | OPT_EXPERT, { &videotoolbox_pixfmt}, "" },

  2.  
  3. { "videotoolbox", videotoolbox_init, HWACCEL_VIDEOTOOLBOX, AV_PIX_FMT_VIDEOTOOLBOX },

(3)解决main函数重复问题

FFmpeg也有个main函数,若是不更名就会冲突报错。

  • 打开 ffmpeg.c 文件,找到main函数,修改成 ffmpeg_main。
  • 并在 ffmpeg.h 中声明。

5、优化解决集成后问题

这个时候,咱们应该已经可否编译成功了,可是还有一些小问题,须要修改下。

1. 计数器置零问题 (ffmpeg.c的代码中会访问空属性致使程序崩溃)

  • 解决方法:
  • 在 ffmpeg.c 中 找到 ffmpeg_cleanup 方法,在 term_exit() 前,将各个计数器置零:
 
  1. nb_filtergraphs=0;

  2. nb_output_files=0;

  3. nb_output_streams=0;

  4. nb_input_files=0;

  5. nb_input_streams=0;

  • 以下图:

2. 命令执行结束崩溃问题

说明

  • FFmpeg 默认执行完会执行 exit_program 方法结束进程,而iOS下只能启动一个进程,若是默认不作处理,执行完一条命令后app就自动退出了,因此须要作一个处理。

解决方案有两种:

(1)第一种方案(有缺点):

  • 网上流传的方法的方法都是找到 exit_program 函数,而后注释掉结束进程的代码,而后调用 pthread_exit 结束线程来代替结束进程,进行解决。

这种方法的缺点:

  • 执行完 ffmpeg 的 main 函数后会回调一个code,这个回调是用于判断命令指定过程当中是否执行错误的回调。可是咱们若是在退出的时候调用了pthread_exit 这样线程就结束了,而后也不会走执行是否成功的回调了。
  • 而且这样的话,想要监听到命令结束,必需要注册一个通知,进行监听线程结束。

(2)第二种方案(修复缺点):

  • 在命令执行完不进行结束线程和进程,只进行 cleanup。

具体作法:

  • 在 ffmpeg.c 的 ffmpeg_main 函数中,把全部调用 exit_program 函数 ,改成调用 ffmpeg_cleanup 函数就能够了。

     

6、iOS 调用 FFmpeg Tool

目前为止,咱们作完上面全部步骤后,咱们已经能够调用 FFmpeg Tool 进行各类音视频操做了,例如 视频合成、视频转Gif、视频帧操做、视频特效、格式转换,视频调速,等各类操做了。

1. FFmpeg 命令简单介绍

使用ffmpeg命令行的大体格式以下:

ffmpeg [options] [[infile options] -i infile]... {[outfile options] outfile}...

2. FFmpeg 命令常见参数

-f 强制指定编码格式
-i 输出源
-t 指定输入输出时长
-r 指定帧率,即1S内的帧数
-threads 指定线程数
-c:v 指定视频的编码格式
-ss 指定持续时长
-b:v 指定比特率
-s 指定分辨率
-y 覆盖输出
-filter 指定过滤器
-vf 指定视频过滤器
-an 指定去除对音频的影响











3. FFmpeg 命令示例 (更多使用可查看其它文档)

 
  1. 格式转换

  2. ffmpeg -i mkv.mkv -acodec copy -vcodec copy newVideo.mp4

  3. ffmpeg -i wav.wav -ar 44100 -y outputmusic.aac

  4.  
  5. 视频转GIF

  6. ffmpeg -i mkv.mkv -ss 00:00:10 -t 10 -pix_fmt rgb24 -f gif -s vga gif.gif

  7.  
  8. 视频声音分离 与合成

  9. ffmpeg -i mp4.mp4 -f mp3 -vn mp3.mp3

  10. ffmpeg -i mp4.mp4 -an mp4No.mp4

  11. ffmpeg -i mp3.mp3 -i mp4No.mp4 -map 0:0 -map 1:0 -c:v copy -c:a libfaac sound.mp4

  12.  
  13. 旋转视频

  14. ffmpeg -i mp4.mp4 -vf transpose=2 transpose.mp4

  15.  
  16. 反转视频

  17. 水平翻转 :ffmpeg -i mp4.mp4 -vf hflip reversed.mp4

  18. 垂直翻转 :ffmpeg -i mp4.mp4 -vf vflip reversed.mp4

  19.  
  20. 合并视频

  21. ffmpeg -f concat -i filelist.txt -y -acodec copy -strict -2 toName

  22.  
  23. 水印字幕合成

  24. ffmpeg -i fromName -i fromOther -filter_complex [0:v][1:v]overlay=0:H-h:enable='between(t,0,1)'[tmp];[tmp][1:v]overlay=0:H-h:enable='between(t,3,4)' -t 7 -y -strict -2 toName

4. iOS 中调用FFmpeg Tool 示例:

(1)第一种调用方式

简单容易理解,可是麻烦。

 
  1. #import "ViewController.h"

  2. #import "ffmpeg.h"

  3. @interface ViewController ()

  4. @end

  5. @implementation ViewController

  6. - (void)viewDidLoad {

  7. [super viewDidLoad];

  8.  
  9. NSString *fromFile = [[NSBundle mainBundle]pathForResource:@"video.mov" ofType:nil];

  10. NSString *toFile = @"/Users/sen/Desktop/Output/video.gif";

  11.  
  12. int argc = 4;

  13. char **arguments = calloc(argc, sizeof(char*));

  14. if(arguments != NULL)

  15. {

  16. arguments[0] = "ffmpeg";

  17. arguments[1] = "-i";

  18. arguments[2] = (char *)[fromFile UTF8String];

  19. arguments[3] = (char *)[toFile UTF8String];

  20.  
  21. if (!ffmpeg_main(argc, arguments)) {

  22. NSLog(@"生成成功");

  23. }

  24. }

  25. }

  26. @end

(2)第二种调用方式

比第一种方案,遍历 FFmpeg 字符串命令,而后调用ffmpeg_main 传递参数。

 
  1. /**

  2. 第二种调用方式

  3. */

  4. - (void)normalRun2{

  5.  
  6. NSString *fromFile = [[NSBundle mainBundle]pathForResource:@"video.mov" ofType:nil];

  7. NSString *toFile = @"/Users/sen/Desktop/Output/video.gif";

  8.  
  9. NSString *command_str = [NSString stringWithFormat:@"ffmpeg -i %@ %@",fromFile,toFile];

  10.  
  11. // 分割字符串

  12. NSMutableArray *argv_array = [command_str componentsSeparatedByString:(@" ")].mutableCopy;

  13.  
  14. // 获取参数个数

  15. int argc = (int)argv_array.count;

  16.  
  17. // 遍历拼接参数

  18. char **argv = calloc(argc, sizeof(char*));

  19.  
  20. for(int i=0; i<argc; i++)

  21. {

  22. NSString *codeStr = argv_array[i];

  23. argv_array[i] = codeStr;

  24. argv[i] = (char *)[codeStr UTF8String];

  25. }

  26.  
  27. ffmpeg_main(argc, argv);

  28. }

结尾

  • 文中Demo:https://github.com/bigsen/FFmpeg_iOS
  • 到目前咱们已经能够在iOS平台调用FFmpeg了,更多FFmpeg命令可查看其它相关文章。
  • 后续的话,我会放出一款工具,能够更方便的调用FFmpeg进行处理命令。
相关文章
相关标签/搜索