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.tracks;
17dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu
18dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhuimport com.coremedia.iso.boxes.*;
19dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhuimport com.googlecode.mp4parser.authoring.Track;
20dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhuimport com.googlecode.mp4parser.authoring.TrackMetaData;
21dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu
22dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhuimport java.nio.ByteBuffer;
23dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhuimport java.util.ArrayList;
24dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhuimport java.util.Arrays;
25dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhuimport java.util.LinkedList;
26dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhuimport java.util.List;
27dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhuimport java.util.Queue;
28dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhuimport java.util.logging.Logger;
29dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu
30dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu/**
31dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu * Changes the timescale of a track by wrapping the track.
32dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu */
33dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhupublic class ChangeTimeScaleTrack implements Track {
34dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu    private static final Logger LOG = Logger.getLogger(ChangeTimeScaleTrack.class.getName());
35dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu
36dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu    Track source;
37dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu    List<CompositionTimeToSample.Entry> ctts;
38dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu    List<TimeToSampleBox.Entry> tts;
39dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu    long timeScale;
40dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu
41dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu    /**
42dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu     * Changes the time scale of the source track to the target time scale and makes sure
43dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu     * that any rounding errors that may have summed are corrected exactly before the syncSamples.
44dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu     *
45dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu     * @param source          the source track
46dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu     * @param targetTimeScale the resulting time scale of this track.
47dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu     * @param syncSamples     at these sync points where rounding error are corrected.
48dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu     */
49dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu    public ChangeTimeScaleTrack(Track source, long targetTimeScale, long[] syncSamples) {
50dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu        this.source = source;
51dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu        this.timeScale = targetTimeScale;
52dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu        double timeScaleFactor = (double) targetTimeScale / source.getTrackMetaData().getTimescale();
53dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu        ctts = adjustCtts(source.getCompositionTimeEntries(), timeScaleFactor);
54dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu        tts = adjustTts(source.getDecodingTimeEntries(), timeScaleFactor, syncSamples, getTimes(source, syncSamples, targetTimeScale));
55dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu    }
56dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu
57dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu    private static long[] getTimes(Track track, long[] syncSamples, long targetTimeScale) {
58dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu        long[] syncSampleTimes = new long[syncSamples.length];
59dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu        Queue<TimeToSampleBox.Entry> timeQueue = new LinkedList<TimeToSampleBox.Entry>(track.getDecodingTimeEntries());
60dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu
61dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu        int currentSample = 1;  // first syncsample is 1
62dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu        long currentDuration = 0;
63dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu        long currentDelta = 0;
64dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu        int currentSyncSampleIndex = 0;
65dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu        long left = 0;
66dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu
67dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu
68dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu        while (currentSample <= syncSamples[syncSamples.length - 1]) {
69dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu            if (currentSample++ == syncSamples[currentSyncSampleIndex]) {
70dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu                syncSampleTimes[currentSyncSampleIndex++] = (currentDuration * targetTimeScale) / track.getTrackMetaData().getTimescale();
71dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu            }
72dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu            if (left-- == 0) {
73dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu                TimeToSampleBox.Entry entry = timeQueue.poll();
74dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu                left = entry.getCount() - 1;
75dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu                currentDelta = entry.getDelta();
76dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu            }
77dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu            currentDuration += currentDelta;
78dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu        }
79dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu        return syncSampleTimes;
80dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu
81dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu    }
82dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu
83dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu    public SampleDescriptionBox getSampleDescriptionBox() {
84dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu        return source.getSampleDescriptionBox();
85dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu    }
86dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu
87dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu    public List<TimeToSampleBox.Entry> getDecodingTimeEntries() {
88dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu        return tts;
89dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu    }
90dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu
91dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu    public List<CompositionTimeToSample.Entry> getCompositionTimeEntries() {
92dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu        return ctts;
93dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu    }
94dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu
95dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu    public long[] getSyncSamples() {
96dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu        return source.getSyncSamples();
97dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu    }
98dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu
99dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu    public List<SampleDependencyTypeBox.Entry> getSampleDependencies() {
100dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu        return source.getSampleDependencies();
101dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu    }
102dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu
103dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu    public TrackMetaData getTrackMetaData() {
104dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu        TrackMetaData trackMetaData = (TrackMetaData) source.getTrackMetaData().clone();
105dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu        trackMetaData.setTimescale(timeScale);
106dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu        return trackMetaData;
107dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu    }
108dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu
109dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu    public String getHandler() {
110dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu        return source.getHandler();
111dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu    }
112dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu
113dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu    public boolean isEnabled() {
114dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu        return source.isEnabled();
115dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu    }
116dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu
117dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu    public boolean isInMovie() {
118dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu        return source.isInMovie();
119dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu    }
120dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu
121dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu    public boolean isInPreview() {
122dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu        return source.isInPreview();
123dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu    }
124dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu
125dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu    public boolean isInPoster() {
126dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu        return source.isInPoster();
127dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu    }
128dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu
129dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu    public List<ByteBuffer> getSamples() {
130dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu        return source.getSamples();
131dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu    }
132dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu
133dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu
134dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu    /**
135dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu     * Adjusting the composition times is easy. Just scale it by the factor - that's it. There is no rounding
136dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu     * error summing up.
137dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu     *
138dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu     * @param source
139dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu     * @param timeScaleFactor
140dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu     * @return
141dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu     */
142dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu    static List<CompositionTimeToSample.Entry> adjustCtts(List<CompositionTimeToSample.Entry> source, double timeScaleFactor) {
143dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu        if (source != null) {
144dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu            List<CompositionTimeToSample.Entry> entries2 = new ArrayList<CompositionTimeToSample.Entry>(source.size());
145dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu            for (CompositionTimeToSample.Entry entry : source) {
146dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu                entries2.add(new CompositionTimeToSample.Entry(entry.getCount(), (int) Math.round(timeScaleFactor * entry.getOffset())));
147dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu            }
148dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu            return entries2;
149dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu        } else {
150dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu            return null;
151dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu        }
152dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu    }
153dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu
154dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu    static List<TimeToSampleBox.Entry> adjustTts(List<TimeToSampleBox.Entry> source, double timeScaleFactor, long[] syncSample, long[] syncSampleTimes) {
155dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu
156dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu        long[] sourceArray = TimeToSampleBox.blowupTimeToSamples(source);
157dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu        long summedDurations = 0;
158dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu
159dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu        LinkedList<TimeToSampleBox.Entry> entries2 = new LinkedList<TimeToSampleBox.Entry>();
160dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu        for (int i = 1; i <= sourceArray.length; i++) {
161dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu            long duration = sourceArray[i - 1];
162dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu
163dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu            long x = Math.round(timeScaleFactor * duration);
164dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu
165dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu
166dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu            TimeToSampleBox.Entry last = entries2.peekLast();
167dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu            int ssIndex;
168dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu            if ((ssIndex = Arrays.binarySearch(syncSample, i + 1)) >= 0) {
169dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu                // we are at the sample before sync point
170dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu                if (syncSampleTimes[ssIndex] != summedDurations) {
171dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu                    long correction = syncSampleTimes[ssIndex] - (summedDurations + x);
172dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu                    LOG.finest(String.format("Sample %d %d / %d - correct by %d", i, summedDurations, syncSampleTimes[ssIndex], correction));
173dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu                    x += correction;
174dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu                }
175dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu            }
176dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu            summedDurations += x;
177dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu            if (last == null) {
178dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu                entries2.add(new TimeToSampleBox.Entry(1, x));
179dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu            } else if (last.getDelta() != x) {
180dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu                entries2.add(new TimeToSampleBox.Entry(1, x));
181dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu            } else {
182dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu                last.setCount(last.getCount() + 1);
183dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu            }
184dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu
185dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu        }
186dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu        return entries2;
187dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu    }
188dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu
189dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu    public Box getMediaHeaderBox() {
190dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu        return source.getMediaHeaderBox();
191dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu    }
192dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu
193dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu    public SubSampleInformationBox getSubsampleInformationBox() {
194dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu        return source.getSubsampleInformationBox();
195dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu    }
196dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu
197dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu    @Override
198dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu    public String toString() {
199dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu        return "ChangeTimeScaleTrack{" +
200dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu                "source=" + source +
201dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu                '}';
202dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu    }
203dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu}