Android将mp3转成AAC再混合到视频中

Posted 汤米粥

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android将mp3转成AAC再混合到视频中相关的知识,希望对你有一定的参考价值。

    mediaMuxer = MediaMuxer(mSavedFile!!.absolutePath,  
                        MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4)
        if (mAudioPath != "") 
            encodeAudio(mediaMuxer)
            VideoEncoder(this, mSavedFile!!, 25, mediaMuxer,audioCodec).start()
         else 
            VideoEncoder(this, mSavedFile!!, 25, mediaMuxer,null).start()
        
    private fun encodeAudio(mediaMuxer: MediaMuxer) 
        audioCodec = AudioEncoder.newInstance()
        audioCodec.setEncodeType(MediaFormat.MIMETYPE_AUDIO_AAC)
        val file = File("/storage/emulated/0/Download/out1.aac")
        if (!file.exists()) 
            file.createNewFile()
        

        audioCodec.setMuxer(mediaMuxer)
        audioCodec.setTotalTime(mTotalTime)
        audioCodec.setIOPath(mAudioPath)
        audioCodec.prepare()
        audioCodec.setOnCompleteListener  audioCodec.release() 

        Handler().postDelayed( audioCodec.startAsync(mAudioPath) , 1000)

//        AudioCodec.getPCMFromAudio(mAudioPath, mAudioPath+".pcm", object : AudioDecodeListener 
//            override fun decodeOver() 
//                Log.e("xxx","mp3 转成 pcm")
//                AudioCodec.PcmToAudio(mAudioPath+".pcm", mAudioPath+".aac", object : AudioDecodeListener 
//                    override fun decodeOver() 
//                        Log.e("xxx","pcm 转成 aac")
//                        Log.e("xxx", "  音频转换完成  ")
//                    
//
//                    override fun decodeFail() 
//                )
//            
//
//            override fun decodeFail() 
//        )


    
import android.media.MediaCodec;
import android.media.MediaCodecInfo;
import android.media.MediaExtractor;
import android.media.MediaFormat;
import android.media.MediaMuxer;
import android.os.Build;
import android.os.Handler;
import android.util.Log;

import androidx.annotation.RequiresApi;

import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.concurrent.CopyOnWriteArrayList;

public class AudioEncoder 

    private static final String TAG = "AudioCodec";
    private String encodeType;
    private String srcPath;
    private MediaCodec mMp3Decoder;
    private MediaCodec mAacEncoder;
    private MediaExtractor extractor;
    private ByteBuffer[] decodeInputBuffers;
    private ByteBuffer[] decodeOutputBuffers;
    private ByteBuffer[] encodeInputBuffers;
    private ByteBuffer[] encodeOutputBuffers;
    private MediaCodec.BufferInfo decodeBufferInfo;
    private MediaCodec.BufferInfo encodeBufferInfo;
    private FileOutputStream fos;
    private BufferedOutputStream bos;
    private ArrayList<byte[]> chunkPCMDataContainer;//PCM数据块容器
    private OnCompleteListener onCompleteListener;
    private OnProgressListener onProgressListener;
    private long fileTotalSize;
    private long decodeSize;
    private MediaMuxer muxer;
    private int audioTrack;
    private boolean codeOver = false;
    private long mAudioPts = 0;
    private long presentationTimeUs;
    ArrayList<TempBufferData> tempBufferDataList = new ArrayList<TempBufferData>();

    private int sampleRate = 44100;
    private int channelCount = 1;

    public void setMuxerStart(boolean muxerStart) 
        this.muxerStart = muxerStart;
    

    private boolean muxerStart = false;

    public void setTotalTime(int mTotalTime) 
        this.mTotalTime = mTotalTime;
    

    private int mTotalTime;

    public static AudioEncoder newInstance() 
        return new AudioEncoder();
    

    /**
     * 设置编码器类型
     *
     * @param encodeType
     */
    public void setEncodeType(String encodeType) 
        this.encodeType = encodeType;
    

    /**
     * 设置输入输出文件位置
     *
     * @param srcPath
     */
    public void setIOPath(String srcPath) 
        this.srcPath = srcPath;
    

    public void setMuxer(MediaMuxer muxer) 
        this.muxer = muxer;
    

    public void setAudioTrack(int audioTrack) 
        this.audioTrack = audioTrack;
    

    /**
     * 此类已经过封装
     * 调用prepare方法 会初始化Decode 、Encode 、输入输出流 等一些列操作
     */
    public void prepare() 

        if (encodeType == null) 
            throw new IllegalArgumentException("encodeType can't be null");
        

        if (srcPath == null) 
            throw new IllegalArgumentException("srcPath can't be null");
        

        chunkPCMDataContainer = new ArrayList<>();

        initMediaDecoder();//解码器



    

    /**
     * 初始化解码器
     */
    private void initMediaDecoder() 
        try 
            extractor = new MediaExtractor();//此类可分离视频文件的音轨和视频轨道
            extractor.setDataSource(srcPath);//媒体文件的位置
            for (int i = 0; i < extractor.getTrackCount(); i++) //遍历媒体轨道 此处我们传入的是音频文件,所以也就只有一条轨道
                MediaFormat format = extractor.getTrackFormat(i);
                String mime = format.getString(MediaFormat.KEY_MIME);
                if (mime != null && mime.startsWith("audio")) //获取音频轨道
