您当前的位置: 首页 >  音视频

命运之手

暂无认证

  • 1浏览

    0关注

    747博文

    0收益

  • 0浏览

    0点赞

    0打赏

    0留言

私信
关注
热门博文

【Android音视频开发】【004】NDK编译Lame库

命运之手 发布时间:2020-05-16 14:59:52 ,浏览量:1

什么是Lame

  • Lame是一个C语言MP3编码库
  • Lame源码本身是运行在PC平台的,我们对其进行了稍加修改,使其适用于Android平台
  • PCM转MP3是安卓开发中常见的需求,PCM是未经处理的原生音频数据,安卓录音得到的都是PCM数据,但是一般网站都会要求MP3格式的,因为PCM体积太大,所以PCM转MP3是非常常见的需求
  • C++一般负责的都是音视频开发,硬件通信,进程控制等工作,而Lame库又是音视频开发当中最常见最简单的功能,很适合作为我们学习NDK的入门材料

下载Android Lame源码和库

这里先给出源码,对于刚学习NDK的新手来说,很多细节都可能出问题,有一个问题就编译不过,所以先给出代码

除了Lame源码部分,建议新手亲自编写全部代码,并弄清全部原理。其实NDK开发就那么多东西,所有坑都踩过,知道解决方法和其中原理,NDK就学得差不多了。早点踩坑,就离熟练掌握更近一步

这里给出两个链接,一个是Demo源码,适用于那些抱着学习态度的人,另一个是编译好的so库和JNA接口,适用于那些急着拿成品直接开发应用的人

AndroidLame完整源码:Project-Lame

编译好的so库和JNA接口:Liblame

核心代码

这里给出除了Lame源码外的所有代码和编译配置

开启NDK编译功能,添加JNA依赖,添加so库依赖 注意,安卓上的JNA的需要依赖一个libjnidispatch.so文件,这和在PC上通过JNA加载DLL是不一样的


	//build.gradle

	apply plugin: 'com.android.application'
	
	android {
	    compileSdkVersion 29
	
	    defaultConfig {
	        applicationId "com.easing.android"
	
	        minSdkVersion 23
	        targetSdkVersion 29
	
	        javaCompileOptions {
	            annotationProcessorOptions {
	                includeCompileClasspath = true
	            }
	        }
	
	        //过滤CPU架构,只使用armv7的库
	        ndk {
	            abiFilters "armeabi-v7a"
	        }
	    }
	
	    //加载指定位置的so库
	    sourceSets {
	        main {
	            jniLibs.srcDirs = ['libs']
	        }
	    }
	
	    //编译jni目录,开启这个选项后,会自动编译C++代码生成so文件,并自动引用
	    //开启此选项后,就不需要再将so库拷贝到sourceSets指定的位置了,否则会引起so库重复错误
	    externalNativeBuild {
	        ndkBuild {
	            path 'src/jni/Android.mk'
	        }
	    }
	
	    compileOptions {
	        sourceCompatibility = 1.8
	        targetCompatibility = 1.8
	    }
	}
	
	dependencies {
	    api project(':android-commons')
	    api 'net.java.dev.jna:jna:5.5.0'
	}

