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 69 public ItemLocationBox() { 70 super(TYPE); 71 } 72 73 @Override 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 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 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 117 public int getOffsetSize() { 118 return offsetSize; 119 } 120 121 public void setOffsetSize(int offsetSize) { 122 this.offsetSize = offsetSize; 123 } 124 125 public int getLengthSize() { 126 return lengthSize; 127 } 128 129 public void setLengthSize(int lengthSize) { 130 this.lengthSize = lengthSize; 131 } 132 133 public int getBaseOffsetSize() { 134 return baseOffsetSize; 135 } 136 137 public void setBaseOffsetSize(int baseOffsetSize) { 138 this.baseOffsetSize = baseOffsetSize; 139 } 140 141 public int getIndexSize() { 142 return indexSize; 143 } 144 145 public void setIndexSize(int indexSize) { 146 this.indexSize = indexSize; 147 } 148 149 public List<Item> getItems() { 150 return items; 151 } 152 153 public void setItems(List<Item> items) { 154 this.items = items; 155 } 156 157 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 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 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 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 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 221 public void setBaseOffset(long baseOffset) { 222 this.baseOffset = baseOffset; 223 } 224 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 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 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 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 283 public Extent createExtent(long extentOffset, long extentLength, long extentIndex) { 284 return new Extent(extentOffset, extentLength, extentIndex); 285 } 286 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 297 public Extent(long extentOffset, long extentLength, long extentIndex) { 298 this.extentOffset = extentOffset; 299 this.extentLength = extentLength; 300 this.extentIndex = extentIndex; 301 } 302 303 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 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 320 public int getSize() { 321 return (indexSize > 0 ? indexSize : 0) + offsetSize + lengthSize; 322 } 323 324 325 @Override 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 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 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