//                    format.setInteger(MediaFormat.KEY_MAX_INPUT_SIZE, 200 * 1024);
                    extractor.selectTrack(i);//选择此音频轨道
                    mMp3Decoder = MediaCodec.createDecoderByType(mime);//创建Decode解码器
                    mMp3Decoder.configure(format, null, null, 0);
                    sampleRate = format.getInteger(MediaFormat.KEY_SAMPLE_RATE);
                    channelCount = format.getInteger(MediaFormat.KEY_CHANNEL_COUNT);
                    break;
                
            
         catch (IOException e) 
            e.printStackTrace();
        

        if (mMp3Decoder == null) 
            Log.e(TAG, "create mMediaDecoder failed");
            return;
        
        mMp3Decoder.start();//启动MediaCodec ,等待传入数据
        decodeInputBuffers = mMp3Decoder.getInputBuffers();//MediaCodec在此ByteBuffer[]中获取输入数据
        decodeOutputBuffers = mMp3Decoder.getOutputBuffers();//MediaCodec将解码后的数据放到此ByteBuffer[]中 我们可以直接在这里面得到PCM数据
        decodeBufferInfo = new MediaCodec.BufferInfo();//用于描述解码得到的byte[]数据的相关信息
        showLog("decode buffers:" + decodeInputBuffers.length);


        //拿到音频的sourceSampleRate之后再初始化编码器
        mAacEncoder = initAACMediaEncode();//AAC编码器
        if (mAacEncoder == null) 
            Log.e(TAG, "create mMediaEncoder failed");
            return;
        
        mAacEncoder.start();
        encodeInputBuffers = mAacEncoder.getInputBuffers();
        encodeOutputBuffers = mAacEncoder.getOutputBuffers();
        encodeBufferInfo = new MediaCodec.BufferInfo();

        new Thread(new EncodeRunnable()).start();

    


    /**
     * 初始化AAC编码器
     *
     * @return
     */
    private MediaCodec initAACMediaEncode() 
        try 
            MediaFormat encodeFormat = MediaFormat.createAudioFormat(MediaFormat.MIMETYPE_AUDIO_AAC, sampleRate, channelCount);//参数对应-> mime type、采样率、声道数
            encodeFormat.setInteger(MediaFormat.KEY_BIT_RATE, 96000);//比特率
            encodeFormat.setInteger(MediaFormat.KEY_AAC_PROFILE, MediaCodecInfo.CodecProfileLevel.AACObjectLC);
            encodeFormat.setInteger(MediaFormat.KEY_MAX_INPUT_SIZE, 100 * 1024);
            MediaCodec mediaCodec = MediaCodec.createEncoderByType(MediaFormat.MIMETYPE_AUDIO_AAC);
            mediaCodec.configure(encodeFormat, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE);
            return mediaCodec;
         catch (IOException e) 
            e.printStackTrace();
        
        return null;
    


    /**
     * 开始转码
     * 音频数据@link #srcPath先解码成PCM  PCM数据在编码成想要得到的@link #encodeType音频格式
     * mp3->PCM->aac
     */
    public void startAsync(String audioPath) 
        showLog("start");

        new Thread(new DecodeRunnable()).start();


