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
- MediaCodec编码aac
- 安卓MediaCodec编码aac
- MediaCodec解码aac
- MediaCodec解码aac,播放
- 使用mediacodec 解码AAC
- ffmpeg开发之旅(3):AAC编码格式分析与MP4文件封装(MediaCodec+MediaMuxer)
- ffmpeg开发之旅(3):AAC编码格式分析与MP4文件封装(MediaCodec+MediaMuxer)
- MediaCodec编译pcm为aac
- MediaCodec编译pcm为aac
- Android MediaCodec解码aac,播放.
- MediaCodec编译pcm为aac
- Android MediaCodec解码aac,播放.
- Android MediaCodec解码aac播放
- 安卓 MediaCodec解码aac
- AAC包增加ADTS头Without MediaCodec
- MediaCodec 硬编码 h264
- Android MediaCodec 视频编码
- MediaCodec之H264编码
- [BZOJ4028] [HEOI2015] 公约数数列 - 分块
- C++静态库和动态库
- Qt Style Sheets 之 border-image
- Jetty 入门部署
- Mybatis复习笔记(二)
- MediaCodec编码aac
- AlertDialog中含有EditText不显示软键盘
- wsq指纹压缩算法库移植nbis
- C++11中final的使用
- Android Volley完全解析(一),初识Volley的基本用法
- 代码上传到github,gitlab等git仓库进行托管
- semaphore的简介
- LeetCode 260:Single number3
- 软件开发简述总结