上一篇中我們在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,如需轉載請自行聯系原作者