基于谷歌官方开源的 LHDC V5 编码器Rust 版及基于官方解码器移植的 C99 版编码器及WillyBilly06 实现 sprlightning 优化调整的解码器源码 fork 版分析整理。源码参考编码器实际分析用的是 LHDC-V5-Encoder WillyBilly06 基于谷歌开源的 Rust 版编码器源码实现的 C99 移植sprlightning fork版与 Rust 原版比特精确一致原版是 WillyBilly06/LHDC-V5-Encoder 。解码器实际分析用的是 LHDC-V5-Decoder WillyBilly06 分析动态库独立实现的 C99 版解码器源码并与 C99 版编码器进行了参数校对sprlightning fork版后经 sprlightning 进行 workspace 分配优化和 default config 调整经真实编码器 round-trip 验证原版是WillyBilly06/LHDC-V5-Decoder 。Example对于ESP32-D0WD可以使用 支持多解码器的ESP-IDF框架 Step 1. 先执行git clone --recursive https://github.com/sprlightning/esp-idf-bt-multiple-codecs.git esp-idfStep 2. 然后进入esp-idf目录并执行git submodule update --recursive --init拉取所有子模块Step 3. 基于第一步的esp-idf创建A2DP Sink项目来测试在项目中配置menuconfig勾选LHDCV5并启用PSRAM并设置CONFIG_SPIRAM_USE_MALLOCy同时注意给蓝牙分配足够的栈 Size8kB 或者更多 。对于PC可以直接使用python脚本来测试。LHDC V5 三部曲导航LHDC V5 编解码流程与原理详解LHDC V5 手机到耳机音乐传输链路详解LHDC V5 算法深度解析一、LHDC V5 概述1.1 什么是 LHDC V5LHDCLow-Latency High-Definition Audio Codec低延迟高清音频编解码器是由台湾盛微先进科技Savitech / HWA开发的蓝牙高清音频编码标准。V5 是其第五代版本核心定位是在蓝牙有限带宽下传输高分辨率音频。谷歌在 AOSPAndroid Open Source Project的system/audio codecs中正式开源了 LHDC V5 的 Rust 实现这也是本文分析的基础。1.2 核心参数参数取值采样率44.1 kHz / 48 kHz / 96 kHz / 192 kHz位深16 bitS16LE/ 24 bitpacked S24LE3 字节/采样声道立体声2 声道独立 L/R 编码非 Mid/Side帧时长固定 5 ms每帧采样数每声道240 44.1/48k480 96k960 192k目标码率64 kbps ~ 1000 kbps共 13 档 AutoMDCT 尺寸480 / 960 / 1920 2 × 每帧采样数1.3 技术定位LHDC V5 属于变换域感知音频编码Transform-domain Perceptual Audio Coding与 MP3MPEG-1 Layer III、AACAdvanced Audio Coding、LDAC索尼同属一个技术范式。其核心思想是将时域 PCM 信号通过MDCT改进离散余弦变换变换到频域利用人耳的心理声学模型掩蔽效应对不同频带分配不同的量化精度对量化后的频谱系数进行熵编码算术编码 Rice 编码压缩冗余解码端执行完全逆过程重建时域 PCM。二、编码器完整流程编码器的核心入口是lv5e_enc_encode()对应公共 APIlhdcv5_enc_encode()。一帧立体声 PCM 的编码分为以下几个阶段2.1 初始化阶段2.1.1 编码器上下文创建lhdcv5_enc_new() → lv5e_enc_context_new()创建编码器上下文lv5e_enc_context_t包含帧头状态lv5e_header_t频率域缓冲区lv5e_fdata_all_buffer_t最大约 117 KB 192k算术编码器状态lv5e_arith_base_t两个声道的编码输出缓冲区encoded_data_ch0/ch1各 171 个 32 位字2.1.2 编码器参数配置lhdcv5_enc_init_encoder() → lv5e_enc_init() → lhdc_enc_lossy_start() → lv5e_fdata_all_buffer_reset() → lv5e_enc_lossy_frame_length_program()关键配置步骤帧长计算根据目标码率和帧时长计算每帧字节数frame_len bitrate × ms / (8 × 1000 × 10 × channel)44.1 kHz 有特殊处理735 采样/帧的非整数关系。段配置选择根据采样率、帧时长、码率选择频带分段配置segment settings44.1/48k 高码率120 kbps480-HR 配置44.1/48k 中码率96~120 kbps480 配置44.1/48k 低码率≤96 kbps480-LB 配置96k960 配置192k1920 配置电平表初始化lv5e_level_table_init()初始化量化步长查找表512 项目标比特范围计算target_range frame_bytes × 8 - header_data_size target_range_bottom target_range × bottom%bottom为 90~96%确保编码输出在目标范围内有一定余量。算术编码模型初始化初始化两个三符号ternary自适应模型的初始频率表2.2 帧头处理lv5e_enc_process_header()每帧开头写入帧头信息包含编码尺寸索引ENC_SIZE_INDEX版本号VERSION_INDEXJAS 标志AR自适应范围标志LARC 标志元数据标志帧头采用 16 位小端格式低 10 位为 payload 长度×2 字节高 6 位为标志位。2.3 核心编码循环lhdc_enc_top对每个声道独立执行以下流程2.3.1 频率变换MDCTlv5e_enc_lossy_frequency_operation() → lv5e_freq_top_reset()原理将时域 PCM 信号通过 MDCT 变换到频域得到频谱系数。技术要点LHDC V5 使用LD-MDCT低延迟改进离散余弦变换帧长 MDCT 尺寸 / 2基于 KISS FFT 实现的快速 MDCT通过 N/4 点复数 FFT 预/后旋转因子 对称展开实现编码器使用定点int32运算确保比特精确变换尺寸48044.1/48k、96096k、1920192kMDCT 的优势临界采样critically sampled无冗余50% 重叠 加窗可实现完全重构 Princen-Bradley 条件频域系数对应固定频带便于应用心理声学模型2.3.2 SNS 频谱噪声整形Spectral Noise Shapinglv5e_enc_freq_shift() → lhdc_enc_lossy_jump_adust_process() → moving_average() → lv5e_freq_shift_apply_encode()原理SNS 是 LHDC V5 的核心感知编码工具。它将频谱划分为多个子带24 或 32 段计算每个子带的能量然后通过一个自适应步长的 DPCM差分脉冲编码调制过程生成每段的缩放因子scale factor最后对频谱系数施加逐段增益。详细流程子带能量计算将频谱按segment_offset[]划分为segment_num个子带每个子带计算能量和se[s] Σ(data[d]² × segment_scale[s]) segment_scale_jump能量包络平滑对子带能量进行加权移动平均4 点窗口非对称计算平均能量dirty_bottom低于阈值的子带被提升到噪声底自适应步长 DPCMjump_adjust这是 SNS 编码的核心。使用一个 64 项的步长表JUMP_TABLE[]从 6 到 4096 指数增长状态机维护当前步长索引index连续相同方向的差分 → 步长增大index est_controlest_control 递增方向翻转 → 步长减小index (3×index 2) 2每段的缩放因子sf[i] sf[i-1] ± JUMP_TABLE[index]符号由差分方向决定这本质上是一个ADPCM自适应差分 PCM编码器用 1 bit/段 的方向信息编码整个频谱包络后处理平滑均值移除mean-remove消除 DC 偏移非对称 4 点移动平均平滑钳位到 [-2560, 1024]然后取反增益应用lv5e_freq_shift_apply_encode()将每段缩放因子转换为增益通过 2 的幂次表对该段内所有频谱系数乘以对应增益正缩放因子 → 增益 1提升负缩放因子 → 增益 1衰减SNS 的作用模拟人耳的频域掩蔽效应强能量子带可以容忍更大的量化噪声衰减该段 → 量化后噪声相对降低弱能量子带被提升到噪声底以上避免音洞用极少的比特1 bit/段 4 bit 模式编码完整的频谱包络2.3.3 24-bit 输入电平平移对于 24-bit 输入需要额外计算一个全局电平平移量jump_level_top确保频谱系数不会溢出 30 位定点范围。通过查找电平表找到合适的衰减量。2.3.4 量化与码率控制Rate Looplhdc_enc_lossy_nbyte_estimation() → lhdc_enc_lossy_freq_level() → lhdc_enc_nbyte_esti() → coef_calc() → lhdc_enc_symbol_generation() → lhdc_enc_symbol_calc()这是编码器最复杂的部分核心目标是找到一个全局量化步长使得编码后的比特数恰好落在目标范围内。量化原理quantized_coeff round(spectrum_coeff × level)其中level是量化步长从电平表level_table中按偏移索引offset_size查找。level越大 → 系数量化后的值越大 → 需要更多比特编码但量化误差越小音质越好。level越小 → 系数越小 → 比特越少但量化误差越大。码率控制循环初始offset_size来自上一帧帧间预测对当前offset_sizea.lhdc_enc_lossy_freq_level()用当前步长量化频谱统计非零系数个数nzcb.lhdc_enc_nbyte_esti()估算编码这些系数需要的比特数coef_calc()计算每个系数的比特数预测两种 IIR 预测器 coef3 / coef7选择误差更小的lhdc_enc_symbol_generation()将系数量化为三进制符号流step1 step2lhdc_enc_symbol_calc()用算术编码估算符号流的实际比特数c. 比较估算比特数与target_range/target_range_bottom如果超出目标 → 增大offset_size减小步长如果低于目标底部 → 减小offset_size增大步长使用牛顿法/二分法快速收敛offset_size (pixel_number - target_range) / offset系数比特数预测coef_calc对每个非零系数计算其幅值所需比特数bits_num[i] log2(|coeff|) 7Q7 定点用两种一阶 IIR 预测器预测下一个系数的比特数coef3pred[i] (3×pred[i-1] 5×bits_num[i]) 3快响应coef7pred[i] (7×pred[i-1] bits_num[i]) 3慢响应/平滑选择累计绝对误差更小的预测器symbol_flag标记选择结果预测值决定该系数保留多少高位reserved_bits低位作为尾数mantissa单独编码三进制符号生成symbol_generation将量化系数转换为三进制0, 1, 2符号流Step 1系数 1 且在有效范围内 → 标记为 2escape symbol否则取最低位0 或 1Step 2对 escape symbol用 Rice 编码展开其商值quotient生成扩展的三进制序列2.3.5 比特流打包输出lhdc_enc_lossy_nbyte_out() → bit_write_uint() → lhdc_enc_nbyte_out() → lv5e_arith_*() → lv5e_bitout_*()找到最优量化步长后执行实际的比特流打包写入前导信息leading section1 bitflag固定 09 bit全局增益索引global_gain量化步长的索引4 bitSNS 模式sns_mode - 8ADPCM 初始状态num_sfb - 1bitSNS 每段方向位jump directionvalid_numbit非零系数计数(nzc 1) - 11 bit符号标志symbol_flag选择 coef3 还是 coef7 预测器4 bit初始残差resid仅高码率帧frame_len ≥ 160算术编码FAC - Fast Adaptive arithmetic Coding对三进制符号流进行自适应范围编码使用滑动窗口sliding window自适应概率模型两个独立模型模型 1stream1 / marker plane初始频率 {54, 12, 1}窗口ma_win1模型 2stream2 / quotient初始频率 {90, 16, 1}窗口ma_win2 ma_win1 × 8总频率归一化为 2^15 32768范围编码器维护range和code寄存器通过归一化移位输出字节尾数 符号位平面mantissa sign plane算术编码只编码了系数的高位Rice 商尾数mantissa紧跟在 FAC 字节流之后按因果预测器分配比特shift[k] calc_bits(|M[k-1]|) 前一系数幅值的比特数作为当前尾数位数预测 M[k] (q[k] shift[k]) | mantissa_bits预测器有两种模式由 flag2 选择模式 0A[k] (5×x 3×A[k-1]) 3快模式 1B[k] (7×B[k-1] x) 3慢每个非零系数后跟 1 bit 符号位1 负填充到固定帧长如果编码比特数不足target_range对剩余非零系数追加 1 bit 残差最后用 0 填充到完整帧长零填充到字节边界溢出重试如果实际编码比特数超出目标范围减少非零系数个数丢弃低能量系数重新估算并编码这是一个内循环直到输出在目标范围内2.3.6 帧头加扰Scrambleencoded_data_encrypt()每个声道编码输出的前 8 字节进行加扰与固定掩码XOR_MASK[] {0xFF, 0xE7, 0x7A, 0xB3, 0xDA, 0xE5, 0xCD, 0x73}异或按SCRAMBLE_ORDER[][]表进行字节重排两种排列由第 9 字节的最低位选择这不是加密密钥固定且公开而是数据加扰目的是避免编码后的帧头出现固定模式便于蓝牙传输中的同步和误码检测。2.4 编码器输出output [frame_header(2 bytes)] [ch0_encoded_data] [ch1_encoded_data]帧头2 字节小端低 10 位 payload_len / 2高 6 位 标志每个声道数据固定enc_pixel_size_byte字节由码率决定两个声道等长独立编码编码后的帧被放入内部队列攒够一个 MTU 大小的数据包后一次性输出对应 A2DP 媒体 payload。三、解码器完整流程解码器的核心入口是lhdc_dec_decode_frame()。一帧 LHDC V5 码流的解码分为以下阶段3.1 初始化阶段3.1.1 工作区分配lhdc_dec_get_workspace_size() → lhdc_dec_init() → lhdc_dec_carve_alloc()解码器采用分离式工作区分配split-workspace每个速率相关的缓冲区独立分配mdct_in/ch_pcmH M/2 个 float共享同一块内存生命周期不重叠mdct_out/quant_spectrumM 个 float / int32共享overlap_buf[2]各 H 个 float重叠相加历史pcm_midH 个 float声道 0 的 PCM 暂存ov_saveH 个 float重叠快照用于解扰选择器重试ent_s1/ent_s2熵解码三进制符号缓冲区最大单块分配为mdct_out M × 4B192k 时 7680 B避免了需要大连续内存块的问题。3.1.2 IMDCT 表初始化lhdc_imdct_init(M)生成快速 IMDCT 所需的旋转因子表twiddle tables并执行自测试与直接余弦公式参考实现对比确保快速路径正确。3.2 帧解析lhdc_dec_parse_header()读取 2 字节小端帧头payload_len (hdr 0x3FF) × 2flags hdr 10校验 payload 长度合法性将 payload 拷贝到内部缓冲区payload_buf[]流参数采样率、声道、位深来自 A2DP 协商的 CIECodec Information Element不在帧内根据采样率和帧时长获取频带配置band_cfgMDCT 尺寸、子带数、子带偏移表、FAC 窗口参数3.3 逐声道解码lhdc_dec_decode_channel_autosel对每个声道独立解码。由于解扰选择器descramble selector在少数帧上可能错误解码器采用自动选择重试机制先用默认选择器第 9 字节最低位解码检测解码后 PCM 峰值是否超过 2× 满量程表示解扰错误导致 FAC 失同步产生巨大系数如果异常恢复重叠缓冲区用翻转的选择器重解码保留峰值更小的结果3.3.1 解扰Descramblelhdc_descramble_inplace()编码器加扰的逆操作按LHDC_PERM[sel][]逆排列前 8 字节与LHDC_XOR_MASK[]异或还原选择器sel payload[8] 13.3.2 前导信息读取Leading Section从比特流中按顺序读取1 bit flag固定 0校验帧同步9 bit global_gain全局增益索引用于逆量化4 bit sns_modeSNS 模式 读取值 8ADPCM 初始状态范围 8~23sns_mode 23是平坦 SNS 逃逸码所有方向位为 0跳过 adsq 重建scale factor 全 0num_sfb - 1 bit SNS 方向位每段 1 bit用于 adsq 逆 DPCMnzc_bits bit 非零系数计数nzc (nzc_raw 1) × 2nzc_bits calc_bits(samples_per_channel) - 1240 采样时为 7 bit1 bit flag2尾数比特分配预测器选择0 快 IIR1 慢 IIR4 bit resid初始移位值仅高码率帧frame_len ≥ 320 字节/声道时存在3.3.3 SNS 参数解码lhdc_sns_decode_params() → sns_adsq_inverse() → sns_post_smooth()adsq 逆 DPCM初始sf[0] 0state sns_moderun 1对每段 i ≥ 1如果 i ≥ 2根据方向位是否与前一段相同更新 state相同runstate min(state run, 63)步长增大不同state max((3×state 2) 2, 0)run 1步长减小sf[i] sf[i-1] sns_step(bit, state)bit0 正向bit1 负向步长表LHDC_SNS_STEP_POS[64]从 6 到 4096 指数增长后处理平滑sns_post_smooth均值移除sf[0] -mean(sf[1..n])sf[i] sf[0]非对称 4 点移动平均窗口 前 1 当前 后 2钳位到 [-2560, 1024]然后取反这与编码器的lv5e_enc_freq_shift()完全对称确保重建的 scale factor 与编码器一致。3.3.4 FAC 熵解码lhdc_entropy_decode_spectrum_ex2() → fac_decode() → rice_decode_coeffs_used()FAC 范围解码器初始化从比特流当前位置读取剩余字节作为 FAC 字节流初始化范围解码器range 0xFFFFFFFFcode 前 4 字节总频率 2^15 32768三进制符号流解码Stream 1marker plane初始化模型初始频率 {54, 12, 1}滑动窗口ma_win1解码nzc个三进制符号0, 1, 2每个符号解码后更新模型滑动窗口频率统计 归一化Stream 2quotient codes初始化模型初始频率 {90, 16, 1}滑动窗口ma_win2 ma_win1 × 8按需解码lazy decode带 1 符号预读范围解码算法fac_decoder range 15 // 归一化因子 sym 第一个满足 r × cum[sym1] code 的符号 // 用乘法替代除法Xtensa 优化 code - r × cum[sym] range r × (cum[sym1] - cum[sym]) while (range 24) 0: // 归一化移位 code (code 8) | next_byte() range 8 update_model(sym) // 滑动窗口频率更新Rice 商解码rice_decode_coeffs_used将三进制符号流转换为系数量值pivot max(count - split, 0)split num_coeffs / 3run 最后一个 s1 2 的索引pivot2 (run pivot) ? count : run对 i ≤ pivot2s1[i] 2 →coeff[i] rice_read_quotient() 2Rice 解码商值 偏移s1[i] 0 或 1 →coeff[i] s1[i]小值直接传递对 i pivot2coeff[i] (rice_read_quotient() 1) | s1[i]s1 作为 LSBRice 商值解码rice_read_quotient遇到符号 2escape循环读取 2 bit 低位 符号 2 标记直到遇到非 2 符号然后读取连续的 1ones count最后以 0 结束。结果 low | ((ones1) shift)未遇到 escape读取连续 1 的个数最多 3 个以 0 结束。结果 ones 个数0~33.3.5 尾数 符号位平面解码lhdc_dec_mant_plane()算术编码只恢复了系数的高位Rice 商 q[k]完整幅值需要从尾数平面恢复shift[k] (pred 0x40) 7 // 因果预测器输出决定尾数位数 M[k] (q[k] shift[k]) | mantissa // 拼接高位和尾数 if M[k] ! 0: sign read_1_bit() // 1 负数预测器更新x calc_bits(|M[k]|) 7当前系数幅值比特数Q7 定点flag2 0快pred (5×x 3×pred) 3flag2 1慢pred (7×pred x) 3初始pred resid_val 7由前导信息中的 resid 字段决定尾数平面起始位置FAC 范围编码器结束后会留下 2 或 3 字节的预读间隙lookahead gap根据最终 range 值确定range ≤ 0x02000000→ 2 字节间隙否则 → 3 字节尾数平面从fac_start_bit (fac_bytes - gap) × 8开始系数逆序de-reversal编码器按逆序量化频谱从高频到低频因此解码后需要将前nzc个系数反转回自然频序for a0, bnzc-1; ab; a, b--: swap(qs[a], qs[b])3.3.6 逆量化Inverse Quantizationlhdc_dec_inverse_quantize()step 2^e(global_gain) // e() 是分段线性函数由 global_gain 索引 spectrum[k] quant[k] × step // 线性逆量化增益指数函数 e(gain_idx)分段线性映射参数取决于帧长、位深、采样率gain_idx ≤ splite gain_idx线性区每档 1 bitsplit gain_idx ≤ 503e split (gain_idx - split) × slope斜率 1粗调区gain_idx 503e e(503) (gain_idx - 504)钳位到 30split和slope由帧长和位深决定例如 48k/16bitsplit ≈ 10slope ≈ 0.03使用exp2f()计算分数指数单精度浮点确保精度。3.3.7 SNS 合成SNS Synthesislhdc_sns_synth_apply()编码器 SNS 的逆操作对每个子带的频谱系数乘以该段的增益gain sns_band_gain(sf[sfb]) // sf 是 adsq 重建的缩放因子 spectrum[k] * gain // k 在该子带范围内sns_band_gain(sf)sf ≥ 0idx sf 4gain POW2_MANT[idx] × 2^-20sf 0idx (sf 0xa0f) 4gain POW2_MANT[idx] × 2^-30POW2_MANT[i] round(2^(20 i/16))161 项查找表注意解码器实际执行的是除法gain 1 / sns_band_gain(sf)因为编码器的 SNS 整形是对频谱施加增益解码器需要逆操作恢复原始频谱形状。3.3.8 快速逆 MDCTFast IMDCTlhdc_imdct_transform()将频域频谱系数变换回时域快速 IMDCT 算法N 点 IMDCT 通过 N/4 点复数 FFT 实现四步分解预旋转pre-twiddle对输入频谱系数乘以复旋转因子N/4 点复数 FFT混合基分解第一级基 28/16/32 点对应 N480/960/1920第二级15 点 DFT通过 3×5 Cooley-Tukey 分解实现后旋转post-twiddle乘以复旋转因子对称展开symmetric unfold利用 IMDCT 的对称性生成 N 点时域输出自测试初始化时将快速路径与直接余弦公式参考实现对比最大误差超过阈值则回退到慢速参考路径。3.3.9 加窗重叠相加Windowed Overlap-Addlhdc_dec_overlap_add()Princen-Bradley 窗使用 KBDKaiser-Bessel Derived窗满足完全重构条件480 点使用预计算的常量 flash 表零 RAM 占用其他尺寸按需生成重叠相加mdct_out[n] * window[n] // 加窗 pcm_out[n] mdct_out[n] overlap_buf[n] // 前半部分 当前 上一帧后半 overlap_buf[n] mdct_out[n overlap] // 保存后半部分供下一帧overlap mdct_size / 2 samples_per_channel每帧输出overlap个采样即 MDCT 尺寸的一半50% 重叠确保帧间无接缝、无相位失真3.4 立体声交织与输出缩放// 声道 0 的 PCM 已暂存在 pcm_mid[] // 声道 1 的 PCM 在 ch_pcm[] mdct_in共享内存 sc 2^(out_bit_depth - 23) × rate_norm(mdct_size) × level_cal(sr, bit_depth) for n in 0..samples_per_ch: L pcm_mid[n] × sc R ch_pcm[n] × sc clip(L, R to full scale) write interleaved L/R to output输出缩放因子2^(bit_depth - 23)编码器内部使用 24-bit 定标转换到输出位深rate_norm mdct_size / 480不同采样率的 IMDCT 重构增益差异归一化96k 比 48k 低 ~12 dB192k 低 ~24 dBlevel_cal经验校准因子确保不同配置下音量一致输出格式16-bitint16 交织 L/R24-bitint32 容器32-bit 对齐24 有效位左对齐便于 I2S DMA 传输声道顺序直接 L/R非 Mid/Side3.5 错误隐藏Error Concealment如果解码后帧峰值超过 2× 满量程表示 FAC 失同步或解扰错误解码器执行将该帧输出置零静音 5ms远好于巨大的爆音清空两个声道的重叠缓冲区避免错误污染下一帧四、关键技术要点总结4.1 编码技术栈总览技术模块编码器解码器作用时频变换LD-MDCT定点KISS FFT快速 IMDCT浮点FFT-based时域→频域/频域→时域感知整形SNSADPCM 频谱包络编码SNS 合成逐段增益利用心理声学掩蔽效应分配噪声量化均匀标量量化 码率控制循环线性逆量化频谱系数量化到整数熵编码FAC 自适应算术编码 Rice 编码FAC 范围解码 Rice 解码压缩量化系数的统计冗余尾数编码因果 IIR 预测比特分配 符号位因果预测尾数恢复 符号位编码系数量化后的低位残差帧结构2B 帧头 等长双声道 payload帧解析 逐声道独立解码蓝牙 A2DP 媒体帧封装加扰XOR 字节重排前 8 字节逆重排 XOR避免固定模式辅助同步4.2 与其他音频编码标准的对比特性LHDC V5LDACAAC-LCMP3变换类型LD-MDCTMDCTMDCTMDCT 多相滤波器组帧长5ms 固定可配1024/960 采样576 采样感知模型SNSADPCM 包络混合 SNS心理声学模型 2心理声学模型 1熵编码FAC 算术 Rice霍夫曼 Rice霍夫曼霍夫曼声道编码独立 L/R独立 L/R M/SM/S 强度立体声M/S 强度立体声最大码率1 Mbps990 kbps320 kbps320 kbps最大采样率192 kHz96 kHz96 kHz48 kHz最大位深24 bit32 bit24 bit16 bit4.3 设计亮点低延迟5ms 固定帧长 LD-MDCT端到端延迟远低于传统蓝牙编码高分辨率支持最高 192kHz/24bit覆盖 Hi-Res Audio 标准码率自适应13 档码率 Auto 模式可根据蓝牙链路质量动态调整比特精确可移植C99 实现无 OS 依赖定点编码器确保跨平台比特精确内存高效解码器分离式工作区分配最大单块 8KB适合 ESP32 等资源受限平台鲁棒性设计解扰选择器自动重试 错误隐藏应对蓝牙传输中的误码4.4 复杂度分析ESP32 240MHz96kHz/24bit解码阶段占比说明熵解码FAC Rice~38%最耗时每符号范围解码 模型更新IMDCT~25%FFT-based 快速变换尾数 SNS 逆量化~20%逐系数操作重叠相加 输出~17%加窗 交织 缩放每声道每帧约 1.2ms双声道 2.4ms远低于 5ms 帧间隔单核即可实时解码。五、参考源码文件索引编码器LHDC-V5-Encoder/文件大小功能include/lhdcv5_enc.h7.3KB公共 API 定义src/lhdcv5_int.h16.7KB内部数据结构、常量、函数声明src/lhdcv5_process.c46.6KB核心编码流程量化、码率控制、符号生成、比特打包src/lhdcv5_api.c24.4KB公共 API 实现、帧队列管理src/lhdcv5_fft.c16.0KB定点 FFTKISS FFT 衍生src/lhdcv5_freq.c6.2KB频率变换MDCT顶层操作src/lhdcv5_arith.c6.1KB自适应算术编码器src/lhdcv5_header.c6.2KB帧头处理src/lhdcv5_bitout.c3.2KB比特流输出器src/lhdcv5_tables.c2.8KB静态查找表src/lhdcv5_workspace.c3.6KB工作区管理src/lhdcv5_cirbuf.c1.9KB环形缓冲区src/lhdcv5_level.c2.9KB量化电平表src/lhdcv5_math.c2.3KB数学辅助函数解码器LHDC-V5-Decoder/decoder/文件大小功能lhdc_dec.c74.1KB核心解码流程帧解析、声道解码、输出缩放、错误隐藏lhdc_dec.h5.3KB公共 API 定义lhdc_dec_internal.h5.2KB解码器内部结构lhdc_entropy_dec.c18.4KBFAC 范围解码器 Rice 商解码lhdc_imdct.c39.1KB快速逆 MDCTFFT-based480/960/1920lhdc_sns_synth.c13.1KBSNS 参数解码 频谱合成lhdc_tables.c63.8KB频带配置、KBD 窗、比特率表lhdc_bit_reader.c2.5KB64-bit 缓存 MSB-first 比特读取器lhdc_diag_config.c2.5KB运行时诊断配置