日韩av黄I国产麻豆传媒I国产91av视频在线观看I日韩一区二区三区在线看I美女国产在线I麻豆视频国产在线观看I成人黄色短片

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 >

使用C语言扩展Python(四)

發(fā)布時(shí)間:2023/12/19 47 豆豆
生活随笔 收集整理的這篇文章主要介紹了 使用C语言扩展Python(四) 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
上一篇里的LAME項(xiàng)目已經(jīng)展示了python如何與C語言交互,但程序仍不夠理想,在python這一端僅僅是傳遞源文件和目標(biāo)文件的路徑,再調(diào)用C模塊的encode方法來進(jìn)行編碼,但問題在于你無法控制encode函數(shù),比如你想編碼的源文件如果不是原始數(shù)據(jù),而是wav文件或者其他格式呢?對于這個(gè)問題,有兩種方法可以選擇,一種模仿前面的C模塊,在你的Python代碼中讀取數(shù)據(jù),并將數(shù)據(jù)塊逐個(gè)傳遞給encode函數(shù),另一種方法是你傳進(jìn)去一個(gè)對象,這個(gè)對象帶有一個(gè)read方法,這樣你就可以在C模塊里直接調(diào)用它的read方法來讀取其數(shù)據(jù)。 聽起來好像第二種更加面向?qū)ο?#xff0c;但實(shí)際上第一種方法反而是更為合適的選擇,因?yàn)樗鼮殪`活,下面我們就在上一篇的基礎(chǔ)上,利用第一種思路對其進(jìn)行改造。在這種新方法中,我們需要多次調(diào)用C模塊的函數(shù),類似于將其視為類的方法。可C語言是不支持類的,因此需要將狀態(tài)信息存儲在某個(gè)地方。除此以外,我們需要將“類”暴露給外部的Python程序,使其能創(chuàng)建“類“的實(shí)例,并調(diào)用它的方法。在“類對象“的內(nèi)部我們則將其寫數(shù)據(jù)的文件信息儲存在”對象“的狀態(tài)中。聽上去就是一種面向?qū)ο蟮姆椒?#xff0c;不是嗎?首先,遵循"測試先行"的原則,先來看我們改造后的Python這一端,你可以每次讀取音頻源文件的一個(gè)數(shù)據(jù)塊,將其轉(zhuǎn)遞給Encoder對象的encode方法,這樣無論你的源文件是何種格式,你都可以在Encoder中進(jìn)行自由的控制,示例代碼如下:代碼import?clame

INBUFSIZE?
=?4096

if?__name__?==?'__main__':
????encoder?
=?clame.Encoder('test.mp3')
????input?
=?file('test.raw',?'rb')
????data?
=?input.read(INBUFSIZE)

????
while?data?!=?'':
????????encoder.encode(data)
????????data?
=?input.read(INBUFSIZE)
????input.close()
????encoder.close()

?再來看C擴(kuò)展模塊這一端,下面是完整的代碼:

代碼#include?<Python.h>
#include?
<lame.h>

typedef?
struct?{
????PyObject_HEAD
????FILE
*?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);
????}
????
if?(self->outfp)?{
????????fclose(self
->outfp);
????}
????self
->ob_type->tp_free(self);
}

static?int?Encoder_init(clame_EncoderObject*?self,?PyObject*?args,?PyObject*?kw)?{
????
char*?outPath;
????
if?(!PyArg_ParseTuple(args,?"s",?&outPath))?{
????????
return?-1;
????}
????
if?(self->outfp?||?self->gfp)?{????
????????PyErr_SetString(PyExc_Exception,?
"__init__?already?called");
????????
return?-1;
????}
????self
->outfp?=?fopen(outPath,?"wb");
????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)?{
????????????fwrite(mp3_buffer,?
1,?mp3_bytes,?self->outfp);
????????}
????}
????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)?{
????????fwrite(mp3_buffer,?
1,?mp3_bytes,?self->outfp);????????
????}
????free(mp3_buffer);
????lame_close(self
->gfp);
????self
->gfp?=?NULL;
????fclose(self
->outfp);
????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,?"close?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?second?lame?module.");
????Py_INCREF(
&clame_EncoderType);
????PyModule_AddObject(m,?
"Encoder",?(PyObject*)?&clame_EncoderType);
}

編譯過程:

gcc?-shared?-I?/usr/include/python2.6?-I?/usr/local/include/lame?clame.c?-lmp3lame?-o?clame.so

首先定義了clame_EncoderObject結(jié)構(gòu)體,這個(gè)結(jié)構(gòu)體就是用來存儲狀態(tài)信息的,字段outfp用來存儲輸出文件,gfp則保存lame的狀態(tài),可以用來檢查是否已經(jīng)是重復(fù)調(diào)用已經(jīng)調(diào)用過的函數(shù)了。

為了創(chuàng)建這個(gè)結(jié)構(gòu)體的一個(gè)新實(shí)例,我們需要定義Encoder_new函數(shù),你可以把這個(gè)函數(shù)視為Python里的__new__方法,當(dāng)Python解釋器需要?jiǎng)?chuàng)建你定義的類型的新實(shí)例時(shí)就會去調(diào)用這個(gè)方法。在這個(gè)方法里沒作什么操作,僅僅是做初始化工作,把outfp和gfp都設(shè)置為NULL,此外,與Encoder_new函數(shù)對應(yīng),還需要定義Encoder_dealloc方法來對實(shí)例進(jìn)行析構(gòu),你可以把這個(gè)函數(shù)視為Python的__del__方法,clame_EncoderType結(jié)構(gòu)體則是真正定義了我們的Encoder對象,它的各個(gè)字段指定了_new,_close,_encode,_dealloc等方法。在initclame方法中,PyModuleObject則實(shí)際指定了在Python程序中使用的Encoder對象。?

?

?

總結(jié)

以上是生活随笔為你收集整理的使用C语言扩展Python(四)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。