org.mp4parser.boxes.iso14496.part12.CompositionTimeToSample Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of isoparser Show documentation
Show all versions of isoparser Show documentation
A generic parser and writer for all ISO 14496 based files (MP4, Quicktime, DCF, PDCF, ...)
package org.mp4parser.boxes.iso14496.part12;
import org.mp4parser.support.AbstractFullBox;
import org.mp4parser.tools.CastUtils;
import org.mp4parser.tools.IsoTypeReader;
import org.mp4parser.tools.IsoTypeWriter;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
/**
* 4cc = "{@value #TYPE}"
*
* aligned(8) class CompositionOffsetBox extends FullBox(‘ctts’, version = 0, 0) {
* unsigned int(32) entry_count;
* int i;
* if (version==0) {
* for (i=0; i < entry_count; i++) {
* unsigned int(32) sample_count;
* unsigned int(32) sample_offset;
* }
* }
* else if (version == 1) {
* for (i=0; i < entry_count; i++) {
* unsigned int(32) sample_count;
* signed int(32) sample_offset;
* }
* }
* }
*
*
* This box provides the offset between decoding time and composition time.
* In version 0 of this box the decoding time must be less than the composition time, and
* the offsets are expressed as unsigned numbers such that
* CT(n) = DT(n) + CTTS(n) where CTTS(n) is the (uncompressed) table entry for sample n.
* In version 1 of this box, the composition timeline and the decoding timeline are
* still derived from each other, but the offsets are signed.
* It is recommended that for the computed composition timestamps, there is
* exactly one with the value 0 (zero).
*/
public class CompositionTimeToSample extends AbstractFullBox {
public static final String TYPE = "ctts";
List entries = Collections.emptyList();
public CompositionTimeToSample() {
super(TYPE);
}
/**
* Decompresses the list of entries and returns the list of composition times.
*
* @param entries composition time to sample entries in compressed form
* @return decoding time per sample
*/
public static int[] blowupCompositionTimes(List entries) {
long numOfSamples = 0;
for (CompositionTimeToSample.Entry entry : entries) {
numOfSamples += entry.getCount();
}
assert numOfSamples <= Integer.MAX_VALUE;
int[] decodingTime = new int[(int) numOfSamples];
int current = 0;
for (CompositionTimeToSample.Entry entry : entries) {
for (int i = 0; i < entry.getCount(); i++) {
decodingTime[current++] = entry.getOffset();
}
}
return decodingTime;
}
protected long getContentSize() {
return 8 + 8 * entries.size();
}
public List getEntries() {
return entries;
}
public void setEntries(List entries) {
this.entries = entries;
}
@Override
public void _parseDetails(ByteBuffer content) {
parseVersionAndFlags(content);
int numberOfEntries = CastUtils.l2i(IsoTypeReader.readUInt32(content));
entries = new ArrayList(numberOfEntries);
for (int i = 0; i < numberOfEntries; i++) {
Entry e = new Entry(CastUtils.l2i(IsoTypeReader.readUInt32(content)), content.getInt());
entries.add(e);
}
}
@Override
protected void getContent(ByteBuffer byteBuffer) {
writeVersionAndFlags(byteBuffer);
IsoTypeWriter.writeUInt32(byteBuffer, entries.size());
for (Entry entry : entries) {
IsoTypeWriter.writeUInt32(byteBuffer, entry.getCount());
byteBuffer.putInt(entry.getOffset());
}
}
public static class Entry {
int count;
int offset;
public Entry(int count, int offset) {
this.count = count;
this.offset = offset;
}
public int getCount() {
return count;
}
public void setCount(int count) {
this.count = count;
}
public int getOffset() {
return offset;
}
public void setOffset(int offset) {
this.offset = offset;
}
@Override
public String toString() {
return "Entry{" +
"count=" + count +
", offset=" + offset +
'}';
}
}
}