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&lt;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