1dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu/*
2dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu * Copyright 2008 CoreMedia AG, Hamburg
3dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu *
4dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu * Licensed under the Apache License, Version 2.0 (the License);
5dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu * you may not use this file except in compliance with the License.
6dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu * You may obtain a copy of the License at
7dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu *
8dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu *     http://www.apache.org/licenses/LICENSE-2.0
9dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu *
10dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu * Unless required by applicable law or agreed to in writing, software
11dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu * distributed under the License is distributed on an AS IS BASIS,
12dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu * See the License for the specific language governing permissions and
14dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu * limitations under the License.
15dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu */
16dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu
17dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhupackage com.coremedia.iso.boxes;
18dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu
19dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu
20dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhuimport com.coremedia.iso.IsoTypeReader;
21dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhuimport com.coremedia.iso.IsoTypeWriter;
22dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhuimport com.googlecode.mp4parser.AbstractFullBox;
23dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu
24dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhuimport java.nio.ByteBuffer;
25dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhuimport java.util.ArrayList;
26dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhuimport java.util.Collections;
27dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhuimport java.util.List;
28dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu
29dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhuimport static com.googlecode.mp4parser.util.CastUtils.l2i;
30dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu
31dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu/**
32dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu * This box contains a compact version of a table that allows indexing from decoding time to sample number.
33dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu * Other tables give sample sizes and pointers, from the sample number. Each entry in the table gives the
34dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu * number of consecutive samples with the same time delta, and the delta of those samples. By adding the
35dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu * deltas a complete time-to-sample map may be built.<br>
36dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu * The Decoding Time to Sample Box contains decode time delta's: <code>DT(n+1) = DT(n) + STTS(n)</code> where STTS(n)
37dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu * is the (uncompressed) table entry for sample n.<br>
38dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu * The sample entries are ordered by decoding time stamps; therefore the deltas are all non-negative. <br>
39dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu * The DT axis has a zero origin; <code>DT(i) = SUM(for j=0 to i-1 of delta(j))</code>, and the sum of all
40dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu * deltas gives the length of the media in the track (not mapped to the overall timescale, and not considering
41dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu * any edit list).    <br>
42dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu * The Edit List Box provides the initial CT value if it is non-empty (non-zero).
43dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu */
44dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhupublic class TimeToSampleBox extends AbstractFullBox {
45dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu    public static final String TYPE = "stts";
46dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu
47dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu    List<Entry> entries = Collections.emptyList();
48dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu
49dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu
50dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu    public TimeToSampleBox() {
51dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu        super(TYPE);
52dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu    }
53dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu
54dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu    protected long getContentSize() {
55dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu        return 8 + entries.size() * 8;
56dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu    }
57dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu
58dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu    @Override
59dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu    public void _parseDetails(ByteBuffer content) {
60dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu        parseVersionAndFlags(content);
61dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu        int entryCount = l2i(IsoTypeReader.readUInt32(content));
62dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu        entries = new ArrayList<Entry>(entryCount);
63dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu
64dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu        for (int i = 0; i < entryCount; i++) {
65dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu            entries.add(new Entry(IsoTypeReader.readUInt32(content), IsoTypeReader.readUInt32(content)));
66dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu        }
67dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu
68dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu    }
69dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu
70dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu    @Override
71dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu    protected void getContent(ByteBuffer byteBuffer) {
72dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu        writeVersionAndFlags(byteBuffer);
73dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu        IsoTypeWriter.writeUInt32(byteBuffer, entries.size());
74dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu        for (Entry entry : entries) {
75dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu            IsoTypeWriter.writeUInt32(byteBuffer, entry.getCount());
76dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu            IsoTypeWriter.writeUInt32(byteBuffer, entry.getDelta());
77dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu        }
78dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu    }
79dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu
80dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu    public List<Entry> getEntries() {
81dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu        return entries;
82dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu    }
83dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu
84dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu    public void setEntries(List<Entry> entries) {
85dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu        this.entries = entries;
86dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu    }
87dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu
88dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu    public String toString() {
89dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu        return "TimeToSampleBox[entryCount=" + entries.size() + "]";
90dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu    }
91dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu
92dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu    public static class Entry {
93dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu        long count;
94dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu        long delta;
95dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu
96dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu        public Entry(long count, long delta) {
97dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu            this.count = count;
98dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu            this.delta = delta;
99dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu        }
100dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu
101dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu        public long getCount() {
102dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu            return count;
103dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu        }
104dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu
105dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu        public long getDelta() {
106dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu            return delta;
107dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu        }
108dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu
109dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu        public void setCount(long count) {
110dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu            this.count = count;
111dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu        }
112dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu
113dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu        public void setDelta(long delta) {
114dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu            this.delta = delta;
115dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu        }
116dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu
117dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu        @Override
118dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu        public String toString() {
119dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu            return "Entry{" +
120dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu                    "count=" + count +
121dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu                    ", delta=" + delta +
122dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu                    '}';
123dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu        }
124dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu    }
125dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu
126dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu    /**
127dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu     * Decompresses the list of entries and returns the list of decoding times.
128dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu     *
129dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu     * @return decoding time per sample
130dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu     */
131dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu    public static long[] blowupTimeToSamples(List<TimeToSampleBox.Entry> entries) {
132dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu        long numOfSamples = 0;
133dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu        for (TimeToSampleBox.Entry entry : entries) {
134dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu            numOfSamples += entry.getCount();
135dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu        }
136dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu        assert numOfSamples <= Integer.MAX_VALUE;
137dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu        long[] decodingTime = new long[(int) numOfSamples];
138dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu
139dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu        int current = 0;
140dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu
141dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu
142dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu        for (TimeToSampleBox.Entry entry : entries) {
143dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu            for (int i = 0; i < entry.getCount(); i++) {
144dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu                decodingTime[current++] = entry.getDelta();
145dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu            }
146dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu        }
147dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu
148dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu        return decodingTime;
149dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu    }
150dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu
151dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu
152dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu}
153