package org.jaudiotagger.audio.mp4.atom;
import org.jaudiotagger.audio.exceptions.CannotReadException;
import org.jaudiotagger.audio.mp4.Mp4NotMetaFieldKey;
import java.nio.ByteBuffer;
import java.nio.charset.CharacterCodingException;
import java.nio.charset.Charset;
import java.nio.charset.CharsetDecoder;
import java.util.HashMap;
import java.util.Map;
/**
* HdlrBox ( Handler box),
* <p/>
* Describes the type of metadata in the following ilst or minf atom
*/
public class Mp4HdlrBox extends AbstractMp4Box {
public static final int VERSION_FLAG_LENGTH = 1;
public static final int OTHER_FLAG_LENGTH = 3;
public static final int RESERVED_FLAG_LENGTH = 4;
public static final int HANDLER_LENGTH = 4;
public static final int RESERVED1_LENGTH = 4;
public static final int RESERVED2_LENGTH = 4;
public static final int RESERVED3_LENGTH = 4;
public static final int NAME_LENGTH = 2;
public static final int HANDLER_POS = VERSION_FLAG_LENGTH + OTHER_FLAG_LENGTH + RESERVED_FLAG_LENGTH;
public static final int RESERVED1_POS = HANDLER_POS + HANDLER_LENGTH;
//Size used by iTunes, but other application could use different size because name field is variable
public static final int ITUNES_META_HDLR_DAT_LENGTH =
VERSION_FLAG_LENGTH +
OTHER_FLAG_LENGTH +
RESERVED_FLAG_LENGTH +
HANDLER_LENGTH +
RESERVED1_LENGTH +
RESERVED2_LENGTH +
RESERVED3_LENGTH +
NAME_LENGTH;
private int reserved; // 32 bit
private String handlerType; // 4 bytes;
private String name; // Variable length but 4 bytes in existing files
private MediaDataType mediaDataType;
private static Map<String, MediaDataType> mediaDataTypeMap;
static {
//Create maps to speed up lookup from raw value to enum
mediaDataTypeMap = new HashMap<String, MediaDataType>();
for (MediaDataType next : MediaDataType.values()) {
mediaDataTypeMap.put(next.getId(), next);
}
}
/**
* DataBuffer must start from from the start of the body
*
* @param header header info
* @param dataBuffer data of box (doesnt include header data)
*/
public Mp4HdlrBox(Mp4BoxHeader header, ByteBuffer dataBuffer) {
this.header = header;
this.dataBuffer = dataBuffer;
}
public void processData() throws CannotReadException {
//Skip other flags
dataBuffer.position(dataBuffer.position() + VERSION_FLAG_LENGTH + OTHER_FLAG_LENGTH + RESERVED_FLAG_LENGTH);
CharsetDecoder decoder = Charset.forName("ISO-8859-1").newDecoder();
try {
handlerType = decoder.decode((ByteBuffer) dataBuffer.slice().limit(HANDLER_LENGTH)).toString();
} catch (CharacterCodingException cee) {
//Ignore
}
//To getFields human readable name
mediaDataType = mediaDataTypeMap.get(handlerType);
}
public String getHandlerType() {
return handlerType;
}
public MediaDataType getMediaDataType() {
return mediaDataType;
}
public String toString() {
String s = "handlerType:" + handlerType + ":human readable:" + mediaDataType.getDescription();
return s;
}
public static enum MediaDataType {
ODSM("odsm", "ObjectDescriptorStream - defined in ISO/IEC JTC1/SC29/WG11 - CODING OF MOVING PICTURES AND AUDIO"),
CRSM("crsm", "ClockReferenceStream - defined in ISO/IEC JTC1/SC29/WG11 - CODING OF MOVING PICTURES AND AUDIO"),
SDSM("sdsm", "SceneDescriptionStream - defined in ISO/IEC JTC1/SC29/WG11 - CODING OF MOVING PICTURES AND AUDIO"),
M7SM("m7sm", "MPEG7Stream - defined in ISO/IEC JTC1/SC29/WG11 - CODING OF MOVING PICTURES AND AUDIO"),
OCSM("ocsm", "ObjectContentInfoStream - defined in ISO/IEC JTC1/SC29/WG11 - CODING OF MOVING PICTURES AND AUDIO"),
IPSM("ipsm", "IPMP Stream - defined in ISO/IEC JTC1/SC29/WG11 - CODING OF MOVING PICTURES AND AUDIO"),
MJSM("mjsm", "MPEG-J Stream - defined in ISO/IEC JTC1/SC29/WG11 - CODING OF MOVING PICTURES AND AUDIO"),
MDIR("mdir", "Apple Meta Data iTunes Reader"),
MP7B("mp7b", "MPEG-7 binary XML"),
MP7T("mp7t", "MPEG-7 XML"),
VIDE("vide", "Video Track"),
SOUN("soun", "Sound Track"),
HINT("hint", "Hint Track"),
APPL("appl", "Apple specific"),
META("meta", "Timed Metadata track - defined in ISO/IEC JTC1/SC29/WG11 - CODING OF MOVING PICTURES AND AUDIO"),;
private String id;
private String description;
MediaDataType(String id, String description) {
this.id = id;
this.description = description;
}
public String getId() {
return id;
}
public String getDescription() {
return description;
}
}
/**
* Create an iTunes style Hdlr box for use within Meta box
* <p/>
* <p>Useful when writing to mp4 that previously didn't contain an mp4 meta atom</p>
* <p/>
* <p>Doesnt write the child data but uses it to se the header length, only sets the atoms immediate
* data</p
*
* @return
*/
public static Mp4HdlrBox createiTunesStyleHdlrBox() {
Mp4BoxHeader hdlrHeader = new Mp4BoxHeader(Mp4NotMetaFieldKey.HDLR.getFieldName());
hdlrHeader.setLength(Mp4BoxHeader.HEADER_LENGTH + Mp4HdlrBox.ITUNES_META_HDLR_DAT_LENGTH);
ByteBuffer hdlrData = ByteBuffer.allocate(Mp4HdlrBox.ITUNES_META_HDLR_DAT_LENGTH);
hdlrData.put(HANDLER_POS, (byte) 0x6d); //mdir
hdlrData.put(HANDLER_POS + 1, (byte) 0x64);
hdlrData.put(HANDLER_POS + 2, (byte) 0x69);
hdlrData.put(HANDLER_POS + 3, (byte) 0x72);
hdlrData.put(RESERVED1_POS, (byte) 0x61); //appl
hdlrData.put(RESERVED1_POS + 1, (byte) 0x70);
hdlrData.put(RESERVED1_POS + 2, (byte) 0x70);
hdlrData.put(RESERVED1_POS + 3, (byte) 0x6c);
hdlrData.rewind();
Mp4HdlrBox hdlrBox = new Mp4HdlrBox(hdlrHeader, hdlrData);
return hdlrBox;
}
}