JNI函數(shù)的注冊:將Java層的native函數(shù)和JNI層對應的實現(xiàn)函數(shù)關聯(lián)起來专执。
===============================
PushNative.java
===============================
package com.fmtech.fmlive.jni;
public class PushNative {
static{
System.loadLibrary("FMLive");
}
public native void setAudioOptions(int sampleRateInHz, int channel);
}
===============================
FMLive.c
===============================
# define NELEM(x) ((int) (sizeof(x) / sizeof((x)[0])))
一、動態(tài)注冊
/*
* 音頻編碼器配置
* Class: com_fmtech_fmlive_jni_PushNative
* Method: setAudioOptions
* Signature: (II)V
*/
//JNIEXPORT void JNICALL Java_com_fmtech_fmlive_jni_PushNative_setAudioOptions
//Use dynamic register
JNIEXPORT void JNICALL native_setAudioOptions(JNIEnv *env, jobject jobj, jint sampleRateInHz, jint numChannels){
audio_encode_handle = faacEncOpen(sampleRateInHz, numChannels,&inputSamples,&maxOutputBytes);
if(!audio_encode_handle){
LOGE("%s","-------open audio_encode failed");
return;
}
//設置音頻編碼參數(shù)
faacEncConfigurationPtr p_config = faacEncGetCurrentConfiguration(audio_encode_handle);
p_config->mpegVersion = MPEG4;
p_config->allowMidside = 1;
p_config->aacObjectType = LOW;
p_config->outputFormat = 0; //輸出是否包含ADTS頭
p_config->useTns = 1; //時域噪音控制,大概就是消爆音
p_config->useLfe = 0;
// p_config->inputFormat = FAAC_INPUT_16BIT;
p_config->quantqual = 100;
p_config->bandWidth = 0; //頻寬
p_config->shortctl = SHORTCTL_NORMAL;
if(!faacEncSetConfiguration(audio_encode_handle, p_config)){
LOGE("%s","set faac encode configure failed");
return;
}
LOGI("%s","set faac encode configure success");
}
typedef struct {
const char* name;
const char* signature;
void* fnPtr;
} JNINativeMethod;
static const JNINativeMethod gMethods[] = {
{
"setAudioOptions",
"(II)V",
(void*)native_setAudioOptions
}
};
static int registerNatives(JNIEnv* env)
{
LOGI("registerNatives begin");
jclass clazz;
clazz = (*env) -> FindClass(env, "com/fmtech/fmlive/jni/PushNative");
if (clazz == NULL) {
LOGI("clazz is null");
return JNI_FALSE;
}
if ((*env) ->RegisterNatives(env, clazz, gMethods, NELEM(gMethods)) < 0) {
LOGI("RegisterNatives error");
return JNI_FALSE;
}
return JNI_TRUE;
}
jint JNI_OnLoad(JavaVM* vm, void* reserved){
JNIEnv* env = NULL;
if ((*vm)->GetEnv(vm,(void**) &env, JNI_VERSION_1_4) != JNI_OK) {
LOGI("ERROR: GetEnv failed\n");
return -1;
}
assert(env != NULL);
registerNatives(env);
return JNI_VERSION_1_4;//jni1.4以上支持
}
1郁油、函數(shù)動態(tài)注冊的好處:
移植方便本股?
2、使用數(shù)據(jù)結構JNINativeMethod來記錄Java native方法和JNI函數(shù)的一一對應關系桐腌。
typedef struct {
const char* name; //Java中native方法的名稱痊末,不用攜帶包的路徑
const char* signature; //Java方法的簽名信息,用字符串表示哩掺,是參數(shù)類型和返回值類型的組合
void* fnPtr; // JNI層對應函數(shù)的函數(shù)指針凿叠,注意它是void*類型
} JNINativeMethod;
3、當Java層通過System.loadLibrary加載完JNI動態(tài)庫后嚼吞,緊接著會查找該庫中一個叫JNI_OnLoad的函數(shù)盒件。如果有,就調用它舱禽,而動態(tài)注冊的工作就是在這里完成的炒刁。
所以,如果想使用動態(tài)注冊方法誊稚,就必須實現(xiàn)JNI_OnLoad函數(shù)翔始,只有在這個函數(shù)中才有機會完成動態(tài)注冊的工作。
二里伯、靜態(tài)注冊
JNIEXPORT void JNICALL Java_com_fmtech_fmlive_jni_PushNative_setAudioOptions
(JNIEnv *env, jobject jobj, jint sampleRateInHz, jint numChannels){
audio_encode_handle = faacEncOpen(sampleRateInHz, numChannels,&inputSamples,&maxOutputBytes);
if(!audio_encode_handle){
LOGE("%s","-------open audio_encode failed");
return;
}
//設置音頻編碼參數(shù)
faacEncConfigurationPtr p_config = faacEncGetCurrentConfiguration(audio_encode_handle);
p_config->mpegVersion = MPEG4;
p_config->allowMidside = 1;
p_config->aacObjectType = LOW;
p_config->outputFormat = 0; //輸出是否包含ADTS頭
p_config->useTns = 1; //時域噪音控制,大概就是消爆音
p_config->useLfe = 0;
// p_config->inputFormat = FAAC_INPUT_16BIT;
p_config->quantqual = 100;
p_config->bandWidth = 0; //頻寬
p_config->shortctl = SHORTCTL_NORMAL;
if(!faacEncSetConfiguration(audio_encode_handle, p_config)){
LOGE("%s","set faac encode configure failed");
return;
}
LOGI("%s","set faac encode configure success");
}
當Java層調用setAudioOptions 函數(shù)時城瞎,它會從對應的JNI庫中尋找Java_com_fmtech_fmlive_jni_PushNative_setAudioOptions函數(shù),如果沒有疾瓮,就會報錯脖镀。如果找到,則會為這個setAudioOptions 和Java_com_fmtech_fmlive_jni_PushNative_setAudioOptions建立一個關聯(lián)關系狼电,其實就是保存JNI層函數(shù)的函數(shù)指針蜒灰。以后再調用setAudioOptions函數(shù)時,直接使用這個函數(shù)指針就可以了肩碟,當然這項工作是由虛擬機完成的强窖。
函數(shù)靜態(tài)注冊就是根據(jù)函數(shù)名來建立Java函數(shù)和JNI函數(shù)之間的關聯(lián)關系的,而且它要求JNI層函數(shù)的名字必須遵守特定的格式削祈。
函數(shù)靜態(tài)注冊的弊端:
1?需要編譯所有聲明了native方法的Java類翅溺,每個所生成的class文件 都得用javah生成一個頭文件。
2、javah生成的JNI層函數(shù)名特別長未巫,書寫起來很不方便窿撬。
3启昧、初次調用native函數(shù)時要根據(jù)函數(shù)名字搜索對應用JNI層函數(shù)來建立關聯(lián)關系叙凡,這樣會影響運行效率。