咸鱼

咸鱼是以盐腌渍后,晒干的鱼

0%

Android Ndk编译开源库(FAAC)

想在Android下实现PCM编码为AAC,已经用Android硬编码实现过AAC编码,但想了解一下FAAC这个库,比较一下两者的差异。

FAAC是开源的C语言库,查了一下网络上的文章,在Linux上编译FAAC,大多数都是编写一个脚本build_android.sh ,脚本里是用make编译,最终只有一个平台的共享库so或者静态库a文件。如:【AAC在Linux下编译】

而Android上使用共享库一般会有如下几个平台:

1
2
3
4
5
6
7
8
9
10
├── arm64-v8a
│   └── libxx.so
├── armeabi
│   └── libxx.so
├── armeabi-v7a
│   └── libxx.so
├── x86
│   └── libxx.so
└── x86_64
└── libxx.so

所以借着FAAC,记录一下Android如何通过NDK使用开源C/C++库。

现在NDK有两种方式编译C/C++库:

  • ndk-build
  • cmake

根据我的理解,两者的不同之处在于:

  1. ndk-build构建的库,编译好的 so 文件,加上 include 目录下的头文件,就可以使用了,不需要再面对开源库繁琐的源码了。但要在Android项目中使用,你还得创建一个NDK项目,通过JNI调用,所以最后你的项目会有两个 so 库文件(开源库 + JNI库)。
  2. cmake 构建,现在创建一个NDK项目,默认就是用cmake,直接把C/C++库的源文件放到cpp目录下,记录到CMakeLists.txt ,直接通过JNI调用库include的接口就行,最后项目就只有一个 so 库文件 (这种方式必须有JNI,否则编译不过)。

那么如何选择?

我觉得两种都可以,不必纠结,但一般源文件多的C/C++库建议用 ndk-build ,不用频繁的编译C/C++代码,拖慢编译速度,但如果你没有ndk-build的环境(第一次构建),配置这个环境也是相当的麻烦。而小项目,如FAAC,则用cmake构建会比较方便,一次就可以把FAAC编译好,并且可以通过JNI将FAAC接口转为Java的。

A. ndk-build编译预构建库

由于之前学NDK有保留一个Demo LearnAndroidAndLibrary\NdkTestLibrarySo 项目,所以直接借鉴Demo的配置文件:Android.mkApplication.mk ,本次直接拷贝过来做一些小的修改。

一. ndk-build编译faac

我这边运行的环境是:Ubuntu, G++, Java8(加入环境变量),Android SDK(加入环境变量) , NDK19 (加入环境变量)。

  1. 下载源码
    1
    2
    3
    $ wget http://downloads.sourceforge.net/faac/faac-1.28.tar.gz
    $ tar -zxvf faac-1.28.tar.gz
    $ cd faac-1.28
  2. 配置项目环境
    1
    2
    3
    $ mkdir jni
    $ cp include jni/
    $ cp libfaac jni/ # 猜的,应该只需要libfaac这些源码
  3. 配置文件
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    $ cd jni
    $ find -name *.c
    ./libfaac/kiss_fft/kiss_fftr.c
    ./libfaac/kiss_fft/kiss_fft.c
    ./libfaac/ltp.c
    ./libfaac/util.c
    ./libfaac/aacquant.c
    ./libfaac/psychkni.c
    ./libfaac/bitstream.c
    ./libfaac/tns.c
    ./libfaac/backpred.c
    ./libfaac/midside.c
    ./libfaac/fft.c
    ./libfaac/frame.c
    ./libfaac/huffman.c
    ./libfaac/channels.c
    ./libfaac/filtbank.c
    $

Android.mk 内容是拷贝其他开源库的,这里只修改两个内容

  1. 源码 .c 文件列表
  2. lib名称
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    $ vim Android.mk
    LOCAL_PATH:=$(call my-dir)

    include $(CLEAR_VARS)
    # 1. 贴进来所有的c文件
    LOCAL_SRC_FILES:= \
    libfaac/kiss_fft/kiss_fftr.c \
    libfaac/kiss_fft/kiss_fft.c \
    libfaac/ltp.c \
    libfaac/util.c \
    libfaac/aacquant.c \
    libfaac/psychkni.c \
    libfaac/bitstream.c \
    libfaac/tns.c \
    libfaac/backpred.c \
    libfaac/midside.c \
    libfaac/fft.c \
    libfaac/frame.c \
    libfaac/huffman.c \
    libfaac/channels.c \
    libfaac/filtbank.c \

    LOCAL_C_INCLUDES := $(LOCAL_PATH)/include

    LOCAL_LDLIBS := -llog

    #LOCAL_SHARED_LIBRARIES := \
    # libcutils

    LOCAL_MODULE:= libfaac # 2. 修改库的名称
    LOCAL_CPPFLAGS := -O2 -fexceptions -DHAVE_SOCKLEN_T -DHAVE_STRUCT_IOVEC -Wno-write-strings
    LOCAL_MODULE_TAGS := optional
    include $(BUILD_SHARED_LIBRARY)

Application.mk 不需要修改

1
2
3
4
5
6
7
$ vim Application.mk
APP_ABI := all # 所有abi平台,这里可以指定abi平台,多个用逗号隔开
APP_PLATFORM := android-30
# APP_STL := stlport_shared # 旧版ndk,如:`ndk;16.1.4479499` 用这个字段,新版不再支持
APP_STL := c++_shared # 新版ndk,c++_static or c++_shared
APP_CPPFLAGS += -fno-rtti
APP_ALLOW_MISSING_DEPS=true

APP_STL stlport_static is no longer supported. Please switch to either c++_static or c++_shared.

二. 编译

faac-1.28/jni 目录下执行

1
$ ndk-build

编译成功

1
2
3
4
5
6
7
8
9
10
11
12
$ tree ../libs/
../libs/
├── arm64-v8a
│   └── libfaac.so
├── armeabi-v7a
│   └── libfaac.so
├── x86
│   └── libfaac.so
└── x86_64
└── libfaac.so

7 directories, 7 files

三. 使用预构建库

  1. include/faaccfg.h faac.h
  2. libfaac.so

参考: [【Android Ndk使用预构建库】](../Android Ndk使用预构建库)

TODO: 刚编译完,还没有时间在Android上测试这个库是否能跑。

B. cmake 编译 faac

这个就比较简单,用 Android Studio 创建一个NDK的Android项目,将libfaac源码放进去,include放进去,剩下的就是和使用预构建库一样了:通过默认的JNI接口 native-lib.cpp调用 include的接口,在通过Java层调用 native-lib.cc就可以使用fAAC了,有空在记录一下这个过程。