使用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);
}

 

 

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值