14

多媒体开发(7):编译Android与iOS平台的FFmpeg

 3 years ago
source link: https://segmentfault.com/a/1190000039092306
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

编译FFmpeg,一个古老的话题,但我还是介绍一遍,就当记录。之前介绍怎么给视频添加水印时,就已经提到FFmpeg的编译,并且在编译时指定了滤镜的功能。

但是,在手机盛行的时代,你可能更需要的是能在iOS或Android平台上运行的FFmpeg,而对于命令行的ffmpeg,你可以在个人电脑上面使用(因为它简洁易操作),也可以在服务程序中使用(安装FFmpeg后直接调用ffmpeg命令),比如小程经常在自己的mac机上使用ffmpeg命令。

本文介绍怎样编译出iOS或Android平台使用的FFmpeg链接库。

正如编译macos平台使用的FFmpeg一样,编译iOS或Android平台使用的FFmpeg,主线也是先configure再make,只不过,有更多的细节需要考虑。

我使用的是macos系统,以下介绍的就是在mac上交叉编译,编译出移动平台使用的FFmpeg。

(1)编译环境准备

pkg-config

FFmpeg在编译时经常使用到第三方库(比如x264、rtmp等),编译器在查找这些第三方库的头文件与库文件时,需要使用到程序pkg-config。

pkg-conifig给编译器提供路径与链接选项。第三方库在make install时会生成pc后缀的文件并拷贝到系统目录,而pkg-config就是从这个pc文件读取出路径信息。

可以设置PKG_CONFIG_PATH这个环境变量,指定目录,让pkg-config到这个目录下面去找pc文件,如果不设置,则默认在/usr/local/lib/pkgconfig目录下面查找,比如某个时刻我的pkgconfig目录下面是这样的一堆pc文件:

mIJ3q2.jpg!mobile

这样安装pkg-config:

brew install pkg-config

安装pkg-config后,可以这样获取第三方库的路径信息:

pkg-config --cflags --libs freetype2

以下是对于pkg-config命令的一个载图:

26RzYz7.png!mobile

需要注意,虽然pkg-config查找到的pc文件里面有记录到第三方静态库的路径,但实际在编译FFmpeg静态库时,并不会链接上这个第三方库,而且在FFmpeg的编译脚本中可以指定第三方库的路径。

freetype

此项只在使用滤镜功能时需要安装。

如果编译时遇到这样的提示:freetype2 not found using pkg-config,那说明还没有安装freetype,这样安装即可:

brew install freetype

clang编译器

此项只在编译iOS平台的FFmpeg时才需要。

因为我的mac机已经安装过xcode,所以clang已经存在。如果你的mac还没有安装clang的话,那建议把xcode安装好。

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

另一个需要的工具是 yasm 汇编编译器,可以这样安装:

brew install yasm

NDK工具包

此项只在编译Android平台的FFmpeg时才需要。

可以使用ndk-r9d版本,或者最新的版本,来编译FFmpeg,下载地址: https://developer.android.goo...

(2)FFmpeg源码下载

git clone git://source.ffmpeg.org/ffmpeg.git ffmpeg

(3)编译脚本

不必自己重写了,找开源的项目过来修改一下(注意开源协议)就可以了,比如参考这个开源项目: https://github.com/yixia/FFmp...

在这个项目里面,有编译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文件)。

在编译得到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的链接库的过程,涉及到编译环境的准备、编译脚本的理解与定制等内容。有缘再见,see you.

aqIJBbI.jpg!mobile


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK