1dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu/* 2dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu * Copyright 2012 Sebastian Annies, Hamburg 3dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu * 4dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu * Licensed under the Apache License, Version 2.0 (the License); 5dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu * you may not use this file except in compliance with the License. 6dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu * You may obtain a copy of the License at 7dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu * 8dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu * http://www.apache.org/licenses/LICENSE-2.0 9dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu * 10dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu * Unless required by applicable law or agreed to in writing, software 11dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu * distributed under the License is distributed on an AS IS BASIS, 12dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu * See the License for the specific language governing permissions and 14dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu * limitations under the License. 15dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu */ 16dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhupackage com.googlecode.mp4parser.authoring.builder; 17dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu 18dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhuimport com.coremedia.iso.BoxParser; 19dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhuimport com.coremedia.iso.IsoFile; 20dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhuimport com.coremedia.iso.IsoTypeWriter; 21dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhuimport com.coremedia.iso.boxes.*; 22dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhuimport com.coremedia.iso.boxes.fragment.*; 23dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhuimport com.googlecode.mp4parser.authoring.DateHelper; 24dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhuimport com.googlecode.mp4parser.authoring.Movie; 25dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhuimport com.googlecode.mp4parser.authoring.Track; 26dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu 27dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhuimport java.io.IOException; 28dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhuimport java.nio.ByteBuffer; 29dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhuimport java.nio.channels.GatheringByteChannel; 30dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhuimport java.nio.channels.ReadableByteChannel; 31dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhuimport java.nio.channels.WritableByteChannel; 32dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhuimport java.util.*; 33dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhuimport java.util.logging.Logger; 34dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu 35dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhuimport static com.googlecode.mp4parser.util.CastUtils.l2i; 36dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu 37dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu/** 38dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu * Creates a fragmented MP4 file. 39dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu */ 40dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhupublic class FragmentedMp4Builder implements Mp4Builder { 41dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu private static final Logger LOG = Logger.getLogger(FragmentedMp4Builder.class.getName()); 42dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu 43dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu protected FragmentIntersectionFinder intersectionFinder; 44dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu 45dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu public FragmentedMp4Builder() { 46dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu this.intersectionFinder = new SyncSampleIntersectFinderImpl(); 47dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu } 48dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu 49dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu public List<String> getAllowedHandlers() { 50dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu return Arrays.asList("soun", "vide"); 51dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu } 52dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu 53dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu public Box createFtyp(Movie movie) { 54dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu List<String> minorBrands = new LinkedList<String>(); 55dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu minorBrands.add("isom"); 56dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu minorBrands.add("iso2"); 57dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu minorBrands.add("avc1"); 58dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu return new FileTypeBox("isom", 0, minorBrands); 59dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu } 60dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu 61dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu /** 62dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu * Some formats require sorting of the fragments. E.g. Ultraviolet CFF files are required 63dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu * to contain the fragments size sort: 64dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu * <ul> 65dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu * <li>video[1].getBytes().length < audio[1].getBytes().length < subs[1].getBytes().length</li> 66dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu * <li> audio[2].getBytes().length < video[2].getBytes().length < subs[2].getBytes().length</li> 67dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu * </ul> 68dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu * 69dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu * make this fragment: 70dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu * 71dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu * <ol> 72dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu * <li>video[1]</li> 73dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu * <li>audio[1]</li> 74dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu * <li>subs[1]</li> 75dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu * <li>audio[2]</li> 76dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu * <li>video[2]</li> 77dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu * <li>subs[2]</li> 78dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu * </ol> 79dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu * 80dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu * @param tracks the list of tracks to returned sorted 81dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu * @param cycle current fragment (sorting may vary between the fragments) 82dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu * @param intersectionMap a map from tracks to their fragments' first samples. 83dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu * @return the list of tracks in order of appearance in the fragment 84dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu */ 85dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu protected List<Track> sortTracksInSequence(List<Track> tracks, final int cycle, final Map<Track, long[]> intersectionMap) { 86dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu tracks = new LinkedList<Track>(tracks); 87dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu Collections.sort(tracks, new Comparator<Track>() { 88dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu public int compare(Track o1, Track o2) { 89dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu long[] startSamples1 = intersectionMap.get(o1); 90dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu long startSample1 = startSamples1[cycle]; 91dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu // one based sample numbers - the first sample is 1 92dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu long endSample1 = cycle + 1 < startSamples1.length ? startSamples1[cycle + 1] : o1.getSamples().size() + 1; 93dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu long[] startSamples2 = intersectionMap.get(o2); 94dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu long startSample2 = startSamples2[cycle]; 95dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu // one based sample numbers - the first sample is 1 96dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu long endSample2 = cycle + 1 < startSamples2.length ? startSamples2[cycle + 1] : o2.getSamples().size() + 1; 97dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu List<ByteBuffer> samples1 = o1.getSamples().subList(l2i(startSample1) - 1, l2i(endSample1) - 1); 98dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu List<ByteBuffer> samples2 = o2.getSamples().subList(l2i(startSample2) - 1, l2i(endSample2) - 1); 99dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu int size1 = 0; 100dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu for (ByteBuffer byteBuffer : samples1) { 101dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu size1 += byteBuffer.limit(); 102dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu } 103dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu int size2 = 0; 104dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu for (ByteBuffer byteBuffer : samples2) { 105dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu size2 += byteBuffer.limit(); 106dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu } 107dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu return size1 - size2; 108dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu } 109dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu }); 110dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu return tracks; 111dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu } 112dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu 113dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu protected List<Box> createMoofMdat(final Movie movie) { 114dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu List<Box> boxes = new LinkedList<Box>(); 115dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu HashMap<Track, long[]> intersectionMap = new HashMap<Track, long[]>(); 116dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu int maxNumberOfFragments = 0; 117dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu for (Track track : movie.getTracks()) { 118dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu long[] intersects = intersectionFinder.sampleNumbers(track, movie); 119dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu intersectionMap.put(track, intersects); 120dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu maxNumberOfFragments = Math.max(maxNumberOfFragments, intersects.length); 121dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu } 122dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu 123dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu 124dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu int sequence = 1; 125dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu // this loop has two indices: 126dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu 127dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu for (int cycle = 0; cycle < maxNumberOfFragments; cycle++) { 128dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu 129dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu final List<Track> sortedTracks = sortTracksInSequence(movie.getTracks(), cycle, intersectionMap); 130dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu 131dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu for (Track track : sortedTracks) { 132dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu if (getAllowedHandlers().isEmpty() || getAllowedHandlers().contains(track.getHandler())) { 133dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu long[] startSamples = intersectionMap.get(track); 134dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu //some tracks may have less fragments -> skip them 135dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu if (cycle < startSamples.length) { 136dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu 137dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu long startSample = startSamples[cycle]; 138dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu // one based sample numbers - the first sample is 1 139dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu long endSample = cycle + 1 < startSamples.length ? startSamples[cycle + 1] : track.getSamples().size() + 1; 140dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu 141dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu // if startSample == endSample the cycle is empty! 142dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu if (startSample != endSample) { 143dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu boxes.add(createMoof(startSample, endSample, track, sequence)); 144dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu boxes.add(createMdat(startSample, endSample, track, sequence++)); 145dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu } 146dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu } 147dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu } 148dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu } 149dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu } 150dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu return boxes; 151dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu } 152dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu 153dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu /** 154dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu * {@inheritDoc} 155dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu */ 156dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu public IsoFile build(Movie movie) { 157dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu LOG.fine("Creating movie " + movie); 158dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu IsoFile isoFile = new IsoFile(); 159dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu 160dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu 161dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu isoFile.addBox(createFtyp(movie)); 162dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu isoFile.addBox(createMoov(movie)); 163dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu 164dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu for (Box box : createMoofMdat(movie)) { 165dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu isoFile.addBox(box); 166dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu } 167dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu isoFile.addBox(createMfra(movie, isoFile)); 168dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu 169dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu return isoFile; 170dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu } 171dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu 172dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu protected Box createMdat(final long startSample, final long endSample, final Track track, final int i) { 173dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu 174dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu class Mdat implements Box { 175dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu ContainerBox parent; 176dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu 177dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu public ContainerBox getParent() { 178dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu return parent; 179dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu } 180dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu 181dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu public void setParent(ContainerBox parent) { 182dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu this.parent = parent; 183dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu } 184dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu 185dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu public long getSize() { 186dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu long size = 8; // I don't expect 2gig fragments 187dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu for (ByteBuffer sample : getSamples(startSample, endSample, track, i)) { 188dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu size += sample.limit(); 189dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu } 190dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu return size; 191dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu } 192dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu 193dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu public String getType() { 194dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu return "mdat"; 195dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu } 196dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu 197dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu public void getBox(WritableByteChannel writableByteChannel) throws IOException { 198dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu List<ByteBuffer> bbs = getSamples(startSample, endSample, track, i); 199dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu final List<ByteBuffer> samples = ByteBufferHelper.mergeAdjacentBuffers(bbs); 200dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu ByteBuffer header = ByteBuffer.allocate(8); 201dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu IsoTypeWriter.writeUInt32(header, l2i(getSize())); 202dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu header.put(IsoFile.fourCCtoBytes(getType())); 203dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu header.rewind(); 204dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu writableByteChannel.write(header); 205dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu if (writableByteChannel instanceof GatheringByteChannel) { 206dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu 207dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu int STEPSIZE = 1024; 208dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu // This is required to prevent android from crashing 209dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu // it seems that {@link GatheringByteChannel#write(java.nio.ByteBuffer[])} 210dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu // just handles up to 1024 buffers 211dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu for (int i = 0; i < Math.ceil((double) samples.size() / STEPSIZE); i++) { 212dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu List<ByteBuffer> sublist = samples.subList( 213dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu i * STEPSIZE, // start 214dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu (i + 1) * STEPSIZE < samples.size() ? (i + 1) * STEPSIZE : samples.size()); // end 215dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu ByteBuffer sampleArray[] = sublist.toArray(new ByteBuffer[sublist.size()]); 216dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu do { 217dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu ((GatheringByteChannel) writableByteChannel).write(sampleArray); 218dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu } while (sampleArray[sampleArray.length - 1].remaining() > 0); 219dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu } 220dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu //System.err.println(bytesWritten); 221dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu } else { 222dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu for (ByteBuffer sample : samples) { 223dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu sample.rewind(); 224dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu writableByteChannel.write(sample); 225dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu } 226dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu } 227dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu 228dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu } 229dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu 230dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu public void parse(ReadableByteChannel readableByteChannel, ByteBuffer header, long contentSize, BoxParser boxParser) throws IOException { 231dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu 232dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu } 233dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu } 234dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu 235dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu return new Mdat(); 236dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu } 237dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu 238dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu protected Box createTfhd(long startSample, long endSample, Track track, int sequenceNumber) { 239dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu TrackFragmentHeaderBox tfhd = new TrackFragmentHeaderBox(); 240dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu SampleFlags sf = new SampleFlags(); 241dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu 242dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu tfhd.setDefaultSampleFlags(sf); 243dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu tfhd.setBaseDataOffset(-1); 244dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu tfhd.setTrackId(track.getTrackMetaData().getTrackId()); 245dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu return tfhd; 246dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu } 247dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu 248dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu protected Box createMfhd(long startSample, long endSample, Track track, int sequenceNumber) { 249dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu MovieFragmentHeaderBox mfhd = new MovieFragmentHeaderBox(); 250dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu mfhd.setSequenceNumber(sequenceNumber); 251dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu return mfhd; 252dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu } 253dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu 254dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu protected Box createTraf(long startSample, long endSample, Track track, int sequenceNumber) { 255dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu TrackFragmentBox traf = new TrackFragmentBox(); 256dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu traf.addBox(createTfhd(startSample, endSample, track, sequenceNumber)); 257dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu for (Box trun : createTruns(startSample, endSample, track, sequenceNumber)) { 258dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu traf.addBox(trun); 259dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu } 260dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu 261dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu return traf; 262dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu } 263dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu 264dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu 265dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu /** 266dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu * Gets the all samples starting with <code>startSample</code> (one based -> one is the first) and 267dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu * ending with <code>endSample</code> (exclusive). 268dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu * 269dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu * @param startSample low endpoint (inclusive) of the sample sequence 270dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu * @param endSample high endpoint (exclusive) of the sample sequence 271dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu * @param track source of the samples 272dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu * @param sequenceNumber the fragment index of the requested list of samples 273dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu * @return a <code>List<ByteBuffer></code> of raw samples 274dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu */ 275dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu protected List<ByteBuffer> getSamples(long startSample, long endSample, Track track, int sequenceNumber) { 276dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu // since startSample and endSample are one-based substract 1 before addressing list elements 277dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu return track.getSamples().subList(l2i(startSample) - 1, l2i(endSample) - 1); 278dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu } 279dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu 280dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu /** 281dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu * Gets the sizes of a sequence of samples- 282dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu * 283dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu * @param startSample low endpoint (inclusive) of the sample sequence 284dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu * @param endSample high endpoint (exclusive) of the sample sequence 285dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu * @param track source of the samples 286dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu * @param sequenceNumber the fragment index of the requested list of samples 287dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu * @return 288dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu */ 289dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu protected long[] getSampleSizes(long startSample, long endSample, Track track, int sequenceNumber) { 290dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu List<ByteBuffer> samples = getSamples(startSample, endSample, track, sequenceNumber); 291dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu 292dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu long[] sampleSizes = new long[samples.size()]; 293dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu for (int i = 0; i < sampleSizes.length; i++) { 294dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu sampleSizes[i] = samples.get(i).limit(); 295dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu } 296dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu return sampleSizes; 297dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu } 298dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu 299dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu /** 300dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu * Creates one or more track run boxes for a given sequence. 301dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu * 302dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu * @param startSample low endpoint (inclusive) of the sample sequence 303dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu * @param endSample high endpoint (exclusive) of the sample sequence 304dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu * @param track source of the samples 305dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu * @param sequenceNumber the fragment index of the requested list of samples 306dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu * @return the list of TrackRun boxes. 307dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu */ 308dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu protected List<? extends Box> createTruns(long startSample, long endSample, Track track, int sequenceNumber) { 309dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu TrackRunBox trun = new TrackRunBox(); 310dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu long[] sampleSizes = getSampleSizes(startSample, endSample, track, sequenceNumber); 311dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu 312dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu trun.setSampleDurationPresent(true); 313dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu trun.setSampleSizePresent(true); 314dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu List<TrackRunBox.Entry> entries = new ArrayList<TrackRunBox.Entry>(l2i(endSample - startSample)); 315dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu 316dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu 317dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu Queue<TimeToSampleBox.Entry> timeQueue = new LinkedList<TimeToSampleBox.Entry>(track.getDecodingTimeEntries()); 318dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu long left = startSample - 1; 319dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu long curEntryLeft = timeQueue.peek().getCount(); 320dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu while (left > curEntryLeft) { 321dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu left -= curEntryLeft; 322dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu timeQueue.remove(); 323dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu curEntryLeft = timeQueue.peek().getCount(); 324dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu } 325dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu curEntryLeft -= left; 326dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu 327dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu 328dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu Queue<CompositionTimeToSample.Entry> compositionTimeQueue = 329dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu track.getCompositionTimeEntries() != null && track.getCompositionTimeEntries().size() > 0 ? 330dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu new LinkedList<CompositionTimeToSample.Entry>(track.getCompositionTimeEntries()) : null; 331dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu long compositionTimeEntriesLeft = compositionTimeQueue != null ? compositionTimeQueue.peek().getCount() : -1; 332dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu 333dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu 334dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu trun.setSampleCompositionTimeOffsetPresent(compositionTimeEntriesLeft > 0); 335dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu 336dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu // fast forward composition stuff 337dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu for (long i = 1; i < startSample; i++) { 338dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu if (compositionTimeQueue != null) { 339dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu //trun.setSampleCompositionTimeOffsetPresent(true); 340dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu if (--compositionTimeEntriesLeft == 0 && compositionTimeQueue.size() > 1) { 341dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu compositionTimeQueue.remove(); 342dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu compositionTimeEntriesLeft = compositionTimeQueue.element().getCount(); 343dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu } 344dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu } 345dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu } 346dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu 347dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu boolean sampleFlagsRequired = (track.getSampleDependencies() != null && !track.getSampleDependencies().isEmpty() || 348dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu track.getSyncSamples() != null && track.getSyncSamples().length != 0); 349dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu 350dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu trun.setSampleFlagsPresent(sampleFlagsRequired); 351dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu 352dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu for (int i = 0; i < sampleSizes.length; i++) { 353dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu TrackRunBox.Entry entry = new TrackRunBox.Entry(); 354dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu entry.setSampleSize(sampleSizes[i]); 355dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu if (sampleFlagsRequired) { 356dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu //if (false) { 357dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu SampleFlags sflags = new SampleFlags(); 358dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu 359dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu if (track.getSampleDependencies() != null && !track.getSampleDependencies().isEmpty()) { 360dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu SampleDependencyTypeBox.Entry e = track.getSampleDependencies().get(i); 361dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu sflags.setSampleDependsOn(e.getSampleDependsOn()); 362dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu sflags.setSampleIsDependedOn(e.getSampleIsDependentOn()); 363dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu sflags.setSampleHasRedundancy(e.getSampleHasRedundancy()); 364dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu } 365dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu if (track.getSyncSamples() != null && track.getSyncSamples().length > 0) { 366dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu // we have to mark non-sync samples! 367dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu if (Arrays.binarySearch(track.getSyncSamples(), startSample + i) >= 0) { 368dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu sflags.setSampleIsDifferenceSample(false); 369dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu sflags.setSampleDependsOn(2); 370dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu } else { 371dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu sflags.setSampleIsDifferenceSample(true); 372dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu sflags.setSampleDependsOn(1); 373dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu } 374dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu } 375dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu // i don't have sample degradation 376dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu entry.setSampleFlags(sflags); 377dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu 378dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu } 379dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu 380dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu entry.setSampleDuration(timeQueue.peek().getDelta()); 381dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu if (--curEntryLeft == 0 && timeQueue.size() > 1) { 382dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu timeQueue.remove(); 383dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu curEntryLeft = timeQueue.peek().getCount(); 384dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu } 385dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu 386dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu if (compositionTimeQueue != null) { 387dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu entry.setSampleCompositionTimeOffset(compositionTimeQueue.peek().getOffset()); 388dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu if (--compositionTimeEntriesLeft == 0 && compositionTimeQueue.size() > 1) { 389dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu compositionTimeQueue.remove(); 390dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu compositionTimeEntriesLeft = compositionTimeQueue.element().getCount(); 391dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu } 392dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu } 393dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu entries.add(entry); 394dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu } 395dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu 396dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu trun.setEntries(entries); 397dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu 398dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu return Collections.singletonList(trun); 399dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu } 400dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu 401dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu /** 402dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu * Creates a 'moof' box for a given sequence of samples. 403dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu * 404dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu * @param startSample low endpoint (inclusive) of the sample sequence 405dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu * @param endSample high endpoint (exclusive) of the sample sequence 406dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu * @param track source of the samples 407dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu * @param sequenceNumber the fragment index of the requested list of samples 408dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu * @return the list of TrackRun boxes. 409dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu */ 410dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu protected Box createMoof(long startSample, long endSample, Track track, int sequenceNumber) { 411dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu MovieFragmentBox moof = new MovieFragmentBox(); 412dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu moof.addBox(createMfhd(startSample, endSample, track, sequenceNumber)); 413dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu moof.addBox(createTraf(startSample, endSample, track, sequenceNumber)); 414dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu 415dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu TrackRunBox firstTrun = moof.getTrackRunBoxes().get(0); 416dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu firstTrun.setDataOffset(1); // dummy to make size correct 417dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu firstTrun.setDataOffset((int) (8 + moof.getSize())); // mdat header + moof size 418dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu 419dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu return moof; 420dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu } 421dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu 422dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu /** 423dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu * Creates a single 'mvhd' movie header box for a given movie. 424dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu * 425dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu * @param movie the concerned movie 426dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu * @return an 'mvhd' box 427dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu */ 428dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu protected Box createMvhd(Movie movie) { 429dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu MovieHeaderBox mvhd = new MovieHeaderBox(); 430dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu mvhd.setVersion(1); 431dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu mvhd.setCreationTime(DateHelper.convert(new Date())); 432dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu mvhd.setModificationTime(DateHelper.convert(new Date())); 433dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu long movieTimeScale = movie.getTimescale(); 434dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu long duration = 0; 435dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu 436dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu for (Track track : movie.getTracks()) { 437dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu long tracksDuration = getDuration(track) * movieTimeScale / track.getTrackMetaData().getTimescale(); 438dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu if (tracksDuration > duration) { 439dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu duration = tracksDuration; 440dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu } 441dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu 442dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu 443dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu } 444dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu 445dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu mvhd.setDuration(duration); 446dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu mvhd.setTimescale(movieTimeScale); 447dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu // find the next available trackId 448dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu long nextTrackId = 0; 449dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu for (Track track : movie.getTracks()) { 450dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu nextTrackId = nextTrackId < track.getTrackMetaData().getTrackId() ? track.getTrackMetaData().getTrackId() : nextTrackId; 451dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu } 452dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu mvhd.setNextTrackId(++nextTrackId); 453dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu return mvhd; 454dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu } 455dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu 456dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu /** 457dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu * Creates a fully populated 'moov' box with all child boxes. Child boxes are: 458dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu * <ul> 459dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu * <li>{@link #createMvhd(com.googlecode.mp4parser.authoring.Movie) mvhd}</li> 460dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu * <li>{@link #createMvex(com.googlecode.mp4parser.authoring.Movie) mvex}</li> 461dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu * <li>a {@link #createTrak(com.googlecode.mp4parser.authoring.Track, com.googlecode.mp4parser.authoring.Movie) trak} for every track</li> 462dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu * </ul> 463dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu * 464dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu * @param movie the concerned movie 465dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu * @return fully populated 'moov' 466dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu */ 467dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu protected Box createMoov(Movie movie) { 468dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu MovieBox movieBox = new MovieBox(); 469dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu 470dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu movieBox.addBox(createMvhd(movie)); 471dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu movieBox.addBox(createMvex(movie)); 472dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu 473dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu for (Track track : movie.getTracks()) { 474dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu movieBox.addBox(createTrak(track, movie)); 475dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu } 476dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu // metadata here 477dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu return movieBox; 478dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu 479dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu } 480dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu 481dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu /** 482dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu * Creates a 'tfra' - track fragment random access box for the given track with the isoFile. 483dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu * The tfra contains a map of random access points with time as key and offset within the isofile 484dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu * as value. 485dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu * 486dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu * @param track the concerned track 487dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu * @param isoFile the track is contained in 488dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu * @return a track fragment random access box. 489dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu */ 490dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu protected Box createTfra(Track track, IsoFile isoFile) { 491dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu TrackFragmentRandomAccessBox tfra = new TrackFragmentRandomAccessBox(); 492dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu tfra.setVersion(1); // use long offsets and times 493dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu List<TrackFragmentRandomAccessBox.Entry> offset2timeEntries = new LinkedList<TrackFragmentRandomAccessBox.Entry>(); 494dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu List<Box> boxes = isoFile.getBoxes(); 495dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu long offset = 0; 496dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu long duration = 0; 497dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu for (Box box : boxes) { 498dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu if (box instanceof MovieFragmentBox) { 499dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu List<TrackFragmentBox> trafs = ((MovieFragmentBox) box).getBoxes(TrackFragmentBox.class); 500dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu for (int i = 0; i < trafs.size(); i++) { 501dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu TrackFragmentBox traf = trafs.get(i); 502dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu if (traf.getTrackFragmentHeaderBox().getTrackId() == track.getTrackMetaData().getTrackId()) { 503dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu // here we are at the offset required for the current entry. 504dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu List<TrackRunBox> truns = traf.getBoxes(TrackRunBox.class); 505dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu for (int j = 0; j < truns.size(); j++) { 506dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu List<TrackFragmentRandomAccessBox.Entry> offset2timeEntriesThisTrun = new LinkedList<TrackFragmentRandomAccessBox.Entry>(); 507dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu TrackRunBox trun = truns.get(j); 508dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu for (int k = 0; k < trun.getEntries().size(); k++) { 509dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu TrackRunBox.Entry trunEntry = trun.getEntries().get(k); 510dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu SampleFlags sf = null; 511dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu if (k == 0 && trun.isFirstSampleFlagsPresent()) { 512dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu sf = trun.getFirstSampleFlags(); 513dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu } else if (trun.isSampleFlagsPresent()) { 514dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu sf = trunEntry.getSampleFlags(); 515dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu } else { 516dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu List<MovieExtendsBox> mvexs = isoFile.getMovieBox().getBoxes(MovieExtendsBox.class); 517dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu for (MovieExtendsBox mvex : mvexs) { 518dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu List<TrackExtendsBox> trexs = mvex.getBoxes(TrackExtendsBox.class); 519dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu for (TrackExtendsBox trex : trexs) { 520dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu if (trex.getTrackId() == track.getTrackMetaData().getTrackId()) { 521dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu sf = trex.getDefaultSampleFlags(); 522dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu } 523dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu } 524dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu } 525dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu 526dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu } 527dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu if (sf == null) { 528dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu throw new RuntimeException("Could not find any SampleFlags to indicate random access or not"); 529dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu } 530dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu if (sf.getSampleDependsOn() == 2) { 531dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu offset2timeEntriesThisTrun.add(new TrackFragmentRandomAccessBox.Entry( 532dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu duration, 533dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu offset, 534dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu i + 1, j + 1, k + 1)); 535dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu } 536dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu duration += trunEntry.getSampleDuration(); 537dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu } 538dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu if (offset2timeEntriesThisTrun.size() == trun.getEntries().size() && trun.getEntries().size() > 0) { 539dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu // Oooops every sample seems to be random access sample 540dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu // is this an audio track? I don't care. 541dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu // I just use the first for trun sample for tfra random access 542dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu offset2timeEntries.add(offset2timeEntriesThisTrun.get(0)); 543dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu } else { 544dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu offset2timeEntries.addAll(offset2timeEntriesThisTrun); 545dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu } 546dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu } 547dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu } 548dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu } 549dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu } 550dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu 551dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu 552dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu offset += box.getSize(); 553dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu } 554dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu tfra.setEntries(offset2timeEntries); 555dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu tfra.setTrackId(track.getTrackMetaData().getTrackId()); 556dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu return tfra; 557dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu } 558dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu 559dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu /** 560dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu * Creates a 'mfra' - movie fragment random access box for the given movie in the given 561dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu * isofile. Uses {@link #createTfra(com.googlecode.mp4parser.authoring.Track, com.coremedia.iso.IsoFile)} 562dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu * to generate the child boxes. 563dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu * 564dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu * @param movie concerned movie 565dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu * @param isoFile concerned isofile 566dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu * @return a complete 'mfra' box 567dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu */ 568dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu protected Box createMfra(Movie movie, IsoFile isoFile) { 569dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu MovieFragmentRandomAccessBox mfra = new MovieFragmentRandomAccessBox(); 570dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu for (Track track : movie.getTracks()) { 571dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu mfra.addBox(createTfra(track, isoFile)); 572dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu } 573dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu 574dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu MovieFragmentRandomAccessOffsetBox mfro = new MovieFragmentRandomAccessOffsetBox(); 575dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu mfra.addBox(mfro); 576dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu mfro.setMfraSize(mfra.getSize()); 577dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu return mfra; 578dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu } 579dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu 580dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu protected Box createTrex(Movie movie, Track track) { 581dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu TrackExtendsBox trex = new TrackExtendsBox(); 582dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu trex.setTrackId(track.getTrackMetaData().getTrackId()); 583dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu trex.setDefaultSampleDescriptionIndex(1); 584dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu trex.setDefaultSampleDuration(0); 585dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu trex.setDefaultSampleSize(0); 586dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu SampleFlags sf = new SampleFlags(); 587dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu if ("soun".equals(track.getHandler())) { 588dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu // as far as I know there is no audio encoding 589dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu // where the sample are not self contained. 590dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu sf.setSampleDependsOn(2); 591dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu sf.setSampleIsDependedOn(2); 592dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu } 593dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu trex.setDefaultSampleFlags(sf); 594dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu return trex; 595dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu } 596dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu 597dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu /** 598dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu * Creates a 'mvex' - movie extends box and populates it with 'trex' boxes 599dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu * by calling {@link #createTrex(com.googlecode.mp4parser.authoring.Movie, com.googlecode.mp4parser.authoring.Track)} 600dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu * for each track to generate them 601dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu * 602dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu * @param movie the source movie 603dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu * @return a complete 'mvex' 604dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu */ 605dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu protected Box createMvex(Movie movie) { 606dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu MovieExtendsBox mvex = new MovieExtendsBox(); 607dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu final MovieExtendsHeaderBox mved = new MovieExtendsHeaderBox(); 608dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu for (Track track : movie.getTracks()) { 609dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu final long trackDuration = getTrackDuration(movie, track); 610dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu if (mved.getFragmentDuration() < trackDuration) { 611dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu mved.setFragmentDuration(trackDuration); 612dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu } 613dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu } 614dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu mvex.addBox(mved); 615dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu 616dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu for (Track track : movie.getTracks()) { 617dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu mvex.addBox(createTrex(movie, track)); 618dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu } 619dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu return mvex; 620dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu } 621dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu 622dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu protected Box createTkhd(Movie movie, Track track) { 623dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu TrackHeaderBox tkhd = new TrackHeaderBox(); 624dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu tkhd.setVersion(1); 625dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu int flags = 0; 626dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu if (track.isEnabled()) { 627dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu flags += 1; 628dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu } 629dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu 630dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu if (track.isInMovie()) { 631dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu flags += 2; 632dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu } 633dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu 634dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu if (track.isInPreview()) { 635dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu flags += 4; 636dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu } 637dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu 638dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu if (track.isInPoster()) { 639dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu flags += 8; 640dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu } 641dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu tkhd.setFlags(flags); 642dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu 643dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu tkhd.setAlternateGroup(track.getTrackMetaData().getGroup()); 644dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu tkhd.setCreationTime(DateHelper.convert(track.getTrackMetaData().getCreationTime())); 645dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu // We need to take edit list box into account in trackheader duration 646dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu // but as long as I don't support edit list boxes it is sufficient to 647dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu // just translate media duration to movie timescale 648dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu tkhd.setDuration(getTrackDuration(movie, track)); 649dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu tkhd.setHeight(track.getTrackMetaData().getHeight()); 650dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu tkhd.setWidth(track.getTrackMetaData().getWidth()); 651dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu tkhd.setLayer(track.getTrackMetaData().getLayer()); 652dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu tkhd.setModificationTime(DateHelper.convert(new Date())); 653dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu tkhd.setTrackId(track.getTrackMetaData().getTrackId()); 654dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu tkhd.setVolume(track.getTrackMetaData().getVolume()); 655dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu return tkhd; 656dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu } 657dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu 658dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu private long getTrackDuration(Movie movie, Track track) { 659dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu return getDuration(track) * movie.getTimescale() / track.getTrackMetaData().getTimescale(); 660dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu } 661dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu 662dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu protected Box createMdhd(Movie movie, Track track) { 663dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu MediaHeaderBox mdhd = new MediaHeaderBox(); 664dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu mdhd.setCreationTime(DateHelper.convert(track.getTrackMetaData().getCreationTime())); 665dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu mdhd.setDuration(getDuration(track)); 666dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu mdhd.setTimescale(track.getTrackMetaData().getTimescale()); 667dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu mdhd.setLanguage(track.getTrackMetaData().getLanguage()); 668dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu return mdhd; 669dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu } 670dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu 671dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu protected Box createStbl(Movie movie, Track track) { 672dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu SampleTableBox stbl = new SampleTableBox(); 673dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu 674dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu stbl.addBox(track.getSampleDescriptionBox()); 675dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu stbl.addBox(new TimeToSampleBox()); 676dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu //stbl.addBox(new SampleToChunkBox()); 677dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu stbl.addBox(new StaticChunkOffsetBox()); 678dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu return stbl; 679dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu } 680dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu 681dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu protected Box createMinf(Track track, Movie movie) { 682dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu MediaInformationBox minf = new MediaInformationBox(); 683dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu minf.addBox(track.getMediaHeaderBox()); 684dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu minf.addBox(createDinf(movie, track)); 685dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu minf.addBox(createStbl(movie, track)); 686dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu return minf; 687dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu } 688dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu 689dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu protected Box createMdiaHdlr(Track track, Movie movie) { 690dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu HandlerBox hdlr = new HandlerBox(); 691dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu hdlr.setHandlerType(track.getHandler()); 692dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu return hdlr; 693dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu } 694dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu 695dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu protected Box createMdia(Track track, Movie movie) { 696dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu MediaBox mdia = new MediaBox(); 697dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu mdia.addBox(createMdhd(movie, track)); 698dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu 699dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu 700dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu mdia.addBox(createMdiaHdlr(track, movie)); 701dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu 702dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu 703dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu mdia.addBox(createMinf(track, movie)); 704dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu return mdia; 705dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu } 706dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu 707dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu protected Box createTrak(Track track, Movie movie) { 708dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu LOG.fine("Creating Track " + track); 709dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu TrackBox trackBox = new TrackBox(); 710dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu trackBox.addBox(createTkhd(movie, track)); 711dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu trackBox.addBox(createMdia(track, movie)); 712dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu return trackBox; 713dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu } 714dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu 715dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu protected DataInformationBox createDinf(Movie movie, Track track) { 716dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu DataInformationBox dinf = new DataInformationBox(); 717dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu DataReferenceBox dref = new DataReferenceBox(); 718dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu dinf.addBox(dref); 719dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu DataEntryUrlBox url = new DataEntryUrlBox(); 720dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu url.setFlags(1); 721dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu dref.addBox(url); 722dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu return dinf; 723dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu } 724dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu 725dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu public FragmentIntersectionFinder getFragmentIntersectionFinder() { 726dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu return intersectionFinder; 727dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu } 728dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu 729dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu public void setIntersectionFinder(FragmentIntersectionFinder intersectionFinder) { 730dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu this.intersectionFinder = intersectionFinder; 731dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu } 732dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu 733dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu protected long getDuration(Track track) { 734dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu long duration = 0; 735dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu for (TimeToSampleBox.Entry entry : track.getDecodingTimeEntries()) { 736dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu duration += entry.getCount() * entry.getDelta(); 737dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu } 738dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu return duration; 739dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu } 740dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu 741dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu 742dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu} 743