SBC音频编解码算法(转载)

AI权益加码!Claude Code、Cursor等20+工具免费用! 购周边限时加赠Coding Plan Lite,畅享主流AI工具!学习进阶更高效! 阅读详情

转自:https://blog.csdn.net/wzz4420381/article/details/48676921

原作者:wzz4420381

1. SBC算法简介

  • SBC是sub band code的缩写,也可称为子带编码
  • 在A2DP协议中,SBC算法是默认支持的
  • 蓝牙SBC算法是一种以中等比特率传递高质量音频数据的低计算复杂度的音频编码算法

1.1 算法基本框图

  • SBC系统使用一个余弦调制的滤波器组,用来解析和同步。滤波器组可设定成4或8个子带
  • 子带信号的量化采用比特分配器和自适应脉冲编码器组调制
  • 可用的比特位数和编码器的块数都是可配置的
  • 编码后的数据由比特流打包器打包,以有线或无线方式传输
  • 解码是编码的逆过程
    这里写图片描述

1.1 算法所用参数

  • sampling_frequency:采样频率。常用的是16KHz,32KHz,44.1KHz和48KHz
  • channel mode:通道模式。可以是单声道,双声道,立体声和联合立体声
  • block length:块长度。可以是4,8,12,16
  • subbands:子带数量。可以是4或8
  • allocation method:分配方式。可以是SNR或loudness
  • bitpool:比特池。范围是2-250。此值越大,编码产生的数据越长

2 SBC算法实现

2.1 SBC编码算法实现

这里写图片描述

  • PCM格式的左右声道进入多相解析器,输出尺度因子和子带采样数据
  • 每个尺度因子分别对应一个子带
  • 量化后的子带采样数据需要进行打包,打包方式可以是分段或不分段
    这里写图片描述
  • 多相解析器的代码实现较为复杂,流程图如下[具体请看参考文献2的Appendix B]:
    这里写图片描述

2.2 SBC解码算法实现

这里写图片描述

  • 解码过程是编码过程的逆
  • 多相综合器的代码实现较为复杂,流程图如下[具体请看参考文献2的Appendix B]:
    这里写图片描述

3 SBC解码算法在某蓝牙主设备上的应用

3.1 帧格式

这里写图片描述

3.2 参数选择

  • sampling frequency:16
  • channel mode:单声道
  • number of subbands:8
  • number of channels:1
  • number of blocks:15
  • allocation method:SNR
  • bitpool:26