//        new Thread(new Runnable() 
//            @Override
//            public void run() 
//                audioToAAC(audioPath, -1, -1);
//            
//        ).start();

//        final String pcmPath = audioPath + ".pcm";
//        final String aacPath = audioPath + ".aac";
//
//        AudioCodec.getPCMFromAudio(audioPath, pcmPath, new AudioCodec.AudioDecodeListener() 
//            @Override
//            public void decodeOver() 
//                Log.e(TAG, "音频解码完成" + pcmPath);
//                AudioCodec.PcmToAudio(pcmPath, aacPath, new AudioCodec.AudioDecodeListener() 
//                    @Override
//                    public void decodeOver() 
//                        Log.e(TAG, "音频编码完成");
//                    
//
//                    @Override
//                    public void decodeFail() 
//                        Log.e(TAG, "音频编码失败");
//                    
//                );
//            
//
//            @Override
//            public void decodeFail() 
//                Log.e(TAG, "音频解码失败");
//            
//        );

    

    //尝试将mp3保存成aac,看能不能正常播放  https://blog.csdn.net/qq_29364417/article/details/87989965
    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;
        int bitRate = 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 = audioPath + ".aac";
//            muxer = new MediaMuxer(newAudioAAc, MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4);
            //音频信息获取
            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);
                bitRate = sourceFormat.getInteger(MediaFormat.KEY_BIT_RATE);

                Log.e("xxx-sourceSampleRate", sourceSampleRate + "");
                Log.e("xxx-bitRate", bitRate + "");
                sourceDuration = sourceFormat.getLong(MediaFormat.KEY_DURATION);
                if (sourceMimeType.startsWith("audio/"))  //找到音轨
                    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,  sourceSampleRate, channelCount);
            format.setInteger(MediaFormat.KEY_AAC_PROFILE, MediaCodecInfo.CodecProfileLevel.AACObjectLC);
            Log.e("xxx-sourceSampleRate", sourceSampleRate + "");
            Log.e("xxx-bitRate", bitRate + "");
            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);

            encodeInputBuffers = mEncorder.getInputBuffers();
            encodeOutputBuffers = mEncorder.getOutputBuffers();
            encodeBufferInfo = new MediaCodec.BufferInfo();

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

            ByteBuffer audioByteBuffer = ByteBuffer.allocate(1024 * 1024 * 10);

            FileOutputStream mFilePcm = new FileOutputStream(audioPath+".pcm");

            FileOutputStream mFileStream = new FileOutputStream(newAudioAAc);

            while (true) 
                int readSampleSize = audioExtractor.readSampleData(audioByteBuffer, 0);
                if (readSampleSize < 0) 
                    audioExtractor.unselectTrack(audioExtractorTrackIndex);
                    break;
                

                long audioSampleTime = audioExtractor.getSampleTime();

                Log.e("xxx-audioSampleTime",audioSampleTime+"");

                //可以做进度回调
                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 = null;
                    if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP) 
                        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 = null;
                    if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP) 
                        decoderOutputBuffer = audioDecoder.getOutputBuffer(sourceOutputBufferIndex);
                    

                    //编码
                    int inputBufferIndex = mEncorder.dequeueInputBuffer(timeOutUs);
                    if (inputBufferIndex >= 0) 
                        ByteBuffer inputBuffer = null;
                        if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP) 
                            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 = null;
                        if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP) 
                            outputBuffer = mEncorder.getOutputBuffer(outputBufferIndex);
                        
                        int outBufferSize = outputBuffer.limit() + 7;
                        byte[] aacBytes = new byte[outBufferSize];
                        addADTStoPacket(aacBytes, outBufferSize);
                        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;
            Log.i(TAG, "编码结束==" + b);
         catch (Exception e) 
            e.printStackTrace();

        
        return newAudioAAc;
    


    /**
     * 将PCM数据存入@link #chunkPCMDataContainer
     *
     * @param pcmChunk PCM数据块
     */
    private void putPCMData(byte[] pcmChunk) 
        synchronized (AudioEncoder.class) //记得加锁
            chunkPCMDataContainer.add(pcmChunk);
        
    

    /**
     * 在Container中@link #chunkPCMDataContainer取出PCM数据
     *
     * @return PCM数据块
     */
    private byte[] getPCMData() 
        synchronized (AudioEncoder.class) //记得加锁
            showLog("getPCM:" + chunkPCMDataContainer.size());
            if (chunkPCMDataContainer.isEmpty()) 
                return null;
            

            byte[] pcmChunk = chunkPCMDataContainer.get(0);//每次取出index 0 的数据
            chunkPCMDataContainer.remove(pcmChunk);//取出后将此数据remove掉 既能保证PCM数据块的取出顺序 又能及时释放内存
            return pcmChunk;
        
    


    /**
     * 解码@link #srcPath音频文件 得到PCM数据块
     *
     * @return 是否解码完所有数据
     */
    private void mp3ToPCM() throws IOException 
        fos = new FileOutputStream( srcPath+".pcm");

        for (int i = 0; i < decodeInputBuffers.length - 1; i++) 
            int inputIndex = mMp3Decoder.dequeueInputBuffer(-1);//获取可用的inputBuffer -1代表一直等待,0表示不等待 建议-1,避免丢帧
            if (inputIndex < 0) 
                codeOver = true;
                return;
            

            ByteBuffer inputBuffer = decodeInputBuffers[inputIndex];//拿到inputBuffer
            inputBuffer.clear();//清空之前传入inputBuffer内的数据
            int sampleSize = extractor.readSampleData(inputBuffer, 0);//MediaExtractor读取数据到inputBuffer中
            long timestampTemp = extractor.getSampleTime();
            if (sampleSize < 0 || timestampTemp > 1000 * mTotalTime) //小于0 代表所有数据已读取完成
                codeOver = true;
             else 
                mMp3Decoder.queueInputBuffer(inputIndex, 0, sampleSize, 0, 0);//通知MediaDecode解码刚刚传入的数据
                extractor.advance();//MediaExtractor移动到下一取样处
                decodeSize += sampleSize;
            
        

        //获取解码得到的byte[]数据 参数BufferInfo上面已介绍 10000同样为等待时间 同上-1代表一直等待,0代表不等待。此处单位为微秒
        //此处建议不要填-1 有些时候并没有数据输出,那么他就会一直卡在这 等待
        int outputIndex = mMp3Decoder.dequeueOutputBuffer(decodeBufferInfo, 10000);

