二、读取 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 个字节,保证能读到第一帧音频数据 f = 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,如需转载请自行联系原作者