constructorObject;
+ try {
+ if (param.length > 0) {
+ constructorObject = clazz.getConstructor(constructorArgsClazz);
+ } else {
+ constructorObject = clazz.getConstructor();
+ }
+
+ return constructorObject.newInstance(constructorArgs);
+ } catch (NoSuchMethodException e) {
+ throw new RuntimeException(e);
+ } catch (InvocationTargetException e) {
+ throw new RuntimeException(e);
+ } catch (InstantiationException e) {
+ throw new RuntimeException(e);
+ } catch (IllegalAccessException e) {
+ throw new RuntimeException(e);
+ }
+
+
+ } catch (ClassNotFoundException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ private class FourCcToBox {
+ private String type;
+ private byte[] userType;
+ private String parent;
+ private String clazzName;
+ private String[] param;
+
+ public FourCcToBox(String type, byte[] userType, String parent) {
+ this.type = type;
+ this.parent = parent;
+ this.userType = userType;
+ }
+
+ public String getClazzName() {
+ return clazzName;
+ }
+
+ public String[] getParam() {
+ return param;
+ }
+
+ public FourCcToBox invoke() {
+ String constructor;
+ if (userType != null) {
+ if (!"uuid".equals((type))) {
+ throw new RuntimeException("we have a userType but no uuid box type. Something's wrong");
+ }
+ constructor = mapping.getProperty((parent) + "-uuid[" + Hex.encodeHex(userType).toUpperCase() + "]");
+ if (constructor == null) {
+ constructor = mapping.getProperty("uuid[" + Hex.encodeHex(userType).toUpperCase() + "]");
+ }
+ if (constructor == null) {
+ constructor = mapping.getProperty("uuid");
+ }
+ } else {
+ constructor = mapping.getProperty((parent) + "-" + (type));
+ if (constructor == null) {
+ constructor = mapping.getProperty((type));
+ }
+ }
+ if (constructor == null) {
+ constructor = mapping.getProperty("default");
+ }
+ if (constructor == null) {
+ throw new RuntimeException("No box object found for " + type);
+ }
+ Matcher m = p.matcher(constructor);
+ boolean matches = m.matches();
+ if (!matches) {
+ throw new RuntimeException("Cannot work with that constructor: " + constructor);
+ }
+ clazzName = m.group(1);
+ param = m.group(2).split(",");
+ return this;
+ }
+ }
+}
diff --git a/android-aac-enc/src/com/coremedia/iso/Utf8.java b/android-aac-enc/src/com/coremedia/iso/Utf8.java
new file mode 100644
index 000000000..a30497e4f
--- /dev/null
+++ b/android-aac-enc/src/com/coremedia/iso/Utf8.java
@@ -0,0 +1,59 @@
+/*
+ * 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.coremedia.iso;
+
+import java.io.UnsupportedEncodingException;
+
+/**
+ * Converts byte[]
-> String
and vice versa.
+ */
+public final class Utf8 {
+ public static byte[] convert(String s) {
+ try {
+ if (s != null) {
+ return s.getBytes("UTF-8");
+ } else {
+ return null;
+ }
+ } catch (UnsupportedEncodingException e) {
+ throw new Error(e);
+ }
+ }
+
+ public static String convert(byte[] b) {
+ try {
+ if (b != null) {
+ return new String(b, "UTF-8");
+ } else {
+ return null;
+ }
+ } catch (UnsupportedEncodingException e) {
+ throw new Error(e);
+ }
+ }
+
+ public static int utf8StringLengthInBytes(String utf8) {
+ try {
+ if (utf8 != null) {
+ return utf8.getBytes("UTF-8").length;
+ } else {
+ return 0;
+ }
+ } catch (UnsupportedEncodingException e) {
+ throw new RuntimeException();
+ }
+ }
+}
diff --git a/android-aac-enc/src/com/coremedia/iso/boxes/AbstractMediaHeaderBox.java b/android-aac-enc/src/com/coremedia/iso/boxes/AbstractMediaHeaderBox.java
new file mode 100644
index 000000000..cc141ae0c
--- /dev/null
+++ b/android-aac-enc/src/com/coremedia/iso/boxes/AbstractMediaHeaderBox.java
@@ -0,0 +1,29 @@
+/*
+ * Copyright 2011 Sebastian Annies, Hamburg, Germany
+ *
+ * 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.coremedia.iso.boxes;
+
+import com.googlecode.mp4parser.AbstractFullBox;
+
+/**
+ * A common superclass for all MediaInformationHeaderBoxes. E.g.
+ * VideoMediaHeaderBox, SoundMediaHeaderBox & HintMediaHeaderBox
+ */
+public abstract class AbstractMediaHeaderBox extends AbstractFullBox {
+ protected AbstractMediaHeaderBox(String type) {
+ super(type);
+ }
+}
diff --git a/android-aac-enc/src/com/coremedia/iso/boxes/AlbumBox.java b/android-aac-enc/src/com/coremedia/iso/boxes/AlbumBox.java
new file mode 100644
index 000000000..d66680691
--- /dev/null
+++ b/android-aac-enc/src/com/coremedia/iso/boxes/AlbumBox.java
@@ -0,0 +1,112 @@
+/*
+ * 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.coremedia.iso.boxes;
+
+import com.coremedia.iso.IsoTypeReader;
+import com.coremedia.iso.IsoTypeWriter;
+import com.coremedia.iso.Utf8;
+import com.googlecode.mp4parser.AbstractFullBox;
+
+import java.nio.ByteBuffer;
+
+/**
+ * Meta information in a 'udta' box about a track.
+ * Defined in 3GPP 26.244.
+ *
+ * @see com.coremedia.iso.boxes.UserDataBox
+ */
+public class AlbumBox extends AbstractFullBox {
+ public static final String TYPE = "albm";
+
+ private String language;
+ private String albumTitle;
+ private int trackNumber;
+
+ public AlbumBox() {
+ super(TYPE);
+ }
+
+ /**
+ * Declares the language code for the {@link #getAlbumTitle()} return value. See ISO 639-2/T for the set of three
+ * character codes.Each character is packed as the difference between its ASCII value and 0x60. The code is
+ * confined to being three lower-case letters, so these values are strictly positive.
+ *
+ * @return the language code
+ */
+ public String getLanguage() {
+ return language;
+ }
+
+ public String getAlbumTitle() {
+ return albumTitle;
+ }
+
+ public int getTrackNumber() {
+ return trackNumber;
+ }
+
+ public void setLanguage(String language) {
+ this.language = language;
+ }
+
+ public void setAlbumTitle(String albumTitle) {
+ this.albumTitle = albumTitle;
+ }
+
+ public void setTrackNumber(int trackNumber) {
+ this.trackNumber = trackNumber;
+ }
+
+ protected long getContentSize() {
+ return 6 + Utf8.utf8StringLengthInBytes(albumTitle) + 1 + (trackNumber == -1 ? 0 : 1);
+ }
+
+ @Override
+ public void _parseDetails(ByteBuffer content) {
+ parseVersionAndFlags(content);
+ language = IsoTypeReader.readIso639(content);
+ albumTitle = IsoTypeReader.readString(content);
+
+ if (content.remaining() > 0) {
+ trackNumber = IsoTypeReader.readUInt8(content);
+ } else {
+ trackNumber = -1;
+ }
+ }
+
+ @Override
+ protected void getContent(ByteBuffer byteBuffer) {
+ writeVersionAndFlags(byteBuffer);
+ IsoTypeWriter.writeIso639(byteBuffer, language);
+ byteBuffer.put(Utf8.convert(albumTitle));
+ byteBuffer.put((byte) 0);
+ if (trackNumber != -1) {
+ IsoTypeWriter.writeUInt8(byteBuffer, trackNumber);
+ }
+ }
+
+ public String toString() {
+ StringBuilder buffer = new StringBuilder();
+ buffer.append("AlbumBox[language=").append(getLanguage()).append(";");
+ buffer.append("albumTitle=").append(getAlbumTitle());
+ if (trackNumber >= 0) {
+ buffer.append(";trackNumber=").append(getTrackNumber());
+ }
+ buffer.append("]");
+ return buffer.toString();
+ }
+}
diff --git a/android-aac-enc/src/com/coremedia/iso/boxes/AuthorBox.java b/android-aac-enc/src/com/coremedia/iso/boxes/AuthorBox.java
new file mode 100644
index 000000000..672cde26a
--- /dev/null
+++ b/android-aac-enc/src/com/coremedia/iso/boxes/AuthorBox.java
@@ -0,0 +1,94 @@
+/*
+ * 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.coremedia.iso.boxes;
+
+
+import com.coremedia.iso.IsoTypeReader;
+import com.coremedia.iso.IsoTypeWriter;
+import com.coremedia.iso.Utf8;
+import com.googlecode.mp4parser.AbstractFullBox;
+
+import java.nio.ByteBuffer;
+
+/**
+ * Meta information in a 'udta' box about a track.
+ * Defined in 3GPP 26.244.
+ *
+ * @see com.coremedia.iso.boxes.UserDataBox
+ */
+public class AuthorBox extends AbstractFullBox {
+ public static final String TYPE = "auth";
+
+ private String language;
+ private String author;
+
+ public AuthorBox() {
+ super(TYPE);
+ }
+
+ /**
+ * Declares the language code for the {@link #getAuthor()} return value. See ISO 639-2/T for the set of three
+ * character codes.Each character is packed as the difference between its ASCII value and 0x60. The code is
+ * confined to being three lower-case letters, so these values are strictly positive.
+ *
+ * @return the language code
+ */
+ public String getLanguage() {
+ return language;
+ }
+
+ /**
+ * Author information.
+ *
+ * @return the author
+ */
+ public String getAuthor() {
+ return author;
+ }
+
+ public void setLanguage(String language) {
+ this.language = language;
+ }
+
+ public void setAuthor(String author) {
+ this.author = author;
+ }
+
+ protected long getContentSize() {
+ return 7 + Utf8.utf8StringLengthInBytes(author);
+ }
+
+ @Override
+ public void _parseDetails(ByteBuffer content) {
+ parseVersionAndFlags(content);
+ language = IsoTypeReader.readIso639(content);
+ author = IsoTypeReader.readString(content);
+ }
+
+ @Override
+ protected void getContent(ByteBuffer byteBuffer) {
+ writeVersionAndFlags(byteBuffer);
+ IsoTypeWriter.writeIso639(byteBuffer, language);
+ byteBuffer.put(Utf8.convert(author));
+ byteBuffer.put((byte) 0);
+ }
+
+
+ public String toString() {
+ return "AuthorBox[language=" + getLanguage() + ";author=" + getAuthor() + "]";
+ }
+}
diff --git a/android-aac-enc/src/com/coremedia/iso/boxes/BitRateBox.java b/android-aac-enc/src/com/coremedia/iso/boxes/BitRateBox.java
new file mode 100644
index 000000000..6c4b0e655
--- /dev/null
+++ b/android-aac-enc/src/com/coremedia/iso/boxes/BitRateBox.java
@@ -0,0 +1,91 @@
+/*
+ * 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.coremedia.iso.boxes;
+
+import com.coremedia.iso.IsoTypeReader;
+import com.coremedia.iso.IsoTypeWriter;
+import com.googlecode.mp4parser.AbstractBox;
+
+import java.nio.ByteBuffer;
+
+/**
+ * class BitRateBox extends Box('btrt') {
+ * unsigned int(32) bufferSizeDB;
+ * // gives the size of the decoding buffer for
+ * // the elementary stream in bytes.
+ * unsigned int(32) maxBitrate;
+ * // gives the maximum rate in bits/second
+ * // over any window of one second.
+ * unsigned int(32) avgBitrate;
+ * // avgBitrate gives the average rate in
+ * // bits/second over the entire presentation.
+ * }
+ */
+
+public final class BitRateBox extends AbstractBox {
+ public static final String TYPE = "btrt";
+
+ private long bufferSizeDb;
+ private long maxBitrate;
+ private long avgBitrate;
+
+ public BitRateBox() {
+ super(TYPE);
+ }
+
+ protected long getContentSize() {
+ return 12;
+ }
+
+ @Override
+ public void _parseDetails(ByteBuffer content) {
+ bufferSizeDb = IsoTypeReader.readUInt32(content);
+ maxBitrate = IsoTypeReader.readUInt32(content);
+ avgBitrate = IsoTypeReader.readUInt32(content);
+ }
+
+ @Override
+ protected void getContent(ByteBuffer byteBuffer) {
+ IsoTypeWriter.writeUInt32(byteBuffer, bufferSizeDb);
+ IsoTypeWriter.writeUInt32(byteBuffer, maxBitrate);
+ IsoTypeWriter.writeUInt32(byteBuffer, avgBitrate);
+ }
+
+ public long getBufferSizeDb() {
+ return bufferSizeDb;
+ }
+
+ public void setBufferSizeDb(long bufferSizeDb) {
+ this.bufferSizeDb = bufferSizeDb;
+ }
+
+ public long getMaxBitrate() {
+ return maxBitrate;
+ }
+
+ public void setMaxBitrate(long maxBitrate) {
+ this.maxBitrate = maxBitrate;
+ }
+
+ public long getAvgBitrate() {
+ return avgBitrate;
+ }
+
+ public void setAvgBitrate(long avgBitrate) {
+ this.avgBitrate = avgBitrate;
+ }
+}
diff --git a/android-aac-enc/src/com/coremedia/iso/boxes/Box.java b/android-aac-enc/src/com/coremedia/iso/boxes/Box.java
new file mode 100644
index 000000000..f6ca30265
--- /dev/null
+++ b/android-aac-enc/src/com/coremedia/iso/boxes/Box.java
@@ -0,0 +1,51 @@
+/*
+ * 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.coremedia.iso.boxes;
+
+import com.coremedia.iso.BoxParser;
+import com.coremedia.iso.boxes.ContainerBox;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.nio.channels.ReadableByteChannel;
+import java.nio.channels.WritableByteChannel;
+
+/**
+ * Defines basic interaction possibilities for any ISO box. Each box has a parent box and a type.
+ */
+public interface Box {
+ ContainerBox getParent();
+
+ void setParent(ContainerBox parent);
+
+ long getSize();
+
+ /**
+ * The box's 4-cc type.
+ * @return the 4 character type of the box
+ */
+ String getType();
+
+ /**
+ * Writes the complete box - size | 4-cc | content - to the given writableByteChannel
.
+ * @param writableByteChannel the box's sink
+ * @throws IOException in case of problems with the Channel
+ */
+ void getBox(WritableByteChannel writableByteChannel) throws IOException;
+
+ void parse(ReadableByteChannel readableByteChannel, ByteBuffer header, long contentSize, BoxParser boxParser) throws IOException;
+}
diff --git a/android-aac-enc/src/com/coremedia/iso/boxes/ChunkOffset64BitBox.java b/android-aac-enc/src/com/coremedia/iso/boxes/ChunkOffset64BitBox.java
new file mode 100755
index 000000000..f2340b95b
--- /dev/null
+++ b/android-aac-enc/src/com/coremedia/iso/boxes/ChunkOffset64BitBox.java
@@ -0,0 +1,51 @@
+package com.coremedia.iso.boxes;
+
+import com.coremedia.iso.IsoTypeReader;
+import com.coremedia.iso.IsoTypeWriter;
+
+import java.nio.ByteBuffer;
+
+import static com.googlecode.mp4parser.util.CastUtils.l2i;
+
+/**
+ * Abstract Chunk Offset Box
+ */
+public class ChunkOffset64BitBox extends ChunkOffsetBox {
+ public static final String TYPE = "co64";
+ private long[] chunkOffsets;
+
+ public ChunkOffset64BitBox() {
+ super(TYPE);
+ }
+
+ @Override
+ public long[] getChunkOffsets() {
+ return chunkOffsets;
+ }
+
+ @Override
+ protected long getContentSize() {
+ return 8 + 8 * chunkOffsets.length;
+ }
+
+ @Override
+ public void _parseDetails(ByteBuffer content) {
+ parseVersionAndFlags(content);
+ int entryCount = l2i(IsoTypeReader.readUInt32(content));
+ chunkOffsets = new long[entryCount];
+ for (int i = 0; i < entryCount; i++) {
+ chunkOffsets[i] = IsoTypeReader.readUInt64(content);
+ }
+ }
+
+ @Override
+ protected void getContent(ByteBuffer byteBuffer) {
+ writeVersionAndFlags(byteBuffer);
+ IsoTypeWriter.writeUInt32(byteBuffer, chunkOffsets.length);
+ for (long chunkOffset : chunkOffsets) {
+ IsoTypeWriter.writeUInt64(byteBuffer, chunkOffset);
+ }
+ }
+
+
+}
diff --git a/android-aac-enc/src/com/coremedia/iso/boxes/ChunkOffsetBox.java b/android-aac-enc/src/com/coremedia/iso/boxes/ChunkOffsetBox.java
new file mode 100755
index 000000000..01f5ae45a
--- /dev/null
+++ b/android-aac-enc/src/com/coremedia/iso/boxes/ChunkOffsetBox.java
@@ -0,0 +1,21 @@
+package com.coremedia.iso.boxes;
+
+import com.googlecode.mp4parser.AbstractFullBox;
+
+/**
+ * Abstract Chunk Offset Box
+ */
+public abstract class ChunkOffsetBox extends AbstractFullBox {
+
+ public ChunkOffsetBox(String type) {
+ super(type);
+ }
+
+ public abstract long[] getChunkOffsets();
+
+
+ public String toString() {
+ return this.getClass().getSimpleName() + "[entryCount=" + getChunkOffsets().length + "]";
+ }
+
+}
diff --git a/android-aac-enc/src/com/coremedia/iso/boxes/ClassificationBox.java b/android-aac-enc/src/com/coremedia/iso/boxes/ClassificationBox.java
new file mode 100644
index 000000000..a20fecaf9
--- /dev/null
+++ b/android-aac-enc/src/com/coremedia/iso/boxes/ClassificationBox.java
@@ -0,0 +1,110 @@
+/*
+ * 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.coremedia.iso.boxes;
+
+import com.coremedia.iso.IsoFile;
+import com.coremedia.iso.IsoTypeReader;
+import com.coremedia.iso.IsoTypeWriter;
+import com.coremedia.iso.Utf8;
+import com.googlecode.mp4parser.AbstractFullBox;
+
+import java.nio.ByteBuffer;
+
+/**
+ * Classification of the media according to 3GPP 26.244.
+ */
+public class ClassificationBox extends AbstractFullBox {
+ public static final String TYPE = "clsf";
+
+
+ private String classificationEntity;
+ private int classificationTableIndex;
+ private String language;
+ private String classificationInfo;
+
+ public ClassificationBox() {
+ super(TYPE);
+ }
+
+ public String getLanguage() {
+ return language;
+ }
+
+ public String getClassificationEntity() {
+ return classificationEntity;
+ }
+
+ public int getClassificationTableIndex() {
+ return classificationTableIndex;
+ }
+
+ public String getClassificationInfo() {
+ return classificationInfo;
+ }
+
+ public void setClassificationEntity(String classificationEntity) {
+ this.classificationEntity = classificationEntity;
+ }
+
+ public void setClassificationTableIndex(int classificationTableIndex) {
+ this.classificationTableIndex = classificationTableIndex;
+ }
+
+ public void setLanguage(String language) {
+ this.language = language;
+ }
+
+ public void setClassificationInfo(String classificationInfo) {
+ this.classificationInfo = classificationInfo;
+ }
+
+ protected long getContentSize() {
+ return 4 + 2 + 2 + Utf8.utf8StringLengthInBytes(classificationInfo) + 1;
+ }
+
+ @Override
+ public void _parseDetails(ByteBuffer content) {
+ parseVersionAndFlags(content);
+ byte[] cE = new byte[4];
+ content.get(cE);
+ classificationEntity = IsoFile.bytesToFourCC(cE);
+ classificationTableIndex = IsoTypeReader.readUInt16(content);
+ language = IsoTypeReader.readIso639(content);
+ classificationInfo = IsoTypeReader.readString(content);
+ }
+
+ @Override
+ protected void getContent(ByteBuffer byteBuffer) {
+ byteBuffer.put(IsoFile.fourCCtoBytes(classificationEntity));
+ IsoTypeWriter.writeUInt16(byteBuffer, classificationTableIndex);
+ IsoTypeWriter.writeIso639(byteBuffer, language);
+ byteBuffer.put(Utf8.convert(classificationInfo));
+ byteBuffer.put((byte) 0);
+ }
+
+
+ public String toString() {
+ StringBuilder buffer = new StringBuilder();
+ buffer.append("ClassificationBox[language=").append(getLanguage());
+ buffer.append("classificationEntity=").append(getClassificationEntity());
+ buffer.append(";classificationTableIndex=").append(getClassificationTableIndex());
+ buffer.append(";language=").append(getLanguage());
+ buffer.append(";classificationInfo=").append(getClassificationInfo());
+ buffer.append("]");
+ return buffer.toString();
+ }
+}
diff --git a/android-aac-enc/src/com/coremedia/iso/boxes/CompositionShiftLeastGreatestAtom.java b/android-aac-enc/src/com/coremedia/iso/boxes/CompositionShiftLeastGreatestAtom.java
new file mode 100644
index 000000000..3534b7ffd
--- /dev/null
+++ b/android-aac-enc/src/com/coremedia/iso/boxes/CompositionShiftLeastGreatestAtom.java
@@ -0,0 +1,101 @@
+package com.coremedia.iso.boxes;
+
+import com.googlecode.mp4parser.AbstractFullBox;
+
+import java.nio.ByteBuffer;
+
+/**
+ * The optional composition shift least greatest atom summarizes the calculated
+ * minimum and maximum offsets between decode and composition time, as well as
+ * the start and end times, for all samples. This allows a reader to determine
+ * the minimum required time for decode to obtain proper presentation order without
+ * needing to scan the sample table for the range of offsets. The type of the
+ * composition shift least greatest atom is ‘cslg’.
+ */
+public class CompositionShiftLeastGreatestAtom extends AbstractFullBox {
+ public CompositionShiftLeastGreatestAtom() {
+ super("cslg");
+ }
+
+ // A 32-bit unsigned integer that specifies the calculated value.
+ int compositionOffsetToDisplayOffsetShift;
+
+ // A 32-bit signed integer that specifies the calculated value.
+ int leastDisplayOffset;
+
+ // A 32-bit signed integer that specifies the calculated value.
+ int greatestDisplayOffset;
+
+ //A 32-bit signed integer that specifies the calculated value.
+ int displayStartTime;
+
+ //A 32-bit signed integer that specifies the calculated value.
+ int displayEndTime;
+
+
+ @Override
+ protected long getContentSize() {
+ return 24;
+ }
+
+ @Override
+ public void _parseDetails(ByteBuffer content) {
+ parseVersionAndFlags(content);
+ compositionOffsetToDisplayOffsetShift = content.getInt();
+ leastDisplayOffset = content.getInt();
+ greatestDisplayOffset = content.getInt();
+ displayStartTime = content.getInt();
+ displayEndTime = content.getInt();
+ }
+
+ @Override
+ protected void getContent(ByteBuffer byteBuffer) {
+ writeVersionAndFlags(byteBuffer);
+ byteBuffer.putInt(compositionOffsetToDisplayOffsetShift);
+ byteBuffer.putInt(leastDisplayOffset);
+ byteBuffer.putInt(greatestDisplayOffset);
+ byteBuffer.putInt(displayStartTime);
+ byteBuffer.putInt(displayEndTime);
+ }
+
+
+ public int getCompositionOffsetToDisplayOffsetShift() {
+ return compositionOffsetToDisplayOffsetShift;
+ }
+
+ public void setCompositionOffsetToDisplayOffsetShift(int compositionOffsetToDisplayOffsetShift) {
+ this.compositionOffsetToDisplayOffsetShift = compositionOffsetToDisplayOffsetShift;
+ }
+
+ public int getLeastDisplayOffset() {
+ return leastDisplayOffset;
+ }
+
+ public void setLeastDisplayOffset(int leastDisplayOffset) {
+ this.leastDisplayOffset = leastDisplayOffset;
+ }
+
+ public int getGreatestDisplayOffset() {
+ return greatestDisplayOffset;
+ }
+
+ public void setGreatestDisplayOffset(int greatestDisplayOffset) {
+ this.greatestDisplayOffset = greatestDisplayOffset;
+ }
+
+ public int getDisplayStartTime() {
+ return displayStartTime;
+ }
+
+ public void setDisplayStartTime(int displayStartTime) {
+ this.displayStartTime = displayStartTime;
+ }
+
+ public int getDisplayEndTime() {
+ return displayEndTime;
+ }
+
+ public void setDisplayEndTime(int displayEndTime) {
+ this.displayEndTime = displayEndTime;
+ }
+}
diff --git a/android-aac-enc/src/com/coremedia/iso/boxes/CompositionTimeToSample.java b/android-aac-enc/src/com/coremedia/iso/boxes/CompositionTimeToSample.java
new file mode 100644
index 000000000..411bfe916
--- /dev/null
+++ b/android-aac-enc/src/com/coremedia/iso/boxes/CompositionTimeToSample.java
@@ -0,0 +1,150 @@
+package com.coremedia.iso.boxes;
+
+import com.coremedia.iso.IsoTypeReader;
+import com.coremedia.iso.IsoTypeWriter;
+import com.googlecode.mp4parser.AbstractFullBox;
+
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import static com.googlecode.mp4parser.util.CastUtils.l2i;
+
+/**
+ *
+ * aligned(8) class CompositionOffsetBox
+ * extends FullBox(‘ctts’, version = 0, 0) {
+ * unsigned int(32) entry_count;
+ * int i;
+ * if (version==0) {
+ * for (i=0; i < entry_count; i++) {
+ * unsigned int(32) sample_count;
+ * unsigned int(32) sample_offset;
+ * }
+ * }
+ * else if (version == 1) {
+ * for (i=0; i < entry_count; i++) {
+ * unsigned int(32) sample_count;
+ * signed int(32) sample_offset;
+ * }
+ * }
+ * }
+ *
+ *
+ * This box provides the offset between decoding time and composition time.
+ * In version 0 of this box the decoding time must be less than the composition time, and
+ * the offsets are expressed as unsigned numbers such that
+ * CT(n) = DT(n) + CTTS(n) where CTTS(n) is the (uncompressed) table entry for sample n.
+ *
+ * In version 1 of this box, the composition timeline and the decoding timeline are
+ * still derived from each other, but the offsets are signed.
+ * It is recommended that for the computed composition timestamps, there is
+ * exactly one with the value 0 (zero).
+ */
+public class CompositionTimeToSample extends AbstractFullBox {
+ public static final String TYPE = "ctts";
+
+ List entries = Collections.emptyList();
+
+ public CompositionTimeToSample() {
+ super(TYPE);
+ }
+
+ protected long getContentSize() {
+ return 8 + 8 * entries.size();
+ }
+
+ public List getEntries() {
+ return entries;
+ }
+
+ public void setEntries(List entries) {
+ this.entries = entries;
+ }
+
+ @Override
+ public void _parseDetails(ByteBuffer content) {
+ parseVersionAndFlags(content);
+ int numberOfEntries = l2i(IsoTypeReader.readUInt32(content));
+ entries = new ArrayList(numberOfEntries);
+ for (int i = 0; i < numberOfEntries; i++) {
+ Entry e = new Entry(l2i(IsoTypeReader.readUInt32(content)), content.getInt());
+ entries.add(e);
+ }
+ }
+
+ @Override
+ protected void getContent(ByteBuffer byteBuffer) {
+ writeVersionAndFlags(byteBuffer);
+ IsoTypeWriter.writeUInt32(byteBuffer, entries.size());
+
+ for (Entry entry : entries) {
+ IsoTypeWriter.writeUInt32(byteBuffer, entry.getCount());
+ byteBuffer.putInt(entry.getOffset());
+ }
+
+ }
+
+
+ public static class Entry {
+ int count;
+ int offset;
+
+ public Entry(int count, int offset) {
+ this.count = count;
+ this.offset = offset;
+ }
+
+ public int getCount() {
+ return count;
+ }
+
+ public int getOffset() {
+ return offset;
+ }
+
+ public void setCount(int count) {
+ this.count = count;
+ }
+
+ public void setOffset(int offset) {
+ this.offset = offset;
+ }
+
+ @Override
+ public String toString() {
+ return "Entry{" +
+ "count=" + count +
+ ", offset=" + offset +
+ '}';
+ }
+ }
+
+
+ /**
+ * Decompresses the list of entries and returns the list of composition times.
+ *
+ * @return decoding time per sample
+ */
+ public static int[] blowupCompositionTimes(List entries) {
+ long numOfSamples = 0;
+ for (CompositionTimeToSample.Entry entry : entries) {
+ numOfSamples += entry.getCount();
+ }
+ assert numOfSamples <= Integer.MAX_VALUE;
+ int[] decodingTime = new int[(int) numOfSamples];
+
+ int current = 0;
+
+
+ for (CompositionTimeToSample.Entry entry : entries) {
+ for (int i = 0; i < entry.getCount(); i++) {
+ decodingTime[current++] = entry.getOffset();
+ }
+ }
+
+ return decodingTime;
+ }
+
+}
diff --git a/android-aac-enc/src/com/coremedia/iso/boxes/ContainerBox.java b/android-aac-enc/src/com/coremedia/iso/boxes/ContainerBox.java
new file mode 100644
index 000000000..a01637420
--- /dev/null
+++ b/android-aac-enc/src/com/coremedia/iso/boxes/ContainerBox.java
@@ -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.coremedia.iso.boxes;
+
+import com.coremedia.iso.IsoFile;
+
+import java.util.List;
+
+/**
+ * Interface for all ISO boxes that may contain other boxes.
+ */
+public interface ContainerBox extends Box {
+
+ /**
+ * Gets all child boxes. May not return null
.
+ *
+ * @return an array of boxes, empty array in case of no children.
+ */
+ List getBoxes();
+
+ /**
+ * Sets all boxes and removes all previous child boxes.
+ * @param boxes the new list of children
+ */
+ void setBoxes(List boxes);
+
+ /**
+ * Gets all child boxes of the given type. May not return null
.
+ *
+ * @param clazz child box's type
+ * @return an array of boxes, empty array in case of no children.
+ */
+ List getBoxes(Class clazz);
+
+ /**
+ * Gets all child boxes of the given type. May not return null
.
+ *
+ * @param clazz child box's type
+ * @param recursive step down the tree
+ * @return an array of boxes, empty array in case of no children.
+ */
+ List getBoxes(Class clazz, boolean recursive);
+
+ /**
+ * Gets the parent box. May be null
in case of the
+ * {@link com.coremedia.iso.IsoFile} itself.
+ *
+ * @return a ContainerBox
that contains this
+ */
+ ContainerBox getParent();
+
+ /**
+ * Returns the number of bytes from the start of the box to start of the first child.
+ *
+ * @return offset of first child from box start
+ */
+ long getNumOfBytesToFirstChild();
+
+ IsoFile getIsoFile();
+}
diff --git a/android-aac-enc/src/com/coremedia/iso/boxes/CopyrightBox.java b/android-aac-enc/src/com/coremedia/iso/boxes/CopyrightBox.java
new file mode 100644
index 000000000..86bc2152b
--- /dev/null
+++ b/android-aac-enc/src/com/coremedia/iso/boxes/CopyrightBox.java
@@ -0,0 +1,86 @@
+/*
+ * 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.coremedia.iso.boxes;
+
+
+import com.coremedia.iso.IsoTypeReader;
+import com.coremedia.iso.IsoTypeWriter;
+import com.coremedia.iso.Utf8;
+import com.googlecode.mp4parser.AbstractFullBox;
+
+import java.nio.ByteBuffer;
+
+/**
+ * The copyright box contains a copyright declaration which applies to the entire presentation, when contained
+ * within the MovieBox, or, when contained in a track, to that entire track. There may be multple boxes using
+ * different language codes.
+ *
+ * @see MovieBox
+ * @see TrackBox
+ */
+public class CopyrightBox extends AbstractFullBox {
+ public static final String TYPE = "cprt";
+
+ private String language;
+ private String copyright;
+
+ public CopyrightBox() {
+ super(TYPE);
+ }
+
+ public String getLanguage() {
+ return language;
+ }
+
+ public String getCopyright() {
+ return copyright;
+ }
+
+ public void setLanguage(String language) {
+ this.language = language;
+ }
+
+ public void setCopyright(String copyright) {
+ this.copyright = copyright;
+ }
+
+ protected long getContentSize() {
+ return 7 + Utf8.utf8StringLengthInBytes(copyright);
+ }
+
+ @Override
+ public void _parseDetails(ByteBuffer content) {
+ parseVersionAndFlags(content);
+ language = IsoTypeReader.readIso639(content);
+ copyright = IsoTypeReader.readString(content);
+ }
+
+ @Override
+ protected void getContent(ByteBuffer byteBuffer) {
+ writeVersionAndFlags(byteBuffer);
+ IsoTypeWriter.writeIso639(byteBuffer, language);
+ byteBuffer.put(Utf8.convert(copyright));
+ byteBuffer.put((byte) 0);
+ }
+
+ public String toString() {
+ return "CopyrightBox[language=" + getLanguage() + ";copyright=" + getCopyright() + "]";
+ }
+
+
+
+}
diff --git a/android-aac-enc/src/com/coremedia/iso/boxes/DataEntryUrlBox.java b/android-aac-enc/src/com/coremedia/iso/boxes/DataEntryUrlBox.java
new file mode 100644
index 000000000..b58608dc2
--- /dev/null
+++ b/android-aac-enc/src/com/coremedia/iso/boxes/DataEntryUrlBox.java
@@ -0,0 +1,53 @@
+/*
+ * 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.coremedia.iso.boxes;
+
+import com.googlecode.mp4parser.AbstractFullBox;
+
+import java.nio.ByteBuffer;
+
+/**
+ * Only used within the DataReferenceBox. Find more information there.
+ *
+ * @see com.coremedia.iso.boxes.DataReferenceBox
+ */
+public class DataEntryUrlBox extends AbstractFullBox {
+ public static final String TYPE = "url ";
+
+ public DataEntryUrlBox() {
+ super(TYPE);
+ }
+
+ @Override
+ public void _parseDetails(ByteBuffer content) {
+ parseVersionAndFlags(content);
+ }
+
+
+ @Override
+ protected void getContent(ByteBuffer byteBuffer) {
+ writeVersionAndFlags(byteBuffer);
+ }
+
+ protected long getContentSize() {
+ return 4;
+ }
+
+ public String toString() {
+ return "DataEntryUrlBox[]";
+ }
+}
diff --git a/android-aac-enc/src/com/coremedia/iso/boxes/DataEntryUrnBox.java b/android-aac-enc/src/com/coremedia/iso/boxes/DataEntryUrnBox.java
new file mode 100644
index 000000000..042a972d7
--- /dev/null
+++ b/android-aac-enc/src/com/coremedia/iso/boxes/DataEntryUrnBox.java
@@ -0,0 +1,69 @@
+/*
+ * 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.coremedia.iso.boxes;
+
+import com.coremedia.iso.IsoTypeReader;
+import com.coremedia.iso.Utf8;
+import com.googlecode.mp4parser.AbstractFullBox;
+
+import java.nio.ByteBuffer;
+
+/**
+ * Only used within the DataReferenceBox. Find more information there.
+ *
+ * @see com.coremedia.iso.boxes.DataReferenceBox
+ */
+public class DataEntryUrnBox extends AbstractFullBox {
+ private String name;
+ private String location;
+ public static final String TYPE = "urn ";
+
+ public DataEntryUrnBox() {
+ super(TYPE);
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public String getLocation() {
+ return location;
+ }
+
+ protected long getContentSize() {
+ return Utf8.utf8StringLengthInBytes(name) + 1 + Utf8.utf8StringLengthInBytes(location) + 1;
+ }
+
+ @Override
+ public void _parseDetails(ByteBuffer content) {
+ name = IsoTypeReader.readString(content);
+ location = IsoTypeReader.readString(content);
+
+ }
+
+ @Override
+ protected void getContent(ByteBuffer byteBuffer) {
+ byteBuffer.put(Utf8.convert(name));
+ byteBuffer.put((byte) 0);
+ byteBuffer.put(Utf8.convert(location));
+ byteBuffer.put((byte) 0);
+ }
+
+ public String toString() {
+ return "DataEntryUrlBox[name=" + getName() + ";location=" + getLocation() + "]";
+ }
+}
diff --git a/android-aac-enc/src/com/coremedia/iso/boxes/DataInformationBox.java b/android-aac-enc/src/com/coremedia/iso/boxes/DataInformationBox.java
new file mode 100644
index 000000000..7f058ebb2
--- /dev/null
+++ b/android-aac-enc/src/com/coremedia/iso/boxes/DataInformationBox.java
@@ -0,0 +1,36 @@
+/*
+ * 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.coremedia.iso.boxes;
+
+import com.googlecode.mp4parser.AbstractContainerBox;
+
+/**
+ *
+ * Box Type: 'dinf'
+ * Container: {@link com.coremedia.iso.boxes.MediaInformationBox} ('minf')
+ * Mandatory: Yes
+ * Quantity: Exactly one
+ * The data information box contains objects that declare the location of the media information in a track.
+ */
+public class DataInformationBox extends AbstractContainerBox {
+ public static final String TYPE = "dinf";
+
+ public DataInformationBox() {
+ super(TYPE);
+ }
+
+}
diff --git a/android-aac-enc/src/com/coremedia/iso/boxes/DataReferenceBox.java b/android-aac-enc/src/com/coremedia/iso/boxes/DataReferenceBox.java
new file mode 100644
index 000000000..8156d3f63
--- /dev/null
+++ b/android-aac-enc/src/com/coremedia/iso/boxes/DataReferenceBox.java
@@ -0,0 +1,65 @@
+/*
+ * 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.coremedia.iso.boxes;
+
+
+import com.coremedia.iso.IsoTypeWriter;
+import com.googlecode.mp4parser.FullContainerBox;
+
+import java.nio.ByteBuffer;
+
+/**
+ * The data reference object contains a table of data references (normally URLs) that declare the location(s) of
+ * the media data used within the presentation. The data reference index in the sample description ties entries in
+ * this table to the samples in the track. A track may be split over several sources in this way.
+ * If the flag is set indicating that the data is in the same file as this box, then no string (not even an empty one)
+ * shall be supplied in the entry field.
+ * The DataEntryBox within the DataReferenceBox shall be either a DataEntryUrnBox or a DataEntryUrlBox.
+ *
+ * @see com.coremedia.iso.boxes.DataEntryUrlBox
+ * @see com.coremedia.iso.boxes.DataEntryUrnBox
+ */
+public class DataReferenceBox extends FullContainerBox {
+
+ public static final String TYPE = "dref";
+
+ public DataReferenceBox() {
+ super(TYPE);
+
+ }
+
+ @Override
+ protected long getContentSize() {
+ return super.getContentSize() + 4;
+ }
+
+ @Override
+ public void _parseDetails(ByteBuffer content) {
+ parseVersionAndFlags(content);
+ content.get(new byte[4]); // basically a skip of 4 bytes signaling the number of child boxes
+ parseChildBoxes(content);
+ }
+
+
+ @Override
+ protected void getContent(ByteBuffer byteBuffer) {
+ writeVersionAndFlags(byteBuffer);
+ IsoTypeWriter.writeUInt32(byteBuffer, getBoxes().size());
+ writeChildBoxes(byteBuffer);
+ }
+
+}
diff --git a/android-aac-enc/src/com/coremedia/iso/boxes/DescriptionBox.java b/android-aac-enc/src/com/coremedia/iso/boxes/DescriptionBox.java
new file mode 100644
index 000000000..83520512a
--- /dev/null
+++ b/android-aac-enc/src/com/coremedia/iso/boxes/DescriptionBox.java
@@ -0,0 +1,77 @@
+/*
+ * 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.coremedia.iso.boxes;
+
+import com.coremedia.iso.IsoTypeReader;
+import com.coremedia.iso.IsoTypeWriter;
+import com.coremedia.iso.Utf8;
+import com.googlecode.mp4parser.AbstractFullBox;
+
+import java.nio.ByteBuffer;
+
+/**
+ * Gives a language dependent description of the media contained in the ISO file.
+ */
+public class DescriptionBox extends AbstractFullBox {
+ public static final String TYPE = "dscp";
+
+ private String language;
+ private String description;
+
+ public DescriptionBox() {
+ super(TYPE);
+ }
+
+ public String getLanguage() {
+ return language;
+ }
+
+ public String getDescription() {
+ return description;
+ }
+
+ protected long getContentSize() {
+ return 7 + Utf8.utf8StringLengthInBytes(description);
+ }
+
+ @Override
+ public void _parseDetails(ByteBuffer content) {
+ parseVersionAndFlags(content);
+ language = IsoTypeReader.readIso639(content);
+ description = IsoTypeReader.readString(content);
+ }
+
+ @Override
+ protected void getContent(ByteBuffer byteBuffer) {
+ writeVersionAndFlags(byteBuffer);
+ IsoTypeWriter.writeIso639(byteBuffer, language);
+ byteBuffer.put(Utf8.convert(description));
+ byteBuffer.put((byte) 0);
+ }
+
+ public String toString() {
+ return "DescriptionBox[language=" + getLanguage() + ";description=" + getDescription() + "]";
+ }
+
+ public void setLanguage(String language) {
+ this.language = language;
+ }
+
+ public void setDescription(String description) {
+ this.description = description;
+ }
+}
diff --git a/android-aac-enc/src/com/coremedia/iso/boxes/EditBox.java b/android-aac-enc/src/com/coremedia/iso/boxes/EditBox.java
new file mode 100644
index 000000000..db3bc2549
--- /dev/null
+++ b/android-aac-enc/src/com/coremedia/iso/boxes/EditBox.java
@@ -0,0 +1,34 @@
+/*
+ * 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.coremedia.iso.boxes;
+
+import com.googlecode.mp4parser.AbstractContainerBox;
+
+/**
+ * An Edit Box maps the presentation time-line to the media time-line as it is stored in the file.
+ * The Edit Box is a container fpr the edit lists. Defined in ISO/IEC 14496-12.
+ *
+ * @see EditListBox
+ */
+public class EditBox extends AbstractContainerBox {
+ public static final String TYPE = "edts";
+
+ public EditBox() {
+ super(TYPE);
+ }
+
+}
diff --git a/android-aac-enc/src/com/coremedia/iso/boxes/EditListBox.java b/android-aac-enc/src/com/coremedia/iso/boxes/EditListBox.java
new file mode 100644
index 000000000..231f8beea
--- /dev/null
+++ b/android-aac-enc/src/com/coremedia/iso/boxes/EditListBox.java
@@ -0,0 +1,248 @@
+/*
+ * 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.coremedia.iso.boxes;
+
+
+import com.coremedia.iso.IsoTypeReader;
+import com.coremedia.iso.IsoTypeWriter;
+import com.googlecode.mp4parser.AbstractFullBox;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.util.LinkedList;
+import java.util.List;
+
+import static com.googlecode.mp4parser.util.CastUtils.l2i;
+
+/**
+ *
+ * Box Type : 'elst'
+ * Container: {@link EditBox}('edts')
+ * Mandatory: No
+ * Quantity : Zero or one
+ * This box contains an explicit timeline map. Each entry defines part of the track time-line: by mapping part of
+ * the media time-line, or by indicating 'empty' time, or by defining a 'dwell', where a single time-point in the
+ * media is held for a period.
+ * Note that edits are not restricted to fall on sample times. This means that when entering an edit, it can be
+ * necessary to (a) back up to a sync point, and pre-roll from there and then (b) be careful about the duration of
+ * the first sample - it might have been truncated if the edit enters it during its normal duration. If this is audio,
+ * that frame might need to be decoded, and then the final slicing done. Likewise, the duration of the last sample
+ * in an edit might need slicing.
+ * Starting offsets for tracks (streams) are represented by an initial empty edit. For example, to play a track from
+ * its start for 30 seconds, but at 10 seconds into the presentation, we have the following edit list:
+ *
+ * Entry-count = 2
+ * Segment-duration = 10 seconds
+ * Media-Time = -1
+ * Media-Rate = 1
+ * Segment-duration = 30 seconds (could be the length of the whole track)
+ * Media-Time = 0 seconds
+ * Media-Rate = 1
+ */
+public class EditListBox extends AbstractFullBox {
+ private List entries = new LinkedList();
+ public static final String TYPE = "elst";
+
+ public EditListBox() {
+ super(TYPE);
+ }
+
+
+ public List getEntries() {
+ return entries;
+ }
+
+ public void setEntries(List entries) {
+ this.entries = entries;
+ }
+
+ protected long getContentSize() {
+ long contentSize = 8;
+ if (getVersion() == 1) {
+ contentSize += entries.size() * 20;
+ } else {
+ contentSize += entries.size() * 12;
+ }
+
+ return contentSize;
+ }
+
+ @Override
+ public void _parseDetails(ByteBuffer content) {
+ parseVersionAndFlags(content);
+ int entryCount = l2i(IsoTypeReader.readUInt32(content));
+ entries = new LinkedList();
+ for (int i = 0; i < entryCount; i++) {
+ entries.add(new Entry(this, content));
+
+ }
+ }
+
+ @Override
+ protected void getContent(ByteBuffer byteBuffer) {
+ writeVersionAndFlags(byteBuffer);
+ IsoTypeWriter.writeUInt32(byteBuffer, entries.size());
+ for (Entry entry : entries) {
+ entry.getContent(byteBuffer);
+ }
+ }
+
+ @Override
+ public String toString() {
+ return "EditListBox{" +
+ "entries=" + entries +
+ '}';
+ }
+
+ public static class Entry {
+ private long segmentDuration;
+ private long mediaTime;
+ private double mediaRate;
+ EditListBox editListBox;
+
+ /**
+ * Creates a new Entry
with all values set.
+ *
+ * @param segmentDuration duration in movie timescale
+ * @param mediaTime starting time
+ * @param mediaRate relative play rate
+ */
+ public Entry(EditListBox editListBox, long segmentDuration, long mediaTime, double mediaRate) {
+ this.segmentDuration = segmentDuration;
+ this.mediaTime = mediaTime;
+ this.mediaRate = mediaRate;
+ this.editListBox = editListBox;
+ }
+
+ public Entry(EditListBox editListBox, ByteBuffer bb) {
+ if (editListBox.getVersion() == 1) {
+ segmentDuration = IsoTypeReader.readUInt64(bb);
+ mediaTime = IsoTypeReader.readUInt64(bb);
+ mediaRate = IsoTypeReader.readFixedPoint1616(bb);
+ } else {
+ segmentDuration = IsoTypeReader.readUInt32(bb);
+ mediaTime = IsoTypeReader.readUInt32(bb);
+ mediaRate = IsoTypeReader.readFixedPoint1616(bb);
+ }
+ this.editListBox = editListBox;
+ }
+
+ /**
+ * The segment duration is an integer that specifies the duration
+ * of this edit segment in units of the timescale in the Movie
+ * Header Box
+ *
+ * @return segment duration in movie timescale
+ */
+ public long getSegmentDuration() {
+ return segmentDuration;
+ }
+
+ /**
+ * The segment duration is an integer that specifies the duration
+ * of this edit segment in units of the timescale in the Movie
+ * Header Box
+ *
+ * @param segmentDuration new segment duration in movie timescale
+ */
+ public void setSegmentDuration(long segmentDuration) {
+ this.segmentDuration = segmentDuration;
+ }
+
+ /**
+ * The media time is an integer containing the starting time
+ * within the media of a specific edit segment(in media time
+ * scale units, in composition time)
+ *
+ * @return starting time
+ */
+ public long getMediaTime() {
+ return mediaTime;
+ }
+
+ /**
+ * The media time is an integer containing the starting time
+ * within the media of a specific edit segment(in media time
+ * scale units, in composition time)
+ *
+ * @param mediaTime starting time
+ */
+ public void setMediaTime(long mediaTime) {
+ this.mediaTime = mediaTime;
+ }
+
+ /**
+ * The media rate specifies the relative rate at which to play the
+ * media corresponding to a specific edit segment.
+ *
+ * @return relative play rate
+ */
+ public double getMediaRate() {
+ return mediaRate;
+ }
+
+ /**
+ * The media rate specifies the relative rate at which to play the
+ * media corresponding to a specific edit segment.
+ *
+ * @param mediaRate new relative play rate
+ */
+ public void setMediaRate(double mediaRate) {
+ this.mediaRate = mediaRate;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+
+ Entry entry = (Entry) o;
+
+ if (mediaTime != entry.mediaTime) return false;
+ if (segmentDuration != entry.segmentDuration) return false;
+
+ return true;
+ }
+
+ @Override
+ public int hashCode() {
+ int result = (int) (segmentDuration ^ (segmentDuration >>> 32));
+ result = 31 * result + (int) (mediaTime ^ (mediaTime >>> 32));
+ return result;
+ }
+
+ public void getContent(ByteBuffer bb) {
+ if (editListBox.getVersion() == 1) {
+ IsoTypeWriter.writeUInt64(bb, segmentDuration);
+ IsoTypeWriter.writeUInt64(bb, mediaTime);
+ } else {
+ IsoTypeWriter.writeUInt32(bb, l2i(segmentDuration));
+ bb.putInt(l2i(mediaTime));
+ }
+ IsoTypeWriter.writeFixedPont1616(bb, mediaRate);
+ }
+
+ @Override
+ public String toString() {
+ return "Entry{" +
+ "segmentDuration=" + segmentDuration +
+ ", mediaTime=" + mediaTime +
+ ", mediaRate=" + mediaRate +
+ '}';
+ }
+ }
+}
diff --git a/android-aac-enc/src/com/coremedia/iso/boxes/FileTypeBox.java b/android-aac-enc/src/com/coremedia/iso/boxes/FileTypeBox.java
new file mode 100644
index 000000000..e6eed202b
--- /dev/null
+++ b/android-aac-enc/src/com/coremedia/iso/boxes/FileTypeBox.java
@@ -0,0 +1,144 @@
+/*
+ * 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.coremedia.iso.boxes;
+
+import com.coremedia.iso.IsoFile;
+import com.coremedia.iso.IsoTypeReader;
+import com.coremedia.iso.IsoTypeWriter;
+import com.googlecode.mp4parser.AbstractBox;
+import com.googlecode.mp4parser.annotations.DoNotParseDetail;
+
+import java.nio.ByteBuffer;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.LinkedList;
+import java.util.List;
+
+/**
+ * This box identifies the specifications to which this file complies.
+ * Each brand is a printable four-character code, registered with ISO, that
+ * identifies a precise specification.
+ */
+public class FileTypeBox extends AbstractBox {
+ public static final String TYPE = "ftyp";
+
+ private String majorBrand;
+ private long minorVersion;
+ private List compatibleBrands = Collections.emptyList();
+
+ public FileTypeBox() {
+ super(TYPE);
+ }
+
+ public FileTypeBox(String majorBrand, long minorVersion, List compatibleBrands) {
+ super(TYPE);
+ this.majorBrand = majorBrand;
+ this.minorVersion = minorVersion;
+ this.compatibleBrands = compatibleBrands;
+ }
+
+ protected long getContentSize() {
+ return 8 + compatibleBrands.size() * 4;
+
+ }
+
+ @Override
+ public void _parseDetails(ByteBuffer content) {
+ majorBrand = IsoTypeReader.read4cc(content);
+ minorVersion = IsoTypeReader.readUInt32(content);
+ int compatibleBrandsCount = content.remaining() / 4;
+ compatibleBrands = new LinkedList();
+ for (int i = 0; i < compatibleBrandsCount; i++) {
+ compatibleBrands.add(IsoTypeReader.read4cc(content));
+ }
+ }
+
+ @Override
+ protected void getContent(ByteBuffer byteBuffer) {
+ byteBuffer.put(IsoFile.fourCCtoBytes(majorBrand));
+ IsoTypeWriter.writeUInt32(byteBuffer, minorVersion);
+ for (String compatibleBrand : compatibleBrands) {
+ byteBuffer.put(IsoFile.fourCCtoBytes(compatibleBrand));
+ }
+
+ }
+
+ /**
+ * Gets the brand identifier.
+ *
+ * @return the brand identifier
+ */
+ public String getMajorBrand() {
+ return majorBrand;
+ }
+
+ /**
+ * Sets the major brand of the file used to determine an appropriate reader.
+ *
+ * @param majorBrand the new major brand
+ */
+ public void setMajorBrand(String majorBrand) {
+ this.majorBrand = majorBrand;
+ }
+
+ /**
+ * Sets the "informative integer for the minor version of the major brand".
+ *
+ * @param minorVersion the version number of the major brand
+ */
+ public void setMinorVersion(int minorVersion) {
+ this.minorVersion = minorVersion;
+ }
+
+ /**
+ * Gets an informative integer for the minor version of the major brand.
+ *
+ * @return an informative integer
+ * @see FileTypeBox#getMajorBrand()
+ */
+ public long getMinorVersion() {
+ return minorVersion;
+ }
+
+ /**
+ * Gets an array of 4-cc brands.
+ *
+ * @return the compatible brands
+ */
+ public List getCompatibleBrands() {
+ return compatibleBrands;
+ }
+
+ public void setCompatibleBrands(List compatibleBrands) {
+ this.compatibleBrands = compatibleBrands;
+ }
+
+ @DoNotParseDetail
+ public String toString() {
+ StringBuilder result = new StringBuilder();
+ result.append("FileTypeBox[");
+ result.append("majorBrand=").append(getMajorBrand());
+ result.append(";");
+ result.append("minorVersion=").append(getMinorVersion());
+ for (String compatibleBrand : compatibleBrands) {
+ result.append(";");
+ result.append("compatibleBrand=").append(compatibleBrand);
+ }
+ result.append("]");
+ return result.toString();
+ }
+}
diff --git a/android-aac-enc/src/com/coremedia/iso/boxes/FreeBox.java b/android-aac-enc/src/com/coremedia/iso/boxes/FreeBox.java
new file mode 100644
index 000000000..6ce4e8af8
--- /dev/null
+++ b/android-aac-enc/src/com/coremedia/iso/boxes/FreeBox.java
@@ -0,0 +1,64 @@
+/*
+ * 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.coremedia.iso.boxes;
+
+
+import com.googlecode.mp4parser.AbstractBox;
+
+import java.nio.ByteBuffer;
+
+/**
+ * A free box. Just a placeholder to enable editing without rewriting the whole file.
+ */
+public class FreeBox extends AbstractBox {
+ public static final String TYPE = "free";
+ ByteBuffer data;
+
+ public FreeBox() {
+ super(TYPE);
+ }
+
+ public FreeBox(int size) {
+ super(TYPE);
+ this.data = ByteBuffer.allocate(size);
+ }
+
+ @Override
+ protected long getContentSize() {
+ return data.limit();
+ }
+
+ @Override
+ public void _parseDetails(ByteBuffer content) {
+ data = content;
+ data.position(data.position() + data.remaining());
+ }
+
+ @Override
+ protected void getContent(ByteBuffer byteBuffer) {
+ data.rewind();
+ byteBuffer.put(data);
+ }
+
+ public ByteBuffer getData() {
+ return data;
+ }
+
+ public void setData(ByteBuffer data) {
+ this.data = data;
+ }
+}
\ No newline at end of file
diff --git a/android-aac-enc/src/com/coremedia/iso/boxes/FreeSpaceBox.java b/android-aac-enc/src/com/coremedia/iso/boxes/FreeSpaceBox.java
new file mode 100644
index 000000000..ed42bf96c
--- /dev/null
+++ b/android-aac-enc/src/com/coremedia/iso/boxes/FreeSpaceBox.java
@@ -0,0 +1,63 @@
+/*
+ * 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.coremedia.iso.boxes;
+
+import com.googlecode.mp4parser.AbstractBox;
+
+import java.nio.ByteBuffer;
+
+/**
+ * The contents of a free-space box are irrelevant and may be ignored, or the object deleted, without affecting the
+ * presentation. Care should be excercized when deleting the object, as this may invalidate the offsets used in the
+ * sample table.
+ */
+public class FreeSpaceBox extends AbstractBox {
+ public static final String TYPE = "skip";
+
+ byte[] data;
+
+ protected long getContentSize() {
+ return data.length;
+ }
+
+ public FreeSpaceBox() {
+ super(TYPE);
+ }
+
+ public void setData(byte[] data) {
+ this.data = data;
+ }
+
+ public byte[] getData() {
+ return data;
+ }
+
+ @Override
+ public void _parseDetails(ByteBuffer content) {
+ data = new byte[content.remaining()];
+ content.get(data);
+ }
+
+ @Override
+ protected void getContent(ByteBuffer byteBuffer) {
+ byteBuffer.put(data);
+ }
+
+ public String toString() {
+ return "FreeSpaceBox[size=" + data.length + ";type=" + getType() + "]";
+ }
+}
diff --git a/android-aac-enc/src/com/coremedia/iso/boxes/FullBox.java b/android-aac-enc/src/com/coremedia/iso/boxes/FullBox.java
new file mode 100644
index 000000000..1515d76db
--- /dev/null
+++ b/android-aac-enc/src/com/coremedia/iso/boxes/FullBox.java
@@ -0,0 +1,17 @@
+package com.coremedia.iso.boxes;
+
+import com.coremedia.iso.boxes.Box;
+
+/**
+ * The FullBox
contains all getters and setters specific
+ * to a so-called full box according to the ISO/IEC 14496/12 specification.
+ */
+public interface FullBox extends Box {
+ int getVersion();
+
+ void setVersion(int version);
+
+ int getFlags();
+
+ void setFlags(int flags);
+}
diff --git a/android-aac-enc/src/com/coremedia/iso/boxes/GenericMediaHeaderBoxImpl.java b/android-aac-enc/src/com/coremedia/iso/boxes/GenericMediaHeaderBoxImpl.java
new file mode 100644
index 000000000..f1f73a525
--- /dev/null
+++ b/android-aac-enc/src/com/coremedia/iso/boxes/GenericMediaHeaderBoxImpl.java
@@ -0,0 +1,39 @@
+package com.coremedia.iso.boxes;
+
+import java.nio.ByteBuffer;
+
+public class GenericMediaHeaderBoxImpl extends AbstractMediaHeaderBox {
+
+ ByteBuffer data;
+
+ @Override
+ protected long getContentSize() {
+ return 4 + data.limit();
+ }
+
+ @Override
+ public void _parseDetails(ByteBuffer content) {
+ parseVersionAndFlags(content);
+ this.data = content.slice();
+ content.position(content.remaining() + content.position());
+
+ }
+
+ @Override
+ protected void getContent(ByteBuffer byteBuffer) {
+ writeVersionAndFlags(byteBuffer);
+ byteBuffer.put((ByteBuffer) data.rewind());
+ }
+
+ public GenericMediaHeaderBoxImpl() {
+ super("gmhd");
+ }
+
+ public ByteBuffer getData() {
+ return data;
+ }
+
+ public void setData(ByteBuffer data) {
+ this.data = data;
+ }
+}
diff --git a/android-aac-enc/src/com/coremedia/iso/boxes/GenreBox.java b/android-aac-enc/src/com/coremedia/iso/boxes/GenreBox.java
new file mode 100644
index 000000000..e2d1faf87
--- /dev/null
+++ b/android-aac-enc/src/com/coremedia/iso/boxes/GenreBox.java
@@ -0,0 +1,80 @@
+/*
+ * 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.coremedia.iso.boxes;
+
+import com.coremedia.iso.IsoTypeReader;
+import com.coremedia.iso.IsoTypeWriter;
+import com.coremedia.iso.Utf8;
+import com.googlecode.mp4parser.AbstractFullBox;
+
+import java.nio.ByteBuffer;
+
+/**
+ * Containing genre information and contained in the UserDataBox
.
+ *
+ * @see com.coremedia.iso.boxes.UserDataBox
+ */
+public class GenreBox extends AbstractFullBox {
+ public static final String TYPE = "gnre";
+
+ private String language;
+ private String genre;
+
+ public GenreBox() {
+ super(TYPE);
+ }
+
+ public String getLanguage() {
+ return language;
+ }
+
+ public String getGenre() {
+ return genre;
+ }
+
+ public void setLanguage(String language) {
+ this.language = language;
+ }
+
+ public void setGenre(String genre) {
+ this.genre = genre;
+ }
+
+ protected long getContentSize() {
+ return 7 + Utf8.utf8StringLengthInBytes(genre);
+ }
+
+ @Override
+ public void _parseDetails(ByteBuffer content) {
+ parseVersionAndFlags(content);
+ language = IsoTypeReader.readIso639(content);
+ genre = IsoTypeReader.readString(content);
+ }
+
+ @Override
+ protected void getContent(ByteBuffer byteBuffer) {
+ writeVersionAndFlags(byteBuffer);
+ IsoTypeWriter.writeIso639(byteBuffer, language);
+ byteBuffer.put(Utf8.convert(genre));
+ byteBuffer.put((byte) 0);
+ }
+
+ public String toString() {
+ return "GenreBox[language=" + getLanguage() + ";genre=" + getGenre() + "]";
+ }
+
+}
diff --git a/android-aac-enc/src/com/coremedia/iso/boxes/HandlerBox.java b/android-aac-enc/src/com/coremedia/iso/boxes/HandlerBox.java
new file mode 100644
index 000000000..01dcacaa9
--- /dev/null
+++ b/android-aac-enc/src/com/coremedia/iso/boxes/HandlerBox.java
@@ -0,0 +1,151 @@
+/*
+ * 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.coremedia.iso.boxes;
+
+
+import com.coremedia.iso.IsoFile;
+import com.coremedia.iso.IsoTypeReader;
+import com.coremedia.iso.IsoTypeWriter;
+import com.coremedia.iso.Utf8;
+import com.googlecode.mp4parser.AbstractFullBox;
+
+import java.nio.ByteBuffer;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * This box within a Media Box declares the process by which the media-data in the track is presented,
+ * and thus, the nature of the media in a track.
+ * This Box when present in a Meta Box, declares the structure or format of the 'meta' box contents.
+ * See ISO/IEC 14496-12 for details.
+ *
+ * @see MetaBox
+ * @see MediaBox
+ */
+public class HandlerBox extends AbstractFullBox {
+ public static final String TYPE = "hdlr";
+ public static final Map readableTypes;
+
+ static {
+ HashMap hm = new HashMap();
+ hm.put("odsm", "ObjectDescriptorStream - defined in ISO/IEC JTC1/SC29/WG11 - CODING OF MOVING PICTURES AND AUDIO");
+ hm.put("crsm", "ClockReferenceStream - defined in ISO/IEC JTC1/SC29/WG11 - CODING OF MOVING PICTURES AND AUDIO");
+ hm.put("sdsm", "SceneDescriptionStream - defined in ISO/IEC JTC1/SC29/WG11 - CODING OF MOVING PICTURES AND AUDIO");
+ hm.put("m7sm", "MPEG7Stream - defined in ISO/IEC JTC1/SC29/WG11 - CODING OF MOVING PICTURES AND AUDIO");
+ hm.put("ocsm", "ObjectContentInfoStream - defined in ISO/IEC JTC1/SC29/WG11 - CODING OF MOVING PICTURES AND AUDIO");
+ hm.put("ipsm", "IPMP Stream - defined in ISO/IEC JTC1/SC29/WG11 - CODING OF MOVING PICTURES AND AUDIO");
+ hm.put("mjsm", "MPEG-J Stream - defined in ISO/IEC JTC1/SC29/WG11 - CODING OF MOVING PICTURES AND AUDIO");
+ hm.put("mdir", "Apple Meta Data iTunes Reader");
+ hm.put("mp7b", "MPEG-7 binary XML");
+ hm.put("mp7t", "MPEG-7 XML");
+ hm.put("vide", "Video Track");
+ hm.put("soun", "Sound Track");
+ hm.put("hint", "Hint Track");
+ hm.put("appl", "Apple specific");
+ hm.put("meta", "Timed Metadata track - defined in ISO/IEC JTC1/SC29/WG11 - CODING OF MOVING PICTURES AND AUDIO");
+
+ readableTypes = Collections.unmodifiableMap(hm);
+
+ }
+
+ private String handlerType;
+ private String name = null;
+ private long a, b, c;
+ private boolean zeroTerm = true;
+
+ private long shouldBeZeroButAppleWritesHereSomeValue;
+
+ public HandlerBox() {
+ super(TYPE);
+ }
+
+ public String getHandlerType() {
+ return handlerType;
+ }
+
+ /**
+ * You are required to add a '\0' string termination by yourself.
+ *
+ * @param name the new human readable name
+ */
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public void setHandlerType(String handlerType) {
+ this.handlerType = handlerType;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public String getHumanReadableTrackType() {
+ return readableTypes.get(handlerType) != null ? readableTypes.get(handlerType) : "Unknown Handler Type";
+ }
+
+ protected long getContentSize() {
+ if (zeroTerm) {
+ return 25 + Utf8.utf8StringLengthInBytes(name);
+ } else {
+ return 24 + Utf8.utf8StringLengthInBytes(name);
+ }
+
+ }
+
+ @Override
+ public void _parseDetails(ByteBuffer content) {
+ parseVersionAndFlags(content);
+ shouldBeZeroButAppleWritesHereSomeValue = IsoTypeReader.readUInt32(content);
+ handlerType = IsoTypeReader.read4cc(content);
+ a = IsoTypeReader.readUInt32(content);
+ b = IsoTypeReader.readUInt32(content);
+ c = IsoTypeReader.readUInt32(content);
+ if (content.remaining() > 0) {
+ name = IsoTypeReader.readString(content, content.remaining());
+ if (name.endsWith("\0")) {
+ name = name.substring(0, name.length() - 1);
+ zeroTerm = true;
+ } else {
+ zeroTerm = false;
+ }
+ } else {
+ zeroTerm = false; //No string at all, not even zero term char
+ }
+ }
+
+ @Override
+ protected void getContent(ByteBuffer byteBuffer) {
+ writeVersionAndFlags(byteBuffer);
+ IsoTypeWriter.writeUInt32(byteBuffer, shouldBeZeroButAppleWritesHereSomeValue);
+ byteBuffer.put(IsoFile.fourCCtoBytes(handlerType));
+ IsoTypeWriter.writeUInt32(byteBuffer, a);
+ IsoTypeWriter.writeUInt32(byteBuffer, b);
+ IsoTypeWriter.writeUInt32(byteBuffer, c);
+ if (name != null) {
+ byteBuffer.put(Utf8.convert(name));
+ }
+ if (zeroTerm) {
+ byteBuffer.put((byte) 0);
+ }
+ }
+
+ public String toString() {
+ return "HandlerBox[handlerType=" + getHandlerType() + ";name=" + getName() + "]";
+ }
+}
diff --git a/android-aac-enc/src/com/coremedia/iso/boxes/HintMediaHeaderBox.java b/android-aac-enc/src/com/coremedia/iso/boxes/HintMediaHeaderBox.java
new file mode 100644
index 000000000..347773806
--- /dev/null
+++ b/android-aac-enc/src/com/coremedia/iso/boxes/HintMediaHeaderBox.java
@@ -0,0 +1,91 @@
+/*
+ * 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.coremedia.iso.boxes;
+
+import com.coremedia.iso.IsoTypeReader;
+import com.coremedia.iso.IsoTypeWriter;
+
+import java.nio.ByteBuffer;
+
+/**
+ * The hint media header contains general information, independent of the protocaol, for hint tracks. Resides
+ * in Media Information Box.
+ *
+ * @see com.coremedia.iso.boxes.MediaInformationBox
+ */
+public class HintMediaHeaderBox extends AbstractMediaHeaderBox {
+ private int maxPduSize;
+ private int avgPduSize;
+ private long maxBitrate;
+ private long avgBitrate;
+ public static final String TYPE = "hmhd";
+
+ public HintMediaHeaderBox() {
+ super(TYPE);
+ }
+
+ public int getMaxPduSize() {
+ return maxPduSize;
+ }
+
+ public int getAvgPduSize() {
+ return avgPduSize;
+ }
+
+ public long getMaxBitrate() {
+ return maxBitrate;
+ }
+
+ public long getAvgBitrate() {
+ return avgBitrate;
+ }
+
+ protected long getContentSize() {
+ return 20;
+ }
+
+ @Override
+ public void _parseDetails(ByteBuffer content) {
+ parseVersionAndFlags(content);
+ maxPduSize = IsoTypeReader.readUInt16(content);
+ avgPduSize = IsoTypeReader.readUInt16(content);
+ maxBitrate = IsoTypeReader.readUInt32(content);
+ avgBitrate = IsoTypeReader.readUInt32(content);
+ IsoTypeReader.readUInt32(content); // reserved!
+
+ }
+
+ @Override
+ protected void getContent(ByteBuffer byteBuffer) {
+ writeVersionAndFlags(byteBuffer);
+ IsoTypeWriter.writeUInt16(byteBuffer, maxPduSize);
+ IsoTypeWriter.writeUInt16(byteBuffer, avgPduSize);
+ IsoTypeWriter.writeUInt32(byteBuffer, maxBitrate);
+ IsoTypeWriter.writeUInt32(byteBuffer, avgBitrate);
+ IsoTypeWriter.writeUInt32(byteBuffer, 0);
+ }
+
+ @Override
+ public String toString() {
+ return "HintMediaHeaderBox{" +
+ "maxPduSize=" + maxPduSize +
+ ", avgPduSize=" + avgPduSize +
+ ", maxBitrate=" + maxBitrate +
+ ", avgBitrate=" + avgBitrate +
+ '}';
+ }
+}
diff --git a/android-aac-enc/src/com/coremedia/iso/boxes/ItemDataBox.java b/android-aac-enc/src/com/coremedia/iso/boxes/ItemDataBox.java
new file mode 100644
index 000000000..46097cc12
--- /dev/null
+++ b/android-aac-enc/src/com/coremedia/iso/boxes/ItemDataBox.java
@@ -0,0 +1,43 @@
+package com.coremedia.iso.boxes;
+
+import com.googlecode.mp4parser.AbstractBox;
+
+import java.nio.ByteBuffer;
+
+/**
+ *
+ */
+public class ItemDataBox extends AbstractBox {
+ ByteBuffer data = ByteBuffer.allocate(0);
+ public static final String TYPE = "idat";
+
+
+ public ItemDataBox() {
+ super(TYPE);
+ }
+
+ public ByteBuffer getData() {
+ return data;
+ }
+
+ public void setData(ByteBuffer data) {
+ this.data = data;
+ }
+
+ @Override
+ protected long getContentSize() {
+ return data.limit();
+ }
+
+
+ @Override
+ public void _parseDetails(ByteBuffer content) {
+ data = content.slice();
+ content.position(content.position() + content.remaining());
+ }
+
+ @Override
+ protected void getContent(ByteBuffer byteBuffer) {
+ byteBuffer.put(data);
+ }
+}
diff --git a/android-aac-enc/src/com/coremedia/iso/boxes/ItemLocationBox.java b/android-aac-enc/src/com/coremedia/iso/boxes/ItemLocationBox.java
new file mode 100644
index 000000000..6dcee6fa1
--- /dev/null
+++ b/android-aac-enc/src/com/coremedia/iso/boxes/ItemLocationBox.java
@@ -0,0 +1,360 @@
+/*
+ * 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.coremedia.iso.boxes;
+
+
+import com.coremedia.iso.IsoTypeReader;
+import com.coremedia.iso.IsoTypeReaderVariable;
+import com.coremedia.iso.IsoTypeWriter;
+import com.coremedia.iso.IsoTypeWriterVariable;
+import com.googlecode.mp4parser.AbstractFullBox;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.util.LinkedList;
+import java.util.List;
+
+/**
+ * aligned(8) class ItemLocationBox extends FullBox(‘iloc’, version, 0) {
+ * unsigned int(4) offset_size;
+ * unsigned int(4) length_size;
+ * unsigned int(4) base_offset_size;
+ * if (version == 1)
+ * unsigned int(4) index_size;
+ * else
+ * unsigned int(4) reserved;
+ * unsigned int(16) item_count;
+ * for (i=0; i 0)) {
+ * unsigned int(index_size*8) extent_index;
+ * }
+ * unsigned int(offset_size*8) extent_offset;
+ * unsigned int(length_size*8) extent_length;
+ * }
+ * }
+ * }
+ */
+public class ItemLocationBox extends AbstractFullBox {
+ public int offsetSize = 8;
+ public int lengthSize = 8;
+ public int baseOffsetSize = 8;
+ public int indexSize = 0;
+ public List- items = new LinkedList
- ();
+
+ public static final String TYPE = "iloc";
+
+ public ItemLocationBox() {
+ super(TYPE);
+ }
+
+ @Override
+ protected long getContentSize() {
+ long size = 8;
+ for (Item item : items) {
+ size += item.getSize();
+ }
+ return size;
+ }
+
+
+ @Override
+ protected void getContent(ByteBuffer byteBuffer) {
+ writeVersionAndFlags(byteBuffer);
+ IsoTypeWriter.writeUInt8(byteBuffer, ((offsetSize << 4) | lengthSize));
+ if (getVersion() == 1) {
+ IsoTypeWriter.writeUInt8(byteBuffer, (baseOffsetSize << 4 | indexSize));
+ } else {
+ IsoTypeWriter.writeUInt8(byteBuffer, (baseOffsetSize << 4));
+ }
+ IsoTypeWriter.writeUInt16(byteBuffer, items.size());
+ for (Item item : items) {
+ item.getContent(byteBuffer);
+ }
+ }
+
+ @Override
+ public void _parseDetails(ByteBuffer content) {
+ parseVersionAndFlags(content);
+ int tmp = IsoTypeReader.readUInt8(content);
+ offsetSize = tmp >>> 4;
+ lengthSize = tmp & 0xf;
+ tmp = IsoTypeReader.readUInt8(content);
+ baseOffsetSize = tmp >>> 4;
+
+ if (getVersion() == 1) {
+ indexSize = tmp & 0xf;
+ }
+ int itemCount = IsoTypeReader.readUInt16(content);
+ for (int i = 0; i < itemCount; i++) {
+ items.add(new Item(content));
+ }
+ }
+
+
+ public int getOffsetSize() {
+ return offsetSize;
+ }
+
+ public void setOffsetSize(int offsetSize) {
+ this.offsetSize = offsetSize;
+ }
+
+ public int getLengthSize() {
+ return lengthSize;
+ }
+
+ public void setLengthSize(int lengthSize) {
+ this.lengthSize = lengthSize;
+ }
+
+ public int getBaseOffsetSize() {
+ return baseOffsetSize;
+ }
+
+ public void setBaseOffsetSize(int baseOffsetSize) {
+ this.baseOffsetSize = baseOffsetSize;
+ }
+
+ public int getIndexSize() {
+ return indexSize;
+ }
+
+ public void setIndexSize(int indexSize) {
+ this.indexSize = indexSize;
+ }
+
+ public List
- getItems() {
+ return items;
+ }
+
+ public void setItems(List
- items) {
+ this.items = items;
+ }
+
+
+ public Item createItem(int itemId, int constructionMethod, int dataReferenceIndex, long baseOffset, List extents) {
+ return new Item(itemId, constructionMethod, dataReferenceIndex, baseOffset, extents);
+ }
+
+ Item createItem(ByteBuffer bb) {
+ return new Item(bb);
+ }
+
+ public class Item {
+ public int itemId;
+ public int constructionMethod;
+ public int dataReferenceIndex;
+ public long baseOffset;
+ public List extents = new LinkedList();
+
+ public Item(ByteBuffer in) {
+ itemId = IsoTypeReader.readUInt16(in);
+
+ if (getVersion() == 1) {
+ int tmp = IsoTypeReader.readUInt16(in);
+ constructionMethod = tmp & 0xf;
+ }
+
+ dataReferenceIndex = IsoTypeReader.readUInt16(in);
+ if (baseOffsetSize > 0) {
+ baseOffset = IsoTypeReaderVariable.read(in, baseOffsetSize);
+ } else {
+ baseOffset = 0;
+ }
+ int extentCount = IsoTypeReader.readUInt16(in);
+
+
+ for (int i = 0; i < extentCount; i++) {
+ extents.add(new Extent(in));
+ }
+ }
+
+ public Item(int itemId, int constructionMethod, int dataReferenceIndex, long baseOffset, List extents) {
+ this.itemId = itemId;
+ this.constructionMethod = constructionMethod;
+ this.dataReferenceIndex = dataReferenceIndex;
+ this.baseOffset = baseOffset;
+ this.extents = extents;
+ }
+
+ public int getSize() {
+ int size = 2;
+
+ if (getVersion() == 1) {
+ size += 2;
+ }
+
+ size += 2;
+ size += baseOffsetSize;
+ size += 2;
+
+
+ for (Extent extent : extents) {
+ size += extent.getSize();
+ }
+ return size;
+ }
+
+ public void setBaseOffset(long baseOffset) {
+ this.baseOffset = baseOffset;
+ }
+
+ public void getContent(ByteBuffer bb) {
+ IsoTypeWriter.writeUInt16(bb, itemId);
+
+ if (getVersion() == 1) {
+ IsoTypeWriter.writeUInt16(bb, constructionMethod);
+ }
+
+
+ IsoTypeWriter.writeUInt16(bb, dataReferenceIndex);
+ if (baseOffsetSize > 0) {
+ IsoTypeWriterVariable.write(baseOffset, bb, baseOffsetSize);
+ }
+ IsoTypeWriter.writeUInt16(bb, extents.size());
+
+ for (Extent extent : extents) {
+ extent.getContent(bb);
+ }
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+
+ Item item = (Item) o;
+
+ if (baseOffset != item.baseOffset) return false;
+ if (constructionMethod != item.constructionMethod) return false;
+ if (dataReferenceIndex != item.dataReferenceIndex) return false;
+ if (itemId != item.itemId) return false;
+ if (extents != null ? !extents.equals(item.extents) : item.extents != null) return false;
+
+ return true;
+ }
+
+ @Override
+ public int hashCode() {
+ int result = itemId;
+ result = 31 * result + constructionMethod;
+ result = 31 * result + dataReferenceIndex;
+ result = 31 * result + (int) (baseOffset ^ (baseOffset >>> 32));
+ result = 31 * result + (extents != null ? extents.hashCode() : 0);
+ return result;
+ }
+
+ @Override
+ public String toString() {
+ return "Item{" +
+ "baseOffset=" + baseOffset +
+ ", itemId=" + itemId +
+ ", constructionMethod=" + constructionMethod +
+ ", dataReferenceIndex=" + dataReferenceIndex +
+ ", extents=" + extents +
+ '}';
+ }
+ }
+
+
+ public Extent createExtent(long extentOffset, long extentLength, long extentIndex) {
+ return new Extent(extentOffset, extentLength, extentIndex);
+ }
+
+ Extent createExtent(ByteBuffer bb) {
+ return new Extent(bb);
+ }
+
+
+ public class Extent {
+ public long extentOffset;
+ public long extentLength;
+ public long extentIndex;
+
+ public Extent(long extentOffset, long extentLength, long extentIndex) {
+ this.extentOffset = extentOffset;
+ this.extentLength = extentLength;
+ this.extentIndex = extentIndex;
+ }
+
+
+ public Extent(ByteBuffer in) {
+ if ((getVersion() == 1) && indexSize > 0) {
+ extentIndex = IsoTypeReaderVariable.read(in, indexSize);
+ }
+ extentOffset = IsoTypeReaderVariable.read(in, offsetSize);
+ extentLength = IsoTypeReaderVariable.read(in, lengthSize);
+ }
+
+ public void getContent(ByteBuffer os) {
+ if ((getVersion() == 1) && indexSize > 0) {
+ IsoTypeWriterVariable.write(extentIndex, os, indexSize);
+ }
+ IsoTypeWriterVariable.write(extentOffset, os, offsetSize);
+ IsoTypeWriterVariable.write(extentLength, os, lengthSize);
+ }
+
+ public int getSize() {
+ return (indexSize > 0 ? indexSize : 0) + offsetSize + lengthSize;
+ }
+
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+
+ Extent extent = (Extent) o;
+
+ if (extentIndex != extent.extentIndex) return false;
+ if (extentLength != extent.extentLength) return false;
+ if (extentOffset != extent.extentOffset) return false;
+
+ return true;
+ }
+
+ @Override
+ public int hashCode() {
+ int result = (int) (extentOffset ^ (extentOffset >>> 32));
+ result = 31 * result + (int) (extentLength ^ (extentLength >>> 32));
+ result = 31 * result + (int) (extentIndex ^ (extentIndex >>> 32));
+ return result;
+ }
+
+ @Override
+ public String toString() {
+ final StringBuilder sb = new StringBuilder();
+ sb.append("Extent");
+ sb.append("{extentOffset=").append(extentOffset);
+ sb.append(", extentLength=").append(extentLength);
+ sb.append(", extentIndex=").append(extentIndex);
+ sb.append('}');
+ return sb.toString();
+ }
+ }
+
+
+}
diff --git a/android-aac-enc/src/com/coremedia/iso/boxes/ItemProtectionBox.java b/android-aac-enc/src/com/coremedia/iso/boxes/ItemProtectionBox.java
new file mode 100644
index 000000000..7eed79003
--- /dev/null
+++ b/android-aac-enc/src/com/coremedia/iso/boxes/ItemProtectionBox.java
@@ -0,0 +1,61 @@
+/*
+ * 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.coremedia.iso.boxes;
+
+import com.coremedia.iso.IsoTypeReader;
+import com.coremedia.iso.IsoTypeWriter;
+import com.googlecode.mp4parser.FullContainerBox;
+
+import java.nio.ByteBuffer;
+
+/**
+ * The Item Protection Box provides an array of item protection information, for use by the Item Information Box.
+ *
+ * @see com.coremedia.iso.boxes.ItemProtectionBox
+ */
+public class ItemProtectionBox extends FullContainerBox {
+
+ public static final String TYPE = "ipro";
+
+ public ItemProtectionBox() {
+ super(TYPE);
+ }
+
+ public SchemeInformationBox getItemProtectionScheme() {
+ if (!getBoxes(SchemeInformationBox.class).isEmpty()) {
+ return getBoxes(SchemeInformationBox.class).get(0);
+ } else {
+ return null;
+ }
+ }
+
+ @Override
+ public void _parseDetails(ByteBuffer content) {
+ parseVersionAndFlags(content);
+ IsoTypeReader.readUInt16(content);
+ parseChildBoxes(content);
+ }
+
+
+ @Override
+ protected void getContent(ByteBuffer byteBuffer) {
+ writeVersionAndFlags(byteBuffer);
+ IsoTypeWriter.writeUInt16(byteBuffer, getBoxes().size());
+ writeChildBoxes(byteBuffer);
+ }
+
+}
diff --git a/android-aac-enc/src/com/coremedia/iso/boxes/KeywordsBox.java b/android-aac-enc/src/com/coremedia/iso/boxes/KeywordsBox.java
new file mode 100644
index 000000000..d9b7c0cf6
--- /dev/null
+++ b/android-aac-enc/src/com/coremedia/iso/boxes/KeywordsBox.java
@@ -0,0 +1,95 @@
+/*
+ * 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.coremedia.iso.boxes;
+
+import com.coremedia.iso.IsoTypeReader;
+import com.coremedia.iso.IsoTypeWriter;
+import com.coremedia.iso.Utf8;
+import com.googlecode.mp4parser.AbstractFullBox;
+
+import java.nio.ByteBuffer;
+
+/**
+ * List of keywords according to 3GPP 26.244.
+ */
+public class KeywordsBox extends AbstractFullBox {
+ public static final String TYPE = "kywd";
+
+ private String language;
+ private String[] keywords;
+
+ public KeywordsBox() {
+ super(TYPE);
+ }
+
+ public String getLanguage() {
+ return language;
+ }
+
+ public String[] getKeywords() {
+ return keywords;
+ }
+
+ public void setLanguage(String language) {
+ this.language = language;
+ }
+
+ public void setKeywords(String[] keywords) {
+ this.keywords = keywords;
+ }
+
+ protected long getContentSize() {
+ long contentSize = 7;
+ for (String keyword : keywords) {
+ contentSize += 1 + Utf8.utf8StringLengthInBytes(keyword) + 1;
+ }
+ return contentSize;
+ }
+
+ @Override
+ public void _parseDetails(ByteBuffer content) {
+ parseVersionAndFlags(content);
+ language = IsoTypeReader.readIso639(content);
+ int keywordCount = IsoTypeReader.readUInt8(content);
+ keywords = new String[keywordCount];
+ for (int i = 0; i < keywordCount; i++) {
+ IsoTypeReader.readUInt8(content);
+ keywords[i] = IsoTypeReader.readString(content);
+ }
+ }
+
+ @Override
+ protected void getContent(ByteBuffer byteBuffer) {
+ writeVersionAndFlags(byteBuffer);
+ IsoTypeWriter.writeIso639(byteBuffer, language);
+ IsoTypeWriter.writeUInt8(byteBuffer, keywords.length);
+ for (String keyword : keywords) {
+ IsoTypeWriter.writeUInt8(byteBuffer, Utf8.utf8StringLengthInBytes(keyword) + 1);
+ byteBuffer.put(Utf8.convert(keyword));
+ }
+ }
+
+ public String toString() {
+ StringBuffer buffer = new StringBuffer();
+ buffer.append("KeywordsBox[language=").append(getLanguage());
+ for (int i = 0; i < keywords.length; i++) {
+ buffer.append(";keyword").append(i).append("=").append(keywords[i]);
+ }
+ buffer.append("]");
+ return buffer.toString();
+ }
+}
diff --git a/android-aac-enc/src/com/coremedia/iso/boxes/MediaBox.java b/android-aac-enc/src/com/coremedia/iso/boxes/MediaBox.java
new file mode 100644
index 000000000..fa5642cb9
--- /dev/null
+++ b/android-aac-enc/src/com/coremedia/iso/boxes/MediaBox.java
@@ -0,0 +1,61 @@
+/*
+ * 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.coremedia.iso.boxes;
+
+
+import com.googlecode.mp4parser.AbstractContainerBox;
+
+/**
+ * The media declaration container contains all the objects that declare information about the media data within a
+ * track.
+ */
+public class MediaBox extends AbstractContainerBox {
+ public static final String TYPE = "mdia";
+
+ public MediaBox() {
+ super(TYPE);
+ }
+
+ public MediaInformationBox getMediaInformationBox() {
+ for (Box box : boxes) {
+ if (box instanceof MediaInformationBox) {
+ return (MediaInformationBox) box;
+ }
+ }
+ return null;
+ }
+
+ public MediaHeaderBox getMediaHeaderBox() {
+ for (Box box : boxes) {
+ if (box instanceof MediaHeaderBox) {
+ return (MediaHeaderBox) box;
+ }
+ }
+ return null;
+ }
+
+ public HandlerBox getHandlerBox() {
+ for (Box box : boxes) {
+ if (box instanceof HandlerBox) {
+ return (HandlerBox) box;
+ }
+ }
+ return null;
+ }
+
+
+}
diff --git a/android-aac-enc/src/com/coremedia/iso/boxes/MediaHeaderBox.java b/android-aac-enc/src/com/coremedia/iso/boxes/MediaHeaderBox.java
new file mode 100644
index 000000000..f9d5a9535
--- /dev/null
+++ b/android-aac-enc/src/com/coremedia/iso/boxes/MediaHeaderBox.java
@@ -0,0 +1,147 @@
+/*
+ * 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.coremedia.iso.boxes;
+
+import com.coremedia.iso.IsoTypeReader;
+import com.coremedia.iso.IsoTypeWriter;
+import com.googlecode.mp4parser.AbstractFullBox;
+
+import java.nio.ByteBuffer;
+
+/**
+ * This box defines overall information which is media-independent, and relevant to the entire presentation
+ * considered as a whole.
+ */
+public class MediaHeaderBox extends AbstractFullBox {
+ public static final String TYPE = "mdhd";
+
+
+ private long creationTime;
+ private long modificationTime;
+ private long timescale;
+ private long duration;
+ private String language;
+
+ public MediaHeaderBox() {
+ super(TYPE);
+ }
+
+ public long getCreationTime() {
+ return creationTime;
+ }
+
+ public long getModificationTime() {
+ return modificationTime;
+ }
+
+ public long getTimescale() {
+ return timescale;
+ }
+
+ public long getDuration() {
+ return duration;
+ }
+
+ public String getLanguage() {
+ return language;
+ }
+
+ protected long getContentSize() {
+ long contentSize = 4;
+ if (getVersion() == 1) {
+ contentSize += 8 + 8 + 4 + 8;
+ } else {
+ contentSize += 4 + 4 + 4 + 4;
+ }
+ contentSize += 2;
+ contentSize += 2;
+ return contentSize;
+
+ }
+
+ public void setCreationTime(long creationTime) {
+ this.creationTime = creationTime;
+ }
+
+ public void setModificationTime(long modificationTime) {
+ this.modificationTime = modificationTime;
+ }
+
+ public void setTimescale(long timescale) {
+ this.timescale = timescale;
+ }
+
+ public void setDuration(long duration) {
+ this.duration = duration;
+ }
+
+ public void setLanguage(String language) {
+ this.language = language;
+ }
+
+ @Override
+ public void _parseDetails(ByteBuffer content) {
+ parseVersionAndFlags(content);
+ if (getVersion() == 1) {
+ creationTime = IsoTypeReader.readUInt64(content);
+ modificationTime = IsoTypeReader.readUInt64(content);
+ timescale = IsoTypeReader.readUInt32(content);
+ duration = IsoTypeReader.readUInt64(content);
+ } else {
+ creationTime = IsoTypeReader.readUInt32(content);
+ modificationTime = IsoTypeReader.readUInt32(content);
+ timescale = IsoTypeReader.readUInt32(content);
+ duration = IsoTypeReader.readUInt32(content);
+ }
+ language = IsoTypeReader.readIso639(content);
+ IsoTypeReader.readUInt16(content);
+ }
+
+
+ public String toString() {
+ StringBuilder result = new StringBuilder();
+ result.append("MeditHeaderBox[");
+ result.append("creationTime=").append(getCreationTime());
+ result.append(";");
+ result.append("modificationTime=").append(getModificationTime());
+ result.append(";");
+ result.append("timescale=").append(getTimescale());
+ result.append(";");
+ result.append("duration=").append(getDuration());
+ result.append(";");
+ result.append("language=").append(getLanguage());
+ result.append("]");
+ return result.toString();
+ }
+
+ protected void getContent(ByteBuffer byteBuffer) {
+ writeVersionAndFlags(byteBuffer);
+ if (getVersion() == 1) {
+ IsoTypeWriter.writeUInt64(byteBuffer, creationTime);
+ IsoTypeWriter.writeUInt64(byteBuffer, modificationTime);
+ IsoTypeWriter.writeUInt32(byteBuffer, timescale);
+ IsoTypeWriter.writeUInt64(byteBuffer, duration);
+ } else {
+ IsoTypeWriter.writeUInt32(byteBuffer, creationTime);
+ IsoTypeWriter.writeUInt32(byteBuffer, modificationTime);
+ IsoTypeWriter.writeUInt32(byteBuffer, timescale);
+ IsoTypeWriter.writeUInt32(byteBuffer, duration);
+ }
+ IsoTypeWriter.writeIso639(byteBuffer, language);
+ IsoTypeWriter.writeUInt16(byteBuffer, 0);
+ }
+}
diff --git a/android-aac-enc/src/com/coremedia/iso/boxes/MediaInformationBox.java b/android-aac-enc/src/com/coremedia/iso/boxes/MediaInformationBox.java
new file mode 100644
index 000000000..ed25051d6
--- /dev/null
+++ b/android-aac-enc/src/com/coremedia/iso/boxes/MediaInformationBox.java
@@ -0,0 +1,49 @@
+/*
+ * 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.coremedia.iso.boxes;
+
+import com.googlecode.mp4parser.AbstractContainerBox;
+
+/**
+ * This box contains all the objects that declare characteristic information of the media in the track.
+ */
+public class MediaInformationBox extends AbstractContainerBox {
+ public static final String TYPE = "minf";
+
+ public MediaInformationBox() {
+ super(TYPE);
+ }
+
+ public SampleTableBox getSampleTableBox() {
+ for (Box box : boxes) {
+ if (box instanceof SampleTableBox) {
+ return (SampleTableBox) box;
+ }
+ }
+ return null;
+ }
+
+ public AbstractMediaHeaderBox getMediaHeaderBox() {
+ for (Box box : boxes) {
+ if (box instanceof AbstractMediaHeaderBox) {
+ return (AbstractMediaHeaderBox) box;
+ }
+ }
+ return null;
+ }
+
+}
diff --git a/android-aac-enc/src/com/coremedia/iso/boxes/MetaBox.java b/android-aac-enc/src/com/coremedia/iso/boxes/MetaBox.java
new file mode 100644
index 000000000..35499ec46
--- /dev/null
+++ b/android-aac-enc/src/com/coremedia/iso/boxes/MetaBox.java
@@ -0,0 +1,113 @@
+/*
+ * 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.coremedia.iso.boxes;
+
+import com.coremedia.iso.IsoTypeReader;
+import com.coremedia.iso.IsoTypeWriter;
+import com.googlecode.mp4parser.AbstractContainerBox;
+import com.googlecode.mp4parser.util.ByteBufferByteChannel;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+
+
+/**
+ * A common base structure to contain general metadata. See ISO/IEC 14496-12 Ch. 8.44.1.
+ */
+public class MetaBox extends AbstractContainerBox {
+ private int version = 0;
+ private int flags = 0;
+
+ public static final String TYPE = "meta";
+
+ public MetaBox() {
+ super(TYPE);
+ }
+
+ @Override
+ public long getContentSize() {
+ if (isMp4Box()) {
+ // it's a fullbox
+ return 4 + super.getContentSize();
+ } else {
+ // it's an apple metabox
+ return super.getContentSize();
+ }
+ }
+
+ @Override
+ public long getNumOfBytesToFirstChild() {
+ if (isMp4Box()) {
+ // it's a fullbox
+ return 12;
+ } else {
+ // it's an apple metabox
+ return 8;
+ }
+ }
+
+ @Override
+ public void _parseDetails(ByteBuffer content) {
+ int pos = content.position();
+ content.get(new byte[4]);
+ String isHdlr = IsoTypeReader.read4cc(content);
+ if ("hdlr".equals(isHdlr)) {
+ // this is apple bullshit - it's NO FULLBOX
+ content.position(pos);
+ version = -1;
+ flags = -1;
+ } else {
+ content.position(pos);
+ version = IsoTypeReader.readUInt8(content);
+ flags = IsoTypeReader.readUInt24(content);
+ }
+ while (content.remaining() >= 8) {
+ try {
+ boxes.add(boxParser.parseBox(new ByteBufferByteChannel(content), this));
+ } catch (IOException e) {
+ throw new RuntimeException("Sebastian needs to fix 7518765283");
+ }
+ }
+ if (content.remaining() > 0) {
+ throw new RuntimeException("Sebastian needs to fix it 90732r26537");
+ }
+ }
+
+ @Override
+ protected void getContent(ByteBuffer byteBuffer) {
+ if (isMp4Box()) {
+ IsoTypeWriter.writeUInt8(byteBuffer, version);
+ IsoTypeWriter.writeUInt24(byteBuffer, flags);
+ }
+ writeChildBoxes(byteBuffer);
+ }
+
+
+ public boolean isMp4Box() {
+ return version != -1 && flags != -1;
+ }
+
+ public void setMp4Box(boolean mp4) {
+ if (mp4) {
+ version = 0;
+ flags = 0;
+ } else {
+ version = -1;
+ flags = -1;
+ }
+ }
+}
diff --git a/android-aac-enc/src/com/coremedia/iso/boxes/MovieBox.java b/android-aac-enc/src/com/coremedia/iso/boxes/MovieBox.java
new file mode 100644
index 000000000..3aff7d837
--- /dev/null
+++ b/android-aac-enc/src/com/coremedia/iso/boxes/MovieBox.java
@@ -0,0 +1,67 @@
+/*
+ * 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.coremedia.iso.boxes;
+
+
+import com.googlecode.mp4parser.AbstractBox;
+import com.googlecode.mp4parser.AbstractContainerBox;
+
+import java.util.List;
+
+/**
+ * The metadata for a presentation is stored in the single Movie Box which occurs at the top-level of a file.
+ * Normally this box is close to the beginning or end of the file, though this is not required.
+ */
+public class MovieBox extends AbstractContainerBox {
+ public static final String TYPE = "moov";
+
+ public MovieBox() {
+ super(TYPE);
+ }
+
+ public int getTrackCount() {
+ return getBoxes(TrackBox.class).size();
+ }
+
+
+ /**
+ * Returns the track numbers associated with this
MovieBox
.
+ *
+ * @return the tracknumbers (IDs) of the tracks in their order of appearance in the file
+ */
+ public long[] getTrackNumbers() {
+
+ List trackBoxes = this.getBoxes(TrackBox.class);
+ long[] trackNumbers = new long[trackBoxes.size()];
+ for (int trackCounter = 0; trackCounter < trackBoxes.size(); trackCounter++) {
+ AbstractBox trackBoxe = trackBoxes.get(trackCounter);
+ TrackBox trackBox = (TrackBox) trackBoxe;
+ trackNumbers[trackCounter] = trackBox.getTrackHeaderBox().getTrackId();
+ }
+ return trackNumbers;
+ }
+
+ public MovieHeaderBox getMovieHeaderBox() {
+ for (Box box : boxes) {
+ if (box instanceof MovieHeaderBox) {
+ return (MovieHeaderBox) box;
+ }
+ }
+ return null;
+ }
+
+}
diff --git a/android-aac-enc/src/com/coremedia/iso/boxes/MovieHeaderBox.java b/android-aac-enc/src/com/coremedia/iso/boxes/MovieHeaderBox.java
new file mode 100644
index 000000000..9dcc3852f
--- /dev/null
+++ b/android-aac-enc/src/com/coremedia/iso/boxes/MovieHeaderBox.java
@@ -0,0 +1,210 @@
+/*
+ * 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.coremedia.iso.boxes;
+
+import com.coremedia.iso.IsoTypeReader;
+import com.coremedia.iso.IsoTypeWriter;
+import com.googlecode.mp4parser.AbstractFullBox;
+
+import java.nio.ByteBuffer;
+
+/**
+ *
+ * Box Type: 'mvhd'
+ * Container: {@link MovieBox} ('moov')
+ * Mandatory: Yes
+ * Quantity: Exactly one
+ *
+ * This box defines overall information which is media-independent, and relevant to the entire presentation
+ * considered as a whole.
+ */
+public class MovieHeaderBox extends AbstractFullBox {
+ private long creationTime;
+ private long modificationTime;
+ private long timescale;
+ private long duration;
+ private double rate = 1.0;
+ private float volume = 1.0f;
+ private long[] matrix = new long[]{0x00010000, 0, 0, 0, 0x00010000, 0, 0, 0, 0x40000000};
+ private long nextTrackId;
+ public static final String TYPE = "mvhd";
+
+ public MovieHeaderBox() {
+ super(TYPE);
+ }
+
+ public long getCreationTime() {
+ return creationTime;
+ }
+
+ public long getModificationTime() {
+ return modificationTime;
+ }
+
+ public long getTimescale() {
+ return timescale;
+ }
+
+ public long getDuration() {
+ return duration;
+ }
+
+ public double getRate() {
+ return rate;
+ }
+
+ public float getVolume() {
+ return volume;
+ }
+
+ public long[] getMatrix() {
+ return matrix;
+ }
+
+ public long getNextTrackId() {
+ return nextTrackId;
+ }
+
+ protected long getContentSize() {
+ long contentSize = 4;
+ if (getVersion() == 1) {
+ contentSize += 28;
+ } else {
+ contentSize += 16;
+ }
+ contentSize += 80;
+ return contentSize;
+ }
+
+ @Override
+ public void _parseDetails(ByteBuffer content) {
+ parseVersionAndFlags(content);
+ if (getVersion() == 1) {
+ creationTime = IsoTypeReader.readUInt64(content);
+ modificationTime = IsoTypeReader.readUInt64(content);
+ timescale = IsoTypeReader.readUInt32(content);
+ duration = IsoTypeReader.readUInt64(content);
+ } else {
+ creationTime = IsoTypeReader.readUInt32(content);
+ modificationTime = IsoTypeReader.readUInt32(content);
+ timescale = IsoTypeReader.readUInt32(content);
+ duration = IsoTypeReader.readUInt32(content);
+ }
+ rate = IsoTypeReader.readFixedPoint1616(content);
+ volume = IsoTypeReader.readFixedPoint88(content);
+ IsoTypeReader.readUInt16(content);
+ IsoTypeReader.readUInt32(content);
+ IsoTypeReader.readUInt32(content);
+ matrix = new long[9];
+ for (int i = 0; i < 9; i++) {
+ matrix[i] = IsoTypeReader.readUInt32(content);
+ }
+ for (int i = 0; i < 6; i++) {
+ IsoTypeReader.readUInt32(content);
+ }
+ nextTrackId = IsoTypeReader.readUInt32(content);
+
+ }
+
+ public String toString() {
+ StringBuilder result = new StringBuilder();
+ result.append("MovieHeaderBox[");
+ result.append("creationTime=").append(getCreationTime());
+ result.append(";");
+ result.append("modificationTime=").append(getModificationTime());
+ result.append(";");
+ result.append("timescale=").append(getTimescale());
+ result.append(";");
+ result.append("duration=").append(getDuration());
+ result.append(";");
+ result.append("rate=").append(getRate());
+ result.append(";");
+ result.append("volume=").append(getVolume());
+ for (int i = 0; i < matrix.length; i++) {
+ result.append(";");
+ result.append("matrix").append(i).append("=").append(matrix[i]);
+ }
+ result.append(";");
+ result.append("nextTrackId=").append(getNextTrackId());
+ result.append("]");
+ return result.toString();
+ }
+
+
+ @Override
+ protected void getContent(ByteBuffer byteBuffer) {
+ writeVersionAndFlags(byteBuffer);
+ if (getVersion() == 1) {
+ IsoTypeWriter.writeUInt64(byteBuffer, creationTime);
+ IsoTypeWriter.writeUInt64(byteBuffer, modificationTime);
+ IsoTypeWriter.writeUInt32(byteBuffer, timescale);
+ IsoTypeWriter.writeUInt64(byteBuffer, duration);
+ } else {
+ IsoTypeWriter.writeUInt32(byteBuffer, creationTime);
+ IsoTypeWriter.writeUInt32(byteBuffer, modificationTime);
+ IsoTypeWriter.writeUInt32(byteBuffer, timescale);
+ IsoTypeWriter.writeUInt32(byteBuffer, duration);
+ }
+ IsoTypeWriter.writeFixedPont1616(byteBuffer, rate);
+ IsoTypeWriter.writeFixedPont88(byteBuffer, volume);
+ IsoTypeWriter.writeUInt16(byteBuffer, 0);
+ IsoTypeWriter.writeUInt32(byteBuffer, 0);
+ IsoTypeWriter.writeUInt32(byteBuffer, 0);
+
+
+ for (int i = 0; i < 9; i++) {
+ IsoTypeWriter.writeUInt32(byteBuffer, matrix[i]);
+ }
+ for (int i = 0; i < 6; i++) {
+ IsoTypeWriter.writeUInt32(byteBuffer, 0);
+ }
+ IsoTypeWriter.writeUInt32(byteBuffer, nextTrackId);
+ }
+
+
+ public void setCreationTime(long creationTime) {
+ this.creationTime = creationTime;
+ }
+
+ public void setModificationTime(long modificationTime) {
+ this.modificationTime = modificationTime;
+ }
+
+ public void setTimescale(long timescale) {
+ this.timescale = timescale;
+ }
+
+ public void setDuration(long duration) {
+ this.duration = duration;
+ }
+
+ public void setRate(double rate) {
+ this.rate = rate;
+ }
+
+ public void setVolume(float volume) {
+ this.volume = volume;
+ }
+
+ public void setMatrix(long[] matrix) {
+ this.matrix = matrix;
+ }
+
+ public void setNextTrackId(long nextTrackId) {
+ this.nextTrackId = nextTrackId;
+ }
+}
diff --git a/android-aac-enc/src/com/coremedia/iso/boxes/NullMediaHeaderBox.java b/android-aac-enc/src/com/coremedia/iso/boxes/NullMediaHeaderBox.java
new file mode 100644
index 000000000..562f8d4a8
--- /dev/null
+++ b/android-aac-enc/src/com/coremedia/iso/boxes/NullMediaHeaderBox.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2011 Sebastian Annies, Hamburg, Germany
+ *
+ * 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.coremedia.iso.boxes;
+
+import java.nio.ByteBuffer;
+
+/**
+ * Streams other than visual and audio (e.g., timed metadata streams) may use a
+ * Null Media Header Box.
+ */
+public class NullMediaHeaderBox extends AbstractMediaHeaderBox {
+ public NullMediaHeaderBox() {
+ super("nmhd");
+ }
+
+ @Override
+ protected long getContentSize() {
+ return 4;
+ }
+
+ @Override
+ public void _parseDetails(ByteBuffer content) {
+ parseVersionAndFlags(content);
+ }
+
+ @Override
+ protected void getContent(ByteBuffer byteBuffer) {
+ writeVersionAndFlags(byteBuffer);
+ }
+}
diff --git a/android-aac-enc/src/com/coremedia/iso/boxes/ObjectDescriptorBox.java b/android-aac-enc/src/com/coremedia/iso/boxes/ObjectDescriptorBox.java
new file mode 100644
index 000000000..e69de29bb
diff --git a/android-aac-enc/src/com/coremedia/iso/boxes/OmaDrmAccessUnitFormatBox.java b/android-aac-enc/src/com/coremedia/iso/boxes/OmaDrmAccessUnitFormatBox.java
new file mode 100644
index 000000000..020881ba3
--- /dev/null
+++ b/android-aac-enc/src/com/coremedia/iso/boxes/OmaDrmAccessUnitFormatBox.java
@@ -0,0 +1,87 @@
+/*
+ * 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.coremedia.iso.boxes;
+
+import com.coremedia.iso.IsoTypeReader;
+import com.coremedia.iso.IsoTypeWriter;
+import com.googlecode.mp4parser.AbstractFullBox;
+
+import java.nio.ByteBuffer;
+
+/**
+ * Describes the format of media access units in PDCF files.
+ */
+public final class OmaDrmAccessUnitFormatBox extends AbstractFullBox {
+ public static final String TYPE = "odaf";
+
+ private boolean selectiveEncryption;
+ private byte allBits;
+
+ private int keyIndicatorLength;
+ private int initVectorLength;
+
+ protected long getContentSize() {
+ return 7;
+ }
+
+ public OmaDrmAccessUnitFormatBox() {
+ super("odaf");
+ }
+
+ public boolean isSelectiveEncryption() {
+ return selectiveEncryption;
+ }
+
+ public int getKeyIndicatorLength() {
+ return keyIndicatorLength;
+ }
+
+ public int getInitVectorLength() {
+ return initVectorLength;
+ }
+
+ public void setInitVectorLength(int initVectorLength) {
+ this.initVectorLength = initVectorLength;
+ }
+
+ public void setKeyIndicatorLength(int keyIndicatorLength) {
+ this.keyIndicatorLength = keyIndicatorLength;
+ }
+
+ public void setAllBits(byte allBits) {
+ this.allBits = allBits;
+ selectiveEncryption = (allBits & 0x80) == 0x80;
+ }
+
+ @Override
+ public void _parseDetails(ByteBuffer content) {
+ parseVersionAndFlags(content);
+ allBits = (byte) IsoTypeReader.readUInt8(content);
+ selectiveEncryption = (allBits & 0x80) == 0x80;
+ keyIndicatorLength = IsoTypeReader.readUInt8(content);
+ initVectorLength = IsoTypeReader.readUInt8(content);
+ }
+
+ @Override
+ protected void getContent(ByteBuffer byteBuffer) {
+ writeVersionAndFlags(byteBuffer);
+ IsoTypeWriter.writeUInt8(byteBuffer, allBits);
+ IsoTypeWriter.writeUInt8(byteBuffer, keyIndicatorLength);
+ IsoTypeWriter.writeUInt8(byteBuffer, initVectorLength);
+ }
+
+}
diff --git a/android-aac-enc/src/com/coremedia/iso/boxes/OriginalFormatBox.java b/android-aac-enc/src/com/coremedia/iso/boxes/OriginalFormatBox.java
new file mode 100644
index 000000000..004c6c2e1
--- /dev/null
+++ b/android-aac-enc/src/com/coremedia/iso/boxes/OriginalFormatBox.java
@@ -0,0 +1,69 @@
+/*
+ * 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.coremedia.iso.boxes;
+
+import com.coremedia.iso.IsoFile;
+import com.coremedia.iso.IsoTypeReader;
+import com.googlecode.mp4parser.AbstractBox;
+
+import java.nio.ByteBuffer;
+
+/**
+ * The Original Format Box contains the four-character-code of the original untransformed sample description.
+ * See ISO/IEC 14496-12 for details.
+ *
+ * @see ProtectionSchemeInformationBox
+ */
+
+public class OriginalFormatBox extends AbstractBox {
+ public static final String TYPE = "frma";
+
+ private String dataFormat = " ";
+
+ public OriginalFormatBox() {
+ super("frma");
+ }
+
+ public String getDataFormat() {
+ return dataFormat;
+ }
+
+
+ public void setDataFormat(String dataFormat) {
+ assert dataFormat.length() == 4;
+ this.dataFormat = dataFormat;
+ }
+
+ protected long getContentSize() {
+ return 4;
+ }
+
+ @Override
+ public void _parseDetails(ByteBuffer content) {
+ dataFormat = IsoTypeReader.read4cc(content);
+ }
+
+ @Override
+ protected void getContent(ByteBuffer byteBuffer) {
+ byteBuffer.put(IsoFile.fourCCtoBytes(dataFormat));
+ }
+
+
+ public String toString() {
+ return "OriginalFormatBox[dataFormat=" + getDataFormat() + "]";
+ }
+}
diff --git a/android-aac-enc/src/com/coremedia/iso/boxes/PerformerBox.java b/android-aac-enc/src/com/coremedia/iso/boxes/PerformerBox.java
new file mode 100644
index 000000000..cf702dce3
--- /dev/null
+++ b/android-aac-enc/src/com/coremedia/iso/boxes/PerformerBox.java
@@ -0,0 +1,78 @@
+/*
+ * 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.coremedia.iso.boxes;
+
+import com.coremedia.iso.IsoTypeReader;
+import com.coremedia.iso.IsoTypeWriter;
+import com.coremedia.iso.Utf8;
+import com.googlecode.mp4parser.AbstractFullBox;
+
+import java.nio.ByteBuffer;
+
+/**
+ * Used to give information about the performer. Mostly used in confunction with music files.
+ * See 3GPP 26.234 for details.
+ */
+public class PerformerBox extends AbstractFullBox {
+ public static final String TYPE = "perf";
+
+ private String language;
+ private String performer;
+
+ public PerformerBox() {
+ super(TYPE);
+ }
+
+ public String getLanguage() {
+ return language;
+ }
+
+ public String getPerformer() {
+ return performer;
+ }
+
+ public void setLanguage(String language) {
+ this.language = language;
+ }
+
+ public void setPerformer(String performer) {
+ this.performer = performer;
+ }
+
+ protected long getContentSize() {
+ return 6 + Utf8.utf8StringLengthInBytes(performer) + 1;
+ }
+
+ @Override
+ protected void getContent(ByteBuffer byteBuffer) {
+ writeVersionAndFlags(byteBuffer);
+ IsoTypeWriter.writeIso639(byteBuffer, language);
+ byteBuffer.put(Utf8.convert(performer));
+ byteBuffer.put((byte) 0);
+ }
+
+ @Override
+ public void _parseDetails(ByteBuffer content) {
+ parseVersionAndFlags(content);
+ language = IsoTypeReader.readIso639(content);
+ performer = IsoTypeReader.readString(content);
+ }
+
+ public String toString() {
+ return "PerformerBox[language=" + getLanguage() + ";performer=" + getPerformer() + "]";
+ }
+}
diff --git a/android-aac-enc/src/com/coremedia/iso/boxes/ProgressiveDownloadInformationBox.java b/android-aac-enc/src/com/coremedia/iso/boxes/ProgressiveDownloadInformationBox.java
new file mode 100644
index 000000000..7acd7edcf
--- /dev/null
+++ b/android-aac-enc/src/com/coremedia/iso/boxes/ProgressiveDownloadInformationBox.java
@@ -0,0 +1,95 @@
+package com.coremedia.iso.boxes;
+
+import com.coremedia.iso.IsoTypeReader;
+import com.coremedia.iso.IsoTypeWriter;
+import com.googlecode.mp4parser.AbstractFullBox;
+
+import java.nio.ByteBuffer;
+import java.util.Collections;
+import java.util.LinkedList;
+import java.util.List;
+
+public class ProgressiveDownloadInformationBox extends AbstractFullBox {
+
+
+ List entries = Collections.emptyList();
+
+ public ProgressiveDownloadInformationBox() {
+ super("pdin");
+ }
+
+ @Override
+ protected long getContentSize() {
+ return 4 + entries.size() * 8;
+ }
+
+ @Override
+ protected void getContent(ByteBuffer byteBuffer) {
+ writeVersionAndFlags(byteBuffer);
+ for (Entry entry : entries) {
+ IsoTypeWriter.writeUInt32(byteBuffer, entry.getRate());
+ IsoTypeWriter.writeUInt32(byteBuffer, entry.getInitialDelay());
+ }
+ }
+
+ public List getEntries() {
+ return entries;
+ }
+
+ public void setEntries(List entries) {
+ this.entries = entries;
+ }
+
+ @Override
+ public void _parseDetails(ByteBuffer content) {
+ parseVersionAndFlags(content);
+ entries = new LinkedList();
+ while (content.remaining() >= 8) {
+ Entry entry = new Entry(IsoTypeReader.readUInt32(content), IsoTypeReader.readUInt32(content));
+ entries.add(entry);
+ }
+ }
+
+
+ public static class Entry {
+ long rate;
+ long initialDelay;
+
+ public Entry(long rate, long initialDelay) {
+ this.rate = rate;
+ this.initialDelay = initialDelay;
+ }
+
+ public long getRate() {
+ return rate;
+ }
+
+ public void setRate(long rate) {
+ this.rate = rate;
+ }
+
+ public long getInitialDelay() {
+ return initialDelay;
+ }
+
+ public void setInitialDelay(long initialDelay) {
+ this.initialDelay = initialDelay;
+ }
+
+ @Override
+ public String toString() {
+ return "Entry{" +
+ "rate=" + rate +
+ ", initialDelay=" + initialDelay +
+ '}';
+ }
+ }
+
+ @Override
+ public String toString() {
+ return "ProgressiveDownloadInfoBox{" +
+ "entries=" + entries +
+ '}';
+ }
+
+}
\ No newline at end of file
diff --git a/android-aac-enc/src/com/coremedia/iso/boxes/ProtectionSchemeInformationBox.java b/android-aac-enc/src/com/coremedia/iso/boxes/ProtectionSchemeInformationBox.java
new file mode 100644
index 000000000..87069d381
--- /dev/null
+++ b/android-aac-enc/src/com/coremedia/iso/boxes/ProtectionSchemeInformationBox.java
@@ -0,0 +1,42 @@
+/*
+ * 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.coremedia.iso.boxes;
+
+import com.googlecode.mp4parser.AbstractContainerBox;
+
+/**
+ * The ProtectionSchemeInformationBox
contains all the information required both
+ * to understand the encryption transform applied and its parameters, and also to find other
+ * information such as the kind and location of the key management system. It also documents the
+ * the original (unencrypted) format of the media. The ProtectionSchemeInformationBox
+ * is a container box. It is mandatory in a sample entry that uses a code idicating a
+ * protected stream.
+ *
+ * @see com.coremedia.iso.boxes.odf.OmaDrmKeyManagenentSystemBox
+ * @see com.coremedia.iso.boxes.sampleentry.AudioSampleEntry#TYPE_ENCRYPTED
+ * @see com.coremedia.iso.boxes.sampleentry.VisualSampleEntry#TYPE_ENCRYPTED
+ */
+public class ProtectionSchemeInformationBox extends AbstractContainerBox {
+ public static final String TYPE = "sinf";
+
+ public ProtectionSchemeInformationBox() {
+ super(TYPE);
+
+ }
+
+
+}
diff --git a/android-aac-enc/src/com/coremedia/iso/boxes/RatingBox.java b/android-aac-enc/src/com/coremedia/iso/boxes/RatingBox.java
new file mode 100644
index 000000000..ad327495a
--- /dev/null
+++ b/android-aac-enc/src/com/coremedia/iso/boxes/RatingBox.java
@@ -0,0 +1,124 @@
+/*
+ * 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.coremedia.iso.boxes;
+
+import com.coremedia.iso.IsoFile;
+import com.coremedia.iso.IsoTypeReader;
+import com.coremedia.iso.IsoTypeWriter;
+import com.coremedia.iso.Utf8;
+import com.googlecode.mp4parser.AbstractFullBox;
+
+import java.nio.ByteBuffer;
+
+
+/**
+ * Contained a the UserDataBox
and containing information about the media's rating. E.g.
+ * PG13or FSK16.
+ */
+public class RatingBox extends AbstractFullBox {
+ public static final String TYPE = "rtng";
+
+ private String ratingEntity;
+ private String ratingCriteria;
+ private String language;
+ private String ratingInfo;
+
+ public RatingBox() {
+ super(TYPE);
+ }
+
+
+ public void setRatingEntity(String ratingEntity) {
+ this.ratingEntity = ratingEntity;
+ }
+
+ public void setRatingCriteria(String ratingCriteria) {
+ this.ratingCriteria = ratingCriteria;
+ }
+
+ public void setLanguage(String language) {
+ this.language = language;
+ }
+
+ public void setRatingInfo(String ratingInfo) {
+ this.ratingInfo = ratingInfo;
+ }
+
+ public String getLanguage() {
+ return language;
+ }
+
+ /**
+ * Gets a four-character code that indicates the rating entity grading the asset, e.g., 'BBFC'. The values of this
+ * field should follow common names of worldwide movie rating systems, such as those mentioned in
+ * [http://www.movie-ratings.net/, October 2002].
+ *
+ * @return the rating organization
+ */
+ public String getRatingEntity() {
+ return ratingEntity;
+ }
+
+ /**
+ * Gets the four-character code that indicates which rating criteria are being used for the corresponding rating
+ * entity, e.g., 'PG13'.
+ *
+ * @return the actual rating
+ */
+ public String getRatingCriteria() {
+ return ratingCriteria;
+ }
+
+ public String getRatingInfo() {
+ return ratingInfo;
+ }
+
+ protected long getContentSize() {
+ return 15 + Utf8.utf8StringLengthInBytes(ratingInfo);
+ }
+
+ @Override
+ public void _parseDetails(ByteBuffer content) {
+ parseVersionAndFlags(content);
+ ratingEntity = IsoTypeReader.read4cc(content);
+ ratingCriteria = IsoTypeReader.read4cc(content);
+ language = IsoTypeReader.readIso639(content);
+ ratingInfo = IsoTypeReader.readString(content);
+
+ }
+
+ @Override
+ protected void getContent(ByteBuffer byteBuffer) {
+ writeVersionAndFlags(byteBuffer);
+ byteBuffer.put(IsoFile.fourCCtoBytes(ratingEntity));
+ byteBuffer.put(IsoFile.fourCCtoBytes(ratingCriteria));
+ IsoTypeWriter.writeIso639(byteBuffer, language);
+ byteBuffer.put(Utf8.convert(ratingInfo));
+ byteBuffer.put((byte) 0);
+ }
+
+ public String toString() {
+ StringBuilder buffer = new StringBuilder();
+ buffer.append("RatingBox[language=").append(getLanguage());
+ buffer.append("ratingEntity=").append(getRatingEntity());
+ buffer.append(";ratingCriteria=").append(getRatingCriteria());
+ buffer.append(";language=").append(getLanguage());
+ buffer.append(";ratingInfo=").append(getRatingInfo());
+ buffer.append("]");
+ return buffer.toString();
+ }
+}
diff --git a/android-aac-enc/src/com/coremedia/iso/boxes/RecordingYearBox.java b/android-aac-enc/src/com/coremedia/iso/boxes/RecordingYearBox.java
new file mode 100644
index 000000000..e2dcbd959
--- /dev/null
+++ b/android-aac-enc/src/com/coremedia/iso/boxes/RecordingYearBox.java
@@ -0,0 +1,63 @@
+/*
+ * 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.coremedia.iso.boxes;
+
+import com.coremedia.iso.IsoTypeReader;
+import com.coremedia.iso.IsoTypeWriter;
+import com.googlecode.mp4parser.AbstractFullBox;
+
+import java.nio.ByteBuffer;
+
+/**
+ *
+ */
+public class RecordingYearBox extends AbstractFullBox {
+ public static final String TYPE = "yrrc";
+
+ int recordingYear;
+
+ public RecordingYearBox() {
+ super(TYPE);
+ }
+
+
+ protected long getContentSize() {
+ return 6;
+ }
+
+ public int getRecordingYear() {
+ return recordingYear;
+ }
+
+ public void setRecordingYear(int recordingYear) {
+ this.recordingYear = recordingYear;
+ }
+
+
+ @Override
+ public void _parseDetails(ByteBuffer content) {
+ parseVersionAndFlags(content);
+ recordingYear = IsoTypeReader.readUInt16(content);
+ }
+
+ @Override
+ protected void getContent(ByteBuffer byteBuffer) {
+ writeVersionAndFlags(byteBuffer);
+ IsoTypeWriter.writeUInt16(byteBuffer, recordingYear);
+ }
+
+}
diff --git a/android-aac-enc/src/com/coremedia/iso/boxes/SampleAuxiliaryInformationOffsetsBox.java b/android-aac-enc/src/com/coremedia/iso/boxes/SampleAuxiliaryInformationOffsetsBox.java
new file mode 100644
index 000000000..517bc033a
--- /dev/null
+++ b/android-aac-enc/src/com/coremedia/iso/boxes/SampleAuxiliaryInformationOffsetsBox.java
@@ -0,0 +1,127 @@
+/*
+ * Copyright 2009 castLabs GmbH, Berlin
+ *
+ * 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.coremedia.iso.boxes;
+
+import com.coremedia.iso.IsoTypeReader;
+import com.coremedia.iso.IsoTypeWriter;
+import com.googlecode.mp4parser.AbstractFullBox;
+
+import java.nio.ByteBuffer;
+import java.util.LinkedList;
+import java.util.List;
+
+import static com.googlecode.mp4parser.util.CastUtils.l2i;
+
+/*
+aligned(8) class SampleAuxiliaryInformationOffsetsBox
+ extends FullBox(‘saio’, version, flags)
+{
+ if (flags & 1) {
+ unsigned int(32) aux_info_type;
+ unsigned int(32) aux_info_type_parameter;
+ }
+ unsigned int(32) entry_count;
+ if ( version == 0 )
+ {
+ unsigned int(32) offset[ entry_count ];
+ }
+ else
+ {
+ unsigned int(64) offset[ entry_count ];
+ }
+}
+ */
+public class SampleAuxiliaryInformationOffsetsBox extends AbstractFullBox {
+ public static final String TYPE = "saio";
+
+ private List offsets = new LinkedList();
+ private long auxInfoType;
+ private long auxInfoTypeParameter;
+
+ public SampleAuxiliaryInformationOffsetsBox() {
+ super(TYPE);
+ }
+
+ @Override
+ protected long getContentSize() {
+ return 8 + (getVersion() == 0 ? 4 * offsets.size() : 8 * offsets.size()) + ((getFlags() & 1) == 1 ? 8 : 0);
+ }
+
+ @Override
+ protected void getContent(ByteBuffer byteBuffer) {
+ writeVersionAndFlags(byteBuffer);
+ if ((getFlags() & 1) == 1) {
+ IsoTypeWriter.writeUInt32(byteBuffer, auxInfoType);
+ IsoTypeWriter.writeUInt32(byteBuffer, auxInfoTypeParameter);
+ }
+
+ IsoTypeWriter.writeUInt32(byteBuffer, offsets.size());
+ for (Long offset : offsets) {
+ if (getVersion() == 0) {
+ IsoTypeWriter.writeUInt32(byteBuffer, offset);
+ } else {
+ IsoTypeWriter.writeUInt64(byteBuffer, offset);
+ }
+ }
+ }
+
+ @Override
+ public void _parseDetails(ByteBuffer content) {
+ parseVersionAndFlags(content);
+
+ if ((getFlags() & 1) == 1) {
+ auxInfoType = IsoTypeReader.readUInt32(content);
+ auxInfoTypeParameter = IsoTypeReader.readUInt32(content);
+ }
+
+ int entryCount = l2i(IsoTypeReader.readUInt32(content));
+ offsets.clear();
+
+ for (int i = 0; i < entryCount; i++) {
+ if (getVersion() == 0) {
+ offsets.add(IsoTypeReader.readUInt32(content));
+ } else {
+ offsets.add(IsoTypeReader.readUInt64(content));
+ }
+ }
+ }
+
+
+ public long getAuxInfoType() {
+ return auxInfoType;
+ }
+
+ public void setAuxInfoType(long auxInfoType) {
+ this.auxInfoType = auxInfoType;
+ }
+
+ public long getAuxInfoTypeParameter() {
+ return auxInfoTypeParameter;
+ }
+
+ public void setAuxInfoTypeParameter(long auxInfoTypeParameter) {
+ this.auxInfoTypeParameter = auxInfoTypeParameter;
+ }
+
+ public List getOffsets() {
+ return offsets;
+ }
+
+ public void setOffsets(List offsets) {
+ this.offsets = offsets;
+ }
+}
diff --git a/android-aac-enc/src/com/coremedia/iso/boxes/SampleAuxiliaryInformationSizesBox.java b/android-aac-enc/src/com/coremedia/iso/boxes/SampleAuxiliaryInformationSizesBox.java
new file mode 100644
index 000000000..655106200
--- /dev/null
+++ b/android-aac-enc/src/com/coremedia/iso/boxes/SampleAuxiliaryInformationSizesBox.java
@@ -0,0 +1,134 @@
+/*
+ * Copyright 2009 castLabs GmbH, Berlin
+ *
+ * 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.coremedia.iso.boxes;
+
+import com.coremedia.iso.IsoFile;
+import com.coremedia.iso.IsoTypeReader;
+import com.coremedia.iso.IsoTypeWriter;
+import com.googlecode.mp4parser.AbstractFullBox;
+
+import java.nio.ByteBuffer;
+import java.util.LinkedList;
+import java.util.List;
+
+import static com.googlecode.mp4parser.util.CastUtils.l2i;
+
+public class SampleAuxiliaryInformationSizesBox extends AbstractFullBox {
+ public static final String TYPE = "saiz";
+
+ private int defaultSampleInfoSize;
+ private List sampleInfoSizes = new LinkedList();
+ private int sampleCount;
+ private String auxInfoType;
+ private String auxInfoTypeParameter;
+
+ public SampleAuxiliaryInformationSizesBox() {
+ super(TYPE);
+ }
+
+ @Override
+ protected long getContentSize() {
+ int size = 4;
+ if ((getFlags() & 1) == 1) {
+ size += 8;
+ }
+
+ size += 5;
+ size += sampleInfoSizes.size();
+ return size;
+ }
+
+ @Override
+ protected void getContent(ByteBuffer byteBuffer) {
+ writeVersionAndFlags(byteBuffer);
+ if ((getFlags() & 1) == 1) {
+ byteBuffer.put(IsoFile.fourCCtoBytes(auxInfoType));
+ byteBuffer.put(IsoFile.fourCCtoBytes(auxInfoTypeParameter));
+ }
+
+ IsoTypeWriter.writeUInt8(byteBuffer, defaultSampleInfoSize);
+ if (defaultSampleInfoSize == 0) {
+ IsoTypeWriter.writeUInt32(byteBuffer, sampleInfoSizes.size());
+ for (short sampleInfoSize : sampleInfoSizes) {
+ IsoTypeWriter.writeUInt8(byteBuffer, sampleInfoSize);
+ }
+ } else {
+ IsoTypeWriter.writeUInt32(byteBuffer, sampleCount);
+ }
+ }
+
+ @Override
+ public void _parseDetails(ByteBuffer content) {
+ parseVersionAndFlags(content);
+ if ((getFlags() & 1) == 1) {
+ auxInfoType = IsoTypeReader.read4cc(content);
+ auxInfoTypeParameter = IsoTypeReader.read4cc(content);
+ }
+
+ defaultSampleInfoSize = (short) IsoTypeReader.readUInt8(content);
+ int sampleCount = l2i(IsoTypeReader.readUInt32(content));
+
+ sampleInfoSizes.clear();
+
+ for (int i = 0; i < sampleCount; i++) {
+ sampleInfoSizes.add((short) IsoTypeReader.readUInt8(content));
+ }
+ }
+
+ public String getAuxInfoType() {
+ return auxInfoType;
+ }
+
+ public void setAuxInfoType(String auxInfoType) {
+ this.auxInfoType = auxInfoType;
+ }
+
+ public String getAuxInfoTypeParameter() {
+ return auxInfoTypeParameter;
+ }
+
+ public void setAuxInfoTypeParameter(String auxInfoTypeParameter) {
+ this.auxInfoTypeParameter = auxInfoTypeParameter;
+ }
+
+ public int getDefaultSampleInfoSize() {
+ return defaultSampleInfoSize;
+ }
+
+ public void setDefaultSampleInfoSize(int defaultSampleInfoSize) {
+ assert defaultSampleInfoSize <= 255;
+ assert defaultSampleInfoSize > 0;
+ this.defaultSampleInfoSize = defaultSampleInfoSize;
+ }
+
+
+ public List getSampleInfoSizes() {
+ return sampleInfoSizes;
+ }
+
+ public void setSampleInfoSizes(List sampleInfoSizes) {
+ this.sampleInfoSizes = sampleInfoSizes;
+ }
+
+ public int getSampleCount() {
+ return sampleCount;
+ }
+
+ public void setSampleCount(int sampleCount) {
+ this.sampleCount = sampleCount;
+ }
+}
diff --git a/android-aac-enc/src/com/coremedia/iso/boxes/SampleDependencyTypeBox.java b/android-aac-enc/src/com/coremedia/iso/boxes/SampleDependencyTypeBox.java
new file mode 100644
index 000000000..bb38d8c70
--- /dev/null
+++ b/android-aac-enc/src/com/coremedia/iso/boxes/SampleDependencyTypeBox.java
@@ -0,0 +1,136 @@
+/*
+ * Copyright 2009 castLabs GmbH, Berlin
+ *
+ * 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.coremedia.iso.boxes;
+
+import com.coremedia.iso.IsoTypeReader;
+import com.coremedia.iso.IsoTypeWriter;
+import com.googlecode.mp4parser.AbstractFullBox;
+
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * aligned(8) class SampleDependencyTypeBox
+ * extends FullBox('sdtp', version = 0, 0) {
+ * for (i=0; i < sample_count; i++){
+ * unsigned int(2) reserved = 0;
+ * unsigned int(2) sample_depends_on;
+ * unsigned int(2) sample_is_depended_on;
+ * unsigned int(2) sample_has_redundancy;
+ * }
+ * }
+ */
+public class SampleDependencyTypeBox extends AbstractFullBox {
+ public static final String TYPE = "sdtp";
+
+ private List entries = new ArrayList();
+
+ public static class Entry {
+
+ public Entry(int value) {
+ this.value = value;
+ }
+
+ private int value;
+
+
+ public int getReserved() {
+ return (value >> 6) & 0x03;
+ }
+
+ public void setReserved(int res) {
+ value = (res & 0x03) << 6 | value & 0x3f;
+ }
+
+ public int getSampleDependsOn() {
+ return (value >> 4) & 0x03;
+ }
+
+ public void setSampleDependsOn(int sdo) {
+ value = (sdo & 0x03) << 4 | value & 0xcf;
+ }
+
+ public int getSampleIsDependentOn() {
+ return (value >> 2) & 0x03;
+ }
+
+ public void setSampleIsDependentOn(int sido) {
+ value = (sido & 0x03) << 2 | value & 0xf3;
+ }
+
+ public int getSampleHasRedundancy() {
+ return value & 0x03;
+ }
+
+ public void setSampleHasRedundancy(int shr) {
+ value = shr & 0x03 | value & 0xfc;
+ }
+
+ @Override
+ public String toString() {
+ return "Entry{" +
+ "reserved=" + getReserved() +
+ ", sampleDependsOn=" + getSampleDependsOn() +
+ ", sampleIsDependentOn=" + getSampleIsDependentOn() +
+ ", sampleHasRedundancy=" + getSampleHasRedundancy() +
+ '}';
+ }
+ }
+
+ public SampleDependencyTypeBox() {
+ super(TYPE);
+ }
+
+ @Override
+ protected long getContentSize() {
+ return 4 + entries.size();
+ }
+
+ @Override
+ protected void getContent(ByteBuffer byteBuffer) {
+ writeVersionAndFlags(byteBuffer);
+ for (Entry entry : entries) {
+ IsoTypeWriter.writeUInt8(byteBuffer, entry.value);
+ }
+ }
+
+ @Override
+ public void _parseDetails(ByteBuffer content) {
+ parseVersionAndFlags(content);
+ while (content.remaining() > 0) {
+ entries.add(new Entry(IsoTypeReader.readUInt8(content)));
+ }
+ }
+
+ public List getEntries() {
+ return entries;
+ }
+
+ public void setEntries(List entries) {
+ this.entries = entries;
+ }
+
+ @Override
+ public String toString() {
+ final StringBuilder sb = new StringBuilder();
+ sb.append("SampleDependencyTypeBox");
+ sb.append("{entries=").append(entries);
+ sb.append('}');
+ return sb.toString();
+ }
+}
diff --git a/android-aac-enc/src/com/coremedia/iso/boxes/SampleDescriptionBox.java b/android-aac-enc/src/com/coremedia/iso/boxes/SampleDescriptionBox.java
new file mode 100644
index 000000000..662fa9948
--- /dev/null
+++ b/android-aac-enc/src/com/coremedia/iso/boxes/SampleDescriptionBox.java
@@ -0,0 +1,81 @@
+/*
+ * 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.coremedia.iso.boxes;
+
+import com.coremedia.iso.IsoTypeWriter;
+import com.coremedia.iso.boxes.sampleentry.SampleEntry;
+import com.googlecode.mp4parser.FullContainerBox;
+
+import java.nio.ByteBuffer;
+
+/**
+ * The sample description table gives detailed information about the coding type used, and any initialization
+ * information needed for that coding.
+ * The information stored in the sample description box after the entry-count is both track-type specific as
+ * documented here, and can also have variants within a track type (e.g. different codings may use different
+ * specific information after some common fields, even within a video track).
+ * For video tracks, a VisualSampleEntry is used; for audio tracks, an AudioSampleEntry. Hint tracks use an
+ * entry format specific to their protocol, with an appropriate name. Timed Text tracks use a TextSampleEntry
+ * For hint tracks, the sample description contains appropriate declarative data for the streaming protocol being
+ * used, and the format of the hint track. The definition of the sample description is specific to the protocol.
+ * Multiple descriptions may be used within a track.
+ * The 'protocol' and 'codingname' fields are registered identifiers that uniquely identify the streaming protocol or
+ * compression format decoder to be used. A given protocol or codingname may have optional or required
+ * extensions to the sample description (e.g. codec initialization parameters). All such extensions shall be within
+ * boxes; these boxes occur after the required fields. Unrecognized boxes shall be ignored.
+ *
+ * Defined in ISO/IEC 14496-12
+ *
+ * @see com.coremedia.iso.boxes.sampleentry.VisualSampleEntry
+ * @see com.coremedia.iso.boxes.sampleentry.TextSampleEntry
+ * @see com.coremedia.iso.boxes.sampleentry.AudioSampleEntry
+ */
+public class SampleDescriptionBox extends FullContainerBox {
+ public static final String TYPE = "stsd";
+
+ public SampleDescriptionBox() {
+ super(TYPE);
+ }
+
+ @Override
+ protected long getContentSize() {
+ return super.getContentSize() + 4;
+ }
+
+ @Override
+ public void _parseDetails(ByteBuffer content) {
+ parseVersionAndFlags(content);
+ content.get(new byte[4]);
+ parseChildBoxes(content);
+ }
+
+ @Override
+ protected void getContent(ByteBuffer byteBuffer) {
+ writeVersionAndFlags(byteBuffer);
+ IsoTypeWriter.writeUInt32(byteBuffer, boxes.size());
+ writeChildBoxes(byteBuffer);
+ }
+
+ public SampleEntry getSampleEntry() {
+ for (Box box : boxes) {
+ if (box instanceof SampleEntry) {
+ return (SampleEntry) box;
+ }
+ }
+ return null;
+ }
+}
diff --git a/android-aac-enc/src/com/coremedia/iso/boxes/SampleSizeBox.java b/android-aac-enc/src/com/coremedia/iso/boxes/SampleSizeBox.java
new file mode 100644
index 000000000..3bc1df080
--- /dev/null
+++ b/android-aac-enc/src/com/coremedia/iso/boxes/SampleSizeBox.java
@@ -0,0 +1,121 @@
+/*
+ * 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.coremedia.iso.boxes;
+
+
+import com.coremedia.iso.IsoTypeReader;
+import com.coremedia.iso.IsoTypeWriter;
+import com.googlecode.mp4parser.AbstractFullBox;
+
+import java.nio.ByteBuffer;
+
+import static com.googlecode.mp4parser.util.CastUtils.l2i;
+
+/**
+ * This box containes the sample count and a table giving the size in bytes of each sample.
+ * Defined in ISO/IEC 14496-12.
+ */
+public class SampleSizeBox extends AbstractFullBox {
+ private long sampleSize;
+ private long[] sampleSizes = new long[0];
+ public static final String TYPE = "stsz";
+ int sampleCount;
+
+ public SampleSizeBox() {
+ super(TYPE);
+ }
+
+ /**
+ * Returns the field sample size.
+ * If sampleSize > 0 every sample has the same size.
+ * If sampleSize == 0 the samples have different size as stated in the sampleSizes field.
+ *
+ * @return the sampleSize field
+ */
+ public long getSampleSize() {
+ return sampleSize;
+ }
+
+ public void setSampleSize(long sampleSize) {
+ this.sampleSize = sampleSize;
+ }
+
+
+ public long getSampleSizeAtIndex(int index) {
+ if (sampleSize > 0) {
+ return sampleSize;
+ } else {
+ return sampleSizes[index];
+ }
+ }
+
+ public long getSampleCount() {
+ if (sampleSize > 0) {
+ return sampleCount;
+ } else {
+ return sampleSizes.length;
+ }
+
+ }
+
+ public long[] getSampleSizes() {
+ return sampleSizes;
+ }
+
+ public void setSampleSizes(long[] sampleSizes) {
+ this.sampleSizes = sampleSizes;
+ }
+
+ protected long getContentSize() {
+ return 12 + (sampleSize == 0 ? sampleSizes.length * 4 : 0);
+ }
+
+ @Override
+ public void _parseDetails(ByteBuffer content) {
+ parseVersionAndFlags(content);
+ sampleSize = IsoTypeReader.readUInt32(content);
+ sampleCount = l2i(IsoTypeReader.readUInt32(content));
+
+ if (sampleSize == 0) {
+ sampleSizes = new long[(int) sampleCount];
+
+ for (int i = 0; i < sampleCount; i++) {
+ sampleSizes[i] = IsoTypeReader.readUInt32(content);
+ }
+ }
+ }
+
+ @Override
+ protected void getContent(ByteBuffer byteBuffer) {
+ writeVersionAndFlags(byteBuffer);
+ IsoTypeWriter.writeUInt32(byteBuffer, sampleSize);
+
+ if (sampleSize == 0) {
+ IsoTypeWriter.writeUInt32(byteBuffer, sampleSizes.length);
+ for (long sampleSize1 : sampleSizes) {
+ IsoTypeWriter.writeUInt32(byteBuffer, sampleSize1);
+ }
+ } else {
+ IsoTypeWriter.writeUInt32(byteBuffer, sampleCount);
+ }
+
+ }
+
+ public String toString() {
+ return "SampleSizeBox[sampleSize=" + getSampleSize() + ";sampleCount=" + getSampleCount() + "]";
+ }
+}
diff --git a/android-aac-enc/src/com/coremedia/iso/boxes/SampleTableBox.java b/android-aac-enc/src/com/coremedia/iso/boxes/SampleTableBox.java
new file mode 100644
index 000000000..33968b350
--- /dev/null
+++ b/android-aac-enc/src/com/coremedia/iso/boxes/SampleTableBox.java
@@ -0,0 +1,124 @@
+/*
+ * 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.coremedia.iso.boxes;
+
+import com.googlecode.mp4parser.AbstractContainerBox;
+
+/**
+ * The sample table contains all the time and data indexing of the media samples in a track. Using the tables
+ * here, it is possible to locate samples in time, determine their type (e.g. I-frame or not), and determine their
+ * size, container, and offset into that container.
+ * If the track that contains the Sample Table Box references no data, then the Sample Table Box does not need
+ * to contain any sub-boxes (this is not a very useful media track).
+ * If the track that the Sample Table Box is contained in does reference data, then the following sub-boxes are
+ * required: Sample Description, Sample Size, Sample To Chunk, and Chunk Offset. Further, the Sample
+ * Description Box shall contain at least one entry. A Sample Description Box is required because it contains the
+ * data reference index field which indicates which Data Reference Box to use to retrieve the media samples.
+ * Without the Sample Description, it is not possible to determine where the media samples are stored. The Sync
+ * Sample Box is optional. If the Sync Sample Box is not present, all samples are sync samples.
+ * Annex A provides a narrative description of random access using the structures defined in the Sample Table
+ * Box.
+ */
+public class SampleTableBox extends AbstractContainerBox {
+ public static final String TYPE = "stbl";
+
+ public SampleTableBox() {
+ super(TYPE);
+ }
+
+ public SampleDescriptionBox getSampleDescriptionBox() {
+ for (Box box : boxes) {
+ if (box instanceof SampleDescriptionBox) {
+ return (SampleDescriptionBox) box;
+ }
+ }
+ return null;
+ }
+
+ public SampleSizeBox getSampleSizeBox() {
+ for (Box box : boxes) {
+ if (box instanceof SampleSizeBox) {
+ return (SampleSizeBox) box;
+ }
+ }
+ return null;
+ }
+
+ public SampleToChunkBox getSampleToChunkBox() {
+ for (Box box : boxes) {
+ if (box instanceof SampleToChunkBox) {
+ return (SampleToChunkBox) box;
+ }
+ }
+ return null;
+ }
+
+ public ChunkOffsetBox getChunkOffsetBox() {
+ for (Box box : boxes) {
+ if (box instanceof ChunkOffsetBox) {
+ return (ChunkOffsetBox) box;
+ }
+ }
+ return null;
+ }
+
+ public void setChunkOffsetBox(ChunkOffsetBox b) {
+ for (int i = 0; i < boxes.size(); i++) {
+ Box box = boxes.get(i);
+ if (box instanceof ChunkOffsetBox) {
+ boxes.set(i, b);
+ }
+ }
+ }
+
+ public TimeToSampleBox getTimeToSampleBox() {
+ for (Box box : boxes) {
+ if (box instanceof TimeToSampleBox) {
+ return (TimeToSampleBox) box;
+ }
+ }
+ return null;
+ }
+
+ public SyncSampleBox getSyncSampleBox() {
+ for (Box box : boxes) {
+ if (box instanceof SyncSampleBox) {
+ return (SyncSampleBox) box;
+ }
+ }
+ return null;
+ }
+
+ public CompositionTimeToSample getCompositionTimeToSample() {
+ for (Box box : boxes) {
+ if (box instanceof CompositionTimeToSample) {
+ return (CompositionTimeToSample) box;
+ }
+ }
+ return null;
+ }
+
+ public SampleDependencyTypeBox getSampleDependencyTypeBox() {
+ for (Box box : boxes) {
+ if (box instanceof SampleDependencyTypeBox) {
+ return (SampleDependencyTypeBox) box;
+ }
+ }
+ return null;
+ }
+
+}
diff --git a/android-aac-enc/src/com/coremedia/iso/boxes/SampleToChunkBox.java b/android-aac-enc/src/com/coremedia/iso/boxes/SampleToChunkBox.java
new file mode 100644
index 000000000..593504d38
--- /dev/null
+++ b/android-aac-enc/src/com/coremedia/iso/boxes/SampleToChunkBox.java
@@ -0,0 +1,156 @@
+/*
+ * 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.coremedia.iso.boxes;
+
+import com.coremedia.iso.IsoTypeReader;
+import com.coremedia.iso.IsoTypeWriter;
+import com.googlecode.mp4parser.AbstractFullBox;
+
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+
+import static com.googlecode.mp4parser.util.CastUtils.l2i;
+
+/**
+ * Samples within the media data are grouped into chunks. Chunks can be of different sizes, and the
+ * samples within a chunk can have different sizes. This table can be used to find the chunk that
+ * contains a sample, its position, and the associated sample description. Defined in ISO/IEC 14496-12.
+ */
+public class SampleToChunkBox extends AbstractFullBox {
+ List entries = Collections.emptyList();
+
+ public static final String TYPE = "stsc";
+
+ public SampleToChunkBox() {
+ super(TYPE);
+ }
+
+ public List getEntries() {
+ return entries;
+ }
+
+ public void setEntries(List entries) {
+ this.entries = entries;
+ }
+
+ protected long getContentSize() {
+ return entries.size() * 12 + 8;
+ }
+
+ @Override
+ public void _parseDetails(ByteBuffer content) {
+ parseVersionAndFlags(content);
+
+ int entryCount = l2i(IsoTypeReader.readUInt32(content));
+ entries = new ArrayList(entryCount);
+ for (int i = 0; i < entryCount; i++) {
+ entries.add(new Entry(
+ IsoTypeReader.readUInt32(content),
+ IsoTypeReader.readUInt32(content),
+ IsoTypeReader.readUInt32(content)));
+ }
+ }
+
+ @Override
+ protected void getContent(ByteBuffer byteBuffer) {
+ writeVersionAndFlags(byteBuffer);
+ IsoTypeWriter.writeUInt32(byteBuffer, entries.size());
+ for (Entry entry : entries) {
+ IsoTypeWriter.writeUInt32(byteBuffer, entry.getFirstChunk());
+ IsoTypeWriter.writeUInt32(byteBuffer, entry.getSamplesPerChunk());
+ IsoTypeWriter.writeUInt32(byteBuffer, entry.getSampleDescriptionIndex());
+ }
+ }
+
+ public String toString() {
+ return "SampleToChunkBox[entryCount=" + entries.size() + "]";
+ }
+
+ /**
+ * Decompresses the list of entries and returns the number of samples per chunk for
+ * every single chunk.
+ *
+ * @param chunkCount overall number of chunks
+ * @return number of samples per chunk
+ */
+ public long[] blowup(int chunkCount) {
+ long[] numberOfSamples = new long[chunkCount];
+ int j = 0;
+ List sampleToChunkEntries = new LinkedList(entries);
+ Collections.reverse(sampleToChunkEntries);
+ Iterator iterator = sampleToChunkEntries.iterator();
+ SampleToChunkBox.Entry currentEntry = iterator.next();
+
+ for (int i = numberOfSamples.length; i > 1; i--) {
+ numberOfSamples[i - 1] = currentEntry.getSamplesPerChunk();
+ if (i == currentEntry.getFirstChunk()) {
+ currentEntry = iterator.next();
+ }
+ }
+ numberOfSamples[0] = currentEntry.getSamplesPerChunk();
+ return numberOfSamples;
+ }
+
+ public static class Entry {
+ long firstChunk;
+ long samplesPerChunk;
+ long sampleDescriptionIndex;
+
+ public Entry(long firstChunk, long samplesPerChunk, long sampleDescriptionIndex) {
+ this.firstChunk = firstChunk;
+ this.samplesPerChunk = samplesPerChunk;
+ this.sampleDescriptionIndex = sampleDescriptionIndex;
+ }
+
+ public long getFirstChunk() {
+ return firstChunk;
+ }
+
+ public void setFirstChunk(long firstChunk) {
+ this.firstChunk = firstChunk;
+ }
+
+ public long getSamplesPerChunk() {
+ return samplesPerChunk;
+ }
+
+ public void setSamplesPerChunk(long samplesPerChunk) {
+ this.samplesPerChunk = samplesPerChunk;
+ }
+
+ public long getSampleDescriptionIndex() {
+ return sampleDescriptionIndex;
+ }
+
+ public void setSampleDescriptionIndex(long sampleDescriptionIndex) {
+ this.sampleDescriptionIndex = sampleDescriptionIndex;
+ }
+
+ @Override
+ public String toString() {
+ return "Entry{" +
+ "firstChunk=" + firstChunk +
+ ", samplesPerChunk=" + samplesPerChunk +
+ ", sampleDescriptionIndex=" + sampleDescriptionIndex +
+ '}';
+ }
+ }
+}
diff --git a/android-aac-enc/src/com/coremedia/iso/boxes/SampleToGroupBox.java b/android-aac-enc/src/com/coremedia/iso/boxes/SampleToGroupBox.java
new file mode 100644
index 000000000..612b8403d
--- /dev/null
+++ b/android-aac-enc/src/com/coremedia/iso/boxes/SampleToGroupBox.java
@@ -0,0 +1,122 @@
+package com.coremedia.iso.boxes;
+
+import com.coremedia.iso.IsoTypeReader;
+import com.coremedia.iso.IsoTypeWriter;
+import com.googlecode.mp4parser.AbstractFullBox;
+
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * aligned(8) class SampleToGroupBox
+ * extends FullBox('sbgp', version = 0, 0)
+ * {
+ * unsigned int(32) grouping_type;
+ * unsigned int(32) entry_count;
+ * for (i=1; i <= entry_count; i++)
+ * {
+ * unsigned int(32) sample_count;
+ * unsigned int(32) group_description_index;
+ * }
+ * }
+ */
+public class SampleToGroupBox extends AbstractFullBox {
+ public static final String TYPE = "sbgp";
+ private long groupingType;
+ private long entryCount;
+ private long groupingTypeParameter;
+ private List entries = new ArrayList();
+
+ public SampleToGroupBox() {
+ super(TYPE);
+ }
+
+ @Override
+ protected long getContentSize() {
+ return 12 + entryCount * 8;
+ }
+
+ public long getGroupingTypeParameter() {
+ return groupingTypeParameter;
+ }
+
+ /**
+ * Usage of this parameter requires version == 1. The version must be set manually.
+ */
+ public void setGroupingTypeParameter(long groupingTypeParameter) {
+ this.groupingTypeParameter = groupingTypeParameter;
+ }
+
+ public List getEntries() {
+ return entries;
+ }
+
+ public void setEntries(List entries) {
+ this.entries = entries;
+ }
+
+ public long getGroupingType() {
+ return groupingType;
+ }
+
+
+ public void setGroupingType(long groupingType) {
+ this.groupingType = groupingType;
+ }
+
+ @Override
+ public void _parseDetails(ByteBuffer content) {
+ parseVersionAndFlags(content);
+ groupingType = IsoTypeReader.readUInt32(content);
+ if (getVersion() == 1) {
+ groupingTypeParameter = IsoTypeReader.readUInt32(content);
+ } else {
+ groupingTypeParameter = -1;
+ }
+ entryCount = IsoTypeReader.readUInt32(content);
+
+ for (int i = 0; i < entryCount; i++) {
+ Entry entry = new Entry();
+ entry.setSampleCount(IsoTypeReader.readUInt32(content));
+ entry.setGroupDescriptionIndex(IsoTypeReader.readUInt32(content));
+ entries.add(entry);
+ }
+ }
+
+ @Override
+ protected void getContent(ByteBuffer byteBuffer) {
+ writeVersionAndFlags(byteBuffer);
+
+ IsoTypeWriter.writeUInt32(byteBuffer, groupingType);
+ if (getVersion() == 1) {
+ IsoTypeWriter.writeUInt32(byteBuffer, groupingTypeParameter);
+ }
+ IsoTypeWriter.writeUInt32(byteBuffer, entryCount);
+ for (Entry entry : entries) {
+ IsoTypeWriter.writeUInt32(byteBuffer, entry.getSampleCount());
+ IsoTypeWriter.writeUInt32(byteBuffer, entry.getGroupDescriptionIndex());
+ }
+ }
+
+ public static class Entry {
+ private long sampleCount;
+ private long groupDescriptionIndex;
+
+ public long getSampleCount() {
+ return sampleCount;
+ }
+
+ public void setSampleCount(long sampleCount) {
+ this.sampleCount = sampleCount;
+ }
+
+ public long getGroupDescriptionIndex() {
+ return groupDescriptionIndex;
+ }
+
+ public void setGroupDescriptionIndex(long groupDescriptionIndex) {
+ this.groupDescriptionIndex = groupDescriptionIndex;
+ }
+ }
+}
diff --git a/android-aac-enc/src/com/coremedia/iso/boxes/SchemeInformationBox.java b/android-aac-enc/src/com/coremedia/iso/boxes/SchemeInformationBox.java
new file mode 100644
index 000000000..5e3565e4c
--- /dev/null
+++ b/android-aac-enc/src/com/coremedia/iso/boxes/SchemeInformationBox.java
@@ -0,0 +1,33 @@
+/*
+ * 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.coremedia.iso.boxes;
+
+import com.googlecode.mp4parser.AbstractContainerBox;
+
+/**
+ * The Scheme Information Box is a container box that is only interpreted by the scheme beeing used.
+ * Any information the encryption system needs is stored here. The content of this box is a series of
+ * boxexes whose type annd format are defined by the scheme declared in the {@link com.coremedia.iso.boxes.SchemeTypeBox}.
+ */
+public class SchemeInformationBox extends AbstractContainerBox {
+ public static final String TYPE = "schi";
+
+ public SchemeInformationBox() {
+ super(TYPE);
+ }
+
+}
diff --git a/android-aac-enc/src/com/coremedia/iso/boxes/SchemeTypeBox.java b/android-aac-enc/src/com/coremedia/iso/boxes/SchemeTypeBox.java
new file mode 100644
index 000000000..ed517da2b
--- /dev/null
+++ b/android-aac-enc/src/com/coremedia/iso/boxes/SchemeTypeBox.java
@@ -0,0 +1,101 @@
+/*
+ * 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.coremedia.iso.boxes;
+
+import com.coremedia.iso.IsoFile;
+import com.coremedia.iso.IsoTypeReader;
+import com.coremedia.iso.IsoTypeWriter;
+import com.coremedia.iso.Utf8;
+import com.googlecode.mp4parser.AbstractFullBox;
+
+import java.nio.ByteBuffer;
+
+/**
+ * The Scheme Type Box identifies the protection scheme. Resides in a Protection Scheme Information Box or
+ * an SRTP Process Box.
+ *
+ * @see com.coremedia.iso.boxes.SchemeInformationBox
+ */
+public class SchemeTypeBox extends AbstractFullBox {
+ public static final String TYPE = "schm";
+ String schemeType = " ";
+ long schemeVersion;
+ String schemeUri = null;
+
+ public SchemeTypeBox() {
+ super(TYPE);
+ }
+
+ public String getSchemeType() {
+ return schemeType;
+ }
+
+ public long getSchemeVersion() {
+ return schemeVersion;
+ }
+
+ public String getSchemeUri() {
+ return schemeUri;
+ }
+
+ public void setSchemeType(String schemeType) {
+ assert schemeType != null && schemeType.length() == 4 : "SchemeType may not be null or not 4 bytes long";
+ this.schemeType = schemeType;
+ }
+
+ public void setSchemeVersion(int schemeVersion) {
+ this.schemeVersion = schemeVersion;
+ }
+
+ public void setSchemeUri(String schemeUri) {
+ this.schemeUri = schemeUri;
+ }
+
+ protected long getContentSize() {
+ return 12 + (((getFlags() & 1) == 1) ? Utf8.utf8StringLengthInBytes(schemeUri) + 1 : 0);
+ }
+
+ @Override
+ public void _parseDetails(ByteBuffer content) {
+ parseVersionAndFlags(content);
+ schemeType = IsoTypeReader.read4cc(content);
+ schemeVersion = IsoTypeReader.readUInt32(content);
+ if ((getFlags() & 1) == 1) {
+ schemeUri = IsoTypeReader.readString(content);
+ }
+ }
+
+ @Override
+ protected void getContent(ByteBuffer byteBuffer) {
+ writeVersionAndFlags(byteBuffer);
+ byteBuffer.put(IsoFile.fourCCtoBytes(schemeType));
+ IsoTypeWriter.writeUInt32(byteBuffer, schemeVersion);
+ if ((getFlags() & 1) == 1) {
+ byteBuffer.put(Utf8.convert(schemeUri));
+ }
+ }
+
+ public String toString() {
+ StringBuilder buffer = new StringBuilder();
+ buffer.append("Schema Type Box[");
+ buffer.append("schemeUri=").append(schemeUri).append("; ");
+ buffer.append("schemeType=").append(schemeType).append("; ");
+ buffer.append("schemeVersion=").append(schemeUri).append("; ");
+ buffer.append("]");
+ return buffer.toString();
+ }
+}
diff --git a/android-aac-enc/src/com/coremedia/iso/boxes/SoundMediaHeaderBox.java b/android-aac-enc/src/com/coremedia/iso/boxes/SoundMediaHeaderBox.java
new file mode 100644
index 000000000..c5fb88d2c
--- /dev/null
+++ b/android-aac-enc/src/com/coremedia/iso/boxes/SoundMediaHeaderBox.java
@@ -0,0 +1,58 @@
+/*
+ * 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.coremedia.iso.boxes;
+
+import com.coremedia.iso.IsoTypeReader;
+import com.coremedia.iso.IsoTypeWriter;
+
+import java.nio.ByteBuffer;
+
+public class SoundMediaHeaderBox extends AbstractMediaHeaderBox {
+
+ public static final String TYPE = "smhd";
+ private float balance;
+
+ public SoundMediaHeaderBox() {
+ super(TYPE);
+ }
+
+ public float getBalance() {
+ return balance;
+ }
+
+ protected long getContentSize() {
+ return 8;
+ }
+
+ @Override
+ public void _parseDetails(ByteBuffer content) {
+ parseVersionAndFlags(content);
+ balance = IsoTypeReader.readFixedPoint88(content);
+ IsoTypeReader.readUInt16(content);
+ }
+
+ @Override
+ protected void getContent(ByteBuffer byteBuffer) {
+ writeVersionAndFlags(byteBuffer);
+ IsoTypeWriter.writeFixedPont88(byteBuffer, balance);
+ IsoTypeWriter.writeUInt16(byteBuffer, 0);
+ }
+
+ public String toString() {
+ return "SoundMediaHeaderBox[balance=" + getBalance() + "]";
+ }
+}
diff --git a/android-aac-enc/src/com/coremedia/iso/boxes/StaticChunkOffsetBox.java b/android-aac-enc/src/com/coremedia/iso/boxes/StaticChunkOffsetBox.java
new file mode 100644
index 000000000..efcdd1455
--- /dev/null
+++ b/android-aac-enc/src/com/coremedia/iso/boxes/StaticChunkOffsetBox.java
@@ -0,0 +1,71 @@
+/*
+ * 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.coremedia.iso.boxes;
+
+import com.coremedia.iso.IsoTypeReader;
+import com.coremedia.iso.IsoTypeWriter;
+
+import java.nio.ByteBuffer;
+
+import static com.googlecode.mp4parser.util.CastUtils.l2i;
+
+/**
+ * The chunk offset table gives the index of each chunk into the containing file. Defined in ISO/IEC 14496-12.
+ */
+public class StaticChunkOffsetBox extends ChunkOffsetBox {
+ public static final String TYPE = "stco";
+
+ private long[] chunkOffsets = new long[0];
+
+ public StaticChunkOffsetBox() {
+ super(TYPE);
+ }
+
+ public long[] getChunkOffsets() {
+ return chunkOffsets;
+ }
+
+ protected long getContentSize() {
+ return 8 + chunkOffsets.length * 4;
+ }
+
+ public void setChunkOffsets(long[] chunkOffsets) {
+ this.chunkOffsets = chunkOffsets;
+ }
+
+ @Override
+ public void _parseDetails(ByteBuffer content) {
+ parseVersionAndFlags(content);
+ int entryCount = l2i(IsoTypeReader.readUInt32(content));
+ chunkOffsets = new long[entryCount];
+ for (int i = 0; i < entryCount; i++) {
+ chunkOffsets[i] = IsoTypeReader.readUInt32(content);
+ }
+
+ }
+
+ @Override
+ protected void getContent(ByteBuffer byteBuffer) {
+ writeVersionAndFlags(byteBuffer);
+ IsoTypeWriter.writeUInt32(byteBuffer, chunkOffsets.length);
+ for (long chunkOffset : chunkOffsets) {
+ IsoTypeWriter.writeUInt32(byteBuffer, chunkOffset);
+ }
+ }
+
+
+}
diff --git a/android-aac-enc/src/com/coremedia/iso/boxes/SubSampleInformationBox.java b/android-aac-enc/src/com/coremedia/iso/boxes/SubSampleInformationBox.java
new file mode 100644
index 000000000..e30aaccf3
--- /dev/null
+++ b/android-aac-enc/src/com/coremedia/iso/boxes/SubSampleInformationBox.java
@@ -0,0 +1,208 @@
+package com.coremedia.iso.boxes;
+
+import com.coremedia.iso.IsoTypeReader;
+import com.coremedia.iso.IsoTypeWriter;
+import com.googlecode.mp4parser.AbstractFullBox;
+
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
+import java.util.List;
+
+import static com.googlecode.mp4parser.util.CastUtils.l2i;
+
+/**
+ * aligned(8) class SubSampleInformationBox
+ * extends FullBox('subs', version, 0) {
+ * unsigned int(32) entry_count;
+ * int i,j;
+ * for (i=0; i < entry_count; i++) {
+ * unsigned int(32) sample_delta;
+ * unsigned int(16) subsample_count;
+ * if (subsample_count > 0) {
+ * for (j=0; j < subsample_count; j++) {
+ * if(version == 1)
+ * {
+ * unsigned int(32) subsample_size;
+ * }
+ * else
+ * {
+ * unsigned int(16) subsample_size;
+ * }
+ * unsigned int(8) subsample_priority;
+ * unsigned int(8) discardable;
+ * unsigned int(32) reserved = 0;
+ * }
+ * }
+ * }
+ * }
+ */
+public class SubSampleInformationBox extends AbstractFullBox {
+ public static final String TYPE = "subs";
+
+ private long entryCount;
+ private List entries = new ArrayList();
+
+ public SubSampleInformationBox() {
+ super(TYPE);
+ }
+
+ public List getEntries() {
+ return entries;
+ }
+
+ public void setEntries(List entries) {
+ this.entries = entries;
+ entryCount = entries.size();
+ }
+
+ @Override
+ protected long getContentSize() {
+ long entries = 8 + ((4 + 2) * entryCount);
+ int subsampleEntries = 0;
+ for (SampleEntry sampleEntry : this.entries) {
+ subsampleEntries += sampleEntry.getSubsampleCount() * (((getVersion() == 1) ? 4 : 2) + 1 + 1 + 4);
+ }
+ return entries + subsampleEntries;
+ }
+
+ @Override
+ public void _parseDetails(ByteBuffer content) {
+ parseVersionAndFlags(content);
+
+ entryCount = IsoTypeReader.readUInt32(content);
+
+ for (int i = 0; i < entryCount; i++) {
+ SampleEntry sampleEntry = new SampleEntry();
+ sampleEntry.setSampleDelta(IsoTypeReader.readUInt32(content));
+ int subsampleCount = IsoTypeReader.readUInt16(content);
+ for (int j = 0; j < subsampleCount; j++) {
+ SampleEntry.SubsampleEntry subsampleEntry = new SampleEntry.SubsampleEntry();
+ subsampleEntry.setSubsampleSize(getVersion() == 1 ? IsoTypeReader.readUInt32(content) : IsoTypeReader.readUInt16(content));
+ subsampleEntry.setSubsamplePriority(IsoTypeReader.readUInt8(content));
+ subsampleEntry.setDiscardable(IsoTypeReader.readUInt8(content));
+ subsampleEntry.setReserved(IsoTypeReader.readUInt32(content));
+ sampleEntry.addSubsampleEntry(subsampleEntry);
+ }
+ entries.add(sampleEntry);
+ }
+
+ }
+
+ @Override
+ protected void getContent(ByteBuffer byteBuffer) {
+ writeVersionAndFlags(byteBuffer);
+ IsoTypeWriter.writeUInt32(byteBuffer, entries.size());
+ for (SampleEntry sampleEntry : entries) {
+ IsoTypeWriter.writeUInt32(byteBuffer, sampleEntry.getSampleDelta());
+ IsoTypeWriter.writeUInt16(byteBuffer, sampleEntry.getSubsampleCount());
+ List subsampleEntries = sampleEntry.getSubsampleEntries();
+ for (SampleEntry.SubsampleEntry subsampleEntry : subsampleEntries) {
+ if (getVersion() == 1) {
+ IsoTypeWriter.writeUInt32(byteBuffer, subsampleEntry.getSubsampleSize());
+ } else {
+ IsoTypeWriter.writeUInt16(byteBuffer, l2i(subsampleEntry.getSubsampleSize()));
+ }
+ IsoTypeWriter.writeUInt8(byteBuffer, subsampleEntry.getSubsamplePriority());
+ IsoTypeWriter.writeUInt8(byteBuffer, subsampleEntry.getDiscardable());
+ IsoTypeWriter.writeUInt32(byteBuffer, subsampleEntry.getReserved());
+ }
+ }
+ }
+
+ @Override
+ public String toString() {
+ return "SubSampleInformationBox{" +
+ "entryCount=" + entryCount +
+ ", entries=" + entries +
+ '}';
+ }
+
+ public static class SampleEntry {
+ private long sampleDelta;
+ private int subsampleCount;
+ private List subsampleEntries = new ArrayList();
+
+ public long getSampleDelta() {
+ return sampleDelta;
+ }
+
+ public void setSampleDelta(long sampleDelta) {
+ this.sampleDelta = sampleDelta;
+ }
+
+ public int getSubsampleCount() {
+ return subsampleCount;
+ }
+
+ public void setSubsampleCount(int subsampleCount) {
+ this.subsampleCount = subsampleCount;
+ }
+
+ public List getSubsampleEntries() {
+ return subsampleEntries;
+ }
+
+ public void addSubsampleEntry(SubsampleEntry subsampleEntry) {
+ subsampleEntries.add(subsampleEntry);
+ subsampleCount++;
+ }
+
+ public static class SubsampleEntry {
+ private long subsampleSize;
+ private int subsamplePriority;
+ private int discardable;
+ private long reserved;
+
+ public long getSubsampleSize() {
+ return subsampleSize;
+ }
+
+ public void setSubsampleSize(long subsampleSize) {
+ this.subsampleSize = subsampleSize;
+ }
+
+ public int getSubsamplePriority() {
+ return subsamplePriority;
+ }
+
+ public void setSubsamplePriority(int subsamplePriority) {
+ this.subsamplePriority = subsamplePriority;
+ }
+
+ public int getDiscardable() {
+ return discardable;
+ }
+
+ public void setDiscardable(int discardable) {
+ this.discardable = discardable;
+ }
+
+ public long getReserved() {
+ return reserved;
+ }
+
+ public void setReserved(long reserved) {
+ this.reserved = reserved;
+ }
+
+ @Override
+ public String toString() {
+ return "SubsampleEntry{" +
+ "subsampleSize=" + subsampleSize +
+ ", subsamplePriority=" + subsamplePriority +
+ ", discardable=" + discardable +
+ ", reserved=" + reserved +
+ '}';
+ }
+ }
+
+ @Override
+ public String toString() {
+ return "SampleEntry{" +
+ "sampleDelta=" + sampleDelta +
+ ", subsampleCount=" + subsampleCount +
+ ", subsampleEntries=" + subsampleEntries +
+ '}';
+ }
+ }
+}
diff --git a/android-aac-enc/src/com/coremedia/iso/boxes/SubtitleMediaHeaderBox.java b/android-aac-enc/src/com/coremedia/iso/boxes/SubtitleMediaHeaderBox.java
new file mode 100644
index 000000000..fa25a5c7b
--- /dev/null
+++ b/android-aac-enc/src/com/coremedia/iso/boxes/SubtitleMediaHeaderBox.java
@@ -0,0 +1,30 @@
+package com.coremedia.iso.boxes;
+
+import java.nio.ByteBuffer;
+
+public class SubtitleMediaHeaderBox extends AbstractMediaHeaderBox {
+
+ public static final String TYPE = "sthd";
+
+ public SubtitleMediaHeaderBox() {
+ super(TYPE);
+ }
+
+ protected long getContentSize() {
+ return 4;
+ }
+
+ @Override
+ public void _parseDetails(ByteBuffer content) {
+ parseVersionAndFlags(content);
+ }
+
+ @Override
+ protected void getContent(ByteBuffer byteBuffer) {
+ writeVersionAndFlags(byteBuffer);
+ }
+
+ public String toString() {
+ return "SubtitleMediaHeaderBox";
+ }
+}
diff --git a/android-aac-enc/src/com/coremedia/iso/boxes/SyncSampleBox.java b/android-aac-enc/src/com/coremedia/iso/boxes/SyncSampleBox.java
new file mode 100644
index 000000000..5fc758b40
--- /dev/null
+++ b/android-aac-enc/src/com/coremedia/iso/boxes/SyncSampleBox.java
@@ -0,0 +1,83 @@
+/*
+ * 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.coremedia.iso.boxes;
+
+import com.coremedia.iso.IsoTypeReader;
+import com.coremedia.iso.IsoTypeWriter;
+import com.googlecode.mp4parser.AbstractFullBox;
+
+import java.nio.ByteBuffer;
+
+import static com.googlecode.mp4parser.util.CastUtils.l2i;
+
+/**
+ * This box provides a compact marking of the random access points withinthe stream. The table is arranged in
+ * strictly decreasinf order of sample number. Defined in ISO/IEC 14496-12.
+ */
+public class SyncSampleBox extends AbstractFullBox {
+ public static final String TYPE = "stss";
+
+ private long[] sampleNumber;
+
+ public SyncSampleBox() {
+ super(TYPE);
+ }
+
+ /**
+ * Gives the numbers of the samples that are random access points in the stream.
+ *
+ * @return random access sample numbers.
+ */
+ public long[] getSampleNumber() {
+ return sampleNumber;
+ }
+
+ protected long getContentSize() {
+ return sampleNumber.length * 4 + 8;
+ }
+
+ @Override
+ public void _parseDetails(ByteBuffer content) {
+ parseVersionAndFlags(content);
+ int entryCount = l2i(IsoTypeReader.readUInt32(content));
+
+ sampleNumber = new long[entryCount];
+ for (int i = 0; i < entryCount; i++) {
+ sampleNumber[i] = IsoTypeReader.readUInt32(content);
+ }
+ }
+
+ @Override
+ protected void getContent(ByteBuffer byteBuffer) {
+ writeVersionAndFlags(byteBuffer);
+
+ IsoTypeWriter.writeUInt32(byteBuffer, sampleNumber.length);
+
+ for (long aSampleNumber : sampleNumber) {
+ IsoTypeWriter.writeUInt32(byteBuffer, aSampleNumber);
+ }
+
+ }
+
+ public String toString() {
+ return "SyncSampleBox[entryCount=" + sampleNumber.length + "]";
+ }
+
+ public void setSampleNumber(long[] sampleNumber) {
+ this.sampleNumber = sampleNumber;
+ }
+}
diff --git a/android-aac-enc/src/com/coremedia/iso/boxes/TimeToSampleBox.java b/android-aac-enc/src/com/coremedia/iso/boxes/TimeToSampleBox.java
new file mode 100644
index 000000000..8f4f97e23
--- /dev/null
+++ b/android-aac-enc/src/com/coremedia/iso/boxes/TimeToSampleBox.java
@@ -0,0 +1,152 @@
+/*
+ * 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.coremedia.iso.boxes;
+
+
+import com.coremedia.iso.IsoTypeReader;
+import com.coremedia.iso.IsoTypeWriter;
+import com.googlecode.mp4parser.AbstractFullBox;
+
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import static com.googlecode.mp4parser.util.CastUtils.l2i;
+
+/**
+ * This box contains a compact version of a table that allows indexing from decoding time to sample number.
+ * Other tables give sample sizes and pointers, from the sample number. Each entry in the table gives the
+ * number of consecutive samples with the same time delta, and the delta of those samples. By adding the
+ * deltas a complete time-to-sample map may be built.
+ * The Decoding Time to Sample Box contains decode time delta's: DT(n+1) = DT(n) + STTS(n)
where STTS(n)
+ * is the (uncompressed) table entry for sample n.
+ * The sample entries are ordered by decoding time stamps; therefore the deltas are all non-negative.
+ * The DT axis has a zero origin; DT(i) = SUM(for j=0 to i-1 of delta(j))
, and the sum of all
+ * deltas gives the length of the media in the track (not mapped to the overall timescale, and not considering
+ * any edit list).
+ * The Edit List Box provides the initial CT value if it is non-empty (non-zero).
+ */
+public class TimeToSampleBox extends AbstractFullBox {
+ public static final String TYPE = "stts";
+
+ List entries = Collections.emptyList();
+
+
+ public TimeToSampleBox() {
+ super(TYPE);
+ }
+
+ protected long getContentSize() {
+ return 8 + entries.size() * 8;
+ }
+
+ @Override
+ public void _parseDetails(ByteBuffer content) {
+ parseVersionAndFlags(content);
+ int entryCount = l2i(IsoTypeReader.readUInt32(content));
+ entries = new ArrayList(entryCount);
+
+ for (int i = 0; i < entryCount; i++) {
+ entries.add(new Entry(IsoTypeReader.readUInt32(content), IsoTypeReader.readUInt32(content)));
+ }
+
+ }
+
+ @Override
+ protected void getContent(ByteBuffer byteBuffer) {
+ writeVersionAndFlags(byteBuffer);
+ IsoTypeWriter.writeUInt32(byteBuffer, entries.size());
+ for (Entry entry : entries) {
+ IsoTypeWriter.writeUInt32(byteBuffer, entry.getCount());
+ IsoTypeWriter.writeUInt32(byteBuffer, entry.getDelta());
+ }
+ }
+
+ public List getEntries() {
+ return entries;
+ }
+
+ public void setEntries(List entries) {
+ this.entries = entries;
+ }
+
+ public String toString() {
+ return "TimeToSampleBox[entryCount=" + entries.size() + "]";
+ }
+
+ public static class Entry {
+ long count;
+ long delta;
+
+ public Entry(long count, long delta) {
+ this.count = count;
+ this.delta = delta;
+ }
+
+ public long getCount() {
+ return count;
+ }
+
+ public long getDelta() {
+ return delta;
+ }
+
+ public void setCount(long count) {
+ this.count = count;
+ }
+
+ public void setDelta(long delta) {
+ this.delta = delta;
+ }
+
+ @Override
+ public String toString() {
+ return "Entry{" +
+ "count=" + count +
+ ", delta=" + delta +
+ '}';
+ }
+ }
+
+ /**
+ * Decompresses the list of entries and returns the list of decoding times.
+ *
+ * @return decoding time per sample
+ */
+ public static long[] blowupTimeToSamples(List