最近在研究 Python 的 mp3 编解码, 可能是 mp3 格式专利问题,这方面可用并且还在维护的 Python 库没发现几个
试了一下 pymedia 倒是可以,但是它官方支持的版本只到 Python 2.4
找了个第三方的 for Python 2.7 版本的, 发现它在 windows 下的实现中输出缓冲区大小写死成 10000 字节,导致解码的实时性差, 努力想把官方工程修改后迁移到 2.7 版本,最后还是放弃了…
也尝试直接用 Lame.exe 用管道收发数据,但是 Windows 下 Python 2.X 貌似不支持管道的异步读写,最后也放弃了 好在我只用考虑 windows 平台,最后通过 ctype 调用 libmp3lame.dll 中的方法实现了我要的功能
代码很简单,只考虑了我需要的音频格式
#coding:utf-8
import time
import ctypes
class LameEncoder():
def __init__(self, sample_rate, channel_count, bit_rate):
self.dll = ctypes.CDLL("libmp3lame.dll")
self.lame = self.dll.lame_init()
self.dll.lame_set_in_samplerate(self.lame, sample_rate);
self.dll.lame_set_num_channels(self.lame, channel_count);
self.dll.lame_set_brate(self.lame, bit_rate);
self.dll.lame_set_quality(self.lame, 3);
self.dll.lame_init_params(self.lame);
def encode(self, pcm_data):
sample_count = len(pcm_data) /2
output_buff_len = int(1.25 * sample_count + 7200)
output_buff = ctypes.create_string_buffer(output_buff_len)
output_size = self.dll.lame_encode_buffer(self.lame, ctypes.create_string_buffer(pcm_data), 0, sample_count, output_buff, output_buff_len);
return output_buff.raw[:output_size]
class LameDecoder():
def __init__(self, sample_rate, channel_count, bit_rate):
self.dll = ctypes.CDLL("libmp3lame.dll")
self.lame = self.dll.lame_init()
self.hip = self.dll.hip_decode_init()
self.dll.lame_set_in_samplerate(self.lame, sample_rate)
self.dll.lame_set_num_channels(self.lame, channel_count)
self.dll.lame_set_brate(self.lame, bit_rate)
self.dll.lame_set_mode(self.lame, 3)
self.dll.lame_set_quality(self.lame, 3)
self.dll.lame_init_params(self.lame)
self.dll.lame_get_framesize(self.lame)
def decode(self, mp3_data):
output_buff_len = self.dll.lame_get_framesize(self.lame) * 2
output_buff = ctypes.create_string_buffer(output_buff_len)
output_size = self.dll.hip_decode1(self.hip, ctypes.create_string_buffer(mp3_data), len(mp3_data), output_buff, 0);
return output_buff.raw[:output_size * 2]
def flush(self):
output_buff_len = self.dll.lame_get_framesize(self.lame) * 2
output_buff = ctypes.create_string_buffer(output_buff_len)
output_size = self.dll.hip_decode1(self.hip, ctypes.create_string_buffer(""), 0, output_buff, 0);
return output_buff.raw[:output_size * 2]
if __name__ == "__main__":
def test_enc():
print "test encode ..."
lame = LameEncoder(8000, 1, 8)
input_file = open("1.pcm", "rb")
output_file = open("1.mp3", "wb+")
while 1:
data = input_file.read(256)
if data:
output = lame.encode(data)
output_file.write(output)
else:
break
input_file.close()
output_file.close()
print "test encode done"
def test_dec():
print "test decode ..."
lame = LameDecoder(8000, 1, 8)
input_file = open("1.mp3", "rb")
output_file = open("2.pcm", "wb+")
while 1:
data = input_file.read(512)
if data:
output = lame.decode(data)
if output:
output_file.write(output)
while 1:
output = lame.flush()
if output:
output_file.write(output)
else:
break
else:
break
input_file.close()
output_file.close()
print "test decode done"
test_enc()
test_dec()