1package com.googlecode.mp4parser.boxes.threegpp26244;
2
3import com.coremedia.iso.IsoTypeReader;
4import com.coremedia.iso.IsoTypeWriter;
5import com.googlecode.mp4parser.AbstractFullBox;
6import com.googlecode.mp4parser.boxes.mp4.objectdescriptors.BitReaderBuffer;
7import com.googlecode.mp4parser.boxes.mp4.objectdescriptors.BitWriterBuffer;
8
9import java.nio.ByteBuffer;
10import java.util.ArrayList;
11import java.util.List;
12
13/**
14 * <pre>
15 * aligned(8) class SegmentIndexBox extends FullBox(‘sidx’, version, 0) {
16 *  unsigned int(32) reference_ID;
17 *  unsigned int(32) timescale;
18 *  if (version==0)
19 *  {
20 *   unsigned int(32) earliest_presentation_time;
21 *   unsigned int(32) first_offset;
22 *  }
23 *  else
24 *  {
25 *   unsigned int(64) earliest_presentation_time;
26 *   unsigned int(64) first_offset;
27 *  }
28 *  unsigned int(16) reserved = 0;
29 *  unsigned int(16) reference_count;
30 *  for(i=1; i <= reference_count; i++)
31 *  {
32 *   bit (1)            reference_type;
33 *   unsigned int(31)   referenced_size;
34 *   unsigned int(32)   subsegment_duration;
35 *   bit(1)             starts_with_SAP;
36 *   unsigned int(3)    SAP_type;
37 *   unsigned int(28)   SAP_delta_time;
38 *  }
39 * }
40 * </pre>
41 */
42public class SegmentIndexBox extends AbstractFullBox {
43    public static final String TYPE = "sidx";
44    List<Entry> entries = new ArrayList<Entry>();
45
46    long referenceId;
47    long timeScale;
48    long earliestPresentationTime;
49    long firstOffset;
50    int reserved;
51
52
53    public SegmentIndexBox() {
54        super(TYPE);
55    }
56
57    @Override
58    protected long getContentSize() {
59        long size = 4;
60        size += 4;
61        size += 4;
62        size += getVersion() == 0 ? 8 : 16;
63        size += 2; // reserved
64        size += 2; // reference count
65
66        size += entries.size() * 12;
67
68        return size;
69    }
70
71    @Override
72    protected void getContent(ByteBuffer byteBuffer) {
73        writeVersionAndFlags(byteBuffer);
74        IsoTypeWriter.writeUInt32(byteBuffer, referenceId);
75        IsoTypeWriter.writeUInt32(byteBuffer, timeScale);
76        if (getVersion() == 0) {
77            IsoTypeWriter.writeUInt32(byteBuffer, earliestPresentationTime);
78            IsoTypeWriter.writeUInt32(byteBuffer, firstOffset);
79        } else {
80            IsoTypeWriter.writeUInt64(byteBuffer, earliestPresentationTime);
81            IsoTypeWriter.writeUInt64(byteBuffer, firstOffset);
82        }
83        IsoTypeWriter.writeUInt16(byteBuffer, reserved);
84        IsoTypeWriter.writeUInt16(byteBuffer, entries.size());
85        for (Entry entry : entries) {
86            BitWriterBuffer b = new BitWriterBuffer(byteBuffer);
87            b.writeBits(entry.getReferenceType(), 1);
88            b.writeBits(entry.getReferencedSize(), 31);
89            IsoTypeWriter.writeUInt32(byteBuffer, entry.getSubsegmentDuration());
90            b = new BitWriterBuffer(byteBuffer);
91            b.writeBits(entry.getStartsWithSap(), 1);
92            b.writeBits(entry.getSapType(), 3);
93            b.writeBits(entry.getSapDeltaTime(), 28);
94        }
95
96    }
97
98    @Override
99    protected void _parseDetails(ByteBuffer content) {
100        parseVersionAndFlags(content);
101        referenceId = IsoTypeReader.readUInt32(content);
102        timeScale = IsoTypeReader.readUInt32(content);
103        if (getVersion() == 0) {
104            earliestPresentationTime = IsoTypeReader.readUInt32(content);
105            firstOffset = IsoTypeReader.readUInt32(content);
106        } else {
107            earliestPresentationTime = IsoTypeReader.readUInt64(content);
108            firstOffset = IsoTypeReader.readUInt64(content);
109        }
110        reserved = IsoTypeReader.readUInt16(content);
111        int numEntries = IsoTypeReader.readUInt16(content);
112        for (int i = 0; i < numEntries; i++) {
113            BitReaderBuffer b = new BitReaderBuffer(content);
114            Entry e = new Entry();
115            e.setReferenceType((byte) b.readBits(1));
116            e.setReferencedSize(b.readBits(31));
117            e.setSubsegmentDuration(IsoTypeReader.readUInt32(content));
118            b = new BitReaderBuffer(content);
119            e.setStartsWithSap((byte) b.readBits(1));
120            e.setSapType((byte) b.readBits(3));
121            e.setSapDeltaTime(b.readBits(28));
122            entries.add(e);
123        }
124    }
125
126
127    public List<Entry> getEntries() {
128        return entries;
129    }
130
131    public void setEntries(List<Entry> entries) {
132        this.entries = entries;
133    }
134
135    public long getReferenceId() {
136        return referenceId;
137    }
138
139    public void setReferenceId(long referenceId) {
140        this.referenceId = referenceId;
141    }
142
143    public long getTimeScale() {
144        return timeScale;
145    }
146
147    public void setTimeScale(long timeScale) {
148        this.timeScale = timeScale;
149    }
150
151    public long getEarliestPresentationTime() {
152        return earliestPresentationTime;
153    }
154
155    public void setEarliestPresentationTime(long earliestPresentationTime) {
156        this.earliestPresentationTime = earliestPresentationTime;
157    }
158
159    public long getFirstOffset() {
160        return firstOffset;
161    }
162
163    public void setFirstOffset(long firstOffset) {
164        this.firstOffset = firstOffset;
165    }
166
167    public int getReserved() {
168        return reserved;
169    }
170
171    public void setReserved(int reserved) {
172        this.reserved = reserved;
173    }
174
175    public static class Entry {
176        byte referenceType;
177        int referencedSize;
178        long subsegmentDuration;
179        byte startsWithSap;
180        byte sapType;
181        int sapDeltaTime;
182
183        public Entry() {
184        }
185
186        public Entry(byte referenceType, int referencedSize, long subsegmentDuration, byte startsWithSap, byte sapType, int sapDeltaTime) {
187            this.referenceType = referenceType;
188            this.referencedSize = referencedSize;
189            this.subsegmentDuration = subsegmentDuration;
190            this.startsWithSap = startsWithSap;
191            this.sapType = sapType;
192            this.sapDeltaTime = sapDeltaTime;
193        }
194
195        public byte getReferenceType() {
196            return referenceType;
197        }
198
199        public void setReferenceType(byte referenceType) {
200            this.referenceType = referenceType;
201        }
202
203        public int getReferencedSize() {
204            return referencedSize;
205        }
206
207        public void setReferencedSize(int referencedSize) {
208            this.referencedSize = referencedSize;
209        }
210
211        public long getSubsegmentDuration() {
212            return subsegmentDuration;
213        }
214
215        public void setSubsegmentDuration(long subsegmentDuration) {
216            this.subsegmentDuration = subsegmentDuration;
217        }
218
219        public byte getStartsWithSap() {
220            return startsWithSap;
221        }
222
223        public void setStartsWithSap(byte startsWithSap) {
224            this.startsWithSap = startsWithSap;
225        }
226
227        public byte getSapType() {
228            return sapType;
229        }
230
231        public void setSapType(byte sapType) {
232            this.sapType = sapType;
233        }
234
235        public int getSapDeltaTime() {
236            return sapDeltaTime;
237        }
238
239        public void setSapDeltaTime(int sapDeltaTime) {
240            this.sapDeltaTime = sapDeltaTime;
241        }
242
243        @Override
244        public String toString() {
245            return "Entry{" +
246                    "referenceType=" + referenceType +
247                    ", referencedSize=" + referencedSize +
248                    ", subsegmentDuration=" + subsegmentDuration +
249                    ", startsWithSap=" + startsWithSap +
250                    ", sapType=" + sapType +
251                    ", sapDeltaTime=" + sapDeltaTime +
252                    '}';
253        }
254
255        @Override
256        public boolean equals(Object o) {
257            if (this == o) return true;
258            if (o == null || getClass() != o.getClass()) return false;
259
260            Entry entry = (Entry) o;
261
262            if (referenceType != entry.referenceType) return false;
263            if (referencedSize != entry.referencedSize) return false;
264            if (sapDeltaTime != entry.sapDeltaTime) return false;
265            if (sapType != entry.sapType) return false;
266            if (startsWithSap != entry.startsWithSap) return false;
267            if (subsegmentDuration != entry.subsegmentDuration) return false;
268
269            return true;
270        }
271
272        @Override
273        public int hashCode() {
274            int result = (int) referenceType;
275            result = 31 * result + referencedSize;
276            result = 31 * result + (int) (subsegmentDuration ^ (subsegmentDuration >>> 32));
277            result = 31 * result + (int) startsWithSap;
278            result = 31 * result + (int) sapType;
279            result = 31 * result + sapDeltaTime;
280            return result;
281        }
282    }
283}
284