1 /*
2  * Copyright 2008 CoreMedia AG, Hamburg
3  *
4  * Licensed under the Apache License, Version 2.0 (the License);
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an AS IS BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.coremedia.iso.boxes;
18 
19 
20 import com.coremedia.iso.IsoTypeReader;
21 import com.coremedia.iso.IsoTypeReaderVariable;
22 import com.coremedia.iso.IsoTypeWriter;
23 import com.coremedia.iso.IsoTypeWriterVariable;
24 import com.googlecode.mp4parser.AbstractFullBox;
25 
26 import java.io.IOException;
27 import java.nio.ByteBuffer;
28 import java.util.LinkedList;
29 import java.util.List;
30 
31 /**
32  * aligned(8) class ItemLocationBox extends FullBox(‘iloc’, version, 0) {
33  * unsigned int(4) offset_size;
34  * unsigned int(4) length_size;
35  * unsigned int(4) base_offset_size;
36  * if (version == 1)
37  * unsigned int(4) index_size;
38  * else
39  * unsigned int(4) reserved;
40  * unsigned int(16) item_count;
41  * for (i=0; i<item_count; i++) {
42  * unsigned int(16) item_ID;
43  * if (version == 1) {
44  * unsigned int(12) reserved = 0;
45  * unsigned int(4) construction_method;
46  * }
47  * unsigned int(16) data_reference_index;
48  * unsigned int(base_offset_size*8) base_offset;
49  * unsigned int(16) extent_count;
50  * for (j=0; j<extent_count; j++) {
51  * if ((version == 1) && (index_size > 0)) {
52  * unsigned int(index_size*8) extent_index;
53  * }
54  * unsigned int(offset_size*8) extent_offset;
55  * unsigned int(length_size*8) extent_length;
56  * }
57  * }
58  * }
59  */
60 public class ItemLocationBox extends AbstractFullBox {
61     public int offsetSize = 8;
62     public int lengthSize = 8;
63     public int baseOffsetSize = 8;
64     public int indexSize = 0;
65     public List<Item> items = new LinkedList<Item>();
66 
67     public static final String TYPE = "iloc";
68 
ItemLocationBox()69     public ItemLocationBox() {
70         super(TYPE);
71     }
72 
73     @Override
getContentSize()74     protected long getContentSize() {
75         long size = 8;
76         for (Item item : items) {
77             size += item.getSize();
78         }
79         return size;
80     }
81 
82 
83     @Override
getContent(ByteBuffer byteBuffer)84     protected void getContent(ByteBuffer byteBuffer) {
85         writeVersionAndFlags(byteBuffer);
86         IsoTypeWriter.writeUInt8(byteBuffer, ((offsetSize << 4) | lengthSize));
87         if (getVersion() == 1) {
88             IsoTypeWriter.writeUInt8(byteBuffer, (baseOffsetSize << 4 | indexSize));
89         } else {
90             IsoTypeWriter.writeUInt8(byteBuffer, (baseOffsetSize << 4));
91         }
92         IsoTypeWriter.writeUInt16(byteBuffer, items.size());
93         for (Item item : items) {
94             item.getContent(byteBuffer);
95         }
96     }
97 
98     @Override
_parseDetails(ByteBuffer content)99     public void _parseDetails(ByteBuffer content) {
100         parseVersionAndFlags(content);
101         int tmp = IsoTypeReader.readUInt8(content);
102         offsetSize = tmp >>> 4;
103         lengthSize = tmp & 0xf;
104         tmp = IsoTypeReader.readUInt8(content);
105         baseOffsetSize = tmp >>> 4;
106 
107         if (getVersion() == 1) {
108             indexSize = tmp & 0xf;
109         }
110         int itemCount = IsoTypeReader.readUInt16(content);
111         for (int i = 0; i < itemCount; i++) {
112             items.add(new Item(content));
113         }
114     }
115 
116 
getOffsetSize()117     public int getOffsetSize() {
118         return offsetSize;
119     }
120 
setOffsetSize(int offsetSize)121     public void setOffsetSize(int offsetSize) {
122         this.offsetSize = offsetSize;
123     }
124 
getLengthSize()125     public int getLengthSize() {
126         return lengthSize;
127     }
128 
setLengthSize(int lengthSize)129     public void setLengthSize(int lengthSize) {
130         this.lengthSize = lengthSize;
131     }
132 
getBaseOffsetSize()133     public int getBaseOffsetSize() {
134         return baseOffsetSize;
135     }
136 
setBaseOffsetSize(int baseOffsetSize)137     public void setBaseOffsetSize(int baseOffsetSize) {
138         this.baseOffsetSize = baseOffsetSize;
139     }
140 
getIndexSize()141     public int getIndexSize() {
142         return indexSize;
143     }
144 
setIndexSize(int indexSize)145     public void setIndexSize(int indexSize) {
146         this.indexSize = indexSize;
147     }
148 
getItems()149     public List<Item> getItems() {
150         return items;
151     }
152 
setItems(List<Item> items)153     public void setItems(List<Item> items) {
154         this.items = items;
155     }
156 
157 
createItem(int itemId, int constructionMethod, int dataReferenceIndex, long baseOffset, List<Extent> extents)158     public Item createItem(int itemId, int constructionMethod, int dataReferenceIndex, long baseOffset, List<Extent> extents) {
159         return new Item(itemId, constructionMethod, dataReferenceIndex, baseOffset, extents);
160     }
161 
createItem(ByteBuffer bb)162     Item createItem(ByteBuffer bb) {
163         return new Item(bb);
164     }
165 
166     public class Item {
167         public int itemId;
168         public int constructionMethod;
169         public int dataReferenceIndex;
170         public long baseOffset;
171         public List<Extent> extents = new LinkedList<Extent>();
172 
Item(ByteBuffer in)173         public Item(ByteBuffer in) {
174             itemId = IsoTypeReader.readUInt16(in);
175 
176             if (getVersion() == 1) {
177                 int tmp = IsoTypeReader.readUInt16(in);
178                 constructionMethod = tmp & 0xf;
179             }
180 
181             dataReferenceIndex = IsoTypeReader.readUInt16(in);
182             if (baseOffsetSize > 0) {
183                 baseOffset = IsoTypeReaderVariable.read(in, baseOffsetSize);
184             } else {
185                 baseOffset = 0;
186             }
187             int extentCount = IsoTypeReader.readUInt16(in);
188 
189 
190             for (int i = 0; i < extentCount; i++) {
191                 extents.add(new Extent(in));
192             }
193         }
194 
Item(int itemId, int constructionMethod, int dataReferenceIndex, long baseOffset, List<Extent> extents)195         public Item(int itemId, int constructionMethod, int dataReferenceIndex, long baseOffset, List<Extent> extents) {
196             this.itemId = itemId;
197             this.constructionMethod = constructionMethod;
198             this.dataReferenceIndex = dataReferenceIndex;
199             this.baseOffset = baseOffset;
200             this.extents = extents;
201         }
202 
getSize()203         public int getSize() {
204             int size = 2;
205 
206             if (getVersion() == 1) {
207                 size += 2;
208             }
209 
210             size += 2;
211             size += baseOffsetSize;
212             size += 2;
213 
214 
215             for (Extent extent : extents) {
216                 size += extent.getSize();
217             }
218             return size;
219         }
220 
setBaseOffset(long baseOffset)221         public void setBaseOffset(long baseOffset) {
222             this.baseOffset = baseOffset;
223         }
224 
getContent(ByteBuffer bb)225         public void getContent(ByteBuffer bb)  {
226             IsoTypeWriter.writeUInt16(bb, itemId);
227 
228             if (getVersion() == 1) {
229                 IsoTypeWriter.writeUInt16(bb, constructionMethod);
230             }
231 
232 
233             IsoTypeWriter.writeUInt16(bb, dataReferenceIndex);
234             if (baseOffsetSize > 0) {
235                 IsoTypeWriterVariable.write(baseOffset, bb, baseOffsetSize);
236             }
237             IsoTypeWriter.writeUInt16(bb, extents.size());
238 
239             for (Extent extent : extents) {
240                 extent.getContent(bb);
241             }
242         }
243 
244         @Override
equals(Object o)245         public boolean equals(Object o) {
246             if (this == o) return true;
247             if (o == null || getClass() != o.getClass()) return false;
248 
249             Item item = (Item) o;
250 
251             if (baseOffset != item.baseOffset) return false;
252             if (constructionMethod != item.constructionMethod) return false;
253             if (dataReferenceIndex != item.dataReferenceIndex) return false;
254             if (itemId != item.itemId) return false;
255             if (extents != null ? !extents.equals(item.extents) : item.extents != null) return false;
256 
257             return true;
258         }
259 
260         @Override
hashCode()261         public int hashCode() {
262             int result = itemId;
263             result = 31 * result + constructionMethod;
264             result = 31 * result + dataReferenceIndex;
265             result = 31 * result + (int) (baseOffset ^ (baseOffset >>> 32));
266             result = 31 * result + (extents != null ? extents.hashCode() : 0);
267             return result;
268         }
269 
270         @Override
toString()271         public String toString() {
272             return "Item{" +
273                     "baseOffset=" + baseOffset +
274                     ", itemId=" + itemId +
275                     ", constructionMethod=" + constructionMethod +
276                     ", dataReferenceIndex=" + dataReferenceIndex +
277                     ", extents=" + extents +
278                     '}';
279         }
280     }
281 
282 
createExtent(long extentOffset, long extentLength, long extentIndex)283     public Extent createExtent(long extentOffset, long extentLength, long extentIndex) {
284         return new Extent(extentOffset, extentLength, extentIndex);
285     }
286 
createExtent(ByteBuffer bb)287     Extent createExtent(ByteBuffer bb) {
288         return new Extent(bb);
289     }
290 
291 
292     public class Extent {
293         public long extentOffset;
294         public long extentLength;
295         public long extentIndex;
296 
Extent(long extentOffset, long extentLength, long extentIndex)297         public Extent(long extentOffset, long extentLength, long extentIndex) {
298             this.extentOffset = extentOffset;
299             this.extentLength = extentLength;
300             this.extentIndex = extentIndex;
301         }
302 
303 
Extent(ByteBuffer in)304         public Extent(ByteBuffer in) {
305             if ((getVersion() == 1) && indexSize > 0) {
306                 extentIndex = IsoTypeReaderVariable.read(in, indexSize);
307             }
308             extentOffset = IsoTypeReaderVariable.read(in, offsetSize);
309             extentLength = IsoTypeReaderVariable.read(in, lengthSize);
310         }
311 
getContent(ByteBuffer os)312         public void getContent(ByteBuffer os)  {
313             if ((getVersion() == 1) && indexSize > 0) {
314                 IsoTypeWriterVariable.write(extentIndex, os, indexSize);
315             }
316             IsoTypeWriterVariable.write(extentOffset, os, offsetSize);
317             IsoTypeWriterVariable.write(extentLength, os, lengthSize);
318         }
319 
getSize()320         public int getSize() {
321             return (indexSize > 0 ? indexSize : 0) + offsetSize + lengthSize;
322         }
323 
324 
325         @Override
equals(Object o)326         public boolean equals(Object o) {
327             if (this == o) return true;
328             if (o == null || getClass() != o.getClass()) return false;
329 
330             Extent extent = (Extent) o;
331 
332             if (extentIndex != extent.extentIndex) return false;
333             if (extentLength != extent.extentLength) return false;
334             if (extentOffset != extent.extentOffset) return false;
335 
336             return true;
337         }
338 
339         @Override
hashCode()340         public int hashCode() {
341             int result = (int) (extentOffset ^ (extentOffset >>> 32));
342             result = 31 * result + (int) (extentLength ^ (extentLength >>> 32));
343             result = 31 * result + (int) (extentIndex ^ (extentIndex >>> 32));
344             return result;
345         }
346 
347         @Override
toString()348         public String toString() {
349             final StringBuilder sb = new StringBuilder();
350             sb.append("Extent");
351             sb.append("{extentOffset=").append(extentOffset);
352             sb.append(", extentLength=").append(extentLength);
353             sb.append(", extentIndex=").append(extentIndex);
354             sb.append('}');
355             return sb.toString();
356         }
357     }
358 
359 
360 }
361