package org.jaudiotagger.audio.real; import org.jaudiotagger.audio.exceptions.CannotReadException; import org.jaudiotagger.audio.generic.AudioFileReader; import org.jaudiotagger.audio.generic.GenericAudioHeader; import org.jaudiotagger.audio.generic.Utils; import org.jaudiotagger.tag.FieldDataInvalidException; import org.jaudiotagger.tag.FieldKey; import org.jaudiotagger.tag.Tag; import java.io.DataInputStream; import java.io.IOException; import java.io.RandomAccessFile; /** * Real Media File Format: Major Chunks: .RMF PROP MDPR CONT DATA INDX */ public class RealFileReader extends AudioFileReader { @Override protected GenericAudioHeader getEncodingInfo(RandomAccessFile raf) throws CannotReadException, IOException { final GenericAudioHeader rv = new GenericAudioHeader(); final RealChunk prop = findPropChunk(raf); final DataInputStream dis = prop.getDataInputStream(); final int objVersion = Utils.readUint16(dis); if (objVersion == 0) { final long maxBitRate = Utils.readUint32(dis) / 1000; final long avgBitRate = Utils.readUint32(dis) / 1000; final long maxPacketSize = Utils.readUint32(dis); final long avgPacketSize = Utils.readUint32(dis); final long packetCnt = Utils.readUint32(dis); final int duration = Utils.readUint32AsInt(dis) / 1000; final long preroll = Utils.readUint32(dis); final long indexOffset = Utils.readUint32(dis); final long dataOffset = Utils.readUint32(dis); final int numStreams = Utils.readUint16(dis); final int flags = Utils.readUint16(dis); rv.setBitrate((int) avgBitRate); rv.setLength(duration); rv.setVariableBitRate(maxBitRate != avgBitRate); } return rv; } private RealChunk findPropChunk(RandomAccessFile raf) throws IOException, CannotReadException { final RealChunk rmf = RealChunk.readChunk(raf); final RealChunk prop = RealChunk.readChunk(raf); return prop; } private RealChunk findContChunk(RandomAccessFile raf) throws IOException, CannotReadException { final RealChunk rmf = RealChunk.readChunk(raf); final RealChunk prop = RealChunk.readChunk(raf); RealChunk rv = RealChunk.readChunk(raf); while (!rv.isCONT()) rv = RealChunk.readChunk(raf); return rv; } @Override protected Tag getTag(RandomAccessFile raf) throws CannotReadException, IOException { final RealChunk cont = findContChunk(raf); final DataInputStream dis = cont.getDataInputStream(); final String title = Utils.readString(dis, Utils.readUint16(dis)); final String author = Utils.readString(dis, Utils.readUint16(dis)); final String copyright = Utils.readString(dis, Utils.readUint16(dis)); final String comment = Utils.readString(dis, Utils.readUint16(dis)); final RealTag rv = new RealTag(); // NOTE: frequently these fields are off-by-one, thus the crazy // logic below... try { rv.addField(FieldKey.TITLE,(title.length() == 0 ? author : title)); rv.addField(FieldKey.ARTIST, title.length() == 0 ? copyright : author); rv.addField(FieldKey.COMMENT,comment); } catch(FieldDataInvalidException fdie) { throw new RuntimeException(fdie); } return rv; } }