卓凡姓黎 2022-06-30 21:28 采纳率: 100%
浏览 39
已结题

使用AudioRecord采样回来的float数组如何编码成aac

使用AudioRecord采样回来的float数组如何编码成aac?

audioFormat 设置成 AudioFormat.ENCODING_PCM_FLOAT,read之后是float数组。而MediaCodec编码需要的是byte数组,如何使用MediaCodec正确编码成aac文件?使用了ByteBuffer putFloat(int index, float value) 之后发现音频文件时长变成了真实时长的好几倍。不知道具体哪里出了问题

初始化
            int audioSource = MediaRecorder.AudioSource.MIC;
            int channelConfig = AudioFormat.CHANNEL_IN_MONO;//单声道
            int channelCount = 1;//对应的通道数
            int audioFormat = AudioFormat.ENCODING_PCM_FLOAT;//采样位数
            int sampleRate = 48000;//采样率
            int bitRate = sampleRate * channelCount * 32;//【比特率】= 【采样率】* 【通道】* 【采样位数】
            int sampleSize = sampleRate / (1000 / 25);//每次采样的样本个数 1000 / 25 => 每25ms采样一次 1秒采样40次 即每次获取12000个样本
//            int bufferSizeInBytes = AudioRecord.getMinBufferSize(sampleRate, channelConfig, audioFormat);
            int bufferSizeInBytes = sampleSize * 4;//float * 4
            floatBuffer = new float[sampleSize];
            audioRecorder = new AudioRecord(audioSource, sampleRate, channelConfig, audioFormat, bufferSizeInBytes);
            //初始化编码器
            mediaCodec = MediaCodec.createEncoderByType(MediaFormat.MIMETYPE_AUDIO_AAC);
            MediaFormat mediaFormat = MediaFormat.createAudioFormat(MediaFormat.MIMETYPE_AUDIO_AAC, sampleRate, channelCount);
            mediaFormat.setInteger(MediaFormat.KEY_AAC_PROFILE, MediaCodecInfo.CodecProfileLevel.AACObjectLC);//标记aac级别
            mediaFormat.setInteger(MediaFormat.KEY_MAX_INPUT_SIZE, bufferSizeInBytes);
            mediaFormat.setInteger(MediaFormat.KEY_BIT_RATE, bitRate);
            mediaCodec.configure(mediaFormat, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE);
            bufferInfo = new MediaCodec.BufferInfo();
读取录音
        try {
            long nanoTime = System.nanoTime() / 1000;
            while (isRecording) {
                //获取音频
                int len = audioRecorder.read(floatBuffer, 0, floatBuffer.length, AudioRecord.READ_BLOCKING);
                if (len > 0) {
                    ByteBuffer inputBuffer = null;
                    int inputIndex = mediaCodec.dequeueInputBuffer(-1);
                    if (inputIndex >= 0) {
                        inputBuffer = mediaCodec.getInputBuffer(inputIndex);
                        inputBuffer.clear();
                    }
                    for (int i = 0; i < len; i++) {
                        int intBits = Float.floatToIntBits(floatBuffer[i]);
                        // 把float数据塞入ByteBuffer
                        if (inputBuffer != null) {
                            inputBuffer.putFloat(i, floatBuffer[i]);
                        }
                    }
                    //编码48000-32bit的采样数据
                    if (inputBuffer != null) {
                        mediaCodec.queueInputBuffer(inputIndex, 0, len * 4, nanoTime, 0);
                        nanoTime += 25000;//增加25毫秒
                    }
                }
            }
        } catch (Exception e) {
            Log.d(TAG, "record出错:" + e);
        }
另外一个线程:获取编码后的数据,并写入文件
            File outputFile = new File(audioRecordFilePath);
            if (!outputFile.getParentFile().exists()) {
                outputFile.getParentFile().mkdirs();
            }
            FileOutputStream fileOutputStream = new FileOutputStream(outputFile);
            while (isRecording) {
                //获取编码后的数据
                int outputIndex = mediaCodec.dequeueOutputBuffer(bufferInfo, 0);
                while (outputIndex >= 0 && isRecording) {
                    ByteBuffer outputBuffer = mediaCodec.getOutputBuffer(outputIndex);//拿到输出Buffer
                    outputBuffer.position(bufferInfo.offset);
                    byte[] outData = new byte[bufferInfo.size + 7];
                    outputBuffer.get(outData, 7, bufferInfo.size);//将编码得到的AAC数据 取出到byte[]中
                    addADTStoPacket(outData, outData.length);
                    fileOutputStream.write(outData);
                    //再取一遍
                    mediaCodec.releaseOutputBuffer(outputIndex, false);
                    outputIndex = mediaCodec.dequeueOutputBuffer(bufferInfo, 0);
                }
            }
            fileOutputStream.flush();
            fileOutputStream.close();
AAC裸流添加ADTS头
    private static final int AAC_PROFILE = 2;//AAC LC,MediaCodecInfo.CodecProfileLevel.AACObjectLC
    private static final int AAC_CHANNEL_CONFIG = 1;//单声道
    private static final int AAC_FREQ_IDX = 8;//对应的是48000采样率
    private void addADTStoPacket(byte[] packet, int packetLen) {
        packet[0] = (byte) 0xFF;
        packet[1] = (byte) 0xF9;
        packet[2] = (byte) (((AAC_PROFILE - 1) << 6) + (AAC_FREQ_IDX << 2) + (AAC_CHANNEL_CONFIG >> 2));
        packet[3] = (byte) (((AAC_CHANNEL_CONFIG & 3) << 6) + (packetLen >> 11));
        packet[4] = (byte) ((packetLen & 0x7FF) >> 3);
        packet[5] = (byte) (((packetLen & 7) << 5) + 0x1F);
        packet[6] = (byte) 0xFC;
    }
  • 写回答

2条回答 默认 最新

  • 卓凡姓黎 2022-07-01 18:11
    关注

    aac头部信息采样率的下标写错了 代码中AAC_FREQ_IDX 应该是3 对应的是48000采样率,可参考下面连接
    https://wiki.multimedia.cx/index.php/MPEG-4_Audio#Sampling_Frequencies

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论
查看更多回答(1条)

报告相同问题?

问题事件

  • 系统已结题 7月9日
  • 已采纳回答 7月1日
  • 创建了问题 6月30日

悬赏问题

  • ¥15 51单片机使lcd显示器开机闪烁预设字符闪烁3次需要加什么代码
  • ¥50 C# 使用DEVMOD设置打印机首选项
  • ¥15 麒麟V10 arm安装gdal
  • ¥15 想用@vueuse 把项目动态改成深色主题,localStorge里面的vueuse-color-scheme一开始就给我改成了dark,不知道什么原因(相关搜索:背景颜色)
  • ¥20 OPENVPN连接问题
  • ¥15 flask实现搜索框访问数据库
  • ¥15 mrk3399刷完安卓11后投屏调试只能显示一个设备
  • ¥100 如何用js写一个游戏云存档
  • ¥15 ansys fluent计算闪退
  • ¥15 有关wireshark抓包的问题