![JAR search and dependency download from the Maven repository](/logo.png)
org.jcodec.movtool.Paste Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of jcodec Show documentation
Show all versions of jcodec Show documentation
Pure Java implementation of video/audio codecs and formats
package org.jcodec.movtool;
import static java.util.Arrays.fill;
import static org.jcodec.containers.mp4.MP4Util.createRefMovie;
import static org.jcodec.movtool.Util.forceEditList;
import static org.jcodec.movtool.Util.insertTo;
import static org.jcodec.movtool.Util.shift;
import static org.jcodec.movtool.Util.spread;
import java.io.File;
import java.io.RandomAccessFile;
import java.util.Arrays;
import org.jcodec.containers.mp4.boxes.ClipRegionBox;
import org.jcodec.containers.mp4.boxes.LoadSettingsBox;
import org.jcodec.containers.mp4.boxes.MovieBox;
import org.jcodec.containers.mp4.boxes.NodeBox;
import org.jcodec.containers.mp4.boxes.SampleSizesBox;
import org.jcodec.containers.mp4.boxes.SoundMediaHeaderBox;
import org.jcodec.containers.mp4.boxes.TrackHeaderBox;
import org.jcodec.containers.mp4.boxes.TrakBox;
import org.jcodec.containers.mp4.boxes.VideoMediaHeaderBox;
import org.jcodec.containers.mp4.io.FileInput;
/**
* This class is part of JCodec ( www.jcodec.org ) This software is distributed
* under FreeBSD License
*
* Paste on ref movies
*
* @author Stanislav Vitvitskiy
*
*/
public class Paste {
public static void main(String[] args) throws Exception {
if (args.length < 2) {
System.out.println("Syntax: paste [frame number]");
System.exit(-1);
}
File toFile = new File(args[0]);
FileInput to = null;
FileInput from = null;
RandomAccessFile out = null;
try {
File outFile = new File(toFile.getParentFile(), toFile.getName().replaceAll("\\.mov$", "") + ".paste.mov");
outFile.delete();
out = new RandomAccessFile(outFile, "rw");
to = new FileInput(toFile);
File fromFile = new File(args[1]);
from = new FileInput(fromFile);
MovieBox toMov = createRefMovie(to, "file://" + toFile.getCanonicalPath());
MovieBox fromMov = createRefMovie(from, "file://" + fromFile.getCanonicalPath());
new Strip().strip(fromMov);
if (args.length > 2) {
new Paste().paste(toMov, fromMov, Integer.parseInt(args[2]));
} else {
new Paste().addToMovie(toMov, fromMov);
}
toMov.write(out);
} finally {
if (to != null)
to.close();
if (from != null)
from.close();
if (out != null)
out.close();
}
}
public void paste(MovieBox to, MovieBox from, int frameNo) {
TrakBox videoTrack = to.getVideoTrack();
if (videoTrack != null && videoTrack.getTimescale() != to.getTimescale())
to.fixTimescale(videoTrack.getTimescale());
long frameTv = to.rescale(getFrameTv(videoTrack, frameNo), videoTrack.getTimescale());
forceEditList(to);
forceEditList(from);
TrakBox[] fromTracks = from.getTracks();
TrakBox[] toTracks = to.getTracks();
int[][] matches = findMatches(fromTracks, toTracks);
for (int i = 0; i < matches[0].length; i++) {
TrakBox localTrack = to.importTrack(from, fromTracks[i]);
if (matches[0][i] != -1) {
insertTo(to, toTracks[matches[0][i]], localTrack, frameTv);
} else {
to.appendTrack(localTrack);
shift(to, localTrack, frameTv);
}
}
for (int i = 0; i < matches[1].length; i++) {
if (matches[1][i] == -1) {
spread(to, toTracks[i], frameTv, to.rescale(from.getDuration(), from.getTimescale()));
}
}
to.updateDuration();
}
public void addToMovie(MovieBox to, MovieBox from) {
for (TrakBox track : from.getTracks()) {
to.appendTrack(to.importTrack(from, track));
}
}
long[] tv;
private long getFrameTv(TrakBox videoTrack, int frame) {
if (tv == null) {
tv = Util.getTimevalues(videoTrack);
}
return tv[frame];
}
private int[][] findMatches(TrakBox[] fromTracks, TrakBox[] toTracks) {
int[] f2t = new int[fromTracks.length];
int[] t2f = new int[toTracks.length];
fill(f2t, -1);
fill(t2f, -1);
for (int i = 0; i < fromTracks.length; i++) {
if (f2t[i] != -1)
continue;
for (int j = 0; j < toTracks.length; j++) {
if (t2f[j] != -1)
continue;
if (matches(fromTracks[i], toTracks[j])) {
f2t[i] = j;
t2f[j] = i;
break;
}
}
}
return new int[][] { f2t, t2f };
}
private boolean matches(TrakBox trakBox1, TrakBox trakBox2) {
return trakBox1.getHandlerType().equals(trakBox2.getHandlerType()) && matchHeaders(trakBox1, trakBox2)
&& matchSampleSizes(trakBox1, trakBox2) && matchMediaHeader(trakBox1, trakBox2)
&& matchClip(trakBox1, trakBox2) && matchLoad(trakBox1, trakBox2);
}
private boolean matchSampleSizes(TrakBox trakBox1, TrakBox trakBox2) {
SampleSizesBox stsz1 = NodeBox.findFirst(trakBox1, SampleSizesBox.class, "mdia", "minf", "stbl", "stsz");
SampleSizesBox stsz2 = NodeBox.findFirst(trakBox1, SampleSizesBox.class, "mdia", "minf", "stbl", "stsz");
return stsz1.getDefaultSize() == stsz2.getDefaultSize();
}
private boolean matchMediaHeader(TrakBox trakBox1, TrakBox trakBox2) {
VideoMediaHeaderBox vmhd1 = NodeBox.findFirst(trakBox1, VideoMediaHeaderBox.class, "mdia", "minf", "vmhd");
VideoMediaHeaderBox vmhd2 = NodeBox.findFirst(trakBox2, VideoMediaHeaderBox.class, "mdia", "minf", "vmhd");
if ((vmhd1 != null && vmhd2 == null) || (vmhd1 == null && vmhd2 != null))
return false;
else if (vmhd1 != null && vmhd2 != null) {
return vmhd1.getGraphicsMode() == vmhd2.getGraphicsMode() && vmhd1.getbOpColor() == vmhd2.getbOpColor()
&& vmhd1.getgOpColor() == vmhd2.getgOpColor() && vmhd1.getrOpColor() == vmhd2.getrOpColor();
} else {
SoundMediaHeaderBox smhd1 = NodeBox.findFirst(trakBox1, SoundMediaHeaderBox.class, "mdia", "minf", "smhd");
SoundMediaHeaderBox smhd2 = NodeBox.findFirst(trakBox2, SoundMediaHeaderBox.class, "mdia", "minf", "smhd");
if ((smhd1 == null && smhd2 != null) || (smhd1 != null && smhd2 == null))
return false;
else if (smhd1 != null && smhd2 != null)
return smhd1.getBalance() == smhd1.getBalance();
}
return true;
}
private boolean matchHeaders(TrakBox trakBox1, TrakBox trakBox2) {
TrackHeaderBox th1 = trakBox1.getTrackHeader();
TrackHeaderBox th2 = trakBox2.getTrackHeader();
return ("vide".equals(trakBox1.getHandlerType()) && Arrays.equals(th1.getMatrix(), th2.getMatrix())
&& th1.getLayer() == th2.getLayer() && th1.getWidth() == th2.getWidth() && th1.getHeight() == th2
.getHeight())
|| ("soun".equals(trakBox1.getHandlerType()) && th1.getVolume() == th2.getVolume())
|| "tmcd".equals(trakBox1.getHandlerType());
}
private boolean matchLoad(TrakBox trakBox1, TrakBox trakBox2) {
LoadSettingsBox load1 = NodeBox.findFirst(trakBox1, LoadSettingsBox.class, "load");
LoadSettingsBox load2 = NodeBox.findFirst(trakBox2, LoadSettingsBox.class, "load");
if (load1 == null && load2 == null)
return true;
if ((load1 == null && load2 != null) || (load1 != null && load2 == null))
return false;
return load1.getPreloadStartTime() == load2.getPreloadStartTime()
&& load1.getPreloadDuration() == load2.getPreloadDuration()
&& load1.getPreloadFlags() == load2.getPreloadFlags()
&& load1.getDefaultHints() == load2.getDefaultHints();
}
private boolean matchClip(TrakBox trakBox1, TrakBox trakBox2) {
ClipRegionBox crgn1 = NodeBox.findFirst(trakBox1, ClipRegionBox.class, "clip", "crgn");
ClipRegionBox crgn2 = NodeBox.findFirst(trakBox2, ClipRegionBox.class, "clip", "crgn");
if ((crgn1 == null && crgn2 != null) || (crgn1 != null && crgn2 == null))
return false;
if (crgn1 == null && crgn2 == null)
return true;
return crgn1.getRgnSize() == crgn2.getRgnSize() && crgn1.getX() == crgn2.getX() && crgn1.getY() == crgn2.getY()
&& crgn1.getWidth() == crgn2.getWidth() && crgn1.getHeight() == crgn2.getHeight();
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy