首页 文章 精选 留言 我的

精选列表

搜索[副语言],共10000篇文章
优秀的个人博客,低调大师

使用C语言扩展Python(五)

上一篇中我们在python端的做法是每次读取一个数据块,然后将这个数据块传递进C扩展模块中去,但对于目标文件的数据写入是在C扩展模块中完成的,但其实可以更面向对象一点,不是吗?原来outfp是一个文件指针, 不如改成一个从Python中传递一个文件对象到C模块里去,这个文件对象有自己的write方法,这样在C扩展模块中你就可以回调文件对象的write方法来完成数据的写入。 首先来看Python端的代码,我们定义了一个file类继承下来的MyFile子类,其中的write方法就是为在C扩展模块中回调而专门准备的。 复制代码 代码 #!/usr/bin/env python import clame INBUFSIZE = 4096 class MyFile(file): def __init__(self, path, mode): file.__init__(self, path, mode) self.n = 0 def write(self, s): file.write(self, s) self.n += 1 output = MyFile('test3.mp3', 'wb') encoder = clame.Encoder(output) input = file('test.raw', 'rb') data = input.read(INBUFSIZE) while data != '': encoder.encode(data) data = input.read(INBUFSIZE) input.close() encoder.close() output.close() print 'output.write was called %d times' % output.n 复制代码 再来看C模块的代码,clame_EncoderObject结构体中的outfp改成了PyObject类型的指针,相应的dealloc方法也做了调整,由于outfp是一个对象,因此需要对其引用计数进行减1操作,而以前的代码是直接调用fclose来直接关闭打开的目标文件。但现在我们只需要对其引用计数做减1操作,等到其为0的时候,在外部的python代码中就可以关闭这个文件对象。同样可以看到在init函数中有相应的引用计数加1的操作。在encode和close两个函数中,通过PyObject_CallMethod实现了对Python对象中指定方法的回调。 复制代码 代码 #include <Python.h> #include <lame.h> /* * On Linux: * gcc -shared -I/usr/include/python2.6 -I/usr/local/include/lame clame.c \ * -lmp3lame -o clame.so * * */ typedef struct { PyObject_HEAD PyObject *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); } Py_XDECREF(self->outfp); self->ob_type->tp_free(self); } static int Encoder_init(clame_EncoderObject *self, PyObject *args, PyObject *kw) { PyObject *outfp; if (!PyArg_ParseTuple(args, "O", &outfp)) { return -1; } if (self->outfp || self->gfp) { PyErr_SetString(PyExc_Exception, "__init__ already called"); return -1; } self->outfp = outfp; Py_INCREF(self->outfp); 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) { PyObject* write_result = PyObject_CallMethod( self->outfp, "write", "(s#)", mp3_buffer, mp3_bytes); if (!write_result) { free(mp3_buffer); return NULL; } Py_DECREF(write_result); } } 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) { PyObject* write_result = PyObject_CallMethod( self->outfp, "write", "(s#)", mp3_buffer, mp3_bytes); if (!write_result) { free(mp3_buffer); return NULL; } Py_DECREF(write_result); } free(mp3_buffer); lame_close(self->gfp); self->gfp = NULL; 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, "Closes 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 third LAME module."); Py_INCREF(&clame_EncoderType); PyModule_AddObject(m, "Encoder", (PyObject *)&clame_EncoderType); } 复制代码 本文转自Phinecos(洞庭散人)博客园博客,原文链接:http://www.cnblogs.com/phinecos/archive/2010/05/23/1742344.html,如需转载请自行联系原作者

资源下载

更多资源
Mario

Mario

马里奥是站在游戏界顶峰的超人气多面角色。马里奥靠吃蘑菇成长,特征是大鼻子、头戴帽子、身穿背带裤,还留着胡子。与他的双胞胎兄弟路易基一起,长年担任任天堂的招牌角色。

Spring

Spring

Spring框架(Spring Framework)是由Rod Johnson于2002年提出的开源Java企业级应用框架,旨在通过使用JavaBean替代传统EJB实现方式降低企业级编程开发的复杂性。该框架基于简单性、可测试性和松耦合性设计理念,提供核心容器、应用上下文、数据访问集成等模块,支持整合Hibernate、Struts等第三方框架,其适用范围不仅限于服务器端开发,绝大多数Java应用均可从中受益。

Rocky Linux

Rocky Linux

Rocky Linux(中文名:洛基)是由Gregory Kurtzer于2020年12月发起的企业级Linux发行版,作为CentOS稳定版停止维护后与RHEL(Red Hat Enterprise Linux)完全兼容的开源替代方案,由社区拥有并管理,支持x86_64、aarch64等架构。其通过重新编译RHEL源代码提供长期稳定性,采用模块化包装和SELinux安全架构,默认包含GNOME桌面环境及XFS文件系统,支持十年生命周期更新。

WebStorm

WebStorm

WebStorm 是jetbrains公司旗下一款JavaScript 开发工具。目前已经被广大中国JS开发者誉为“Web前端开发神器”、“最强大的HTML5编辑器”、“最智能的JavaScript IDE”等。与IntelliJ IDEA同源,继承了IntelliJ IDEA强大的JS部分的功能。

用户登录
用户注册