找回密码
 立即注册

使用微信账号登录

只需一步,快速开始

查看: 24|回复: 6

[经典蓝牙协议栈] 咨询LHDCV5解码算法

[复制链接]
连续签到天数:1天
签到总天数:1天
签到总奖励:5金币
发表于 昨天 18:43 | 显示全部楼层 |阅读模式
我正在制作ESP32蓝牙播放器,根据Github开源的解码器已经在ESP32上成功跑通了AAC、aptX[HD]、LDAC,然后我试图在ESP32上实现LHDCV5,但是注意到目前似乎没人开源过LHDCV5的解码器,我只找到了BES的SDK(包含LHDCV5静态库“.a”文件及对应的api头文件)、AOSP的LHDCV5解码器(缺lhdcv5_util_dec.c文件)、小米手机内置的LHDCV5动态库“.so”文件。
因为我不懂逆向,同时注意到AOSP和ESP32的bluedroid架构几乎一样,且其依赖的外部库只是缺一个源文件,所以我从AOSP移植LHDCV5解码器到ESP-IDF,目前这部分工作已经完成,我将他们开源在Github的liblhdc-collections/tree/main/ESP-IDF/bluedroid;它们包含下列文件:
  1. └─bluedroid
  2.         ├─api
  3.         │  └─include
  4.         │          esp_a2dp_api.h
  5.         │
  6.         ├─external
  7.         │  └─liblhdcv5dec
  8.         │      │  CMakeLists.txt
  9.         │      │  release_note
  10.         │      │
  11.         │      ├─inc
  12.         │      │      lhdcv5BT_dec.h
  13.         │      │
  14.         │      ├─include
  15.         │      │      lhdcv5_util_dec.h
  16.         │      │
  17.         │      └─src
  18.         │              lhdcv5BT_dec.c
  19.         │              lhdcv5_util_dec.c
  20.         │
  21.         └─stack
  22.                 ├─a2dp
  23.                 │      a2dp_vendor.c
  24.                 │      a2dp_vendor_lhdcv5.c
  25.                 │      a2dp_vendor_lhdcv5_decoder.c
  26.                 │
  27.                 └─include
  28.                         └─stack
  29.                                         a2dp_vendor.h
  30.                                         a2dp_vendor_lhdcv5.h
  31.                                         a2dp_vendor_lhdcv5_constants.h
  32.                                         a2dp_vendor_lhdcv5_decoder.h
  33.                                         a2dp_vendor_lhdc_constants.h
复制代码


因为AOSP需要使用liblhdcv5外部库,所以移植到IDF的LHDCV5解码器也是,因此我也同步移植了AOSP的LHDCV5外部库,但是正如前面所说,这个外部库缺乏lhdcv5_util_dec.c的实现,因此我依据lhdcv5_util_dec.h中声明的函数和使用的变量逆推了一个lhdcv5_util_dec.c,但是其中的关键部分——LHDCV5解码算法我无法得知,我搜索不到任何与LHDC编码算法相关的文档/代码。

