1 /* 2 * Copyright 2009 castLabs GmbH, Berlin 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.fragment; 18 19 import com.coremedia.iso.IsoTypeReader; 20 import com.coremedia.iso.IsoTypeReaderVariable; 21 import com.coremedia.iso.IsoTypeWriter; 22 import com.coremedia.iso.IsoTypeWriterVariable; 23 import com.googlecode.mp4parser.AbstractFullBox; 24 25 import java.nio.ByteBuffer; 26 import java.util.ArrayList; 27 import java.util.Collections; 28 import java.util.List; 29 30 /** 31 * aligned(8) class TrackFragmentRandomAccessBox 32 * extends FullBox('tfra', version, 0) { 33 * unsigned int(32) track_ID; 34 * const unsigned int(26) reserved = 0; 35 * unsigned int(2) length_size_of_traf_num; 36 * unsigned int(2) length_size_of_trun_num; 37 * unsigned int(2) length_size_of_sample_num; 38 * unsigned int(32) number_of_entry; 39 * for(i=1; i <= number_of_entry; i++){ 40 * if(version==1){ 41 * unsigned int(64) time; 42 * unsigned int(64) moof_offset; 43 * }else{ 44 * unsigned int(32) time; 45 * unsigned int(32) moof_offset; 46 * } 47 * unsigned int((length_size_of_traf_num+1) * 8) traf_number; 48 * unsigned int((length_size_of_trun_num+1) * 8) trun_number; 49 * unsigned int((length_size_of_sample_num+1) * 8) sample_number; 50 * } 51 * } 52 */ 53 public class TrackFragmentRandomAccessBox extends AbstractFullBox { 54 public static final String TYPE = "tfra"; 55 56 private long trackId; 57 private int reserved; 58 private int lengthSizeOfTrafNum = 2; 59 private int lengthSizeOfTrunNum = 2; 60 private int lengthSizeOfSampleNum = 2; 61 private List<Entry> entries = Collections.emptyList(); 62 TrackFragmentRandomAccessBox()63 public TrackFragmentRandomAccessBox() { 64 super(TYPE); 65 } 66 67 getContentSize()68 protected long getContentSize() { 69 long contentSize = 4; 70 contentSize += 4 + 4 /*26 + 2 + 2 + 2 */ + 4; 71 if (getVersion() == 1) { 72 contentSize += (8 + 8) * entries.size(); 73 } else { 74 contentSize += (4 + 4) * entries.size(); 75 } 76 contentSize += lengthSizeOfTrafNum * entries.size(); 77 contentSize += lengthSizeOfTrunNum * entries.size(); 78 contentSize += lengthSizeOfSampleNum * entries.size(); 79 return contentSize; 80 } 81 82 83 @Override _parseDetails(ByteBuffer content)84 public void _parseDetails(ByteBuffer content) { 85 parseVersionAndFlags(content); 86 trackId = IsoTypeReader.readUInt32(content); 87 long temp = IsoTypeReader.readUInt32(content); 88 reserved = (int) (temp >> 6); 89 lengthSizeOfTrafNum = ((int) (temp & 0x3F) >> 4) + 1; 90 lengthSizeOfTrunNum = ((int) (temp & 0xC) >> 2) + 1; 91 lengthSizeOfSampleNum = ((int) (temp & 0x3)) + 1; 92 long numberOfEntries = IsoTypeReader.readUInt32(content); 93 94 entries = new ArrayList<Entry>(); 95 96 for (int i = 0; i < numberOfEntries; i++) { 97 Entry entry = new Entry(); 98 if (getVersion() == 1) { 99 entry.time = IsoTypeReader.readUInt64(content); 100 entry.moofOffset = IsoTypeReader.readUInt64(content); 101 } else { 102 entry.time = IsoTypeReader.readUInt32(content); 103 entry.moofOffset = IsoTypeReader.readUInt32(content); 104 } 105 entry.trafNumber = IsoTypeReaderVariable.read(content, lengthSizeOfTrafNum); 106 entry.trunNumber = IsoTypeReaderVariable.read(content, lengthSizeOfTrunNum); 107 entry.sampleNumber = IsoTypeReaderVariable.read(content, lengthSizeOfSampleNum); 108 109 entries.add(entry); 110 } 111 112 } 113 114 115 @Override getContent(ByteBuffer byteBuffer)116 protected void getContent(ByteBuffer byteBuffer) { 117 writeVersionAndFlags(byteBuffer); 118 IsoTypeWriter.writeUInt32(byteBuffer, trackId); 119 long temp; 120 temp = reserved << 6; 121 temp = temp | (((lengthSizeOfTrafNum - 1) & 0x3) << 4); 122 temp = temp | (((lengthSizeOfTrunNum - 1) & 0x3) << 2); 123 temp = temp | ((lengthSizeOfSampleNum - 1) & 0x3); 124 IsoTypeWriter.writeUInt32(byteBuffer, temp); 125 IsoTypeWriter.writeUInt32(byteBuffer, entries.size()); 126 127 for (Entry entry : entries) { 128 if (getVersion() == 1) { 129 IsoTypeWriter.writeUInt64(byteBuffer, entry.time); 130 IsoTypeWriter.writeUInt64(byteBuffer, entry.moofOffset); 131 } else { 132 IsoTypeWriter.writeUInt32(byteBuffer, entry.time); 133 IsoTypeWriter.writeUInt32(byteBuffer, entry.moofOffset); 134 } 135 IsoTypeWriterVariable.write(entry.trafNumber, byteBuffer, lengthSizeOfTrafNum); 136 IsoTypeWriterVariable.write(entry.trunNumber, byteBuffer, lengthSizeOfTrunNum); 137 IsoTypeWriterVariable.write(entry.sampleNumber, byteBuffer, lengthSizeOfSampleNum); 138 139 } 140 } 141 142 setTrackId(long trackId)143 public void setTrackId(long trackId) { 144 this.trackId = trackId; 145 } 146 setLengthSizeOfTrafNum(int lengthSizeOfTrafNum)147 public void setLengthSizeOfTrafNum(int lengthSizeOfTrafNum) { 148 this.lengthSizeOfTrafNum = lengthSizeOfTrafNum; 149 } 150 setLengthSizeOfTrunNum(int lengthSizeOfTrunNum)151 public void setLengthSizeOfTrunNum(int lengthSizeOfTrunNum) { 152 this.lengthSizeOfTrunNum = lengthSizeOfTrunNum; 153 } 154 setLengthSizeOfSampleNum(int lengthSizeOfSampleNum)155 public void setLengthSizeOfSampleNum(int lengthSizeOfSampleNum) { 156 this.lengthSizeOfSampleNum = lengthSizeOfSampleNum; 157 } 158 getTrackId()159 public long getTrackId() { 160 return trackId; 161 } 162 getReserved()163 public int getReserved() { 164 return reserved; 165 } 166 getLengthSizeOfTrafNum()167 public int getLengthSizeOfTrafNum() { 168 return lengthSizeOfTrafNum; 169 } 170 getLengthSizeOfTrunNum()171 public int getLengthSizeOfTrunNum() { 172 return lengthSizeOfTrunNum; 173 } 174 getLengthSizeOfSampleNum()175 public int getLengthSizeOfSampleNum() { 176 return lengthSizeOfSampleNum; 177 } 178 getNumberOfEntries()179 public long getNumberOfEntries() { 180 return entries.size(); 181 } 182 getEntries()183 public List<Entry> getEntries() { 184 return Collections.unmodifiableList(entries); 185 } 186 setEntries(List<Entry> entries)187 public void setEntries(List<Entry> entries) { 188 this.entries = entries; 189 } 190 191 public static class Entry { 192 private long time; 193 private long moofOffset; 194 private long trafNumber; 195 private long trunNumber; 196 private long sampleNumber; 197 Entry()198 public Entry() { 199 } 200 Entry(long time, long moofOffset, long trafNumber, long trunNumber, long sampleNumber)201 public Entry(long time, long moofOffset, long trafNumber, long trunNumber, long sampleNumber) { 202 this.moofOffset = moofOffset; 203 this.sampleNumber = sampleNumber; 204 this.time = time; 205 this.trafNumber = trafNumber; 206 this.trunNumber = trunNumber; 207 } 208 getTime()209 public long getTime() { 210 return time; 211 } 212 getMoofOffset()213 public long getMoofOffset() { 214 return moofOffset; 215 } 216 getTrafNumber()217 public long getTrafNumber() { 218 return trafNumber; 219 } 220 getTrunNumber()221 public long getTrunNumber() { 222 return trunNumber; 223 } 224 getSampleNumber()225 public long getSampleNumber() { 226 return sampleNumber; 227 } 228 setTime(long time)229 public void setTime(long time) { 230 this.time = time; 231 } 232 setMoofOffset(long moofOffset)233 public void setMoofOffset(long moofOffset) { 234 this.moofOffset = moofOffset; 235 } 236 setTrafNumber(long trafNumber)237 public void setTrafNumber(long trafNumber) { 238 this.trafNumber = trafNumber; 239 } 240 setTrunNumber(long trunNumber)241 public void setTrunNumber(long trunNumber) { 242 this.trunNumber = trunNumber; 243 } 244 setSampleNumber(long sampleNumber)245 public void setSampleNumber(long sampleNumber) { 246 this.sampleNumber = sampleNumber; 247 } 248 249 @Override toString()250 public String toString() { 251 return "Entry{" + 252 "time=" + time + 253 ", moofOffset=" + moofOffset + 254 ", trafNumber=" + trafNumber + 255 ", trunNumber=" + trunNumber + 256 ", sampleNumber=" + sampleNumber + 257 '}'; 258 } 259 260 @Override equals(Object o)261 public boolean equals(Object o) { 262 if (this == o) return true; 263 if (o == null || getClass() != o.getClass()) return false; 264 265 Entry entry = (Entry) o; 266 267 if (moofOffset != entry.moofOffset) return false; 268 if (sampleNumber != entry.sampleNumber) return false; 269 if (time != entry.time) return false; 270 if (trafNumber != entry.trafNumber) return false; 271 if (trunNumber != entry.trunNumber) return false; 272 273 return true; 274 } 275 276 @Override hashCode()277 public int hashCode() { 278 int result = (int) (time ^ (time >>> 32)); 279 result = 31 * result + (int) (moofOffset ^ (moofOffset >>> 32)); 280 result = 31 * result + (int) (trafNumber ^ (trafNumber >>> 32)); 281 result = 31 * result + (int) (trunNumber ^ (trunNumber >>> 32)); 282 result = 31 * result + (int) (sampleNumber ^ (sampleNumber >>> 32)); 283 return result; 284 } 285 } 286 287 @Override toString()288 public String toString() { 289 return "TrackFragmentRandomAccessBox{" + 290 "trackId=" + trackId + 291 ", entries=" + entries + 292 '}'; 293 } 294 } 295