美文网首页
IOS下 SBC音频解码

IOS下 SBC音频解码

作者: copy_farmer | 来源:发表于2021-01-22 13:54 被阅读0次

    SBC介绍

    1.SBC一般bai的音频格式,蓝牙传输在不支持AAC,aptx的时候都用SBC传输,音质一般,现在80%都是这种格式

    代码部分(用FFmpeg)

    1.头文件

    #import <Foundation/Foundation.h>
    
    NS_ASSUME_NONNULL_BEGIN
    
    @interface SBCStreamDecoder : NSObject
    
    @property (nonatomic,copy) void(^onRecvPCMData)(NSData *pcmData);
    
    
    +(id)sharedInstance;
    
    
    -(void)initSBCDecodec;
    -(void)decodeSBCData:(NSData*)data;
    /* 释放SBC解码器 */
    - (void)finishSBCDecode;
    
    
    @end
    
    

    1.m文件

    #import "SBCStreamDecoder.h"
    
    
    #import <VideoToolbox/VideoToolbox.h>
    
    
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    
    #include <libavutil/frame.h>
    #include <libavutil/mem.h>
    
    #include <libavcodec/avcodec.h>
    
    
    
    
    
    @interface SBCStreamDecoder (){
        AVCodecContext *codecContext;
        AVCodecParserContext *parserContext;
        AVFrame *decodecAVFrame;
        AVPacket *decodecAVPacket;
    }
    @property (assign, nonatomic) AVFrame *sbcFrame;
    @property (assign, nonatomic) AVCodec *sbcCodec;
    @property (assign, nonatomic) AVCodecContext *sbcCodecCtx;
    @property (assign, nonatomic) AVPacket  *sbcPacket;
    @property (assign, nonatomic)AVCodecParserContext *sbcParser;
    @end
    @implementation SBCStreamDecoder
    
    static SBCStreamDecoder *sbcStreamDecoder = nil;
    static dispatch_once_t onceToken;
    +(id)sharedInstance
    {
        dispatch_once(&onceToken, ^{
            sbcStreamDecoder = [[self alloc] init];
        });
        return sbcStreamDecoder;
    }
    
    //获取format
    -(int)get_format_from_sample_fmt:(const char **)fmt sampleFormat:(enum AVSampleFormat)sample_fmt{
        int i;
        struct sample_fmt_entry {
            enum AVSampleFormat sample_fmt; const char *fmt_be, *fmt_le;
        } sample_fmt_entries[] = {
            { AV_SAMPLE_FMT_U8P,  "u8p",    "u8p"    },
            { AV_SAMPLE_FMT_S16P,  "s16p",    "s16p"    },
            { AV_SAMPLE_FMT_S32P,  "s32p",    "s32p"    },
            { AV_SAMPLE_FMT_FLTP,  "fltp",    "fltp"    },
            { AV_SAMPLE_FMT_DBLP,  "u8",    "u8"    },
            { AV_SAMPLE_FMT_S64,  "s64",    "s64"    },
            { AV_SAMPLE_FMT_S64P,  "dblp",    "dblp"    },
            { AV_SAMPLE_FMT_NB,  "nb",    "nb"    },
            { AV_SAMPLE_FMT_U8,  "u8",    "u8"    },
            { AV_SAMPLE_FMT_S16, "s16be", "s16le" },
            { AV_SAMPLE_FMT_S32, "s32be", "s32le" },
            { AV_SAMPLE_FMT_FLT, "f32be", "f32le" },
            { AV_SAMPLE_FMT_DBL, "f64be", "f64le" },
        };
        *fmt = NULL;
        for (i = 0; i < FF_ARRAY_ELEMS(sample_fmt_entries); i++) {
            struct sample_fmt_entry *entry = &sample_fmt_entries[i];
            if (sample_fmt == entry->sample_fmt) {
                *fmt = AV_NE(entry->fmt_be, entry->fmt_le);
                NSLog(@"sample format %s \n",
                      av_get_sample_fmt_name(sample_fmt));
                return 0;
            }
        }
        NSLog(@"sample format %s is not supported as output format\n",
              av_get_sample_fmt_name(sample_fmt));
        return -1;
    }
    
    
    -(NSData*)decodeAudioData:(AVCodecContext *)dec_ctx pkt:(AVPacket *)pkt frame:(AVFrame*)frame {
        
        NSMutableData  *resultData = [[NSMutableData alloc]init];
        
        int i, ch;
        int ret, data_size;
        
        /* send the packet with the compressed data to the decoder */
        ret = avcodec_send_packet(dec_ctx, pkt);
        if (ret < 0) {
            NSLog(@"Error submitting the packet to the decoder\n");
            
        }
        
        /* read all the output frames (in general there may be any number of them */
        while (ret >= 0) {
            ret = avcodec_receive_frame(dec_ctx, frame);
            if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF){
                NSLog (@"AVERROR \n");
                return  resultData;
            }else if (ret < 0) {
                NSLog (@"Error during decoding\n");
                return  resultData;
            }
            data_size = av_get_bytes_per_sample(dec_ctx->sample_fmt);
            NSLog(@"采样位数 %d", data_size);
            
            if (data_size < 0) {
                /* This should not occur, checking just for paranoia */
                NSLog (@"Failed to calculate data size\n");
                return  resultData;
            }
            NSLog(@"frame->nb_samples %d", frame->nb_samples);
            for (i = 0; i < frame->nb_samples; i++){
                for (ch = 0; ch < dec_ctx->channels; ch++){
                    /*写入到输出文件中*/
                    uint8_t *copyByte = malloc(data_size);
                    memcpy(copyByte, frame->data[ch] + data_size*i, data_size);
                    [resultData appendData: [NSData dataWithBytes:copyByte length:data_size]];
                    free(copyByte);
                }
            }
            //               fwrite(frame->data[ch] + data_size*i, 1, data_size,outputFile);
        }
        NSLog (@"decode finish\n");
        
        return resultData;
    }
    
    
    -(void)initSBCDecodec{
        const AVCodec *codec;
        
        
        //初始化av_packet 结构体
        decodecAVPacket = av_packet_alloc();
        
        /* 查找支持解码器 */
        codec = avcodec_find_decoder(AV_CODEC_ID_SBC);
        if (!codec) {
            NSLog(@"Codec not found\n");
            return;
            
        }
        /* 初始化解析器 */
        parserContext = av_parser_init(codec->id);
        if (!parserContext) {
            NSLog(@"Parser not found\n");
            return;
        }
        /* 初始化内容结构体 */
        codecContext = avcodec_alloc_context3(codec);
        if (!codecContext) {
            NSLog(@"Could not allocate audio codec context\n");
            return;
        }
        
        /* 打开解码器 */
        if (avcodec_open2(codecContext, codec, NULL) < 0) {
            NSLog(@"Could not open codec\n");
            return;
        }
        
    }
    
    -(void)decodeSBCData:(NSData*)data{
        int  ret;
        if (!decodecAVFrame) {
            if (!(decodecAVFrame = av_frame_alloc())) {
                NSLog(@"Could not allocate audio frame\n");
                return;
            }
        }
        int  length = (int)data.length;
        while (length>0) {
            /* 开始解析文件 */
            uint8_t *decodData = (Byte*)[data bytes];
            ret = av_parser_parse2(parserContext, codecContext, &decodecAVPacket->data, &decodecAVPacket->size,
                                   decodData, length,
                                   AV_NOPTS_VALUE, AV_NOPTS_VALUE, 0);
            if (ret < 0) {
                NSLog(@"Error while parsing\n");
                return;
            }
            /* 解析成功 开始解码 */
            if (decodecAVPacket->size){
                NSData *pcmData = [self decodeAudioData:codecContext pkt:decodecAVPacket frame:decodecAVFrame];
                if(pcmData.length!=0){
               
                    if(self.onRecvPCMData){
                        self.onRecvPCMData(pcmData);
                        
                    }
                }
            }
            data = [data subdataWithRange:NSMakeRange(ret, length-ret)];
            length -= ret;
        }
        /* 解码完成释放解码器 */
        decodecAVPacket->data = NULL;
        decodecAVPacket->size = 0;
        
    }
    
    -(void)finishSBCDecode{
        avcodec_free_context(&codecContext);
        av_parser_close(parserContext);
        av_frame_free(&decodecAVFrame);
        av_packet_free(&decodecAVPacket);
    }
    
    
    
    
    @end
    

    相关文章

      网友评论

          本文标题:IOS下 SBC音频解码

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