org.farng.mp3.id3
Class ID3v2_2

java.lang.Object
  extended byorg.farng.mp3.AbstractMP3FileItem
      extended byorg.farng.mp3.AbstractMP3Tag
          extended byorg.farng.mp3.id3.AbstractID3
              extended byorg.farng.mp3.id3.AbstractID3v2
                  extended byorg.farng.mp3.id3.ID3v2_2
Direct Known Subclasses:
ID3v2_3

public class ID3v2_2
extends AbstractID3v2

The two biggest design goals were to be able to implement ID3v2 without disturbing old software too much and that ID3v2 should be expandable.

The first criterion is met by the simple fact that the MPEG decoding software uses a syncsignal, embedded in the audiostream, to 'lock on to' the audio. Since the ID3v2 tag doesn't contain a valid syncsignal, no software will attempt to play the tag. If, for any reason, coincidence make a syncsignal appear within the tag it will be taken care of by the 'unsynchronisation scheme' described in section 5.

The second criterion has made a more noticeable impact on the design of the ID3v2 tag. It is constructed as a container for several information blocks, called frames, whose format need not be known to the software that encounters them. At the start of every frame there is an identifier that explains the frames's format and content, and a size descriptor that allows software to skip unknown frames.

If a total revision of the ID3v2 tag should be needed, there is a version number and a size descriptor in the ID3v2 header.

The ID3 tag described in this document is mainly targeted to files encoded with MPEG-2 layer I, MPEG-2 layer II, MPEG-2 layer III and MPEG-2.5, but may work with other types of encoded audio.

The bitorder in ID3v2 is most significant bit first (MSB). The byteorder in multibyte numbers is most significant byte first (e.g. $12345678 would be encoded $12 34 56 78).

It is permitted to include padding after all the final frame (at the end of the ID3 tag), making the size of all the frames together smaller than the size given in the head of the tag. A possible purpose of this padding is to allow for adding a few additional frames or enlarge existing frames within the tag without having to rewrite the entire file. The value of the padding bytes must be $00.

Padding is good as it increases the write speed when there is already a tag present in a file. If the new tag is one byte longer than the previous tag, than the extra byte can be taken from the padding, instead of having to shift the entire file one byte. Padding is of course bad in that it increases the size of the file, but if the amount of padding is wisely chosen (with clustersize in mind), the impact on filesystems will be virtually none. As the contents is $00, it is also easy for modems and other transmission devices/protocols to compress the padding. Having a $00 filled padding also increases the ability to recover erroneous tags.

The ID3v2 tag header, which should be the first information in the file, is 10 bytes as follows:

ID3/file identifier "ID3"
ID3 version$02 00
ID3 flags%xx000000
ID3 size4 * %0xxxxxxx

The first three bytes of the tag are always "ID3" to indicate that this is an ID3 tag, directly followed by the two version bytes. The first byte of ID3 version is it's major version, while the second byte is its revision number. All revisions are backwards compatible while major versions are not. If software with ID3v2 and below support should encounter version three or higher it should simply ignore the whole tag. Version and revision will never be $FF.

In the first draft of ID3v2 the identifier was "TAG", just as in ID3v1. It was later changed to "MP3" as I thought of the ID3v2 as the fileheader MP3 had always been missing. When it became appearant than ID3v2 was going towards a general purpose audio header the identifier was changed to "ID3".

The first bit (bit 7) in the 'ID3 flags' is indicating whether or not unsynchronisation is used; a set bit indicates usage.

The second bit (bit 6) is indicating whether or not compression is used; a set bit indicates usage. Since no compression scheme has been decided yet, the ID3 decoder (for now) should just ignore the entire tag if the compression bit is set.

Currently, zlib compression is being considered for the compression, in an effort to stay out of the all-too-common marsh of patent trouble. Have a look at the additions draft for the latest developments.

The ID3 tag size is encoded with four bytes where the first bit (bit 7) is set to zero in every byte, making a total of 28 bits. The zeroed bits are ignored, so a 257 bytes long tag is represented as $00 00 02 01.

We really gave it a second thought several times before we introduced these awkward size descriptions. The reason is that we thought it would be even worse to have a file header with no set size (as we wanted to unsynchronise the header if there were any false synchronisations in it). An easy way of calculating the tag size is A*2^21+B*2^14+C*2^7+D = A*2097152+B*16384+C*128+D, where A is the first byte, B the second, C the third and D the fourth byte.

The ID3 tag size is the size of the complete tag after unsychronisation, including padding, excluding the header (total tag size - 10). The reason to use 28 bits (representing up to 256MB) for size description is that we don't want to run out of space here.

