Package: pilk
pilkpython silk codec binding 支持微信语音编解码pilk: python + silk关联项目:weixin-wxposed-silk-voice安装pipinstallpilk介绍与说明SILK是一种语音编码格式，由Skype公司研发，网上可找到的最新版本是 2012 发布的。SILK原始代码已上传到Release, 包含规范文档Tencent系语音支持来自silk-v3-decoderRelease中也包含silk-v3-decoder重编译的x64-win版本，支持中文，源代码SILK编码格式 和Tencent系语音的关系：此处Tencent系语音，仅以微信语音为例标准SILK文件以b'#!SILK_V3'开始，以b'\xFF\xFF'结束，中间为语音数据微信语音文件在标准SILK文件的开头插入了b'\x02'，去除了结尾的b'\xFF\xFF'，中间不变已下统称为语音文件语音数据语音数据分为很多个独立frame，每个frame开头两字节存储剩余frame数据的大小，每个frame默认存储20ms的音频数据据此可写出获取语音文件持续时间(duration) 的函数（此函数pilk中已包含）defget_duration(silk_path:str,frame_ms:int=20)->int:"""获取 silk 文件持续时间，单位：ms"""withopen(silk_path,'rb')assilk:tencent=Falseifsilk.read(1)==b'\x02':tencent=Truesilk.seek(0)iftencent:silk.seek(10)else:silk.seek(9)i=0whileTrue:size=silk.read(2)iflen(size)!=2:breaksize=size[0]+size[1]<<8ifnottencentandsize==0xffff:breaki+=1silk.seek(silk.tell()+size)returni*frame_ms根据SILK格式规范，frame_ms可为20, 40, 60, 80, 100快速入门详情请在 IDE 中查看 API 文档注释在使用pilk之前，你还需清楚音频文件mp3, aac, m4a, flac, wav, ...与语音文件之间的转换是借助PCM raw
data完成的具体转换关系：音频文件 ⇔ PCM ⇔ 语音文件音(视)频文件 ➜ PCM借助 ffmpeg，你当然需要先有ffmpegffmpeg -y -i<音(视)频输入文件>-vn -ar<采样率>-ac 1 -f s16le<PCM输出文件>-y: 可加可不加，表示 <PCM输出文件> 已存在时不询问，直接覆盖-i: 没啥好说的，固定的，后接 <音(视)频输入文件>-vn: 表示不处理视频数据，建议添加，虽然不加也不会处理视频数据（视频数据不存在转PCM的说法），但可能会打印警告-ar: 设置采样率，可选的值是 [8000, 12000, 16000, 24000, 32000, 44100, 48000], 这里你可以直接理解为声音质量-ac: 设置声道数，在这里必须为1，这是由SILK决定的-f: 表示强制转换为指定的格式，一般来说必须为s16le, 表示16-bit short integer Little-Endian dataexample1:ffmpeg -y -i mv.mp4 -vn -ar 44100 -ac 1 -f s16le mv.pcmexample2:ffmpeg -y -i music.mp3 -ar 44100 -ac 1 -f s16le music.pcmPCM ➜ 音频文件ffmpeg -y -f s16le -i<PCM输入文件>-ar<采样率>-ac<声道数><音频输出文件>-f: 这里必须为s16le, 同样也是由SILK决定的-ar: 同上-ac: 含义同上，值随意<音频输出文件>: 扩展名要准确，没有指定格式时，ffmpeg会根据给定的输出文件扩展名来判断需要输出的格式example3:ffmpeg -y -f s16le -i test.pcm test.mp3ffmpeg 也可以使用 python ffmpeg binding 替换，推荐PyAV大家自行研究，这里不再啰嗦。讲完了 音频文件 ⇔ PCM，接下来就是用pilk进行 PCM ⇔ 语音文件 互转silk 编码importpilk# pcm_rate 参数必须和 使用 ffmpeg 转 音频 到 PCM 文件时，使用的 `-ar` 参数一致# pcm_rate 参数必须和 使用 ffmpeg 转 音频 到 PCM 文件时，使用的 `-ar` 参数一致# pcm_rate 参数必须和 使用 ffmpeg 转 音频 到 PCM 文件时，使用的 `-ar` 参数一致duration=pilk.encode("test.pcm","test.silk",pcm_rate=44100,tencent=True)print("语音时间为:",duration)silk 解码importpilk# pcm_rate 参数必须和 使用 ffmpeg 转 音频 到 PCM 文件时，使用的 `-ar` 参数一致duration=pilk.decode("test.silk","test.pcm")print("语音时间为:",duration)使用 Python 转任意媒体文件到 SILK使用pudub依赖ffmpegimportos,pilkfrompydubimportAudioSegmentdefconvert_to_silk(media_path:str)->str:"""将输入的媒体文件转出为 silk, 并返回silk路径"""media=AudioSegment.from_file(media_path)pcm_path=os.path.basename(media_path)pcm_path=os.path.splitext(pcm_path)[0]silk_path=pcm_path+'.silk'pcm_path+='.pcm'media.export(pcm_path,'s16le',parameters=['-ar',str(media.frame_rate),'-ac','1']).close()pilk.encode(pcm_path,silk_path,pcm_rate=media.frame_rate,tencent=True)returnsilk_path使用pyav推荐importosimportavimportpilkdefto_pcm(in_path:str)->tuple[str,int]:"""任意媒体文件转 pcm"""out_path=os.path.splitext(in_path)[0]+'.pcm'withav.open(in_path)asin_container:in_stream=in_container.streams.audio[0]sample_rate=in_stream.codec_context.sample_ratewithav.open(out_path,'w','s16le')asout_container:out_stream=out_container.add_stream('pcm_s16le',rate=sample_rate,layout='mono')try:forframeinin_container.decode(in_stream):frame.pts=Noneforpacketinout_stream.encode(frame):out_container.mux(packet)except:passreturnout_path,sample_ratedefconvert_to_silk(media_path:str)->str:"""任意媒体文件转 silk, 返回silk路径"""pcm_path,sample_rate=to_pcm(media_path)silk_path=os.path.splitext(pcm_path)[0]+'.silk'pilk.encode(pcm_path,silk_path,pcm_rate=sample_rate,tencent=True)os.remove(pcm_path)returnsilk_path