上一篇博文介绍了如何用MediaCodec进行aac编码,这篇介绍如何解码,在解码上要注意的点是解码时要一帧一帧的喂给解码器而且得带adts头,另外要将头一帧的两个特殊字节用来对解码器进行配置,解码出来就是pcm编码的音频数据了,可以直接将pcm数据写进AudioTrack进行播放。
-
-
-
-
-
-
- public class AudioDecoder implements AudioCodec{
- private static final String TAG ="AudioDecoder";
- private Worker mWorker;
- private Server mServer;
- private byte[] mPcmData;
- public AudioDecoder(Server server) throws DecoderServerNullException {
- if (server==null){
- throw new DecoderServerNullException();
- }
- mServer=server;
- }
-
- 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(mServer!=null){
- if(!mServer.hasRelease()){
- mServer.release();
- }
- }
- }
-
- private class Worker extends Thread{
- private boolean isRunning=false;
- private AudioTrack mPlayer;
- private MediaCodec mDecoder;
- MediaCodec.BufferInfo mBufferInfo;
- public void setRunning(boolean run){
- isRunning=run;
- }
- @Override
- public void run() {
- super.run();
- if(!prepare()){
- isRunning=false;
- Log.d(TAG,"音频解码器初始化失败");
- }
- while(isRunning){
- decode();
- }
- release();
- }
-
-
-
-
-
- public boolean prepare() {
-
- mServer.start();
- mBufferInfo = new MediaCodec.BufferInfo();
- mPlayer=new AudioTrack(AudioManager.STREAM_MUSIC,KEY_SAMPLE_RATE, AudioFormat.CHANNEL_OUT_STEREO, AUDIO_FORMAT,BUFFFER_SIZE,AudioTrack.MODE_STREAM);
- mPlayer.play();
- try {
- mDecoder = MediaCodec.createDecoderByType(MIME_TYPE);
- byte[] csd_0=mServer.readFrame();
- if(csd_0==null){
- return false;
- }
- MediaFormat format = new MediaFormat();
- format.setString(MediaFormat.KEY_MIME,MIME_TYPE);
- format.setInteger(MediaFormat.KEY_CHANNEL_COUNT, KEY_CHANNEL_COUNT);
- format.setInteger(MediaFormat.KEY_SAMPLE_RATE, KEY_SAMPLE_RATE);
- format.setInteger(MediaFormat.KEY_BIT_RATE, KEY_BIT_RATE);
- format.setInteger(MediaFormat.KEY_IS_ADTS,1);
- format.setInteger(MediaFormat.KEY_AAC_PROFILE,KEY_AAC_PROFILE);
- byte[] bytes = new byte[]{csd_0[7],csd_0[8]};
- ByteBuffer bb = ByteBuffer.wrap(bytes);
- format.setByteBuffer("csd-0", bb);
- mDecoder.configure(format, null, null, 0);
- } catch (IOException e) {
- e.printStackTrace();
- return false;
- }
- if (mDecoder == null) {
- Log.e(TAG, "create mediaDecode failed");
- return false;
- }
- mDecoder.start();
- return true;
- }
-
-
-
-
- public void decode() {
-
- boolean isEOF=false;
- while(!isEOF){
-
- int inputIndex = mDecoder.dequeueInputBuffer(-1);
- if(inputIndex>=0){
- ByteBuffer inputBuffer = mDecoder.getInputBuffer(inputIndex);
- if(inputBuffer==null){
- return ;
- }
- inputBuffer.clear();
- Frame frame=mServer.readFrameWidthCache();
- if(frame==null){
- mDecoder.queueInputBuffer(inputIndex, 0, 0, 0, MediaCodec.BUFFER_FLAG_END_OF_STREAM);
- isEOF = true;
- isRunning=false;
-
- mServer.release();
- }else {
- inputBuffer.put(frame.mData,0,frame.length);
- mDecoder.queueInputBuffer(inputIndex, 0, frame.length, 0, 0);
- }
- }else {
- isEOF=true;
- }
- int outputIndex = mDecoder.dequeueOutputBuffer(mBufferInfo, WAIT_TIME);
- Log.d(TAG,"audio decoding .....");
- ByteBuffer outputBuffer;
-
- while (outputIndex >= 0) {
- outputBuffer = mDecoder.getOutputBuffer(outputIndex);
- if(mPcmData==null||mPcmData.length<mBufferInfo.size){
- mPcmData=new byte[mBufferInfo.size];
- }
-
- outputBuffer.get(mPcmData,0,mBufferInfo.size);
- outputBuffer.clear();
-
- mPlayer.write(mPcmData,0,mBufferInfo.size);
- mDecoder.releaseOutputBuffer(outputIndex, false);
- outputIndex = mDecoder.dequeueOutputBuffer(mBufferInfo, WAIT_TIME);
- }
- }
- }
-
-
-
-
- private void release(){
- if(mDecoder!=null){
- mDecoder.stop();
- mDecoder.release();
- }
- if(mPlayer!=null){
- mPlayer.stop();
- mPlayer.release();
- mPlayer=null;
- }
-
- }
- }
- }
上面的代码包含了解码和播放,后来了解到往AudioTrack写入数据时会造成阻塞,因为我是用Socket接收来的音频数据,所以在播放时造成了很大的延迟,应该放在另外的线程上来播放才对。大家根据自己的需要进行修改就好了。