当我将 pcm 编码为 aac 文件时,该文件未使用 aac 分析工具正确分析

Posted

技术标签:

【中文标题】当我将 pcm 编码为 aac 文件时,该文件未使用 aac 分析工具正确分析【英文标题】:when i encode pcm to an aac file,the file is not correctly analyzed with aac analysis tool 【发布时间】:2018-01-09 09:06:10 【问题描述】:

当采样率为44100时,可以解码aac字节数组,i 能发出声音,但其他的不能正确解码。我不知道 为什么?

在编码之前,我设置了MediaFormat。csd-0是从其他样本复制的,并且MediaFormat参数将被显示。

private boolean prepare() 
    String codecName = null;
    for (int i = 0; i < MediaCodecList.getCodecCount(); i++) 
        MediaCodecInfo mediaCodecInfo = MediaCodecList.getCodecInfoAt(i);
        for (String type : mediaCodecInfo.getSupportedTypes()) 
            if (TextUtils.equals(type, MIME_TYPE)
                    && mediaCodecInfo.isEncoder()) 
                codecName = mediaCodecInfo.getName();
                break;
            
        
        if (null != codecName) 
            break;
        
    
    try 
        mBufferInfo = new MediaCodec.BufferInfo();
        mEncoder = MediaCodec.createByCodecName(codecName);
        MediaFormat mediaFormat = MediaFormat.createAudioFormat(MIME_TYPE,
                KEY_SAMPLE_RATE, KEY_CHANNEL_COUNT);
        mediaFormat.setString(MediaFormat.KEY_MIME, MediaFormat.MIMETYPE_AUDIO_AAC);
        mediaFormat.setInteger(MediaFormat.KEY_BIT_RATE, KEY_BIT_RATE);
        mediaFormat.setInteger(MediaFormat.KEY_AAC_PROFILE,
                KEY_AAC_PROFILE);
        mediaFormat.setInteger(MediaFormat.KEY_MAX_INPUT_SIZE, mFrameSize);
        byte[] data = new byte[](byte) 0x11, (byte) 0x90;
        ByteBuffer csd_0 = ByteBuffer.wrap(data);
        mediaFormat.setByteBuffer("csd-0", csd_0);
        mEncoder.configure(mediaFormat, null, null,
                MediaCodec.CONFIGURE_FLAG_ENCODE);
        mEncoder.start();
     catch (IOException e) 
        e.printStackTrace();
        return false;
    
    mBuffer = new byte[mFrameSize];
    int minBufferSize = AudioRecord.getMinBufferSize(KEY_SAMPLE_RATE, CHANNEL_IN,
            AUDIO_FORMAT);
    mRecord = new AudioRecord(MediaRecorder.Audiosource.MIC,
            KEY_SAMPLE_RATE, CHANNEL_IN, AUDIO_FORMAT, minBufferSize * 2);
    mRecord.startRecording();
    return true;

使用android MediaCodec api 编码为aac in while.encoderCallback 将被MediaCodec 调用解码。

long presentationTimeUs = 0;
    private void encode(byte[] data) 
        //api > 21
        if (Build.VERSION.SDK_INT > Build.VERSION_CODES.LOLLIPOP) 

            int inputBufferIndex = mEncoder.dequeueInputBuffer(-1);
            if (inputBufferIndex >= 0) 

                ByteBuffer inputBuffer = mEncoder.getInputBuffer(inputBufferIndex);
                inputBuffer.clear();

                inputBuffer.put(data);
                inputBuffer.limit(data.length);

                mEncoder.queueInputBuffer(inputBufferIndex, 0, data.length,
                        computePresentationTime(presentationTimeUs), BUFFER_FLAG_CODEC_CONFIG);
                presentationTimeUs+=1;
            

            int outputBufferIndex = mEncoder.dequeueOutputBuffer(mBufferInfo, 0);

            while (outputBufferIndex >= 0) 

                ByteBuffer outputBuffer = mEncoder.getOutputBuffer(outputBufferIndex);

                outputBuffer.position(mBufferInfo.offset);
                outputBuffer.limit(mBufferInfo.offset + mBufferInfo.size);


                int length = mBufferInfo.size + 7;
                if (mFrameByte == null || mFrameByte.length < length) 
                    mFrameByte = new byte[length];
                
                addADTStoPacket(mFrameByte, length);

                outputBuffer.get(mFrameByte, 7, mBufferInfo.size);

                if (encoderCallback!=null)
                    encoderCallback.encode(mFrameByte);

                    mFrameByte = null;
                
                mEncoder.releaseOutputBuffer(outputBufferIndex, false);
                outputBufferIndex = mEncoder.dequeueOutputBuffer(mBufferInfo, 0);
            
    

添加广告标题。

private void addADTStoPacket(byte[] packet, int packetLen) 
        int profile = KEY_AAC_PROFILE;  //AAC LC
        int freqIdx = FREQ_IDX;  //44.1KHz
        int chanCfg = CHAN_CFG;  //CPE
        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 interface AudioCodec 
    String MIME_TYPE = MediaFormat.MIMETYPE_AUDIO_AAC;
    int KEY_CHANNEL_COUNT = 2;
    int KEY_BIT_RATE = 64 * 1024;
    int KEY_SAMPLE_RATE = 44100;
    int CHANNEL_OUT = AudioFormat.CHANNEL_OUT_STEREO;
    int CHANNEL_IN = AudioFormat.CHANNEL_IN_STEREO;
    int KEY_AAC_PROFILE = MediaCodecInfo.CodecProfileLevel.AACObjectLC;
    int WAIT_TIME = 10000;
    int AUDIO_FORMAT = AudioFormat.ENCODING_PCM_16BIT;
    int BUFFFER_SIZE = 2048;
    int FREQ_IDX = 4;
    int CHAN_CFG = 1;

【问题讨论】:

【参考方案1】:

可能是我的英文不好,所以有人看不懂我的描述。现在,我找到了AAC文件无法播放或播放半速的原因。AAC的csd-0配置决定了是否成功。

我将下面的参数设置为MediaCodec,用于编码和解码。采样率为44100。

int KEY_CHANNEL_COUNT = 2;
int KEY_BIT_RATE = 64*1024;
int KEY_SAMPLE_RATE = 44100;
int CHANNEL_OUT = AudioFormat.CHANNEL_OUT_STEREO;
int CHANNEL_IN = AudioFormat.CHANNEL_IN_STEREO;
int KEY_AAC_PROFILE = MediaCodecInfo.CodecProfileLevel.AACObjectLC;
int WAIT_TIME = 10000;
int AUDIO_FORMAT = AudioFormat.ENCODING_PCM_16BIT;
int BUFFFER_SIZE = 2048;
int FREQ_IDX = 4;
int CHAN_CFG = 2;
byte CSD_0 = 0x12;
byte CSD_1 = (byte) 0x12;

csd-0 被设置为通过 MediaCodec 从 pcm 编码 aac。

byte[] data = new byte[]CSD_0, CSD_1;
ByteBuffer csd_0 = ByteBuffer.wrap(data);
mediaFormat.setByteBuffer("csd-0", csd_0);

csd-0 可以根据您的采样率进行更改。例如,您的采样率是 8000。

int KEY_CHANNEL_COUNT = 1;
int KEY_SAMPLE_RATE = 8000;
int KEY_BIT_RATE = 16000;
int CHANNEL_OUT = AudioFormat.CHANNEL_OUT_STEREO;
int CHANNEL_IN = AudioFormat.CHANNEL_IN_STEREO;
int KEY_AAC_PROFILE = MediaCodecInfo.CodecProfileLevel.AACObjectLC;
int WAIT_TIME = 10000;
int AUDIO_FORMAT = AudioFormat.ENCODING_PCM_16BIT;
int BUFFFER_SIZE = 2048;
int FREQ_IDX = 11;
int CHAN_CFG = 1;
byte CSD_0 = 0x15;
byte CSD_1 = (byte) 0x88;

【讨论】:

以上是关于当我将 pcm 编码为 aac 文件时,该文件未使用 aac 分析工具正确分析的主要内容,如果未能解决你的问题,请参考以下文章

解码aac,并生成wav文件

最简单的基于FFMPEG的音频编码器(PCM编码为AAC)

使用 AudioConverter 将 PCM 转换为 AAC 并使用 AVAssetWriter 写入 .mp4 文件时音频失真

如何使用 FFmpeg (C/C++) 将原始 pcm_f32le 音频编码为 AAC 编码音频?

在 iOS 中实时将 pcm 样本编码为 mp3,可能吗?

Android 音频采集——MediaRecord(编码后录影文件) AudioRecord(PCM原始数据)