天天看點

使用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) {

    if (!PyArg_ParseTuple(args, "O", &outfp)) {

        return -1;

    if (self->outfp || self->gfp) {

        PyErr_SetString(PyExc_Exception, "__init__ already called");

    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)) {

    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);

        }

        Py_DECREF(write_result);

    free(mp3_buffer);

    Py_RETURN_NONE;

static PyObject *Encoder_close(clame_EncoderObject *self) {

    mp3_length = 7200;

    mp3_bytes = lame_encode_flush(self->gfp, mp3_buffer, sizeof(mp3_buffer));

    if (mp3_bytes > 0) {

                                 self->outfp, "write", "(s#)", mp3_buffer, mp3_bytes);

    if (!write_result) {

        free(mp3_buffer);

    Py_DECREF(write_result);

    lame_close(self->gfp);

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[] = {

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,如需轉載請自行聯系原作者