//        showLog("decodeOutIndex:" + outputIndex);
        ByteBuffer outputBuffer;
        byte[] chunkPCM;
        while (outputIndex >= 0) //每次解码完成的数据不一定能一次吐出 所以用while循环,保证解码器吐出所有数据
            outputBuffer = decodeOutputBuffers[outputIndex];//拿到用于存放PCM数据的Buffer
            chunkPCM = new byte[decodeBufferInfo.size];//BufferInfo内定义了此数据块的大小
            outputBuffer.get(chunkPCM);//将Buffer内的数据取出到字节数组中
            outputBuffer.clear();//数据取出后一定记得清空此Buffer MediaCodec是循环使用这些Buffer的,不清空下次会得到同样的数据
            //保存到文件中
            fos.write(chunkPCM);
            fos.flush();
            putPCMData(chunkPCM);//自己定义的方法,供编码器所在的线程获取数据,下面会贴出代码
            mMp3Decoder.releaseOutputBuffer(outputIndex, false);//此操作一定要做,不然MediaCodec用完所有的Buffer后 将不能向外输出数据
            outputIndex = mMp3Decoder.dequeueOutputBuffer(decodeBufferInfo, 10000);//再次获取数据,如果没有数据输出则outputIndex=-1 循环结束
        

        fos.close();

    

    /**
     * 编码PCM数据 得到@link #encodeType格式的音频文件,并保存到@link 
     */
    @RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR2)
    private void pcmToAac() 

        int inputIndex;
        ByteBuffer inputBuffer;
        int outputIndex;
        ByteBuffer outputBuffer;
        byte[] chunkAudio;
        int outBitSize;
        int outPacketSize;
        byte[] chunkPCM;


