用ffmpeg解碼AAC音頻流

上一篇寫了視頻流解碼局骤,下面為大家分享解碼AAC音頻流缩擂。
1.首先創(chuàng)建一個文件專門用來解碼,在DDAACDecoder.h文件中對外暴露以下三個方法:


#import <Foundation/Foundation.h>

@interface DDAACDecoder : NSObject

/* 初始化AAC解碼器 */
- (BOOL)initAACDecoderWithSampleRate:(int)sampleRate channel:(int)channel bit:(int)bit ;

/* 解碼AAC音頻 */
- (void)AACDecoderWithMediaData:(NSData *)mediaData sampleRate:(int)sampleRate completion:(void(^)(uint8_t *out_buffer, size_t out_buffer_size))completion;

/* 釋放AAC解碼器 */
- (void)releaseAACDecoder;

@end

2.在.m文件中實現(xiàn)所暴露的方法


#import "DDACDecoder.h"
#import "libavcodec/avcodec.h"
#import "libswscale/swscale.h"
#include <libavformat/avformat.h>
#include "libswresample/swresample.h"

@interface DDAACDecoder ()

@property (assign, nonatomic) AVFrame *aacFrame;
@property (assign, nonatomic) AVCodec *aacCodec;
@property (assign, nonatomic) AVCodecContext *aacCodecCtx;
@property (assign, nonatomic) AVPacket aacPacket;

@end

@implementation DDAACDecoder

/**
 *  初始化音頻解碼器
 *
 *  @param sampleRate 采樣率
 *  @param channel    通道數(shù)
 *  @param bit        位數(shù)
 *
 *  @return YES:解碼成功
 */
- (BOOL)initAACDecoderWithSampleRate:(int)sampleRate channel:(int)channel bit:(int)bit {
    av_register_all();
    avformat_network_init();
    self.aacCodec = avcodec_find_decoder(AV_CODEC_ID_AAC);
    av_init_packet(&_aacPacket);
    
    if (self.aacCodec != nil) {
        self.aacCodecCtx = avcodec_alloc_context3(self.aacCodec);
        
        // 初始化codecCtx
        self.aacCodecCtx->codec_type = AVMEDIA_TYPE_AUDIO;
        self.aacCodecCtx->sample_rate = sampleRate;
        self.aacCodecCtx->channels = channel;
        self.aacCodecCtx->bit_rate = bit;
        self.aacCodecCtx->channel_layout = AV_CH_LAYOUT_STEREO;
        
        self.sampleRate = sampleRate;
        self.channel = channel;
        self.bit = bit;
        
        // 打開codec
        if (avcodec_open2(self.aacCodecCtx, self.aacCodec, NULL) >= 0) {
            self.aacFrame = av_frame_alloc();
            
        }
    }
    return (BOOL)self.aacFrame;
}

/**
 *  音頻解碼
 *
 *  @param mediaData  被解碼音頻數(shù)據(jù)
 *  @param sampleRate 采樣率
 *  @param completion block:返回解碼后的數(shù)據(jù)及長度
 */
- (void)AACDecoderWithMediaData:(NSData *)mediaData sampleRate:(int)sampleRate completion:(void (^)(uint8_t *, size_t))completion {
    _aacPacket.data = (uint8_t *)mediaData.bytes;
    _aacPacket.size = (int)mediaData.length;
    
    if (&_aacPacket) {
        avcodec_send_packet(self.aacCodecCtx, &_aacPacket);
        int result = avcodec_receive_frame(self.aacCodecCtx, self.aacFrame);
        
        if (result == 0) {
            struct SwrContext *au_convert_ctx = swr_alloc();
            au_convert_ctx = swr_alloc_set_opts(au_convert_ctx,
                                                AV_CH_LAYOUT_STEREO, AV_SAMPLE_FMT_S16, sampleRate,
                                                self.aacCodecCtx->channel_layout, self.aacCodecCtx->sample_fmt, self.aacCodecCtx->sample_rate,
                                                0, NULL);
            swr_init(au_convert_ctx);
            
            int out_linesize;
            int out_buffer_size=av_samples_get_buffer_size(&out_linesize, self.aacCodecCtx->channels,self.aacCodecCtx->frame_size,self.aacCodecCtx->sample_fmt, 1);
            uint8_t *out_buffer=(uint8_t *)av_malloc(out_buffer_size);
            swr_convert(au_convert_ctx, &out_buffer, out_linesize, (const uint8_t **)self.aacFrame->data , self.aacFrame->nb_samples);
            
            swr_free(&au_convert_ctx);
            au_convert_ctx = NULL;
            if (completion) {
                completion(out_buffer, out_linesize);
            }
            // 釋放
            av_free(out_buffer);
        }
    }
}

