安卓 MediaCodec解码aac

来源:互联网 发布:旅行商问题算法 编辑:程序博客网 时间:2024/06/05 01:42

上一篇博文介绍了如何用MediaCodec进行aac编码,这篇介绍如何解码,在解码上要注意的点是解码时要一帧一帧的喂给解码器而且得带adts头,另外要将头一帧的两个特殊字节用来对解码器进行配置,解码出来就是pcm编码的音频数据了,可以直接将pcm数据写进AudioTrack进行播放。

[java] view plain copy
  1. /** 
  2.  * @author zhangsutao 
  3.  * @file AudioDecoder 
  4.  * @brief aac音频解码播放器 
  5.  * @date 2016/8/7 
  6.  */  
  7. public class AudioDecoder implements AudioCodec{  
  8.     private static final String TAG ="AudioDecoder";  
  9.     private Worker mWorker;  
  10.     private Server mServer;  
  11.     private byte[] mPcmData;  
  12.     public AudioDecoder(Server server) throws DecoderServerNullException {  
  13.         if (server==null){  
  14.             throw new DecoderServerNullException();  
  15.         }  
  16.         mServer=server;  
  17.     }  
  18.   
  19.     public void start(){  
  20.         if(mWorker==null){  
  21.             mWorker=new Worker();  
  22.             mWorker.setRunning(true);  
  23.             mWorker.start();  
  24.         }  
  25.     }  
  26.     public void stop(){  
  27.         if(mWorker!=null){  
  28.             mWorker.setRunning(false);  
  29.             mWorker=null;  
  30.         }  
  31.         if(mServer!=null){  
  32.             if(!mServer.hasRelease()){  
  33.                 mServer.release();  
  34.             }  
  35.         }  
  36.     }  
  37.   
  38.         private class Worker extends Thread{  
  39.             private boolean isRunning=false;  
  40.             private AudioTrack mPlayer;  
  41.             private MediaCodec mDecoder;  
  42.             MediaCodec.BufferInfo mBufferInfo;  
  43.             public void setRunning(boolean run){  
  44.                 isRunning=run;  
  45.             }  
  46.             @Override  
  47.             public void run() {  
  48.                 super.run();  
  49.                 if(!prepare()){  
  50.                     isRunning=false;  
  51.                     Log.d(TAG,"音频解码器初始化失败");  
  52.                 }  
  53.                 while(isRunning){  
  54.                     decode();  
  55.                 }  
  56.                 release();  
  57.             }  
  58.   
  59.             /** 
  60.              * 等待客户端连接,初始化解码器 
  61.              * @return 初始化失败返回false,成功返回true 
  62.              */  
  63.             public boolean prepare() {  
  64.                 //等待客户端  
  65.                 mServer.start();  
  66.                 mBufferInfo = new MediaCodec.BufferInfo();  
  67.                 mPlayer=new AudioTrack(AudioManager.STREAM_MUSIC,KEY_SAMPLE_RATE, AudioFormat.CHANNEL_OUT_STEREO, AUDIO_FORMAT,BUFFFER_SIZE,AudioTrack.MODE_STREAM);  
  68.                 mPlayer.play();  
  69.                 try {  
  70.                     mDecoder = MediaCodec.createDecoderByType(MIME_TYPE);  
  71.                     byte[] csd_0=mServer.readFrame();  
  72.                     if(csd_0==null){  
  73.                         return false;  
  74.                     }  
  75.                     MediaFormat format = new MediaFormat();  
  76.                     format.setString(MediaFormat.KEY_MIME,MIME_TYPE);  
  77.                     format.setInteger(MediaFormat.KEY_CHANNEL_COUNT, KEY_CHANNEL_COUNT);  
  78.                     format.setInteger(MediaFormat.KEY_SAMPLE_RATE, KEY_SAMPLE_RATE);  
  79.                     format.setInteger(MediaFormat.KEY_BIT_RATE, KEY_BIT_RATE);  
  80.                     format.setInteger(MediaFormat.KEY_IS_ADTS,1);  
  81.                     format.setInteger(MediaFormat.KEY_AAC_PROFILE,KEY_AAC_PROFILE);  
  82.                     byte[] bytes = new byte[]{csd_0[7],csd_0[8]};  
  83.                     ByteBuffer bb = ByteBuffer.wrap(bytes);  
  84.                     format.setByteBuffer("csd-0", bb);  
  85.                     mDecoder.configure(format, nullnull0);  
  86.                 } catch (IOException e) {  
  87.                     e.printStackTrace();  
  88.                     return false;  
  89.                 }  
  90.                 if (mDecoder == null) {  
  91.                     Log.e(TAG, "create mediaDecode failed");  
  92.                     return false;  
  93.                 }  
  94.                 mDecoder.start();  
  95.                 return true;  
  96.             }  
  97.   
  98.             /** 
  99.              * aac解码+播放 
  100.              */  
  101.             public void decode() {  
  102.   
  103.                 boolean isEOF=false;  
  104.                 while(!isEOF){  
  105.                     //获取可用的inputBuffer -1代表一直等待,0表示不等待 建议-1,避免丢帧  
  106.                     int inputIndex = mDecoder.dequeueInputBuffer(-1);  
  107.                     if(inputIndex>=0){  
  108.                         ByteBuffer inputBuffer = mDecoder.getInputBuffer(inputIndex);  
  109.                         if(inputBuffer==null){  
  110.                             return ;  
  111.                         }  
  112.                         inputBuffer.clear();  
  113.                         Frame frame=mServer.readFrameWidthCache();  
  114.                         if(frame==null){  
  115.                             mDecoder.queueInputBuffer(inputIndex, 000, MediaCodec.BUFFER_FLAG_END_OF_STREAM);  
  116.                             isEOF = true;  
  117.                             isRunning=false;  
  118.                             //服务已经断开,释放服务端  
  119.                             mServer.release();  
  120.                         }else {  
  121.                             inputBuffer.put(frame.mData,0,frame.length);  
  122.                             mDecoder.queueInputBuffer(inputIndex, 0, frame.length, 00);  
  123.                         }  
  124.                     }else {  
  125.                         isEOF=true;  
  126.                     }  
  127.                     int outputIndex = mDecoder.dequeueOutputBuffer(mBufferInfo, WAIT_TIME);  
  128.                     Log.d(TAG,"audio decoding .....");  
  129.                     ByteBuffer outputBuffer;  
  130.                     //每次解码完成的数据不一定能一次吐出 所以用while循环,保证解码器吐出所有数据  
  131.                     while (outputIndex >= 0) {  
  132.                         outputBuffer = mDecoder.getOutputBuffer(outputIndex);  
  133.                         if(mPcmData==null||mPcmData.length<mBufferInfo.size){  
  134.                             mPcmData=new byte[mBufferInfo.size];  
  135.                         }  
  136. //                        chunkPCM = new byte[mBufferInfo.size];  
  137.                         outputBuffer.get(mPcmData,0,mBufferInfo.size);  
  138.                         outputBuffer.clear();//数据取出后一定记得清空此Buffer MediaCodec是循环使用这些Buffer的,不清空下次会得到同样的数据  
  139.                         //播放音乐  
  140.                         mPlayer.write(mPcmData,0,mBufferInfo.size);  
  141.                         mDecoder.releaseOutputBuffer(outputIndex, false);//此操作一定要做,不然MediaCodec用完所有的Buffer后 将不能向外输出数据  
  142.                         outputIndex = mDecoder.dequeueOutputBuffer(mBufferInfo, WAIT_TIME);//再次获取数据,如果没有数据输出则outputIndex=-1 循环结束  
  143.                     }  
  144.                 }  
  145.             }  
  146.   
  147.             /** 
  148.              * 释放资源 
  149.              */  
  150.             private void release(){  
  151.                 if(mDecoder!=null){  
  152.                     mDecoder.stop();  
  153.                     mDecoder.release();  
  154.                 }  
  155.                 if(mPlayer!=null){  
  156.                     mPlayer.stop();  
  157.                     mPlayer.release();  
  158.                     mPlayer=null;  
  159.                 }  
  160.   
  161.             }  
  162.         }  
  163.     }  

上面的代码包含了解码和播放,后来了解到往AudioTrack写入数据时会造成阻塞,因为我是用Socket接收来的音频数据,所以在播放时造成了很大的延迟,应该放在另外的线程上来播放才对。大家根据自己的需要进行修改就好了。
原创粉丝点击