posts - 48,comments - 156,trackbacks - 0

          Pymedia 是個(gè) C/C++/Python 的多媒體模塊,可以對(duì)包括 mp3/ogg/avi等多媒體格式文件進(jìn)行編碼解碼和播放,基于 ffmpeg 提供了簡單的 Python 接口。

          一、PyMedia 的下載和安裝

          官方的 PyMedia 模塊已經(jīng)很久沒有更新了,而且不支持最新的 Python 2.7 和 Python 3.0,使用起來是比較費(fèi)勁的, 這里有一個(gè)網(wǎng)址,里面包含了各種非官方維護(hù)的 Python 模塊,其中就有支持 Python 2.7 的 PyMedia 。

          非官方維護(hù) Python 庫

          頁面打開以后,我的小紅傘報(bào)告有惡意文件,不知道怎么回事,直接刪除,應(yīng)該沒什么影響。下載以后安裝,一切正常。

          二、讀取 Mp3 文件

          讀取 mp3 文件就用普通的 python 函數(shù)即可,代碼如下:

          data= open( u'鄺美云 - 我和春天有個(gè)約會(huì).mp3''rb' ) 
          s
          = f.read(10000)

          這里要特別注意第二行代碼,它讀取了這個(gè) mp3 文件的前 10000 個(gè)字節(jié),大概 10K 左右,為什么不是讀取前 1000 個(gè)字節(jié),或者全部讀取( 5M 左右)呢?

          我從網(wǎng)上搜索了一下,大概搞明白了是怎么回事,這里我們需要首先了解一下 Mp3 的文件結(jié)構(gòu)

          三、Mp3 文件結(jié)構(gòu)

          MP3文件大體分為三部分:TAG_V2(ID3V2),F(xiàn)rame, TAG_V1(ID3V1) 。

          音頻數(shù)據(jù)是一幀一幀存儲(chǔ), 一幀數(shù)據(jù)的長度為 4 個(gè)字節(jié),而 Frame 正是存儲(chǔ)音頻數(shù)據(jù)幀的部分。

          而文件頭部和文件尾部則存儲(chǔ)了一些其他信息數(shù)據(jù),如專輯名稱、歌手、年代等等,這些數(shù)據(jù)并不能被解碼為音頻。

          對(duì)于 PyMedia 來說,至少要讀出文件中的第一幀音頻數(shù)據(jù)才行,多讀取幾幀沒關(guān)系,但是第一幀必須讀取出來,否則后面的程序就沒辦法運(yùn)行了。

          至于第一幀數(shù)據(jù)從什么地方開始,這個(gè)是不確定的,所以第一次讀取一般多讀一點(diǎn),保證第一幀能被讀取到。

          那么有沒有辦法來確認(rèn)下一第一幀是否被讀取到了呢?繼續(xù)往下看

          四、解析出音頻數(shù)據(jù)幀

          讀取出前 10000 個(gè)字節(jié)的數(shù)據(jù)后,我們就可以把其中的音頻數(shù)據(jù)幀解析出來,然后播放,代碼如下:

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

          第一行代碼導(dǎo)入 muxer 模塊,muxer 谷歌給翻譯成“合成器”,應(yīng)該是這個(gè)意思吧

          第二行代碼創(chuàng)建了一個(gè) Mp3 的 Demuxer 對(duì)象 dm

          第三行代碼是重點(diǎn),它從我們讀取的第一段 10000 個(gè)字節(jié)的數(shù)據(jù)中,解析出最初的幾幀,并將這些數(shù)據(jù)幀存放到 frames 數(shù)組中

          第四行代碼測試了 frames 數(shù)組的長度,就可以知道 10000 個(gè)字節(jié)中到底包含了幾幀音頻數(shù)據(jù)。
          對(duì)于這首歌而言是 2 幀, 如果前面一下讀取了全部數(shù)據(jù),這里會(huì)顯示 1103 ,即這個(gè)文件一共包含 1103 幀音頻數(shù)據(jù)。

          五、設(shè)置解碼器

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

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

          第一行代碼導(dǎo)入解碼器模塊

          第二行代碼生成解碼器對(duì)象,傳入了一個(gè)參數(shù) dm.streams[0]

          這里解釋一下,我們?cè)谇懊娼馕鰯?shù)據(jù)的時(shí)候,dm 對(duì)象根據(jù)數(shù)據(jù)內(nèi)容中自動(dòng)生成了 dm.streams 數(shù)組,其實(shí)這數(shù)組中就包含一個(gè)元素,就是 dm.streams[0],他的內(nèi)容如下:

          {'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 文件的文件信息和編碼信息,在這里,這個(gè)參數(shù)我們是從文件數(shù)據(jù)中解析出來的,其實(shí)我們自己設(shè)置也行,像下面這樣:

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

          六、解碼第一幀音頻數(shù)據(jù),并創(chuàng)建音頻輸出對(duì)象

          有了解碼器以后,我們就可以首先解碼第一幀音頻數(shù)據(jù),并創(chuàng)建音頻輸出對(duì)象,代碼如下:

          1 #4.解碼第一幀音頻數(shù)據(jù),并創(chuàng)建輸出對(duì)象
          2 frame = frames[0]
          3 #音頻數(shù)據(jù)在 frame 數(shù)組的第二個(gè)元素中
          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 數(shù)組中存放了最初的幾幀音頻數(shù)據(jù),frames[0] 就是第一幀音頻數(shù)據(jù)

          第二行代碼:嚴(yán)格來說 frames[0] 也是一個(gè)數(shù)組,它包含五個(gè)元素,其中第二個(gè)元素 frames[0][1]才是真正的音頻數(shù)據(jù),這只是 PyMedia 的一個(gè)設(shè)計(jì),和 Mp3 音頻幀的數(shù)據(jù)結(jié)構(gòu)沒關(guān)系

          第六行、第七行代碼,創(chuàng)建了一個(gè)音頻輸出對(duì)象

          七、播放、讀取、解碼......循環(huán)下去

          現(xiàn)在我們有了音頻輸出對(duì)象,有了第一幀解碼后的數(shù)據(jù),就可以直接播放了

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

          然后繼續(xù)讀取數(shù)據(jù)、解碼、播放,后面的步驟就簡單了,PyMedia 會(huì)自動(dòng)找出數(shù)據(jù)幀

          #7.繼續(xù)讀取、解碼、播放
          while True:
              data
          = f.read(512)
              
          if len(data)>0:
                  r
          = dec.decode( data )
                  
          if r: snd.play( r.data )
              
          else:
                  
          break

          當(dāng)讀取完最后一幀數(shù)據(jù)數(shù)據(jù)以后,要讓程序延時(shí)一會(huì)在退出,否則最后一幀數(shù)據(jù)不會(huì)被播放出來,程序就結(jié)束了

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

          完整的代碼

          #1.二進(jìn)制方法讀取前 10000 個(gè)字節(jié),保證能讀到第一幀音頻數(shù)據(jù)
          = open( u'鄺美云 - 我和春天有個(gè)約會(huì).mp3''rb' ) 
          data
          = f.read(10000)

          #2.創(chuàng)建合成器對(duì)象,解析出最初的幾幀音頻數(shù)據(jù)
          import pymedia.muxer as muxer
          dm 
          = muxer.Demuxer('mp3')
          frames 
          = dm.parse( data )
          print len(frames)

          #3.根據(jù)解析出來的 Mp3 編碼信息,創(chuàng)建解碼器對(duì)象
          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.解碼第一幀音頻數(shù)據(jù)
          frame = frames[0]
          #音頻數(shù)據(jù)在 frame 數(shù)組的第二個(gè)元素中
          r= dec.decode( frame[ 1 ] )
          print "sample_rate:%s , channels:%s " % (r.sample_rate,r.channels)
          #注意:這一步可以直接解碼 r=dec.decode( data),而不用讀出第一幀音頻數(shù)據(jù)
          #
          但是開始會(huì)有一下噪音,如果是網(wǎng)絡(luò)流純音頻數(shù)據(jù),不包含標(biāo)簽信息,則不會(huì)出現(xiàn)雜音

          #5.創(chuàng)建音頻輸出對(duì)象
          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.繼續(xù)讀取、解碼、播放
          while True:
              data 
          = f.read(512)
              
          if len(data)>0:
                  r 
          = dec.decode( data )
                  
          if r: snd.play( r.data )
              
          else:
                  
          break

          #8.延時(shí),直到播放完畢
          import time
          while snd.isPlaying(): time.sleep( .5 )

          //==============================================================================
          posted on 2011-08-07 02:10 左洸 閱讀(5168) 評(píng)論(3)  編輯  收藏 所屬分類: Python

          FeedBack:
          # re: 用 PyMedia 解碼并播放 mp3 文件[未登錄]
          2011-08-09 08:38 | greatghoul
          很詳盡呀,還沒有接觸過pymedia,感覺很簡單易用。  回復(fù)  更多評(píng)論
            
          # re: 用 PyMedia 解碼并播放 mp3 文件
          2011-08-09 16:20 | CHI Flat Iron
          感覺很復(fù)雜啊,不過還是謝謝啦  回復(fù)  更多評(píng)論
            
          # re: 用 PyMedia 解碼并播放 mp3 文件
          2011-08-15 16:03 | 水星家紡
          感覺很復(fù)雜啊,不過還是謝謝啦   回復(fù)  更多評(píng)論
            
          主站蜘蛛池模板: 连州市| 哈巴河县| 武冈市| 青河县| 巢湖市| 汽车| 邮箱| 崇义县| 濉溪县| 光泽县| 兴宁市| 石泉县| 陇西县| 哈密市| 墨竹工卡县| 乾安县| 枣强县| 凤庆县| 和政县| 确山县| 濉溪县| 侯马市| 汝南县| 临猗县| 贡嘎县| 溧阳市| 乃东县| 泰安市| 谢通门县| 牡丹江市| 托克逊县| 梅河口市| 屯昌县| 读书| 瓦房店市| 淄博市| 钟山县| 永川市| 琼结县| 呈贡县| 璧山县|