Archive

Posts Tagged ‘mp3’

Query MP3 Information using Android supported function

June 28, 2011 4 comments

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:

package pete.android.study;

import android.app.Activity;
import android.media.MediaMetadataRetriever;
import android.os.Bundle;
import android.widget.TextView;

public class MainActivity extends Activity {
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        TextView tvMain = (TextView)findViewById(R.id.tvMain);
        // load data file
        MediaMetadataRetriever metaRetriever = new MediaMetadataRetriever();
        metaRetriever.setDataSource("/sdcard/music.mp3");

        String out = "";
        // get mp3 info
        out += metaRetriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_TITLE);
        out += "\n";
        out += metaRetriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_ARTIST);
        out += "\n";
        out += metaRetriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_ALBUM);
        out += "\n";
        out += metaRetriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_YEAR);
        out += "\n";
        // convert duration to minute:seconds
        String duration = metaRetriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_DURATION);
        long dur = Integer.parseInt(duration);
        String seconds = String.valueOf(dur % 60);
        String minutes = String.valueOf(dur / 60000);
        out += "Length: [ " + minutes + "m" + seconds + "s ]\n";

        // close object
        metaRetriever.release();
        // display output
        tvMain.setText(out);
    }
}

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

June 28, 2011 1 comment

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 🙂

package pete.android.study;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.Calendar;
import java.util.HashMap;

public class MP3HeaderInfo {

	// --- { constants } --- >>>
	// ID3 tag value
	public static final String ID3_TAG = "TAG";
	public static final int BYTE_128 = 128;
	public static final int[] OFFSET_TAG = new int[] { 0, 3 };
	public static final int[] OFFSET_TITLE = new int[] { 3, 33 };
	public static final int[] OFFSET_ARTIST = new int[] { 33, 63 };
	public static final int[] OFFSET_YEAR = new int[] { 93, 97 };
	public static final int[] OFFSET_ALBUM = new int[] { 63, 93 };

	// indexer
	public static final int FROM = 0;
	public static final int TO = 1;

	// key attribute
	public static final String TITLE = "Title";
	public static final String ARTIST = "Artist";
	public static final String YEAR = "Year";
	public static final String ALBUM = "Album";

	// default values for each key value
	public static final String DEFAULT_TITLE = "Unknown Title";
	public static final String DEFAULT_ARTIST = "Unknown Artist";
	public static final String DEFAULT_YEAR = String.valueOf(Calendar.getInstance().get(Calendar.YEAR));
	public static final String DEFAULT_ALBUM = "Unknown Album";
	// --- { constants } --- <<<

	// --- { fields } --- >>>
	private String mFile;
	private String mTitle = DEFAULT_TITLE;
	private String mArtist = DEFAULT_ARTIST;
	private String mYear = DEFAULT_YEAR;
	private String mAlbum = DEFAULT_ALBUM;
	private String mErrorLog; // for error information
	// --- { fields } --- <<<

	// --- { constructor } --- >>>
	public MP3HeaderInfo(String file) {
		mFile = file;
		// auto parse file, only once
		parseAudio();
	}
	// --- { constructor } --- <<<

	// --- { properties } --- >>>
	public String getTitle() {
		return !mTitle.equals("") ? mTitle.trim() : DEFAULT_TITLE;
	}

	public String getArtist() {
		return !mArtist.equals("") ? mArtist.trim() : DEFAULT_ARTIST;
	}

	public String getYear() {
		return !mYear.equals("") ? mYear.trim() : DEFAULT_YEAR;
	}

	public String getAlbum() {
		return !mAlbum.equals("") ? mAlbum.trim() : DEFAULT_ALBUM;
	}

	public String getErrorLog() {
		return mErrorLog;
	}
	// --- { properties } --- <<<

	// --- { private methods } --- >>>
	private boolean parseAudio() {
		// create MP3 File object
		File mp3 = new File(mFile);
		FileInputStream fis;
		try {
			// create new file stream for parsing file in binary
			fis = new FileInputStream(mp3);
			// get file size
			int size = (int) mp3.length();
			// offset to the first byte of the last 128 bytes
			fis.skip(size - BYTE_128);
			// read chunk of 128 bytes
			byte[] chunk = new byte[BYTE_128];
			fis.read(chunk);
			// convert chunk to string
			String id3 = new String(chunk);
			// get first 3 byte
			String tag = id3.substring(OFFSET_TAG[FROM], OFFSET_TAG[TO]);
			// if equals to "TAG" meaning a valid readable one
			if(tag.equals(ID3_TAG)) {
				mTitle = id3.substring(OFFSET_TITLE[FROM], OFFSET_TITLE[TO]);
				mArtist = id3.substring(OFFSET_ARTIST[FROM], OFFSET_ARTIST[TO]);
				mYear = id3.substring(OFFSET_YEAR[FROM], OFFSET_YEAR[TO]);
				mAlbum = id3.substring(OFFSET_ALBUM[FROM], OFFSET_ALBUM[TO]);
			}

			// close stream after done
			fis.close();
			// return complete
			return true;
		} catch (FileNotFoundException e) {
			// log error
			mErrorLog = e.getMessage();
			return false;
		} catch (IOException e) {
			// log error
			mErrorLog = e.getMessage();
			return false;
		}
	}

	// --- { private methods } --- <<<

	// --- { public methods } --- >>>
	public static HashMap<String, String> getInfo(String file) {
		HashMap<String, String> result = new HashMap<String, String>();
		MP3HeaderInfo info = new MP3HeaderInfo(file);
		result.put(ARTIST, info.getArtist());
		result.put(TITLE, info.getTitle());
		result.put(YEAR, info.getYear());
		result.put(ALBUM, info.getAlbum());

		return result;
	}
	// --- { public methods } --- <<<

}

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

package pete.android.study;

import java.util.HashMap;

import android.app.Activity;
import android.os.Bundle;
import android.widget.TextView;

public class MainActivity extends Activity {
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        TextView tvMain = (TextView)findViewById(R.id.tvMain);

        HashMap<String, String> info = MP3HeaderInfo.getInfo("/sdcard/music.mp3");

        String out = "";
        out += info.get("Title") + " - " + info.get("Year") + "\n";
        out += info.get("Album") + "\n" + info.get("Artist") + "\n";
        tvMain.setText(out);
    }
}

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: Tutorials Tags: , , ,

A Quick Study on MP3 file structure

June 28, 2011 1 comment

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 :))

 

Cheers,

Pete Houston

 

Categories: Tutorials Tags: , , , , ,