home  |  docs  |  features  |  forum  |  contact  search  |  site map 
Mailing List


  Tutorial chapter

And here is the dessert ! You'll find almost everything you'll need to work with the audio data from parsing and decoding to encoding and multiplexing. But how about meta tags you ask ? Don't worry, it'll be there.

All compressed files may( and they do in most cases ) contain different kind of information inside such as cover art, lyrics, duration, seeking positions, author name, title and etc.
The way it is stored in the file called 'multiplexing' when you store different things in the same file. In order to read all different chunks of information you'll need to 'demultiplex' that file and treat those chunks differently.

Don't worry if you didn't get that from the first cut, we'll cover that later.
What's the most important information you want to see about your mp3 file ?
I guess it will be track name, artist, album and year. Below is how you can extract that information from the compressed file with PyMedia:
import pymedia.audio.acodec as acodec
import pymedia.muxer as muxer
f= open( sName, 'rb' )
s= f.read( 8192 )
file_ext = str.split( name, '.' )[ -1 ].lower()
dm = muxer.Demuxer( file_ext )
frames= dm.parse( s )
print dm.hasHeader(), dm.getInfo()

The trick here is: when you have that information in the file, it will be read by the Demuxer object, but if not, hasHeader() will return False so you know that file has nothing available.
Most of the compressed files have meta information available in the very beginning of the file, but some of them may need extra handling( mp3 file with IDv1 tags for instance ).
What you can expect out of getInfo() ? It depends on the way codec stores that information. Here is the most common list:
  • artist
  • album
  • title
  • year
  • comment
  • copyright
As you see, it does not contain any of the physical parameters of the compressed data. Rather you'll have it after you decode at least on demuxed frame.
dec= acodec.Decoder( dm.streams[ 0 ] )
frame= r[ 0 ]
r= dec.decode( frame[ 1 ] )
print r.sample_rate, r.channels, r.bitrate, r.sample_length

Why it is essential ? Because we're going to create a new instance of Encoder which will depend on those parameters( if you want it to do the right thing ).
Now we know all the parameters our existing file has. Let's pass it over to the Encoder which will let us re-encode file into, let's say mp3 format.
params= {
'id': acodec.getCodecId('mp3'),
'bitrate': r.bitrate,
'sample_rate': r.sample_rate,
'ext': 'mp3',
'channels': r.channels }
enc= acodec.Encoder( params )

The code above will create a new Encoder object which will have exactly the same bitrate and number of channels as your original file but will be rather in mp3 format than your original one.
Now you need to pass all the meta information to it, so you don't lose anything:
enc.setInfo( dec.getInfo() )

Believe it or not, that's all you need ! I'm not kidding :).
As long as everything has been set up, all you need is just carefully go through the whole file, decode it, encode it back into the format you want and save the result. In other words, it takes less when written:
f1= open( 'YOUR OUTPUT FILE NAME', 'wb' )
while len( s ):
frames= enc.encode( r.data )
f1.write( enc.mux( frames ) )
s= f.read( 1024 )
r= dec.decode( s )

You were about to think that it is it ? Nope, there is the one important thing you'll need. Flush.

Flushing everything that codec has in its own buffer is very important as it makes sure the resulting file is complete and valid. But what it'll cost you ? Nothing serious, just one extra line:
f1.write( enc.flush() )

What you think ? I've spent many hours thinking through this stuff. Right now I'm just using it. Hopefully you'll find it useful as well.
Click here to get the fully functional example.
SourceForge.net Logo home | docs | features
contact | News | Mailing List

2004 PyMedia© - opens up multimedia for everyone