org.jcodec.containers.mp4.boxes.NodeBox Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of jcodec Show documentation
Show all versions of jcodec Show documentation
Pure Java implementation of video/audio codecs and formats
package org.jcodec.containers.mp4.boxes;
import java.util.Iterator;
import org.jcodec.common.io.NIOUtils;
import org.jcodec.common.logging.Logger;
import org.jcodec.common.tools.ToJSON;
import org.jcodec.containers.mp4.IBoxFactory;
import java.lang.StringBuilder;
import java.lang.reflect.Array;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.Collection;
import java.util.LinkedList;
import java.util.List;
import java.util.ListIterator;
import org.jcodec.platform.Platform;
/**
* 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 The JCodec project
*
*/
public class NodeBox extends Box {
protected List boxes;
protected IBoxFactory factory;
public NodeBox(Header atom) {
super(atom);
this.boxes = new LinkedList();
}
public void setFactory(IBoxFactory factory) {
this.factory = 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, IBoxFactory factory) {
ByteBuffer fork = input.duplicate();
while (input.remaining() >= 4 && fork.getInt() == 0)
input.getInt();
if (input.remaining() < 4)
return null;
Box ret = null;
Header childAtom = Header.read(input);
if (childAtom != null && input.remaining() >= childAtom.getBodySize()) {
ret = Box.parseBox(NIOUtils.read(input, (int) childAtom.getBodySize()), childAtom, factory);
}
return ret;
}
public List getBoxes() {
return boxes;
}
public void add(Box box) {
boxes.add(box);
}
protected void doWrite(ByteBuffer out) {
for (Box box : boxes) {
box.write(out);
}
}
@Override
public int estimateSize() {
int total = 0;
for (Box box : boxes) {
total += box.estimateSize();
}
return total + Header.estimateHeaderSize(total);
}
public void addFirst(MovieHeaderBox box) {
boxes.add(0, box);
}
public void replace(String fourcc, Box box) {
removeChildren(fourcc);
add(box);
}
public void replaceBox(Box box) {
removeChildren(box.getFourcc());
add(box);
}
protected void dump(StringBuilder sb) {
sb.append("{\"tag\":\"" + header.getFourcc() + "\",");
List fields = new ArrayList(0);
ToJSON.fieldsToJSON(this, sb, fields.toArray(new String[0]));
sb.append("\"boxes\": [");
dumpBoxes(sb);
sb.append("]");
sb.append("}");
}
protected void dumpBoxes(StringBuilder sb) {
for (int i = 0; i < boxes.size(); i++) {
boxes.get(i).dump(sb);
if (i < boxes.size() - 1)
sb.append(",");
}
}
public void removeChildren(String... arguments) {
for (Iterator it = boxes.iterator(); it.hasNext();) {
Box box = it.next();
String fcc = box.getFourcc();
for (int i = 0; i < arguments.length; i++) {
String cand = arguments[i];
if (cand.equals(fcc)) {
it.remove();
break;
}
}
}
}
public static Box doCloneBox(Box box, int approxSize, IBoxFactory bf) {
ByteBuffer buf = ByteBuffer.allocate(approxSize);
box.write(buf);
buf.flip();
return parseChildBox(buf, bf);
}
public static Box cloneBox(Box box, int approxSize, IBoxFactory bf) {
return NodeBox.doCloneBox(box, approxSize, bf);
}
public static T[] findDeep(Box box, Class class1, String name) {
List storage = new ArrayList();
findDeepInner(box, class1, name, storage);
return storage.toArray((T[]) Array.newInstance(class1, 0));
}
public static void findDeepInner(Box box, Class class1, String name, List storage) {
if (box == null)
return;
if (name.equals(box.getHeader().getFourcc())) {
storage.add((T) box);
return;
}
if (box instanceof NodeBox) {
NodeBox nb = (NodeBox) box;
for (Box candidate : nb.getBoxes()) {
findDeepInner(candidate, class1, name, storage);
}
}
}
public static T[] findAll(Box box, Class class1, String path) {
return findAllPath(box, class1, new String[] { path });
}
public static T findFirst(NodeBox box, Class clazz, String path) {
return findFirstPath(box, clazz, new String[] { path });
}
public static T findFirstPath(NodeBox box, Class clazz, String[] path) {
T[] result = (T[]) findAllPath(box, clazz, path);
return result.length > 0 ? result[0] : null;
}
public static T[] findAllPath(Box box, Class class1, String[] path) {
List result = new LinkedList();
List tlist = new LinkedList();
for (int i = 0; i < path.length; i++) {
String type = path[i];
tlist.add(type);
}
findBox(box, tlist, result);
for (ListIterator it = result.listIterator(); it.hasNext();) {
Box next = it.next();
if (next == null) {
it.remove();
} else if (!Platform.isAssignableFrom(class1, next.getClass())) {
// Trying to reinterpret one box as the other
try {
it.set(Box.asBox(class1, next));
} catch (Exception e) {
Logger.warn("Failed to reinterpret box: " + next.getFourcc() + " as: " + class1.getName() + "."
+ e.getMessage());
it.remove();
}
}
}
return result.toArray((T[]) Array.newInstance(class1, 0));
}
public static void findBox(Box root, List path, Collection result) {
if (path.size() > 0) {
String head = path.remove(0);
if (root instanceof NodeBox) {
NodeBox nb = (NodeBox) root;
for (Box candidate : nb.getBoxes()) {
if (head == null || head.equals(candidate.header.getFourcc())) {
findBox(candidate, path, result);
}
}
}
path.add(0, head);
} else {
result.add(root);
}
}
}