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