//        showLog("doEncode");
        for (int i = 0; i < encodeInputBuffers.length - 1; i++) 
            chunkPCM = getPCMData();//获取解码器所在线程输出的数据 代码后边会贴上
            if (chunkPCM == null) 
                break;
            
            inputIndex = mAacEncoder.dequeueInputBuffer(-1);//同解码器
            inputBuffer = encodeInputBuffers[inputIndex];//同解码器
            inputBuffer.clear();//同解码器
            inputBuffer.limit(chunkPCM.length);
            inputBuffer.put(chunkPCM);//PCM数据填充给inputBuffer

            //***************问题在这儿,之前这里写死成441000,导致播放时长变短,音频声音变急促***************/
            presentationTimeUs += (long) (1.0 * chunkPCM.length / ( sampleRate * channelCount * (16 / 8)) * 1000000.0);


            mAacEncoder.queueInputBuffer(inputIndex, 0, chunkPCM.length, presentationTimeUs, 0);//通知编码器 编码
        

        outputIndex = mAacEncoder.dequeueOutputBuffer(encodeBufferInfo, 10000);//同解码器

        if (outputIndex == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) 
            audioTrack = muxer.addTrack(mAacEncoder.getOutputFormat());
         else 
            while (outputIndex >= 0) //同解码器
                outBitSize = encodeBufferInfo.size;
                outPacketSize = outBitSize + 7;//7为ADTS头部的大小
                outputBuffer = encodeOutputBuffers[outputIndex];//拿到输出Buffer
                outputBuffer.position(encodeBufferInfo.offset);
                outputBuffer.limit(encodeBufferInfo.offset + outBitSize);
                chunkAudio = new byte[outPacketSize];
                addADTStoPacket(chunkAudio, outPacketSize);//添加ADTS 代码后面会贴上
                outputBuffer.get(chunkAudio, 7, outBitSize);//将编码得到的AAC数据 取出到byte[]中 偏移量offset=7 你懂得
                outputBuffer.position(encodeBufferInfo.offset);
                while (!muxerStart) 
                    try 
                        Thread.sleep(100);
                     catch (Exception e) 

                    
                

                //将数据写到混合器的audioTrack轨道中去
                muxer.writeSampleData(audioTrack, outputBuffer, encodeBufferInfo);
                mAacEncoder.releaseOutputBuffer(outputIndex, false);
                outputIndex = mAacEncoder.dequeueOutputBuffer(encodeBufferInfo, 10000);
            
        
    

    public static ByteBuffer clone(ByteBuffer original) 
        ByteBuffer clone = ByteBuffer.allocate(original.capacity());
        original.rewind();//copy from the beginning
        clone.put(original);
        original.rewind();
        clone.flip();
        return clone;
    

    /**
     * 添加ADTS头
     *
     * @param packet
     * @param packetLen
     */
    private void addADTStoPacket(byte[] packet, int packetLen) 
        int profile = 2; // AAC LC
        int freqIdx = 4; // 44.1KHz
        int chanCfg = 2; // CPE


// fill in ADTS data
        packet[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;
    

    /**
     * 释放资源
     */
    public void release() 
        try 
            if (bos != null) 
                bos.flush();
            
         catch (IOException e) 
            e.printStackTrace();
         finally 
            if (bos != null) 
                try 
                    bos.close();
                 catch (IOException e) 
                    e.printStackTrace();
                 finally 
                    bos = null;
                
            
        

        try 
            if (fos != null) 
                fos.close();
            
         catch (IOException e) 
            e.printStackTrace();
         finally 
            fos = null;
        

        if (mAacEncoder != null) 
            mAacEncoder.stop();
            mAacEncoder.release();
            mAacEncoder = null;
        

        if (mMp3Decoder != null) 
            mMp3Decoder.stop();
            mMp3Decoder.release();
            mMp3Decoder = null;
        

        if (extractor != null) 
            extractor.release();
            extractor = null;
        

        if (onCompleteListener != null) 
            onCompleteListener = null;
        

        if (onProgressListener != null) 
            onProgressListener = null;
        
        showLog("release");
    

    /**
     * 解码线程
     */
    private class DecodeRunnable implements Runnable 
        @Override
        public void run() 
            while (!codeOver) 
                try 
                    mp3ToPCM();
                 catch (IOException e) 
                    e.printStackTrace();
                
            
        
    

    /**
     * 编码线程
     */
    private class EncodeRunnable implements Runnable 

        @Override
        public void run() 
            long t = System.currentTimeMillis();
            while (!codeOver || !chunkPCMDataContainer.isEmpty()) 
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) 
                    pcmToAac();
                
            
            if (onCompleteListener != null) 
                onCompleteListener.completed();
            
            showLog("size:" + fileTotalSize + " decodeSize:" + decodeSize + "time:" + (System.currentTimeMillis() - t));
        
    


    /**
     * 转码完成回调接口
     */
    public interface OnCompleteListener 
        void completed();
    

    /**
     * 转码进度监听器
     */
    public interface OnProgressListener 
        void progress();
    

    class TempBufferData 
        public TempBufferData(ByteBuffer byteBuffer, MediaCodec.BufferInfo bufferInfo) 
            this.byteBuffer = byteBuffer;
            this.bufferInfo = bufferInfo;
        

        ByteBuffer byteBuffer;
        MediaCodec.BufferInfo bufferInfo;
    
    /**
     * 设置转码完成监听器
     *
     * @param onCompleteListener
     */
    public void setOnCompleteListener(OnCompleteListener onCompleteListener) 
        this.onCompleteListener = onCompleteListener;
    

    public void setOnProgressListener(OnProgressListener onProgressListener) 
        this.onProgressListener = onProgressListener;
    

    private void showLog(String msg) 
