2013-02-18 384 views
20

我正在使用的Android(Jelly Bean)的一個媒體編解碼器類來PCM格式編碼爲AAC。該文件已編碼,但沒有音樂播放器能夠播放該文件。我無法在網上找到任何工作代碼或適當的文檔。PCM到AAC轉換使用mediacodec

這是我的代碼:

public void doConvert() 
{ 

    new AsyncTask<Void, Void, Void>() 
    { 

     @Override 
     protected Void doInBackground(Void... params) 
     { 
      try 
      { 
       int codecCount = MediaCodecList.getCodecCount(); 

       for (int i=0; i < codecCount; i++) 
       { 
        MediaCodecInfo info = MediaCodecList.getCodecInfoAt(i); 
        Logger.getLogger(MainActivity.class.getSimpleName()).log(Level.INFO, info.getName()); 
        for (String type : info.getSupportedTypes()) 
        { 
         Logger.getLogger(MainActivity.class.getSimpleName()).log(Level.INFO, type); 
        } 

       } 

       File inputFile = new File(Environment.getExternalStorageDirectory().getAbsolutePath()+"/Download/Ghajini27_Mono_8Khz.wav"); 
       //File inputFile = new File(sampleFD.get); 
       Log.e("File", String.valueOf(inputFile.length())); 
       FileInputStream fis = new FileInputStream(inputFile); 
       fis.skip(44);//remove wav header 

       File outputFile = new File(Environment.getExternalStorageDirectory().getAbsolutePath()+"/Download/out.m4a"); 
       if (outputFile.exists()) outputFile.delete(); 

       FileOutputStream fos = new FileOutputStream(outputFile); 

       //BufferedOutputStream bos=new BufferedOutputStream(new FileOutputStream(outputFile)); 
       MediaCodec codec = MediaCodec.createEncoderByType("audio/mp4a-latm"); 
       MediaFormat outputFormat = MediaFormat.createAudioFormat("audio/mp4a-latm", 22050, 1); 
       outputFormat.setInteger(MediaFormat.KEY_AAC_PROFILE, MediaCodecInfo.CodecProfileLevel.AACObjectLC); 
      // outputFormat.setInteger(MediaFormat.KEY_CHANNEL_MASK, AudioFormat.CHANNEL_CONFIGURATION_MONO); 
       outputFormat.setInteger(MediaFormat.KEY_BIT_RATE, 22050 ); 
       outputFormat.setInteger(MediaFormat.KEY_CHANNEL_COUNT, 1); 
       //outputFormat.setLong(MediaFormat.KEY_MAX_INPUT_SIZE, inputFile.length()); 
       double durationInMs = (inputFile.length()/16000)*1000; 
       Log.e("duration",String.valueOf((long)durationInMs)); 
       outputFormat.setLong(MediaFormat.KEY_DURATION, (long)durationInMs); 


       codec.configure(outputFormat, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE); 
       codec.start(); 

       ByteBuffer[] inputBuffers = codec.getInputBuffers(); 
       ByteBuffer[] outputBuffer = codec.getOutputBuffers(); 

       boolean hasMoreData = true; 
       MediaCodec.BufferInfo outBuffInfo = new BufferInfo(); 
       byte readBuffer[] = new byte[48000]; 
       byte writeBuffer[] = new byte[48000]; 

       do 
       { 
        int nextBuffer = codec.dequeueInputBuffer(5000); 
        Log.e("NextBuffer","nextInputBuffer = "+nextBuffer); 

        if (nextBuffer >= 0) 
        { 



         ByteBuffer inBuf = inputBuffers[nextBuffer]; 
         inBuf.clear(); 
         int bytesRead = fis.read(readBuffer,0, inBuf.capacity()); 

         Log.e("bytesread","Read = "+bytesRead); 

         if (bytesRead < inBuf.capacity()) 
         { 
          hasMoreData = false; 
         } 

         inBuf.put(readBuffer, 0, bytesRead); 

         codec.queueInputBuffer(nextBuffer, 0, bytesRead, 0, hasMoreData?0:MediaCodec.BUFFER_FLAG_END_OF_STREAM); 
        } 


        int outputBufferIndex = codec.dequeueOutputBuffer(outBuffInfo, 3000); 
       /* logger.log(Level.INFO,"nextOutputBuffer = "+outputBufferIndex); 
        logger.log(Level.INFO,"outBuffInfo offset = "+outBuffInfo.offset); 
        logger.log(Level.INFO,"outBuffInfo size = "+outBuffInfo.size); 
        logger.log(Level.INFO,"outBuffInfo flags = "+outBuffInfo.flags);*/ 


        //while (outputBufferIndex > -1) 
        //{ 

         outputBuffer[outputBufferIndex].position(outBuffInfo.offset); 
         outputBuffer[outputBufferIndex].get(writeBuffer,0,outBuffInfo.size); 

         fos.write(writeBuffer,0, outBuffInfo.size); 
         // logger.log(Level.INFO,"Writing = "+outBuffInfo.size+" bytes"); 


         outputBuffer[outputBufferIndex].clear(); 

         codec.releaseOutputBuffer(outputBufferIndex, false); 

         if (outBuffInfo.flags == MediaCodec.BUFFER_FLAG_END_OF_STREAM) 
         { 
          codec.flush(); 
          codec.stop(); 
          codec.release(); 
          break; 
         } 

         //outputBufferIndex = codec.dequeueOutputBuffer(outBuffInfo, 1000); 
         //logger.log(Level.INFO,"nextOutputBuffer = "+outputBufferIndex); 
        //} 

       } while (outBuffInfo.flags != MediaCodec.BUFFER_FLAG_END_OF_STREAM); 

       fis.close(); 
       fos.flush(); 
       fos.close(); 



      } 
      catch (Exception e) 
      { 
       //Logger.getLogger(MainActivity.class.getSimpleName()).log(Level.INFO, "Codec Error",e); 
      } 

      //logger.log(Level.INFO,"Done"); 

      return null; 
     } 

    }.execute(); 
} 
+0

