使用C语言扩展Python(三)
上一篇中我们已经了解如何在Python程序和C模块之间进行值的相互传递,现在我们来进入实作阶段,看看如何将一个C语言开发的开源mp3编解码库LAME包装为一个Python下可以使用的扩展模块。
首先去http://lame.sourceforge.net/download.php下载LAME的源代码,然后切换到root用户编译源代码,
./configure
make
make install
make
make install
安装完成后你可以在/usr/local/include/lame目录下找到lame.h头文件,我们在后面的demo程序中会include它的,下面就是一个非常简单的lame示例程序lame_test.c:

#include <stdio.h>
#include <stdlib.h>
#include <lame.h>
#define INBUFSIZE 4096
#define MP3BUFSIZE (int) (1.25 * INBUFSIZE) + 7200
int encode(char* inPath, char* outPath) {
int status = 0;
lame_global_flags* gfp;
int ret_code;
FILE* infp;
FILE* outfp;
short* input_buffer;
int input_samples;
char* mp3_buffer;
int mp3_bytes;
gfp = lame_init();
if (gfp == NULL) {
printf("lame_init failed\n");
status = -1;
goto exit;
}
ret_code = lame_init_params(gfp);
if (ret_code < 0) {
printf("lame_init_params returned %d\n",ret_code);
status = -1;
goto close_lame;
}
infp = fopen(inPath, "rb");
outfp = fopen(outPath, "wb");
input_buffer = (short*)malloc(INBUFSIZE*2);
mp3_buffer = (char*)malloc(MP3BUFSIZE);
do{
input_samples = fread(input_buffer, 2, INBUFSIZE, infp);
mp3_bytes = lame_encode_buffer_interleaved(gfp, input_buffer,input_samples/2, mp3_buffer, MP3BUFSIZE);
if (mp3_bytes < 0) {
printf("lame_encode_buffer_interleaved returned %d\n", mp3_bytes);
status = -1;
goto free_buffers;
} else if(mp3_bytes > 0) {
fwrite(mp3_buffer, 1, mp3_bytes, outfp);
}
}while (input_samples == INBUFSIZE);
mp3_bytes = lame_encode_flush(gfp, mp3_buffer, sizeof(mp3_buffer));
if (mp3_bytes > 0) {
printf("writing %d mp3 bytes\n", mp3_bytes);
fwrite(mp3_buffer, 1, mp3_bytes, outfp);
}
free_buffers:
free(mp3_buffer);
free(input_buffer);
fclose(outfp);
fclose(infp);
close_lame:
lame_close(gfp);
exit:
return status;
}
int main(int argc, char** argv) {
if (argc < 3) {
printf("usage: lame_test rawinfile mp3outfile\n");
}
encode(argv[1], argv[2]);
return 0;
}
#include <stdlib.h>
#include <lame.h>
#define INBUFSIZE 4096
#define MP3BUFSIZE (int) (1.25 * INBUFSIZE) + 7200
int encode(char* inPath, char* outPath) {
int status = 0;
lame_global_flags* gfp;
int ret_code;
FILE* infp;
FILE* outfp;
short* input_buffer;
int input_samples;
char* mp3_buffer;
int mp3_bytes;
gfp = lame_init();
if (gfp == NULL) {
printf("lame_init failed\n");
status = -1;
goto exit;
}
ret_code = lame_init_params(gfp);
if (ret_code < 0) {
printf("lame_init_params returned %d\n",ret_code);
status = -1;
goto close_lame;
}
infp = fopen(inPath, "rb");
outfp = fopen(outPath, "wb");
input_buffer = (short*)malloc(INBUFSIZE*2);
mp3_buffer = (char*)malloc(MP3BUFSIZE);
do{
input_samples = fread(input_buffer, 2, INBUFSIZE, infp);
mp3_bytes = lame_encode_buffer_interleaved(gfp, input_buffer,input_samples/2, mp3_buffer, MP3BUFSIZE);
if (mp3_bytes < 0) {
printf("lame_encode_buffer_interleaved returned %d\n", mp3_bytes);
status = -1;
goto free_buffers;
} else if(mp3_bytes > 0) {
fwrite(mp3_buffer, 1, mp3_bytes, outfp);
}
}while (input_samples == INBUFSIZE);
mp3_bytes = lame_encode_flush(gfp, mp3_buffer, sizeof(mp3_buffer));
if (mp3_bytes > 0) {
printf("writing %d mp3 bytes\n", mp3_bytes);
fwrite(mp3_buffer, 1, mp3_bytes, outfp);
}
free_buffers:
free(mp3_buffer);
free(input_buffer);
fclose(outfp);
fclose(infp);
close_lame:
lame_close(gfp);
exit:
return status;
}
int main(int argc, char** argv) {
if (argc < 3) {
printf("usage: lame_test rawinfile mp3outfile\n");
}
encode(argv[1], argv[2]);
return 0;
}
编译步骤:
gcc -I /usr/local/include/lame lame_test.c -lmp3lame -o lame_test
试验准备:
首先需要一个test.wav文件,先安装sox来将wav文件转为raw格式的数据:
sudo apt-get install sox
sox test.wav -t raw test.raw
sox test.wav -t raw test.raw
然后执行lame_test来对其进行mp3编码:
./lame_test ./test.raw ./test.mp3
好了,现在我们要在这个c程序的基础上将其包装为一个Python扩展模块。下面的pylame.c就是简单地调用lame_test.c中定义的encode方法,然后通过它对外部的python程序提高mp3编码的服务