//        Log.d("AudioCodec", msg);
    
 /**
     * 解码线程
     */
    private class DecodeRunnable implements Runnable 
        @Override
        public void run() 
            while (!codeOver) 
                try 
                    mp3ToPCM();
                 catch (IOException e) 
                    e.printStackTrace();
                
            
        
    

    /**
     * 编码线程
     */
    private class EncodeRunnable implements Runnable 

        @Override
        public void run() 
            long t = System.currentTimeMillis();
            while (!codeOver || !chunkPCMDataContainer.isEmpty()) 
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) 
                    pcmToAac();
                
            
            if (onCompleteListener != null) 
                onCompleteListener.completed();
            
            showLog("size:" + fileTotalSize + " decodeSize:" + decodeSize + "time:" + (System.currentTimeMillis() - t));
        
    
 /**
     * 解码@link #srcPath音频文件 得到PCM数据块
     *
     * @return 是否解码完所有数据
     */
    private void mp3ToPCM() throws IOException 
        fos = new FileOutputStream( srcPath+".pcm");

        for (int i = 0; i < decodeInputBuffers.length - 1; i++) 
            int inputIndex = mMp3Decoder.dequeueInputBuffer(-1);//获取可用的inputBuffer -1代表一直等待,0表示不等待 建议-1,避免丢帧
            if (inputIndex < 0) 
                codeOver = true;
                return;
            

            ByteBuffer inputBuffer = decodeInputBuffers[inputIndex];//拿到inputBuffer
            inputBuffer.clear();//清空之前传入inputBuffer内的数据
            int sampleSize = extractor.readSampleData(inputBuffer, 0);//MediaExtractor读取数据到inputBuffer中
            long timestampTemp = extractor.getSampleTime();
            if (sampleSize < 0 || timestampTemp > 1000 * mTotalTime) //小于0 代表所有数据已读取完成
                codeOver = true;
             else 
                mMp3Decoder.queueInputBuffer(inputIndex, 0, sampleSize, 0, 0);//通知MediaDecode解码刚刚传入的数据
                extractor.advance();//MediaExtractor移动到下一取样处
                decodeSize += sampleSize;
            
        

        //获取解码得到的byte[]数据 参数BufferInfo上面已介绍 10000同样为等待时间 同上-1代表一直等待,0代表不等待。此处单位为微秒
        //此处建议不要填-1 有些时候并没有数据输出,那么他就会一直卡在这 等待
        int outputIndex = mMp3Decoder.dequeueOutputBuffer(decodeBufferInfo, 10000);

