用ffmpeg解码AAC音频流

上一篇写了视频流解码,下面为大家分享解码AAC音频流。
1.首先创建一个文件专门用来解码,在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文件中实现所暴露的方法


#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    通道数
 *  @param bit        位数
 *
 *  @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  被解码音频数据
 *  @param sampleRate 采样率
 *  @param completion block:返回解码后的数据及长度
 */
- (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

注意:使用完后,一定要释放,要不然会内存泄漏。

3.对解码后的音频数据进行处理,这里我就不再叙述。

推荐阅读更多精彩内容