上一篇寫了視頻流解碼局骤,下面為大家分享解碼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ù)進行處理喝滞,這里我就不再敘述红竭。