diff options
Diffstat (limited to 'isoparser/src/main/java/com/googlecode/mp4parser/.svn')
8 files changed, 1059 insertions, 0 deletions
diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/.svn/all-wcprops b/isoparser/src/main/java/com/googlecode/mp4parser/.svn/all-wcprops new file mode 100644 index 0000000..31dd55d --- /dev/null +++ b/isoparser/src/main/java/com/googlecode/mp4parser/.svn/all-wcprops @@ -0,0 +1,41 @@ +K 25 +svn:wc:ra_dav:version-url +V 72 +/svn/!svn/ver/776/trunk/isoparser/src/main/java/com/googlecode/mp4parser +END +AbstractContainerBox.java +K 25 +svn:wc:ra_dav:version-url +V 98 +/svn/!svn/ver/616/trunk/isoparser/src/main/java/com/googlecode/mp4parser/AbstractContainerBox.java +END +AbstractFullBox.java +K 25 +svn:wc:ra_dav:version-url +V 93 +/svn/!svn/ver/525/trunk/isoparser/src/main/java/com/googlecode/mp4parser/AbstractFullBox.java +END +Version.java +K 25 +svn:wc:ra_dav:version-url +V 85 +/svn/!svn/ver/599/trunk/isoparser/src/main/java/com/googlecode/mp4parser/Version.java +END +AbstractBox.java +K 25 +svn:wc:ra_dav:version-url +V 89 +/svn/!svn/ver/772/trunk/isoparser/src/main/java/com/googlecode/mp4parser/AbstractBox.java +END +RequiresParseDetailAspect.java +K 25 +svn:wc:ra_dav:version-url +V 103 +/svn/!svn/ver/705/trunk/isoparser/src/main/java/com/googlecode/mp4parser/RequiresParseDetailAspect.java +END +FullContainerBox.java +K 25 +svn:wc:ra_dav:version-url +V 94 +/svn/!svn/ver/616/trunk/isoparser/src/main/java/com/googlecode/mp4parser/FullContainerBox.java +END diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/.svn/entries b/isoparser/src/main/java/com/googlecode/mp4parser/.svn/entries new file mode 100644 index 0000000..159e3a7 --- /dev/null +++ b/isoparser/src/main/java/com/googlecode/mp4parser/.svn/entries @@ -0,0 +1,250 @@ +10 + +dir +778 +http://mp4parser.googlecode.com/svn/trunk/isoparser/src/main/java/com/googlecode/mp4parser +http://mp4parser.googlecode.com/svn + + + +2012-09-10T14:34:23.574807Z +776 +sebastian.annies@gmail.com + + + + + + + + + + + + + + +7decde4b-c250-0410-a0da-51896bc88be6 + +AbstractContainerBox.java +file + + + + +2012-09-14T17:27:51.677236Z +023ce1033e326946fb1e551942a711fe +2012-05-17T09:04:15.805545Z +616 +Sebastian.Annies@gmail.com + + + + + + + + + + + + + + + + + + + + + +5225 + +AbstractFullBox.java +file + + + + +2012-09-14T17:27:51.677236Z +9a0208c01832235bc5b32054aaea4cb5 +2012-04-25T19:24:04.485529Z +525 +Sebastian.Annies@gmail.com + + + + + + + + + + + + + + + + + + + + + +1937 + +authoring +dir + +boxes +dir + +h264 +dir + +Version.java +file + + + + +2012-09-14T17:27:51.677236Z +6123f036beaaa10451566670349e4454 +2012-05-10T08:19:36.847188Z +599 +Sebastian.Annies@gmail.com + + + + + + + + + + + + + + + + + + + + + +718 + +srt +dir + +AbstractBox.java +file + + + + +2012-09-14T17:27:51.677236Z +35f21f761802c8d830736d617b7dd93a +2012-09-01T02:22:41.253285Z +772 +michael.stattmann@gmail.com + + + + + + + + + + + + + + + + + + + + + +9423 + +annotations +dir + +util +dir + +RequiresParseDetailAspect.java +file + + + + +2012-09-14T17:27:51.677236Z +f5277a7d1c211e4312c9ff308ad3b5f9 +2012-07-06T09:18:45.003720Z +705 +Sebastian.Annies@gmail.com + + + + + + + + + + + + + + + + + + + + + +2591 + +FullContainerBox.java +file + + + + +2012-09-14T17:27:51.677236Z +96f90fe7c15db4a397da4f38d047702f +2012-05-17T09:04:15.805545Z +616 +Sebastian.Annies@gmail.com + + + + + + + + + + + + + + + + + + + + + +5054 + diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/.svn/text-base/AbstractBox.java.svn-base b/isoparser/src/main/java/com/googlecode/mp4parser/.svn/text-base/AbstractBox.java.svn-base new file mode 100644 index 0000000..f75bc1d --- /dev/null +++ b/isoparser/src/main/java/com/googlecode/mp4parser/.svn/text-base/AbstractBox.java.svn-base @@ -0,0 +1,275 @@ +/* + * Copyright 2012 Sebastian Annies, Hamburg + * + * Licensed under the Apache License, Version 2.0 (the License); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.googlecode.mp4parser; + +import com.coremedia.iso.BoxParser; +import com.coremedia.iso.ChannelHelper; +import com.coremedia.iso.Hex; +import com.coremedia.iso.IsoFile; +import com.coremedia.iso.IsoTypeWriter; +import com.coremedia.iso.boxes.Box; +import com.coremedia.iso.boxes.ContainerBox; +import com.coremedia.iso.boxes.UserBox; +import com.googlecode.mp4parser.annotations.DoNotParseDetail; + +import java.io.IOException; +import java.nio.ByteBuffer; +import java.nio.channels.FileChannel; +import java.nio.channels.ReadableByteChannel; +import java.nio.channels.WritableByteChannel; +import java.util.logging.Logger; + +import static com.googlecode.mp4parser.util.CastUtils.l2i; + +/** + * A basic on-demand parsing box. Requires the implementation of three methods to become a fully working box: + * <ol> + * <li>{@link #_parseDetails(java.nio.ByteBuffer)}</li> + * <li>{@link #getContent(java.nio.ByteBuffer)}</li> + * <li>{@link #getContentSize()}</li> + * </ol> + * additionally this new box has to be put into the <code>isoparser-default.properties</code> file so that + * it is accessible by the <code>PropertyBoxParserImpl</code> + */ +public abstract class AbstractBox implements Box { + public static int MEM_MAP_THRESHOLD = 100 * 1024; + private static Logger LOG = Logger.getLogger(AbstractBox.class.getName()); + + protected String type; + private byte[] userType; + private ContainerBox parent; + + private ByteBuffer content; + private ByteBuffer deadBytes = null; + + + protected AbstractBox(String type) { + this.type = type; + } + + protected AbstractBox(String type, byte[] userType) { + this.type = type; + this.userType = userType; + } + + /** + * Get the box's content size without its header. This must be the exact number of bytes + * that <code>getContent(ByteBuffer)</code> writes. + * + * @return Gets the box's content size in bytes + * @see #getContent(java.nio.ByteBuffer) + */ + protected abstract long getContentSize(); + + /** + * Write the box's content into the given <code>ByteBuffer</code>. This must include flags + * and version in case of a full box. <code>byteBuffer</code> has been initialized with + * <code>getSize()</code> bytes. + * + * @param byteBuffer the sink for the box's content + */ + protected abstract void getContent(ByteBuffer byteBuffer); + + /** + * Parse the box's fields and child boxes if any. + * + * @param content the box's raw content beginning after the 4-cc field. + */ + protected abstract void _parseDetails(ByteBuffer content); + + /** + * Read the box's content from a byte channel without parsing it. Parsing is done on-demand. + * + * @param readableByteChannel the (part of the) iso file to parse + * @param contentSize expected contentSize of the box + * @param boxParser creates inner boxes + * @throws IOException in case of an I/O error. + */ + @DoNotParseDetail + public void parse(ReadableByteChannel readableByteChannel, ByteBuffer header, long contentSize, BoxParser boxParser) throws IOException { + if (readableByteChannel instanceof FileChannel && contentSize > MEM_MAP_THRESHOLD) { + // todo: if I map this here delayed I could use transferFrom/transferTo in the getBox method + // todo: potentially this could speed up writing. + // + // It's quite expensive to map a file into the memory. Just do it when the box is larger than a MB. + content = ((FileChannel) readableByteChannel).map(FileChannel.MapMode.READ_ONLY, ((FileChannel) readableByteChannel).position(), contentSize); + ((FileChannel) readableByteChannel).position(((FileChannel) readableByteChannel).position() + contentSize); + } else { + assert contentSize < Integer.MAX_VALUE; + content = ChannelHelper.readFully(readableByteChannel, contentSize); + } + } + + public void getBox(WritableByteChannel os) throws IOException { + ByteBuffer bb = ByteBuffer.allocate(l2i(getSize())); + getHeader(bb); + if (content == null) { + getContent(bb); + if (deadBytes != null) { + deadBytes.rewind(); + while (deadBytes.remaining() > 0) { + bb.put(deadBytes); + } + } + } else { + content.rewind(); + bb.put(content); + } + bb.rewind(); + os.write(bb); + } + + + /** + * Parses the raw content of the box. It surrounds the actual parsing + * which is done + */ + synchronized final void parseDetails() { + if (content != null) { + ByteBuffer content = this.content; + this.content = null; + content.rewind(); + _parseDetails(content); + if (content.remaining() > 0) { + deadBytes = content.slice(); + } + assert verify(content); + } + } + + /** + * Sets the 'dead' bytes. These bytes are left if the content of the box + * has been parsed but not all bytes have been used up. + * + * @param newDeadBytes the unused bytes with no meaning but required for bytewise reconstruction + */ + protected void setDeadBytes(ByteBuffer newDeadBytes) { + deadBytes = newDeadBytes; + } + + + /** + * Gets the full size of the box including header and content. + * + * @return the box's size + */ + public long getSize() { + long size = (content == null ? getContentSize() : content.limit()); + size += (8 + // size|type + (size >= ((1L << 32) - 8) ? 8 : 0) + // 32bit - 8 byte size and type + (UserBox.TYPE.equals(getType()) ? 16 : 0)); + size += (deadBytes == null ? 0 : deadBytes.limit()); + return size; + } + + @DoNotParseDetail + public String getType() { + return type; + } + + @DoNotParseDetail + public byte[] getUserType() { + return userType; + } + + @DoNotParseDetail + public ContainerBox getParent() { + return parent; + } + + @DoNotParseDetail + public void setParent(ContainerBox parent) { + this.parent = parent; + } + + @DoNotParseDetail + public IsoFile getIsoFile() { + return parent.getIsoFile(); + } + + /** + * Check if details are parsed. + * + * @return <code>true</code> whenever the content <code>ByteBuffer</code> is not <code>null</code> + */ + public boolean isParsed() { + return content == null; + } + + + /** + * Verifies that a box can be reconstructed byte-exact after parsing. + * + * @param content the raw content of the box + * @return <code>true</code> if raw content exactly matches the reconstructed content + */ + private boolean verify(ByteBuffer content) { + ByteBuffer bb = ByteBuffer.allocate(l2i(getContentSize() + (deadBytes != null ? deadBytes.limit() : 0))); + getContent(bb); + if (deadBytes != null) { + deadBytes.rewind(); + while (deadBytes.remaining() > 0) { + bb.put(deadBytes); + } + } + content.rewind(); + bb.rewind(); + + + if (content.remaining() != bb.remaining()) { + LOG.severe(this.getType() + ": remaining differs " + content.remaining() + " vs. " + bb.remaining()); + return false; + } + int p = content.position(); + for (int i = content.limit() - 1, j = bb.limit() - 1; i >= p; i--, j--) { + byte v1 = content.get(i); + byte v2 = bb.get(j); + if (v1 != v2) { + LOG.severe(String.format("%s: buffers differ at %d: %2X/%2X", this.getType(), i, v1, v2)); + byte[] b1 = new byte[content.remaining()]; + byte[] b2 = new byte[bb.remaining()]; + content.get(b1); + bb.get(b2); + System.err.println("original : " + Hex.encodeHex(b1, 4)); + System.err.println("reconstructed : " + Hex.encodeHex(b2, 4)); + return false; + } + } + return true; + + } + + private boolean isSmallBox() { + return (content == null ? (getContentSize() + (deadBytes != null ? deadBytes.limit() : 0) + 8) : content.limit()) < 1L << 32; + } + + private void getHeader(ByteBuffer byteBuffer) { + if (isSmallBox()) { + IsoTypeWriter.writeUInt32(byteBuffer, this.getSize()); + byteBuffer.put(IsoFile.fourCCtoBytes(getType())); + } else { + IsoTypeWriter.writeUInt32(byteBuffer, 1); + byteBuffer.put(IsoFile.fourCCtoBytes(getType())); + IsoTypeWriter.writeUInt64(byteBuffer, getSize()); + } + if (UserBox.TYPE.equals(getType())) { + byteBuffer.put(getUserType()); + } + + + } +} diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/.svn/text-base/AbstractContainerBox.java.svn-base b/isoparser/src/main/java/com/googlecode/mp4parser/.svn/text-base/AbstractContainerBox.java.svn-base new file mode 100644 index 0000000..93369f3 --- /dev/null +++ b/isoparser/src/main/java/com/googlecode/mp4parser/.svn/text-base/AbstractContainerBox.java.svn-base @@ -0,0 +1,171 @@ +/* + * Copyright 2008 CoreMedia AG, Hamburg + * + * Licensed under the Apache License, Version 2.0 (the License); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.googlecode.mp4parser; + +import com.coremedia.iso.BoxParser; +import com.coremedia.iso.boxes.Box; +import com.coremedia.iso.boxes.ContainerBox; +import com.googlecode.mp4parser.util.ByteBufferByteChannel; + +import java.io.IOException; +import java.nio.ByteBuffer; +import java.nio.channels.ReadableByteChannel; +import java.nio.channels.WritableByteChannel; +import java.util.ArrayList; +import java.util.Collections; +import java.util.LinkedList; +import java.util.List; +import java.util.logging.Logger; + + +/** + * Abstract base class suitable for most boxes acting purely as container for other boxes. + */ +public abstract class AbstractContainerBox extends AbstractBox implements ContainerBox { + private static Logger LOG = Logger.getLogger(AbstractContainerBox.class.getName()); + + protected List<Box> boxes = new LinkedList<Box>(); + protected BoxParser boxParser; + + @Override + protected long getContentSize() { + long contentSize = 0; + for (Box boxe : boxes) { + contentSize += boxe.getSize(); + } + return contentSize; + } + + public AbstractContainerBox(String type) { + super(type); + } + + public List<Box> getBoxes() { + return Collections.unmodifiableList(boxes); + } + + public void setBoxes(List<Box> boxes) { + this.boxes = new LinkedList<Box>(boxes); + } + + @SuppressWarnings("unchecked") + public <T extends Box> List<T> getBoxes(Class<T> clazz) { + return getBoxes(clazz, false); + } + + @SuppressWarnings("unchecked") + public <T extends Box> List<T> getBoxes(Class<T> clazz, boolean recursive) { + List<T> boxesToBeReturned = new ArrayList<T>(2); + for (Box boxe : boxes) { + //clazz.isInstance(boxe) / clazz == boxe.getClass()? + // I hereby finally decide to use isInstance + + if (clazz.isInstance(boxe)) { + boxesToBeReturned.add((T) boxe); + } + + if (recursive && boxe instanceof ContainerBox) { + boxesToBeReturned.addAll(((ContainerBox) boxe).getBoxes(clazz, recursive)); + } + } + return boxesToBeReturned; + } + + /** + * Add <code>b</code> to the container and sets the parent correctly. + * + * @param b will be added to the container + */ + public void addBox(Box b) { + b.setParent(this); + boxes.add(b); + } + + public void removeBox(Box b) { + b.setParent(this); + boxes.remove(b); + } + + @Override + public void parse(ReadableByteChannel readableByteChannel, ByteBuffer header, long contentSize, BoxParser boxParser) throws IOException { + super.parse(readableByteChannel, header, contentSize, boxParser); + this.boxParser = boxParser; + } + + @Override + public void _parseDetails(ByteBuffer content) { + parseChildBoxes(content); + } + + + public String toString() { + StringBuilder buffer = new StringBuilder(); + + buffer.append(this.getClass().getSimpleName()).append("["); + for (int i = 0; i < boxes.size(); i++) { + if (i > 0) { + buffer.append(";"); + } + buffer.append(boxes.get(i).toString()); + } + buffer.append("]"); + return buffer.toString(); + } + + /** + * The number of bytes from box start (first length byte) to the + * first length byte of the first child box + * + * @return offset to first child box + */ + public long getNumOfBytesToFirstChild() { + return 8; + } + + @Override + protected void getContent(ByteBuffer byteBuffer) { + writeChildBoxes(byteBuffer); + } + + protected final void parseChildBoxes(ByteBuffer content) { + try { + while (content.remaining() >= 8) { // 8 is the minimal size for a sane box + boxes.add(boxParser.parseBox(new ByteBufferByteChannel(content), this)); + } + + if (content.remaining() != 0) { + setDeadBytes(content.slice()); + LOG.warning("Something's wrong with the sizes. There are dead bytes in a container box."); + } + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + protected final void writeChildBoxes(ByteBuffer bb) { + WritableByteChannel wbc = new ByteBufferByteChannel(bb); + for (Box box : boxes) { + try { + box.getBox(wbc); + } catch (IOException e) { + // My WritableByteChannel won't throw any excpetion + throw new RuntimeException("Cannot happen to me", e); + } + } + } + +} diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/.svn/text-base/AbstractFullBox.java.svn-base b/isoparser/src/main/java/com/googlecode/mp4parser/.svn/text-base/AbstractFullBox.java.svn-base new file mode 100644 index 0000000..bec8975 --- /dev/null +++ b/isoparser/src/main/java/com/googlecode/mp4parser/.svn/text-base/AbstractFullBox.java.svn-base @@ -0,0 +1,74 @@ +/* + * Copyright 2008 CoreMedia AG, Hamburg + * + * Licensed under the Apache License, Version 2.0 (the License); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.googlecode.mp4parser; + + +import com.coremedia.iso.IsoTypeReader; +import com.coremedia.iso.IsoTypeWriter; +import com.coremedia.iso.boxes.FullBox; + +import java.nio.ByteBuffer; + +/** + * Base class for all ISO Full boxes. + */ +public abstract class AbstractFullBox extends AbstractBox implements FullBox { + private int version; + private int flags; + + protected AbstractFullBox(String type) { + super(type); + } + + protected AbstractFullBox(String type, byte[] userType) { + super(type, userType); + } + + public int getVersion() { + return version; + } + + public void setVersion(int version) { + this.version = version; + } + + public int getFlags() { + return flags; + } + + public void setFlags(int flags) { + this.flags = flags; + } + + + /** + * Parses the version/flags header and returns the remaining box size. + * + * @param content + * @return number of bytes read + */ + protected final long parseVersionAndFlags(ByteBuffer content) { + version = IsoTypeReader.readUInt8(content); + flags = IsoTypeReader.readUInt24(content); + return 4; + } + + protected final void writeVersionAndFlags(ByteBuffer bb) { + IsoTypeWriter.writeUInt8(bb, version); + IsoTypeWriter.writeUInt24(bb, flags); + } +} diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/.svn/text-base/FullContainerBox.java.svn-base b/isoparser/src/main/java/com/googlecode/mp4parser/.svn/text-base/FullContainerBox.java.svn-base new file mode 100644 index 0000000..d16e47d --- /dev/null +++ b/isoparser/src/main/java/com/googlecode/mp4parser/.svn/text-base/FullContainerBox.java.svn-base @@ -0,0 +1,159 @@ +/* + * Copyright 2008 CoreMedia AG, Hamburg + * + * Licensed under the Apache License, Version 2.0 (the License); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.googlecode.mp4parser; + +import com.coremedia.iso.BoxParser; +import com.coremedia.iso.boxes.Box; +import com.coremedia.iso.boxes.ContainerBox; +import com.googlecode.mp4parser.util.ByteBufferByteChannel; + +import java.io.IOException; +import java.nio.ByteBuffer; +import java.nio.channels.ReadableByteChannel; +import java.nio.channels.WritableByteChannel; +import java.util.ArrayList; +import java.util.LinkedList; +import java.util.List; +import java.util.logging.Logger; + +/** + * Abstract base class for a full iso box only containing ither boxes. + */ +public abstract class FullContainerBox extends AbstractFullBox implements ContainerBox { + protected List<Box> boxes = new LinkedList<Box>(); + private static Logger LOG = Logger.getLogger(FullContainerBox.class.getName()); + BoxParser boxParser; + + public void setBoxes(List<Box> boxes) { + this.boxes = new LinkedList<Box>(boxes); + } + + @SuppressWarnings("unchecked") + public <T extends Box> List<T> getBoxes(Class<T> clazz) { + return getBoxes(clazz, false); + } + + @SuppressWarnings("unchecked") + public <T extends Box> List<T> getBoxes(Class<T> clazz, boolean recursive) { + List<T> boxesToBeReturned = new ArrayList<T>(2); + for (Box boxe : boxes) { //clazz.isInstance(boxe) / clazz == boxe.getClass()? + if (clazz == boxe.getClass()) { + boxesToBeReturned.add((T) boxe); + } + + if (recursive && boxe instanceof ContainerBox) { + boxesToBeReturned.addAll((((ContainerBox) boxe).getBoxes(clazz, recursive))); + } + } + // Optimize here! Spare object creation work on arrays directly! System.arrayCopy + return boxesToBeReturned; + //return (T[]) boxesToBeReturned.toArray(); + } + + protected long getContentSize() { + long contentSize = 4; // flags and version + for (Box boxe : boxes) { + contentSize += boxe.getSize(); + } + return contentSize; + } + + public void addBox(Box b) { + b.setParent(this); + boxes.add(b); + } + + public void removeBox(Box b) { + b.setParent(null); + boxes.remove(b); + } + + public FullContainerBox(String type) { + super(type); + } + + public List<Box> getBoxes() { + return boxes; + } + + @Override + public void parse(ReadableByteChannel readableByteChannel, ByteBuffer header, long contentSize, BoxParser boxParser) throws IOException { + super.parse(readableByteChannel, header, contentSize, boxParser); + this.boxParser = boxParser; + } + + @Override + public void _parseDetails(ByteBuffer content) { + parseVersionAndFlags(content); + parseChildBoxes(content); + } + + protected final void parseChildBoxes(ByteBuffer content) { + try { + while (content.remaining() >= 8) { // 8 is the minimal size for a sane box + boxes.add(boxParser.parseBox(new ByteBufferByteChannel(content), this)); + } + + if (content.remaining() != 0) { + setDeadBytes(content.slice()); + LOG.severe("Some sizes are wrong"); + } + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + public String toString() { + StringBuilder buffer = new StringBuilder(); + buffer.append(this.getClass().getSimpleName()).append("["); + for (int i = 0; i < boxes.size(); i++) { + if (i > 0) { + buffer.append(";"); + } + buffer.append(boxes.get(i).toString()); + } + buffer.append("]"); + return buffer.toString(); + } + + + protected void getContent(ByteBuffer byteBuffer) { + writeVersionAndFlags(byteBuffer); + writeChildBoxes(byteBuffer); + } + + protected final void writeChildBoxes(ByteBuffer bb) { + WritableByteChannel wbc = new ByteBufferByteChannel(bb); + for (Box box : boxes) { + try { + box.getBox(wbc); + } catch (IOException e) { + // cannot happen since my WritableByteChannel won't throw any excpetion + throw new RuntimeException("Cannot happen.", e); + } + + } + } + + public long getNumOfBytesToFirstChild() { + long sizeOfChildren = 0; + for (Box box : boxes) { + sizeOfChildren += box.getSize(); + } + return getSize() - sizeOfChildren; + } +} diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/.svn/text-base/RequiresParseDetailAspect.java.svn-base b/isoparser/src/main/java/com/googlecode/mp4parser/.svn/text-base/RequiresParseDetailAspect.java.svn-base new file mode 100644 index 0000000..5009230 --- /dev/null +++ b/isoparser/src/main/java/com/googlecode/mp4parser/.svn/text-base/RequiresParseDetailAspect.java.svn-base @@ -0,0 +1,62 @@ +/* + * Copyright 2012 Sebastian Annies, Hamburg + * + * Licensed under the Apache License, Version 2.0 (the License); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.googlecode.mp4parser; + +import org.aspectj.lang.JoinPoint; +import org.aspectj.lang.annotation.Aspect; +import org.aspectj.lang.annotation.Before; + +@Aspect +/** + * An aspect to trigger the actual parsing of boxes' content when it is actually needed. This aspect + * calls {@link com.googlecode.mp4parser.AbstractBox#parseDetails()} before actually executing + * the method. + */ +public class RequiresParseDetailAspect { + + + @Before("this(com.googlecode.mp4parser.AbstractBox) && ((execution(public * * (..)) && !( " + + "execution(* parseDetails()) || " + + "execution(* getNumOfBytesToFirstChild()) || " + + "execution(* getType()) || " + + "execution(* isParsed()) || " + + "execution(* getHeader(*)) || " + + "execution(* parse()) || " + + "execution(* getBox(*)) || " + + "execution(* getSize()) || " + + "execution(* parseDetails()) || " + + "execution(* _parseDetails(*)) || " + + "execution(* parse(*,*,*,*)) || " + + "execution(* getIsoFile()) || " + + "execution(* getParent()) || " + + "execution(* setParent(*)) || " + + "execution(* getUserType()) || " + + "execution(* setUserType(*))) && " + + "!@annotation(com.googlecode.mp4parser.annotations.DoNotParseDetail)) || @annotation(com.googlecode.mp4parser.annotations.ParseDetail))") + public void before(JoinPoint joinPoint) { + if (joinPoint.getTarget() instanceof AbstractBox) { + if (!((AbstractBox) joinPoint.getTarget()).isParsed()) { + //System.err.println(String.format("parsed detail %s", joinPoint.getTarget().getClass().getSimpleName())); + ((AbstractBox) joinPoint.getTarget()).parseDetails(); + } + } else { + throw new RuntimeException("Only methods in subclasses of " + AbstractBox.class.getName() + " can be annotated with ParseDetail"); + } + + } + + +}
\ No newline at end of file diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/.svn/text-base/Version.java.svn-base b/isoparser/src/main/java/com/googlecode/mp4parser/.svn/text-base/Version.java.svn-base new file mode 100644 index 0000000..f93816f --- /dev/null +++ b/isoparser/src/main/java/com/googlecode/mp4parser/.svn/text-base/Version.java.svn-base @@ -0,0 +1,27 @@ +package com.googlecode.mp4parser; + +import java.io.IOException; +import java.io.InputStreamReader; +import java.io.LineNumberReader; +import java.util.logging.Logger; + +/** + * The classic version object. + */ +public class Version { + private static final Logger LOG = Logger.getLogger(Version.class.getName()); + public static final String VERSION; + + static { + LineNumberReader lnr = new LineNumberReader(new InputStreamReader(Version.class.getResourceAsStream("/version.txt"))); + String version; + try { + version = lnr.readLine(); + } catch (IOException e) { + LOG.warning(e.getMessage()); + version = "unknown"; + } + VERSION = version; + + } +} |