用 PyMedia 解码并播放 mp3 文件

简介:

Pymedia 是个 C/C++/Python 的多媒体模块,可以对包括 mp3/ogg/avi等多媒体格式文件进行编码解码和播放,基于 ffmpeg 提供了简单的 Python 接口。

一、PyMedia 的下载和安装

官方的 PyMedia 模块已经很久没有更新了,而且不支持最新的 Python 2.7 和 Python 3.0,使用起来是比较费劲的, 这里有一个网址,里面包含了各种非官方维护的 Python 模块,其中就有支持 Python 2.7 的 PyMedia 。

非官方维护 Python 库

页面打开以后,我的小红伞报告有恶意文件,不知道怎么回事,直接删除,应该没什么影响。下载以后安装,一切正常。

二、读取 Mp3 文件

读取 mp3 文件就用普通的 python 函数即可,代码如下:

data=  open( u ' 邝美云 - 我和春天有个约会.mp3 ' ' rb '  ) 
s
=  f.read( 10000 )

这里要特别注意第二行代码,它读取了这个 mp3 文件的前 10000 个字节,大概 10K 左右,为什么不是读取前 1000 个字节,或者全部读取( 5M 左右)呢?

我从网上搜索了一下,大概搞明白了是怎么回事,这里我们需要首先了解一下 Mp3 的文件结构

三、Mp3 文件结构

MP3文件大体分为三部分:TAG_V2(ID3V2),Frame, TAG_V1(ID3V1) 。

音频数据是一帧一帧存储, 一帧数据的长度为 4 个字节,而 Frame 正是存储音频数据帧的部分。

而文件头部和文件尾部则存储了一些其他信息数据,如专辑名称、歌手、年代等等,这些数据并不能被解码为音频。

对于 PyMedia 来说,至少要读出文件中的第一帧音频数据才行,多读取几帧没关系,但是第一帧必须读取出来,否则后面的程序就没办法运行了。

至于第一帧数据从什么地方开始,这个是不确定的,所以第一次读取一般多读一点,保证第一帧能被读取到。

那么有没有办法来确认下一第一帧是否被读取到了呢?继续往下看

四、解析出音频数据帧

读取出前 10000 个字节的数据后,我们就可以把其中的音频数据帧解析出来,然后播放,代码如下:

1  import  pymedia.muxer as muxer
2  dm =  muxer.Demuxer( ' mp3 ' )
3  frames =  dm.parse( data )
4  print  len(frames)

第一行代码导入 muxer 模块,muxer 谷歌给翻译成“合成器”,应该是这个意思吧

第二行代码创建了一个 Mp3 的 Demuxer 对象 dm

第三行代码是重点,它从我们读取的第一段 10000 个字节的数据中,解析出最初的几帧,并将这些数据帧存放到 frames 数组中

第四行代码测试了 frames 数组的长度,就可以知道 10000 个字节中到底包含了几帧音频数据。
对于这首歌而言是 2 帧, 如果前面一下读取了全部数据,这里会显示 1103 ,即这个文件一共包含 1103 帧音频数据。

五、设置解码器

这里要注意一下,解码和解析可不是一回事,不要搞混了。看代码:

1  import  pymedia.audio.acodec as acodec
2  dec =  acodec.Decoder( dm.streams[ 0 ] )

第一行代码导入解码器模块

第二行代码生成解码器对象,传入了一个参数 dm.streams[0]

这里解释一下,我们在前面解析数据的时候,dm 对象根据数据内容中自动生成了 dm.streams 数组,其实这数组中就包含一个元素,就是 dm.streams[0],他的内容如下:

{ ' index ' 0 ' block_align ' 0 ' type ' 1 ' frame_rate_base ' 1 ' height ' 0 ' channels ' 0 , ' width ' 0 ' length ' - 2077252342 ' sample_rate ' 0 ' frame_rate ' : 25 ' bitrate ' 0 ' id ' 86016 }

说白了就是 mp3 文件的文件信息和编码信息,在这里,这个参数我们是从文件数据中解析出来的,其实我们自己设置也行,像下面这样:

1  params  =  { ' id ' : acodec.getCodecID( ' mp3 ' ),  ' bitrate ' 128000 ' sample_rate ' 44100 ' ext ' ' mp3 ' ' channels ' 2 }
2  dec =  acodec.Decoder(params)

六、解码第一帧音频数据,并创建音频输出对象

有了解码器以后,我们就可以首先解码第一帧音频数据,并创建音频输出对象,代码如下:

复制代码
1  # 4.解码第一帧音频数据,并创建输出对象
2  frame  =  frames[0]
3  # 音频数据在 frame 数组的第二个元素中
4  r =  dec.decode( frame[  1  ] )
5  print   " sample_rate:%s , channels:%s  "   %  (r.sample_rate,r.channels)
6  import  pymedia.audio.sound as sound
7  snd =  sound.Output( r.sample_rate, r.channels, sound.AFMT_S16_LE )
复制代码

第一行代码:前面我们说过,frames 数组中存放了最初的几帧音频数据,frames[0] 就是第一帧音频数据

第二行代码:严格来说 frames[0] 也是一个数组,它包含五个元素,其中第二个元素 frames[0][1]才是真正的音频数据,这只是 PyMedia 的一个设计,和 Mp3 音频帧的数据结构没关系

第六行、第七行代码,创建了一个音频输出对象

七、播放、读取、解码......循环下去

现在我们有了音频输出对象,有了第一帧解码后的数据,就可以直接播放了

# 6.播放
if  r: snd.play( r.data )

然后继续读取数据、解码、播放,后面的步骤就简单了,PyMedia 会自动找出数据帧

复制代码
# 7.继续读取、解码、播放
while  True:
    data
=  f.read( 512 )
    
if  len(data) > 0:
        r
=  dec.decode( data )
        
if  r: snd.play( r.data )
    
else :
        
break
复制代码

当读取完最后一帧数据数据以后,要让程序延时一会在退出,否则最后一帧数据不会被播放出来,程序就结束了

1  import  time
2  while  snd.isPlaying(): time.sleep( . 5  )

完整的代码

复制代码
# 1.二进制方法读取前 10000 个字节,保证能读到第一帧音频数据
=  open( u ' 邝美云 - 我和春天有个约会.mp3 ' ' rb '  ) 
data
=  f.read( 10000 )

# 2.创建合成器对象,解析出最初的几帧音频数据
import  pymedia.muxer as muxer
dm 
=  muxer.Demuxer( ' mp3 ' )
frames 
=  dm.parse( data )
print  len(frames)

# 3.根据解析出来的 Mp3 编码信息,创建解码器对象
import  pymedia.audio.acodec as acodec
dec 
=  acodec.Decoder( dm.streams[ 0 ] )
# 像下面这样也行
#
params = {'id': acodec.getCodecID('mp3'), 'bitrate': 128000, 'sample_rate': 44100, 'ext': 'mp3', 'channels': 2}
#
dec= acodec.Decoder(params)


# 4.解码第一帧音频数据
frame  =  frames[0]
# 音频数据在 frame 数组的第二个元素中
r =  dec.decode( frame[  1  ] )
print   " sample_rate:%s , channels:%s  "   %  (r.sample_rate,r.channels)
# 注意:这一步可以直接解码 r=dec.decode( data),而不用读出第一帧音频数据
#
但是开始会有一下噪音,如果是网络流纯音频数据,不包含标签信息,则不会出现杂音

# 5.创建音频输出对象
import  pymedia.audio.sound as sound
snd 
=  sound.Output( r.sample_rate, r.channels, sound.AFMT_S16_LE )

# 6.播放
if  r: snd.play( r.data )

# 7.继续读取、解码、播放
while  True:
    data 
=  f.read( 512 )
    
if  len(data) > 0:
        r 
=  dec.decode( data )
        
if  r: snd.play( r.data )
    
else :
        
break

# 8.延时,直到播放完毕
import  time
while  snd.isPlaying(): time.sleep( . 5  )
复制代码


//==============================================================================



 本文转自左洸博客园博客,原文链接:http://www.cnblogs.com/myqiao/archive/2011/08/07/2129777.html,如需转载请自行联系原作者


目录
相关文章
|
Android开发
Android MediaTek 平台增加UART接口的红外模块支持,支持NEC红外遥控
Android MediaTek 平台增加UART接口的红外模块支持,支持NEC红外遥控
280 0
|
4月前
|
负载均衡 网络安全 网络虚拟化
双ISP(双互联网服务提供商)
双ISP(双互联网服务提供商)指同时接入两家网络服务商,通过冗余备份、负载均衡和路径优化提升网络稳定性、速度与安全性。适用于企业关键业务、跨境服务及家庭高需求用户。实现方式包括硬件(双WAN口路由器、双网卡服务器)、软件(BGP多线接入、VPN多路径)及运营商套餐。优点为更稳定、更快速、更强抗攻击能力;缺点是成本较高且配置复杂。适合外贸公司等对网络要求高的场景,需权衡成本与技术难度。
226 3
|
测试技术 Linux API
mutagen-处理音频元数据的Python模块
Mutagen是处理音频元数据的Python模块。它支持ASF,FLAC,MP4,Monkey's Audio,MP3,Musepack,Ogg Opus,Ogg FLAC,Ogg Speex,Ogg Theora,Ogg Vorbis,True Audio,WavPack,OptimFROG和AIFF音频文件。支持所有版本的ID3v2,并解析所有标准的ID3v2.4帧。它可以读取Xing标头,以准确计算MP3的比特率和长度。无论音频格式如何,都可以编辑ID3和APEv2标签。它还可以在单个数据包/页面级别上处理Ogg流。
2731 0
mutagen-处理音频元数据的Python模块
|
12月前
|
Java Shell Windows
java Runtime.exec()执行shell/cmd命令:常见的几种陷阱与一种完善实现
java Runtime.exec()执行shell/cmd命令:常见的几种陷阱与一种完善实现
313 6
|
关系型数据库 MySQL Shell
使用Docker安装部署MySQL数据库
使用Docker安装部署MySQL数据库
2487 0
|
11月前
|
算法 决策智能
基于GA-PSO遗传粒子群混合优化算法的TSP问题求解matlab仿真
本文介绍了基于GA-PSO遗传粒子群混合优化算法解决旅行商问题(TSP)的方法。TSP旨在寻找访问一系列城市并返回起点的最短路径,属于NP难问题。文中详细阐述了遗传算法(GA)和粒子群优化算法(PSO)的基本原理及其在TSP中的应用,展示了如何通过编码、选择、交叉、变异及速度和位置更新等操作优化路径。算法在MATLAB2022a上实现,实验结果表明该方法能有效提高求解效率和解的质量。
|
Java API 开发工具
java实现chatGPT SDK
构建了一个Java ChatGPT-SDK,用于封装OpenAI接口,支持多种服务调用链路,特别是会话模型。SDK采用工厂模式,提供会话服务的创建,利用OkHttp3和Retrofit2处理HTTP请求,包括请求拦截设置apiKey。核心接口包括IOpenAiApi和OpenAiSession,后者实现会话交互,支持流式响应。测试代码展示了如何使用SDK进行聊天交互。
346 2
|
SQL 存储 安全
SQL安全性能:构建坚不可摧的数据防线
随着信息技术的发展,数据成为核心资产,SQL数据库作为关键工具,其安全性至关重要。本文探讨了SQL安全的重要性、常见威胁及对策: - **重要性**: 包括数据保护、业务连续性和合规要求。 - **威胁**: 如SQL注入、未经授权访问、数据泄露和拒绝服务攻击。 - **措施**: 实施访问控制、数据加密、定期更新/备份、审计/监控及漏洞管理。 - **最佳实践**: 定期培训、建立应急响应计划、持续评估改进和安全编程。 通过这些方法,组织能够构建强大的SQL数据防护体系。
513 0
|
存储 自然语言处理 API
Flutter应用的国际化支持:实现多语言环境的优雅策略
【4月更文挑战第26天】Flutter提供强大的国际化(i18n)和本地化(l10n)支持,使开发者能轻松实现应用多语言特性。通过定义`.arb`文件来管理字符串资源,使用`LocalizationsDelegate`加载资源,设置应用语言环境,以及在UI中使用`S.of(context).someString`访问字符串。进阶技巧包括字符串格式化、复数形式、双向文本和Unicode支持。充分测试确保所有语言正确显示。随着全球化需求增长,Flutter的国际化支持成为应用开发关键。
|
内存技术
pcm转wav的方法及代码示例
pcm转wav的方法及代码示例