NDK编译配置


	//Android.mk
	
	#记录当前路径
	LOCAL_PATH := $(call my-dir)
	
	#清除默认的LOCAL变量
	include $(CLEAR_VARS)
	
	#模块名称
	LOCAL_MODULE := liblame
	
	#链接系统模块
	LOCAL_LDLIBS := -lm -llog
	
	#源码列表
	#建议通过工具自动遍历所有源码文件,生成路径列表
	#不建议通过指令遍历所有源码,较为复杂且难以阅读
	LOCAL_SRC_FILES := JnaLame.cpp logcat.cpp liblame/bitstream.c liblame/bitstream.h liblame/encoder.c liblame/encoder.h liblame/fft.c liblame/fft.h liblame/gain_analysis.c liblame/gain_analysis.h liblame/id3tag.c liblame/id3tag.h liblame/l3side.h liblame/lame-analysis.h liblame/lame.c liblame/lame.h liblame/lameerror.h liblame/lame_global_flags.h liblame/machine.h liblame/mpglib_interface.c liblame/newmdct.c liblame/newmdct.h liblame/presets.c liblame/psymodel.c liblame/psymodel.h liblame/quantize.c liblame/quantize.h liblame/quantize_pvt.c liblame/quantize_pvt.h liblame/reservoir.c liblame/reservoir.h liblame/set_get.c liblame/set_get.h liblame/tables.c liblame/tables.h liblame/takehiro.c liblame/util.c liblame/util.h liblame/vbrquantize.c liblame/vbrquantize.h liblame/VbrTag.c liblame/VbrTag.h liblame/version.c liblame/version.h
	
	#引入本地库
	#此处引入C++标准库作为测试
	#由于Application.mk里面已经开启了标准库,这里其实是多余的
	LOCAL_C_INCLUDES := D:/dev/sdk/ndk/21.0.6113669/sources/cxx-stl/llvm-libc++/libs/armeabi-v7a/libc++_static.a
	LOCAL_C_INCLUDES += D:/dev/sdk/ndk/21.0.6113669/sources/cxx-stl/llvm-libc++/libs/arm64-v8a/libc++_static.a
	
	#指示编译器生成动态库
	#如果不生成动态库,则不需要Application.mk文件
	include $(BUILD_SHARED_LIBRARY)

so库编译配置


	//Application.mk

	#指定要适配的CPU架构
	APP_ABI := armeabi-v7a
	
	#最低安卓版本要求
	APP_PLATFORM := android-23
	
	#忽略格式安全检查
	APP_CPPFLAGS := -Wno-error=format-security
	
	#开启C++标准库
	APP_STL := c++_static
	

通过std::cout打印内容到控制台


	//logcat.cpp

	#ifndef LOGCAT_CPP
	#define LOGCAT_CPP
	
	#include 
	#include 
	#include 
	#include 
	#include 
	#include 
	
	static int pfd[2];
	static pthread_t tid;
	static const char *TAG = "NativeLogger";
	
	#define LOGI(...)  __android_log_print(ANDROID_LOG_INFO, TAG, __VA_ARGS__)
	#define LOGD(...)  __android_log_print(ANDROID_LOG_DEBUG, TAG, __VA_ARGS__)
	#define LOGE(...)  __android_log_print(ANDROID_LOG_ERROR, TAG, __VA_ARGS__)
	
	//子线程,不断从FileDescription中读取数据并打印
	static void *threadFunc(void *) {
	    ssize_t byteCount;
	    char buffer[1024];
	    while ((byteCount = read(pfd[0], buffer, sizeof buffer - 1)) > 0) {
	        if (buffer[byteCount - 1] == '\n') --byteCount;
	        buffer[byteCount] = 0;
	        LOGI(buffer);
	    }
	    return 0;
	}
	
	//开启JNI日志服务
	static int startNativeLogger(const char *tag) {
	    TAG = tag;
	
	    //将stdout与stderror与缓冲区解绑
	    setvbuf(stdout, nullptr, _IOLBF, 0);
	    setvbuf(stderr, nullptr, _IONBF, 0);
	
	    //打开FileDescription,并将stdout和stderror重定向到FileDescription
	    pipe(pfd);
	    dup2(pfd[1], 1);
	    dup2(pfd[1], 2);
	
	    //开启子线程,不断从FileDescription中读取数据并打印
	    if (pthread_create(&tid, 0, threadFunc, 0) == -1)
	        return -1;
	    pthread_detach(tid);
	    return 0;
	}
	
	#endif

Lame暴漏接口给JNA调用


	//JnaLame.cpp

	#include "logcat.cpp"
	#include "liblame/lame.h"
	
	//使用std::cout前需先调用此方法,设置打印标志,开启打印服务
	extern "C" int initNativeLogger(const char *tag) {
	    startNativeLogger(tag);
	    std::cout             
关注
打赏
1654938663
查看更多评论
0.0446s