使用C语言扩展Python(四)

INBUFSIZE = 4096
if __name__ == '__main__':
encoder = clame.Encoder('test.mp3')
input = file('test.raw', 'rb')
data = input.read(INBUFSIZE)
while data != '':
encoder.encode(data)
data = input.read(INBUFSIZE)
input.close()
encoder.close()
再来看C扩展模块这一端,下面是完整的代码:

#include <lame.h>
typedef struct {
PyObject_HEAD
FILE* outfp;
lame_global_flags* gfp;
}clame_EncoderObject;
static PyObject* Encoder_new(PyTypeObject* type, PyObject* args, PyObject* kw) {
clame_EncoderObject* self = (clame_EncoderObject* )type->tp_alloc(type, 0);
self->outfp = NULL;
self->gfp = NULL;
return (PyObject*)self;
}
static void Encoder_dealloc(clame_EncoderObject* self) {
if (self->gfp) {
lame_close(self->gfp);
}
if (self->outfp) {
fclose(self->outfp);
}
self->ob_type->tp_free(self);
}
static int Encoder_init(clame_EncoderObject* self, PyObject* args, PyObject* kw) {
char* outPath;
if (!PyArg_ParseTuple(args, "s", &outPath)) {
return -1;
}
if (self->outfp || self->gfp) {
PyErr_SetString(PyExc_Exception, "__init__ already called");
return -1;
}
self->outfp = fopen(outPath, "wb");
self->gfp = lame_init();
lame_init_params(self->gfp);
return 0;
}
static PyObject* Encoder_encode(clame_EncoderObject* self, PyObject* args) {
char* in_buffer;
int in_length;
int mp3_length;
char* mp3_buffer;
int mp3_bytes;
if (!(self->outfp || self->gfp)) {
PyErr_SetString(PyExc_Exception, "encoder not open");
return NULL;
}
if (!PyArg_ParseTuple(args, "s#", &in_buffer, &in_length)) {
return NULL;
}
in_length /= 2;
mp3_length = (int)(1.25 * in_length) + 7200;
mp3_buffer = (char*)malloc(mp3_length);
if (in_length > 0) {
mp3_bytes = lame_encode_buffer_interleaved(self->gfp, (short*)in_buffer, in_length/2, mp3_buffer, mp3_length);
if (mp3_bytes > 0) {
fwrite(mp3_buffer, 1, mp3_bytes, self->outfp);
}
}
free(mp3_buffer);
Py_RETURN_NONE;
}
static PyObject* Encoder_close(clame_EncoderObject* self) {
int mp3_length;
char* mp3_buffer;
int mp3_bytes;
if (!(self->outfp && self->gfp)) {
PyErr_SetString(PyExc_Exception, "encoder not open");
return NULL;
}
mp3_length = 7200;
mp3_buffer = (char*)malloc(mp3_length);
mp3_bytes = lame_encode_flush(self->gfp, mp3_buffer, sizeof(mp3_buffer));
if (mp3_bytes > 0) {
fwrite(mp3_buffer, 1, mp3_bytes, self->outfp);
}
free(mp3_buffer);
lame_close(self->gfp);
self->gfp = NULL;
fclose(self->outfp);
self->outfp = NULL;
Py_RETURN_NONE;
}
static PyMethodDef Encoder_methods[] = {
{"encode", (PyCFunction)Encoder_encode, METH_VARARGS, "encodes and writes data to the output file."},
{"close", (PyCFunction)Encoder_close, METH_NOARGS, "close the output file."},
{NULL, NULL, 0, NULL}
};
static PyTypeObject clame_EncoderType = {
PyObject_HEAD_INIT(NULL)
0, // ob_size
"clame.Encoder", // tp_name
sizeof(clame_EncoderObject), // tp_basicsize
0, // tp_itemsize
(destructor)Encoder_dealloc, // tp_dealloc
0, // tp_print
0, // tp_getattr
0, // tp_setattr
0, // tp_compare
0, // tp_repr
0, // tp_as_number
0, // tp_as_sequence
0, // tp_as_mapping
0, // tp_hash
0, // tp_call
0, // tp_str
0, // tp_getattro
0, // tp_setattro
0, // tp_as_buffer
Py_TPFLAGS_DEFAULT, // tp_flags
"My first encoder object.", // tp_doc
0, // tp_traverse
0, // tp_clear
0, // tp_richcompare
0, // tp_weaklistoffset
0, // tp_iter
0, // tp_iternext
Encoder_methods, // tp_methods
0, // tp_members
0, // tp_getset
0, // tp_base
0, // tp_dict
0, // tp_descr_get
0, // tp_descr_set
0, // tp_dictoffset
(initproc)Encoder_init, // tp_init
0, // tp_alloc
Encoder_new, // tp_new
0, // tp_free
};
static PyMethodDef clame_methods[] = {
{NULL, NULL, 0, NULL}
};
PyMODINIT_FUNC initclame() {
PyObject* m;
if (PyType_Ready(&clame_EncoderType) < 0) {
return;
m = Py_InitModule3("clame", clame_methods, "My second lame module.");
Py_INCREF(&clame_EncoderType);
PyModule_AddObject(m, "Encoder", (PyObject*) &clame_EncoderType);
}
编译过程:
首先定义了clame_EncoderObject结构体,这个结构体就是用来存储状态信息的,字段outfp用来存储输出文件,gfp则保存lame的状态,可以用来检查是否已经是重复调用已经调用过的函数了。
为了创建这个结构体的一个新实例,我们需要定义Encoder_new函数,你可以把这个函数视为Python里的__new__方法,当Python解释器需要创建你定义的类型的新实例时就会去调用这个方法。在这个方法里没作什么操作,仅仅是做初始化工作,把outfp和gfp都设置为NULL,此外,与Encoder_new函数对应,还需要定义Encoder_dealloc方法来对实例进行析构,你可以把这个函数视为Python的__del__方法,clame_EncoderType结构体则是真正定义了我们的Encoder对象,它的各个字段指定了_new,_close,_encode,_dealloc等方法。在initclame方法中,PyModuleObject则实际指定了在Python程序中使用的Encoder对象。
作者:洞庭散人
出处:http://phinecos.cnblogs.com/
posted on 2010-05-23 00:43 Phinecos(洞庭散人) 阅读(4015) 评论(2) 编辑 收藏 举报
【推荐】国内首个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的设计模式综述