使用C语言扩展Python(四)

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

ExpandedBlockStart.gif代码
#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对象。 

 

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/465504.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

案例 github_2019年12月Github上最热门的Java开源项目,速来围观!

转眼之间&#xff0c;已经进入了2020年&#xff0c;2019年发生的一切仿佛就在昨天。那么&#xff0c;刚过去不久的12月份GitHub上最热门的Java开源项目排行已经出炉啦。下面我带大家一起来看看上榜详情&#xff1a;1、Alinkhttps://github.com/alibaba/Alink Star 1695Alink 是…

实战CRC校验 | 固件如何校验自身完整性?

来源&#xff1a;公众号【鱼鹰谈单片机】作者&#xff1a;鱼鹰Osprey在一些比较严格的行业里面&#xff0c;不是说你的程序能完成必要功能就可以&#xff0c;还需要添加一些额外的功能&#xff0c;比如最常见的看门狗功能&#xff0c;它可以在程序死机时完成重启&#xff0c;但…

想一个颠覆性技术方向建议,你能想到什么?

如上图&#xff0c;是这次文章的主题。我对这个问题是有想法的&#xff0c;我现在是做音频研究&#xff0c;但是我觉得未来核心的方向一定是能源。试想一下&#xff0c;现在的手机功能越来越多&#xff0c;移动设备将会占领我们未来很长一段时间&#xff0c;那么手机的电池要如…

centos 安装idea 非可视化_太厉害了!目前 Redis 可视化工具最全的横向评测

转自&#xff1a;一入码坑深似海链接&#xff1a;www.jianshu.com/p/cb9f4dcb3b921. 命令行不知道大家在日常操作redis时用什么可视化工具呢&#xff1f;以前总觉得没有什么太好的可视化工具&#xff0c;于是问了一个业内朋友。对方回&#xff1a;你还用可视化工具&#xff1f;…

解决克隆clone github 仓库速度过慢的问题

解决克隆clone GitHub 仓库速度过慢的问题 由于大家都懂的原因&#xff0c;我们访问GitHub的速度确实有点慢&#xff0c;特别是克隆比较大的仓库的时候&#xff0c;那速度简直无法直视。 今天我就给大家带来一个邪门歪道&#xff0c;不通过FQ来解决速度问题。 先说结论吧&#…

聊聊身边的嵌入式,自拍神器自拍杆

曾几何时&#xff0c;自拍杆风靡世界&#xff0c;火当然是有原因的&#xff0c;这么一个小装备&#xff0c;极大的满足了人们爱拍照的需求&#xff0c;方便好用、经济实惠。恰巧我手上也有一个&#xff0c;收起来时很小、不占地方打开后可随意调节拍照同时它有个隐藏式三脚架功…

大恶人吉日嘎拉之走火入魔闭门造车之.NET疯狂架构经验分享系列之(十二)多语言支持...

虽然平时很少接触老外的项目、也很少碰到老外&#xff0c;但往往赚大钱的人是经常跟老外做买卖的人居多&#xff0c;他们大多需要网站是全英文的&#xff0c;我们往往上手有一个成熟的中文的网站或者软件&#xff0c;例如成熟的B2C网上购物系统&#xff0c;但是没办法也没精力再…

lisp用entmake生产圆柱体_德BBG公司开发用于CFRP储罐模块生产过程的自闭合HPRTM模具...

自主概念、足以批量生产、可以降低投资成本。每次操作最多可同时生产15个气瓶。照片来源&#xff1a;BBG机械制造商BBG GmbH&Co.KG(德国明德尔海姆)于9月16日提出了一种自动闭合高压树脂传递模塑(HP-RTM)模具的概念&#xff0c;该模具能够快速、重复地制造各种车辆用的紧凑…

【深度剖析】小米CyberDog四足机器人的AI运动系统的实现

2021年8月10日&#xff0c;雷军进行继宣布造车之后的第二次演讲。在这场以“我的梦想&#xff0c;我的选择”为主题的演讲上&#xff0c;雷军详细讲述了创业后的故事&#xff0c;发布了一系列全新产品。其中&#xff0c;给人最大惊喜同时也给人带来诸多疑问的就是我们这篇推文的…

变更控制管理流程图_制度是最好的老板,流程就是最好的管理!流程建立法则(附案例)...

