RSS

Query MP3 Information using Android supported function

16 Nov

By Pete Houston

That was quite a hard time to look for a way to retrieve MP3 metadata (header info) in Android. Mr. Google this time also doesn’t work for me _ _!

After a while looking around at Android Developers’ Reference, I’ve found one interesting class:MediaMetadataRetriever class, look at here. It seems like doing the function of retrieving music file header, like MP3 header information. So I give it a try and this is result:

Results from MediaMetadataRetriever

Results from MediaMetadataRetriever

It really looks good as you see! It’s better than the handy one in my previous post on getting MP3 basic information.

Give it a try:

 

01 package pete.android.study;
02
03 import android.app.Activity;
04 import android.media.MediaMetadataRetriever;
05 import android.os.Bundle;
06 import android.widget.TextView;
07
08 public class MainActivity extends Activity {
09     /** Called when the activity is first created. */
10     @Override
11     public void onCreate(Bundle savedInstanceState) {
12         super.onCreate(savedInstanceState);
13         setContentView(R.layout.main);
14
15         TextView tvMain = (TextView)findViewById(R.id.tvMain);
16         // load data file
17         MediaMetadataRetriever metaRetriever = new MediaMetadataRetriever();
18         metaRetriever.setDataSource("/sdcard/music.mp3");
19
20         String out = "";
21         // get mp3 info
22         out += metaRetriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_TITLE);
23         out += "\n";
24         out += metaRetriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_ARTIST);
25         out += "\n";
26         out += metaRetriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_ALBUM);
27         out += "\n";
28         out += metaRetriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_YEAR);
29         out += "\n";
30         // convert duration to minute:seconds
31         String duration = metaRetriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_DURATION);
32         long dur = Integer.parseInt(duration);
33         String seconds = String.valueOf(dur % 60);
34         String minutes = String.valueOf(dur / 60000);
35         out += "Length: [ " + minutes + "m" + seconds + "s ]\n";
36
37         // close object
38         metaRetriever.release();
39         // display output
40         tvMain.setText(out);
41     }
42 }

 

I’m quite surprised because of the result by using MediaMetadataRetriever, so simple and effective; also, just cannot believe that I cannot find any article on Internet about using this for querying Media or MP3 information.
I guess this article probably helps many of you in difficulties.
Hope you like it!

Browse source code from Android-Newbie Repository

Cheers,
Pete Houston

Parsing MP3 Basic Info manually

Let’s continue from my previous article on MP3 file structure.

We’re going into practice to parse MP3 basic info: Title, Artist, Year, Album. These are the most basic ones and we can achieve by reading the very last 128 bytes at the end of file.

First you need to put the file into Emulator, in my case, I put into “/sdcard/music.mp3“. After parsing just display it to screen:

MP3 Info Parsing

MP3 Info Parsing

Think it simple, just Java, no Android thought here!

This is how I did it :)

 

