All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.jcodec.movtool.Cut Maven / Gradle / Ivy

There is a newer version: 0.2.5
Show newest version
package org.jcodec.movtool;

import static java.lang.Integer.parseInt;
import static java.lang.Math.max;
import static org.apache.commons.io.FilenameUtils.removeExtension;
import static org.jcodec.common.NIOUtils.readableFileChannel;
import static org.jcodec.common.NIOUtils.writableFileChannel;
import static org.jcodec.containers.mp4.MP4Util.createRefMovie;
import static org.jcodec.movtool.Util.forceEditList;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.ListIterator;

import org.apache.commons.lang.StringUtils;
import org.jcodec.common.NIOUtils;
import org.jcodec.common.SeekableByteChannel;
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.TrakBox;

/**
 * This class is part of JCodec ( www.jcodec.org ) This software is distributed
 * under FreeBSD License
 * 
 * Cut on ref movies
 * 
 * @author The JCodec project
 * 
 */
public class Cut {
    public static void main(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) {
            if ("-cut".equals(args[shift])) {
                String[] pt = StringUtils.split(args[shift + 1], ":");
                slices.add(new Slice(parseInt(pt[0]), parseInt(pt[1])));
                if (pt.length > 2)
                    sliceNames.add(pt[2]);
                else
                    sliceNames.add(null);
                shift += 2;
            } else if ("-self".equals(args[shift])) {
                ++shift;
                selfContained = true;
            } else
                break;
        }
        File source = new File(args[shift]);

        SeekableByteChannel input = null;
        SeekableByteChannel out = null;
        List outs = new ArrayList();
        try {
            input = readableFileChannel(source);
            MovieBox movie = createRefMovie(input, "file://" + source.getCanonicalPath());
            List slicesMovs;
            if (!selfContained) {
                out = writableFileChannel(new File(source.getParentFile(), removeExtension(source.getName())
                        + ".ref.mov"));
                slicesMovs = new Cut().cut(movie, slices);
                MP4Util.writeMovie(out, movie);
            } else {
                out = writableFileChannel(new File(source.getParentFile(), removeExtension(source.getName())
                        + ".self.mov"));
                slicesMovs = new Cut().cut(movie, slices);
                new Strip().strip(movie);
                new Flattern().flattern(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)
                continue;
            SeekableByteChannel out = null;
            try {
                out = writableFileChannel(new File(parentFile, names.get(i)));
                MP4Util.writeMovie(out, slices.get(i));
            } finally {
                NIOUtils.closeQuietly(out);
            }
        }
    }

    public static class Slice {
        private double inSec;
        private double outSec;

        public Slice(double in, double out) {
            super();
            this.inSec = in;
            this.outSec = out;
        }
    }

    public List cut(MovieBox movie, List commands) {

        TrakBox videoTrack = movie.getVideoTrack();
        if (videoTrack != null && videoTrack.getTimescale() != movie.getTimescale())
            movie.fixTimescale(videoTrack.getTimescale());

        TrakBox[] tracks = movie.getTracks();
        for (TrakBox trakBox : tracks) {
            forceEditList(movie, trakBox);
            List edits = trakBox.getEdits();
            for (Slice cut : commands) {
                split(edits, cut.inSec, movie, trakBox);
                split(edits, cut.outSec, movie, trakBox);
            }
        }
        ArrayList result = new ArrayList();
        for (Slice cut : commands) {
            MovieBox clone = (MovieBox) MP4Util.cloneBox(movie, 16 * 1024 * 1024);
            for (TrakBox trakBox : clone.getTracks()) {
                selectInner(trakBox.getEdits(), cut, movie, trakBox);
            }
            result.add(clone);
        }

        long movDuration = 0;
        for (TrakBox trakBox : movie.getTracks()) {
            selectOuter(trakBox.getEdits(), commands, movie, trakBox);
            trakBox.setEdits(trakBox.getEdits());
            movDuration = max(movDuration, trakBox.getDuration());
        }
        movie.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) (commands.get(i).inSec * movie.getTimescale());
            outMv[i] = (long) (commands.get(i).outSec * movie.getTimescale());
        }
        long editStartMv = 0;
        ListIterator lit = edits.listIterator();
        while (lit.hasNext()) {
            Edit edit = lit.next();
            for (int i = 0; i < inMv.length; i++) {
                if (editStartMv + edit.getDuration() > inMv[i] && editStartMv < outMv[i])
                    lit.remove();
            }
            editStartMv += edit.getDuration();
        }
    }

    private void selectInner(List edits, Slice cut, MovieBox movie, TrakBox trakBox) {
        long inMv = (long) (movie.getTimescale() * cut.inSec);
        long outMv = (long) (movie.getTimescale() * cut.outSec);

        long editStart = 0;
        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 * movie.getTimescale()));
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy