private int calcSpaceReq(MovieBox movie) { int sum = 0; TrakBox[] tracks = movie.getTracks(); for (int i = 0; i < tracks.length; i++) { TrakBox trakBox = tracks[i]; ChunkOffsetsBox stco = trakBox.getStco(); if (stco != null) sum += stco.getChunkOffsets().length * 4; } return sum; }
public List<MovieBox> cut(MovieBox movie, List<Slice> commands) { TrakBox videoTrack = movie.getVideoTrack(); if (videoTrack != null && videoTrack.getTimescale() != movie.getTimescale()) movie.fixTimescale(videoTrack.getTimescale()); TrakBox[] tracks = movie.getTracks(); for (int i = 0; i < tracks.length; i++) { TrakBox trakBox = tracks[i]; forceEditList(movie, trakBox); List<Edit> edits = trakBox.getEdits(); for (Slice cut : commands) { split(edits, cut.inSec, movie, trakBox); split(edits, cut.outSec, movie, trakBox); } } ArrayList<MovieBox> result = new ArrayList<MovieBox>(); for (Slice cut : commands) { MovieBox clone = (MovieBox) NodeBox.cloneBox(movie, 16 * 1024 * 1024, BoxFactory.getDefault()); 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; }
protected SeekableByteChannel[][] getInputs(MovieBox movie) throws IOException { TrakBox[] tracks = movie.getTracks(); SeekableByteChannel[][] result = new SeekableByteChannel[tracks.length][]; for (int i = 0; i < tracks.length; i++) { DataRefBox drefs = NodeBox.findFirstPath(tracks[i], DataRefBox.class, Box.path("mdia.minf.dinf.dref")); if (drefs == null) { throw new RuntimeException("No data references"); } List<Box> entries = drefs.getBoxes(); SeekableByteChannel[] e = new SeekableByteChannel[entries.size()]; SeekableByteChannel[] inputs = new SeekableByteChannel[entries.size()]; for (int j = 0; j < e.length; j++) { inputs[j] = resolveDataRef(entries.get(j)); } result[i] = inputs; } return result; }
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)); }