private static void saveSlices(List<MovieBox> slices, List<String> names, File parentFile) throws IOException { for (int i = 0; i < slices.size(); i++) { if (names.get(i) == null) continue; SeekableByteChannel out = null; try { out = writableChannel(new File(parentFile, names.get(i))); MP4Util.writeMovie(out, slices.get(i)); } finally { NIOUtils.closeQuietly(out); } } }
public void flatternChannel(MovieBox movie, SeekableByteChannel out) throws IOException { if (!movie.isPureRefMovie(movie)) throw new IllegalArgumentException("movie should be reference"); ByteBuffer buf = ByteBuffer.allocate(16 * 1024 * 1024); FileTypeBox ftyp = FileTypeBox.createFileTypeBox("qt ", 0x20050300, Arrays.asList(new String[] {"qt "})); ftyp.write(buf); long movieOff = buf.position(); movie.write(buf); int extraSpace = calcSpaceReq(movie); Header.createHeader("free", 8 + extraSpace).write(buf); NIOUtils.skip(buf, extraSpace); long mdatOff = buf.position(); Header.createHeader("mdat", 0x100000001L).write(buf); buf.flip(); out.write(buf); SeekableByteChannel[][] inputs = getInputs(movie); TrakBox[] tracks = movie.getTracks(); ChunkReader[] readers = new ChunkReader[tracks.length]; ChunkWriter[] writers = new ChunkWriter[tracks.length]; Chunk[] head = new Chunk[tracks.length]; int totalChunks = 0, writtenChunks = 0, lastProgress = 0; long[] off = new long[tracks.length]; for (int i = 0; i < tracks.length; i++) { readers[i] = new ChunkReader(tracks[i]); totalChunks += readers[i].size(); writers[i] = new ChunkWriter(tracks[i], inputs[i], out); head[i] = readers[i].next(); if (tracks[i].isVideo()) off[i] = 2 * movie.getTimescale(); } while (true) { int min = -1; for (int i = 0; i < readers.length; i++) { if (head[i] == null) continue; if (min == -1) min = i; else { long iTv = movie.rescale(head[i].getStartTv(), tracks[i].getTimescale()) + off[i]; long minTv = movie.rescale(head[min].getStartTv(), tracks[min].getTimescale()) + off[min]; if (iTv < minTv) min = i; } } if (min == -1) break; writers[min].write(head[min]); head[min] = readers[min].next(); writtenChunks++; lastProgress = calcProgress(totalChunks, writtenChunks, lastProgress); } long mdatSize = out.position() - mdatOff; for (int i = 0; i < tracks.length; i++) { writers[i].apply(); } out.setPosition(movieOff); MP4Util.writeMovie(out, movie); long extra = mdatOff - out.position(); if (extra < 0) throw new RuntimeException("Not enough space to write the header"); out.write( (ByteBuffer) ByteBuffer.allocate(8).putInt((int) extra).put(new byte[] {'f', 'r', 'e', 'e'}).flip()); out.setPosition(mdatOff + 8); out.write(ByteBuffer.allocate(8).putLong(mdatSize)); }
public static void main1(String[] args) throws Exception { if (args.length < 1) { System.out.println( "Syntax: cut [-command arg]...[-command arg] [-self] <movie file>\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<Slice> slices = new ArrayList<Slice>(); List<String> sliceNames = new ArrayList<String>(); boolean selfContained = false; int shift = 0; while (true) { if ("-cut".equals(args[shift])) { String[] pt = StringUtils.splitS(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<SeekableByteChannel> outs = new ArrayList<SeekableByteChannel>(); try { input = readableChannel(source); MovieBox movie = createRefMovie(input, "file://" + source.getCanonicalPath()); List<MovieBox> slicesMovs; if (!selfContained) { out = writableChannel( new File( source.getParentFile(), JCodecUtil2.removeExtension(source.getName()) + ".ref.mov")); slicesMovs = new Cut().cut(movie, slices); MP4Util.writeMovie(out, movie); } else { out = writableChannel( new File( source.getParentFile(), JCodecUtil2.removeExtension(source.getName()) + ".self.mov")); slicesMovs = new Cut().cut(movie, slices); new Strip().strip(movie); new Flattern().flatternChannel(movie, out); } saveSlices(slicesMovs, sliceNames, source.getParentFile()); } finally { if (input != null) input.close(); if (out != null) out.close(); for (SeekableByteChannel o : outs) { o.close(); } } }