package org.jcodec.containers.mp4; import static org.jcodec.common.NIOUtils.readableFileChannel; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.nio.ByteBuffer; import java.nio.channels.FileChannel; import java.nio.channels.WritableByteChannel; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import org.jcodec.codecs.h264.mp4.AvcCBox; import org.jcodec.common.Codec; import org.jcodec.common.NIOUtils; import org.jcodec.common.SeekableByteChannel; import org.jcodec.containers.mp4.boxes.Box; import org.jcodec.containers.mp4.boxes.BoxFactory; import org.jcodec.containers.mp4.boxes.Header; import org.jcodec.containers.mp4.boxes.MovieBox; import org.jcodec.containers.mp4.boxes.NodeBox; import org.jcodec.containers.mp4.boxes.TrakBox; /** * This class is part of JCodec ( www.jcodec.org ) This software is distributed * under FreeBSD License * * @author The JCodec project * */ public class MP4Util { private static Map<Codec, String> codecMapping = new HashMap<Codec, String>(); static { codecMapping.put(Codec.MPEG2, "m2v1"); codecMapping.put(Codec.H264, "avc1"); codecMapping.put(Codec.J2K, "mjp2"); } public static MovieBox createRefMovie(SeekableByteChannel input, String url) throws IOException { MovieBox movie = parseMovie(input); for (TrakBox trakBox : movie.getTracks()) { trakBox.setDataRef(url); } return movie; } public static MovieBox parseMovie(SeekableByteChannel input) throws IOException { for (Atom atom : getRootAtoms(input)) { if ("moov".equals(atom.getHeader().getFourcc())) { return (MovieBox) atom.parseBox(input); } } return null; } public static List<Atom> getRootAtoms(SeekableByteChannel input) throws IOException { input.position(0); List<Atom> result = new ArrayList<Atom>(); long off = 0; Header atom; while (off < input.size()) { input.position(off); atom = Header.read(NIOUtils.fetchFrom(input, 16)); if (atom == null) break; result.add(new Atom(atom, off)); off += atom.getSize(); } return result; } public static Atom atom(SeekableByteChannel input) throws IOException { long off = input.position(); Header atom = Header.read(NIOUtils.fetchFrom(input, 16)); return atom == null ? null : new Atom(atom, off); } public static class Atom { private long offset; private Header header; public Atom(Header header, long offset) { this.header = header; this.offset = offset; } public long getOffset() { return offset; } public Header getHeader() { return header; } public Box parseBox(SeekableByteChannel input) throws IOException { input.position(offset + header.headerSize()); return NodeBox.parseBox(NIOUtils.fetchFrom(input, (int) header.getSize()), header, BoxFactory.getDefault()); } public void copy(SeekableByteChannel input, WritableByteChannel out) throws IOException { input.position(offset); NIOUtils.copy(input, out, header.getSize()); } } public static MovieBox parseMovie(File source) throws IOException { SeekableByteChannel input = null; try { input = readableFileChannel(source); return parseMovie(input); } finally { if (input != null) input.close(); } } public static MovieBox createRefMovie(File source) throws IOException { SeekableByteChannel input = null; try { input = readableFileChannel(source); return createRefMovie(input, "file://" + source.getCanonicalPath()); } finally { if (input != null) input.close(); } } public static void writeMovie(File f, MovieBox movie) throws IOException { FileChannel out = null; try { out = new FileInputStream(f).getChannel(); writeMovie(f, movie); } finally { out.close(); } } public static void writeMovie(SeekableByteChannel out, MovieBox movie) throws IOException { ByteBuffer buf = ByteBuffer.allocate(16 * 1024 * 1024); movie.write(buf); buf.flip(); out.write(buf); } public static Box cloneBox(Box box, int approxSize) { return cloneBox(box, approxSize, BoxFactory.getDefault()); } public static Box cloneBox(Box box, int approxSize, BoxFactory bf) { ByteBuffer buf = ByteBuffer.allocate(approxSize); box.write(buf); buf.flip(); return NodeBox.parseChildBox(buf, bf); } public static String getFourcc(Codec codec) { return codecMapping.get(codec); } public static ByteBuffer writeBox(Box box, int approxSize) { ByteBuffer buf = ByteBuffer.allocate(approxSize); box.write(buf); buf.flip(); return buf; } }