1dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhupackage com.coremedia.iso.boxes; 2dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu 3dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhuimport com.coremedia.iso.IsoTypeReader; 4dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhuimport com.coremedia.iso.IsoTypeWriter; 5dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhuimport com.googlecode.mp4parser.AbstractFullBox; 6dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu 7dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhuimport java.nio.ByteBuffer; 8dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhuimport java.util.ArrayList; 9dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhuimport java.util.Collections; 10dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhuimport java.util.List; 11dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu 12dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhuimport static com.googlecode.mp4parser.util.CastUtils.l2i; 13dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu 14dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu/** 15dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu * <pre> 16dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu * aligned(8) class CompositionOffsetBox 17dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu * extends FullBox(‘ctts’, version = 0, 0) { 18dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu * unsigned int(32) entry_count; 19dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu * int i; 20dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu * if (version==0) { 21dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu * for (i=0; i < entry_count; i++) { 22dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu * unsigned int(32) sample_count; 23dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu * unsigned int(32) sample_offset; 24dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu * } 25dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu * } 26dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu * else if (version == 1) { 27dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu * for (i=0; i < entry_count; i++) { 28dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu * unsigned int(32) sample_count; 29dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu * signed int(32) sample_offset; 30dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu * } 31dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu * } 32dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu * } 33dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu * </pre> 34dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu * <p/> 35dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu * This box provides the offset between decoding time and composition time. 36dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu * In version 0 of this box the decoding time must be less than the composition time, and 37dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu * the offsets are expressed as unsigned numbers such that 38dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu * CT(n) = DT(n) + CTTS(n) where CTTS(n) is the (uncompressed) table entry for sample n. 39dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu * <p/> 40dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu * In version 1 of this box, the composition timeline and the decoding timeline are 41dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu * still derived from each other, but the offsets are signed. 42dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu * It is recommended that for the computed composition timestamps, there is 43dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu * exactly one with the value 0 (zero). 44dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu */ 45dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhupublic class CompositionTimeToSample extends AbstractFullBox { 46dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu public static final String TYPE = "ctts"; 47dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu 48dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu List<Entry> entries = Collections.emptyList(); 49dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu 50dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu public CompositionTimeToSample() { 51dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu super(TYPE); 52dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu } 53dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu 54dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu protected long getContentSize() { 55dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu return 8 + 8 * entries.size(); 56dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu } 57dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu 58dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu public List<Entry> getEntries() { 59dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu return entries; 60dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu } 61dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu 62dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu public void setEntries(List<Entry> entries) { 63dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu this.entries = entries; 64dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu } 65dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu 66dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu @Override 67dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu public void _parseDetails(ByteBuffer content) { 68dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu parseVersionAndFlags(content); 69dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu int numberOfEntries = l2i(IsoTypeReader.readUInt32(content)); 70dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu entries = new ArrayList<Entry>(numberOfEntries); 71dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu for (int i = 0; i < numberOfEntries; i++) { 72dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu Entry e = new Entry(l2i(IsoTypeReader.readUInt32(content)), content.getInt()); 73dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu entries.add(e); 74dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu } 75dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu } 76dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu 77dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu @Override 78dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu protected void getContent(ByteBuffer byteBuffer) { 79dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu writeVersionAndFlags(byteBuffer); 80dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu IsoTypeWriter.writeUInt32(byteBuffer, entries.size()); 81dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu 82dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu for (Entry entry : entries) { 83dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu IsoTypeWriter.writeUInt32(byteBuffer, entry.getCount()); 84dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu byteBuffer.putInt(entry.getOffset()); 85dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu } 86dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu 87dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu } 88dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu 89dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu 90dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu public static class Entry { 91dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu int count; 92dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu int offset; 93dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu 94dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu public Entry(int count, int offset) { 95dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu this.count = count; 96dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu this.offset = offset; 97dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu } 98dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu 99dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu public int getCount() { 100dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu return count; 101dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu } 102dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu 103dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu public int getOffset() { 104dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu return offset; 105dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu } 106dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu 107dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu public void setCount(int count) { 108dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu this.count = count; 109dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu } 110dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu 111dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu public void setOffset(int offset) { 112dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu this.offset = offset; 113dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu } 114dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu 115dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu @Override 116dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu public String toString() { 117dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu return "Entry{" + 118dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu "count=" + count + 119dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu ", offset=" + offset + 120dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu '}'; 121dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu } 122dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu } 123dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu 124dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu 125dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu /** 126dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu * Decompresses the list of entries and returns the list of composition times. 127dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu * 128dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu * @return decoding time per sample 129dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu */ 130dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu public static int[] blowupCompositionTimes(List<CompositionTimeToSample.Entry> entries) { 131dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu long numOfSamples = 0; 132dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu for (CompositionTimeToSample.Entry entry : entries) { 133dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu numOfSamples += entry.getCount(); 134dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu } 135dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu assert numOfSamples <= Integer.MAX_VALUE; 136dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu int[] decodingTime = new int[(int) numOfSamples]; 137dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu 138dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu int current = 0; 139dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu 140dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu 141dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu for (CompositionTimeToSample.Entry entry : entries) { 142dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu for (int i = 0; i < entry.getCount(); i++) { 143dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu decodingTime[current++] = entry.getOffset(); 144dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu } 145dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu } 146dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu 147dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu return decodingTime; 148dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu } 149dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu 150dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu} 151