iOS下使用FFMPEG的一些总结

作者: 蜗蜗牛在奔跑 | 来源:发表于2016-02-03 11:05 被阅读11564次

ffmpeg是一个多平台多媒体处理工具,处理视频和音频的功能非常强大。目前在网上搜到的iOS上使用FFMPEG的资料都比较陈旧,而FFMPEG更新迭代比较快; 且网上的讲解不够详细,对于初次接触FFMPEG的新手(例如我)来说确实不太好使用。为了防止忘记,这里对iOS下使用FFMPEG做一个总结。

1. FFMPEG层次结构的简单理解

要使用FFMPEG,首先需要理解FFMPEG的代码结构。根据志哥的提示,ffmpeg的代码是包括两部分的,一部分是library,一部分是tool。api都是在library里面,如果直接调api来操作视频的话,就需要写c或者c++了。另一部分是tool,使用的是命令行,则不需要自己去编码来实现视频操作的流程。实际上tool只不过把命令行转换为api的操作而已。

2. 预热-在mac os下使用ffmpeg

在mac os下使用ffmpeg比较简单,可以直接使用命令行来操作。首先安装ffmpeg,这里默认系统已经安装好brew,只需要在终端上输入:

brew install ffmpeg

等待安装结束即可。

安装结束后,尝试以下命令:

ffmpeg -i input.mp4 output.avi

如果能顺利转换,表明安装成功

3. 编译能在iOS下使用的FFMPEG library库

这一步是编译1所说的library,编译好之后可以调用FFMPEG的api。网上有一些方法,但都要自己手动编译,稍显复杂而且比较陈旧。按照app store的需求,编译出来的包还必须支持arm64。我在万能的github中找到一个能够"一键编译"的脚本,地址如下:

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

而且写这个脚本的歪果仁挺好人,更新很及时,已经更新到了最新的2.5.3版本。下载下来,只有一个build-ffmpeg.sh脚本文件。在终端中转至脚本的目录,执行命令:

./build-ffmpeg.sh

脚本则会自动从github中把ffmpeg源码下到本地并开始编译。

编译结束后,文件目录如下:

【iOS开发】iOS下使用FFMPEG的一些总结

其中,ffmpeg-2.5.3是源码,FFmpeg-iOS是编译出来的库,里面有我们需要的.a静态库,一共有7个。

执行命令:

lipo -info libavcodec.a

查看.a包支持的架构,这几个包都支持了armv7 armv7s i386 x86_64 arm64这几个架构,这个脚本果真是业界良心啊~~~

4.在xcode中引入FFMPEG library库

新建工程,把上面编译好的FFmpeg-iOS拖到xcode工程中,添加一个头文件引用

#include "avformat.h"

添加一个api语句:

av_register_all();

添加一个空的类,把执行文件.m后缀改为.mm,开启混编模式。

添加相应的framework,包括avfoundation和coremedia。

运行工程,如果没有报错,则表明编译成功。

5.在xcode项目中使用命令行

执行到第4步,已经可以使用library库了。但是如果要对视频进行操作,还是需要手动写很多代码去调用api,工作量较大,自然不如直接写命令行方便。为了命令行能够在xcode工程中使用,还需要做以下工作:

(1)添加源码中的tools,具体文件包括:

【iOS开发】iOS下使用FFMPEG的一些总结

(2)添加Header Search Paths

在target--build setting中搜索Header Search Paths,并在Header Search Paths下面添加源码ffmpeg-2.5.3和scratch的路径。

(3)修改ffmpeg.h和ffmpeg.c源码

如果此时run这个工程,则会报错,原因是工程里面有2个main函数,此时处理方法为:

在ffmpeg.h中添加一个函数声明:

int ffmpeg_main(int argc, char **argv);

在ffmpeg.c中找到main函数,把main函数改为ffmpeg_main。

(4)调用命令行范例

添加头文件:#import "ffmpeg.h"

调用命令行

int numberOfArgs = 16;

char** arguments = calloc(numberOfArgs, sizeof(char*));

arguments[0] = "ffmpeg";

arguments[1] = "-i";

arguments[2] = inputPath;

arguments[3] = "-ss";

arguments[4] = "0";

arguments[5] = "-t";

arguments[6] = durationChar;

arguments[7] = "-vcodec";

arguments[8] = "copy";

arguments[9] = "-acodec";

arguments[10] = "aac";

arguments[11] = "-strict";

arguments[12] = "-2";

arguments[13] = "-b:a";

