MediaCodec编码aac

来源:互联网 发布:阿里云带宽调整 编辑:程序博客网 时间:2024/05/22 14:09

我们可以用AudioRecoder对音频进行采集,采集的音频是pcm编码的原始数据,通过MediaCodec编码成aac音频,这里要注意的是编码出来是aac裸流,是无法播放的,要播放的话必须在每一帧音频前加adts头,adts头包含音频数据的采样率,声道,帧长度等信息,必须有adts头才可以正确解码。还有就是编码时出来的第一帧是一个两个字节的数据,这个数据也是比较特殊的需要用来在解码时配置解码器,才可以正确解码。


/** * @author zhangsutao * @file AudioCodec.java * @brief 音频编解码器基类 * @date 2016/8/7 */public interface AudioCodec {    String MIME_TYPE="audio/mp4a-latm";    int KEY_CHANNEL_COUNT=2;    int KEY_SAMPLE_RATE=44100;    int KEY_BIT_RATE=64000;    int KEY_AAC_PROFILE= MediaCodecInfo.CodecProfileLevel.AACObjectLC;    int WAIT_TIME=10000;    int AUDIO_FORMAT = AudioFormat.ENCODING_PCM_16BIT;    int CHANNEL_MODE = AudioFormat.CHANNEL_IN_STEREO;    int BUFFFER_SIZE=2048;}


/*** @author zhangsutao* @file AudioEncoder.java* @brief aac音频编码器* @date 2016/8/7*/public class AudioEncoder implements AudioCodec{private Client mClient;private Worker mWorker;private final String TAG="AudioEncoder";private byte[] mFrameByte;public AudioEncoder(Client client) {mClient=client;}public void start(){if(mWorker==null){mWorker=new Worker();mWorker.setRunning(true);mWorker.start();}}public void stop(){if(mWorker!=null){mWorker.setRunning(false);mWorker=null;}if(!mClient.hasRelease()){mClient.release();}}private class Worker extends Thread{private final int mFrameSize = 2048;private byte[] mBuffer;private boolean isRunning=false;private MediaCodec mEncoder;private AudioRecord mRecord;MediaCodec.BufferInfo mBufferInfo;@Overridepublic void run() {if(!prepare()){Log.d(TAG,"音频编码器初始化失败");isRunning=false;}while(isRunning){int num = mRecord.read(mBuffer, 0, mFrameSize);Log.d(TAG, "buffer = " + mBuffer.toString() + ", num = " + num);encode(mBuffer);}release();}public void setRunning(boolean run){isRunning=run;}/** * 释放资源 */private void release() {if(mEncoder!=null){mEncoder.stop();mEncoder.release();}if(mRecord!=null){mRecord.stop();mRecord.release();mRecord = null;}}/** * 连接服务端,编码器配置 * @return true配置成功,false配置失败         */private boolean prepare() {try {mClient.connectToServer();mBufferInfo = new MediaCodec.BufferInfo();mEncoder = MediaCodec.createEncoderByType(MIME_TYPE);MediaFormat mediaFormat = MediaFormat.createAudioFormat(MIME_TYPE,KEY_SAMPLE_RATE, KEY_CHANNEL_COUNT);mediaFormat.setInteger(MediaFormat.KEY_BIT_RATE, KEY_BIT_RATE);mediaFormat.setInteger(MediaFormat.KEY_AAC_PROFILE,KEY_AAC_PROFILE);mEncoder.configure(mediaFormat, null, null,MediaCodec.CONFIGURE_FLAG_ENCODE);mEncoder.start();} catch (IOException e) {e.printStackTrace();return false;}mBuffer = new byte[mFrameSize];int minBufferSize = AudioRecord.getMinBufferSize(KEY_SAMPLE_RATE, CHANNEL_MODE,AUDIO_FORMAT);mRecord = new AudioRecord(MediaRecorder.AudioSource.MIC,KEY_SAMPLE_RATE, CHANNEL_MODE, AUDIO_FORMAT, minBufferSize * 2);mRecord.startRecording();return true;}private void encode(byte[] data) {int inputBufferIndex = mEncoder.dequeueInputBuffer(-1);if (inputBufferIndex >= 0) {ByteBuffer inputBuffer = mEncoder.getInputBuffer(inputBufferIndex);inputBuffer.clear();inputBuffer.put(data);inputBuffer.limit(data.length);mEncoder.queueInputBuffer(inputBufferIndex, 0, data.length,System.nanoTime(), 0);}int outputBufferIndex = mEncoder.dequeueOutputBuffer(mBufferInfo, 0);while (outputBufferIndex >= 0) {ByteBuffer outputBuffer = mEncoder.getOutputBuffer(outputBufferIndex);//给adts头字段空出7的字节int length=mBufferInfo.size+7;if(mFrameByte==null||mFrameByte.length<length){mFrameByte=new byte[length];}addADTStoPacket(mFrameByte,length);outputBuffer.get(mFrameByte,7,mBufferInfo.size);boolean isSusscess1=mClient.sendInt(length);boolean isSusscess2=mClient.send(mFrameByte,0,length);if(!(isSusscess1&&isSusscess2)){isRunning=false;mClient.release();}mEncoder.releaseOutputBuffer(outputBufferIndex, false);outputBufferIndex = mEncoder.dequeueOutputBuffer(mBufferInfo, 0);}}/** * 给编码出的aac裸流添加adts头字段 * @param packet 要空出前7个字节,否则会搞乱数据 * @param packetLen         */private void addADTStoPacket(byte[] packet, int packetLen) {int profile = 2;  //AAC LCint freqIdx = 4;  //44.1KHzint chanCfg = 2;  //CPEpacket[0] = (byte)0xFF;packet[1] = (byte)0xF9;packet[2] = (byte)(((profile-1)<<6) + (freqIdx<<2) +(chanCfg>>2));packet[3] = (byte)(((chanCfg&3)<<6) + (packetLen>>11));packet[4] = (byte)((packetLen&0x7FF) >> 3);packet[5] = (byte)(((packetLen&7)<<5) + 0x1F);packet[6] = (byte)0xFC;}}}


1 0
原创粉丝点击