public Mp4Tag read(RandomAccessFile raf) throws CannotReadException, IOException {
Mp4Tag tag = new Mp4Tag();
//Get to the facts everything we are interested in is within the moov box, so just load data from file
//once so no more file I/O needed
Mp4BoxHeader moovHeader = Mp4BoxHeader.seekWithinLevel(raf, Mp4NotMetaFieldKey.MOOV.getFieldName());
if (moovHeader == null) {
throw new CannotReadException(ErrorMessage.MP4_FILE_NOT_CONTAINER.getMsg());
}
ByteBuffer moovBuffer = ByteBuffer.allocate(moovHeader.getLength() - Mp4BoxHeader.HEADER_LENGTH);
raf.getChannel().read(moovBuffer);
moovBuffer.rewind();
//Level 2-Searching for "udta" within "moov"
Mp4BoxHeader boxHeader = Mp4BoxHeader.seekWithinLevel(moovBuffer, Mp4NotMetaFieldKey.UDTA.getFieldName());
if (boxHeader != null) {
//Level 3-Searching for "meta" within udta
boxHeader = Mp4BoxHeader.seekWithinLevel(moovBuffer, Mp4NotMetaFieldKey.META.getFieldName());
if (boxHeader == null) {
//logger.warning(ErrorMessage.MP4_FILE_HAS_NO_METADATA.getMsg());
return tag;
}
Mp4MetaBox meta = new Mp4MetaBox(boxHeader, moovBuffer);
meta.processData();
//Level 4- Search for "ilst" within meta
boxHeader = Mp4BoxHeader.seekWithinLevel(moovBuffer, Mp4NotMetaFieldKey.ILST.getFieldName());
//This file does not actually contain a tag
if (boxHeader == null) {
//logger.warning(ErrorMessage.MP4_FILE_HAS_NO_METADATA.getMsg());
return tag;
}
} else {
//Level 2-Searching for "meta" not within udta
boxHeader = Mp4BoxHeader.seekWithinLevel(moovBuffer, Mp4NotMetaFieldKey.META.getFieldName());
if (boxHeader == null) {
//logger.warning(ErrorMessage.MP4_FILE_HAS_NO_METADATA.getMsg());
return tag;
}
Mp4MetaBox meta = new Mp4MetaBox(boxHeader, moovBuffer);
meta.processData();
//Level 3- Search for "ilst" within meta
boxHeader = Mp4BoxHeader.seekWithinLevel(moovBuffer, Mp4NotMetaFieldKey.ILST.getFieldName());
//This file does not actually contain a tag
if (boxHeader == null) {
//logger.warning(ErrorMessage.MP4_FILE_HAS_NO_METADATA.getMsg());
return tag;
}
}
//Size of metadata (exclude the size of the ilst parentHeader), take a slice starting at
//metadata children to make things safer
int length = boxHeader.getLength() - Mp4BoxHeader.HEADER_LENGTH;
ByteBuffer metadataBuffer = moovBuffer.slice();
//Datalength is longer are there boxes after ilst at this level?
//logger.info("headerlengthsays:" + length + "datalength:" + metadataBuffer.limit());
int read = 0;
//logger.info("Started to read metadata fields at position is in metadata buffer:" + metadataBuffer.position());
while (read < length) {
//Read the boxHeader
boxHeader.update(metadataBuffer);
//Create the corresponding datafield from the id, and slice the buffer so position of main buffer
//wont get affected
//logger.info("Next position is at:" + metadataBuffer.position());
createMp4Field(tag, boxHeader, metadataBuffer.slice());
//Move position in buffer to the start of the next parentHeader
metadataBuffer.position(metadataBuffer.position() + boxHeader.getDataLength());
read += boxHeader.getLength();
}
return tag;
}