编译 FFmpeg, 这是一个古老的话题, 但是小程还是介绍一遍, 就当是记录
小程之前介绍怎么给视频添加水印时, 就已经提到 FFmpeg 的编译, 因为需要在编译时指定滤镜的功能, 读者可以关注广州小程微信公众号并查阅这篇文章(音视频 ->FFmpeg 应用)
但是, 在手机盛行的时代, 读者可能更需要的是能在 iOS 或 Android 平台上运行的 FFmpeg, 而对于命令行的 ffmpeg, 读者可以在个人电脑上面使用(因为它简洁易操作), 也可以在服务程序中使用(安装 FFmpeg 后直接调用 ffmpeg 命令), 比如小程经常在自己的 mac 机上使用 ffmpeg 命令
本文介绍如何编译出 iOS 或 Android 平台使用的 FFmpeg 链接库
正如编译 macos 平台使用的 FFmpeg 一样, 编译 iOS 或 Android 平台使用的 FFmpeg, 主线也是先 configure 再 make, 只不过, 有更多的细节需要考虑
小程使用的是 macos 系统
(1)编译环境准备
(a)pkg-config
FFmpeg 在编译时经常使用到第三方库(比如 x264rtmp 等), 编译器在查找这些第三方库的头文件与库文件时, 需要使用到程序 pkg-config
pkg-conifig 给编译器提供路径与链接选项第三方库在 make install 时会生成 pc 后缀的文件并拷贝到系统目录, 而 pkg-config 就是从这个 pc 文件读取出路径信息
这样安装 pkg-config:
brew install pkg-config
安装 pkg-config 后, 可以这样得到第三方库的路径信息:
pkg-config --cflags --libs librtmp
以下是对于 pkg-config 命令的一个载图:
可以设置 PKG_CONFIG_PATH 这个环境变量, 让 pkg-config 到这个目录下面去找 pc 文件, 如果不设置, 则默认在 / usr/local/lib/pkgconfig 目录下面查找
需要注意, 虽然 pkg-config 查找到的 pc 文件里面有记录到第三方静态库的路径, 但实际在编译 FFmpeg 静态库时, 并不会链接上这个第三方库, 而且在 FFmpeg 的编译脚本中可以指定第三方库的路径
(b)clang 编译器
此项只在编译 iOS 平台的 FFmpeg 时才需要
小程的 mac 机已经安装过 xcode, 所以 clang 已经存在如果读者还没有安装 clang 的话, 那建议把 xcode 安装好
(c)asm 编译器
此项只在编译 iOS 平台的 FFmpeg 时才需要
x264 或 FFmpeg 等, 都有汇编代码, 编译这些汇编代码, 需要使用更先进的编译脚本来处理, 而 mac 系统没有这样的脚本
这个脚本是 gas-preprocessor.pl
可以这样安装 gas-preprocessor.pl:
- git clone git://github.com/mansr/gas-preprocessor.git
- sudo cp -f gas-preprocessor/gas-preprocessor.pl /usr/local/bin/
- chmod +x /usr/local/bin/gas-preprocessor.pl
另一个需要的工具是 yasm 汇编编译器, 可以这样安装:
brew install yasm
(d)NDK 工具包
此项只在编译 Android 平台的 FFmpeg 时才需要
可以使用 ndk-r9d 版本, 或者最新的版本, 来编译 FFmpeg
下载地址:<https://developer.android.google.cn/ndk/downloads/index.html>;
(2)FFmpeg 源码下载
git clone git://source.ffmpeg.org/ffmpeg.git ffmpeg
(3)编译脚本
不必自己重写了, 找开源的项目过来修改一下 (注意开源协议) 就可以了, 比如参考这个开源项目:
<https://github.com/yixia/FFmpeg-Vitamio.git>;
在这个项目里面, 有编译 Android 跟 iOS 平台的相应脚本, 而且有相应的优化处理
在移动平台使用的库都很注重两个东西, 一个是性能, 另一个是体积大小一个好的脚本, 既要根据不同的硬件类型作编译上的优化, 也要根据软件需求裁剪 FFmpeg 的功能使得出来的库尽可能小(毕竟 FFmpeg 的功能并非全部都用上)
(4)脚本修改
小程先介绍一下脚本里面的一些关键参数, 这些参数并非平台通用
指定指令集:
--extra-cflags='-arch armv7s' --extra-ldflags='-arch armv7s'
指定 cpu 类型:
- --arch=arm --cpu=cortex-a9
- (应该根据不同的指令集使用不同的 cpu 优化;--arch=arm64, 像这样指定具体指令架构也是可以的)
指定系统:
--target-os=darwin
指定 sdk:
--sysroot=/Applications/Xcode.app/.../xxx.sdk
指定编译器:
--cc=xxx/clang
指定库生成目录:
--prefix=build
指定使用的 muxer/demuxer/encoder/decoder 等:
--enable-muxer=mp4
基本上使用上面介绍的脚本就可以编译了, 但有时候也可以作一些修改, 比如要加入第三方库时, 或者要对某个指令集作优化时, 等等
小程再提一些注意点, 有可能帮到读者解决编译过程中遇到的问题
--sysroot 需要指定 iOS 平台为....sdk/, 不包括 usr/inclue;Android 平台是编译链的目录
extra-cflags 跟 extra-ldflags 要指定 - arch(iOS)或 - march(Android)
在 xcode8.3.2(sdk 为 10.3)上, armv7/armv7s/arm64 不能使用 "-mfloat-abi=hard" 选项, 并且 arm64 要指定 - mcpu=cortex-a53
在 xcode9.2(sdk 为 11.2)上, 需要 --disable-asm
对于实际项目来说, FFmpeg 的编译是关键的一步, 应该多花时间去研究一些关键的细节 -- 功能性能跟体积大小都很重要
(5)开始编译
运行脚本即可最终会生成二进制库, 比如 iOS 一般为静态库(.a 文件), 而 Android 一般为动态库(.so 文件)
至此, 已经介绍完在 iOS 或 Android 平台编译 FFmpeg 的过程
在编译得到 FFmpeg 的链接库后, 就可以调用它, 让它运行起来这时, 需要写自己的调用程序小程在这里给出一个简单的调用示例, 并且不做代码解释, 只是让有需要的读者有一个感知对于具体的知识点, 在后续再做介绍
- extern "C" {
- #include "libavcodec/avcodec.h"
- #include "libavformat/avformat.h"
- }
- void dump_file_format(const char* filepath) {
- av_register_all();
- av_log_set_level(AV_LOG_DEBUG);
- AVFormatContext* formatContext = avformat_alloc_context();
- AVCodecContext* codecContext = NULL;
- int status = 0;
- bool success = false;
- int audioindex = -1;
- status = avformat_open_input(&formatContext, filepath, NULL, NULL);
- if (status == 0) {
- status = avformat_find_stream_info(formatContext, NULL);
- if (status>= 0) {
- for (int i = 0; i <formatContext->nb_streams; i ++) {
- if (formatContext->streams[i]->codec->codec_type == AVMEDIA_TYPE_AUDIO) {
- audioindex = i;
- break;
- }
- }
- if (audioindex> -1) {
- codecContext = formatContext->streams[audioindex]->codec;
- AVCodec* codec = avcodec_find_decoder(codecContext->codec_id);
- if (codec) {
- status = avcodec_open2(codecContext, codec, NULL);
- if (status == 0) {
- success = true;
- }
- }
- }
- }
- }
- if (success) {
- av_dump_format(formatContext, 0, filepath, false);
- av_log(NULL, AV_LOG_DEBUG, "format and decoder sucessful, and now in decoding each frame\n");
- printf("sample_rate=%d, channels=%d\n", codecContext->sample_rate, codecContext->channels);
- }
- avformat_free_context(formatContext);
- }
- int main(int argc, const char *argv[])
- {
- const char filepath[] = "test2.mp3";
- dump_file_format(filepath);
- return 0;
- }
总结一下, 本文介绍了在 macos 上, 编译出 iOS 平台或 Android 平台的 FFmpeg 的链接库的过程涉及到编译环境的准备编译脚本的理解与定制, 难度系数为 2
来源: http://blog.51cto.com/13136504/2091763