#include <Python.h>
#include <lame.h>
int encode(char* ,char*);
static PyObject * pylame_encode(PyObject* self, PyObject* args) {
int status;
char* inPath;
char* outPath;
if (!PyArg_ParseTuple(args, "ss", &inPath, &outPath)) {
return NULL;
}
status = encode(inPath, outPath);
return Py_BuildValue("i", status);
}
static PyMethodDef pylame_methods[] = {
{"encode", pylame_encode, METH_VARARGS, NULL},
{NULL, NULL, 0, NULL}
};
PyMODINIT_FUNC initpylame() {
Py_InitModule3("pylame", pylame_methods, "an simple lame module.");
}
#include <lame.h>
int encode(char* ,char*);
static PyObject * pylame_encode(PyObject* self, PyObject* args) {
int status;
char* inPath;
char* outPath;
if (!PyArg_ParseTuple(args, "ss", &inPath, &outPath)) {
return NULL;
}
status = encode(inPath, outPath);
return Py_BuildValue("i", status);
}
static PyMethodDef pylame_methods[] = {
{"encode", pylame_encode, METH_VARARGS, NULL},
{NULL, NULL, 0, NULL}
};
PyMODINIT_FUNC initpylame() {
Py_InitModule3("pylame", pylame_methods, "an simple lame module.");
}
模块编译步骤:
gcc -shared -I /usr/include/python2.6 -I /usr/local/include/lame/ pylame.c lame_test.c -lmp3lame -o pylame.so
ok,现在lame扩展模块已经封装好了,可以到python程序中进行调用了。在pylame.so所在目录下新建一个python文件lame1.py代码如下:
import pylame
if __name__ == '__main__':
inPath = './test.raw'
outPath = './test.mp3'
pylame.encode(inPath, outPath)
if __name__ == '__main__':
inPath = './test.raw'
outPath = './test.mp3'
pylame.encode(inPath, outPath)
编译执行:
python ./lame1.py
你会发现生成了一个test.mp3,打开听听看是否是你想要的歌曲呢,呵呵。。。
作者:洞庭散人
出处:http://phinecos.cnblogs.com/
本博客遵从Creative Commons Attribution 3.0 License,若用于非商业目的,您可以自由转载,但请保留原作者信息和文章链接URL。
posted on 2010-05-22 18:00 Phinecos(洞庭散人) 阅读(5082) 评论(0) 编辑 收藏 举报
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· .NET周刊【3月第1期 2025-03-02】
· 分享 3 个 .NET 开源的文件压缩处理库,助力快速实现文件压缩解压功能!
· [AI/GPT/综述] AI Agent的设计模式综述
2009-05-22 笔试题练习(四)