An ID3v2 tag can be detected with the following pattern:
    $49 44 33 yy yy xx zz zz zz zz
Where yy is less than $FF, xx is the 'flags' byte and zz is less than $80.

Version:
$Revision: 1.5 $
Author:
Eric Farng

Field Summary
protected  boolean compression
           
protected  boolean unsynchronization
           
 
Constructor Summary
ID3v2_2()
          Creates a new ID3v2_2 object.
ID3v2_2(AbstractMP3Tag mp3tag)
          Creates a new ID3v2_2 object.
ID3v2_2(ID3v2_2 copyObject)
          Creates a new ID3v2_2 object.
ID3v2_2(java.io.RandomAccessFile file)
          Creates a new ID3v2_2 object.
 
Method Summary
 void append(AbstractMP3Tag tag)
          This method does nothing, but is called by subclasses for completeness
 boolean equals(java.lang.Object obj)
          Determines whether another object is equal to this tag.
 java.lang.String getAlbumTitle()
           
 java.lang.String getAuthorComposer()
           
 java.lang.String getIdentifier()
          ID string that usually corresponds to the class name, but can be displayed to the user.
 java.lang.String getLeadArtist()
           
 int getSize()
           
 java.lang.String getSongComment()
           
 java.lang.String getSongGenre()
           
 java.lang.String getSongLyric()
           
 java.lang.String getSongTitle()
           
 java.lang.String getTrackNumberOnAlbum()
           
 java.lang.String getYearReleased()
           
 void overwrite(AbstractMP3Tag tag)
          This method does nothing, but is called by subclasses for completeness
 void read(java.io.RandomAccessFile file)
          import java.io.IOException; import java.io.RandomAccessFile; read from current file pointer position.
 boolean seek(java.io.RandomAccessFile file)
          Looks for this tag.
 void setAlbumTitle(java.lang.String albumTitle)
           
 void setAuthorComposer(java.lang.String authorComposer)
           
 void setLeadArtist(java.lang.String leadArtist)
           
 void setSongComment(java.lang.String songComment)
           
 void setSongGenre(java.lang.String songGenre)
           
 void setSongLyric(java.lang.String songLyrics)
           
 void setSongTitle(java.lang.String songTitle)
           
 void setTrackNumberOnAlbum(java.lang.String trackNumberOnAlbum)
           
 void setYearReleased(java.lang.String yearReleased)
           
 java.lang.String toString()
           
 void write(AbstractMP3Tag tag)
          This method does nothing, but is called by subclasses for completeness
 void write(java.io.RandomAccessFile file)
          Method to write this object to the file argument at is current file pointer position.
 
Methods inherited from class org.farng.mp3.id3.AbstractID3v2
append, appendDuplicateFrameId, byteArrayToSize, clearFrameMap, decrementPaddingCounter, delete, getDuplicateBytes, getDuplicateFrameId, getEmptyFrameBytes, getFileReadBytes, getFrame, getFrameCount, getFrameIterator, getFrameOfType, getInvalidFrameBytes, getMajorVersion, getPaddingCounter, getPaddingSize, getRevision, hasFrame, hasFrameOfType, incrementDuplicateBytes, incrementEmptyFrameBytes, incrementInvalidFrameBytes, incrementPaddingCounter, iterator, overwrite, removeFrame, removeFrameOfType, resetPaddingCounter, setFileReadBytes, setFrame, setMajorVersion, setPaddingSize, setRevision, sizeToByteArray, values
 
Methods inherited from class org.farng.mp3.AbstractMP3Tag
isSubsetOf
 
Methods inherited from class org.farng.mp3.AbstractMP3FileItem
isSubsetOf
 
Methods inherited from class java.lang.Object
clone, finalize, getClass, hashCode, notify, notifyAll, wait, wait, wait
 

Field Detail

compression

protected boolean compression

unsynchronization

protected boolean unsynchronization
Constructor Detail

ID3v2_2

public ID3v2_2()
Creates a new ID3v2_2 object.


ID3v2_2

public ID3v2_2(ID3v2_2 copyObject)
Creates a new ID3v2_2 object.


ID3v2_2

public ID3v2_2(AbstractMP3Tag mp3tag)
Creates a new ID3v2_2 object.


ID3v2_2

public ID3v2_2(java.io.RandomAccessFile file)
        throws TagException,
               java.io.IOException
Creates a new ID3v2_2 object.

Method Detail

getIdentifier

public java.lang.String getIdentifier()
Description copied from class: AbstractMP3FileItem
ID string that usually corresponds to the class name, but can be displayed to the user. It is not indended to identify each individual instance.

Specified by:
getIdentifier in class AbstractMP3FileItem
Returns:
ID string

