相親交友原始碼中,音訊AAC解碼的實現程式碼
音訊AAC解碼
在相親交友原始碼中,為了提升音訊資料的傳輸效率,我們需要對音訊資料進行編碼處理,但是編碼後的音訊檔案是無法直接播放的,需要進行解碼處理,今天我們就來看一下在相親交友原始碼開發中,實現音訊AAC解碼的相關程式碼。
在解碼時 ?? 我們需要封裝一個工具類CCAudioDecoder。
解碼工具類標頭檔案
#import <Foundation/Foundation.h> #import <AVFoundation/AVFoundation.h> @class CCAudioConfig; /**AAC解碼回撥代理*/ @protocol CCAudioDecoderDelegate <NSObject> - (void)audioDecodeCallback:(NSData *)pcmData; @end @interface CCAudioDecoder : NSObject @property (nonatomic, strong) CCAudioConfig *config; @property (nonatomic, weak) id<CCAudioDecoderDelegate> delegate; //初始化 傳入解碼配置 - (instancetype)initWithConfig:(CCAudioConfig *)config; /**解碼aac*/ - (void)decodeAudioAACData: (NSData *)aacData; @end
.m中的擴充套件類??
@interface CCAudioDecoder() @property (nonatomic, strong) dispatch_queue_t decoderQueue; @property (nonatomic, strong) dispatch_queue_t callbackQueue; //對音訊轉換器物件 @property (nonatomic) AudioConverterRef audioConverter; //AAC快取區 @property (nonatomic) char *aacBuffer; //AAC快取區大小 @property (nonatomic) UInt32 aacBufferSize; //音訊流包的描述資訊 @property (nonatomic) AudioStreamPacketDescription *packetDesc; @end
初始化
接著看看初始化??
- (instancetype)initWithConfig:(CCAudioConfig *)config { self = [super init]; if (self) { _decoderQueue = dispatch_queue_create("aac hard decoder queue", DISPATCH_QUEUE_SERIAL); _callbackQueue = dispatch_queue_create("aac hard decoder callback queue", DISPATCH_QUEUE_SERIAL); _audioConverter = NULL; _aacBufferSize = 0; _aacBuffer = NULL; _config = config; if (_config == nil) { _config = [[CCAudioConfig alloc] init]; } AudioStreamPacketDescription desc = {0}; _packetDesc = &desc; [self setupEncoder]; } return self; }
然後是setupEncoder??
- (void)setupEncoder { //輸出引數pcm AudioStreamBasicDescription outputAudioDes = {0}; outputAudioDes.mSampleRate = (Float64)_config.sampleRate; //取樣率 outputAudioDes.mChannelsPerFrame = (UInt32)_config.channelCount; //輸出聲道數(左聲道、右聲道) outputAudioDes.mFormatID = kAudioFormatLinearPCM; //輸出格式 outputAudioDes.mFormatFlags = (kAudioFormatFlagIsSignedInteger | kAudioFormatFlagIsPacked); //編碼 12 outputAudioDes.mFramesPerPacket = 1; //每一個packet幀數 ; outputAudioDes.mBitsPerChannel = 16; //資料幀中每個通道的取樣位數。 outputAudioDes.mBytesPerFrame = outputAudioDes.mBitsPerChannel / 8 *outputAudioDes.mChannelsPerFrame; //每一幀大小(取樣位數 / 8 *聲道數) outputAudioDes.mBytesPerPacket = outputAudioDes.mBytesPerFrame * outputAudioDes.mFramesPerPacket; //每個packet大小(幀大小 * 幀數) outputAudioDes.mReserved = 0; //對其方式 0(8位元組對齊) //輸入引數aac AudioStreamBasicDescription inputAduioDes = {0}; inputAduioDes.mSampleRate = (Float64)_config.sampleRate; inputAduioDes.mFormatID = kAudioFormatMPEG4AAC; inputAduioDes.mFormatFlags = kMPEG4Object_AAC_LC; inputAduioDes.mFramesPerPacket = 1024; inputAduioDes.mChannelsPerFrame = (UInt32)_config.channelCount; //填充輸出相關資訊 UInt32 inDesSize = sizeof(inputAduioDes); AudioFormatGetProperty(kAudioFormatProperty_FormatInfo, 0, NULL, &inDesSize, &inputAduioDes); //獲取解碼器的描述資訊(只能傳入software) AudioClassDescription *audioClassDesc = [self getAudioCalssDescriptionWithType:outputAudioDes.mFormatID fromManufacture:kAppleSoftwareAudioCodecManufacturer]; //建立converter OSStatus status = AudioConverterNewSpecific(&inputAduioDes, &outputAudioDes, 1, audioClassDesc, &_audioConverter); if (status != noErr) { NSLog(@"Error!:硬解碼AAC建立失敗, status= %d", (int)status); return; } }
和編碼的- (void)setupEncoderWithSampleBuffer: (CMSampleBufferRef)sampleBuffer流程基本上一模一樣。區別在於相親交友原始碼建立解碼器的方法getAudioCalssDescriptionWithType:fromManufacture:??
- (AudioClassDescription *)getAudioCalssDescriptionWithType:(AudioFormatID)type fromManufacture:(uint32_t)manufacture { static AudioClassDescription desc; UInt32 decoderSpecific = type; //獲取滿足AAC解碼器的總大小 UInt32 size; OSStatus status = AudioFormatGetPropertyInfo(kAudioFormatProperty_Decoders, sizeof(decoderSpecific), &decoderSpecific, &size); if (status != noErr) { NSLog(@"Error!:硬解碼AAC get info 失敗, status= %d", (int)status); return nil; } //計算aac解碼器的個數 unsigned int count = size / sizeof(AudioClassDescription); //建立一個包含count個解碼器的陣列 AudioClassDescription description[count]; //將滿足aac解碼的解碼器的資訊寫入陣列 status = AudioFormatGetProperty(kAudioFormatProperty_Encoders, sizeof(decoderSpecific), &decoderSpecific, &size, &description); if (status != noErr) { NSLog(@"Error!:硬解碼AAC get propery 失敗, status= %d", (int)status); return nil; } for (unsigned int i = 0; i < count; i++) { if (type == description[i].mSubType && manufacture == description[i].mManufacturer) { desc = description[i]; return &desc; } }
有以下幾點區別??
-
輸出引數不同:編碼是AAC 解碼是PCM
-
轉換器不同,編碼是kAudioFormatProperty_Encoders,解碼是kAudioFormatProperty_Decoders
相親交友原始碼音訊解碼前的準備
我們封裝了個結構體CCAudioUserData,用於記錄aac的資訊 作為解碼回撥函式的引數??
typedef struct { char * data; UInt32 size; UInt32 channelCount; AudioStreamPacketDescription packetDesc; } CCAudioUserData;
解碼
接著就是相親交友原始碼中的音訊解碼流程了??
- (void)decodeAudioAACData:(NSData *)aacData { if (!_audioConverter) { return; } dispatch_async(_decoderQueue, ^{ //CCAudioUserData記錄aac的資訊 作為引數參入解碼回撥函式 CCAudioUserData userData = {0}; userData.channelCount = (UInt32)_config.channelCount; userData.data = (char *)[aacData bytes]; userData.size = (UInt32)aacData.length; userData.packetDesc.mDataByteSize = (UInt32)aacData.length; userData.packetDesc.mStartOffset = 0; userData.packetDesc.mVariableFramesInPacket = 0; //輸出大小和packet個數 UInt32 pcmBufferSize = (UInt32)(2048 * _config.channelCount); UInt32 pcmDataPacketSize = 1024; //建立臨時容器pcm uint8_t *pcmBuffer = malloc(pcmBufferSize); memset(pcmBuffer, 0, pcmBufferSize); //輸出buffer AudioBufferList outAudioBufferList = {0}; outAudioBufferList.mNumberBuffers = 1; outAudioBufferList.mBuffers[0].mNumberChannels = (uint32_t)_config.channelCount; outAudioBufferList.mBuffers[0].mDataByteSize = (UInt32)pcmBufferSize; outAudioBufferList.mBuffers[0].mData = pcmBuffer; //輸出描述 AudioStreamPacketDescription outputPacketDesc = {0}; //配置填充函式,獲取輸出資料 OSStatus status = AudioConverterFillComplexBuffer(_audioConverter, &AudioDecoderConverterComplexInputDataProc, &userData, &pcmDataPacketSize, &outAudioBufferList, &outputPacketDesc); if (status != noErr) { NSLog(@"Error: AAC Decoder error, status=%d",(int)status); return; } //如果獲取到資料 if (outAudioBufferList.mBuffers[0].mDataByteSize > 0) { NSData *rawData = [NSData dataWithBytes:outAudioBufferList.mBuffers[0].mData length:outAudioBufferList.mBuffers[0].mDataByteSize]; dispatch_async(_callbackQueue, ^{ [_delegate audioDecodeCallback:rawData]; }); } free(pcmBuffer); }); }
其中解碼的回撥函式是AudioDecoderConverterComplexInputDataProc。
解碼回撥
static OSStatus AudioDecoderConverterComplexInputDataProc( AudioConverterRef inAudioConverter, UInt32 *ioNumberDataPackets, AudioBufferList *ioData, AudioStreamPacketDescription **outDataPacketDescription, void *inUserData) { CCAudioUserData *audioDecoder = (CCAudioUserData *)(inUserData); if (audioDecoder->size <= 0) { ioNumberDataPackets = 0; return -1; } //填充資料 *outDataPacketDescription = &audioDecoder->packetDesc; (*outDataPacketDescription)[0].mStartOffset = 0; (*outDataPacketDescription)[0].mDataByteSize = audioDecoder->size; (*outDataPacketDescription)[0].mVariableFramesInPacket = 0; ioData->mBuffers[0].mData = audioDecoder->data; ioData->mBuffers[0].mDataByteSize = audioDecoder->size; ioData->mBuffers[0].mNumberChannels = audioDecoder->channelCount; return noErr; }
在相親交友原始碼實現音訊解碼的過程中你會發現,不需要橋接self物件,因為我們把資料快取在自定義的結構體CCAudioUserData之中。這點也是和編碼的區別。
至此,解碼的工具類已封裝完畢!
本文轉載自網路,轉載僅為分享乾貨知識,如有侵權歡迎聯絡雲豹科技進行刪除處理
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/69996194/viewspace-2842260/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- 相親交友原始碼中語音連麥的實現方式,值得一看原始碼
- 在相親交友原始碼中實現視訊連麥直播需要哪些步驟?原始碼
- 相親交友原始碼中的事件循壞,你瞭解多少?原始碼事件
- 相親交友原始碼開發,前端如何實現水印功能?原始碼前端
- 如何在相親交友原始碼中實現正方形驗證碼輸入框?原始碼
- 如何實現相親交友原始碼的CPU效能優化?解決方案梳理原始碼優化
- 相親交友原始碼實現程式內快取,提升高併發能力!原始碼快取
- 相親交友原始碼實現相親直播間,移動終端的優化方案原始碼優化
- 在相親原始碼的多人音視訊聊天中插入現場直播的實現方式原始碼
- 開發相親交友原始碼,需要熟練掌握的音視訊基礎知識原始碼
- 相親交友原始碼開發中,Redis的三種限流方式原始碼Redis
- 搭建相親交友原始碼 ,API 介面統一格式返回的實現原始碼API
- ffmpeg音訊編碼之pcm轉碼aac音訊
- Android音視訊(四)MediaCodec編解碼AACAndroid
- 相親交友原始碼開發,前端API如何請求快取?原始碼前端API快取
- 相親交友原始碼前端效能優化,通常使用哪些手段?原始碼前端優化
- 陪玩系統原始碼實現音訊編碼的相關步驟原始碼音訊
- 相親交友原始碼開發中會用到的幾種日期處理方法原始碼
- 相親交友原始碼的架構設計,實現合成複用原則需要如何做?原始碼架構
- 如何解決相親交友原始碼中Redis快取擊穿、雪崩問題?原始碼Redis快取
- 相親交友原始碼第三方登入的實現及易擴充套件的達成原始碼套件
- 直播原始碼和短視訊原始碼,相親相愛的一家人原始碼
- 相親原始碼中移動支付的實現,沒有想象中那麼難原始碼
- 一對一交友原始碼,仿抖音短視訊原始碼,搭建的祕密你瞭解多少?原始碼
- 相親原始碼開發,從程式碼級別減少資料請求次數的實現原始碼
- 一文解讀伊對相親交友app原始碼功能特色、應用場景APP原始碼
- 相親交友原始碼開發,演算法的定義及複雜度分析原始碼演算法複雜度
- 交友原始碼中即時通訊怎麼工作的?原始碼
- 10種相親交友原始碼客戶端儲存方式,各有優缺點原始碼客戶端
- 編寫相親交友原始碼,註釋方面應該重視哪些問題?原始碼
- 相親交友原始碼開發,關於分散式快取應該瞭解的一些事原始碼分散式快取
- 在相親原始碼開發中,如何實現圓角及特殊圓角的使用?原始碼
- 2022直播交友原始碼一對多直播系統原始碼同城視訊聊天交友app原始碼APP
- 一對一交友原始碼+直播原始碼+短視訊原始碼,誰才是流量之王?原始碼
- Axios 原始碼解讀 —— 原始碼實現篇iOS原始碼
- 【秒懂音視訊開發】14_AAC編碼
- 有視訊APP上線,一對一交友原始碼和抖音短視訊原始碼穩步前行APP原始碼
- 實現手機直播原始碼中兩個執行緒依次執行的相關程式碼原始碼執行緒