为什么很多企业制定了战略&#xff0c;一线执行却没有到位&#xff1f;为什么员工办事拖拉&#xff0c;执行力不到位&#xff1f;为什么总有下属在等待老板分配任务&#xff0c;不能主动地去工作&#xff1f;为什么一些企业的老板处于很忙碌的的糟糕状态&#xff1f;上述这样问…

第二节:Css重写样式

一丶 进入浏览器---->F12----->找到要修改的区域的Style 进行重写Css样式 二丶打开新页面 window.open("/Persitent/OtherIndex?connectionId" connectionId,"_blank"); 转载于:https://www.cnblogs.com/chenze-Index/p/9309775.html

我的Linux内核学习笔记

在开始今天的内容之前&#xff0c;其实有一些题外话可以和大家分享一下。自从工作以来&#xff0c;我个人一直都有一个观点。那就是怎么样利用简单的代码来说明开发中的问题&#xff0c;或者是解释软件中的原理&#xff0c;这是一个很高的学问。有些道理看上去云里雾里说不清楚…

10 文件无效_新手必看!10个CAD常见问题解决技巧

对于很多刚接触CAD的萌新来说&#xff0c;学习过程遇到的问题总是很多。如果没有老师解答的话&#xff0c;上百度搜索也常常不得要领&#xff0c;所以今天为大家做了大概的问题总结&#xff0c;主要是以下几个问题&#xff1a;1多线段合并A&#xff0e;输入命令“PE”B&#xf…

TurboMail手机客户端—强大的附件文档阅读能力

2019独角兽企业重金招聘Python工程师标准>>> 对于频繁使用邮件的用户而言&#xff0c;收发附件已是家常便饭&#xff0c;但对于手机查看附件&#xff0c;用户却遇到了很多问题。稍微低端的手机&#xff0c;除了txt格式的文本&#xff0c;基本上其他格式的文档&#…

连不上机器判断机器状态_如何准确估计机器人的状态,增强机器人控制的精度及稳定性...

在机器人学中&#xff0c;状态估计和控制一样&#xff0c;是无法避开的问题。 任何传感器的精度都是有限的&#xff0c;如何利用传感器信息&#xff0c;尽可能准确地估计一组完整描述机器人随时间运动的物理量&#xff0c;如位置、速度、加速度、角度、角速度等&#xff0c;是状…

2个字符串相等 swift_Swift快速入门(一)之 Swift基础语法

Swift快速入门&#xff08;一&#xff09;之 Swift基础语法近期重新学习了一遍Swift语言&#xff0c;主要以《Swift编程权威指南&#xff08;第2版&#xff09;》为教程&#xff0c;学习过程中结合比对Java语言特性将学习心得作为三篇笔记&#xff1a;Swift基础语法&#xff0c…

bootstrap switch只出现一个对号_python:34.第一个只出现一次的字符位置

题目描述在一个字符串(0<字符串长度<10000&#xff0c;全部由字母组成)中找到第一个只出现一次的字符,并返回它的位置, 如果没有则返回 -1&#xff08;需要区分大小写&#xff09;.解析暴力解法&#xff0c;时间复杂度是 。# -*- coding:utf-8 -*- class Solution:def Fi…

mac系统如何进入系统偏好设置_MacOS Big Sur 系统偏好设置无法解锁Bug解决

前不久&#xff0c;MacOS推送正式版Big Sur&#xff0c;我满怀期待的更新。更新的过程很平缓&#xff0c;一切都很顺利。但在使用时&#xff0c;出现了一个问题&#xff0c;系统偏好设置的锁无法解除&#xff0c;导致有些软件需要权限&#xff0c;却不能正常允许通过&#xff0…

事务嵌套问题_注意Spring事务这一点,避免出现大事务

背景本篇文章主要分享压测的(高并发)时候发现的一些问题。之前的两篇文章已经讲述了在高并发的情况下&#xff0c;消息队列和数据库连接池的一些总结和优化&#xff0c;有兴趣的可以在我的公众号中去翻阅。废话不多说&#xff0c;进入正题。事务&#xff0c;想必各位CRUD之王对…

多布局怎么搭建_怎么制作网页?网页制作基本步骤

怎么制作网页?网页制作基本步骤&#xff0c;互联网时代&#xff0c;各行各业的企业为了适应时代的发展&#xff0c;纷纷从线下转移至线上来拓展自己的业务。若想让更多人了解自己的企业&#xff0c;拥有一个专属网站至关重要。网站不仅可以详细介绍企业信息&#xff0c;更重要…