/** * */ package mp4.util.atom; /** * The edit list atom. */ public class ElstAtom extends LeafAtom { private static final int ENTRIES_OFFSET = 4; private static final int TABLE_OFFSET = 8; private static final int TRACK_DURATION = 0; private static final int MEDIA_TIME = 4; private static final int MEDIA_RATE = 8; private static final int ENTRY_SIZE = 12; /** * Construct an empty elst atom. */ public ElstAtom() { super(new byte[]{'e','l','s','t'}); } /** * Copy constructor. Performs a deep copy. * @param old the version to copy */ public ElstAtom(ElstAtom old) { super(old); } /** * Construct a single edit list entry. * @param size the number of entries to allocate */ public ElstAtom(int size) { this(); allocateData(size); } /** * Add an entry to the edit list. * @param num the entry number * @param duration the edit list duration * @param mediaTime the edit time * @param mediaRate the edit media rate */ public void addEntry(int num, long duration, long mediaTime, int mediaRate) { setNumEntries(num); setDuration(num - 1, duration); setMediaTime(num - 1, mediaTime); setMediaRate(num - 1, mediaRate); } /** * Allocate space for the specified number of entries * @param numEntries the number of entries in the edit list */ @Override public void allocateData(long numEntries) { long size = TABLE_OFFSET + (numEntries * ENTRY_SIZE); super.allocateData(size); } /** * Set a new duration for each elst entry. * @param duration the new duration value */ public void setDuration(long duration) { for (int i = 0; i < getNumEntries(); i++) { setDuration(i, duration); } } /** * Return the number of entries in the edit list * @return the number of entries in the edit list */ public long getNumEntries() { return data.getUnsignedInt(ENTRIES_OFFSET); } /** * Set the number of entries in the edit list * @param numEntries the number of edit list entries */ public void setNumEntries(long numEntries) { data.addUnsignedInt(ENTRIES_OFFSET, numEntries); } /** * Return the track duration for the specified index * @param index the table index * @return the track duration for the specified index */ public long getDuration(int index) { return data.getUnsignedInt(TABLE_OFFSET + (index * ENTRY_SIZE) + TRACK_DURATION); } /** * Set the track duration for the specified edit list entry * @param index the table index * @param val the new duration */ public void setDuration(int index, long val) { data.addUnsignedInt(TABLE_OFFSET + (index * ENTRY_SIZE) + TRACK_DURATION, val); } /** * Return the media time for the specified index * @param index the table index * @return the media time for the specified index */ public long getMediaTime(int index) { return data.getUnsignedInt(TABLE_OFFSET + (index * ENTRY_SIZE) + MEDIA_TIME); } /** * Set the media time for the specified index * @param index the elst table index * @param time the new time */ public void setMediaTime(int index, long time) { data.addUnsignedInt(TABLE_OFFSET + (index * ENTRY_SIZE) + MEDIA_TIME, time); } /** * Return the media rate for the specified index. The media rate is a * fixed point value. The first 16-bits is the integer and the next 16-bits * is the fraction. * @param index the table index * @return the media rate for the specified index */ public double getMediaRate(int index) { return data.getFixedPoint(TABLE_OFFSET + (index * ENTRY_SIZE) + MEDIA_RATE); } /** * Sets the integer portion of the media rate for the specified edit list entry. * @param index the table index value * @param rate the media rate integer portion */ public void setMediaRate(int index, int rate) { data.addFixedPoint(TABLE_OFFSET + (index * ENTRY_SIZE) + MEDIA_RATE, rate, 0); } @Override public void accept(AtomVisitor v) throws AtomException { v.visit(this); } /** * Update the specified time with information in the edit list * @param time the time in seconds * @param mediaTS the media time scale * @param movieTS the movie time scale * @return the updated time in the media time scale */ public long editTime(float time, long mediaTS, long movieTS) { long movieTime = (long)(time * movieTS); long mediaTime = (long)(time * mediaTS); for (int i = 0; i < getNumEntries(); i++) { if (movieTime < getDuration(i) && getMediaTime(i) != -1) { // we don't handle dwell edits assert getMediaRate(i) != 0; return mediaTime + getMediaTime(i); } } return mediaTime; } }