001 package pete.android.study;
002
003 import java.io.File;
004 import java.io.FileInputStream;
005 import java.io.FileNotFoundException;
006 import java.io.IOException;
007 import java.util.Calendar;
008 import java.util.HashMap;
009
010 public class MP3HeaderInfo {
011
012     // --- { constants } --- >>>
013     // ID3 tag value
014     public static final String ID3_TAG = "TAG";
015     public static final int BYTE_128 = 128;
016     public static final int[] OFFSET_TAG = new int[] { 03 };
017     public static final int[] OFFSET_TITLE = new int[] { 333 };
018     public static final int[] OFFSET_ARTIST = new int[] { 3363 };
019     public static final int[] OFFSET_YEAR = new int[] { 9397 };
020     public static final int[] OFFSET_ALBUM = new int[] { 6393 };
021
022     // indexer
023     public static final int FROM = 0;
024     public static final int TO = 1;
025
026     // key attribute
027     public static final String TITLE = "Title";
028     public static final String ARTIST = "Artist";
029     public static final String YEAR = "Year";
030     public static final String ALBUM = "Album";
031
032     // default values for each key value
033     public static final String DEFAULT_TITLE = "Unknown Title";
034     public static final String DEFAULT_ARTIST = "Unknown Artist";
035     public static final String DEFAULT_YEAR = String.valueOf(Calendar.getInstance().get(Calendar.YEAR));
036     public static final String DEFAULT_ALBUM = "Unknown Album";
037     // --- { constants } --- <<<
038
039     // --- { fields } --- >>>
040     private String mFile;
041     private String mTitle = DEFAULT_TITLE;
042     private String mArtist = DEFAULT_ARTIST;
043     private String mYear = DEFAULT_YEAR;
044     private String mAlbum = DEFAULT_ALBUM;
045     private String mErrorLog; // for error information
046     // --- { fields } --- <<<
047
048     // --- { constructor } --- >>>
049     public MP3HeaderInfo(String file) {
050         mFile = file;
051         // auto parse file, only once
052         parseAudio();
053     }
054     // --- { constructor } --- <<<
055
056     // --- { properties } --- >>>
057     public String getTitle() {
058         return !mTitle.equals("") ? mTitle.trim() : DEFAULT_TITLE;
059     }
060
061     public String getArtist() {
062         return !mArtist.equals("") ? mArtist.trim() : DEFAULT_ARTIST;
063     }
064
065     public String getYear() {
066         return !mYear.equals("") ? mYear.trim() : DEFAULT_YEAR;
067     }
068
069     public String getAlbum() {
070         return !mAlbum.equals("") ? mAlbum.trim() : DEFAULT_ALBUM;
071     }
072
073     public String getErrorLog() {
074         return mErrorLog;
075     }
076     // --- { properties } --- <<<
077
078     // --- { private methods } --- >>>
079     private boolean parseAudio() {
080         // create MP3 File object
081         File mp3 = new File(mFile);
082         FileInputStream fis;
083         try {
084             // create new file stream for parsing file in binary
085             fis = new FileInputStream(mp3);
086             // get file size
087             int size = (int) mp3.length();
088             // offset to the first byte of the last 128 bytes
089             fis.skip(size - BYTE_128);
090             // read chunk of 128 bytes
091             byte[] chunk = new byte[BYTE_128];
092             fis.read(chunk);
093             // convert chunk to string
094             String id3 = new String(chunk);
095             // get first 3 byte
096             String tag = id3.substring(OFFSET_TAG[FROM], OFFSET_TAG[TO]);
097             // if equals to "TAG" meaning a valid readable one
098             if(tag.equals(ID3_TAG)) {
099                 mTitle = id3.substring(OFFSET_TITLE[FROM], OFFSET_TITLE[TO]);
100                 mArtist = id3.substring(OFFSET_ARTIST[FROM], OFFSET_ARTIST[TO]);
101                 mYear = id3.substring(OFFSET_YEAR[FROM], OFFSET_YEAR[TO]);
102                 mAlbum = id3.substring(OFFSET_ALBUM[FROM], OFFSET_ALBUM[TO]);
103             }
104
105             // close stream after done
106             fis.close();
107             // return complete
108             return true;
109         catch (FileNotFoundException e) {
110             // log error
111             mErrorLog = e.getMessage();
112             return false;
113         catch (IOException e) {
114             // log error
115             mErrorLog = e.getMessage();
116             return false;
117         }
118     }
119
120     // --- { private methods } --- <<<
121
122     // --- { public methods } --- >>>
123     public static HashMap<String, String> getInfo(String file) {
124         HashMap<String, String> result = new HashMap<String, String>();
125         MP3HeaderInfo info = new MP3HeaderInfo(file);
126         result.put(ARTIST, info.getArtist());
127         result.put(TITLE, info.getTitle());
128         result.put(YEAR, info.getYear());
129         result.put(ALBUM, info.getAlbum());
130
131         return result;
132     }
133     // --- { public methods } --- <<<
134
135 }

 

For MainActivity, just input file name to parse and display:

 

01 package pete.android.study;
02
03 import java.util.HashMap;
04
05 import android.app.Activity;
06 import android.os.Bundle;
07 import android.widget.TextView;
08
09 public class MainActivity extends Activity {
10     /** Called when the activity is first created. */
11     @Override
12     public void onCreate(Bundle savedInstanceState) {
13         super.onCreate(savedInstanceState);
14         setContentView(R.layout.main);
15
16         TextView tvMain = (TextView)findViewById(R.id.tvMain);
17
18         HashMap<String, String> info = MP3HeaderInfo.getInfo("/sdcard/music.mp3");
19
20         String out = "";
21         out += info.get("Title") + " - " + info.get("Year") + "\n";
22         out += info.get("Album") + "\n" + info.get("Artist") + "\n";
23         tvMain.setText(out);
24     }
25 }

 

Very very basic of Java file handling, isn’t it?
Talking about MP3 Song Duration or Bit-rate, well, it’s quite complicated … I’m still not good enough at parsing them at the moment, it would take some more time to study about.
However, I guess those above info is enough to display to users. Or you can even achieve reading more metadata on MP3 file by using third-party libraries for your applications.
Have fun!

Cheers,
Pete Houston

Categories:TutorialsTags:

A Quick Study on MP3 file structure

Just had a little time playing around with MP3 file and found it quite interesting.

Do you like “New Divide” by Linkin Park, which is the Original Sound Track on Transformer 2: The Revenge of the Fallen? I personally like it very much. Ah right, Transformer 3 – Dark of the Moon is coming tomorrow, certainly I’ll watch it :D .

If you have the MP3 file of the song, on Windows Explorer right click on it and select Properties, open tab Details:

Windows Explorer: MP3 File Properties

Windows Explorer: MP3 File Properties

You can see its information like: Title, Artists, Album, Year, Genre, Length ….

Ok, try to open it using Mp3tag (v2.49):

MP3Tag - File Info View

MP3Tag – File Info View

The tag version of MP3 file is: ID3v2.3, which is basically derived from v1 and v2.3. Let’s have a look at the internal structure of ID3v1:

Internal layout of an ID3v1 tagged file.Internal layout of an ID3v1 tagged file.

At the description at original page about ID3v1,

Song Title 30 characters
Artist 30 characters
Album 30 characters
Year 4 characters
Comment 30 characters
Genre 1 byte

If you one sum the the size of all these fields we see that 30+30+30+4+30+1 equals 125 bytes and not 128 bytes. The missing three bytes can be found at the very beginning of the tag, before the song title. These three bytes are always “TAG” and is the identification that this is indeed a ID3 tag. The easiest way to find a ID3v1/1.1 tag is to look for the word “TAG” 128 bytes from the end of a file. ” – Quoted from ID3.org

Another pages on MP3 internal:

http://www.multiweb.cz/twoinches/mp3inside.htm

http://www.fortunecity.com/underworld/sonic/3/id3tag.html

So we can easily extract any MP3 file tag information by parsing its very last 128 bytes (128 bytes at the end).

Once again, I open the song in a hex editor:

Hex Editor: MP3 Binary Format

Hex Editor: MP3 Binary Format

That’s right, the info is there!

Generally, instead of reading MP3 file header structure at beginning, we can use the very last 128 bytes to extract its basic info. Interesting, isn’t it?

We’re gonna make a library to query MP3 basic info using Java on Android in next article :)

Just take a cup of coffee and enjoy the song “….give me reason …. connect the space between …” , lol :) )

 

Copy from: http://xjaphx.wordpress.com/tag/mp3/

Advertisements
 
Leave a comment

Posted by on November 16, 2012 in Android

 

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

 
%d bloggers like this: