package org.jcodec.movtool; import java.io.File; import java.io.IOException; import java.util.ArrayList; import java.util.List; import java.util.ListIterator; import org.jcodec.common.JCodecUtil2; import org.jcodec.common.StringUtils; import org.jcodec.common.io.NIOUtils; import org.jcodec.common.io.SeekableByteChannel; import org.jcodec.containers.mp4.BoxFactory; import org.jcodec.containers.mp4.MP4Util; import org.jcodec.containers.mp4.boxes.Edit; import org.jcodec.containers.mp4.boxes.MovieBox; import org.jcodec.containers.mp4.boxes.NodeBox; import org.jcodec.containers.mp4.boxes.TrakBox; public class Cut { public static void main1(String[] args) throws Exception { if (args.length < 1) { System.out.println("Syntax: cut [-command arg]...[-command arg] [-self] \n\tCreates a reference movie out of the file and applies a set of changes specified by the commands to it."); System.exit(-1); } List slices = new ArrayList<>(); List sliceNames = new ArrayList<>(); boolean selfContained = false; int shift = 0; while (true) { while ("-cut".equals(args[shift])) { String[] pt = StringUtils.splitS(args[shift + 1], ":"); slices.add(new Slice((double)Integer.parseInt(pt[0]), (double)Integer.parseInt(pt[1]))); if (pt.length > 2) { sliceNames.add(pt[2]); } else { sliceNames.add(null); } shift += 2; } if ("-self".equals(args[shift])) { shift++; selfContained = true; continue; } break; } File source = new File(args[shift]); SeekableByteChannel input = null; SeekableByteChannel out = null; List outs = new ArrayList<>(); try { List slicesMovs; input = NIOUtils.readableChannel(source); MP4Util.Movie movie = MP4Util.createRefFullMovie(input, "file://" + source.getCanonicalPath()); if (!selfContained) { out = NIOUtils.writableChannel(new File(source.getParentFile(), JCodecUtil2.removeExtension(source.getName()) + ".ref.mov")); slicesMovs = new Cut().cut(movie, slices); MP4Util.writeFullMovie(out, movie); } else { out = NIOUtils.writableChannel(new File(source.getParentFile(), JCodecUtil2.removeExtension(source.getName()) + ".self.mov")); slicesMovs = new Cut().cut(movie, slices); new Strip().strip(movie.getMoov()); new Flatten().flattenChannel(movie, out); } saveSlices(slicesMovs, sliceNames, source.getParentFile()); } finally { if (input != null) input.close(); if (out != null) out.close(); for (SeekableByteChannel o : outs) o.close(); } } private static void saveSlices(List slices, List names, File parentFile) throws IOException { for (int i = 0; i < slices.size(); i++) { if (names.get(i) != null) SeekableByteChannel out = null; } } public static class Slice { private double inSec; private double outSec; public Slice(double _in, double out) { this.inSec = _in; this.outSec = out; } } public List cut(MP4Util.Movie movie, List commands) { MovieBox moov = movie.getMoov(); TrakBox videoTrack = moov.getVideoTrack(); if (videoTrack != null && videoTrack.getTimescale() != moov.getTimescale()) moov.fixTimescale(videoTrack.getTimescale()); TrakBox[] tracks = moov.getTracks(); for (int i = 0; i < tracks.length; i++) { TrakBox trakBox = tracks[i]; Util.forceEditList(moov, trakBox); List edits = trakBox.getEdits(); for (Slice cut : commands) { split(edits, cut.inSec, moov, trakBox); split(edits, cut.outSec, moov, trakBox); } } ArrayList result = new ArrayList<>(); for (Slice cut : commands) { MovieBox clone = (MovieBox)NodeBox.cloneBox(moov, 16777216, BoxFactory.getDefault()); for (TrakBox trakBox : clone.getTracks()) selectInner(trakBox.getEdits(), cut, moov, trakBox); result.add(new MP4Util.Movie(movie.getFtyp(), clone)); } long movDuration = 0L; for (TrakBox trakBox : moov.getTracks()) { selectOuter(trakBox.getEdits(), commands, moov, trakBox); trakBox.setEdits(trakBox.getEdits()); movDuration = Math.max(movDuration, trakBox.getDuration()); } moov.setDuration(movDuration); return result; } private void selectOuter(List edits, List commands, MovieBox movie, TrakBox trakBox) { long[] inMv = new long[commands.size()]; long[] outMv = new long[commands.size()]; for (int i = 0; i < commands.size(); i++) { inMv[i] = (long)(((Slice)commands.get(i)).inSec * (double)movie.getTimescale()); outMv[i] = (long)(((Slice)commands.get(i)).outSec * (double)movie.getTimescale()); } long editStartMv = 0L; ListIterator lit = edits.listIterator(); while (lit.hasNext()) { Edit edit = lit.next(); for (int j = 0; j < inMv.length; j++) { if (editStartMv + edit.getDuration() > inMv[j] && editStartMv < outMv[j]) lit.remove(); } editStartMv += edit.getDuration(); } } private void selectInner(List edits, Slice cut, MovieBox movie, TrakBox trakBox) { long inMv = (long)((double)movie.getTimescale() * cut.inSec); long outMv = (long)((double)movie.getTimescale() * cut.outSec); long editStart = 0L; ListIterator lit = edits.listIterator(); while (lit.hasNext()) { Edit edit = lit.next(); if (editStart + edit.getDuration() <= inMv || editStart >= outMv) lit.remove(); editStart += edit.getDuration(); } } private void split(List edits, double sec, MovieBox movie, TrakBox trakBox) { Util.split(movie, trakBox, (long)(sec * (double)movie.getTimescale())); } }