3.3 代码示例

 
  1. void SBC_Decode(uint8_t * DataIn, FILE * fOutput)

  2. {

  3. #define SBC_SAMPLING_FREQ 16

  4. #define SBC_CHANNEL_MODE 0

  5. #define SBC_NUM_OF_SUBBANDS 8

  6. #define SBC_NUM_OF_CHANNELS 1

  7. #define SBC_NUM_OF_BLOCKS 15

  8. #define SBC_ALLOC_METHOD 0

  9. #define SBC_BITPOOL 26

  10. #define SBC_DECODED_BUFFER_SIZE (16*8)

  11. uint8_t blocks_per_packet = SBC_NUM_OF_BLOCKS;

  12. uint8_t num_bits = SBC_BITPOOL;

  13. const uint8_t * buf = (DataIn+1);//ignore CRC byte

  14. uint16_t len = SBC_GROUP_SIZE;

  15. uint16_t usDecodedBuffer[SBC_DECODED_BUFFER_SIZE];

  16. /* convenience */

  17. const uint8_t * end = buf + len;

  18. #define left (end - buf)

  19. uint16_t * outBufPtr = usDecodedBuffer;

  20. /* workspace */

  21. static INSAMPLE samples[16][8]; /* We blow the stack if this is not static. */

  22. ITER i, j, k;

  23. uint32_t scaleFactors[8]; //= {0x0f, 0x0c, 0x0b, 0x0b, 0x0a, 0x0a, 0x09, 0x09};

  24. int32_t bitneed[8];

  25. uint32_t bits[8];

  26. int32_t bitcount, slicecount, bitslice;

  27. uint8_t samplingRate, blocks, snr, numSubbands, bitpoolSz, bitpos = 0x80;

  28. int8_t max_bitneed = 0;

  29. #ifndef SPEED_OVER_ACCURACY

  30. int32_t levels[8];

  31. #endif

  32. #if (DEBUG_DECODING == 1)

  33. const uint8_t *start_buf = buf;

  34. pr_info("%s: blocks_per_packet = %d, num_bits = %d, buf = %p, len = %d\n",

  35. __func__, blocks_per_packet, num_bits, buf, len);

  36. for (i = 0; i < len; i++) {

  37. pr_info("buf[%d] = 0x%02x\n", i, buf[i]);

  38. }

  39. #endif

  40. /* look into the frame header */

  41. if (left < SBC_GROUP_SIZE) goto out;/* too short a frame header */

  42. /* use Bemote specific constants */

  43. samplingRate = 0; /* always 16000 Hz */

  44. blocks = blocks_per_packet;

  45. snr = 0;

  46. numSubbands = SBC_NUM_OF_SUBBANDS;

  47. bitpoolSz = num_bits;

  48. /* read scale factors */

  49. /* pr_info("sbc_decode: read scale factors, numSubbands = %d\n", numSubbands); */

  50. /**/

  51. for(i = 0; i < numSubbands; i++){

  52. if(bitpos == 0x80){

  53. scaleFactors[i] = (*buf) >> 4;

  54. bitpos = 0x08;

  55. }

  56. else{

  57. scaleFactors[i] = (*buf++) & 0x0F;

  58. bitpos = 0x80;

  59. }

  60. }

  61. /* calculate bitneed table and max_bitneed value (A2DP 12.6.3.1) */

  62. if(snr){

  63. for(i = 0; i < numSubbands; i++){

  64. bitneed[i] = scaleFactors[i];

  65. if(bitneed[i] > max_bitneed) max_bitneed = bitneed[i];

  66. }

  67. }

  68. else{

  69. const signed char* tbl;

  70. if(numSubbands == 4) tbl = (const signed char*)loudness_4[samplingRate];

  71. else tbl = (const signed char*)loudness_8[samplingRate];

  72. for(i = 0; i < numSubbands; i++){

  73. if(scaleFactors[i]){

  74. int loudness = scaleFactors[i] - tbl[i];

  75. if(loudness > 0) loudness /= 2;

  76. bitneed[i] = loudness;

  77. }

  78. else bitneed[i] = -5;

  79. if(bitneed[i] > max_bitneed) max_bitneed = bitneed[i];

  80. }

  81. }

  82. /* fit bitslices into the bitpool */

  83. bitcount = 0;

  84. slicecount = 0;

  85. bitslice = max_bitneed + 1;

  86. /* pr_info("sbc_decode: fit bitslices into the bitpool, bitslice = %d\n", bitslice ); */

  87. do{

  88. bitslice--;

  89. bitcount += slicecount;

  90. slicecount = 0;

  91. for(i = 0; i < numSubbands; i++){

  92. if(bitneed[i] > bitslice + 1 && bitneed[i] < bitslice + 16) slicecount++;

  93. else if(bitneed[i] == bitslice + 1) slicecount += 2;

  94. }

  95. }while(bitcount + slicecount < bitpoolSz);

  96. /* distribute bits */

  97. for(i = 0; i < numSubbands; i++){

  98. if(bitneed[i] < bitslice + 2) bits[i] = 0;

  99. else{

  100. int8_t v = bitneed[i] - bitslice;

  101. if(v > 16) v = 16;

  102. bits[i] = v;

  103. }

  104. }

  105. /* allocate remaining bits */

  106. for(i = 0; i < numSubbands && bitcount < bitpoolSz; i++){

  107. if(bits[i] >= 2 && bits[i] < 16){

  108. bits[i]++;

  109. bitcount++;

  110. }

  111. else if(bitneed[i] == bitslice + 1 && bitpoolSz > bitcount + 1){

  112. bits[i] = 2;

  113. bitcount += 2;

  114. }

  115. }

  116. for(i = 0; i < numSubbands && bitcount < bitpoolSz; i++){

  117. if(bits[i] < 16){

  118. bits[i]++;

  119. bitcount++;

  120. }

  121. }

  122. /* reconstruct subband samples (A2DP 12.6.4) */

  123. #ifndef SPEED_OVER_ACCURACY

  124. for(i = 0; i < numSubbands; i++) levels[i] = (1 << bits[i]) - 1;

  125. #endif

  126. /* pr_info("sbc_decode: reconstruct subband samples, blocks = %d\n", blocks ); */

  127. for(j = 0; j < blocks; j++){

  128. for(i = 0; i < numSubbands; i++){

  129. if(bits[i]){

  130. uint32_t val = 0;

  131. k = bits[i];

  132. do{

  133. val <<= 1;

  134. #if (DEBUG_DECODING == 1)

  135. pr_info("%s: buf = %p, offset %d\n",

  136. __func__, buf, buf-start_buf);

  137. #endif

  138. if(*buf & bitpos) val++;

  139. if(!(bitpos >>= 1)){

  140. bitpos = 0x80;

  141. buf++;

  142. }

  143. }while(--k);

  144. val = (val << 1) | 1;

  145. val <<= scaleFactors[i];

  146. #ifdef SPEED_OVER_ACCURACY

  147. val = mulshift(val, bits[i]);

  148. #else

  149. val /= levels[i];

  150. #endif

  151. val -= (1 << scaleFactors[i]);

  152. samples[j][i] = SAMPLE_CVT(val);

  153. }

  154. else samples[j][i] = SAMPLE_CVT(0);

  155. }

  156. }

  157. //sbc_decoder_reset();

  158. for(j = 0; j < blocks; j++){

  159. synth(outBufPtr, samples[j], numSubbands, gV);

  160. outBufPtr += numSubbands;

  161. }

  162. /* if we used a byte partially, skip the rest of it, it is "padding" */

  163. if(bitpos != 0x80) buf++;

  164. out:

  165. #if (DEBUG_DECODING == 1)

  166. if(left < 0)

  167. pr_err("SBC: buffer over-read by %d bytes.\n", -left);

  168. if(left > 0)

  169. pr_err("SBC: buffer under-read by %d bytes.\n", left);

  170. #endif

  171. fwrite(usDecodedBuffer, sizeof(uint16_t), 120, fOutput);

  172. fflush(fOutput);

  173. memset(usDecodedBuffer, 0, sizeof(usDecodedBuffer));

  174. }

4 总结

  • 在章节3中给出的例子中,压缩前的数据有120*2=240Byte,压缩后的数据有54Byte,压缩比接近4.4:1,压缩比是可调的,其与编码参数有关
  • 压缩后的帧数据长度可以由编码参数计算出来。此例中,
    帧长度=4+(4 * 子带数量 * 通道数量)/8+(块数量 * 通道数量 * bitpool)/8
    =4+(4*8*1)/8+(15*1*26)/8=8+48.75=57(加上CRC正好58字节)
  • 如果在传输过程中丢失了个别帧,解压后回放时会出现一小段音频的整体丢失,对整体的解压没有影响

参考文献

1. LOW-POWER IMPLEMENTATION OF THE BLUETOOTH SUBBAND AUDIO CODEC.pdf
2. A2DP_SPEC_V12.pdf
3. 音频数据SBC算法编码方法及蓝牙立体声子系统.pdf

【蓝牙sbc协议】sbc源码阅读笔记(一)——编码过程 sbcenc.c *main(int argc, char argv[]) 首先设定 option 的默认值,然后根据用户命令设定 option 相关参数。 对指定文件进行编码(执行encode函数) usage(void) 打印相关option: Option Option 打印帮助信息 h help 打印帮助信息 v verbose 详细模式 m msbc mSBC编解码器 s subbands 子带数量(4/8) b bitpool Bitpool value 阅读详情

