设为首页 收藏本站
查看: 1138|回复: 0

[经验分享] 使用C语言扩展Python(五)

[复制链接]

尚未签到

发表于 2015-4-20 13:00:14 | 显示全部楼层 |阅读模式
上一篇中我们在python端的做法是每次读取一个数据块,然后将这个数据块传递进C扩展模块中去,但对于目标文件的数据写入是在C扩展模块中完成的,但其实可以更面向对象一点,不是吗?原来outfp是一个文件指针,
不如改成一个从Python中传递一个文件对象到C模块里去,这个文件对象有自己的write方法,这样在C扩展模块中你就可以回调文件对象的write方法来完成数据的写入。
首先来看Python端的代码,我们定义了一个file类继承下来的MyFile子类,其中的write方法就是为在C扩展模块中回调而专门准备的。
DSC0000.gif DSC0001.gif 代码

#!/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
#include
/*
* 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);
}
  
  

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-58900-1-1.html 上篇帖子: python类型转换、数值操作(收藏) 下篇帖子: Python中的函数(三)
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表