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