Привязка кодека Python Silk поддерживает голосовой кодек WeChat
шелк: питон + шелк
Связанные проекты: weixin-wxposed-silk-voice
pip install pilk
SILK — это формат кодирования речи, разработанный Skype . Последняя версия, доступная в Интернете, была выпущена в 2012 году.
Исходный код SILK загружен в релиз, включая документацию по спецификациям.
Голосовая поддержка Tencent осуществляется с помощью Silk-v3-декодера.
Релиз также содержит перекомпилированную x64-win версию Silk-v3-декодера, поддерживает китайский язык, исходный код.
Tencent здесь имеет в виду голос, принимая в качестве примера только голос WeChat.
b'#!SILK_V3'
и заканчивается b'xFFxFF'
с голосовыми данными в середине.b'x02'
в начало стандартного файла SILK , удаляет b'xFFxFF'
в конце и оставляет середину неизмененной.все вместе называются голосовыми файлами
Голосовые данные делятся на множество независимых кадров . Первые два байта каждого кадра хранят размер остальных данных кадра . Каждый кадр по умолчанию хранит 20 мс аудиоданных.
На основании этого можно написать функцию для получения длительности голосового файла (эта функция включена в Pilk )
def get_duration ( silk_path : str , frame_ms : int = 20 ) -> int :
"""获取 silk 文件持续时间,单位:ms"""
with open ( silk_path , 'rb' ) as silk :
tencent = False
if silk . read ( 1 ) == b' x02 ' :
tencent = True
silk . seek ( 0 )
if tencent :
silk . seek ( 10 )
else :
silk . seek ( 9 )
i = 0
while True :
size = silk . read ( 2 )
if len ( size ) != 2 :
break
i += 1
size = size [ 0 ] + size [ 1 ] * 16
silk . seek ( silk . tell () + size )
return i * frame_ms
Согласно спецификации формата SILK , frame_ms может быть 20, 40, 60, 80, 100
Подробности можно найти в комментариях к документации API в IDE.
Перед использованием Pilk вам необходимо знать, что преобразование между аудиофайлами mp3, aac, m4a, flac, wav, ...
и голосовыми файлами выполняется с помощью необработанных данных PCM.
Конкретное соотношение преобразования: аудиофайл ⇔ PCM ⇔ голосовой файл.
Аудио (видео) файлы ➜ PCM
Конечно, с ffmpeg вам сначала нужно иметь ffmpeg.
ffmpeg -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 data
ffmpeg -y -i mv.mp4 -vn -ar 44100 -ac 1 -f s16le mv.pcm
ffmpeg -y -i music.mp3 -ar 44100 -ac 1 -f s16le music.pcm
PCM ➜ Аудиофайлы
ffmpeg -y -f s16le -ar <采样率> -ac <声道数> -i < PCM输入文件> <音频输出文件>
-f
: это должно быть s16le
, что также определяется SILK.-ar
: То же, что и выше-ac
: смысл тот же, что и выше, значение произвольное.<音频输出文件>
: расширение должно быть точным. Если формат не указан, ffmpeg определит формат, который необходимо вывести, на основе заданного расширения выходного файла.ffmpeg -y -f s16le -ar 16000 -i test.pcm test.mp3
ffmpeg также можно заменить привязкой ffmpeg к python. Рекомендуется изучить PyAV самостоятельно, поэтому я не буду здесь вдаваться в подробности.
После разговора об аудиофайлах ⇔ PCM, следующим шагом будет использование pilk для преобразования голосовых файлов PCM ⇔.
import pilk
# 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 )
import pilk
# pcm_rate 参数必须和 使用 ffmpeg 转 音频 到 PCM 文件时,使用的 `-ar` 参数一致
duration = pilk . decode ( "test.silk" , "test.pcm" )
print ( "语音时间为:" , duration )
Используйте pudub, чтобы зависеть от ffmpeg
import os , pilk
from pydub import AudioSegment
def convert_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 )
return silk_path
Рекомендуется использовать pyav
import os
import av
import pilk
def to_pcm ( in_path : str ) -> tuple [ str , int ]:
"""任意媒体文件转 pcm"""
out_path = os . path . splitext ( in_path )[ 0 ] + '.pcm'
with av . open ( in_path ) as in_container :
in_stream = in_container . streams . audio [ 0 ]
sample_rate = in_stream . codec_context . sample_rate
with av . open ( out_path , 'w' , 's16le' ) as out_container :
out_stream = out_container . add_stream (
'pcm_s16le' ,
rate = sample_rate ,
layout = 'mono'
)
try :
for frame in in_container . decode ( in_stream ):
frame . pts = None
for packet in out_stream . encode ( frame ):
out_container . mux ( packet )
except :
pass
return out_path , sample_rate
def convert_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 )
return silk_path