FileDocCategorySizeDatePackage
ChangeTimeScaleTrack.javaAPI Docmp4parser 1.0-RC-177152Wed Dec 19 20:10:37 GMT 2012com.googlecode.mp4parser.authoring.tracks

ChangeTimeScaleTrack

public class ChangeTimeScaleTrack extends Object implements com.googlecode.mp4parser.authoring.Track
Changes the timescale of a track by wrapping the track.

Fields Summary
private static final Logger
LOG
com.googlecode.mp4parser.authoring.Track
source
List
ctts
List
tts
long
timeScale
Constructors Summary
public ChangeTimeScaleTrack(com.googlecode.mp4parser.authoring.Track source, long targetTimeScale, long[] syncSamples)
Changes the time scale of the source track to the target time scale and makes sure that any rounding errors that may have summed are corrected exactly before the syncSamples.

param
source the source track
param
targetTimeScale the resulting time scale of this track.
param
syncSamples at these sync points where rounding error are corrected.


                                                                             
           
        this.source = source;
        this.timeScale = targetTimeScale;
        double timeScaleFactor = (double) targetTimeScale / source.getTrackMetaData().getTimescale();
        ctts = adjustCtts(source.getCompositionTimeEntries(), timeScaleFactor);
        tts = adjustTts(source.getDecodingTimeEntries(), timeScaleFactor, syncSamples, getTimes(source, syncSamples, targetTimeScale));
    
Methods Summary
static java.util.ListadjustCtts(java.util.List source, double timeScaleFactor)
Adjusting the composition times is easy. Just scale it by the factor - that's it. There is no rounding error summing up.

param
source
param
timeScaleFactor
return

        if (source != null) {
            List<CompositionTimeToSample.Entry> entries2 = new ArrayList<CompositionTimeToSample.Entry>(source.size());
            for (CompositionTimeToSample.Entry entry : source) {
                entries2.add(new CompositionTimeToSample.Entry(entry.getCount(), (int) Math.round(timeScaleFactor * entry.getOffset())));
            }
            return entries2;
        } else {
            return null;
        }
    
static java.util.ListadjustTts(java.util.List source, double timeScaleFactor, long[] syncSample, long[] syncSampleTimes)


        long[] sourceArray = TimeToSampleBox.blowupTimeToSamples(source);
        long summedDurations = 0;

        LinkedList<TimeToSampleBox.Entry> entries2 = new LinkedList<TimeToSampleBox.Entry>();
        for (int i = 1; i <= sourceArray.length; i++) {
            long duration = sourceArray[i - 1];

            long x = Math.round(timeScaleFactor * duration);


            TimeToSampleBox.Entry last = entries2.peekLast();
            int ssIndex;
            if ((ssIndex = Arrays.binarySearch(syncSample, i + 1)) >= 0) {
                // we are at the sample before sync point
                if (syncSampleTimes[ssIndex] != summedDurations) {
                    long correction = syncSampleTimes[ssIndex] - (summedDurations + x);
                    LOG.finest(String.format("Sample %d %d / %d - correct by %d", i, summedDurations, syncSampleTimes[ssIndex], correction));
                    x += correction;
                }
            }
            summedDurations += x;
            if (last == null) {
                entries2.add(new TimeToSampleBox.Entry(1, x));
            } else if (last.getDelta() != x) {
                entries2.add(new TimeToSampleBox.Entry(1, x));
            } else {
                last.setCount(last.getCount() + 1);
            }

        }
        return entries2;
    
public java.util.ListgetCompositionTimeEntries()

        return ctts;
    
public java.util.ListgetDecodingTimeEntries()

        return tts;
    
public java.lang.StringgetHandler()

        return source.getHandler();
    
public BoxgetMediaHeaderBox()

        return source.getMediaHeaderBox();
    
public java.util.ListgetSampleDependencies()

        return source.getSampleDependencies();
    
public SampleDescriptionBoxgetSampleDescriptionBox()

        return source.getSampleDescriptionBox();
    
public java.util.ListgetSamples()

        return source.getSamples();
    
public SubSampleInformationBoxgetSubsampleInformationBox()

        return source.getSubsampleInformationBox();
    
public long[]getSyncSamples()

        return source.getSyncSamples();
    
private static long[]getTimes(com.googlecode.mp4parser.authoring.Track track, long[] syncSamples, long targetTimeScale)

        long[] syncSampleTimes = new long[syncSamples.length];
        Queue<TimeToSampleBox.Entry> timeQueue = new LinkedList<TimeToSampleBox.Entry>(track.getDecodingTimeEntries());

        int currentSample = 1;  // first syncsample is 1
        long currentDuration = 0;
        long currentDelta = 0;
        int currentSyncSampleIndex = 0;
        long left = 0;


        while (currentSample <= syncSamples[syncSamples.length - 1]) {
            if (currentSample++ == syncSamples[currentSyncSampleIndex]) {
                syncSampleTimes[currentSyncSampleIndex++] = (currentDuration * targetTimeScale) / track.getTrackMetaData().getTimescale();
            }
            if (left-- == 0) {
                TimeToSampleBox.Entry entry = timeQueue.poll();
                left = entry.getCount() - 1;
                currentDelta = entry.getDelta();
            }
            currentDuration += currentDelta;
        }
        return syncSampleTimes;

    
public com.googlecode.mp4parser.authoring.TrackMetaDatagetTrackMetaData()

        TrackMetaData trackMetaData = (TrackMetaData) source.getTrackMetaData().clone();
        trackMetaData.setTimescale(timeScale);
        return trackMetaData;
    
public booleanisEnabled()

        return source.isEnabled();
    
public booleanisInMovie()

        return source.isInMovie();
    
public booleanisInPoster()

        return source.isInPoster();
    
public booleanisInPreview()

        return source.isInPreview();
    
public java.lang.StringtoString()

        return "ChangeTimeScaleTrack{" +
                "source=" + source +
                '}";