• 开源LC3编解码器测试Demo


    1.介绍

    本文开源LC3编解码器实现来自于Zephyr项目下的一个模块,github仓库:

    https://github.com/zephyrproject-rtos/liblc3codec

    2.使用 

    使用本demo只需复制test.c和Makefile到clone下来的文件夹内,使用的测试文件名为test_48K_16.pcm,编码后的文件名为encodedata,解码后的文件名为decode.pcm

    音频测试文件格式为:

    如果你想使用自己的音频文件测试,请根据实际文件修改代码。 

    3.修改配置

     

    3.1PCM格式

    本库LC3支持两种格式:

    16bit格式

    LC3_PCM_FORMAT_S16

    24bit格式

    LC3_PCM_FORMAT_S24

    16bit格式下每个采样占用2个字节,24bit没使用过,但是每个采样应该占用4个字节。

    3.2帧长

    通常单帧音频长10ms,也支持7.5ms(应该是为了兼容经典蓝牙音频)

    3.3采样率

    采样率支持 8000, 16000, 24000, 32000, 48000。正常LC3应该还支持44.1KHz的采样率,但是笔者发现官方测试demo中把44100注释掉了,不知是否本库还未支持,建议先不要用44100测试。

    3.4编码输出字节

    范围是20~400,但是BAP其实规定了一些固定规格,如下图所示:

    本demo中使用120字节,也就是单帧被编码为120字节。

    4.代码

    4.1test.c

    1. #include "include/lc3.h"
    2. #include <stdlib.h>
    3. #include <string.h>
    4. #include <stdio.h>
    5. #include <sys/types.h>
    6. #include <sys/stat.h>
    7. #include <fcntl.h>
    8. #include <unistd.h>
    9. int main(int argc,char *argv[])
    10. {
    11. //PCM格式
    12. enum lc3_pcm_format pcmFormat = LC3_PCM_FORMAT_S16;
    13. //帧长10ms
    14. int dtUs = 10000;
    15. //采样率48K
    16. int srHz =48000;
    17. //单帧编码后输出字节数
    18. uint16_t output_byte_count = 120;
    19. //编码器需占用缓存大小
    20. unsigned encodeSize = lc3_encoder_size(dtUs, srHz);
    21. //解码器需占用缓存大小
    22. unsigned decodeSize = lc3_decoder_size(dtUs, srHz);
    23. //单帧的采样数
    24. uint16_t sampleOfFrames = lc3_frame_samples(dtUs, srHz);
    25. //单帧字节数,一个采样占用两个字节
    26. uint16_t bytesOfFrames = sampleOfFrames*2;
    27. //编码器缓存
    28. void* encMem = NULL;
    29. //解码器缓存
    30. void* decMem = NULL;
    31. //输入文件的文件描述符
    32. int inFd = -1;
    33. //输出文件的文件描述符
    34. int outFd = -1;
    35. //输入帧缓冲
    36. unsigned char *inBuf = (unsigned char *)malloc(bytesOfFrames);
    37. //输出帧缓冲
    38. unsigned char *outBuf = (unsigned char *)malloc(bytesOfFrames);
    39. encMem = malloc(encodeSize);
    40. /* 编码 */
    41. lc3_encoder_t lc3_encoder = lc3_setup_encoder(dtUs, srHz, 0, encMem);
    42. if((inFd = open("./test_48K_16.pcm", O_RDONLY))<=0)
    43. {
    44. printf("encode open inFd err\n");
    45. return -1;
    46. }
    47. if((outFd = open("./encodedata", O_CREAT|O_WRONLY|O_TRUNC, 0666))<=0)
    48. {
    49. printf("encode open outFd err\n");
    50. return -1;
    51. }
    52. while(read(inFd,inBuf,bytesOfFrames)==bytesOfFrames)
    53. {
    54. lc3_encode(lc3_encoder, pcmFormat, (const int16_t*)inBuf, 1,output_byte_count, outBuf);
    55. // memcpy(outBuf,inBuf,bytesOfFrames);
    56. if(write(outFd,outBuf,output_byte_count)!=output_byte_count)
    57. {
    58. printf("encode write err\n");
    59. break;
    60. }
    61. memset(inBuf,0,bytesOfFrames);
    62. memset(outBuf,0,bytesOfFrames);
    63. }
    64. free(encMem);
    65. encMem = NULL;
    66. close(inFd);
    67. close(outFd);
    68. /* 解码 */
    69. decMem = malloc(decodeSize);
    70. lc3_decoder_t lc3_decoder = lc3_setup_decoder(dtUs, srHz, 0, decMem);
    71. if((inFd = open("./encodedata", O_RDONLY))<=0)
    72. {
    73. printf("decode open inFd err\n");
    74. return -1;
    75. }
    76. if((outFd = open("./decode.pcm", O_CREAT|O_WRONLY|O_TRUNC, 0666))<=0)
    77. {
    78. printf("decode open outFd err\n");
    79. return -1;
    80. }
    81. while(read(inFd,inBuf,output_byte_count)==output_byte_count)
    82. {
    83. lc3_decode(lc3_decoder, inBuf, output_byte_count, pcmFormat,outBuf, 1);
    84. if(write(outFd,outBuf,bytesOfFrames)!=bytesOfFrames)
    85. {
    86. printf("decode write err\n");
    87. break;
    88. }
    89. memset(inBuf,0,bytesOfFrames);
    90. memset(outBuf,0,bytesOfFrames);
    91. }
    92. free(decMem);
    93. close(inFd);
    94. close(outFd);
    95. free(inBuf);
    96. free(outBuf);
    97. inBuf = NULL;
    98. outBuf = NULL;
    99. return 0;
    100. }

    4.2Makefile

    1. TARGET = test
    2. BUILD_DIR = build
    3. CC = gcc
    4. CFLAGS = $(INCLUDES)
    5. OFLAGS = -lm
    6. SOURCES = \
    7. test.c \
    8. $(wildcard ./src/*.c)
    9. INCLUDES = \
    10. -Iinclude/ \
    11. -Isrc/
    12. FILE_PATH = \
    13. ./ \
    14. ./src/
    15. TEST_OBJECTS = $(addprefix $(BUILD_DIR)/,$(notdir $(SOURCES:.c=.o)))
    16. vpath %.c $(FILE_PATH)
    17. all: $(TARGET)
    18. $(BUILD_DIR)/%.o: %.c Makefile | $(BUILD_DIR)
    19. $(CC) -c $(CFLAGS) $< -o $@
    20. $(TARGET) : $(TEST_OBJECTS)
    21. $(CC) $(CFLAGS) $(TEST_OBJECTS) $(OFLAGS) -o $@
    22. $(BUILD_DIR):
    23. mkdir $@
    24. clean:
    25. rm -rf $(BUILD_DIR)
    26. rm $(TARGET)

    懒人专用链接:

    https://github.com/CXsCode/lc3test

    官方LC3文档:

    Low Complexity Communication Codec 1.0 – Bluetooth® Technology Website

    一个LC3plus实现:

    ETSI提供的开源LC3plus实现:

    https://www.etsi.org/deliver/etsi_ts/103600_103699/103634/01.03.01_60/ts_103634v010301p0.zip

    实现方案:

    https://www.etsi.org/deliver/etsi_ts/103600_103699/103634/01.03.01_60/ts_103634v010301p.pdf

  • 相关阅读:
    DBCO-(CH2)3-Acid,CAS:1207355-31-4
    基于thinkphp校园二手交易网站#毕业设计
    乐鑫面试流程
    R 语言的安装教程
    Delphi 取消与设置CDS本地排序
    蓝牙耳机销量排行榜2022,性价比高实用的蓝牙耳机品牌
    Node.js之path路径模块
    pixhawk飞控和自习开发的stm32芯片通讯问题
    windows安装wsl
    Pytorch知识点学习
  • 原文地址:https://blog.csdn.net/qwe5959798/article/details/125526369