iOS 中集成 FFmpeg

ffmpeg

FFmpeg是一套可以用来记录、转换数字音频、视频,并能将其转化为流的开源计算机程序。它提供了录制、转换以及流化音视频的完整解决方案

ffmpeg的代码是包括两部分的,一部分是library,一部分是tool。api都是在library里面,如果直接调api来操作视频的话,就需要写c或者c++了。另一部分是tool,使用的是命令行,则不需要自己去编码来实现视频操作的流程。

从编译FFmpeg ——> 到使用FFmpeg ——> 注意事项

一、编译FFmpeg

  1. 编译FFmpeg所需的脚本文件gas-preprocessor
  • 下载之后,将 gas-preprocessor.pl 文件复制到 /usr/sbin/ 目录下,如果该目录无法修改,那么可将文件复制到 /usr/local/bin/ 目录下。
  • 为 gas-preprocessor.pl 文件开启可执行权限,在终端中进行如下命令:
chmod 777 /usr/sbin/gas-preprocessor.pl
或者
chmod 777 /usr/local/bin/gas-preprocessor.pl
  1. yasm 1.2.0 yasm 是一个完全重写的 NASM 汇编。它支持x86和AMD64指令集。
    可以使用homebrew来安装,如果没有install yasm,在执行./build-ffmpeg.sh命令的时候,会自动检测并安装。
brew install yasm
  1. 编译脚本FFmpeg-iOS-build-script
    在这个文件中,我们可以对要进行编译的FFmpeg进行一系列的设置。
    FFmpeg-iOS-build-script
  • 设置FFmpeg的版本
FF_VERSION="4.0.3"
  • 设置所要支持的架构
ARCHS="arm64 armv7 x86_64 i386"
  • 设置所需要的FFmpeg功能配置
禁用一些不必要的功能,可以有效地减小最终库文件的大小
CONFIGURE_FLAGS="--enable-cross-compile --disable-debug --disable-programs \
                 --disable-doc --enable-pic"
其中 --disable-cross-compile 禁止交叉编译
其中 --enable-cross-compile 支持交叉编译
  • 进入脚本所在文件夹目录,执行脚本
./build-ffmpeg.sh

执行结果
执行结果

二、将FFmpeg导入到项目中

将FFmpeg-iOS添加到项目中
FFmpeg-iOS lib文件
  • 添加依赖库

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

三、FFmpeg命令行功能

相关的命令行网络比较多,这里搜集整理了一些,整理备用,同时感谢共享

ffmpeg 命令集举例

  1. 获取视频的信息
ffmpeg -i video.avi 
  1. 将图片序列合成视频
ffmpeg -f image2 -i image%d.jpg video.mpg 

上面的命令会把当前目录下的图片(名字如:image1.jpg. image2.jpg. 等…)合并成video.mpg

  1. 将视频分解成图片序列
ffmpeg -i video.mpg image%d.jpg 

上面的命令会生成image1.jpg. image2.jpg. …
支持的图片格式有:PGM. PPM. PAM. PGMYUV. JPEG. GIF. PNG. TIFF. SGI

  1. 为视频重新编码以适合在iPod/iPhone上播放
ffmpeg -i source_video.avi input -acodec aac -ab 128kb -vcodec mpeg4 -b 1200kb -mbd 2 -flags +4mv+trell -aic 2 -cmp 2 -subcmp 2 -s 320x180 -title X final_video.mp4 

说明:

  • 源视频:source_video.avi
  • 音频编码:aac
  • 音频位率:128kb/s
  • 视频编码:mpeg4
  • 视频位率:1200kb/s
  • 视频尺寸:320 X 180
  • 生成的视频:final_video.mp4
  1. 为视频重新编码以适合在PSP上播放
ffmpeg -i source_video.avi -b 300 -s 320x240 -vcodec xvid -ab 32 -ar 24000 -acodec aac final_video.mp4 

说明:

  • 源视频:source_video.avi
  • 音频编码:aac
  • 音频位率:32kb/s
  • 视频编码:xvid
  • 视频位率:1200kb/s
  • 视频尺寸:320 X 180
  • 生成的视频:final_video.mp4
  1. 从视频抽出声音.并存为Mp3
ffmpeg -i source_video.avi -vn -ar 44100 -ac 2 -ab 192 -f mp3 sound.mp3 

说明:

  • 源视频:source_video.avi
  • 音频位率:192kb/s
  • 输出格式:mp3
  • 生成的声音:sound.mp3
  1. 将wav文件转成Mp3
ffmpeg -i son_origine.avi -vn -ar 44100 -ac 2 -ab 192 -f mp3 son_final.mp3 
  1. 将.avi视频转成.mpg
ffmpeg -i video_origine.avi video_finale.mpg 
  1. 将.mpg转成.avi
ffmpeg -i video_origine.mpg video_finale.avi 
  1. 将.avi转成gif动画(未压缩)
ffmpeg -i video_origine.avi gif_anime.gif 
  1. 合成视频和音频
ffmpeg -i son.wav -i video_origine.avi video_finale.mpg 
  1. 将.avi转成.flv
ffmpeg -i video_origine.avi -ab 56 -ar 44100 -b 200 -r 15 -s 320x240 -f flv video_finale.flv 
  1. 将.avi转成dv
ffmpeg -i video_origine.avi -s pal -r pal -aspect 4:3 -ar 48000 -ac 2 video_finale.dv 

或者:

ffmpeg -i video_origine.avi -target pal-dv video_finale.dv 
  1. 将.avi压缩成divx
ffmpeg -i video_origine.avi -s 320x240 -vcodec msmpeg4v2 video_finale.avi 
  1. 将Ogg Theora压缩成Mpeg dvd
ffmpeg -i film_sortie_cinelerra.ogm -s 720x576 -vcodec mpeg2video -acodec mp3 film_terminate.mpg 
  1. 将.avi压缩成SVCD mpeg2
    NTSC格式:
ffmpeg -i video_origine.avi -target ntsc-svcd video_finale.mpg 

PAL格式:

ffmpeg -i video_origine.avi -target pal-svcd video_finale.mpg 
  1. 将.avi压缩成VCD mpeg2
    NTSC格式:
ffmpeg -i video_origine.avi -target ntsc-vcd video_finale.mpg 

PAL格式:

ffmpeg -i video_origine.avi -target pal-vcd video_finale.mpg 
  1. 多通道编码
ffmpeg -i fichierentree -pass 2 -passlogfile ffmpeg2pass fichiersortie-2 
  1. 从flv提取mp3
ffmpeg -i source.flv -ab 128k dest.mp3

常用点:

对视频进行调速

ffmpeg -t 3.0 -i /Users/mdm/Desktop/water.mp4 -an -r 25 -filter:v setpts=0.5*PTS -t 6.0 -b:v 1024k -y /Users/mdm/Desktop/newWater.mp4
  • 注意:
    该方法中,假设调为x倍速,则setpts=1.0 / x*PTS。
    该调速方法,最多支持在[0.25, 4]区间内调整。

其中,一些常见的参数配置如下:

-f 强制指定编码格式

-i 输出源

-t 指定输入输出时长

-r 指定帧率,即1S内的帧数

-threads 指定线程数

-c:v 指定视频的编码格式

-ss 指定持续时长

-b:v 指定比特率

-s 指定分辨率

-y 覆盖输出

-filter 指定过滤器

-vf 指定视频过滤器

-an 指定去除对音频的影响

四、FFmpeg在iOS开发上的使用

  1. 将Appdelegate.m后缀改为.mm,开启混编模式。
    command+B,如果没有报错,则表明编译成功。
  2. 要对视频进行操作,还是需要手动写很多代码去调用api,工作量较大,自然不如直接写命令行方便。这时候就要添加源码中的添加源码中的tools:
    在iOS上集成FFmpeg的命令行工具fftools是个繁琐的过程,各个版本之间还有差异,需要导入的文件不一样.
  • 从 ffmpeg-4.0.3 中找到以下文件:


    fftools文件
  • 从 scratch 文件夹中找到

config.h
  • 修改以下文件:
cmdutils.c 文件中,注释
#include "compat/va_copy.h"
#include "libavdevice/avdevice.h"
#include "libavresample/avresample.h"
#include "libpostproc/postprocess.h"
#include "libavutil/libm.h"

PRINT_LIB_INFO(avdevice,   AVDEVICE,   flags, level);
PRINT_LIB_INFO(avresample, AVRESAMPLE, flags, level);
PRINT_LIB_INFO(postproc,   POSTPROC,   flags, level);
ffmpeg_filter.c 文件中,注释
#include "libavresample/avresample.h"
ffmpeg.c 文件中,注释
#include "libavdevice/avdevice.h"
#include "libavutil/internal.h"
#include "libavutil/libm.h"
#include "libavformat/os_support.h"

ff_dlog(NULL, "force_key_frame: n:%f n_forced:%f prev_forced_n:%f t:%f prev_forced_t:%f -> res:%f\n",
                    ost->forced_keyframes_expr_const_values[FKF_N],
                    ost->forced_keyframes_expr_const_values[FKF_N_FORCED],
                    ost->forced_keyframes_expr_const_values[FKF_PREV_FORCED_N],
                    ost->forced_keyframes_expr_const_values[FKF_T],
                    ost->forced_keyframes_expr_const_values[FKF_PREV_FORCED_T],
                    res);
ffmpeg_opt.c 文件中,注释
{ "videotoolbox_pixfmt", HAS_ARG | OPT_STRING | OPT_EXPERT, { &videotoolbox_pixfmt}, "" },

