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.IsoTypeWriter; 21 import com.googlecode.mp4parser.AbstractFullBox; 22 23 import java.nio.ByteBuffer; 24 25 /** 26 * aligned(8) class TrackFragmentHeaderBox 27 * extends FullBox('tfhd', 0, tf_flags){ 28 * unsigned int(32) track_ID; 29 * // all the following are optional fields 30 * unsigned int(64) base_data_offset; 31 * unsigned int(32) sample_description_index; 32 * unsigned int(32) default_sample_duration; 33 * unsigned int(32) default_sample_size; 34 * unsigned int(32) default_sample_flags 35 * } 36 */ 37 public class TrackFragmentHeaderBox extends AbstractFullBox { 38 public static final String TYPE = "tfhd"; 39 40 private long trackId; 41 private long baseDataOffset = -1; 42 private long sampleDescriptionIndex; 43 private long defaultSampleDuration = -1; 44 private long defaultSampleSize = -1; 45 private SampleFlags defaultSampleFlags; 46 private boolean durationIsEmpty; 47 TrackFragmentHeaderBox()48 public TrackFragmentHeaderBox() { 49 super(TYPE); 50 } 51 getContentSize()52 protected long getContentSize() { 53 long size = 8; 54 int flags = getFlags(); 55 if ((flags & 0x1) == 1) { //baseDataOffsetPresent 56 size += 8; 57 } 58 if ((flags & 0x2) == 0x2) { //sampleDescriptionIndexPresent 59 size += 4; 60 } 61 if ((flags & 0x8) == 0x8) { //defaultSampleDurationPresent 62 size += 4; 63 } 64 if ((flags & 0x10) == 0x10) { //defaultSampleSizePresent 65 size += 4; 66 } 67 if ((flags & 0x20) == 0x20) { //defaultSampleFlagsPresent 68 size += 4; 69 } 70 return size; 71 } 72 73 getContent(ByteBuffer byteBuffer)74 protected void getContent(ByteBuffer byteBuffer) { 75 writeVersionAndFlags(byteBuffer); 76 IsoTypeWriter.writeUInt32(byteBuffer, trackId); 77 78 if ((getFlags() & 0x1) == 1) { //baseDataOffsetPresent 79 IsoTypeWriter.writeUInt64(byteBuffer, getBaseDataOffset()); 80 } 81 if ((getFlags() & 0x2) == 0x2) { //sampleDescriptionIndexPresent 82 IsoTypeWriter.writeUInt32(byteBuffer, getSampleDescriptionIndex()); 83 } 84 if ((getFlags() & 0x8) == 0x8) { //defaultSampleDurationPresent 85 IsoTypeWriter.writeUInt32(byteBuffer, getDefaultSampleDuration()); 86 } 87 if ((getFlags() & 0x10) == 0x10) { //defaultSampleSizePresent 88 IsoTypeWriter.writeUInt32(byteBuffer, getDefaultSampleSize()); 89 } 90 if ((getFlags() & 0x20) == 0x20) { //defaultSampleFlagsPresent 91 defaultSampleFlags.getContent(byteBuffer); 92 } 93 } 94 95 @Override _parseDetails(ByteBuffer content)96 public void _parseDetails(ByteBuffer content) { 97 parseVersionAndFlags(content); 98 trackId = IsoTypeReader.readUInt32(content); 99 if ((getFlags() & 0x1) == 1) { //baseDataOffsetPresent 100 baseDataOffset = IsoTypeReader.readUInt64(content); 101 } 102 if ((getFlags() & 0x2) == 0x2) { //sampleDescriptionIndexPresent 103 sampleDescriptionIndex = IsoTypeReader.readUInt32(content); 104 } 105 if ((getFlags() & 0x8) == 0x8) { //defaultSampleDurationPresent 106 defaultSampleDuration = IsoTypeReader.readUInt32(content); 107 } 108 if ((getFlags() & 0x10) == 0x10) { //defaultSampleSizePresent 109 defaultSampleSize = IsoTypeReader.readUInt32(content); 110 } 111 if ((getFlags() & 0x20) == 0x20) { //defaultSampleFlagsPresent 112 defaultSampleFlags = new SampleFlags(content); 113 } 114 if ((getFlags() & 0x10000) == 0x10000) { //durationIsEmpty 115 durationIsEmpty = true; 116 } 117 } 118 hasBaseDataOffset()119 public boolean hasBaseDataOffset() { 120 return (getFlags() & 0x1) != 0; 121 } 122 hasSampleDescriptionIndex()123 public boolean hasSampleDescriptionIndex() { 124 return (getFlags() & 0x2) != 0; 125 } 126 hasDefaultSampleDuration()127 public boolean hasDefaultSampleDuration() { 128 return (getFlags() & 0x8) != 0; 129 } 130 hasDefaultSampleSize()131 public boolean hasDefaultSampleSize() { 132 return (getFlags() & 0x10) != 0; 133 } 134 hasDefaultSampleFlags()135 public boolean hasDefaultSampleFlags() { 136 return (getFlags() & 0x20) != 0; 137 } 138 getTrackId()139 public long getTrackId() { 140 return trackId; 141 } 142 getBaseDataOffset()143 public long getBaseDataOffset() { 144 return baseDataOffset; 145 } 146 getSampleDescriptionIndex()147 public long getSampleDescriptionIndex() { 148 return sampleDescriptionIndex; 149 } 150 getDefaultSampleDuration()151 public long getDefaultSampleDuration() { 152 return defaultSampleDuration; 153 } 154 getDefaultSampleSize()155 public long getDefaultSampleSize() { 156 return defaultSampleSize; 157 } 158 getDefaultSampleFlags()159 public SampleFlags getDefaultSampleFlags() { 160 return defaultSampleFlags; 161 } 162 isDurationIsEmpty()163 public boolean isDurationIsEmpty() { 164 return durationIsEmpty; 165 } 166 setTrackId(long trackId)167 public void setTrackId(long trackId) { 168 this.trackId = trackId; 169 } 170 setBaseDataOffset(long baseDataOffset)171 public void setBaseDataOffset(long baseDataOffset) { 172 if (baseDataOffset == -1) { 173 setFlags(getFlags() & (Integer.MAX_VALUE ^ 0x1)); 174 } else { 175 setFlags(getFlags() | 0x1); // activate the field 176 } 177 this.baseDataOffset = baseDataOffset; 178 } 179 setSampleDescriptionIndex(long sampleDescriptionIndex)180 public void setSampleDescriptionIndex(long sampleDescriptionIndex) { 181 if (sampleDescriptionIndex == -1) { 182 setFlags(getFlags() & (Integer.MAX_VALUE ^ 0x2)); 183 } else { 184 setFlags(getFlags() | 0x2); // activate the field 185 } 186 this.sampleDescriptionIndex = sampleDescriptionIndex; 187 } 188 setDefaultSampleDuration(long defaultSampleDuration)189 public void setDefaultSampleDuration(long defaultSampleDuration) { 190 setFlags(getFlags() | 0x8); // activate the field 191 this.defaultSampleDuration = defaultSampleDuration; 192 } 193 setDefaultSampleSize(long defaultSampleSize)194 public void setDefaultSampleSize(long defaultSampleSize) { 195 setFlags(getFlags() | 0x10); // activate the field 196 this.defaultSampleSize = defaultSampleSize; 197 } 198 setDefaultSampleFlags(SampleFlags defaultSampleFlags)199 public void setDefaultSampleFlags(SampleFlags defaultSampleFlags) { 200 setFlags(getFlags() | 0x20); // activate the field 201 this.defaultSampleFlags = defaultSampleFlags; 202 } 203 setDurationIsEmpty(boolean durationIsEmpty)204 public void setDurationIsEmpty(boolean durationIsEmpty) { 205 setFlags(getFlags() | 0x10000); // activate the field 206 this.durationIsEmpty = durationIsEmpty; 207 } 208 209 @Override toString()210 public String toString() { 211 final StringBuilder sb = new StringBuilder(); 212 sb.append("TrackFragmentHeaderBox"); 213 sb.append("{trackId=").append(trackId); 214 sb.append(", baseDataOffset=").append(baseDataOffset); 215 sb.append(", sampleDescriptionIndex=").append(sampleDescriptionIndex); 216 sb.append(", defaultSampleDuration=").append(defaultSampleDuration); 217 sb.append(", defaultSampleSize=").append(defaultSampleSize); 218 sb.append(", defaultSampleFlags=").append(defaultSampleFlags); 219 sb.append(", durationIsEmpty=").append(durationIsEmpty); 220 sb.append('}'); 221 return sb.toString(); 222 } 223 224 } 225