国外 网站 模板,深圳网站建设ppchsj,网站设计活动主题,南头英文网站建设上一篇里的LAME项目已经展示了python如何与C语言交互#xff0c;但程序仍不够理想#xff0c;在python这一端仅仅是传递源文件和目标文件的路径#xff0c;再调用C模块的encode方法来进行编码#xff0c;但问题在于你无法控制encode函数#xff0c;比如你想编码的源文件如…上一篇里的LAME项目已经展示了python如何与C语言交互但程序仍不够理想在python这一端仅仅是传递源文件和目标文件的路径再调用C模块的encode方法来进行编码但问题在于你无法控制encode函数比如你想编码的源文件如果不是原始数据而是wav文件或者其他格式呢对于这个问题有两种方法可以选择一种模仿前面的C模块在你的Python代码中读取数据并将数据块逐个传递给encode函数另一种方法是你传进去一个对象这个对象带有一个read方法这样你就可以在C模块里直接调用它的read方法来读取其数据。 听起来好像第二种更加面向对象但实际上第一种方法反而是更为合适的选择因为它更为灵活,下面我们就在上一篇的基础上,利用第一种思路对其进行改造。在这种新方法中我们需要多次调用C模块的函数类似于将其视为类的方法。可C语言是不支持类的因此需要将状态信息存储在某个地方。除此以外我们需要将“类”暴露给外部的Python程序使其能创建“类“的实例并调用它的方法。在“类对象“的内部我们则将其写数据的文件信息储存在”对象“的状态中。听上去就是一种面向对象的方法不是吗首先,遵循测试先行的原则,先来看我们改造后的Python这一端,你可以每次读取音频源文件的一个数据块,将其转递给Encoder对象的encode方法,这样无论你的源文件是何种格式,你都可以在Encoder中进行自由的控制,示例代码如下:代码import clameINBUFSIZE 4096if __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 Python.h#include lame.htypedef 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);}编译过程gcc -shared -I /usr/include/python2.6 -I /usr/local/include/lame clame.c -lmp3lame -o clame.so首先定义了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对象。