所以我在lhdcv5_util_dec.c的LHDCV5解码函数“int32_t lhdcv5_util_dec_process(uint8_t * pOutBuf, uint8_t * pInput, uint32_t InLen, uint32_t *OutLen)”中调用了正弦发生器进行伪解码,实际输出的是正弦发生器产生的标准音。对于这个liblhdcv5dec,我也将其开源在Github:liblhdcv5dec,完整内容可以在这个Github仓库看到,其中的伪解码函数如下:
  1. int32_t lhdcv5_util_dec_process(uint8_t * pOutBuf, uint8_t * pInput, uint32_t InLen, uint32_t *OutLen)
  2. {
  3.     if (!decoder_initialized)
  4.         return LHDCV5_UTIL_DEC_ERROR_NO_INIT;
  5.     if (!pInput || !pOutBuf || !OutLen)
  6.         return LHDCV5_UTIL_DEC_ERROR_PARAM;

  7.     // 计算样本大小和帧样本数 - 使用输出位深
  8.     uint32_t sample_bytes = (g_output_bit_per_sample + 7) / 8;
  9.     uint32_t frame_samples = 256;  // LHDC V5典型每声道样本数
  10.     uint32_t channels = (g_channel_type == LHDC_OUTPUT_STEREO) ? 2 : 1;
  11.     *OutLen = frame_samples * sample_bytes * channels;

  12.     // 生成32位正弦波PCM数据,然后根据需要转换
  13.     int32_t *out_32 = (int32_t *)pOutBuf;
  14.     int16_t *out_16 = (int16_t *)pOutBuf;
  15.     uint8_t *out_24 = pOutBuf;  // 24位特殊处理,存储为3字节

  16.     for (uint32_t i = 0; i < frame_samples; i++) {
  17.         // 生成左声道样本(始终生成32位样本)
  18.         int32_t sample_32 = generate_sine_sample(g_sampleRate, 32);
  19.         
  20.         // 根据输出位深转换
  21.         switch (g_output_bit_per_sample) {
  22.             case 16:
  23.                 // 从32位转换到16位
  24.                 int16_t sample_16 = (int16_t)(sample_32 >> 16);
  25.                 out_16[i * 2] = sample_16;  // 左声道
  26.                 if (channels == 2) {
  27.                     // 右声道使用稍作修改的样本,制造立体声效果
  28.                     out_16[i * 2 + 1] = (int16_t)(sample_16 * 0.9f); // 右声道
  29.                 }
  30.                 break;
  31.                
  32.             case 24:
  33.                 // 从32位转换到24位
  34.                 int32_t sample_24 = sample_32 >> 8; // 右移8位得到24位

  35.                 // 正确处理有符号24位样本
  36.                 int32_t clamped_sample = sample_24;
  37.                 // 确保样本在24位范围内
  38.                 if (clamped_sample > 8388607) clamped_sample = 8388607;
  39.                 if (clamped_sample < -8388608) clamped_sample = -8388608;
  40.                
  41.                 // 转换为无符号偏移量(+8388608)以便正确存储符号位
  42.                 uint32_t u_sample = clamped_sample + 8388608;
  43.                
  44.                 out_24[i * 6] = u_sample & 0xFF;         // 低8位
  45.                 out_24[i * 6 + 1] = (u_sample >> 8) & 0xFF;  // 中8位
  46.                 out_24[i * 6 + 2] = (u_sample >> 16) & 0xFF; // 高8位
  47.                
  48.                 if (channels == 2) {
  49.                     int32_t right_sample = (int32_t)(sample_24 * 0.9f);
  50.                     int32_t clamped_right = right_sample;
  51.                     if (clamped_right > 8388607) clamped_right = 8388607;
  52.                     if (clamped_right < -8388608) clamped_right = -8388608;
  53.                     
  54.                     uint32_t u_right = clamped_right + 8388608;
  55.                     out_24[i * 6 + 3] = u_right & 0xFF;
  56.                     out_24[i * 6 + 4] = (u_right >> 8) & 0xFF;
  57.                     out_24[i * 6 + 5] = (u_right >> 16) & 0xFF;
  58.                 }
  59.                 break;
  60.                
  61.             case 32:
  62.                 out_32[i * 2] = sample_32;  // 左声道
  63.                 if (channels == 2) {
  64.                     out_32[i * 2 + 1] = (int32_t)(sample_32 * 0.9f);  // 右声道
  65.                 }
  66.                 break;
  67.         }
  68.     }

  69.     LOG_DEBUG("%s: Generated sine wave frame - %u samples, %u bits, %u channels, %u bytes",
  70.              __func__, frame_samples, g_bitPerSample, channels, *OutLen);
  71.     return LHDCV5_UTIL_DEC_SUCCESS;
  72. }
复制代码

目前在ESP32上已经可以运行伪解码的LHDCV5了,小米14连接ESP32后,以LHDCV5协商,手机播放音乐时,ESP32上听到的是正弦发生器的标准音。我想知道我该如何获取LHDCV5的解码算法源码?官方肯定是不行了,早段时间发过邮件没理我。注意到论坛的大神@O11111和@O2C14已经在这方面有进展,非常佩服,也注意到有人说还有别的大神也实现了,但我不知道怎么联系,我是新来的小白一个,不知大神们可否与我交流一下,我挺想在ESP32等设备上实现真正的LHDCV5解码,可以有偿(不是太贵都能接受),不白拿资料Github的sprlightning可联系到我,还有我Q是3397935446






本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册  

×
楼主热帖
积分商城 - 让您的金币更有价值!||官方Q群 - 让您的沟通更加及时!
连续签到天数:13天
签到总天数:290天
签到总奖励:6369金币
发表于 昨天 22:51 | 显示全部楼层
虽然没有资料,但是给你大大的赞。
积分商城 - 让您的金币更有价值!||官方Q群 - 让您的沟通更加及时!
回复 支持 反对

使用道具 举报

连续签到天数:1天
签到总天数:1天
签到总奖励:5金币
 楼主| 发表于 昨天 23:54 | 显示全部楼层
jsjj 发表于 2025-11-25 22:51
虽然没有资料,但是给你大大的赞。

哈哈感谢
积分商城 - 让您的金币更有价值!||官方Q群 - 让您的沟通更加及时!
回复 支持 反对

使用道具 举报

连续签到天数:1天
签到总天数:1天
签到总奖励:5金币
 楼主| 发表于 8 小时前 | 显示全部楼层
不知道什么情况,上面写的地址超链接没生效,这里直接把开源地址发出来吧:
1)移植到IDF的liblhdcv5dec源码(伪解码版本):https://github.com/sprlightning/liblhdcv5dec
2)与liblhdcv5dec配套的LHDCV5解码器源码(IDF bluedroid):https://github.com/sprlightning/liblhdc-collections/tree/main/ESP-IDF/bluedroid
3)我收集的所有LHDC方面的资料,包括BES2600IHC、BES2700IHC(含静态库),和Android方面(含64位动态库),也集成了我在使用的IDF内容:https://github.com/sprlightning/liblhdc-collections
积分商城 - 让您的金币更有价值!||官方Q群 - 让您的沟通更加及时!
回复 支持 反对

使用道具 举报

连续签到天数:1天
签到总天数:918天
签到总奖励:16604金币
发表于 7 小时前 | 显示全部楼层
是的,我们开发了 LHDCV5 编码器和解码器,但从未公开发布。我只在 Linux 系统下使用打过补丁的 Pipewire 版本进行了测试。我们计划最终发布,但目前存在一些限制,例如不支持 192 kHz(不过反正也没什么用)或无损编码。
积分商城 - 让您的金币更有价值!||官方Q群 - 让您的沟通更加及时!
回复 支持 反对

使用道具 举报

连续签到天数:1天
签到总天数:1天
签到总奖励:5金币
 楼主| 发表于 4 小时前 | 显示全部楼层
O11111 发表于 2025-11-26 01:13
是的,我们开发了 LHDCV5 编码器和解码器,但从未公开发布。我只在 Linux 系统下使用打过补丁的 Pipewire  ...

感谢大神回复,我对你和O2C14搞定LHDCV5的编解码器算法感到非常钦佩。因为你们计划最终发布,那我就等等,并关注你们的动态
我认为复现LHDCV5的编解码算法应该需要比较好的通信理论基础,我确定我这方面能力不行,可能起不到什么帮助;不过对于LHDCV5的测试我是很期待的,我有支持LHDCV5的XIAOMI14手机和漫步者花再halo space耳机,以及移植codecs的能力,如果大神们有这方面的需求可以找我
此外我有一个疑问,你们已经实现了LHDCV5在低采样率下的编解码,为什么高采样率还不支持?是受限于处理器计算速度?还是什么别的限制?不同采样率情况下编解码算法会有较大差异吗?原谅我的奇怪问题,因为我这方面不是很懂,但是我确实比较好奇~
积分商城 - 让您的金币更有价值!||官方Q群 - 让您的沟通更加及时!
回复 支持 反对

使用道具 举报

连续签到天数:1天
签到总天数:412天
签到总奖励:3227金币
发表于 3 分钟前 | 显示全部楼层
不错不错学习一下
积分商城 - 让您的金币更有价值!||官方Q群 - 让您的沟通更加及时!
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册  

本版积分规则

小黑屋|手机版|我爱蓝牙网 - 52Bluetooth

GMT+8, 2025-11-26 08:59 , Processed in 0.070414 second(s), 16 queries , Gzip On, MemCached On.

Powered by Discuz! X3.5

© 2001-2025 Discuz! Team.

快速回复 返回顶部 返回列表