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