package org.jcodec.movtool;
import java.lang.IllegalStateException;
import java.lang.System;
import org.jcodec.common.logging.Logger;
import org.jcodec.common.model.RationalLarge;
import org.jcodec.common.tools.MainUtils;
import org.jcodec.common.tools.MainUtils.Cmd;
import org.jcodec.containers.mp4.boxes.MovieBox;
import org.jcodec.containers.mp4.boxes.MovieFragmentBox;
import org.jcodec.containers.mp4.boxes.TimeToSampleBox;
import org.jcodec.containers.mp4.boxes.TimeToSampleBox.TimeToSampleEntry;
import org.jcodec.containers.mp4.boxes.TrakBox;
import java.io.File;
/**
* This class is part of JCodec ( www.jcodec.org ) This software is distributed
* under FreeBSD License
*
* Changes FPS on an MP4 file.
*
* @author Stan Vitvitskyy
*
*/
public class SetFPS {
private static final int MIN_TIMESCALE_ALLOWED = 25;
public static void main1(String[] args) throws Exception {
Cmd cmd = MainUtils.parseArguments(args);
if (cmd.argsLength() < 2) {
MainUtils.printHelpNoFlags("movie", "num:den");
System.exit(-1);
}
final RationalLarge newFPS = RationalLarge.parse(cmd.getArg(1));
new InplaceMP4Editor().modify(new File(cmd.getArg(0)), new MP4Edit() {
@Override
public void apply(MovieBox mov) {
TrakBox vt = mov.getVideoTrack();
TimeToSampleBox stts = vt.getStts();
TimeToSampleEntry[] entries = stts.getEntries();
long nSamples = 0;
long totalDuration = 0;
for (TimeToSampleEntry e : entries) {
nSamples += e.getSampleCount();
totalDuration += e.getSampleCount() * e.getSampleDuration();
}
int newTimescale = (int) newFPS.multiply(new RationalLarge(totalDuration, nSamples)).scalarClip();
if (newTimescale >= MIN_TIMESCALE_ALLOWED) {
// Playing with timescale if possible
vt.setTimescale(newTimescale);
} else {
// Playing with actual sample durations
double mul = new RationalLarge(vt.getTimescale() * totalDuration, nSamples).divideBy(newFPS)
.scalar();
Logger.info("Applying multiplier to sample durations: " + mul);
for (TimeToSampleEntry e : entries) {
e.setSampleDuration((int) (e.getSampleDuration() * mul * 100));
}
vt.setTimescale(vt.getTimescale() * 100);
}
if (newTimescale != vt.getTimescale()) {
Logger.info("Changing timescale to: " + vt.getTimescale());
long newDuration = totalDuration * mov.getTimescale() / vt.getTimescale();
mov.setDuration(newDuration);
vt.setDuration(newDuration);
} else {
Logger.info("Already at " + newFPS.toString() + "fps, not changing.");
}
}
@Override
public void applyToFragment(MovieBox mov, MovieFragmentBox[] fragmentBox) {
throw new RuntimeException("Unsupported");
}
});
}
}