1 /* 2 * Copyright 2012 Sebastian Annies, 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 package com.googlecode.mp4parser.authoring; 17 18 import com.coremedia.iso.boxes.*; 19 import com.coremedia.iso.boxes.fragment.*; 20 import com.coremedia.iso.boxes.mdat.SampleList; 21 22 import java.nio.ByteBuffer; 23 import java.util.Iterator; 24 import java.util.LinkedList; 25 import java.util.List; 26 27 import static com.googlecode.mp4parser.util.CastUtils.l2i; 28 29 /** 30 * Represents a single track of an MP4 file. 31 */ 32 public class Mp4TrackImpl extends AbstractTrack { 33 private List<ByteBuffer> samples; 34 private SampleDescriptionBox sampleDescriptionBox; 35 private List<TimeToSampleBox.Entry> decodingTimeEntries; 36 private List<CompositionTimeToSample.Entry> compositionTimeEntries; 37 private long[] syncSamples = new long[0]; 38 private List<SampleDependencyTypeBox.Entry> sampleDependencies; 39 private TrackMetaData trackMetaData = new TrackMetaData(); 40 private String handler; 41 private AbstractMediaHeaderBox mihd; 42 43 public Mp4TrackImpl(TrackBox trackBox) { 44 final long trackId = trackBox.getTrackHeaderBox().getTrackId(); 45 samples = new SampleList(trackBox); 46 SampleTableBox stbl = trackBox.getMediaBox().getMediaInformationBox().getSampleTableBox(); 47 handler = trackBox.getMediaBox().getHandlerBox().getHandlerType(); 48 49 mihd = trackBox.getMediaBox().getMediaInformationBox().getMediaHeaderBox(); 50 decodingTimeEntries = new LinkedList<TimeToSampleBox.Entry>(); 51 compositionTimeEntries = new LinkedList<CompositionTimeToSample.Entry>(); 52 sampleDependencies = new LinkedList<SampleDependencyTypeBox.Entry>(); 53 54 decodingTimeEntries.addAll(stbl.getTimeToSampleBox().getEntries()); 55 if (stbl.getCompositionTimeToSample() != null) { 56 compositionTimeEntries.addAll(stbl.getCompositionTimeToSample().getEntries()); 57 } 58 if (stbl.getSampleDependencyTypeBox() != null) { 59 sampleDependencies.addAll(stbl.getSampleDependencyTypeBox().getEntries()); 60 } 61 if (stbl.getSyncSampleBox() != null) { 62 syncSamples = stbl.getSyncSampleBox().getSampleNumber(); 63 } 64 65 66 sampleDescriptionBox = stbl.getSampleDescriptionBox(); 67 final List<MovieExtendsBox> movieExtendsBoxes = trackBox.getParent().getBoxes(MovieExtendsBox.class); 68 if (movieExtendsBoxes.size() > 0) { 69 for (MovieExtendsBox mvex : movieExtendsBoxes) { 70 final List<TrackExtendsBox> trackExtendsBoxes = mvex.getBoxes(TrackExtendsBox.class); 71 for (TrackExtendsBox trex : trackExtendsBoxes) { 72 if (trex.getTrackId() == trackId) { 73 List<Long> syncSampleList = new LinkedList<Long>(); 74 75 long sampleNumber = 1; 76 for (MovieFragmentBox movieFragmentBox : trackBox.getIsoFile().getBoxes(MovieFragmentBox.class)) { 77 List<TrackFragmentBox> trafs = movieFragmentBox.getBoxes(TrackFragmentBox.class); 78 for (TrackFragmentBox traf : trafs) { 79 if (traf.getTrackFragmentHeaderBox().getTrackId() == trackId) { 80 List<TrackRunBox> truns = traf.getBoxes(TrackRunBox.class); 81 for (TrackRunBox trun : truns) { 82 final TrackFragmentHeaderBox tfhd = ((TrackFragmentBox) trun.getParent()).getTrackFragmentHeaderBox(); 83 boolean first = true; 84 for (TrackRunBox.Entry entry : trun.getEntries()) { 85 if (trun.isSampleDurationPresent()) { 86 if (decodingTimeEntries.size() == 0 || 87 decodingTimeEntries.get(decodingTimeEntries.size() - 1).getDelta() != entry.getSampleDuration()) { 88 decodingTimeEntries.add(new TimeToSampleBox.Entry(1, entry.getSampleDuration())); 89 } else { 90 TimeToSampleBox.Entry e = decodingTimeEntries.get(decodingTimeEntries.size() - 1); 91 e.setCount(e.getCount() + 1); 92 } 93 } else { 94 if (tfhd.hasDefaultSampleDuration()) { 95 decodingTimeEntries.add(new TimeToSampleBox.Entry(1, tfhd.getDefaultSampleDuration())); 96 } else { 97 decodingTimeEntries.add(new TimeToSampleBox.Entry(1, trex.getDefaultSampleDuration())); 98 } 99 } 100 101 if (trun.isSampleCompositionTimeOffsetPresent()) { 102 if (compositionTimeEntries.size() == 0 || 103 compositionTimeEntries.get(compositionTimeEntries.size() - 1).getOffset() != entry.getSampleCompositionTimeOffset()) { 104 compositionTimeEntries.add(new CompositionTimeToSample.Entry(1, l2i(entry.getSampleCompositionTimeOffset()))); 105 } else { 106 CompositionTimeToSample.Entry e = compositionTimeEntries.get(compositionTimeEntries.size() - 1); 107 e.setCount(e.getCount() + 1); 108 } 109 } 110 final SampleFlags sampleFlags; 111 if (trun.isSampleFlagsPresent()) { 112 sampleFlags = entry.getSampleFlags(); 113 } else { 114 if (first && trun.isFirstSampleFlagsPresent()) { 115 sampleFlags = trun.getFirstSampleFlags(); 116 } else { 117 if (tfhd.hasDefaultSampleFlags()) { 118 sampleFlags = tfhd.getDefaultSampleFlags(); 119 } else { 120 sampleFlags = trex.getDefaultSampleFlags(); 121 } 122 } 123 } 124 if (sampleFlags != null && !sampleFlags.isSampleIsDifferenceSample()) { 125 //iframe 126 syncSampleList.add(sampleNumber); 127 } 128 sampleNumber++; 129 first = false; 130 } 131 } 132 } 133 } 134 } 135 // Warning: Crappy code 136 long[] oldSS = syncSamples; 137 syncSamples = new long[syncSamples.length + syncSampleList.size()]; 138 System.arraycopy(oldSS, 0, syncSamples, 0, oldSS.length); 139 final Iterator<Long> iterator = syncSampleList.iterator(); 140 int i = oldSS.length; 141 while (iterator.hasNext()) { 142 Long syncSampleNumber = iterator.next(); 143 syncSamples[i++] = syncSampleNumber; 144 } 145 } 146 } 147 } 148 } 149 MediaHeaderBox mdhd = trackBox.getMediaBox().getMediaHeaderBox(); 150 TrackHeaderBox tkhd = trackBox.getTrackHeaderBox(); 151 152 setEnabled(tkhd.isEnabled()); 153 setInMovie(tkhd.isInMovie()); 154 setInPoster(tkhd.isInPoster()); 155 setInPreview(tkhd.isInPreview()); 156 157 trackMetaData.setTrackId(tkhd.getTrackId()); 158 trackMetaData.setCreationTime(DateHelper.convert(mdhd.getCreationTime())); 159 trackMetaData.setLanguage(mdhd.getLanguage()); 160 /* System.err.println(mdhd.getModificationTime()); 161 System.err.println(DateHelper.convert(mdhd.getModificationTime())); 162 System.err.println(DateHelper.convert(DateHelper.convert(mdhd.getModificationTime()))); 163 System.err.println(DateHelper.convert(DateHelper.convert(DateHelper.convert(mdhd.getModificationTime()))));*/ 164 165 trackMetaData.setModificationTime(DateHelper.convert(mdhd.getModificationTime())); 166 trackMetaData.setTimescale(mdhd.getTimescale()); 167 trackMetaData.setHeight(tkhd.getHeight()); 168 trackMetaData.setWidth(tkhd.getWidth()); 169 trackMetaData.setLayer(tkhd.getLayer()); 170 trackMetaData.setMatrix(tkhd.getMatrix()); 171 } 172 173 public List<ByteBuffer> getSamples() { 174 return samples; 175 } 176 177 178 public SampleDescriptionBox getSampleDescriptionBox() { 179 return sampleDescriptionBox; 180 } 181 182 public List<TimeToSampleBox.Entry> getDecodingTimeEntries() { 183 return decodingTimeEntries; 184 } 185 186 public List<CompositionTimeToSample.Entry> getCompositionTimeEntries() { 187 return compositionTimeEntries; 188 } 189 190 public long[] getSyncSamples() { 191 return syncSamples; 192 } 193 194 public List<SampleDependencyTypeBox.Entry> getSampleDependencies() { 195 return sampleDependencies; 196 } 197 198 public TrackMetaData getTrackMetaData() { 199 return trackMetaData; 200 } 201 202 public String getHandler() { 203 return handler; 204 } 205 206 public AbstractMediaHeaderBox getMediaHeaderBox() { 207 return mihd; 208 } 209 210 public SubSampleInformationBox getSubsampleInformationBox() { 211 return null; 212 } 213 214 @Override 215 public String toString() { 216 return "Mp4TrackImpl{" + 217 "handler='" + handler + '\'' + 218 '}'; 219 } 220 } 221