//        showLog("decodeOutIndex:" + outputIndex);
        ByteBuffer outputBuffer;
        byte[] chunkPCM;
        while (outputIndex >= 0) //每次解码完成的数据不一定能一次吐出 所以用while循环,保证解码器吐出所有数据
            outputBuffer = decodeOutputBuffers[outputIndex];//拿到用于存放PCM数据的Buffer
            chunkPCM = new byte[decodeBufferInfo.size];//BufferInfo内定义了此数据块的大小
            outputBuffer.get(chunkPCM);//将Buffer内的数据取出到字节数组中
            outputBuffer.clear();//数据取出后一定记得清空此Buffer MediaCodec是循环使用这些Buffer的,不清空下次会得到同样的数据
            //保存到文件中
            fos.write(chunkPCM);
            fos.flush();
            putPCMData(chunkPCM);//自己定义的方法,供编码器所在的线程获取数据,下面会贴出代码
            mMp3Decoder.releaseOutputBuffer(outputIndex, false);//此操作一定要做,不然MediaCodec用完所有的Buffer后 将不能向外输出数据
            outputIndex = mMp3Decoder.dequeueOutputBuffer(decodeBufferInfo, 10000);//再次获取数据,如果没有数据输出则outputIndex=-1 循环结束
        

        fos.close();

    
 /**
     * 编码PCM数据 得到@link #encodeType格式的音频文件,并保存到@link 
     */
    @RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR2)
    private void pcmToAac() 

        int inputIndex;
        ByteBuffer inputBuffer;
        int outputIndex;
        ByteBuffer outputBuffer;
        byte[] chunkAudio;
        int outBitSize;
        int outPacketSize;
        byte[] chunkPCM;


//        showLog("doEncode");
        for (int i = 0; i < encodeInputBuffers.length - 1; i++) 
            chunkPCM = getPCMData();//获取解码器所在线程输出的数据 代码后边会贴上
            if (chunkPCM == null) 
                break;
            
            inputIndex = mAacEncoder.dequeueInputBuffer(-1);//同解码器
            inputBuffer = encodeInputBuffers[inputIndex];//同解码器
            inputBuffer.clear();//同解码器
            inputBuffer.limit(chunkPCM.length);
            inputBuffer.put(chunkPCM);//PCM数据填充给inputBuffer

            //***************问题在这儿,之前这里写死成441000,导致播放时长变短,音频声音变急促***************/
            presentationTimeUs += (long) (1.0 * chunkPCM.length / ( sampleRate * channelCount * (16 / 8)) * 1000000.0);


            mAacEncoder.queueInputBuffer(inputIndex, 0, chunkPCM.length, presentationTimeUs, 0);//通知编码器 编码
        

        outputIndex = mAacEncoder.dequeueOutputBuffer(encodeBufferInfo, 10000);//同解码器

        if (outputIndex == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) 
            audioTrack = muxer.addTrack(mAacEncoder.getOutputFormat());
         else 
            while (outputIndex >= 0) //同解码器
                outBitSize = encodeBufferInfo.size;
                outPacketSize = outBitSize + 7;//7为ADTS头部的大小
                outputBuffer = encodeOutputBuffers[outputIndex];//拿到输出Buffer
                outputBuffer.position(encodeBufferInfo.offset);
                outputBuffer.limit(encodeBufferInfo.offset + outBitSize);
                chunkAudio = new byte[outPacketSize];
                addADTStoPacket(chunkAudio, outPacketSize);//添加ADTS 代码后面会贴上
                outputBuffer.get(chunkAudio, 7, outBitSize);//将编码得到的AAC数据 取出到byte[]中 偏移量offset=7 你懂得
                outputBuffer.position(encodeBufferInfo.offset);
                while (!muxerStart) 
                    try 
                        Thread.sleep(100);
                     catch (Exception e) 

                    
                

                //将数据写到混合器的audioTrack轨道中去
                muxer.writeSampleData(audioTrack, outputBuffer, encodeBufferInfo);
                mAacEncoder.releaseOutputBuffer(outputIndex, false);
                outputIndex = mAacEncoder.dequeueOutputBuffer(encodeBufferInfo, 10000);
            
        
    

以上是关于Android将mp3转成AAC再混合到视频中的主要内容,如果未能解决你的问题,请参考以下文章

怎么把mp3转成aac格式?

mp3转成aac后音质会降低吗

ffmpeg 音轨提取

MP3转AAC音频格式怎么使用音频转换器转换?

有啥转换器可以将QMCFLAC格式转成MP3格式

flac格式如何转成MP3或者WMA格式?