android 实时PCM数据编码成AAC

获取PCM流

package com.ff.aac.audio;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import com.ff.aac.jni.AacEncoder;

import android.media.AudioRecord;
import android.media.MediaRecorder.AudioSource;
import android.os.SystemClock;
import android.util.Log;
/**
 * 音频发送封装类
 */
public class DAudioRecord implements Runnable{
	private final String TAG="DAudioRecord";
	private int mFrequency;//采样率
	private int mChannel;//声道
	private int mSampBit;//采样精度
	private AacEncoder encoder;
	private AudioRecord mAudioRecord;
	private boolean recordTag;
	private int minBufferSize;
	public DAudioRecord(int frequency,int channel,int sampbit){
		this.mFrequency = frequency;
		this.mChannel = channel;
		this.mSampBit = sampbit;
	}
	
	public void init(){
		if(mAudioRecord != null){
			release();
		}
		try {
			minBufferSize = AudioRecord.getMinBufferSize(mFrequency, mChannel, mSampBit);
			mAudioRecord = new AudioRecord(AudioSource.MIC, mFrequency, mChannel, mSampBit, minBufferSize);
			Log.i(TAG, "minBufferSize = " + minBufferSize);
		} catch (Exception e) {
			Log.i(TAG, "创建录音器出错");
		}
	}
	
	public void startRecord(AacEncoder encoder){
		this.recordTag = true;
		this.encoder = encoder;
		new Thread(this).start();
	}
	
	public void stopRecord(){
		this.recordTag = false;
	}
	
	public void release(){
		if(mAudioRecord != null){
			try {
				mAudioRecord.stop();
				mAudioRecord.release();
				encoder.stopSendRecodData();
			} catch (Exception e) {
				Log.i(TAG, "关闭录音出错");
			}finally{
				mAudioRecord = null;
				encoder = null;
				System.gc();
			}
		}
	}

	@Override
	public void run() {
		try {
			boolean b = true;
			while (b && recordTag) {
				if(mAudioRecord.getState() == AudioRecord.STATE_INITIALIZED){
					mAudioRecord.startRecording();
					b = false;
				}
				Log.i(TAG, "录音开始初始化");
				SystemClock.sleep(10);
			}
			byte[] audioData = new byte[512]; // 640
			byte[] audioData1 = new byte[2048]; // inputSamples = 1024, maxOutputBytes = 768  ,maxInputBytes = 2048 (jni 中编码aac中获取到的信息)
			int i = 0;
			while (recordTag) {
				int size = mAudioRecord.read(audioData, 0,audioData.length);
				if (size == audioData.length) {
					Log.i("AAC_JNI", "录音" + size);
					for(int j = 0; j < size; j++){
						audioData1[j + i * 512] = audioData[j];
					}
					i++;
					if(i == 4){
						this.encoder.sendRecordData(audioData1);
						i = 0;
					}
				}
			}
		} catch (Exception e) {
			Log.i(TAG, "录音过程出错 " + e.getMessage());
		}
	}
}

jni中结构体

struct AacDecoderInfo{
	faacEncHandle hEncoder;
	char* pcmBuffer;
	char* aacBuffer;
	int maxInputBytes;
	int maxOutputBytes;
	int bitSize;
	int inputSamples;
	FILE* ftOutFile;
};
struct AacDecoderInfo *aacDecoderInfo;
jni中进行实时编码

