A ligação do codec de seda python suporta o codec de voz WeChat
pilk: python + seda
Projetos relacionados: weixin-wxposed-silk-voice
pip install pilk
SILK é um formato de codificação de voz desenvolvido pelo Skype . A última versão disponível online foi lançada em 2012.
O código original do SILK foi carregado no Release, incluindo documentos de especificação
O suporte de voz Tencent vem do decodificador silk-v3
A versão também contém a versão x64-win recompilada do decodificador silk-v3, suporta código-fonte chinês
Tencent aqui se refere à voz, tomando apenas a voz do WeChat como exemplo
b'#!SILK_V3'
e termina com b'xFFxFF'
, com dados de voz no meiob'x02'
no início do arquivo SILK padrão, remove b'xFFxFF'
no final e deixa o meio inalterado.são coletivamente chamados de arquivos de voz
Os dados de voz são divididos em muitos quadros independentes. Os primeiros dois bytes de cada quadro armazenam o tamanho dos dados restantes do quadro . Cada quadro armazena 20 ms de dados de áudio por padrão.
Com base nisso, você pode escrever uma função para obter a duração do arquivo de voz (esta função está incluída no 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
De acordo com a especificação do formato SILK , frame_ms pode ser 20, 40, 60, 80, 100
Verifique os comentários da documentação da API no IDE para obter detalhes.
Antes de usar o pilk , você precisa saber que a conversão entre arquivos de áudio mp3, aac, m4a, flac, wav, ...
e arquivos de voz é concluída com a ajuda de dados brutos PCM
Relação de conversão específica: arquivo de áudio ⇔ PCM ⇔ arquivo de voz
Arquivos de áudio (vídeo) ➜ PCM
Com o ffmpeg, é claro que você precisa primeiro ter o ffmpeg
ffmpeg -y -i <音(视)频输入文件> -vn -ar <采样率> -ac 1 -f s16le < PCM输出文件>
-y
: Pode ser adicionado ou não, indicando que <arquivo de saída PCM> não pergunta se já existe, mas o sobrescreve diretamente-i
: Nada a dizer, corrigido, seguido por <arquivo de entrada de áudio (vídeo)>-vn
: Indica que os dados de vídeo não serão processados. Recomenda-se adicioná-los. Embora os dados de vídeo não sejam processados sem adicioná-los (não existe conversão de dados de vídeo para PCM), um aviso pode ser impresso.-ar
: Defina a taxa de amostragem, os valores opcionais são [8000, 12000, 16000, 24000, 32000, 44100, 48000], aqui você pode entender diretamente como a qualidade do som-ac
: Defina o número de canais, que deve ser 1 aqui, que é determinado pelo SILK-f
: significa conversão forçada para o formato especificado, geralmente deve ser s16le , o que significa 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 ➜ Arquivos de áudio
ffmpeg -y -f s16le -ar <采样率> -ac <声道数> -i < PCM输入文件> <音频输出文件>
-f
: Deve ser s16le
, que também é determinado pelo SILK-ar
: O mesmo que acima-ac
: O significado é o mesmo acima, o valor é arbitrário<音频输出文件>
: A extensão deve ser precisa. Quando o formato não for especificado, o ffmpeg determinará o formato que precisa ser gerado com base na extensão do arquivo de saída fornecida.ffmpeg -y -f s16le -ar 16000 -i test.pcm test.mp3
O ffmpeg também pode ser substituído pela ligação python ffmpeg. É recomendável que você estude o PyAV sozinho, por isso não entrarei em detalhes aqui.
Depois de falar sobre arquivos de áudio ⇔ PCM, o próximo passo é usar o pilk para converter arquivos PCM ⇔ de voz.
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 )
Use pudub para depender do 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
Recomendado usando 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