为了避免两个main函数问题:

ffmpeg.h 文件下增加函数声明:
int ffmpeg_main(int argc, char **argv);
ffmpeg.c 文件中:
main函数修改为ffmpeg_main;主要是为了避免两个main函数存在

修改执行一次 ffmpeg_main 方法后 App 退出问题:

cmdutils.h 中,将void exit_program(int ret) av_noreturn;改为void exit_program(int ret);
cmdutils.c 中,
int exit_program(int ret)
{
    if (program_exit)
        program_exit(ret);

//    exit(ret);
    return ret;
}

修改多次调用 ffmpeg_main 时,访问空指针的问题:

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;
term_exit();

然后剩下的缺什么.h文件,就在 ffmpeg-4.0.3找到什么文件,然后加到include文件夹下对应的路径
command+B,编译成功!

  1. iOS调用命令行将视频转换为一组图片
    添加头文件:#import "ffmpeg.h"
    调用命令行
- (IBAction)converterBtnAction:(id)sender {
    dispatch_async(dispatch_get_global_queue(0, 0), ^{
        NSString *moviePath = [[NSBundle mainBundle] pathForResource:@"movie" ofType:@"mp4"];
        NSString *imageName = @"image%d.jpg";
        NSString *imagesPath = [NSString stringWithFormat:@"%@/%@", [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) firstObject], imageName];
        
        int numberOfArgs = 6;
        char** arguments = calloc(numberOfArgs, sizeof(char*));
        
        arguments[0] = "ffmpeg";
        arguments[1] = "-i";
        arguments[2] = (char *)[moviePath UTF8String];
        arguments[3] = "-r";
        arguments[4] = "20";
        arguments[5] = (char *)[imagesPath UTF8String];
        
        int result = ffmpeg_main(numberOfArgs, arguments);
        NSLog(@"----------- %d", result);
        dispatch_async(dispatch_get_main_queue(), ^{
            [self presentViewController:[[ResultViewController alloc] init] animated:YES completion:^{
                
            }];
        });
        
    });
    
}
  1. 运行效果


    2019-01-14 13_38_42.gif
运行效果
  1. 编译报错(过程中遇到的两个报错的地方,及解决办法)
'libavcodec/avcodec.h' file not found

解决办法
添加header search paths
屏幕快照 2019-01-11 下午5.05.33.png

加入ffmpeg_hw.c文件!

五、注意事项

  1. ffmpeg 是需要对实体文件进行处理的,所以无论是输入源还是输出源,都必须对应实体文件,同时在 ffmpeg 的命令中,需指定路径。对于输出源来说,如果不指定 -y,即覆盖输出,那么如果输出源文件已经存在,ffmpeg 命令会执行失败。
  2. ffmpeg 命令需要阻塞线程来处理,所以为了避免主线程的阻塞,建议放入子线程进行处理。
  3. ffmpeg 的输入和输出需要知道明确的编码格式:输入编码可以通过解码来获取到,但是输入编码如果指定的话,就必须与实体文件编码一致,否则解码会出错;输出源同样需要指定编码格式,如果没有明确指定输出的编码格式,那么需要在输出路径中指定后缀,否则会出现编码出错。
  4. 如果需要对 GIF 进行调速的话,直接通过指定 GIF 的 -r 来生成新的 GIF 是不合适的,因为 GIF 的帧间隔可以不一致,而通过设置 -r,就将所有帧间隔设置为一致,这样生成的效果与理想效果不一致。可通过将 GIF 转为视频,然后调整视频的速度生成新的视频,进而再生成新 GIF 来达到目的。
  5. 由于 ffmpeg 的命令行工具中,有许多参数为全局变量,所以为了保证使用的正确,我们需要保证在一个时间点,只有一次 ffmpeg_main() 方法的调用。
  6. 在使用全局调色板的时候,需要注意与水印的搭配处理。如果全局调色板是在添加水印之前就已经生成,那么添加水印之后,使用该全局调色板生成 GIF,水印会被全局调色板校正,从而在 GIF 上显示不出来。

六、各模块的功能

libavformat:用于各种音视频封装格式的生成和解析;
libavcodec:用于各种类型声音、图像编解码;
libavutil:包含一些公共的工具函数;
libswscale:用于视频场景比例缩放、色彩映射转换;
libpostproc:用于后期效果处理;
ffmpeg:该项目提供的一个工具,可用于格式转换、解码或电视卡即时编码等;
ffsever:一个 HTTP 多媒体即时广播串流服务器;
ffplay:是一个简单的播放器,使用ffmpeg 库解析和解码,通过SDL显示;

相关链接

iOS开发中集成FFmpeg以及相关注意事项
IOS FFMPEG的使用

😊附上demo,如果帮到你了请给个🌟
GitHub

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

推荐阅读更多精彩内容