關(guān)于一些參數(shù)的含義和音頻采集參考:
iOS音頻AudioStreamBasicDescription設(shè)置
iOS 音頻AudioComponentDescription類型設(shè)置
iOS 音頻采集
創(chuàng)建一個(gè)編碼器
- (void)createAudioConvert{
AudioConverterRef m_converter;
//輸入音頻的相關(guān)屬性
AudioStreamBasicDescription inputFormat = {0};
inputFormat.mSampleRate = 44100;
inputFormat.mFormatID = kAudioFormatLinearPCM;
inputFormat.mFormatFlags = kAudioFormatFlagIsSignedInteger | kAudioFormatFlagsNativeEndian | kAudioFormatFlagIsPacked;
inputFormat.mChannelsPerFrame = 2;
inputFormat.mFramesPerPacket = 1;
inputFormat.mBitsPerChannel = 16;
inputFormat.mBytesPerFrame = inputFormat.mBitsPerChannel / 8 * inputFormat.mChannelsPerFrame;
inputFormat.mBytesPerPacket = inputFormat.mBytesPerFrame * inputFormat.mFramesPerPacket;
// 這里開始是輸出音頻格式
AudioStreamBasicDescription outputFormat = {0};
outputFormat.mSampleRate = inputFormat.mSampleRate; // 采樣率保持一致
outputFormat.mFormatID = kAudioFormatMPEG4AAC; // AAC編碼 kAudioFormatMPEG4AAC kAudioFormatMPEG4AAC_HE_V2
outputFormat.mChannelsPerFrame = inputFormat.mChannelsPerFrame;// 聲道數(shù)保持一致
outputFormat.mFramesPerPacket = 1024; // AAC一幀是1024個(gè)字節(jié)
//設(shè)置輸出格式喳瓣,編碼方式
const OSType subtype = kAudioFormatMPEG4AAC;
AudioClassDescription requestedCodecs[2] = {
{
kAudioEncoderComponentType,
subtype,
kAppleSoftwareAudioCodecManufacturer
},
{
kAudioEncoderComponentType,
subtype,
kAppleHardwareAudioCodecManufacturer
}
};
//初始化m_converter
OSStatus result = AudioConverterNewSpecific(&inputFormat, &outputFormat, 2, requestedCodecs, &m_converter);
// AAC并不是隨便的碼率都可以支持畏陕。比如如果PCM采樣率是44100Hz,那么碼率可以設(shè)置64000bps,如果是16000仁讨,可以設(shè)置為32000bps实昨。
UInt32 outputBitrate = 64000;
UInt32 propSize = sizeof(outputBitrate);
if(result == noErr) {
//設(shè)置碼率
result = AudioConverterSetProperty(m_converter, kAudioConverterEncodeBitRate, propSize, &outputBitrate);
}
///到此,我們?nèi)〉昧司幋a器 m_converter
}
開始編碼
接上篇丈挟,采集器采集的數(shù)據(jù),在封裝成NSData之后蛔趴,傳入編碼器進(jìn)行編碼
///開始積累需要編碼的數(shù)據(jù)
- (void)encodeAudioData:(nullable NSData*)audioData timeStamp:(uint64_t)timeStamp{
///當(dāng)待編碼數(shù)據(jù)到達(dá)一定量時(shí)候進(jìn)行編碼
///[self bufferLength] 為了方便理解這么寫例朱,其實(shí)是一個(gè)常量
if(leftLength + audioData.length >= [self bufferLength]){
///發(fā)送數(shù)據(jù)去編碼
NSInteger totalSize = leftLength + audioData.length;
NSInteger encodeCount = totalSize/[self bufferLength];
char *totalBuf = malloc(totalSize);
char *p = totalBuf;
memset(totalBuf, (int)totalSize, 0);
memcpy(totalBuf, leftBuf, leftLength);
memcpy(totalBuf + leftLength, audioData.bytes, audioData.length);
for(NSInteger index = 0;index < encodeCount;index++){
[self encodeBuffer:p timeStamp:timeStamp];
p += [self bufferLength];
}
leftLength = totalSize%[self bufferLength];
memset(leftBuf, 0, [self bufferLength]);
memcpy(leftBuf, totalBuf + (totalSize -leftLength), leftLength);
free(totalBuf);
}else{
///< 積累數(shù)據(jù)
memcpy(leftBuf+leftLength, audioData.bytes, audioData.length);
leftLength = leftLength + audioData.length;
}
}
開始進(jìn)行編碼
//開始編碼
- (void)encodeBuffer:(char*)buf timeStamp:(uint64_t)timeStamp{
AudioBuffer inBuffer;
inBuffer.mNumberChannels = 1;
inBuffer.mData = buf;
inBuffer.mDataByteSize = (UInt32)[self bufferLength];
AudioBufferList buffers;
buffers.mNumberBuffers = 1;
buffers.mBuffers[0] = inBuffer;
// 初始化一個(gè)輸出緩沖列表
AudioBufferList outBufferList;
outBufferList.mNumberBuffers = 1;
outBufferList.mBuffers[0].mNumberChannels = inBuffer.mNumberChannels;
outBufferList.mBuffers[0].mDataByteSize = inBuffer.mDataByteSize; // 設(shè)置緩沖區(qū)大小
outBufferList.mBuffers[0].mData = aacBuf; // 設(shè)置AAC緩沖區(qū)
UInt32 outputDataPacketSize = 1;
if (AudioConverterFillComplexBuffer(m_converter, audioInputDataProc, &buffers, &outputDataPacketSize, &outBufferList, NULL) != noErr) {
return;
}
//編碼后的數(shù)據(jù)
//outBufferList.mBuffers[0].mData
//size
//outBufferList.mBuffers[0].mDataByteSize
//timeStamp
//timeStamp
//轉(zhuǎn)為NSData
//[NSData dataWithBytes:outBufferList.mBuffers[0].mData length:outBufferList.mBuffers[0].mDataByteSize]
//ADTS 頭
//NSData *adts = [self adtsData:2 rawDataLength:outBufferList.mBuffers[0].mDataByteSize];
}
OSStatus audioInputDataProc(AudioConverterRef inConverter, UInt32 *ioNumberDataPackets, AudioBufferList *ioData, AudioStreamPacketDescription * *outDataPacketDescription, void *inUserData) {
//AudioConverterFillComplexBuffer 編碼過程中箫荡,會(huì)要求這個(gè)函數(shù)來填充輸入數(shù)據(jù)渔隶,也就是原始PCM數(shù)據(jù)
AudioBufferList bufferList = *(AudioBufferList *)inUserData;
ioData->mBuffers[0].mNumberChannels = 1;
ioData->mBuffers[0].mData = bufferList.mBuffers[0].mData;
ioData->mBuffers[0].mDataByteSize = bufferList.mBuffers[0].mDataByteSize;
return noErr;
}
另外,獲取到的數(shù)據(jù)默認(rèn)是沒有ADTS頭的绞灼,如果需要添加终吼,調(diào)用以下代碼
- (NSData *)adtsData:(NSInteger)channel rawDataLength:(NSInteger)rawDataLength {
int adtsLength = 7;
char *packet = malloc(sizeof(char) * adtsLength);
// Variables Recycled by addADTStoPacket
int profile = 2; //AAC LC
//39=MediaCodecInfo.CodecProfileLevel.AACObjectELD;
NSInteger freqIdx = [self sampleRateIndex:self.configuration.audioSampleRate]; //44.1KHz
int chanCfg = (int)channel; //MPEG-4 Audio Channel Configuration. 1 Channel front-center
NSUInteger fullLength = adtsLength + rawDataLength;
// fill in ADTS data
packet[0] = (char)0xFF; // 11111111 = syncword
packet[1] = (char)0xF9; // 1111 1 00 1 = syncword MPEG-2 Layer CRC
packet[2] = (char)(((profile-1)<<6) + (freqIdx<<2) +(chanCfg>>2));
packet[3] = (char)(((chanCfg&3)<<6) + (fullLength>>11));
packet[4] = (char)((fullLength&0x7FF) >> 3);
packet[5] = (char)(((fullLength&7)<<5) + 0x1F);
packet[6] = (char)0xFC;
NSData *data = [NSData dataWithBytesNoCopy:packet length:adtsLength freeWhenDone:YES];
return data;
}
- (NSInteger)sampleRateIndex:(NSInteger)frequencyInHz {
NSInteger sampleRateIndex = 0;
switch (frequencyInHz) {
case 96000:
sampleRateIndex = 0;
break;
case 88200:
sampleRateIndex = 1;
break;
case 64000:
sampleRateIndex = 2;
break;
case 48000:
sampleRateIndex = 3;
break;
case 44100:
sampleRateIndex = 4;
break;
case 32000:
sampleRateIndex = 5;
break;
case 24000:
sampleRateIndex = 6;
break;
case 22050:
sampleRateIndex = 7;
break;
case 16000:
sampleRateIndex = 8;
break;
case 12000:
sampleRateIndex = 9;
break;
case 11025:
sampleRateIndex = 10;
break;
case 8000:
sampleRateIndex = 11;
break;
case 7350:
sampleRateIndex = 12;
break;
default:
sampleRateIndex = 15;
}
return sampleRateIndex;
}
其他參數(shù):
{
char *leftBuf;
char *aacBuf;
NSInteger leftLength;
AudioConverterRef m_converter;
}
- (instancetype)init{
if (self = [super init]) {
/*leftBuf aacBuf銷毀的時(shí)候需要釋放 free(leftBuf) free(aacBuf)*/
if (!leftBuf) {
leftBuf = malloc([self bufferLength]);
}
if (!aacBuf) {
aacBuf = malloc([self bufferLength]);
}
leftLength = 0;
}
return self;
}
- (NSUInteger)bufferLength{
/* 1024 * 2 * 聲道數(shù) */
return 1024 * 2 * 2;
}
Demo地址整理后奉上商佛。
有其他不明白的姆打,可以留言,看到就會(huì)回復(fù)玛追。
如果喜歡闲延,請(qǐng)幫忙點(diǎn)贊。支持轉(zhuǎn)載垒玲,轉(zhuǎn)載請(qǐng)附原文鏈接合愈。