getSize

public int getSize()
Specified by:
getSize in class AbstractMP3FileItem

append

public void append(AbstractMP3Tag tag)
Description copied from class: AbstractMP3Tag
This method does nothing, but is called by subclasses for completeness

Overrides:
append in class AbstractID3v2

equals

public boolean equals(java.lang.Object obj)
Description copied from class: AbstractMP3Tag
Determines whether another object is equal to this tag. It just compares if they are the same class, then calls super.equals(object).

Overrides:
equals in class AbstractID3v2

overwrite

public void overwrite(AbstractMP3Tag tag)
Description copied from class: AbstractMP3Tag
This method does nothing, but is called by subclasses for completeness

Overrides:
overwrite in class AbstractID3v2

read

public void read(java.io.RandomAccessFile file)
          throws TagException,
                 java.io.IOException
Description copied from class: AbstractMP3FileItem
import java.io.IOException; import java.io.RandomAccessFile; read from current file pointer position.

Specified by:
read in class AbstractMP3FileItem
Parameters:
file - file to read from
Throws:
TagException - on any exception generated by this library.
java.io.IOException - on any I/O error

seek

public boolean seek(java.io.RandomAccessFile file)
             throws java.io.IOException
Description copied from class: AbstractMP3Tag
Looks for this tag. returns true if found. If found, the file pointer is right after the tag start indicator i.e. "TAG" "LYRICSBEGIN" "ID3" + 2

Specified by:
seek in class AbstractMP3Tag
Parameters:
file - MP3 file to overwrite
Returns:
returns true if found, false otherwise.
Throws:
java.io.IOException - on any I/O error

toString

public java.lang.String toString()

write

public void write(AbstractMP3Tag tag)
Description copied from class: AbstractMP3Tag
This method does nothing, but is called by subclasses for completeness

Overrides:
write in class AbstractID3v2

write

public void write(java.io.RandomAccessFile file)
           throws java.io.IOException
Description copied from class: AbstractMP3FileItem
Method to write this object to the file argument at is current file pointer position.

Specified by:
write in class AbstractMP3FileItem
Parameters:
file - file to write to
Throws:
java.io.IOException - on any I/O error

getSongTitle

public java.lang.String getSongTitle()
Specified by:
getSongTitle in class AbstractMP3Tag

getLeadArtist

public java.lang.String getLeadArtist()
Specified by:
getLeadArtist in class AbstractMP3Tag

getAlbumTitle

public java.lang.String getAlbumTitle()
Specified by:
getAlbumTitle in class AbstractMP3Tag

getYearReleased

public java.lang.String getYearReleased()
Specified by:
getYearReleased in class AbstractMP3Tag

getSongComment

public java.lang.String getSongComment()
Specified by:
getSongComment in class AbstractMP3Tag

getSongGenre

public java.lang.String getSongGenre()
Specified by:
getSongGenre in class AbstractMP3Tag

getTrackNumberOnAlbum

public java.lang.String getTrackNumberOnAlbum()
Specified by:
getTrackNumberOnAlbum in class AbstractMP3Tag

getSongLyric

public java.lang.String getSongLyric()
Specified by:
getSongLyric in class AbstractMP3Tag

getAuthorComposer

public java.lang.String getAuthorComposer()
Specified by:
getAuthorComposer in class AbstractMP3Tag

setSongTitle

public void setSongTitle(java.lang.String songTitle)
Specified by:
setSongTitle in class AbstractMP3Tag

setLeadArtist

public void setLeadArtist(java.lang.String leadArtist)
Specified by:
setLeadArtist in class AbstractMP3Tag

setAlbumTitle

public void setAlbumTitle(java.lang.String albumTitle)
Specified by:
setAlbumTitle in class AbstractMP3Tag

setYearReleased

public void setYearReleased(java.lang.String yearReleased)
Specified by:
setYearReleased in class AbstractMP3Tag

setSongComment

public void setSongComment(java.lang.String songComment)
Specified by:
setSongComment in class AbstractMP3Tag

setSongGenre

public void setSongGenre(java.lang.String songGenre)
Specified by:
setSongGenre in class AbstractMP3Tag

setTrackNumberOnAlbum

public void setTrackNumberOnAlbum(java.lang.String trackNumberOnAlbum)
Specified by:
setTrackNumberOnAlbum in class AbstractMP3Tag

setSongLyric

public void setSongLyric(java.lang.String songLyrics)
Specified by:
setSongLyric in class AbstractMP3Tag

setAuthorComposer

public void setAuthorComposer(java.lang.String authorComposer)
Specified by:
setAuthorComposer in class AbstractMP3Tag


Copyright (c) 2004 Eric Farng