Android平台上使用AudioRecord采集音视频数据,通过MediaCodec对音视频实施硬编码,回调aac数据流
初始化AudioRecord
{
if(loop)
return;
workThread = new Thread() {
@Override
public void run() {
if (audioRecord != null) {
audioRecord.startRecording();
}
while (loop && !Thread.interrupted()) {
//读取音频数据到buf
int size = audioRecord.read(audioBuf,0,audioBuf.length);
if (size > 0) {
// set audio data to encoder
// Log.d(TAG, "== =lgd= ====录音字节数:" + size);
if (mCallback != null) {
mCallback.audioData(audioBuf);
}
}
}
Log.d(TAG, "= =lgd= ==Audio录音线程退出...");
}
};
loop = true;
workThread.start();
}
初始化音频编码器:
public void initAudioEncoder(int sampleRate, int pcmFormat, int chanelCount){
aBufferInfo = new MediaCodec.BufferInfo();
audioQueue = new LinkedBlockingQueue<>();
audioCodecInfo = selectCodec(AUDIO_MIME_TYPE);
if (audioCodecInfo == null) {
if (DEBUG) Log.e(TAG, "= =lgd= Unable to find an appropriate codec for " + AUDIO_MIME_TYPE);
return;
}
Log.d(TAG, "===liuguodong===selected codec: " + audioCodecInfo.getName());
audioFormat = MediaFormat.createAudioFormat(AUDIO_MIME_TYPE, sampleRate, chanelCount);
audioFormat.setInteger(MediaFormat.KEY_AAC_PROFILE, MediaCodecInfo.CodecProfileLevel.AACObjectLC);
audioFormat.setInteger(MediaFormat.KEY_CHANNEL_MASK, AudioFormat.CHANNEL_IN_STEREO);//CHANNEL_IN_STEREO 立体声
int bitRate = sampleRate * pcmFormat * chanelCount;
audioFormat.setInteger(MediaFormat.KEY_BIT_RATE, bitRate);
audioFormat.setInteger(MediaFormat.KEY_CHANNEL_COUNT, chanelCount);
audioFormat.setInteger(MediaFormat.KEY_SAMPLE_RATE, sampleRate);
Log.d(TAG, " =lgd= =====format: " + audioFormat.toString());
if (aEncoder != null) {
return;
}
try {
aEncoder = MediaCodec.createEncoderByType(AUDIO_MIME_TYPE);
} catch (IOException e) {
e.printStackTrace();
throw new RuntimeException("===liuguodong===初始化音频编码器失败", e);
}
Log.d(TAG, String.format("= =lgd= =编码器:%s创建完成", aEncoder.getName()));
// aEncoder.configure(audioFormat, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE);
}
开始音频编码:
{
if (aEncoder == null) {
throw new RuntimeException(" =lgd= =请初始化音频编码器=====");
}
if (audioEncoderLoop) {
throw new RuntimeException(" =lgd= 音频编码线程必须先停止===");
}
audioEncoderThread = new Thread() {
@Override
public void run() {
Log.d(TAG, "===liuguodong=====Audio 编码线程 启动...");
presentationTimeUs = System.currentTimeMillis() * 1000;
aEncoderEnd = false;
aEncoder.configure(audioFormat, null, null,
MediaCodec.CONFIGURE_FLAG_ENCODE);
aEncoder.start();
while (audioEncoderLoop && !Thread.interrupted()) {
try {
byte[] data = audioQueue.take();
encodeAudioData(data);
} catch (InterruptedException e) {
e.printStackTrace();
break;
}
}
if (aEncoder != null) {
//停止音频编码器
aEncoder.stop();
//释放音频编码器
aEncoder.release();
aEncoder = null;
}
audioQueue.clear();
Log.d(TAG, "= =lgd= ==Audio 编码线程 退出...");
}
};
audioEncoderLoop = true;
audioEncoderThread.start();
}
数据回调:
private void setListener() {
mAudioGather.setCallback(new AudioGather.Callback() {
@Override
public void audioData(byte[] data) {
mAVEncoder.putAudioData(data);
}
});
mAVEncoder.setCallback(new AVEncoder.Callback() {
@Override
public void outputAudioSpecConfig(final byte[] aacSpec, final int len){
Runnable runnable = new Runnable() {
@Override
public void run() {
Log.e(TAG, "outputAudioSpecConfig");
}
};
try {
mRunnables.put(runnable);
} catch (InterruptedException e) {
Log.e(TAG, " =lgd= outputAudioSpecConfig=====error: "+e.toString());
e.printStackTrace();
}
}
@Override
public void outputAudioData(final byte[] aac, final int len,final int nTimeStamp) {
Runnable runnable = new Runnable() {
@Override
public void run() {
Log.e(TAG, "outPutAACData len"+len);
}
};
try {
mRunnables.put(runnable);
} catch (InterruptedException e) {
Log.e(TAG, " =lgd= outputAudioData=====error: "+e.toString());
e.printStackTrace();
}
}
});
}