JNIEXPORT void JNICALL Java_com_ff_aac_jni_AacEncoder_initAACEncoder
  (JNIEnv *env, jobject obj){
	unsigned long sampleRate = 8000;
	unsigned int numChannels = 1;
	unsigned long inputSamples;
	unsigned long maxOutputBytes;
	faacEncHandle hEncoder = faacEncOpen(sampleRate, numChannels, &inputSamples, &maxOutputBytes);
	LOGD("inputSamples = %d, maxOutputBytes = %d, sampleRate = %d", inputSamples, maxOutputBytes);

 	faacEncConfigurationPtr pConfigPtr;
 	pConfigPtr = faacEncGetCurrentConfiguration(hEncoder);
	if(!pConfigPtr){
	    LOGD("faacEncGetCurrentConfiguration ERROR!");
	    faacEncClose(hEncoder);
            hEncoder = NULL;
            return;
	 }

	pConfigPtr->inputFormat = FAAC_INPUT_16BIT;//输入数据类型
        pConfigPtr->outputFormat = 1; //0-Raw ; 1-ADTS
 	pConfigPtr->bitRate = 8000;
 //	pConfigPtr->useTns= 0;//瞬时噪声定形(temporal noise shaping,TNS)滤波器
 //	pConfigPtr->useLfe= 0;//低频效果
	pConfigPtr->aacObjectType= LOW; //编码类型
	pConfigPtr->shortctl=SHORTCTL_NORMAL;
	pConfigPtr->quantqual=20;
        pConfigPtr->mpegVersion = MPEG2;
	int nRetVal = faacEncSetConfiguration(hEncoder, pConfigPtr);
	LOGD("nRetVal = %d", nRetVal);

	int nPCMBitSize = 16; // 量化位数
	int m_nMaxInputBytes = inputSamples * nPCMBitSize / 8;
	LOGD("m_nMaxInputBytes = %d", m_nMaxInputBytes);

	char pbPCMBuffer[m_nMaxInputBytes]; // 读取PCM数据
	char pbAACBuffer[maxOutputBytes];

	FILE* fpOut = fopen("/storage/emulated/0/t/pcm2aac.aac", "wb");
 	aacDecoderInfo = malloc(sizeof(struct AacDecoderInfo));
	aacDecoderInfo->hEncoder = hEncoder;
 	aacDecoderInfo->pcmBuffer = pbPCMBuffer;
	aacDecoderInfo->aacBuffer = pbAACBuffer;
 	aacDecoderInfo->maxInputBytes = m_nMaxInputBytes;
	aacDecoderInfo->maxOutputBytes = maxOutputBytes;
	aacDecoderInfo->bitSize = nPCMBitSize;
	aacDecoderInfo->inputSamples = inputSamples;
 	aacDecoderInfo->ftOutFile = fpOut;

	isRecord = true;
}

/*
 * http://blog.csdn.net/jwzhangjie/article/details/8782656 (如果不这样设置将导致编码失败)
 *
 *  */
size_t read_int16(int16_t *outbuf, size_t num, unsigned char *inputbuf){
	size_t i = 0 , j = 0;
	unsigned char bufi[8];
	while(i < num){
		memcpy(bufi, inputbuf+j, (aacDecoderInfo->bitSize / 8));
		j+= (aacDecoderInfo->bitSize / 8);
		int16_t s = ((int16_t*)bufi)[0];
		outbuf[i] = s;
		i++;
	}
	return 0;
}

JNIEXPORT void JNICALL Java_com_ff_aac_jni_AacEncoder_sendRecordData
  (JNIEnv *env, jobject obj, jbyteArray arr){
	LOGD("sendRecordData isRecord = %d", isRecord);
	jsize size = (*env)->GetArrayLength(env, arr);
	LOGD("sendRecordData arr size = %d", size);
	int inputSamples = size / (aacDecoderInfo->bitSize / 8);
	LOGD("sendRecordData intputSamples = %d, default intputSamples = %d", inputSamples, aacDecoderInfo->inputSamples);
	memset(aacDecoderInfo->aacBuffer, 0, aacDecoderInfo->maxOutputBytes);
	char* cArr = (*env)->GetByteArrayElements(env,arr,false);
	int pumbuff_size = size / (aacDecoderInfo->bitSize / 8);
	int pumBuf[pumbuff_size];
	read_int16(pumBuf, size, cArr);

	int nRetVal = faacEncEncode(aacDecoderInfo->hEncoder, pumBuf, inputSamples, aacDecoderInfo->aacBuffer, aacDecoderInfo->maxOutputBytes);
	LOGD("sendRecordData nRetVal = %d", nRetVal);
	(*env)->ReleaseByteArrayElements(env, arr, cArr, 0);
	fwrite(aacDecoderInfo->aacBuffer, 1, nRetVal, aacDecoderInfo->ftOutFile);
}

JNIEXPORT void JNICALL Java_com_ff_aac_jni_AacEncoder_stopSendRecodData
  (JNIEnv *env, jobject obj){
 	fclose(aacDecoderInfo->ftOutFile);
	faacEncClose(aacDecoderInfo->hEncoder);
	free(aacDecoderInfo);
}
java 调用

        int frequency = 8000;
	int channel = AudioFormat.CHANNEL_IN_MONO;
	int sampbit = AudioFormat.ENCODING_PCM_16BIT;
    	audioRecord = new DAudioRecord(frequency, channel, sampbit);
    	audioRecord.init();
    	final AacEncoder encoder = new AacEncoder();
 	audioRecord.startRecord(encoder);

package com.ff.aac.jni;

public class AacEncoder {
	static{
		System.loadLibrary("aacdec");
	}
	public native void initAACEncoder();
	public native void sendRecordData(byte[] data);
	public native void stopSendRecodData();
}


你可能感兴趣的:(实时,PCM,aac)