天天看點

android 音頻檔案轉AAC

實作:

/**
     *
     * @param audioPath
     * @param audioStartTimeUs -1 表示不截取
     * @param audioEndTimeUs -1 表示不截取
     * @return
     */
    public String audioToAAC(String audioPath,long audioStartTimeUs,long audioEndTimeUs){

        long a=System.currentTimeMillis();
        int audioExtractorTrackIndex=-1;
        int audioMuxerTrackIndex=-1;
        int channelCount=1;
        int sourceSampleRate = 0;
        String newAudioAAc = "";
        long sourceDuration=0;

        try {
            File tempFlie = new File(audioPath);
            String tempName = tempFlie.getName();
            String suffix = tempName.substring(tempName.lastIndexOf(".") + 1);
//             newAudioAAc= tempFlie.getParentFile().getAbsolutePath() + "/" + tempName.replace(suffix, "aac");
            newAudioAAc= FileTools.getAudioSaveDirectory()+ tempName.replace(suffix, "aac");
//            muxer = new MediaMuxer(newAudioAAc, MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4);
            LogTools.i(TAG,"audioPath=="+audioPath+",newAudioAAC=="+newAudioAAc+",newAudioAAc=="+newAudioAAc);
            //音頻資訊擷取
            MediaExtractor audioExtractor = new MediaExtractor();
            audioExtractor.setDataSource(audioPath); 
            int trackCount = audioExtractor.getTrackCount(); 

            MediaFormat sourceFormat=null;
            String sourceMimeType="";
            int timeOutUs=300;

            for (int i = 0; i < trackCount; i++) {
                sourceFormat = audioExtractor.getTrackFormat(i); 
                sourceMimeType = sourceFormat.getString(MediaFormat.KEY_MIME);
                channelCount=sourceFormat.getInteger(MediaFormat.KEY_CHANNEL_COUNT);
                sourceSampleRate = sourceFormat.getInteger(MediaFormat.KEY_SAMPLE_RATE);
                sourceDuration = sourceFormat.getLong(MediaFormat.KEY_DURATION);
                if (sourceMimeType.startsWith("audio/")) { //找到音軌
                    LogTools.i(TAG,"sourceMimeType=="+sourceMimeType+",channelCount=="+channelCount+",sourceSampleRate=="+sourceSampleRate);
                    audioExtractorTrackIndex = i;
                    break;
                }
            }

            //初始化解碼器
            MediaCodec audioDecoder=null;
            audioDecoder = MediaCodec.createDecoderByType(sourceMimeType);
            audioDecoder.configure(sourceFormat, null, null, 0);
            audioDecoder.start();

            //初始化編碼
            MediaCodec mEncorder=null;
            mEncorder = MediaCodec.createEncoderByType(MediaFormat.MIMETYPE_AUDIO_AAC);
            MediaFormat format = MediaFormat.createAudioFormat(MediaFormat.MIMETYPE_AUDIO_AAC, 44100, channelCount);
            format.setInteger(MediaFormat.KEY_AAC_PROFILE, MediaCodecInfo.CodecProfileLevel.AACObjectLC);
            format.setInteger(MediaFormat.KEY_BIT_RATE, 96000);
            format.setInteger(MediaFormat.KEY_MAX_INPUT_SIZE, 1024*1024 * 10);
            mEncorder.configure(format, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE);
            mEncorder.start();

            audioExtractor.selectTrack(audioExtractorTrackIndex);

            MediaCodec.BufferInfo sourceAudioBufferInfo = new MediaCodec.BufferInfo();
            MediaCodec.BufferInfo audioBufferInfo = new MediaCodec.BufferInfo();

            ByteBuffer audioByteBuffer = ByteBuffer.allocate(1024*1024*10);
            FileOutputStream mFileStream = new FileOutputStream(newAudioAAc);

            while (true) {
                int readSampleSize = audioExtractor.readSampleData(audioByteBuffer, 0); 
                LogTools.i(TAG, "readSampleSize==" + readSampleSize+",audioByteBuffer.limit=="+audioByteBuffer.limit()+",timeOutUs=="+timeOutUs);
                if (readSampleSize < 0) { 
                    audioExtractor.unselectTrack(audioExtractorTrackIndex);
                    break;
                }

                long audioSampleTime=audioExtractor.getSampleTime();
                
                //可以做進度回調
                LogTools.i(TAG, "audioSampleTime==" +audioSampleTime+",,progress=="+((float)audioSampleTime/(float)sourceDuration));
                if (audioStartTimeUs !=-1 && audioSampleTime < audioStartTimeUs) { 
                    audioExtractor.advance(); 
                    continue;
                }

                if (audioEndTimeUs !=-1 && audioSampleTime > audioEndTimeUs) { 
                    break;
                }

                int audioSampleFlags=audioExtractor.getSampleFlags();

                //解碼
                int sourceInputBufferIndex = audioDecoder.dequeueInputBuffer(timeOutUs);
                if (sourceInputBufferIndex >= 0) {
                    ByteBuffer sourceInputBuffer = audioDecoder.getInputBuffer(sourceInputBufferIndex);
                    sourceInputBuffer.clear();
                    sourceInputBuffer.put(audioByteBuffer);
                    audioDecoder.queueInputBuffer(sourceInputBufferIndex, 0, readSampleSize, audioSampleTime, audioSampleFlags);
                }


                int sourceOutputBufferIndex = audioDecoder.dequeueOutputBuffer(sourceAudioBufferInfo, timeOutUs);
                if (sourceOutputBufferIndex == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) {
                    // 後續輸出格式變化
                }
                while (sourceOutputBufferIndex >= 0) {
                    ByteBuffer decoderOutputBuffer = audioDecoder.getOutputBuffer(sourceOutputBufferIndex);



                    //編碼
                    int inputBufferIndex = mEncorder.dequeueInputBuffer(timeOutUs);
                    if (inputBufferIndex >= 0) {
                        ByteBuffer inputBuffer = mEncorder.getInputBuffer(inputBufferIndex);
                        inputBuffer.clear();
                        inputBuffer.put(decoderOutputBuffer);
                        mEncorder.queueInputBuffer(inputBufferIndex, 0, decoderOutputBuffer.limit(), audioSampleTime, audioSampleFlags);
                    }

                    int outputBufferIndex = mEncorder.dequeueOutputBuffer(audioBufferInfo, timeOutUs);
                    if (outputBufferIndex == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) {
                        // 後續輸出格式變化
                    }
                    while (outputBufferIndex >= 0) {

                        ByteBuffer outputBuffer = mEncorder.getOutputBuffer(outputBufferIndex);
                        int outBufferSize = outputBuffer.limit() + 7;
                        byte[] aacBytes = new byte[outBufferSize];
                        addADTStoPacket(aacBytes, outBufferSize, channelCount);
                        outputBuffer.get(aacBytes, 7, outputBuffer.limit());

                        mFileStream.write(aacBytes);
                        
                        mEncorder.releaseOutputBuffer(outputBufferIndex, false);
                        outputBufferIndex = mEncorder.dequeueOutputBuffer(audioBufferInfo, timeOutUs);
                    }




                    audioDecoder.releaseOutputBuffer(sourceOutputBufferIndex, false);
                    sourceOutputBufferIndex = audioDecoder.dequeueOutputBuffer(sourceAudioBufferInfo, timeOutUs);
                }
                audioExtractor.advance(); 
            }

            //釋放資源
            mEncorder.stop();
            mFileStream.flush();
            mFileStream.close();
            long b=System.currentTimeMillis()-a;
            LogTools.i(TAG,"編碼結束=="+b);
        } catch (Exception e) {
            e.printStackTrace();

        }
        return newAudioAAc;
    }

    public static void addADTStoPacket(byte[] packet, int packetLen, int chancfg) {
        int profile = 2;  //AAC LC,MediaCodecInfo.CodecProfileLevel.AACObjectLC;
        int freqIdx = 4;  //見後面注釋avpriv_mpeg4audio_sample_rates中441000對應的數組下标,來自ffmpeg源碼
//        int chanCfg = 1;  //見後面注釋channel_configuration,AudioFormat.CHANNEL_IN_MONO 單聲道(聲道數量)
        int chanCfg = chancfg;  //見後面注釋channel_configuration,AudioFormat.CHANNEL_IN_MONO 單聲道(聲道數量)

        /*int avpriv_mpeg4audio_sample_rates[] = {96000, 88200, 64000, 48000, 44100, 32000,24000, 22050, 16000, 12000, 11025, 8000, 7350};
        channel_configuration: 表示聲道數chanCfg
        0: Defined in AOT Specifc Config
        1: 1 channel: front-center
        2: 2 channels: front-left, front-right
        3: 3 channels: front-center, front-left, front-right
        4: 4 channels: front-center, front-left, front-right, back-center
        5: 5 channels: front-center, front-left, front-right, back-left, back-right
        6: 6 channels: front-center, front-left, front-right, back-left, back-right, LFE-channel
        7: 8 channels: front-center, front-left, front-right, side-left, side-right, back-left, back-right, LFE-channel
        8-15: Reserved
        */

        // fill in ADTS data
        packet[0] = (byte)0xFF;
//        packet[1] = (byte)0xF9;
        packet[1] = (byte)0xF1; //解決ios 手機不能播放問題
        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;

    }