美文网首页iOS-开发
用ffmpeg解码AAC音频流

用ffmpeg解码AAC音频流

作者: 温暖C | 来源:发表于2016-09-17 14:57 被阅读4881次

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

    相关文章

      网友评论

        本文标题:用ffmpeg解码AAC音频流

        本文链接:https://www.haomeiwen.com/subject/dxfwettx.html