Android PCM转AAC(AudioRecord采集)

Android平台上使用AudioRecord采集音视频数据,通过MediaCodec对音视频实施硬编码,回调aac数据流

初始化AudioRecord

{
        if(loop)
            return;
        workThread = new Thread() {
            @Override
            public void run() {
                if (audioRecord != null) {
                    audioRecord.startRecording();
                }
                while (loop && !Thread.interrupted()) {
                    //读取音频数据到buf
                    int size = audioRecord.read(audioBuf,0,audioBuf.length);
                    if (size > 0) {
                        // set audio data to encoder
                       // Log.d(TAG, "== =lgd= ====录音字节数:" + size);
                        if (mCallback != null) {
                            mCallback.audioData(audioBuf);
                        }
                    }
                }
                Log.d(TAG, "= =lgd= ==Audio录音线程退出...");
            }
        };

        loop = true;
        workThread.start();
    }

初始化音频编码器:

 public void initAudioEncoder(int sampleRate, int pcmFormat, int chanelCount){
        aBufferInfo = new MediaCodec.BufferInfo();
        audioQueue = new LinkedBlockingQueue<>();
        audioCodecInfo = selectCodec(AUDIO_MIME_TYPE);
        if (audioCodecInfo == null) {
            if (DEBUG) Log.e(TAG, "= =lgd= Unable to find an appropriate codec for " + AUDIO_MIME_TYPE);
            return;
        }
        Log.d(TAG, "===liuguodong===selected codec: " + audioCodecInfo.getName());
        audioFormat = MediaFormat.createAudioFormat(AUDIO_MIME_TYPE, sampleRate, chanelCount);
        audioFormat.setInteger(MediaFormat.KEY_AAC_PROFILE, MediaCodecInfo.CodecProfileLevel.AACObjectLC);
        audioFormat.setInteger(MediaFormat.KEY_CHANNEL_MASK, AudioFormat.CHANNEL_IN_STEREO);//CHANNEL_IN_STEREO 立体声
        int bitRate = sampleRate * pcmFormat * chanelCount;
        audioFormat.setInteger(MediaFormat.KEY_BIT_RATE, bitRate);
        audioFormat.setInteger(MediaFormat.KEY_CHANNEL_COUNT, chanelCount);
        audioFormat.setInteger(MediaFormat.KEY_SAMPLE_RATE, sampleRate);
        Log.d(TAG, " =lgd= =====format: " + audioFormat.toString());

        if (aEncoder != null) {
            return;
        }
        try {
            aEncoder = MediaCodec.createEncoderByType(AUDIO_MIME_TYPE);
        } catch (IOException e) {
            e.printStackTrace();
            throw new RuntimeException("===liuguodong===初始化音频编码器失败", e);
        }
        Log.d(TAG, String.format("= =lgd= =编码器:%s创建完成", aEncoder.getName()));
       // aEncoder.configure(audioFormat, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE);
    }

开始音频编码:

{
        if (aEncoder == null) {
            throw new RuntimeException(" =lgd= =请初始化音频编码器=====");
        }

        if (audioEncoderLoop) {
            throw new RuntimeException(" =lgd= 音频编码线程必须先停止===");
        }
        audioEncoderThread = new Thread() {
            @Override
            public void run() {
                Log.d(TAG, "===liuguodong=====Audio 编码线程 启动...");
                presentationTimeUs = System.currentTimeMillis() * 1000;
                aEncoderEnd = false;
                aEncoder.configure(audioFormat, null, null,
                        MediaCodec.CONFIGURE_FLAG_ENCODE);
                aEncoder.start();
                while (audioEncoderLoop && !Thread.interrupted()) {
                    try {
                        byte[] data = audioQueue.take();
                        encodeAudioData(data);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                        break;
                    }
                }
                if (aEncoder != null) {
                    //停止音频编码器
                    aEncoder.stop();
                    //释放音频编码器
                    aEncoder.release();
                    aEncoder = null;
                }

                audioQueue.clear();
                Log.d(TAG, "= =lgd= ==Audio 编码线程 退出...");
            }
        };
        audioEncoderLoop = true;
        audioEncoderThread.start();
    }

数据回调:

 private void setListener() {


        mAudioGather.setCallback(new AudioGather.Callback() {
            @Override
            public void audioData(byte[] data) {
                mAVEncoder.putAudioData(data);
            }
        });

        mAVEncoder.setCallback(new AVEncoder.Callback() {
            @Override
            public void outputAudioSpecConfig(final byte[] aacSpec, final int len){
                Runnable runnable = new Runnable() {
                    @Override
                    public void run() {
                        Log.e(TAG, "outputAudioSpecConfig");
                    }
                };
                try {
                    mRunnables.put(runnable);
                } catch (InterruptedException e) {
                    Log.e(TAG, " =lgd= outputAudioSpecConfig=====error: "+e.toString());
                    e.printStackTrace();
                }
            }

            @Override
            public void outputAudioData(final byte[] aac, final int len,final int nTimeStamp) {
                Runnable runnable = new Runnable() {
                    @Override
                    public void run() {
                        Log.e(TAG, "outPutAACData len"+len);
                    }
                };
                try {
                    mRunnables.put(runnable);
                } catch (InterruptedException e) {
                    Log.e(TAG, " =lgd= outputAudioData=====error: "+e.toString());
                    e.printStackTrace();
                }
            }
        });
    }

源码地址:https://github.com/printlybyte/AndroidPCMtoAACpushing

猜你喜欢

转载自blog.csdn.net/liu3364575/article/details/80319351