/**
 *  是否音頻解碼器
 */
- (void)releaseAACDecoder {
    if(self.aacCodecCtx) {
        avcodec_close(self.aacCodecCtx);
        avcodec_free_context(&_aacCodecCtx);
        self.aacCodecCtx = NULL;
    }

    if(self.aacFrame) {
        av_frame_free(&_aacFrame);
        self.aacFrame = NULL;
    }
}

@end

注意:使用完后施流,一定要釋放啄骇,要不然會內(nèi)存泄漏霎终。

3.對解碼后的音頻數(shù)據(jù)進行處理喝滞,這里我就不再敘述红竭。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市变隔,隨后出現(xiàn)的幾起案子规伐,更是在濱河造成了極大的恐慌,老刑警劉巖匣缘,帶你破解...
    沈念sama閱讀 216,591評論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件猖闪,死亡現(xiàn)場離奇詭異,居然都是意外死亡肌厨,警方通過查閱死者的電腦和手機培慌,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,448評論 3 392
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來柑爸,“玉大人吵护,你說我怎么就攤上這事”眵ⅲ” “怎么了馅而?”我有些...
    開封第一講書人閱讀 162,823評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長譬圣。 經(jīng)常有香客問我瓮恭,道長,這世上最難降的妖魔是什么厘熟? 我笑而不...
    開封第一講書人閱讀 58,204評論 1 292
  • 正文 為了忘掉前任屯蹦,我火速辦了婚禮,結(jié)果婚禮上盯漂,老公的妹妹穿的比我還像新娘颇玷。我一直安慰自己,他們只是感情好就缆,可當我...
    茶點故事閱讀 67,228評論 6 388
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著谒亦,像睡著了一般竭宰。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上份招,一...
    開封第一講書人閱讀 51,190評論 1 299
  • 那天切揭,我揣著相機與錄音,去河邊找鬼锁摔。 笑死廓旬,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的谐腰。 我是一名探鬼主播孕豹,決...
    沈念sama閱讀 40,078評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼涩盾,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了励背?” 一聲冷哼從身側(cè)響起春霍,我...
    開封第一講書人閱讀 38,923評論 0 274
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎叶眉,沒想到半個月后址儒,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,334評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡衅疙,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,550評論 2 333
  • 正文 我和宋清朗相戀三年莲趣,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片饱溢。...
    茶點故事閱讀 39,727評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡妖爷,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出理朋,到底是詐尸還是另有隱情絮识,我是刑警寧澤,帶...
    沈念sama閱讀 35,428評論 5 343
  • 正文 年R本政府宣布嗽上,位于F島的核電站次舌,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏兽愤。R本人自食惡果不足惜彼念,卻給世界環(huán)境...
    茶點故事閱讀 41,022評論 3 326
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望浅萧。 院中可真熱鬧逐沙,春花似錦、人聲如沸洼畅。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,672評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽帝簇。三九已至徘郭,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間丧肴,已是汗流浹背残揉。 一陣腳步聲響...
    開封第一講書人閱讀 32,826評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留芋浮,地道東北人抱环。 一個月前我還...
    沈念sama閱讀 47,734評論 2 368
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親镇草。 傳聞我的和親對象是個殘疾皇子眶痰,可洞房花燭夜當晚...
    茶點故事閱讀 44,619評論 2 354

推薦閱讀更多精彩內(nèi)容