上一篇中我们在python端的做法是每次读取一个数据块,然后将这个数据块传递进C扩展模块中去,但对于目标文件的数据写入是在C扩展模块中完成的,但其实可以更面向对象一点,不是吗?原来outfp是一个文件指针,
不如改成一个从Python中传递一个文件对象到C模块里去,这个文件对象有自己的write方法,这样在C扩展模块中你就可以回调文件对象的write方法来完成数据的写入。
首先来看Python端的代码,我们定义了一个file类继承下来的MyFile子类,其中的write方法就是为在C扩展模块中回调而专门准备的。
![](http://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
![ExpandedBlockStart.gif](http://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gif)
<!--<br/ /><br/ />Code highlighting produced by Actipro CodeHighlighter (freeware)<br/ />http://www.CodeHighlighter.com/<br/ /><br/ />-->
#
!/usr/bin/envpython
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.writewascalled%dtimes ' % output.n
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.writewascalled%dtimes ' % output.n
再来看C模块的代码,clame_EncoderObject结构体中的outfp改成了PyObject类型的指针,相应的dealloc方法也做了调整,由于outfp是一个对象,因此需要对其引用计数进行减1操作,而以前的代码是直接调用fclose来直接关闭打开的目标文件。但现在我们只需要对其引用计数做减1操作,等到其为0的时候,在外部的python代码中就可以关闭这个文件对象。同样可以看到在init函数中有相应的引用计数加1的操作。在encode和close两个函数中,通过PyObject_CallMethod实现了对Python对象中指定方法的回调。
![](http://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
![ExpandedBlockStart.gif](http://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gif)
<!--<br/ /><br/ />Code highlighting produced by Actipro CodeHighlighter (freeware)<br/ />http://www.CodeHighlighter.com/<br/ /><br/ />-->
#include
<
Python.h
>
#include < lame.h >
/*
*OnLinux:
*gcc-shared-I/usr/include/python2.6-I/usr/local/include/lameclame.c/
*-lmp3lame-oclame.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__alreadycalled " );
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, " encodernotopen " );
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, " encodernotopen " );
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 PyMethodDefEncoder_methods[] = {
{ " encode " ,(PyCFunction)Encoder_encode,METH_VARARGS,
" Encodesandwritesdatatotheoutputfile. " },
{ " close " ,(PyCFunction)Encoder_close,METH_NOARGS,
" Closestheoutputfile. " },
{NULL,NULL, 0 ,NULL}
};
static PyTypeObjectclame_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 */
" Myfirstencoderobject. " , /* 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 PyMethodDefclame_methods[] = {
{NULL,NULL, 0 ,NULL}
};
PyMODINIT_FUNCinitclame(){
PyObject * m;
if (PyType_Ready( & clame_EncoderType) < 0 ){
return ;
}
m = Py_InitModule3( " clame " ,clame_methods, " MythirdLAMEmodule. " );
Py_INCREF( & clame_EncoderType);
PyModule_AddObject(m, " Encoder " ,(PyObject * ) & clame_EncoderType);
}
#include < lame.h >
/*
*OnLinux:
*gcc-shared-I/usr/include/python2.6-I/usr/local/include/lameclame.c/
*-lmp3lame-oclame.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__alreadycalled " );
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, " encodernotopen " );
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, " encodernotopen " );
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 PyMethodDefEncoder_methods[] = {
{ " encode " ,(PyCFunction)Encoder_encode,METH_VARARGS,
" Encodesandwritesdatatotheoutputfile. " },
{ " close " ,(PyCFunction)Encoder_close,METH_NOARGS,
" Closestheoutputfile. " },
{NULL,NULL, 0 ,NULL}
};
static PyTypeObjectclame_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 */
" Myfirstencoderobject. " , /* 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 PyMethodDefclame_methods[] = {
{NULL,NULL, 0 ,NULL}
};
PyMODINIT_FUNCinitclame(){
PyObject * m;
if (PyType_Ready( & clame_EncoderType) < 0 ){
return ;
}
m = Py_InitModule3( " clame " ,clame_methods, " MythirdLAMEmodule. " );
Py_INCREF( & clame_EncoderType);
PyModule_AddObject(m, " Encoder " ,(PyObject * ) & clame_EncoderType);
}