/* * @(#)ConcatDemoMain.java * * Copyright (c) 2012 Werner Randelshofer, Goldau, Switzerland. * All rights reserved. * * You may not use, copy or modify this file, except in compliance with the * license agreement you entered into with Werner Randelshofer. * For details see accompanying license terms. */ package org.monte.iodemo; import java.io.File; import java.io.IOException; import java.util.ArrayList; import org.monte.media.Buffer; import org.monte.media.BufferFlag; import org.monte.media.MovieReader; import org.monte.media.MovieWriter; import org.monte.media.Registry; /** * Demonstrates how to concatenate multiple movie files without re-encoding the * media data. <p> Caveat: If an input file has multiple tracks of different * durations, then the audio/video sync of subsequent input file will drift. On * the upside this allows to merge a file which only contains video with a file * that only contains audio. * * @author Werner Randelshofer * @version $Id$ */ public class ConcatDemoMain { /** * Main function. <p> Takes one output file and one or more input files as * arguments. Concatenates all input files into the output file. * <pre> * ConcatDemo [-o outputfile] [-i inputfile ...] * </pre> * * @param args the command line arguments */ public static void main(String[] args) { // Use hardcoded arguments for debugging /* args=new String[] {"-i", "/Users/werni/Movies/ScreenRecording 2012-07-27 at 21.34.31.avi", "/Users/werni/Movies/ScreenRecording 2012-07-27 at 21.34.31.avi", "/Users/werni/Movies/ScreenRecording 2012-07-27 at 21.34.31.avi", "-o", "/Users/werni/Movies/concat1.avi"}; */ // Parse arguments File outfile = null; ArrayList<File> infiles = new ArrayList<File>(); try { char arg = ' '; for (int i = 0; i < args.length; i++) { if (args[i].length() > 1 && args[i].charAt(0) == '-') { arg = args[i].charAt(1); } else { switch (arg) { case 'o': if (outfile != null) { throw new IllegalArgumentException("error: only one outputfile allowed"); } outfile = new File(args[i]); break; case 'i': infiles.add(new File(args[i])); break; default: throw new IllegalArgumentException("error: illegal option: " + args[i]); } } } if (outfile == null) { throw new IllegalArgumentException("error: no outputfile specified"); } /* if (outfile.exists()) { throw new IllegalArgumentException("error: outputfile exists: " + outfile); }*/ if (infiles.size() == 0) { throw new IllegalArgumentException("error: no inputfiles specified"); } for (File f : infiles) { if (!f.exists()) { throw new IllegalArgumentException("error: inputfile does not exist: " + f); } } } catch (IllegalArgumentException e) { System.err.println(e.getMessage()); System.err.println("usage: java -jar ConcatDemo.jar [-o outputfile] [-i inputfile ...]"); String version = ConcatDemoMain.class.getPackage().getImplementationVersion(); System.err.println("ConcatDemo " + (version == null ? "" : version + " ") + "(c) Werner Randelshofer"); System.exit(10); } try { concat(outfile, infiles); } catch (IOException e) { System.err.println("error: " + e.getMessage()); } } private static void concat(File outfile, ArrayList<File> infiles) throws IOException { MovieWriter out = Registry.getInstance().getWriter(outfile); if (out == null) { throw new IOException("output file format not supported for: " + outfile); } try { // For each input track in each input file, find a matching output track. // If no matching output track has been found, create a new output track. int[][] matchingT = new int[infiles.size()][0]; for (int i = 0, imax = infiles.size(); i < imax; i++) { File infile = infiles.get(i); MovieReader in = Registry.getInstance().getReader(infile); if (in == null) { throw new IOException("input file format not supported for: " + infile); } try { matchingT[i] = new int[in.getTrackCount()]; for (int t = 0, jmax = in.getTrackCount(); t < jmax; t++) { matchingT[i][t] = -1; for (int outputTrack = 0, nOutputTracks = out.getTrackCount(); outputTrack < nOutputTracks; outputTrack++) { if (in.getFormat(t).matches(out.getFormat(outputTrack))) { // if a movie has multiple tracks with the same format, // we assign them to multiple output tracks for (int tt = 0; tt < t; tt++) { if (matchingT[i][tt] == outputTrack) { continue; } } matchingT[i][t] = outputTrack; break; } } if (matchingT[i][t] == -1) { matchingT[i][t] = out.getTrackCount(); out.addTrack(in.getFormat(t)); } } } finally { in.close(); } } // For each input file, write all media samples into the matching // output tracks. Buffer buf = new Buffer(); for (int i = 0, imax = infiles.size(); i < imax; i++) { File infile = infiles.get(i); MovieReader in = Registry.getInstance().getReader(infile); if (in == null) { throw new IOException("input file format not supported for: " + infile); } try { for (int t = in.nextTrack(); t != -1; t = in.nextTrack()) { in.read(t, buf); out.write(matchingT[i][t], buf); } } finally { in.close(); } } } finally { out.close(); } } }