Android移植lame库(采用CMake)
貌似许多人都是从lame库开始入门Android NDK开发的,在网上一搜一大堆详细教程。本篇的亮点是采用Google推荐的CMake工具(不是ndk-builder)来移植lame项目。重点写一下与ndk-builder的差异,而非教程。
1.CMake是什么?
这个是AndroidStudio 2.2以上的版本才可使用的,跟ndk-builder一样是一款原生构建工具。
与ndk-builder不同的是,ndk-builder需要用到mk文件,而CMake则使用CMakeLists文件。
具体可阅读官方介绍 向您的项目中添加C代码 以及 CMake(不读的话,可能看不懂怎么移植哦)
在这里要说的就是,如果你使用的是AndroidStudio 2.2以上的版本,那么只要在创建项目时选择“Include C++ Support”选项,然后不停点击下一步就可以创建一个使用CMake工具构建C\C++代码的项目。
当然前提是,你在SDK Manager中安装了CMake。
由于本文重点在移植lame项目,对CMake的介绍就不多说了。
2.将lame的代码放入项目
现在假设你已经创建了一个采用CMake的NDK项目,那么你可以找到两个很重要的东西:cpp文件夹和CMakeLists.txt文件。前者是用来放C\C++源码的,后者则是CMake的构建脚本文件。
如果你看完了向您的项目中添加C代码 文章,那你肯定知道CMakeLists.txt脚本中的大体内容了。
好了,先下载lame吧。
http://lame.sourceforge.net/download.php
http://sourceforge.net/projects/lame/files/lame/3.99/lame-3.99.5.tar.gz
下载完之后解压,然后找到libmp3lame文件夹,将里面的.c和.h文件全部复制到项目的cpp目录中。
注意:libmp3lame文件夹内还包含其他文件夹,不用管它。
然后,再找到include文件夹,将lame.h文件拷贝到cpp目录中。(总共43个文件)
接下来需要将源文件加入到项目中,通过CMakeLists.txt脚本来控制
在CMakeLists中修改add_library 方法的最后一个参数,通过AndroidStudio创建的ndk项目中会有一个native-lib.cpp文件,在此文件后将lame相关的所有.c文件添加进来。这一步是指定源代码的位置。
像下面这样:
add_library(native-lib
SHARED
native-lib.cpp bitstream.c encoder.c gain_analysis.c lame.c id3tag.c
mpglib_interface.c newmdct.c presets.c psymodel.c quantize.c fft.c
quantize_pvt.c reservoir.c set_get.c tables.c takehiro.c util.c
vbrquantize.c VbrTag.c version.c)
不过,这里要注意,AndroidStudio默认的CMakeLists文件的位置在项目目录中,我将它放到cpp目录中去了。所以才能直接添加.c文件名,否则需要添加相对路径“src/main/cpp/xxx.c”
到此,lame项目就已经被放入我们的ndk项目中了。
3.移植修改
首先,需要对lame中的三个文件进行一些小改动。
1)删除fft.c文件的47行的"include "vector/lame_intrin.h""
2)修改set_get.h文件的24行的#include“lame.h"
3)将util.h文件的574行的"extern ieee754_float32_t fast_log2(ieee754_float32_t x);"
替换为 "extern float fast_log2(float x);"
这些跟ndk-builder是一样的,网上有很多教程。
然后,需要修改app -> build.gradle文件
android {
...
defaultConfig {
...
externalNativeBuild{
cmake{
cFlags "-DSTDC_HEADERS"
}
}
}
}
没错,就是添加这个-DSTDC_HEADERS编译标识。
大家可以试一下,如果不加这个标志,我们的项目编译会报错,比如undefined symbol bcopy...之类的。
这里说明一下我的调查结果:
首先,添加-D标志的意思就是给编译器添加宏定义。那么-DSTDC_HEADERS就相当于给项目增加一句”#define STDC_HEADERS“。
我们打开machine.h文件看一下第34行:
#ifdef STDC_HEADERS
# include <stdlib.h>
# include <string.h>
#else
# ifndef HAVE_STRCHR
# define strchr index
# define strrchr rindex
# endif
char *strchr(), *strrchr();
# ifndef HAVE_MEMCPY
# define memcpy(d, s, n) bcopy ((s), (d), (n))
# define memmove(d, s, n) bcopy ((s), (d), (n))
# endif
#endif
意思很明白,如果没有定义STDC_HEADERS这个宏则会用到bcopy方法,而这个方法我们根本没有,于是就报错了。
4.测试
到现在我们的移植工作就已经做完了,接下来可以简单测试一下。
打开项目中的native-lib.cpp文件,做如下修改:
#include <jni.h>
#include <string>
#include "lame.h"
extern "C"
jstring
Java_com_javine_mylameproject_MainActivity_stringFromJNI(
JNIEnv *env,
jobject /* this */) {
return env->NewStringUTF(get_lame_version());
}
运行项目,如无意外我们的app会显示lame的版本号 3.99.5