aac是针对音频 进行压缩的一种算法 该编码优点很多。音质好 支持的采样率 声道都很多。在Android上使用非常常见
之前使用ffmepeg 1.1的decode_audio4这个函数 解码有误 双声道16位 居然解码成单声道32位 (nb_sample_fm=8)
没找到好的解决方法 (据说换老版本的ffmpeg0.5可以解决 )
之后有尝试提炼opcore 中的aac decode 发现太复杂
再之后尝试使用OPSLes 但是 居然在源代码里面 有个结构体定义的bug 导致无法编译 不得不移植faad2
2:使用NDK编译
3:编写JNI测试函数,使用aac文件测试效果。
1:http://www.audiocoding.com/downloads.html 下载2.7
FAAD2 Source | Version 2.7 ZIP Package |
目录结构
---jni
|---faad2
|-----aacDe
|----libfaad
.
.
.
我们之关心libfaad 和include这两个文件夹
2:编写mk脚本
在jni目录下编写Android.mk文件,内容如下
- LOCAL_PATH := $(call my-dir)
- FAAD2_TOP := $(LOCAL_PATH)/faad2
- include $(CLEAR_VARS)
- include $(FAAD2_TOP)/libfaad/Android.mk
- LOCAL_C_INCLUDES := \
- $(LOCAL_PATH) \
- $(FAAD2_TOP)/android \
- $(FAAD2_TOP)/include \
- $(LOCAL_PATH)/codebook
- LOCAL_PATH:= $(call my-dir)
- include $(CLEAR_VARS)
- LOCAL_SRC_FILES:=bits.c \
- cfft.c \
- decoder.c \
- drc.c \
- drm_dec.c \
- error.c \
- filtbank.c \
- ic_predict.c \
- is.c \
- lt_predict.c \
- mdct.c \
- mp4.c \
- ms.c \
- output.c \
- pns.c \
- ps_dec.c \
- ps_syntax.c \
- pulse.c \
- specrec.c \
- syntax.c \
- tns.c \
- hcr.c \
- huffman.c \
- rvlc.c \
- ssr.c \
- ssr_fb.c \
- ssr_ipqf.c \
- common.c \
- sbr_dct.c \
- sbr_e_nf.c \
- sbr_fbt.c \
- sbr_hfadj.c \
- sbr_hfgen.c \
- sbr_huff.c \
- sbr_qmf.c \
- sbr_syntax.c \
- sbr_tf_grid.c \
- sbr_dec.c
- LOCAL_MODULE:=faad
- LOCAL_C_INCLUDES := \
- $(LOCAL_PATH) \
- $(FAAD2_TOP)/android \
- $(FAAD2_TOP)/include \
- $(LOCAL_PATH)/codebook
- LOCAL_CFLAGS:= \
- -DHAVE_CONFIG_H
- include $(BUILD_SHARED_LIBRARY)
最后在/jnifaad/下面编写config.h文件
- /* config.h. Generated from config.h.in by configure. */
- /* config.h.in. Generated from configure.in by autoheader. */
- /* Define if you want to use libfaad together with Digital Radio Mondiale
- (DRM) */
- /* #undef DRM */
- /* Define if you want support for Digital Radio Mondiale (DRM) parametric
- stereo */
- /* #undef DRM_PS */
- /* Define to 1 if you have the <dlfcn.h> header file. */
- #define HAVE_DLFCN_H 1
- /* Define to 1 if you have the <errno.h> header file. */
- #define HAVE_ERRNO_H 1
- /* Define if needed */
- /* #undef HAVE_FLOAT32_T */
- /* Define to 1 if you have the <float.h> header file. */
- #define HAVE_FLOAT_H 1
- /* Define to 1 if you have the `getpwuid' function. */
- #define HAVE_GETPWUID 1
- /* Define to 1 if you have the <inttypes.h> header file. */
- #define HAVE_INTTYPES_H 1
- /* Define if you have the IOKit API */
- /* #undef HAVE_IOKIT_IOKITLIB_H */
- /* Define to 1 if you have the <limits.h> header file. */
- #define HAVE_LIMITS_H 1
- /* Define if you have C99's lrintf function. */
- #define HAVE_LRINTF 1
- /* Define to 1 if you have the <mathf.h> header file. */
- /* #undef HAVE_MATHF_H */
- /* Define to 1 if you have the `memcpy' function. */
- #define HAVE_MEMCPY 1
- /* Define to 1 if you have the <memory.h> header file. */
- #define HAVE_MEMORY_H 1
- /* Define to 1 if you have the <stdint.h> header file. */
- #define HAVE_STDINT_H 1
- /* Define to 1 if you have the <stdlib.h> header file. */
- #define HAVE_STDLIB_H 1
- /* Define to 1 if you have the `strchr' function. */
- #define HAVE_STRCHR 1
- /* Define to 1 if you have the <strings.h> header file. */
- #define HAVE_STRINGS_H 1
- /* Define to 1 if you have the <string.h> header file. */
- #define HAVE_STRING_H 1
- /* Define to 1 if you have the `strsep' function. */
- #define HAVE_STRSEP 1
- /* Define to 1 if you have the <sysfs/libsysfs.h> header file. */
- /* #undef HAVE_SYSFS_LIBSYSFS_H */
- /* Define to 1 if you have the <sys/stat.h> header file. */
- #define HAVE_SYS_STAT_H 1
- /* Define to 1 if you have the <sys/time.h> header file. */
- #define HAVE_SYS_TIME_H 1
- /* Define to 1 if you have the <sys/types.h> header file. */
- #define HAVE_SYS_TYPES_H 1
- /* Define to 1 if you have the <unistd.h> header file. */
- #define HAVE_UNISTD_H 1
- /* Define to 1 if your C compiler doesn't accept -c and -o together. */
- /* #undef NO_MINUS_C_MINUS_O */
- /* Name of package */
- #define PACKAGE "faad2"
- /* Define to the address where bug reports for this package should be sent. */
- #define PACKAGE_BUGREPORT ""
- /* Define to the full name of this package. */
- #define PACKAGE_NAME ""
- /* Define to the full name and version of this package. */
- #define PACKAGE_STRING ""
- /* Define to the one symbol short name of this package. */
- #define PACKAGE_TARNAME ""
- /* Define to the version of this package. */
- #define PACKAGE_VERSION ""
- /* Define to 1 if you have the ANSI C header files. */
- #define STDC_HEADERS 1
- /* Define to 1 if you can safely include both <sys/time.h> and <time.h>. */
- #define TIME_WITH_SYS_TIME 1
- /* Version number of package */
- #define VERSION "2.7.0"
- /* Define to 1 if your processor stores words with the most significant byte
- first (like Motorola and SPARC, unlike Intel and VAX). */
- /* #undef WORDS_BIGENDIAN */
- /* Define to `__inline__' or `__inline' if that's what the C compiler
- calls it, or to nothing if 'inline' is not supported under any name. */
- #ifndef __cplusplus
- /* #undef inline */
- #endif
- /* Define to `long int' if <sys/types.h> does not define. */
- /* #undef off_t */
使用NDK 命令 ndk-build(我的版本为ndk-linux-x64-r8)
如果没有问题 会在/libs/下面生成一个libfaad2.a文件 没错 就是一个静态库 为什么是静态库 看下面
如果运行NDK编译命令没有动静 则在/jni/目录下编译个Application.mk文件
- APP_STL:= gnustl_static
- APP_ABI := armeabi-v7a
- APP_PLATFORM := android-14
- APP_MODULES := libfaad
上面语句的意思
第一行 用GNU库
第二行 针对arme-v7a的CPU
第三行 针对设备的版本 4.0.3
最后一行 静态库的名称
能用的库就出来了 然后怎么调用它呢 ?
JNI技术
修改jni/Android.mk如下
- LOCAL_PATH := $(call my-dir)
- include $(CLEAR_VARS)
- LOCAL_MODULE := libfaad
- LOCAL_SRC_FILES := lib/libfaad.a
- include $(PREBUILT_STATIC_LIBRARY)
- LOCAL_C_INCLUDES := $(LOCAL_PATH)/ \
- $(call include-path-for, wilhelm)
- LOCAL_MODULE := pcmNativePlayer
- LOCAL_LDLIBS := -L$(NDK_PLATFORMS_ROOT)/$(TARGET_PLATFORM)/arch-arm/usr/lib -L$(LOCAL_PATH)
- LOCAL_LDLIBS += -lOpenSLES -llog -lz -ldl
- #-ljnigraphics -cpu -lgcc
- LOCAL_SRC_FILES := decode_aac_adts.cpp
- #native-audio-jni.cpp
- LOCAL_STATIC_LIBRARIES:= libfaad
- LOCAL_SHARED_LIBRARIES := \
- libutils \
- libOpenSLES
- include $(BUILD_SHARED_LIBRARY)
然后编写一个/jni/decode_aac_adts.cpp
- /**
- * faaddec.c
- * use faad library to decode AAC, only can decode frame with ADTS head
- */
- #include <stdio.h>
- #include <memory.h>
- extern "C"{
- #include "faad.h"
- #include "neaacdec.h"
- }
- #include <jni.h>
- //#include "native-audio-jni.h"
- #include <stdio.h>
- #include <stdlib.h>
- #include <android/log.h>
- #define LOG_TAG "faad2_decode_aac_adts"
- #define LOGI(...) __android_log_print(ANDROID_LOG_INFO,LOG_TAG,__VA_ARGS__)
- #define LOGE(...) __android_log_print(ANDROID_LOG_ERROR,LOG_TAG,__VA_ARGS__)
- #define LOGW(...) __android_log_print(ANDROID_LOG_WARN,LOG_TAG,__VA_ARGS__)
- #define FRAME_MAX_LEN 1024*5
- #define BUFFER_MAX_LEN 1024*1024
- void show_usage()
- {
- LOGI("usage\nfaaddec src_file dst_file");
- }
- /**
- * fetch one ADTS frame
- */
- int get_one_ADTS_frame(unsigned char* buffer, size_t buf_size,
- unsigned char* data, size_t* data_size)
- {
- size_t size = 0;
- if (!buffer || !data || !data_size)
- {
- return -1;
- }
- while (1)
- {
- if (buf_size < 7)
- {
- return -1;
- }
- if ((buffer[0] == 0xff) && ((buffer[1] & 0xf0) == 0xf0))
- {
- size |= ((buffer[3] & 0x03) << 11); //high 2 bit
- size |= buffer[4] << 3; //middle 8 bit
- size |= ((buffer[5] & 0xe0) >> 5); //low 3bit
- break;
- }
- --buf_size;
- ++buffer;
- }
- if (buf_size < size)
- {
- return -1;
- }
- memcpy(data, buffer, size);
- *data_size = size;
- return 0;
- }
- int main2(int argc, char* argv[])
- {
- static unsigned char frame[FRAME_MAX_LEN];
- static unsigned char buffer[BUFFER_MAX_LEN] =
- { 0 };
- char src_file[128] =
- { 0 };
- char dst_file[128] =
- { 0 };
- FILE* ifile = NULL;
- FILE* ofile = NULL;
- unsigned long samplerate;
- unsigned char channels;
- NeAACDecHandle decoder = 0;
- size_t data_size = 0;
- size_t size = 0;
- NeAACDecFrameInfo frame_info;
- unsigned char* input_data = buffer;
- unsigned char* pcm_data = NULL;
- //analyse parameter
- if (argc < 3)
- {
- show_usage();
- return -1;
- }
- sscanf(argv[1], "%s", src_file);
- sscanf(argv[2], "%s", dst_file);
- LOGI("source file is null%s",argv[1]);
- LOGI("dst file is null%s",argv[2]);
- ifile = fopen(src_file, "rb");
- ofile = fopen(dst_file, "wb");
- if (!ifile || !ofile)
- {
- LOGI("source or destination file is null");
- return -1;
- }
- data_size = fread(buffer, 1, BUFFER_MAX_LEN, ifile);
- //open decoder
- decoder = NeAACDecOpen();
- if (get_one_ADTS_frame(buffer, data_size, frame, &size) < 0)
- {
- return -1;
- }
- //initialize decoder
- NeAACDecInit(decoder, frame, size, &samplerate, &channels);
- LOGI("samplerate %d, channels %d\n", samplerate, channels);
- while (get_one_ADTS_frame(input_data, data_size, frame, &size) == 0)
- {
- // LOGI("frame size %d\n", size);
- //decode ADTS frame
- pcm_data = (unsigned char*) NeAACDecDecode(decoder, &frame_info, frame,
- size);
- if (frame_info.error > 0)
- {
- LOGI("%s\n", NeAACDecGetErrorMessage(frame_info.error));
- }
- else if (pcm_data && frame_info.samples > 0)
- {
- LOGI(
- "frame info: bytesconsumed %d, channels %d, header_type %d\
- object_type %d, samples %d, samplerate %d\n",
- frame_info.bytesconsumed, frame_info.channels,
- frame_info.header_type, frame_info.object_type,
- frame_info.samples, frame_info.samplerate);
- //put openSL queue to render
- //updateAudioData(pcm_data,frame_info.samples * frame_info.channels,0);
- fwrite(pcm_data, 1, frame_info.samples * frame_info.channels,
- ofile); //2个通道
- fflush(ofile);
- }
- data_size -= size;
- input_data += size;
- }
- NeAACDecClose(decoder);
- fclose(ifile);
- fclose(ofile);
- return 0;
- }
- extern "C"
- {
- jint Java_org_gl_jni_JNI_fileBackPlay(JNIEnv* env, jobject thiz,
- jstring filepath, jint fileRealLength)
- {
- // if (stats == stats_ING)
- // {
- // LOGE( "is playing");
- // return stats;
- // }
- char * fileName = (char*) (env)->GetStringUTFChars(filepath, NULL);
- LOGI( "fileName:%s", fileName);
- char* files[3] ;
- files[0] = "0";
- files[1] = fileName;
- files[2] = "/sdcard/pcm_faac_out";
- main2(4,files);
- env->ReleaseStringUTFChars(filepath, fileName);
- return 0;
- }
- }
再一次运行ndk-build编译出一个动态库 faad2.so
编译工作完成
编写测试函数
细节不多说
java代码 src/org/gl/jni/JNI.java
- package org.gl.jni;
- public class JNI {
- static {
- System.loadLibrary("faad");
- }
- public static native int fileBackPlay(String fileName);
- }
- 调用代码如下 <pre name="code" class="java"> new Thread() {
- public void run() {
- try {
- JNI.fileBackPlay("/sdcard/test1.aac");
- } catch (Exception e) {
- // TODO: handle exception
- }
- };
- }.start();</pre><br>
- <pre></pre>
- <p></p>
- 完成后会在sdcard下面产生一个PCM格式的输出文件 <pre name="code" class="cpp">/sdcard/pcm_faac_out</pre>
- <p>拿出来在windows下面 用cooledit播放一下。具体参数跟 下面调用函数中的文件 的编码设置有关</p>
- <p>AAC格式编码介绍:AAC编码就是将PCMGE格式的音频信号压缩 有利于网络传输和存储</p>
- <p>pcm:声音模拟信号数字化后的数据</p>
- <p><br>
- </p>
- <p></p>
- <p><br>
- </p>
- <pre></pre>
-
由于最近要做AAC解码,查看了网上最初有两种思路:第一章种是ffmpeg,我查看./configure --list-decoders的时候,有看到aac解码器,同时在x86上编译也能够打开aac解码器,但是用用ndk交叉编译的时候即使--enable-decoder=aac也没有打开AAC解码器,所以这种方法暂停。第二中方法是使用faad2解码,在x86上调试,写一个demo能够解码aac,然后就是交叉编译,也得到库,所以就使用第二种方法。在这里记录下来,帮助解码AAC的同仁。
1、到官网http://www.audiocoding.com/downloads.html 下载faad,当前的版本是2.7,
2、创建一个文件夹AACDecoder,进入AACDecoder
3、将下载的faad加压,并且重新命名为jni
4、然后就是创建Android.mk, Application.mk,首先在jni目录下面创建Android.mk
- LOCAL_PATH := $(call my-dir)
- FAAD2_TOP := $(LOCAL_PATH)
- include $(CLEAR_VARS)
- include $(FAAD2_TOP)/libfaad/Android.mk
然后就是Application.mk,当然不创建Application.mk也没有问题
- APP_ABI := armeabi
- /* config.h. Generated from config.h.in by configure. */
- /* config.h.in. Generated from configure.in by autoheader. */
- /* Define if you want to use libfaad together with Digital Radio Mondiale
- (DRM) */
- /* #undef DRM */
- /* Define if you want support for Digital Radio Mondiale (DRM) parametric
- stereo */
- /* #undef DRM_PS */
- /* Define to 1 if you have the <dlfcn.h> header file. */
- #define HAVE_DLFCN_H 1
- /* Define to 1 if you have the <errno.h> header file. */
- #define HAVE_ERRNO_H 1
- /* Define if needed */
- /* #undef HAVE_FLOAT32_T */
- /* Define to 1 if you have the <float.h> header file. */
- #define HAVE_FLOAT_H 1
- /* Define to 1 if you have the `getpwuid' function. */
- #define HAVE_GETPWUID 1
- /* Define to 1 if you have the <inttypes.h> header file. */
- #define HAVE_INTTYPES_H 1
- /* Define if you have the IOKit API */
- /* #undef HAVE_IOKIT_IOKITLIB_H */
- /* Define to 1 if you have the <limits.h> header file. */
- #define HAVE_LIMITS_H 1
- /* Define if you have C99's lrintf function. */
- #define HAVE_LRINTF 1
- /* Define to 1 if you have the <mathf.h> header file. */
- /* #undef HAVE_MATHF_H */
- /* Define to 1 if you have the `memcpy' function. */
- #define HAVE_MEMCPY 1
- /* Define to 1 if you have the <memory.h> header file. */
- #define HAVE_MEMORY_H 1
- /* Define to 1 if you have the <stdint.h> header file. */
- #define HAVE_STDINT_H 1
- /* Define to 1 if you have the <stdlib.h> header file. */
- #define HAVE_STDLIB_H 1
- /* Define to 1 if you have the `strchr' function. */
- #define HAVE_STRCHR 1
- /* Define to 1 if you have the <strings.h> header file. */
- #define HAVE_STRINGS_H 1
- /* Define to 1 if you have the <string.h> header file. */
- #define HAVE_STRING_H 1
- /* Define to 1 if you have the `strsep' function. */
- #define HAVE_STRSEP 1
- /* Define to 1 if you have the <sysfs/libsysfs.h> header file. */
- /* #undef HAVE_SYSFS_LIBSYSFS_H */
- /* Define to 1 if you have the <sys/stat.h> header file. */
- #define HAVE_SYS_STAT_H 1
- /* Define to 1 if you have the <sys/time.h> header file. */
- #define HAVE_SYS_TIME_H 1
- /* Define to 1 if you have the <sys/types.h> header file. */
- #define HAVE_SYS_TYPES_H 1
- /* Define to 1 if you have the <unistd.h> header file. */
- #define HAVE_UNISTD_H 1
- /* Define to 1 if your C compiler doesn't accept -c and -o together. */
- /* #undef NO_MINUS_C_MINUS_O */
- /* Name of package */
- #define PACKAGE "faad2"
- /* Define to the address where bug reports for this package should be sent. */
- #define PACKAGE_BUGREPORT ""
- /* Define to the full name of this package. */
- #define PACKAGE_NAME ""
- /* Define to the full name and version of this package. */
- #define PACKAGE_STRING ""
- /* Define to the one symbol short name of this package. */
- #define PACKAGE_TARNAME ""
- /* Define to the version of this package. */
- #define PACKAGE_VERSION ""
- /* Define to 1 if you have the ANSI C header files. */
- #define STDC_HEADERS 1
- /* Define to 1 if you can safely include both <sys/time.h> and <time.h>. */
- #define TIME_WITH_SYS_TIME 1
- /* Version number of package */
- #define VERSION "2.7.0"
- /* Define to 1 if your processor stores words with the most significant byte
- first (like Motorola and SPARC, unlike Intel and VAX). */
- /* #undef WORDS_BIGENDIAN */
- /* Define to `__inline__' or `__inline' if that's what the C compiler
- calls it, or to nothing if 'inline' is not supported under any name. */
- #ifndef __cplusplus
- /* #undef inline */
- #endif
- /* Define to `long int' if <sys/types.h> does not define. */
- /* #undef off_t */
6.进入libfaad文件夹下面创建Android.mk
- LOCAL_PATH:= $(call my-dir)
- include $(CLEAR_VARS)
- LOCAL_SRC_FILES:= \
- bits.c \
- cfft.c \
- decoder.c \
- drc.c \
- drm_dec.c \
- error.c \
- filtbank.c \
- ic_predict.c \
- is.c \
- lt_predict.c \
- mdct.c \
- mp4.c \
- ms.c \
- output.c \
- pns.c \
- ps_dec.c \
- ps_syntax.c \
- pulse.c \
- specrec.c \
- syntax.c \
- tns.c \
- hcr.c \
- huffman.c \
- rvlc.c \
- ssr.c \
- ssr_fb.c \
- ssr_ipqf.c \
- common.c \
- sbr_dct.c \
- sbr_e_nf.c \
- sbr_fbt.c \
- sbr_hfadj.c \
- sbr_hfgen.c \
- sbr_huff.c \
- sbr_qmf.c \
- sbr_syntax.c \
- sbr_tf_grid.c \
- sbr_dec.c
- LOCAL_MODULE:= libfaad
- LOCAL_C_INCLUDES := \
- $(LOCAL_PATH) \
- $(FAAD2_TOP)/android \
- $(FAAD2_TOP)/include \
- $(LOCAL_PATH)/codebook
- LOCAL_CFLAGS:= \
- -DHAVE_CONFIG_H
- include $(BUILD_SHARED_LIBRARY)
7、在jni目录下面运行ndk-build
8、运行结果如下:
- root@zhangjie:/home/AACDecoder/jni# ndk-build
- Compile thumb : faad <= bits.c
- Compile thumb : faad <= cfft.c
- Compile thumb : faad <= decoder.c
- Compile thumb : faad <= drc.c
- Compile thumb : faad <= drm_dec.c
- Compile thumb : faad <= error.c
- Compile thumb : faad <= filtbank.c
- Compile thumb : faad <= ic_predict.c
- Compile thumb : faad <= is.c
- Compile thumb : faad <= lt_predict.c
- Compile thumb : faad <= mdct.c
- Compile thumb : faad <= mp4.c
- Compile thumb : faad <= ms.c
- Compile thumb : faad <= output.c
- Compile thumb : faad <= pns.c
- Compile thumb : faad <= ps_dec.c
- Compile thumb : faad <= ps_syntax.c
- Compile thumb : faad <= pulse.c
- Compile thumb : faad <= specrec.c
- Compile thumb : faad <= syntax.c
- Compile thumb : faad <= tns.c
- Compile thumb : faad <= hcr.c
- Compile thumb : faad <= huffman.c
- Compile thumb : faad <= rvlc.c
- Compile thumb : faad <= ssr.c
- Compile thumb : faad <= ssr_fb.c
- Compile thumb : faad <= ssr_ipqf.c
- Compile thumb : faad <= common.c
- Compile thumb : faad <= sbr_dct.c
- Compile thumb : faad <= sbr_e_nf.c
- Compile thumb : faad <= sbr_fbt.c
- Compile thumb : faad <= sbr_hfadj.c
- Compile thumb : faad <= sbr_hfgen.c
- Compile thumb : faad <= sbr_huff.c
- Compile thumb : faad <= sbr_qmf.c
- Compile thumb : faad <= sbr_syntax.c
- Compile thumb : faad <= sbr_tf_grid.c
- Compile thumb : faad <= sbr_dec.c
- SharedLibrary : libfaad.so
- Install : libfaad.so => libs/armeabi/libfaad.so