相关推荐

SBC 编码

SBC(Sub-band Coding,子带编码编码器是一种在蓝牙音频传输等领域广泛应用的编码技术。SBC编码器的基本原理是把信号的频率分为若干子带,然后对每个子带进行编码,并根据每个子带的重要性及特点分配不同的位数来表示数据。例如,在音频编码中,由于人耳对不同频率的敏感度不同,可以在对人耳敏感的子带使用较细的量化,对人耳不敏感的子带使用较粗糙的量化,从而在不降低主观听觉效果的情况下达到较好的压缩效果。SBC是蓝牙规范的必选项之一,对于蓝牙音频传输来说至关重要。

百态·数智思维 | 聚焦大数据、量化与未来AI 1409

c语言 sbc 音频编解码算法

纯C语言编写的 SBC 音频编解码算法,包含测试demo,压缩比可以更加需求进行调节

蓝牙协议中的SBC编解码原理和仿真

一、SBC的原理   SBC是subband codec的缩写,中文叫做次频带编码,也叫子带编码。其基本原理是把信号的频率分为若干子带,然后对每个子带进行编码,并根据每个子带的重要性及特点分配不同的位数(采样深度)来表示数据。例如,在音频编码中,由于人耳对不同频率的敏感度不同,可以在对人耳敏感的子带使用较细的量化(较大的采样深度),对人耳不敏感的子带使用较粗糙的量化(较小的采样深度),从而在不降...

weixin_30662109的博客 9353

sbc编解码源代码

android上用的,网上下载,版权自己考虑,侵权与上传者无关

SBC音频编解码算法在无线音频传输上的简单应用

SBC音频编解码算法浅析1. SBC算法简介 SBC是sub band code的缩写,也可称为子带编码 在A2DP协议中,SBC算法是默认支持的 蓝牙SBC算法是一种以中等比特率传递高质量音频数据的低计算复杂度的音频编码算法 1.1 算法基本框图 SBC系统使用一个余弦调制的滤波器组,用来解析和同步。滤波器组可设定成4或8个子带 子带信号的量化采用比特分配器和自适应脉冲编码器组调制 可用的比特位数

wzz4420381的博客 1万+

SBC音频压缩编解码,MCU上也能用,最大可压缩16倍

SBC, sub band code的缩写,也可称为子带编码。其原理是:通过带通滤波器将音频信号分成不同频段的子带信号,然后将这些信号经过频率搬移转变成基带信号,再对它们分别取样,量化和编码,最后合成一个总的码流传送出去,如下图所示。这样做的好处是:舍弃或减小人耳听觉不敏感的频率部分,在敏感频率处采用较细的量化,在低比特率条件下获得更好的听觉效果。A2DP中规定SBC编码支持最大比特率是单声道320kbps,立体声512kbps。但按其推荐,实际上使用最多的是44.1KHz,328kbps的立体声传输。

YJJ_1997的博客 4329

【A2DP】规范精讲[5]:深入剖析A2DP中的SBC编解码

SBC 编解码器的互操作性要求涵盖了多个方面,包括采样频率、声道模式、块长度、子带数量、分配方法、比特池值以及媒体数据包头部和有效负载格式等。理解和遵循这些要求对于实现 SBC 编解码器在不同设备之间的稳定、高效音频传输至关重要。在实际应用中,开发者需要根据这些要求进行设备的开发和配置,以确保设备之间的兼容性和音频传输质量。

byte轻骑兵的技术小窝 1万+

【A2DP】规范精讲[14]:SBC编解码器技术框架深度解析

本文深入解析蓝牙音频基础编解码SBC的技术细节,涵盖其设计定位、核心概念、数学基础、帧结构设计及语义定义。作为A2DP规范的强制性编解码器,SBC在计算复杂度、功耗和音质间取得平衡,成为蓝牙音频设备的通用语言。文章详细剖析SBC帧的自包含结构,包括帧头、比例因子、音频样本和填充位的精密设计,以及语法语义的协同作用。特别探讨了JOINT_STEREO模式下的动态编码策略和比特分配算法,揭示了SBC在有限资源下实现高效音频编码的技术原理。通过理解这些基础规范,开发者能够更好地实现和优化SBC编解码器。

byte轻骑兵的技术小窝 1万+

【A2DP】规范精讲[4]: 深入解读A2DP协议中的音频编解码器互操作性要求

蓝牙音频编解码器的互操作性要求是确保不同设备之间音频传输顺畅、高效的关键。通过遵守这些要求,设备可以实现音频数据的正确编码、传输和解码,从而提供高质量的音频体验。

byte轻骑兵的技术小窝 9605

android蓝牙开发切换编解码

Android 蓝牙开发中的编解码切换 在 Android 应用开发中,蓝牙通信是一个常见的需求。尤其是在涉及音频流或数据的传输时,编解码的选择对最终效果有着至关重要的影响。本文将为你介绍如何在 Android 蓝牙开发中进行编解码的切换,以及相关代码示例。 编解码的基本概念 编解码器(Codec)是一种用于将信息编码为特...

weixin_36846612的博客 655

【A2DP】规范精讲[13]: 蓝牙音频技术中的关键术语与缩略语全指南

蓝牙技术中的这些术语缩写相互关联、相互作用,共同构成了一个完整的技术体系。从音频编码格式的选择到蓝牙设备之间的连接和数据传输,再到数据的处理和保护,每个术语都在其中扮演着不可或缺的角色。对于蓝牙技术的开发者、工程师以及爱好者来说,深入理解这些术语的含义和应用,不仅有助于准确解读技术文档和标准规范,更能够在实际的开发和应用中,设计出更加高效、稳定和优质的蓝牙产品和解决方案。

byte轻骑兵的技术小窝 9640

CSR867x — 说说蓝牙音频常用的编解码格式

写在前面:最近接触了几种蓝牙音频编码格式,以下是搜集到的资料,笔者做了下整理; SBC (Sub-band coding,子带编码) 最早的格式应该是SBCSBC是A2DP(Advanced Audio DistribuTIon Profile,蓝牙音频传输协议)协议强制规定的编码格式。所有的蓝牙都会支持这个协议,所以所有的蓝牙音频芯片也会支持这个协议。SBC编码在传输时的码率具体参数未找到,根据sony官网宣传给出的资料,是:328Kbps,44.1KHZ。 这个码率其实和高品质的MP3

文化人的博客 1万+

【Bluedroid】A2dp Source播放流程源码分析(4):深入解析SBC编码器初始化(a2dp_sbc_encoder_init)

SBC(Subband Coding)作为蓝牙 A2DP 协议的标准编解码器,其编码器的初始化与参数配置直接影响音频传输的音质、效率与兼容性。本文基于Andoird A2DP 协议栈源码,系统剖析 SBC 编码器的初始化流程,包括核心参数(比特池、采样率、声道模式等)的解析、计算与动态调整逻辑,以及与传输层的协同优化(如 MTU 适配、帧封装策略)。通过梳理从配置解析到编码器就绪的全流程,揭示 SBC 如何在蓝牙带宽限制下平衡音质与传输稳定性,为理解蓝牙音频编码机制提供关键技术参考。

byte轻骑兵的技术小窝 4549

【A2DP】规范精讲[8]: 解读A2DP中的ATRAC家族编解码

本文深入解析索尼专有音频编解码器ATRAC在A2DP协议中的实现规范。ATRAC作为索尼生态的"私有音频密码",其开发需获得索尼授权,核心参数包括Version字段、ChannelMode、采样频率等7个关键元素。与通用编解码器不同,ATRAC具有严格版本隔离要求,并引入特有的MaximumSUL参数控制音频单元长度。

byte轻骑兵的技术小窝 2万+

【A2DP】规范精讲[9]: 解读A2DP厂商特定编解码器框架

本文详细解析了蓝牙音频中的厂商特定编解码器机制,包括其技术规范、实现要求和市场意义。文章首先阐述了厂商特定编解码器的必要性,指出其在实现差异化音质方面的关键作用。随后深入分析了规范中关于VendorID、CodecID和参数值的具体要求,并详细介绍了协商流程的三个关键步骤。同时,文章结合实际案例指出了开发过程中常见的兼容性问题和解决方案,强调了SBC回退机制的重要性。最后,从商业角度评估了厂商特定编解码器的技术投入与市场价值,为相关产品决策提供了参考依据。

byte轻骑兵的技术小窝 1万+

【A2DP】规范精讲[10]: 深入解读A2DP中的MPEG-D USAC编解码

本文深入解析A2DP规范中MPEG-D USAC编解码器的技术要点。USAC作为统一语音和音频编码标准,其核心优势在于同时优化语音和音乐场景,特别适合车载、游戏耳机等多场景设备。文章详细解读了USAC的编解码器特定信息元素、媒体包格式、协商流程及DRC优化等关键技术规范,并提供了实际开发中的问题排查指南。USAC凭借其场景自适应能力、低延迟切换和高效压缩等特点,正成为蓝牙音频领域面向未来的"全能型"解决方案,尤其适合需要兼顾语音和音乐表现的多场景应用。

byte轻骑兵的技术小窝 1万+

蓝牙 HFP 场景下 LC3 与 MSBC 编解码器初始化设计与实现解析

本文深入解析了蓝牙HFP协议中LC3和MSBC两种宽频语音编解码器的初始化设计。LC3作为原生低复杂度编解码器,采用7.5ms帧长和32kHz采样率配置;MSBC基于SBC优化,固定16kHz采样率和26比特池。两者均采用三层架构设计:上层统一接口、中层封装适配、底层差异化实现。初始化流程重点关注协议兼容性、资源安全和编解码协同三大问题,通过参数对称配置、内存安全管理和包大小校验等机制确保稳定性。这些设计为蓝牙语音产品的开发提供了重要参考,特别适合车载和穿戴设备等低延迟场景。

byte轻骑兵的技术小窝 1万+

小身材,大内涵的音频模组--你需要吗?

  经过几个月的打磨,我们的智能音频模组--顺耳风终于和大家见面了。接下来,就介绍给大家大致认识一下吧。下图就是它: 它可以变成什么? * 智能耳机* 智能音箱* AI语音设备* 蓝牙无线声卡* USB有线声卡 它的名字:   产品的名字就是它的化身,名如其才,只要看上他一眼,就再也无法释怀了。这个模组是专门为那些对音频处理和传输有特殊需求的客户定制的。它是一个单独可以作为音箱,耳机或...

weixin_30372371的博客 120

【A2DP】规范精讲[6]:深入解析A2DP中的MPEG-1,2 Audio编解码

本文深入解析了蓝牙A2DP规范中的MPEG-1,2 Audio编解码器(MP1/MP2/MP3),重点阐述了其在音频压缩技术演进中的重要地位。文章详细解读了编解码器特定信息元素、媒体包格式、参数协商机制等核心技术要点,包括Layer选择、CRC校验、声道模式、采样率等关键参数。通过对比其他蓝牙音频编解码器,分析了MPEG系列在兼容性方面的独特优势,并提供实际开发中的问题排查方法。文章特别强调MPEG-1,2 Audio在保证老设备兼容性方面的重要价值,是蓝牙音频开发人员理解传统音频技术的重要参考。

byte轻骑兵的技术小窝 2万+
上一篇: C语言中文件打开模式(r/w/a/r+/w+/a+/rb/wb/ab/rb+/wb+/ab+)浅析
下一篇: C语言判断文件是否存在--存在且删除的方法
哆啦@熊
博客等级 码龄18年 1518粉丝 37原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值