您應該發佈代碼的相關部分。否則,其他人或多或少無法弄清楚你可能做錯了什麼。 – Michael 2013-02-18 10:56:22

+0

編碼文件沒有標題,只是一個原始文件 – tikson 2013-02-18 11:40:03

+0

你能做到這一點嗎? – Soham 2014-05-04 22:09:56

回答

9

你需要選擇一個容器它。我更喜歡adts。

複製的有效載荷數據爲阿雷那是你的容器足夠大,只需添加上你的位。所以在網上淘了我的解決方案後,我工作的一些片斷到位

法「fillInADTSHeader」

profile =(configParams[0]>>3)&0x1f; 

    frequency_index = (this.configParams[0]&0x7) <<1 | (this.configParams[1]>>7) &0x1; 

    channel_config = (this.configParams[1]>>3) &0xf; 

    int finallength = encoded_length + 7;  
    ENCodedByteArray[0] = (byte) 0xff; 
    ENCodedByteArray[1] = (byte) 0xf1; 
    ENCodedByteArray[2] = (byte) (((profile - 1) << 6) + (frequency_index << 2) +(channel_config >> 2)); 
    ENCodedByteArray[3] = (byte) (((channel_config & 0x3) << 6) + (finallength >> 11)); 
    ENCodedByteArray[4] = (byte)((finallength & 0x7ff) >> 3); 
    ENCodedByteArray[5] = (byte) (((finallength & 7) << 5) + 0x1f) ; 
    ENCodedByteArray[6] = (byte) 0xfc; 

使用類似

  byte chunkADTS[]=new byte[info.size + 7]; 
      fillInADTSHeader(chunkADTS,info.size); 
      outputBuffers[bR].get(chunkADTS,7,info.size); 
      buffer.pushData(chunkADTS); 

在Shoutcast的應發揮,等等