package mp4.util.atom; /** * The time-to-sample atom is shared by the ctts and stts atoms, which * are similar in functionality. The stts atom is the decoding * time-to-sample mapping atom. The decoding time (DT) atom * gives the deltas between successive decoding times. The ctts atom * is the composition time-to-sample atom. The composition time (CT) atom * provides composition times. When the decoding and composition times are * the same, then the ctts atom is not present. */ public abstract class TimeToSampleAtom extends LeafAtom { protected static final int ENTRIES_OFFSET = 4; protected static final int TABLE_OFFSET = 8; protected static final int SAMPLE_COUNT = 0; // the semantics of SAMPLE_VALUE depends up on the concrete class protected static final int SAMPLE_VALUE = 4; protected static final int ENTRY_SIZE = 8; /** * Constructor passes argument to super class * @param type the atom type */ protected TimeToSampleAtom(byte[] type) { super(type); } /** * Copy constructor. Performs a deep copy. * @param old the atom to copy. */ protected TimeToSampleAtom(TimeToSampleAtom old) { super(old); } /** * Allocate space for the data in the atom * @param numEntries the number of entries in the atom */ @Override public void allocateData(long numEntries) { long size = TABLE_OFFSET + (numEntries * ENTRY_SIZE); super.allocateData(size); } /** * Return the number of entries in the table. * @return the number of entries in the table */ public final long getNumEntries() { return data.getUnsignedInt(ENTRIES_OFFSET); } /** * Set the number of entries in the stts table * @param numEntries the number of entries */ public final void setNumEntries(long numEntries) { data.addUnsignedInt(ENTRIES_OFFSET, numEntries); } /** * Return the sample count for the specified index * @param index the index into the stts table * @return the sample count */ public final long getSampleCount(int index) { return data.getUnsignedInt(TABLE_OFFSET + (index * ENTRY_SIZE) + SAMPLE_COUNT); } /** * Set the sample count for the specified entry * @param index the index in the table * @param sc the sample count value */ public final void setSampleCount(int index, long sc) { data.addUnsignedInt(TABLE_OFFSET + (index * ENTRY_SIZE) + SAMPLE_COUNT, sc); } /** * Return the sample value at the specified index. The meaning of the * sample value depends upon the concrete class. For stts, it is a duration * value. For ctts, it is an offset. * @param index the index into the time to sample table * @return the sample value */ protected final long getSampleValue(int index) { return data.getUnsignedInt(TABLE_OFFSET + (index * ENTRY_SIZE) + SAMPLE_VALUE); } /** * Set the sample value for the specified entry. The meaning of the * sample value depends upon the concrete class. For stts, it is a duration * value. For ctts, it is an offset. * @param index the table index * @param value the value value for the specified entry */ protected final void setSampleValue(int index, long value) { data.addUnsignedInt(TABLE_OFFSET + (index * ENTRY_SIZE) + SAMPLE_VALUE, value); } /** * Cut the atom at the specified sample number. This method is * used by the subclass methods, stts or ctts. * @param sampleNum the sample number * @param cutAtom the stts or ctts atom */ protected void cut(long sampleNum, TimeToSampleAtom cutAtom) { // search the table for the specified sample long numEntries = getNumEntries(); long upperBoundSample = 0; int i; for (i = 0; i < numEntries; i++) { long count = getSampleCount(i); upperBoundSample += count; if (sampleNum <= upperBoundSample) { // we've found the stts entry that contains this sample // create a new stts entry with the new count break; } } // create the new table long newCount = upperBoundSample - sampleNum + 1; long newNumEntries = numEntries - i; // add the new number of entries to the table cutAtom.allocateData(newNumEntries); cutAtom.setNumEntries(newNumEntries); // add the new first entry int entryNumber = 0; cutAtom.setSampleCount(entryNumber, newCount); cutAtom.setSampleValue(entryNumber, getSampleValue(i)); entryNumber++; // copy the rest of the entries from the old table to the new table for (i++; i < numEntries; i++, entryNumber++) { cutAtom.setSampleCount(entryNumber, getSampleCount(i)); cutAtom.setSampleValue(entryNumber, getSampleValue(i)); } } public abstract void accept(AtomVisitor v) throws AtomException; /** * Compute the duration of the samples in the track. This atom contains * the duration of each sample. This method iterates over the table * to compute the duration of all the samples * @return the duration of the track */ public long computeDuration() { long duration = 0; for (long i = 0; i < getNumEntries(); i++) { duration += (getSampleCount((int)i) * getSampleValue((int)i)); } return duration; } }