上一篇里的LAME项目已经展示了python如何与C语言交互,但程序仍不够理想,在python这一端仅仅是传递源文件和目标文件的路径,再调用C模块的encode方法来进行编码,但问题在于你无法控制encode函数,比如你想编码的源文件如果不是原始数据,而是wav文件或者其他格式呢?对于这个问题,有两种方法可以选择,一种模仿前面的C模块,在你的Python代码中读取数据,并将数据块逐个传递给encode函数,另一种方法是你传进去一个对象,这个对象带有一个read方法,这样你就可以在C模块里直接调用它的read方法来读取其数据。
听起来好像第二种更加面向对象,但实际上第一种方法反而是更为合适的选择,因为它更为灵活,下面我们就在上一篇的基础上,利用第一种思路对其进行改造。在这种新方法中,我们需要多次调用C模块的函数,类似于将其视为类的方法。可C语言是不支持类的,因此需要将状态信息存储在某个地方。除此以外,我们需要将“类”暴露给外部的Python程序,使其能创建“类“的实例,并调用它的方法。在“类对象“的内部我们则将其写数据的文件信息储存在”对象“的状态中。听上去就是一种面向对象的方法,不是吗?
首先,遵循"测试先行"的原则,先来看我们改造后的Python这一端,你可以每次读取音频源文件的一个数据块,将其转递给Encoder对象的encode方法,这样无论你的源文件是何种格式,你都可以在Encoder中进行自由的控制,示例代码如下:
代码

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扩展模块这一端,下面是完整的代码:

代码

#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结构体,这个结构体就是用来存储状态信息的,字段outfp用来存储输出文件,gfp则保存lame的状态,可以用来检查是否已经是重复调用已经调用过的函数了。

为了创建这个结构体的一个新实例,我们需要定义Encoder_new函数,你可以把这个函数视为Python里的__new__方法,当Python解释器需要创建你定义的类型的新实例时就会去调用这个方法。在这个方法里没作什么操作,仅仅是做初始化工作,把outfp和gfp都设置为NULL,此外,与Encoder_new函数对应,还需要定义Encoder_dealloc方法来对实例进行析构,你可以把这个函数视为Python的__del__方法,clame_EncoderType结构体则是真正定义了我们的Encoder对象,它的各个字段指定了_new,_close,_encode,_dealloc等方法。在initclame方法中,PyModuleObject则实际指定了在Python程序中使用的Encoder对象。

使用C语言扩展Python(四)相关推荐

  1. 用C语言扩展Python的功能的实例

    用C语言扩展Python的功能的实例 分类: C/C++ 编程技巧 Programes 2008-04-23 09:31 1232人阅读 评论(0)收藏 举报 python扩展语言cmethodsnu ...

  2. python代码用c语言封装_使用C语言扩展Python程序的简单入门指引

    一.简介 Python是一门功能强大的高级脚本语言,它的强大不仅表现在其自身的功能上,而且还表现在其良好的可扩展性上,正因如此,Python已经开始受到越来越多人的青睐,并且被屡屡成功地应用于各类大型 ...

  3. c语言实现python语法_用C语言扩展Python的功能

    转自:http://www.ibm.com/developerworks/cn/linux/l-pythc/ 一.简介 Python是一门功能强大的高级脚本语言,它的强大不仅表现在其自身的功能上,而且 ...

  4. 如何将c语言程序封装供python调用_转:用C语言扩展Python的功能

    一.简介 Python是一门功能强大的高级脚本语言,它的强大不仅表现在其自身的功能上,而且还表现在其良好的可扩展性上,正因如此,Python已经开始受到越来越多人的青睐,并且被屡屡成功地应用于各类大型 ...

  5. c语言转换为python语言_【转】用C语言扩展Python的功能

    一.简介 Python是一门功能强大的高级脚本语言,它的强大不仅表现在其自身的功能上,而且还表现在其良好的可扩展性上,正因如此,Python已经开始受到越来越多人的青睐,并且被屡屡成功地应用于各类大型 ...

  6. python安装c语言库_C语言扩展Python模块

    一. main.cpp #include #include "Python.h" static PyObject* Py_Add_Formular(PyObject *self, ...

  7. 使用C语言扩展Python(三)

    上一篇中我们已经了解如何在Python程序和C模块之间进行值的相互传递,现在我们来进入实作阶段,看看如何将一个C语言开发的开源mp3编解码库LAME包装为一个Python下可以使用的扩展模块. 首先去 ...

  8. 用C语言扩展Python的功能

    https://www.ibm.com/developerworks/cn/linux/l-pythc/

  9. python c 混合编程 用c循环_混合编程:用 C 语言来扩展 Python 大法吧!

    Python 实在是一种让人上瘾的编程语言,简洁的语法+丰富的扩展包,几乎可以用 Python 做任何事情,唯一的黑点似乎就是「慢」,但是与高效的编译语言 C\C++ 互联以后,可以解决脚本语言运行速 ...

最新文章

  1. 源目标OKR— 在线团队协同办公、项目管理工具
  2. tensorflow checkpoint文件
  3. idea编译的jsp存在哪里
  4. <马哲>生产方式是社会发展的决定力量2017-12-27
  5. c++适配器模式adapter
  6. 使用CADisplayLink实现UILabel动画特效
  7. linux ntfs 速度慢,将U盘磁盘格式改成NTFS解决u盘复制速度慢问题
  8. 少儿编程100讲轻松学python(三)-python如何重命名文件
  9. UVA 10405-Longest Common Subsequence
  10. 判断应用程序在前台还是后台
  11. hung task日志linux,Linux Kernel Crash--hung_task_timeout_secs
  12. IIS服务器应用程序不可用的解决办法
  13. linux监控文件是否传输,利用SecureCRT在linux与Windows之间传输文件
  14. C学习的日志(随手记、随手写)
  15. [Kerberos基础]-- kerberos认证原理---讲的非常细致,易懂
  16. ios 设置控制器背景半透明_iOS Modal出半透明控制器
  17. NLP创业破局,如何摘取更高处的果实
  18. Android App软件框架搭建
  19. JAVA的人民币大写(金额)转化
  20. 论文笔记-DeepLung: Deep 3D Dual Path Nets for Automated Pulmonary Nodule Detection and Classification

热门文章

  1. c++基础学习(13)--(STL、标准库)
  2. 写出表格的结构html,一个面试题,根据json结构生成html表格
  3. gcc中的内嵌汇编语言(Intel i386平台)
  4. java - 通用 CRUD(增、删、改、查)工具类,代码高效复用
  5. linux 查看空间(内存、磁盘、文件目录、分区)的几个命令
  6. linux (阿里云 CentOS7) 中安装配置 RocketMQ
  7. String... 参数定义中有三个点的意思
  8. unexpected EOF while looking for matching ``‘
  9. 解决dataTable 报错:cannot read property “style“ of undefined
  10. Easyjs 细说Javascript里的 闭包(Closure)