arguments[14] = "32k";

arguments[15] = outputPath;

int result = ffmpeg_main(numberOfArgs, arguments);

其中inputpath和outputpath是文件路径。经测试,这两个路径不支持asset-library://协议和file:// 协议,所以如果是要用相册的文件,我目前的解决办法是把它拷贝到沙盒里面。

6. 改关闭进程为关闭线程

如果顺利进行到了第5步,在app中是能够用命令行处理视频了,但会出现一个问题,app会退出。经肖大神提醒,发现了命令行执行完毕之后会退出进程。而iOS下只能启动一个进程,因此必须改关闭进程为关闭线程,或者直接把关闭进程的方法给注掉。

在ffmpeg.c中可以看到,执行退出进程的方法是exit_program,定位到了cmdutils.c中执行了c语言的exit方法。这里我将它改为了pthread_exit(需要添加#include 头文件)。在xcode项目中使用时,则可以用NSThread来新开一个线程,执行完毕之后,把线程关闭了即可。再使用NSThreadWillExitNotification通知,即可监听线程退出的情况。

7. 修复ffmpeg.c里面的一个bug

在实际项目中,可能需要多次调用命令行,但在多次调用命令行的过程中,发现ffmpeg.c的代码中会访问空属性导致程序崩溃。逐步debug后发现,很多指针已经置空了,但它们的计数却没有置零,不知道是不是ffmpeg.c的一个bug。修复方法如下:在ffmpeg_cleanup方法下,将各个计数器置零,包括:

nb_filtergraphs

nb_output_files

nb_output_streams

nb_input_files

nb_input_streams

置零之后,重复使用ffmpeg_main方法一切正常。

相关文章

网友评论

  • 095b62ead3cd:我在编译完之后查看.a文件支持的架构,发现不支持armv7s,请问是什么原因造成的呢?应该怎么解决?
  • 牛巴粉带走:楼主,我在集成ffmpeg 3.4 ,打算用命令行操作,现在遇到一个问题,麻烦看一下,怎么解决
    Undefined symbols for architecture arm64:
    "_videotoolbox_pixfmt", referenced from:
    _options in ffmpeg_opt.o
    "_videotoolbox_init", referenced from:
    _hwaccels in ffmpeg_opt.o
    "_hw_device_free_all", referenced from:
    _transcode in ffmpeg-5FAD79E060D31151.o
    "_hw_device_get_by_name", referenced from:
    _opt_filter_hw_device in ffmpeg_opt.o
    "_hw_device_init_from_string", referenced from:
    _opt_init_hw_device in ffmpeg_opt.o
    "_hw_device_setup_for_encode", referenced from:
    _init_output_stream in ffmpeg-5FAD79E060D31151.o
    "_hw_device_setup_for_decode", referenced from:
    _init_input_stream in ffmpeg-5FAD79E060D31151.o
    ld: symbol(s) not found for architecture arm64
    clang: error: linker command failed with exit code 1 (use -v to see invocation)
    蜗蜗牛在奔跑:@取个名字烧脑 试试这个http://blog.csdn.net/wownbafifa/article/details/50963148
  • feng55:请问下如何手动控制命令终止呢,因为需要在执行命令的过程中手动去控制开关
  • 67800d7adfe9:怎么判断一条命令是否执行完成呢。
    67800d7adfe9:@L1先生 谢谢哈
    蜗蜗牛在奔跑:@keepin 这个我好久没看了,有空给你查查
  • 罗火火:在Header Search Paths下面添加源码ffmpeg-2.5.3和scratch的路径。这两个文件加起来300来兆 确定么 亲
    蜗蜗牛在奔跑:@MrRightGen 可以的
    MrRightGen:楼主 , 能用在Mac桌面版应用上面吗
    蜗蜗牛在奔跑:@罗火火 是的,这个很大
  • c7a04d67b30e:执行命令行 添加源码中的哪些文件?
    c7a04d67b30e:@L1先生 请问除了NSThreadWillExitNotification 有别的方法吗
    c7a04d67b30e:@L1先生 我运行都一切正常,但是当做完ffmpeg_main(argc, argv);后代码就不继续往下执行了
    蜗蜗牛在奔跑:@淇淇滴滴滴 是的
  • 取个名字怎么那么难啊:我在编译FFmpeg的时候编译arm64失败 ,C compiler test failed.现在有最新的脚本吗
  • 吴霸格07:博主已超神
  • Link913:你会精简安装库吗
  • AnAn_AnAn:从哪搬的文。你试了 调用命令了吗,,,我这怎么报错
    AnAn_AnAn:@L1先生 切片转mp4的 命令 你试过没..
    ffmpeg -i \"http://......../1/hls/index.m3u8\" –vcodec copy ~/desktop/FM/15.mp4
    蜗蜗牛在奔跑:@JasonAn 试了,完全好使,你看看那些必要的插件安装了没有
  • 35b0fedb0676:执行brew install ffmpeg时提示 command not found: brew
    ➜ ~ 这是为什么呢
    蜗蜗牛在奔跑:你需要在终端里面用命令行安装brew
  • 8aeb24e99c4e:我在iOS 中按照文章的方法调用FFmpeg命令行,在第六步“改关闭进程为关闭线程”中修改了cmdutils.c 中退出方法为pthread_exit,并在调用FFmpeg时使用NSThread开了一个线程,但是第二次执行命令还是不行,报Option threads not found.的错误。这个怎么解决呢?
  • 5e47aa23eddf:骗骗小孩还可以 水
  • MinorUncle:请问为什么我吧.m修改为.mm就出问题了是问么原因,不修改就能运行,但是我有其他文件必须要修改。报错代码:
    Undefined symbols for architecture arm64:
    "av_read_frame(AVFormatContext*, AVPacket*)", referenced from:
    ___20-[H264Decoder start]_block_invoke in H264Decoder.o
    "avcodec_send_packet(AVCodecContext*, AVPacket const*)", referenced from:
    ___20-[H264Decoder start]_block_invoke in H264Decoder.o
    "avcodec_open2(AVCodecContext*, AVCodec const*, AVDictionary**)", referenced from:
    -[H264Decoder start] in H264Decoder.o
    "avformat_alloc_context()", referenced from:
    -[H264Decoder _init] in H264Decoder.o
    "avformat_open_input(AVFormatContext**, char const*, AVInputFormat*, AVDictionary**)", referenced from:
    -[H264Decoder _init] in H264Decoder.o
    "avformat_find_stream_info(AVFormatContext*, AVDictionary**)", referenced from:
    -[H264Decoder _init] in H264Decoder.o
    "avcodec_find_decoder(AVCodecID)", referenced from:
    -[H264Decoder _init] in H264Decoder.o
    "av_register_all()", referenced from:
    -[H264Decoder initWithUrl:] in H264Decoder.o
    ld: symbol(s) not found for architecture arm64
    clang: error: linker command failed with exit code 1 (use -v to see invocation)
    蜗蜗牛在奔跑:@ttdiOS 我的没问题呢,库编译好了
    ttdiOS:我也碰到类似的问题,你的解决了?
    ttdiOS:我也碰到类似的问题,你的解决了?
  • 27bba2520ac9:大哥,脚本编译出来的没有你说的ffmpeg.h和ffmpeg.c了啊
    b11af78a64d0:@pointOneZero 在ffmpeg-3.0里
  • b11af78a64d0:我把exit_program的方法注掉之后,在term_exit方法崩溃了,把term_exit方法注掉,直接error: memory read failed
    我想实现执行一个ffmpeg_main()之后紧接着在执行这个方法,可是执行一个之后直接退出线程了。
    将多个视频合并之后,获得合并之后的路径,然后将合并的视频进行压缩该如何实现?谢谢。
    ttdiOS:cmdutils.h文件int exit_program(int ret);声明是不是改成的这样?
    .h文件里exit_program(int ret)方法后删除av_noreturn删掉
    b11af78a64d0:没有 功能用系统框架做的
    8aeb24e99c4e:@basy 你这个问题解决没? 我也遇到这个问题,没法搞定。。 急盼回复
  • puppySweet:这个文章有点坑 最新版本都没有ffmpeg.h了
  • puppySweet:你说处理视频 啥意思看不到代码啊 你都做了哪些处理啊。 你的inputpath和outpath 处理完后 都有啥效果
  • jsonzhou:看了这些还是不懂 终端编译手生
    蜗蜗牛在奔跑:@feng55 那个需要你自己旋转一下
    feng55:@L1先生 请问大神。有使用过这个命令采集过avfoundation 吗。。不知道为什么我采集的视频一直被旋转了90度,画面是歪的
    蜗蜗牛在奔跑:@jsonzhou 这个终端命令不用死记硬背,按照命令就行

本文标题:iOS下使用FFMPEG的一些总结

本文链接:https://www.haomeiwen.com/subject/xukekttx.html