上一篇写了视频流解码,下面为大家分享解码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.对解码后的音频数据进行处理,这里我就不再叙述。
网友评论