package org.jcodec.containers.mp4.boxes; import java.nio.ByteBuffer; import java.util.Iterator; import java.util.LinkedList; import java.util.List; import org.jcodec.common.NIOUtils; /** * This class is part of JCodec ( www.jcodec.org ) This software is distributed * under FreeBSD License * * A node box * * A box containing children, no data * * @author Jay Codec * */ public class NodeBox extends Box { private static final int MAX_BOX_SIZE = 128 * 1024 * 1024; protected List<Box> boxes = new LinkedList<Box>(); protected BoxFactory factory = BoxFactory.getDefault(); public NodeBox(Header atom) { super(atom); } public NodeBox(NodeBox other) { super(other); this.boxes = other.boxes; this.factory = other.factory; } public void parse(ByteBuffer input) { while (input.remaining() >= 8) { Box child = parseChildBox(input, factory); if (child != null) boxes.add(child); } } public static Box parseChildBox(ByteBuffer input, BoxFactory factory) { ByteBuffer fork = input.duplicate(); while (input.remaining() >= 4 && fork.getInt() == 0) input.getInt(); if (input.remaining() < 4) return null; Header childAtom = Header.read(input); if (childAtom != null && input.remaining() >= childAtom.getBodySize()) return parseBox(NIOUtils.read(input, (int) childAtom.getBodySize()), childAtom, factory); else return null; } public static Box newBox(Header header, BoxFactory factory) { Class<? extends Box> claz = factory.toClass(header.getFourcc()); if (claz == null) return new LeafBox(header); try { try { return claz.getConstructor(Header.class).newInstance(header); } catch (NoSuchMethodException e) { return claz.newInstance(); } } catch (Exception e) { throw new RuntimeException(e); } } public static Box parseBox(ByteBuffer input, Header childAtom, BoxFactory factory) { Box box = newBox(childAtom, factory); if (childAtom.getBodySize() < MAX_BOX_SIZE) { box.parse(input); return box; } else { return new LeafBox(new Header("free", 8)); } } public List<Box> getBoxes() { return boxes; } public void add(Box box) { boxes.add(box); } protected void doWrite(ByteBuffer out) { for (Box box : boxes) { box.write(out); } } public void addFirst(MovieHeaderBox box) { boxes.add(0, box); } public void replace(String fourcc, Box box) { removeChildren(fourcc); add(box); } public void dump(StringBuilder sb) { super.dump(sb); sb.append(": {\n"); dumpBoxes(sb); sb.append("\n}"); } protected void dumpBoxes(StringBuilder sb) { StringBuilder sb1 = new StringBuilder(); Iterator<Box> iterator = boxes.iterator(); while (iterator.hasNext()) { iterator.next().dump(sb1); if (iterator.hasNext()) sb1.append(",\n"); } sb.append(sb1.toString().replaceAll("([^\n]*)\n", " $1\n")); } public void removeChildren(String... fourcc) { for (Iterator<Box> it = boxes.iterator(); it.hasNext();) { Box box = it.next(); String fcc = box.getFourcc(); for (String cand : fourcc) { if (cand.equals(fcc)) { it.remove(); break; } } } } }