在iOS上将PCM(CMSampleBufferRef)编码为AAC-如何设置频率和比特率?

在iOS上将PCM(CMSampleBufferRef)编码为AAC-如何设置频率和比特率?,ios,audio,core-audio,aac,audiotoolbox,Ios,Audio,Core Audio,Aac,Audiotoolbox,我想将PCM(CMSampleBufferRef(s)从AVCaptureAudioDataOutputSampleBufferDelegate)编码到AAC中 当第一个CMSampleBufferRef到达时,我根据文档设置了两个(输入/输出)AudioStreamBasicDescription,“输出” AudioStreamBasicDescription inAudioStreamBasicDescription = *CMAudioFormatDescriptionGetStream

我想将PCM(
CMSampleBufferRef
(s)从
AVCaptureAudioDataOutputSampleBufferDelegate
)编码到AAC中

当第一个
CMSampleBufferRef
到达时,我根据文档设置了两个(输入/输出)
AudioStreamBasicDescription
,“输出”

AudioStreamBasicDescription inAudioStreamBasicDescription = *CMAudioFormatDescriptionGetStreamBasicDescription((CMAudioFormatDescriptionRef)CMSampleBufferGetFormatDescription(sampleBuffer));

AudioStreamBasicDescription outAudioStreamBasicDescription = {0}; // Always initialize the fields of a new audio stream basic description structure to zero, as shown here: ...
outAudioStreamBasicDescription.mSampleRate = 44100; // The number of frames per second of the data in the stream, when the stream is played at normal speed. For compressed formats, this field indicates the number of frames per second of equivalent decompressed data. The mSampleRate field must be nonzero, except when this structure is used in a listing of supported formats (see “kAudioStreamAnyRate”).
outAudioStreamBasicDescription.mFormatID = kAudioFormatMPEG4AAC; // kAudioFormatMPEG4AAC_HE does not work. Can't find `AudioClassDescription`. `mFormatFlags` is set to 0.
outAudioStreamBasicDescription.mFormatFlags = kMPEG4Object_AAC_SSR; // Format-specific flags to specify details of the format. Set to 0 to indicate no format flags. See “Audio Data Format Identifiers” for the flags that apply to each format.
outAudioStreamBasicDescription.mBytesPerPacket = 0; // The number of bytes in a packet of audio data. To indicate variable packet size, set this field to 0. For a format that uses variable packet size, specify the size of each packet using an AudioStreamPacketDescription structure.
outAudioStreamBasicDescription.mFramesPerPacket = 1024; // The number of frames in a packet of audio data. For uncompressed audio, the value is 1. For variable bit-rate formats, the value is a larger fixed number, such as 1024 for AAC. For formats with a variable number of frames per packet, such as Ogg Vorbis, set this field to 0.
outAudioStreamBasicDescription.mBytesPerFrame = 0; // The number of bytes from the start of one frame to the start of the next frame in an audio buffer. Set this field to 0 for compressed formats. ...
outAudioStreamBasicDescription.mChannelsPerFrame = 1; // The number of channels in each frame of audio data. This value must be nonzero.
outAudioStreamBasicDescription.mBitsPerChannel = 0; // ... Set this field to 0 for compressed formats.
outAudioStreamBasicDescription.mReserved = 0; // Pads the structure out to force an even 8-byte alignment. Must be set to 0.
音频转换器ref

AudioClassDescription audioClassDescription;
memset(&audioClassDescription, 0, sizeof(audioClassDescription));
UInt32 size;
NSAssert(AudioFormatGetPropertyInfo(kAudioFormatProperty_Encoders, sizeof(outAudioStreamBasicDescription.mFormatID), &outAudioStreamBasicDescription.mFormatID, &size) == noErr, nil);
uint32_t count = size / sizeof(AudioClassDescription);
AudioClassDescription descriptions[count];
NSAssert(AudioFormatGetProperty(kAudioFormatProperty_Encoders, sizeof(outAudioStreamBasicDescription.mFormatID), &outAudioStreamBasicDescription.mFormatID, &size, descriptions) == noErr, nil);
for (uint32_t i = 0; i < count; i++) {

    if ((outAudioStreamBasicDescription.mFormatID == descriptions[i].mSubType) && (kAppleSoftwareAudioCodecManufacturer == descriptions[i].mManufacturer)) {

        memcpy(&audioClassDescription, &descriptions[i], sizeof(audioClassDescription));

    }
}
NSAssert(audioClassDescription.mSubType == outAudioStreamBasicDescription.mFormatID && audioClassDescription.mManufacturer == kAppleSoftwareAudioCodecManufacturer, nil);
AudioConverterRef audioConverter;
memset(&audioConverter, 0, sizeof(audioConverter));
NSAssert(AudioConverterNewSpecific(&inAudioStreamBasicDescription, &outAudioStreamBasicDescription, 1, &audioClassDescription, &audioConverter) == 0, nil);
inInputDataProc()
实现:

OSStatus inInputDataProc(AudioConverterRef inAudioConverter, UInt32 *ioNumberDataPackets, AudioBufferList *ioData, AudioStreamPacketDescription **outDataPacketDescription, void *inUserData)
{
    AudioBufferList audioBufferList = *(AudioBufferList *)inUserData;

    ioData->mBuffers[0].mData = audioBufferList.mBuffers[0].mData;
    ioData->mBuffers[0].mDataByteSize = audioBufferList.mBuffers[0].mDataByteSize;

    return  noErr;
}
现在,
数据
保存了我的原始AAC,我用适当的ADTS头将其包装到ADTS帧中,这些ADTS帧的序列是可播放的AAC文档

但是我没有像我想的那样理解这个代码。一般来说,我听不懂音频。。。我只是在博客、论坛和文档之后写的,用了很长时间,现在它可以工作了,但我不知道为什么以及如何更改一些参数。下面是我的问题:

  • 我需要在HW编码器被占用期间使用此转换器(被
    AVAssetWriter
    )。这就是为什么我通过
    AudioConverterNewSpecific()
    而不是
    AudioConverterNew()
    制作SW转换器的原因。但是现在设置
    outAudioStreamBasicDescription.mFormatID=kaudioformampeg4aac_HE不起作用。找不到
    AudioClassDescription
    。即使
    mFormatFlags
    设置为0。使用
    kaudioformampeg4aac
    kMPEG4Object\u AAC\u SSR
    )而不是
    kaudioformampeg4aac\u HE
    ),我失去了什么?我应该使用什么进行直播<代码>kMPEG4Object\u AAC\u SSR
    kMPEG4Object\u AAC\u Main

  • 如何正确改变采样率?例如,如果我将
    outAudioStreamBasicDescription.mSampleRate
    设置为22050或8000,则音频播放速度会减慢。我在ADTS标题中为与
    outAudioStreamBasicDescription.mSampleRate
    相同的频率设置采样频率索引

  • 如何改变比特率?ffmpeg-i显示了生产的aac的以下信息:
    Stream#0:0:音频:aac,44100Hz,单声道,fltp,64kb/s
    。 例如,如何将其更改为16 kbps?比特率随着频率的降低而降低,但我相信这不是唯一的方法?正如我在第2章中提到的,降低频率会破坏播放效果

  • 如何计算缓冲区的大小?现在我将其设置为
    uint32\u t bufferSize=inAaudioBufferList.mBuffers[0].mDataByteSize
  • 如何正确设置
    ioOutputDataPacketSize
    ?如果我没有弄错文档,我应该将其设置为
    UInt32 ioOutputDataPacketSize=bufferSize/outAudioStreamBasicDescription.mBytesPerPacket
    mBytesPerPacket
    为0。如果我将其设置为0,
    AudioConverterFillComplexBuffer()
    返回错误。如果我把它设为1,它会工作,但我不知道为什么

  • inInputDataProc()
    中有3个“out”参数。我只设置了
    ioData
    。是否还应设置
    ioNumberDataPackets
    outDataPacketDescription
    ?为什么和如何


  • 在将音频输入AAC转换器之前,您可能需要使用重新采样音频单元来更改原始音频数据的采样率。否则,AAC头和音频数据之间将不匹配。

    编码器不重新采样率吗?即使输出ASBD采样率与输入不同?如果没有,如何在编码前重新采样?user500,您知道如何正确设置比特率了吗?你能对我的问题发表意见吗。谢谢对不起,我没有。
    OSStatus inInputDataProc(AudioConverterRef inAudioConverter, UInt32 *ioNumberDataPackets, AudioBufferList *ioData, AudioStreamPacketDescription **outDataPacketDescription, void *inUserData)
    {
        AudioBufferList audioBufferList = *(AudioBufferList *)inUserData;
    
        ioData->mBuffers[0].mData = audioBufferList.mBuffers[0].mData;
        ioData->mBuffers[0].mDataByteSize = audioBufferList.mBuffers[0].mDataByteSize;
    
        return  noErr;
    }