summaryrefslogtreecommitdiff
path: root/isoparser/src/main/java/com/googlecode/mp4parser/boxes/mp4
diff options
context:
space:
mode:
Diffstat (limited to 'isoparser/src/main/java/com/googlecode/mp4parser/boxes/mp4')
-rw-r--r--isoparser/src/main/java/com/googlecode/mp4parser/boxes/mp4/.svn/all-wcprops23
-rw-r--r--isoparser/src/main/java/com/googlecode/mp4parser/boxes/mp4/.svn/entries136
-rw-r--r--isoparser/src/main/java/com/googlecode/mp4parser/boxes/mp4/.svn/text-base/AbstractDescriptorBox.java.svn-base84
-rw-r--r--isoparser/src/main/java/com/googlecode/mp4parser/boxes/mp4/.svn/text-base/ESDescriptorBox.java.svn-base36
-rw-r--r--isoparser/src/main/java/com/googlecode/mp4parser/boxes/mp4/.svn/text-base/ObjectDescriptorBox.java.svn-base46
-rw-r--r--isoparser/src/main/java/com/googlecode/mp4parser/boxes/mp4/AbstractDescriptorBox.java84
-rw-r--r--isoparser/src/main/java/com/googlecode/mp4parser/boxes/mp4/ESDescriptorBox.java36
-rw-r--r--isoparser/src/main/java/com/googlecode/mp4parser/boxes/mp4/ObjectDescriptorBox.java46
-rw-r--r--isoparser/src/main/java/com/googlecode/mp4parser/boxes/mp4/objectdescriptors/.svn/all-wcprops107
-rw-r--r--isoparser/src/main/java/com/googlecode/mp4parser/boxes/mp4/objectdescriptors/.svn/entries606
-rw-r--r--isoparser/src/main/java/com/googlecode/mp4parser/boxes/mp4/objectdescriptors/.svn/text-base/AudioSpecificConfig.java.svn-base1176
-rw-r--r--isoparser/src/main/java/com/googlecode/mp4parser/boxes/mp4/objectdescriptors/.svn/text-base/BaseDescriptor.java.svn-base99
-rw-r--r--isoparser/src/main/java/com/googlecode/mp4parser/boxes/mp4/objectdescriptors/.svn/text-base/BitReaderBuffer.java.svn-base51
-rw-r--r--isoparser/src/main/java/com/googlecode/mp4parser/boxes/mp4/objectdescriptors/.svn/text-base/BitWriterBuffer.java.svn-base36
-rw-r--r--isoparser/src/main/java/com/googlecode/mp4parser/boxes/mp4/objectdescriptors/.svn/text-base/DecoderConfigDescriptor.java.svn-base262
-rw-r--r--isoparser/src/main/java/com/googlecode/mp4parser/boxes/mp4/objectdescriptors/.svn/text-base/DecoderSpecificInfo.java.svn-base85
-rw-r--r--isoparser/src/main/java/com/googlecode/mp4parser/boxes/mp4/objectdescriptors/.svn/text-base/Descriptor.java.svn-base39
-rw-r--r--isoparser/src/main/java/com/googlecode/mp4parser/boxes/mp4/objectdescriptors/.svn/text-base/ESDescriptor.java.svn-base376
-rw-r--r--isoparser/src/main/java/com/googlecode/mp4parser/boxes/mp4/objectdescriptors/.svn/text-base/ExtensionDescriptor.java.svn-base73
-rw-r--r--isoparser/src/main/java/com/googlecode/mp4parser/boxes/mp4/objectdescriptors/.svn/text-base/ExtensionProfileLevelDescriptor.java.svn-base51
-rw-r--r--isoparser/src/main/java/com/googlecode/mp4parser/boxes/mp4/objectdescriptors/.svn/text-base/InitialObjectDescriptor.java.svn-base136
-rw-r--r--isoparser/src/main/java/com/googlecode/mp4parser/boxes/mp4/objectdescriptors/.svn/text-base/ObjectDescriptor.java_bak.svn-base104
-rw-r--r--isoparser/src/main/java/com/googlecode/mp4parser/boxes/mp4/objectdescriptors/.svn/text-base/ObjectDescriptorBase.java.svn-base27
-rw-r--r--isoparser/src/main/java/com/googlecode/mp4parser/boxes/mp4/objectdescriptors/.svn/text-base/ObjectDescriptorFactory.java.svn-base189
-rw-r--r--isoparser/src/main/java/com/googlecode/mp4parser/boxes/mp4/objectdescriptors/.svn/text-base/ProfileLevelIndicationDescriptor.java.svn-base70
-rw-r--r--isoparser/src/main/java/com/googlecode/mp4parser/boxes/mp4/objectdescriptors/.svn/text-base/SLConfigDescriptor.java.svn-base119
-rw-r--r--isoparser/src/main/java/com/googlecode/mp4parser/boxes/mp4/objectdescriptors/.svn/text-base/UnknownDescriptor.java.svn-base42
-rw-r--r--isoparser/src/main/java/com/googlecode/mp4parser/boxes/mp4/objectdescriptors/AudioSpecificConfig.java1176
-rw-r--r--isoparser/src/main/java/com/googlecode/mp4parser/boxes/mp4/objectdescriptors/BaseDescriptor.java99
-rw-r--r--isoparser/src/main/java/com/googlecode/mp4parser/boxes/mp4/objectdescriptors/BitReaderBuffer.java51
-rw-r--r--isoparser/src/main/java/com/googlecode/mp4parser/boxes/mp4/objectdescriptors/BitWriterBuffer.java36
-rw-r--r--isoparser/src/main/java/com/googlecode/mp4parser/boxes/mp4/objectdescriptors/DecoderConfigDescriptor.java262
-rw-r--r--isoparser/src/main/java/com/googlecode/mp4parser/boxes/mp4/objectdescriptors/DecoderSpecificInfo.java85
-rw-r--r--isoparser/src/main/java/com/googlecode/mp4parser/boxes/mp4/objectdescriptors/Descriptor.java39
-rw-r--r--isoparser/src/main/java/com/googlecode/mp4parser/boxes/mp4/objectdescriptors/ESDescriptor.java376
-rw-r--r--isoparser/src/main/java/com/googlecode/mp4parser/boxes/mp4/objectdescriptors/ExtensionDescriptor.java73
-rw-r--r--isoparser/src/main/java/com/googlecode/mp4parser/boxes/mp4/objectdescriptors/ExtensionProfileLevelDescriptor.java51
-rw-r--r--isoparser/src/main/java/com/googlecode/mp4parser/boxes/mp4/objectdescriptors/InitialObjectDescriptor.java136
-rw-r--r--isoparser/src/main/java/com/googlecode/mp4parser/boxes/mp4/objectdescriptors/ObjectDescriptor.java_bak104
-rw-r--r--isoparser/src/main/java/com/googlecode/mp4parser/boxes/mp4/objectdescriptors/ObjectDescriptorBase.java27
-rw-r--r--isoparser/src/main/java/com/googlecode/mp4parser/boxes/mp4/objectdescriptors/ObjectDescriptorFactory.java189
-rw-r--r--isoparser/src/main/java/com/googlecode/mp4parser/boxes/mp4/objectdescriptors/ProfileLevelIndicationDescriptor.java70
-rw-r--r--isoparser/src/main/java/com/googlecode/mp4parser/boxes/mp4/objectdescriptors/SLConfigDescriptor.java119
-rw-r--r--isoparser/src/main/java/com/googlecode/mp4parser/boxes/mp4/objectdescriptors/UnknownDescriptor.java42
-rw-r--r--isoparser/src/main/java/com/googlecode/mp4parser/boxes/mp4/samplegrouping/.svn/all-wcprops59
-rw-r--r--isoparser/src/main/java/com/googlecode/mp4parser/boxes/mp4/samplegrouping/.svn/entries334
-rw-r--r--isoparser/src/main/java/com/googlecode/mp4parser/boxes/mp4/samplegrouping/.svn/text-base/CencSampleEncryptionInformationGroupEntry.java.svn-base125
-rw-r--r--isoparser/src/main/java/com/googlecode/mp4parser/boxes/mp4/samplegrouping/.svn/text-base/GroupEntry.java.svn-base28
-rw-r--r--isoparser/src/main/java/com/googlecode/mp4parser/boxes/mp4/samplegrouping/.svn/text-base/RateShareEntry.java.svn-base246
-rw-r--r--isoparser/src/main/java/com/googlecode/mp4parser/boxes/mp4/samplegrouping/.svn/text-base/RollRecoveryEntry.java.svn-base77
-rw-r--r--isoparser/src/main/java/com/googlecode/mp4parser/boxes/mp4/samplegrouping/.svn/text-base/SampleGroupDescriptionBox.java.svn-base200
-rw-r--r--isoparser/src/main/java/com/googlecode/mp4parser/boxes/mp4/samplegrouping/.svn/text-base/SampleToGroupBox.java.svn-base174
-rw-r--r--isoparser/src/main/java/com/googlecode/mp4parser/boxes/mp4/samplegrouping/.svn/text-base/TemporalLevelEntry.java.svn-base82
-rw-r--r--isoparser/src/main/java/com/googlecode/mp4parser/boxes/mp4/samplegrouping/.svn/text-base/UnknownEntry.java.svn-base83
-rw-r--r--isoparser/src/main/java/com/googlecode/mp4parser/boxes/mp4/samplegrouping/.svn/text-base/VisualRandomAccessEntry.java.svn-base94
-rw-r--r--isoparser/src/main/java/com/googlecode/mp4parser/boxes/mp4/samplegrouping/CencSampleEncryptionInformationGroupEntry.java125
-rw-r--r--isoparser/src/main/java/com/googlecode/mp4parser/boxes/mp4/samplegrouping/GroupEntry.java28
-rw-r--r--isoparser/src/main/java/com/googlecode/mp4parser/boxes/mp4/samplegrouping/RateShareEntry.java246
-rw-r--r--isoparser/src/main/java/com/googlecode/mp4parser/boxes/mp4/samplegrouping/RollRecoveryEntry.java77
-rw-r--r--isoparser/src/main/java/com/googlecode/mp4parser/boxes/mp4/samplegrouping/SampleGroupDescriptionBox.java200
-rw-r--r--isoparser/src/main/java/com/googlecode/mp4parser/boxes/mp4/samplegrouping/SampleToGroupBox.java174
-rw-r--r--isoparser/src/main/java/com/googlecode/mp4parser/boxes/mp4/samplegrouping/TemporalLevelEntry.java82
-rw-r--r--isoparser/src/main/java/com/googlecode/mp4parser/boxes/mp4/samplegrouping/UnknownEntry.java83
-rw-r--r--isoparser/src/main/java/com/googlecode/mp4parser/boxes/mp4/samplegrouping/VisualRandomAccessEntry.java94
64 files changed, 9685 insertions, 0 deletions
diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/boxes/mp4/.svn/all-wcprops b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/mp4/.svn/all-wcprops
new file mode 100644
index 0000000..b552219
--- /dev/null
+++ b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/mp4/.svn/all-wcprops
@@ -0,0 +1,23 @@
+K 25
+svn:wc:ra_dav:version-url
+V 82
+/svn/!svn/ver/770/trunk/isoparser/src/main/java/com/googlecode/mp4parser/boxes/mp4
+END
+ESDescriptorBox.java
+K 25
+svn:wc:ra_dav:version-url
+V 103
+/svn/!svn/ver/377/trunk/isoparser/src/main/java/com/googlecode/mp4parser/boxes/mp4/ESDescriptorBox.java
+END
+AbstractDescriptorBox.java
+K 25
+svn:wc:ra_dav:version-url
+V 109
+/svn/!svn/ver/507/trunk/isoparser/src/main/java/com/googlecode/mp4parser/boxes/mp4/AbstractDescriptorBox.java
+END
+ObjectDescriptorBox.java
+K 25
+svn:wc:ra_dav:version-url
+V 107
+/svn/!svn/ver/377/trunk/isoparser/src/main/java/com/googlecode/mp4parser/boxes/mp4/ObjectDescriptorBox.java
+END
diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/boxes/mp4/.svn/entries b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/mp4/.svn/entries
new file mode 100644
index 0000000..be8f9d8
--- /dev/null
+++ b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/mp4/.svn/entries
@@ -0,0 +1,136 @@
+10
+
+dir
+778
+http://mp4parser.googlecode.com/svn/trunk/isoparser/src/main/java/com/googlecode/mp4parser/boxes/mp4
+http://mp4parser.googlecode.com/svn
+
+
+
+2012-08-31T05:20:57.236953Z
+770
+michael.stattmann@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+7decde4b-c250-0410-a0da-51896bc88be6
+
+ESDescriptorBox.java
+file
+
+
+
+
+2012-09-14T17:27:51.127228Z
+3938742e971cd377b37592461870d872
+2012-03-05T23:28:24.666173Z
+377
+Sebastian.Annies@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+1021
+
+objectdescriptors
+dir
+
+AbstractDescriptorBox.java
+file
+
+
+
+
+2012-09-14T17:27:51.127228Z
+3361124b1437f844ab4727c8dea81e3d
+2012-04-21T22:05:38.425329Z
+507
+Sebastian.Annies@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+2487
+
+samplegrouping
+dir
+
+ObjectDescriptorBox.java
+file
+
+
+
+
+2012-09-14T17:27:51.127228Z
+b81e2d3876ef2af7ba17bf2d8bd6e504
+2012-03-05T23:28:24.666173Z
+377
+Sebastian.Annies@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+1983
+
diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/boxes/mp4/.svn/text-base/AbstractDescriptorBox.java.svn-base b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/mp4/.svn/text-base/AbstractDescriptorBox.java.svn-base
new file mode 100644
index 0000000..7d614e2
--- /dev/null
+++ b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/mp4/.svn/text-base/AbstractDescriptorBox.java.svn-base
@@ -0,0 +1,84 @@
+/*
+ * Copyright 2011 castLabs, 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.googlecode.mp4parser.boxes.mp4;
+
+import com.googlecode.mp4parser.AbstractFullBox;
+import com.googlecode.mp4parser.boxes.mp4.objectdescriptors.BaseDescriptor;
+import com.googlecode.mp4parser.boxes.mp4.objectdescriptors.ObjectDescriptorFactory;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+/**
+ * ES Descriptor Box.
+ */
+public class AbstractDescriptorBox extends AbstractFullBox {
+ private static Logger log = Logger.getLogger(AbstractDescriptorBox.class.getName());
+
+
+ public BaseDescriptor descriptor;
+ public ByteBuffer data;
+
+ public AbstractDescriptorBox(String type) {
+ super(type);
+ }
+
+ @Override
+ protected void getContent(ByteBuffer byteBuffer) {
+ writeVersionAndFlags(byteBuffer);
+ data.rewind(); // has been fforwarded by parsing
+ byteBuffer.put(data);
+ }
+
+ @Override
+ protected long getContentSize() {
+ return 4 + data.limit();
+ }
+
+ public BaseDescriptor getDescriptor() {
+ return descriptor;
+ }
+
+ public String getDescriptorAsString() {
+ return descriptor.toString();
+ }
+
+ public void setData(ByteBuffer data) {
+ this.data = data;
+ }
+
+ @Override
+ public void _parseDetails(ByteBuffer content) {
+ parseVersionAndFlags(content);
+ data = content.slice();
+ content.position(content.position() + content.remaining());
+ try {
+ data.rewind();
+ descriptor = ObjectDescriptorFactory.createFrom(-1, data);
+ } catch (IOException e) {
+ log.log(Level.WARNING, "Error parsing ObjectDescriptor", e);
+ //that's why we copied it ;)
+ } catch (IndexOutOfBoundsException e) {
+ log.log(Level.WARNING, "Error parsing ObjectDescriptor", e);
+ //that's why we copied it ;)
+ }
+
+ }
+
+}
diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/boxes/mp4/.svn/text-base/ESDescriptorBox.java.svn-base b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/mp4/.svn/text-base/ESDescriptorBox.java.svn-base
new file mode 100644
index 0000000..5d9d591
--- /dev/null
+++ b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/mp4/.svn/text-base/ESDescriptorBox.java.svn-base
@@ -0,0 +1,36 @@
+/*
+ * Copyright 2011 castLabs, 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.googlecode.mp4parser.boxes.mp4;
+
+import com.googlecode.mp4parser.boxes.mp4.objectdescriptors.ESDescriptor;
+
+/**
+ * ES Descriptor Box.
+ */
+public class ESDescriptorBox extends AbstractDescriptorBox {
+ public static final String TYPE = "esds";
+
+ public ESDescriptorBox() {
+ super(TYPE);
+ }
+
+ public ESDescriptor getEsDescriptor() {
+ return (ESDescriptor) super.getDescriptor();
+ }
+
+
+}
diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/boxes/mp4/.svn/text-base/ObjectDescriptorBox.java.svn-base b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/mp4/.svn/text-base/ObjectDescriptorBox.java.svn-base
new file mode 100644
index 0000000..c9e7493
--- /dev/null
+++ b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/mp4/.svn/text-base/ObjectDescriptorBox.java.svn-base
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2011 Sebastian Annies, Hamburg
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.googlecode.mp4parser.boxes.mp4;
+
+/**
+ * This object contains an Object Descriptor or an Initial Object Descriptor.
+ * There are a number of possible file types based on usage, depending on the descriptor:
+ * <ul>
+ * <li>Presentation, contains IOD which contains a BIFS stream (MP4 file);
+ * <li>Sub-part of a presentation, contains an IOD without a BIFS stream (MP4 file);</li>
+ * <li>Sub-part of a presentation, contains an OD (MP4 file);</li>
+ * <li>Free-form file, referenced by MP4 data references (free-format);</li>
+ * <li>Sub-part of a presentation, referenced by an ES URL.</li>
+ * </ul>
+ * NOTE: <br/>
+ * The first three are MP4 files, a file referenced by a data reference is not necessarily an MP4 file, as it is
+ * free-format. Files referenced by ES URLs, by data references, or intended as input to an editing process, need not have
+ * an Object Descriptor Box. <br/>
+ * An OD URL may point to an MP4 file. Implicitly, the target of such a URL is the OD/IOD located in the 'iods'
+ * atom in that file.</br/>
+ * If an MP4 file contains several object descriptors, only the OD/IOD in the 'iods' atom can be addressed using
+ * an OD URL from a remote MPEG-4 presentation.
+ */
+public class ObjectDescriptorBox extends AbstractDescriptorBox {
+ public static final String TYPE = "iods";
+
+ public ObjectDescriptorBox() {
+ super(TYPE);
+ }
+
+
+}
diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/boxes/mp4/AbstractDescriptorBox.java b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/mp4/AbstractDescriptorBox.java
new file mode 100644
index 0000000..7d614e2
--- /dev/null
+++ b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/mp4/AbstractDescriptorBox.java
@@ -0,0 +1,84 @@
+/*
+ * Copyright 2011 castLabs, 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.googlecode.mp4parser.boxes.mp4;
+
+import com.googlecode.mp4parser.AbstractFullBox;
+import com.googlecode.mp4parser.boxes.mp4.objectdescriptors.BaseDescriptor;
+import com.googlecode.mp4parser.boxes.mp4.objectdescriptors.ObjectDescriptorFactory;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+/**
+ * ES Descriptor Box.
+ */
+public class AbstractDescriptorBox extends AbstractFullBox {
+ private static Logger log = Logger.getLogger(AbstractDescriptorBox.class.getName());
+
+
+ public BaseDescriptor descriptor;
+ public ByteBuffer data;
+
+ public AbstractDescriptorBox(String type) {
+ super(type);
+ }
+
+ @Override
+ protected void getContent(ByteBuffer byteBuffer) {
+ writeVersionAndFlags(byteBuffer);
+ data.rewind(); // has been fforwarded by parsing
+ byteBuffer.put(data);
+ }
+
+ @Override
+ protected long getContentSize() {
+ return 4 + data.limit();
+ }
+
+ public BaseDescriptor getDescriptor() {
+ return descriptor;
+ }
+
+ public String getDescriptorAsString() {
+ return descriptor.toString();
+ }
+
+ public void setData(ByteBuffer data) {
+ this.data = data;
+ }
+
+ @Override
+ public void _parseDetails(ByteBuffer content) {
+ parseVersionAndFlags(content);
+ data = content.slice();
+ content.position(content.position() + content.remaining());
+ try {
+ data.rewind();
+ descriptor = ObjectDescriptorFactory.createFrom(-1, data);
+ } catch (IOException e) {
+ log.log(Level.WARNING, "Error parsing ObjectDescriptor", e);
+ //that's why we copied it ;)
+ } catch (IndexOutOfBoundsException e) {
+ log.log(Level.WARNING, "Error parsing ObjectDescriptor", e);
+ //that's why we copied it ;)
+ }
+
+ }
+
+}
diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/boxes/mp4/ESDescriptorBox.java b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/mp4/ESDescriptorBox.java
new file mode 100644
index 0000000..5d9d591
--- /dev/null
+++ b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/mp4/ESDescriptorBox.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright 2011 castLabs, 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.googlecode.mp4parser.boxes.mp4;
+
+import com.googlecode.mp4parser.boxes.mp4.objectdescriptors.ESDescriptor;
+
+/**
+ * ES Descriptor Box.
+ */
+public class ESDescriptorBox extends AbstractDescriptorBox {
+ public static final String TYPE = "esds";
+
+ public ESDescriptorBox() {
+ super(TYPE);
+ }
+
+ public ESDescriptor getEsDescriptor() {
+ return (ESDescriptor) super.getDescriptor();
+ }
+
+
+}
diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/boxes/mp4/ObjectDescriptorBox.java b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/mp4/ObjectDescriptorBox.java
new file mode 100644
index 0000000..c9e7493
--- /dev/null
+++ b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/mp4/ObjectDescriptorBox.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2011 Sebastian Annies, Hamburg
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.googlecode.mp4parser.boxes.mp4;
+
+/**
+ * This object contains an Object Descriptor or an Initial Object Descriptor.
+ * There are a number of possible file types based on usage, depending on the descriptor:
+ * <ul>
+ * <li>Presentation, contains IOD which contains a BIFS stream (MP4 file);
+ * <li>Sub-part of a presentation, contains an IOD without a BIFS stream (MP4 file);</li>
+ * <li>Sub-part of a presentation, contains an OD (MP4 file);</li>
+ * <li>Free-form file, referenced by MP4 data references (free-format);</li>
+ * <li>Sub-part of a presentation, referenced by an ES URL.</li>
+ * </ul>
+ * NOTE: <br/>
+ * The first three are MP4 files, a file referenced by a data reference is not necessarily an MP4 file, as it is
+ * free-format. Files referenced by ES URLs, by data references, or intended as input to an editing process, need not have
+ * an Object Descriptor Box. <br/>
+ * An OD URL may point to an MP4 file. Implicitly, the target of such a URL is the OD/IOD located in the 'iods'
+ * atom in that file.</br/>
+ * If an MP4 file contains several object descriptors, only the OD/IOD in the 'iods' atom can be addressed using
+ * an OD URL from a remote MPEG-4 presentation.
+ */
+public class ObjectDescriptorBox extends AbstractDescriptorBox {
+ public static final String TYPE = "iods";
+
+ public ObjectDescriptorBox() {
+ super(TYPE);
+ }
+
+
+}
diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/boxes/mp4/objectdescriptors/.svn/all-wcprops b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/mp4/objectdescriptors/.svn/all-wcprops
new file mode 100644
index 0000000..5e1798f
--- /dev/null
+++ b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/mp4/objectdescriptors/.svn/all-wcprops
@@ -0,0 +1,107 @@
+K 25
+svn:wc:ra_dav:version-url
+V 100
+/svn/!svn/ver/712/trunk/isoparser/src/main/java/com/googlecode/mp4parser/boxes/mp4/objectdescriptors
+END
+ObjectDescriptorBase.java
+K 25
+svn:wc:ra_dav:version-url
+V 126
+/svn/!svn/ver/377/trunk/isoparser/src/main/java/com/googlecode/mp4parser/boxes/mp4/objectdescriptors/ObjectDescriptorBase.java
+END
+SLConfigDescriptor.java
+K 25
+svn:wc:ra_dav:version-url
+V 124
+/svn/!svn/ver/712/trunk/isoparser/src/main/java/com/googlecode/mp4parser/boxes/mp4/objectdescriptors/SLConfigDescriptor.java
+END
+BitWriterBuffer.java
+K 25
+svn:wc:ra_dav:version-url
+V 121
+/svn/!svn/ver/683/trunk/isoparser/src/main/java/com/googlecode/mp4parser/boxes/mp4/objectdescriptors/BitWriterBuffer.java
+END
+ESDescriptor.java
+K 25
+svn:wc:ra_dav:version-url
+V 118
+/svn/!svn/ver/712/trunk/isoparser/src/main/java/com/googlecode/mp4parser/boxes/mp4/objectdescriptors/ESDescriptor.java
+END
+BaseDescriptor.java
+K 25
+svn:wc:ra_dav:version-url
+V 120
+/svn/!svn/ver/377/trunk/isoparser/src/main/java/com/googlecode/mp4parser/boxes/mp4/objectdescriptors/BaseDescriptor.java
+END
+ExtensionDescriptor.java
+K 25
+svn:wc:ra_dav:version-url
+V 125
+/svn/!svn/ver/377/trunk/isoparser/src/main/java/com/googlecode/mp4parser/boxes/mp4/objectdescriptors/ExtensionDescriptor.java
+END
+Descriptor.java
+K 25
+svn:wc:ra_dav:version-url
+V 116
+/svn/!svn/ver/377/trunk/isoparser/src/main/java/com/googlecode/mp4parser/boxes/mp4/objectdescriptors/Descriptor.java
+END
+InitialObjectDescriptor.java
+K 25
+svn:wc:ra_dav:version-url
+V 129
+/svn/!svn/ver/377/trunk/isoparser/src/main/java/com/googlecode/mp4parser/boxes/mp4/objectdescriptors/InitialObjectDescriptor.java
+END
+ObjectDescriptor.java_bak
+K 25
+svn:wc:ra_dav:version-url
+V 126
+/svn/!svn/ver/377/trunk/isoparser/src/main/java/com/googlecode/mp4parser/boxes/mp4/objectdescriptors/ObjectDescriptor.java_bak
+END
+ExtensionProfileLevelDescriptor.java
+K 25
+svn:wc:ra_dav:version-url
+V 137
+/svn/!svn/ver/377/trunk/isoparser/src/main/java/com/googlecode/mp4parser/boxes/mp4/objectdescriptors/ExtensionProfileLevelDescriptor.java
+END
+DecoderSpecificInfo.java
+K 25
+svn:wc:ra_dav:version-url
+V 125
+/svn/!svn/ver/712/trunk/isoparser/src/main/java/com/googlecode/mp4parser/boxes/mp4/objectdescriptors/DecoderSpecificInfo.java
+END
+ProfileLevelIndicationDescriptor.java
+K 25
+svn:wc:ra_dav:version-url
+V 138
+/svn/!svn/ver/712/trunk/isoparser/src/main/java/com/googlecode/mp4parser/boxes/mp4/objectdescriptors/ProfileLevelIndicationDescriptor.java
+END
+DecoderConfigDescriptor.java
+K 25
+svn:wc:ra_dav:version-url
+V 129
+/svn/!svn/ver/501/trunk/isoparser/src/main/java/com/googlecode/mp4parser/boxes/mp4/objectdescriptors/DecoderConfigDescriptor.java
+END
+BitReaderBuffer.java
+K 25
+svn:wc:ra_dav:version-url
+V 121
+/svn/!svn/ver/501/trunk/isoparser/src/main/java/com/googlecode/mp4parser/boxes/mp4/objectdescriptors/BitReaderBuffer.java
+END
+AudioSpecificConfig.java
+K 25
+svn:wc:ra_dav:version-url
+V 125
+/svn/!svn/ver/712/trunk/isoparser/src/main/java/com/googlecode/mp4parser/boxes/mp4/objectdescriptors/AudioSpecificConfig.java
+END
+ObjectDescriptorFactory.java
+K 25
+svn:wc:ra_dav:version-url
+V 129
+/svn/!svn/ver/377/trunk/isoparser/src/main/java/com/googlecode/mp4parser/boxes/mp4/objectdescriptors/ObjectDescriptorFactory.java
+END
+UnknownDescriptor.java
+K 25
+svn:wc:ra_dav:version-url
+V 123
+/svn/!svn/ver/377/trunk/isoparser/src/main/java/com/googlecode/mp4parser/boxes/mp4/objectdescriptors/UnknownDescriptor.java
+END
diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/boxes/mp4/objectdescriptors/.svn/entries b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/mp4/objectdescriptors/.svn/entries
new file mode 100644
index 0000000..b150321
--- /dev/null
+++ b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/mp4/objectdescriptors/.svn/entries
@@ -0,0 +1,606 @@
+10
+
+dir
+778
+http://mp4parser.googlecode.com/svn/trunk/isoparser/src/main/java/com/googlecode/mp4parser/boxes/mp4/objectdescriptors
+http://mp4parser.googlecode.com/svn
+
+
+
+2012-07-12T22:44:00.389345Z
+712
+Sebastian.Annies@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+7decde4b-c250-0410-a0da-51896bc88be6
+
+ObjectDescriptorBase.java
+file
+
+
+
+
+2012-09-14T17:27:50.997226Z
+830afc294b0cc9e0fec5d733e021863c
+2012-02-27T13:49:22.148513Z
+351
+Sebastian.Annies@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+961
+
+SLConfigDescriptor.java
+file
+
+
+
+
+2012-09-14T17:27:50.997226Z
+a0907a19df5c0cc9764689f9c6e3baa3
+2012-07-12T22:44:00.389345Z
+712
+Sebastian.Annies@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+3338
+
+BitWriterBuffer.java
+file
+
+
+
+
+2012-09-14T17:27:50.997226Z
+771f8d900c6ff640d51fbb5dd4e933af
+2012-06-23T08:51:59.024275Z
+683
+Sebastian.Annies@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+1304
+
+ESDescriptor.java
+file
+
+
+
+
+2012-09-14T17:27:50.997226Z
+98f2c06a445b6b1d9836a6d3017da884
+2012-07-12T22:44:00.389345Z
+712
+Sebastian.Annies@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+12845
+
+BaseDescriptor.java
+file
+
+
+
+
+2012-09-14T17:27:50.997226Z
+c74bfdd283a75b2a57aa1b7ebc71c178
+2012-02-27T13:49:22.148513Z
+351
+Sebastian.Annies@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+2811
+
+ExtensionDescriptor.java
+file
+
+
+
+
+2012-09-14T17:27:50.997226Z
+907c329cba88c885e4b4b4a751facc6d
+2012-02-27T13:49:22.148513Z
+351
+Sebastian.Annies@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+2973
+
+Descriptor.java
+file
+
+
+
+
+2012-09-14T17:27:50.997226Z
+ac97c8117fd734f9dd22172d9a9a3a42
+2012-02-27T13:49:22.148513Z
+351
+Sebastian.Annies@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+1228
+
+InitialObjectDescriptor.java
+file
+
+
+
+
+2012-09-14T17:27:50.997226Z
+9f15d54d46b6644e1beb981b4d8fcee6
+2012-02-27T13:49:22.148513Z
+351
+Sebastian.Annies@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+5237
+
+ObjectDescriptor.java_bak
+file
+
+
+
+
+2012-09-14T17:27:50.997226Z
+e77953ffb3ced634e03955f8eb0db522
+2012-02-27T13:49:22.148513Z
+351
+Sebastian.Annies@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+3666
+
+ExtensionProfileLevelDescriptor.java
+file
+
+
+
+
+2012-09-14T17:27:50.997226Z
+e7e0a38947f89d9285ddfdef6205c843
+2012-02-27T13:49:22.148513Z
+351
+Sebastian.Annies@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+1626
+
+DecoderSpecificInfo.java
+file
+
+
+
+
+2012-09-14T17:27:50.997226Z
+f1faa43de84eaf3219495512761b4521
+2012-07-12T22:44:00.389345Z
+712
+Sebastian.Annies@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+2292
+
+ProfileLevelIndicationDescriptor.java
+file
+
+
+
+
+2012-09-14T17:27:50.997226Z
+6c76abf5466eb8aa9dded6ea17e66588
+2012-07-12T22:44:00.389345Z
+712
+Sebastian.Annies@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+2143
+
+DecoderConfigDescriptor.java
+file
+
+
+
+
+2012-09-14T17:27:50.997226Z
+ead55e14a62664da9869cb3a092d4fc2
+2012-04-20T14:18:38.758800Z
+501
+hoemmagnus@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+9508
+
+BitReaderBuffer.java
+file
+
+
+
+
+2012-09-14T17:27:50.997226Z
+9a0bad29e63d974899749007d890b027
+2012-04-20T14:18:38.758800Z
+501
+hoemmagnus@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+1241
+
+ObjectDescriptorFactory.java
+file
+
+
+
+
+2012-09-14T17:27:50.997226Z
+cd9f2bc6eb85a79c6148d91099bbe300
+2012-02-27T13:49:22.148513Z
+351
+Sebastian.Annies@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+7011
+
+AudioSpecificConfig.java
+file
+
+
+
+
+2012-09-14T17:27:51.007226Z
+79095f48595f6573c76ec69e5717cdfe
+2012-07-12T22:44:00.389345Z
+712
+Sebastian.Annies@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+40856
+
+UnknownDescriptor.java
+file
+
+
+
+
+2012-09-14T17:27:51.007226Z
+66e3ecf5b31e50a1a4f80d08e4643af9
+2012-02-27T13:49:22.148513Z
+351
+Sebastian.Annies@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+1467
+
diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/boxes/mp4/objectdescriptors/.svn/text-base/AudioSpecificConfig.java.svn-base b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/mp4/objectdescriptors/.svn/text-base/AudioSpecificConfig.java.svn-base
new file mode 100644
index 0000000..86e319e
--- /dev/null
+++ b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/mp4/objectdescriptors/.svn/text-base/AudioSpecificConfig.java.svn-base
@@ -0,0 +1,1176 @@
+/*
+ * Copyright 2011 castLabs, 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.googlecode.mp4parser.boxes.mp4.objectdescriptors;
+
+import com.coremedia.iso.Hex;
+import com.coremedia.iso.IsoTypeWriter;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Map;
+
+
+//
+//GetAudioObjectType()
+//{
+//audioObjectType; 5 uimsbf
+//if (audioObjectType == 31) {
+//audioObjectType = 32 + audioObjectTypeExt; 6 uimsbf
+//}
+//return audioObjectType;
+//}
+//AudioSpecificConfig ()
+//{
+//audioObjectType = GetAudioObjectType();
+//samplingFrequencyIndex; 4 bslbf
+//if ( samplingFrequencyIndex == 0xf ) {
+//samplingFrequency; 24 uimsbf
+//}
+//channelConfiguration; 4 bslbf
+//sbrPresentFlag = -1;
+//psPresentFlag = -1;
+//if ( audioObjectType == 5 ||
+//audioObjectType == 29 ) {
+//extensionAudioObjectType = 5;
+//sbrPresentFlag = 1;
+//if ( audioObjectType == 29 ) {
+//psPresentFlag = 1;
+//}
+//extensionSamplingFrequencyIndex; 4 uimsbf
+//if ( extensionSamplingFrequencyIndex == 0xf )
+//extensionSamplingFrequency; 24 uimsbf
+//audioObjectType = GetAudioObjectType();
+//if ( audioObjectType == 22 )
+//extensionChannelConfiguration; 4 uimsbf
+//}
+//else {
+//extensionAudioObjectType = 0;
+//}
+//switch (audioObjectType) {
+//case 1:
+//case 2:
+//case 3:
+//case 4:
+//case 6:
+//case 7:
+//case 17:
+//case 19:
+//case 20:
+//case 21:
+//case 22:
+//case 23:
+//GASpecificConfig();
+//break:
+//case 8:
+//CelpSpecificConfig();
+//break;
+//case 9:
+//HvxcSpecificConfig();
+//break:
+//case 12:
+//TTSSpecificConfig();
+//break;
+//case 13:
+//case 14:
+//case 15:
+//case 16:
+//StructuredAudioSpecificConfig();
+//break;
+//case 24:
+//ErrorResilientCelpSpecificConfig();
+//break;
+//case 25:
+//ErrorResilientHvxcSpecificConfig();
+//break;
+//case 26:
+//case 27:
+//ParametricSpecificConfig();
+//break;
+// case 28:
+//SSCSpecificConfig();
+//break;
+//case 30:
+//sacPayloadEmbedding; 1 uimsbf
+//SpatialSpecificConfig();
+//break;
+//case 32:
+//case 33:
+//case 34:
+//MPEG_1_2_SpecificConfig();
+//break;
+//case 35:
+//DSTSpecificConfig();
+//break;
+//case 36:
+//fillBits; 5 bslbf
+//ALSSpecificConfig();
+//break;
+//case 37:
+//case 38:
+//SLSSpecificConfig();
+//break;
+//case 39:
+//ELDSpecificConfig(channelConfiguration);
+//break:
+//case 40:
+//case 41:
+//SymbolicMusicSpecificConfig();
+//break;
+//default:
+///* reserved */
+//}
+//switch (audioObjectType) {
+//case 17:
+//case 19:
+//case 20:
+//case 21:
+//case 22:
+//case 23:
+//case 24:
+//case 25:
+//case 26:
+//case 27:
+//case 39:
+//epConfig; 2 bslbf
+//if ( epConfig == 2 || epConfig == 3 ) {
+//ErrorProtectionSpecificConfig();
+//}
+//if ( epConfig == 3 ) {
+//directMapping; 1 bslbf
+//if ( ! directMapping ) {
+///* tbd */
+//}
+//}
+//}
+//if ( extensionAudioObjectType != 5 && bits_to_decode() >= 16 ) {
+//syncExtensionType; 11 bslbf
+//if (syncExtensionType == 0x2b7) {
+// extensionAudioObjectType = GetAudioObjectType();
+//if ( extensionAudioObjectType == 5 ) {
+//sbrPresentFlag; 1 uimsbf
+//if (sbrPresentFlag == 1) {
+//extensionSamplingFrequencyIndex; 4 uimsbf
+//if ( extensionSamplingFrequencyIndex == 0xf ) {
+//extensionSamplingFrequency; 24 uimsbf
+//}
+//if ( bits_to_decode() >= 12 ) {
+//syncExtensionType; 11 bslbf
+//if (syncExtesionType == 0x548) {
+//psPresentFlag; 1 uimsbf
+//}
+//}
+//}
+//}
+//if ( extensionAudioObjectType == 22 ) {
+//sbrPresentFlag; 1 uimsbf
+//if (sbrPresentFlag == 1) {
+//extensionSamplingFrequencyIndex; 4 uimsbf
+//if ( extensionSamplingFrequencyIndex == 0xf ) {
+//extensionSamplingFrequency; 24 uimsbf
+//}
+//}
+//extensionChannelConfiguration; 4 uimsbf
+//}
+//}
+//}
+//}
+// }
+//
+// TFCodingType
+//0x0 AAC scaleable
+//0x1 BSAC
+//0x2 TwinVQ
+//0x3 AAC non scaleable (i.e. multichannel)
+//
+// class TFSpecificConfig( uint(4) samplingFrequencyIndex, uint(4) channelConfiguration ) {
+//uint(2) TFCodingType;
+//uint(1) frameLength;
+//uint(1) dependsOnCoreCoder;
+//if (dependsOnCoreCoder == 1){
+//uint(14)coreCoderDelay
+//}
+//if (TFCodingType==BSAC) {
+//uint(11) lslayer_length
+//}
+//uint (1) extensionFlag;
+//if (channelConfiguration == 0 ){
+//program_config_element();
+//}
+//if (extensionFlag==1){
+//<to be defined in mpeg4 phase 2>
+//}
+//}
+//
+//program_config_element()
+//{
+//element_instance_tag 4 uimsbf
+//profile 2 uimsbf
+//sampling_frequency_index 4 uimsbf
+//num_front_channel_elements 4 uimsbf
+//num_side_channel_elements 4 uimsbf
+//num_back_channel_elements 4 uimsbf
+// num_lfe_channel_elements 2 uimsbf
+//num_assoc_data_elements 3 uimsbf
+//num_valid_cc_elements 4 uimsbf
+//mono_mixdown_present 1 uimsbf
+//if ( mono_mixdown_present == 1 )
+//mono_mixdown_element_number 4 uimsbf
+//stereo_mixdown_present 1 uimsbf
+//if ( stereo_mixdown_present == 1 )
+//stereo_mixdown_element_number 4 uimsbf
+//matrix_mixdown_idx_present 1 uimsbf
+//if ( matrix_mixdown_idx_present == 1 ) {
+//matrix_mixdown_idx 2 uimsbf
+//pseudo_surround_enable 1 uimsbf
+//}
+//for ( i = 0; i < num_front_channel_elements; i++) {
+//front_element_is_cpe[i]; 1 bslbf
+//front_element_tag_select[i]; 4 uimsbf
+//}
+//for ( i = 0; i < num_side_channel_elements; i++) {
+//side_element_is_cpe[i]; 1 bslbf
+//side_element_tag_select[i]; 4 uimsbf
+//}
+//for ( i = 0; i < num_back_channel_elements; i++) {
+//back_element_is_cpe[i]; 1 bslbf
+//back_element_tag_select[i]; 4 uimsbf
+//}
+//for ( i = 0; i < num_lfe_channel_elements; i++)
+//lfe_element_tag_select[i]; 4 uimsbf
+//for ( i = 0; i < num_assoc_data_elements; i++)
+//assoc_data_element_tag_select[i]; 4 uimsbf
+//for ( i = 0; i < num_valid_cc_elements; i++) {
+//cc_element_is_ind_sw[i]; 1 uimsbf
+//valid_cc_element_tag_select[i]; 4 uimsbf
+//}
+//byte_alignment()
+//comment_field_bytes 8 uimsbf
+//for ( i = 0; i < comment_field_bytes; i++)
+//comment_field_data[i]; 8 uimsbf
+//}
+
+@Descriptor(tags = 0x5, objectTypeIndication = 0x40)
+public class AudioSpecificConfig extends BaseDescriptor {
+ byte[] configBytes;
+
+ public static Map<Integer, Integer> samplingFrequencyIndexMap = new HashMap<Integer, Integer>();
+ public static Map<Integer, String> audioObjectTypeMap = new HashMap<Integer, String>();
+ int audioObjectType;
+ int samplingFrequencyIndex;
+ int samplingFrequency;
+ int channelConfiguration;
+ int extensionAudioObjectType;
+ int sbrPresentFlag;
+ int psPresentFlag;
+ int extensionSamplingFrequencyIndex;
+ int extensionSamplingFrequency;
+ int extensionChannelConfiguration;
+ int sacPayloadEmbedding;
+ int fillBits;
+ int epConfig;
+ int directMapping;
+ int syncExtensionType;
+
+ //GASpecificConfig
+ int frameLengthFlag;
+ int dependsOnCoreCoder;
+ int coreCoderDelay;
+ int extensionFlag;
+ int layerNr;
+ int numOfSubFrame;
+ int layer_length;
+ int aacSectionDataResilienceFlag;
+ int aacScalefactorDataResilienceFlag;
+ int aacSpectralDataResilienceFlag;
+ int extensionFlag3;
+ boolean gaSpecificConfig;
+
+ //ParametricSpecificConfig
+ int isBaseLayer;
+ int paraMode;
+ int paraExtensionFlag;
+ int hvxcVarMode;
+ int hvxcRateMode;
+ int erHvxcExtensionFlag;
+ int var_ScalableFlag;
+ int hilnQuantMode;
+ int hilnMaxNumLine;
+ int hilnSampleRateCode;
+ int hilnFrameLength;
+ int hilnContMode;
+ int hilnEnhaLayer;
+ int hilnEnhaQuantMode;
+ boolean parametricSpecificConfig;
+
+ @Override
+ public void parseDetail(ByteBuffer bb) throws IOException {
+ ByteBuffer configBytes = bb.slice();
+ configBytes.limit(sizeOfInstance);
+ bb.position(bb.position() + sizeOfInstance);
+
+ //copy original bytes to internal array for constructing codec config strings (todo until writing of the config is supported)
+ this.configBytes = new byte[sizeOfInstance];
+ configBytes.get(this.configBytes);
+ configBytes.rewind();
+
+ BitReaderBuffer bitReaderBuffer = new BitReaderBuffer(configBytes);
+ audioObjectType = getAudioObjectType(bitReaderBuffer);
+ samplingFrequencyIndex = bitReaderBuffer.readBits(4);
+
+ if (samplingFrequencyIndex == 0xf) {
+ samplingFrequency = bitReaderBuffer.readBits(24);
+ }
+
+ channelConfiguration = bitReaderBuffer.readBits(4);
+
+ if (audioObjectType == 5 ||
+ audioObjectType == 29) {
+ extensionAudioObjectType = 5;
+ sbrPresentFlag = 1;
+ if (audioObjectType == 29) {
+ psPresentFlag = 1;
+ }
+ extensionSamplingFrequencyIndex = bitReaderBuffer.readBits(4);
+ if (extensionSamplingFrequencyIndex == 0xf)
+ extensionSamplingFrequency = bitReaderBuffer.readBits(24);
+ audioObjectType = getAudioObjectType(bitReaderBuffer);
+ if (audioObjectType == 22)
+ extensionChannelConfiguration = bitReaderBuffer.readBits(4);
+ } else {
+ extensionAudioObjectType = 0;
+ }
+
+ switch (audioObjectType) {
+ case 1:
+ case 2:
+ case 3:
+ case 4:
+ case 6:
+ case 7:
+ case 17:
+ case 19:
+ case 20:
+ case 21:
+ case 22:
+ case 23:
+ parseGaSpecificConfig(samplingFrequencyIndex, channelConfiguration, audioObjectType, bitReaderBuffer);
+ //GASpecificConfig();
+ break;
+ case 8:
+ throw new UnsupportedOperationException("can't parse CelpSpecificConfig yet");
+ //CelpSpecificConfig();
+ //break;
+ case 9:
+ throw new UnsupportedOperationException("can't parse HvxcSpecificConfig yet");
+ //HvxcSpecificConfig();
+ //break;
+ case 12:
+ throw new UnsupportedOperationException("can't parse TTSSpecificConfig yet");
+ //TTSSpecificConfig();
+ //break;
+ case 13:
+ case 14:
+ case 15:
+ case 16:
+ throw new UnsupportedOperationException("can't parse StructuredAudioSpecificConfig yet");
+ //StructuredAudioSpecificConfig();
+ //break;
+ case 24:
+ throw new UnsupportedOperationException("can't parse ErrorResilientCelpSpecificConfig yet");
+ //ErrorResilientCelpSpecificConfig();
+ //break;
+ case 25:
+ throw new UnsupportedOperationException("can't parse ErrorResilientHvxcSpecificConfig yet");
+ //ErrorResilientHvxcSpecificConfig();
+ //break;
+ case 26:
+ case 27:
+ parseParametricSpecificConfig(samplingFrequencyIndex, channelConfiguration, audioObjectType, bitReaderBuffer);
+ //ParametricSpecificConfig();
+ break;
+ case 28:
+ throw new UnsupportedOperationException("can't parse SSCSpecificConfig yet");
+ //SSCSpecificConfig();
+ //break;
+ case 30:
+ sacPayloadEmbedding = bitReaderBuffer.readBits(1);
+ throw new UnsupportedOperationException("can't parse SpatialSpecificConfig yet");
+ //SpatialSpecificConfig();
+ //break;
+ case 32:
+ case 33:
+ case 34:
+ throw new UnsupportedOperationException("can't parse MPEG_1_2_SpecificConfig yet");
+ //MPEG_1_2_SpecificConfig();
+ //break;
+ case 35:
+ throw new UnsupportedOperationException("can't parse DSTSpecificConfig yet");
+ //DSTSpecificConfig();
+ //break;
+ case 36:
+ fillBits = bitReaderBuffer.readBits(5);
+ throw new UnsupportedOperationException("can't parse ALSSpecificConfig yet");
+ //ALSSpecificConfig();
+ //break;
+ case 37:
+ case 38:
+ throw new UnsupportedOperationException("can't parse SLSSpecificConfig yet");
+ //SLSSpecificConfig();
+ //break;
+ case 39:
+ throw new UnsupportedOperationException("can't parse ELDSpecificConfig yet");
+ //ELDSpecificConfig(channelConfiguration);
+ //break;
+ case 40:
+ case 41:
+ throw new UnsupportedOperationException("can't parse SymbolicMusicSpecificConfig yet");
+ //SymbolicMusicSpecificConfig();
+ //break;
+ default:
+ /* reserved */
+ }
+
+ switch (audioObjectType) {
+ case 17:
+ case 19:
+ case 20:
+ case 21:
+ case 22:
+ case 23:
+ case 24:
+ case 25:
+ case 26:
+ case 27:
+ case 39:
+ epConfig = bitReaderBuffer.readBits(2);
+ if (epConfig == 2 || epConfig == 3) {
+ throw new UnsupportedOperationException("can't parse ErrorProtectionSpecificConfig yet");
+ //ErrorProtectionSpecificConfig();
+ }
+ if (epConfig == 3) {
+ directMapping = bitReaderBuffer.readBits(1);
+ if (directMapping == 0) {
+ /* tbd */
+ throw new RuntimeException("not implemented");
+ }
+ }
+ }
+
+ if (extensionAudioObjectType != 5 && bitReaderBuffer.remainingBits() >= 16) {
+ syncExtensionType = bitReaderBuffer.readBits(11);
+ if (syncExtensionType == 0x2b7) {
+ extensionAudioObjectType = getAudioObjectType(bitReaderBuffer);
+ if (extensionAudioObjectType == 5) {
+ sbrPresentFlag = bitReaderBuffer.readBits(1);
+ if (sbrPresentFlag == 1) {
+ extensionSamplingFrequencyIndex = bitReaderBuffer.readBits(4);
+ if (extensionSamplingFrequencyIndex == 0xf) {
+ extensionSamplingFrequency = bitReaderBuffer.readBits(24);
+ }
+ if (bitReaderBuffer.remainingBits() >= 12) {
+ syncExtensionType = bitReaderBuffer.readBits(11); //10101001000
+ if (syncExtensionType == 0x548) {
+ psPresentFlag = bitReaderBuffer.readBits(1);
+ }
+ }
+ }
+ }
+ if (extensionAudioObjectType == 22) {
+ sbrPresentFlag = bitReaderBuffer.readBits(1);
+ if (sbrPresentFlag == 1) {
+ extensionSamplingFrequencyIndex = bitReaderBuffer.readBits(4);
+ if (extensionSamplingFrequencyIndex == 0xf) {
+ extensionSamplingFrequency = bitReaderBuffer.readBits(24);
+ }
+ }
+ extensionChannelConfiguration = bitReaderBuffer.readBits(4);
+ }
+ }
+ }
+ }
+
+ private int gaSpecificConfigSize() {
+ return 0;
+ }
+
+ public int serializedSize() {
+ int out = 4;
+ if (audioObjectType == 2) {
+ out += gaSpecificConfigSize();
+ } else {
+ throw new UnsupportedOperationException("can't serialize that yet");
+ }
+ return out;
+ }
+
+ public ByteBuffer serialize() {
+ ByteBuffer out = ByteBuffer.allocate(serializedSize());
+ IsoTypeWriter.writeUInt8(out, 5);
+ IsoTypeWriter.writeUInt8(out, serializedSize() - 2);
+ BitWriterBuffer bwb = new BitWriterBuffer(out);
+ bwb.writeBits(audioObjectType, 5);
+ bwb.writeBits(samplingFrequencyIndex, 4);
+ if (samplingFrequencyIndex == 0xf) {
+ throw new UnsupportedOperationException("can't serialize that yet");
+ }
+ bwb.writeBits(channelConfiguration, 4);
+
+ // Don't support any extensions, unusual GASpecificConfig other than the default or anything...
+
+ return out;
+ }
+
+ private int getAudioObjectType(BitReaderBuffer in) throws IOException {
+ int audioObjectType = in.readBits(5);
+ if (audioObjectType == 31) {
+ audioObjectType = 32 + in.readBits(6);
+ }
+ return audioObjectType;
+ }
+
+ private void parseGaSpecificConfig(int samplingFrequencyIndex, int channelConfiguration, int audioObjectType, BitReaderBuffer in) throws IOException {
+// GASpecificConfig (samplingFrequencyIndex,
+// channelConfiguration,
+// audioObjectType)
+// {
+ frameLengthFlag = in.readBits(1);
+ dependsOnCoreCoder = in.readBits(1);
+ if (dependsOnCoreCoder == 1) {
+ coreCoderDelay = in.readBits(14);
+ }
+ extensionFlag = in.readBits(1);
+ if (channelConfiguration == 0) {
+ throw new UnsupportedOperationException("can't parse program_config_element yet");
+ //program_config_element ();
+ }
+ if ((audioObjectType == 6) || (audioObjectType == 20)) {
+ layerNr = in.readBits(3);
+ }
+ if (extensionFlag == 1) {
+ if (audioObjectType == 22) {
+ numOfSubFrame = in.readBits(5);
+ layer_length = in.readBits(11);
+ }
+ if (audioObjectType == 17 || audioObjectType == 19 ||
+ audioObjectType == 20 || audioObjectType == 23) {
+ aacSectionDataResilienceFlag = in.readBits(1);
+ aacScalefactorDataResilienceFlag = in.readBits(1);
+ aacSpectralDataResilienceFlag = in.readBits(1);
+ }
+ extensionFlag3 = in.readBits(1);
+ if (extensionFlag3 == 1) {
+ /* tbd in version 3 */
+ }
+ }
+// }
+ gaSpecificConfig = true;
+ }
+
+ private void parseParametricSpecificConfig(int samplingFrequencyIndex, int channelConfiguration, int audioObjectType, BitReaderBuffer in) throws IOException {
+ /*
+ ParametricSpecificConfig() {
+ isBaseLayer; 1 uimsbf
+ if (isBaseLayer) {
+ PARAconfig();
+ } else {
+ HILNenexConfig();
+ }
+ }
+ */
+ isBaseLayer = in.readBits(1);
+ if (isBaseLayer == 1) {
+ parseParaConfig(samplingFrequencyIndex, channelConfiguration, audioObjectType, in);
+ } else {
+ parseHilnEnexConfig(samplingFrequencyIndex, channelConfiguration, audioObjectType, in);
+ }
+ }
+
+ private void parseParaConfig(int samplingFrequencyIndex, int channelConfiguration, int audioObjectType, BitReaderBuffer in) throws IOException {
+ /*
+ PARAconfig()
+ {
+ PARAmode; 2 uimsbf
+ if (PARAmode != 1) {
+ ErHVXCconfig();
+ }
+ if (PARAmode != 0) {
+ HILNconfig();
+ }
+ PARAextensionFlag; 1 uimsbf
+ if (PARAextensionFlag) {
+ // to be defined in MPEG-4 Phase 3
+ }
+ }
+ */
+ paraMode = in.readBits(2);
+
+ if (paraMode != 1) {
+ parseErHvxcConfig(samplingFrequencyIndex, channelConfiguration, audioObjectType, in);
+ }
+ if (paraMode != 0) {
+ parseHilnConfig(samplingFrequencyIndex, channelConfiguration, audioObjectType, in);
+ }
+
+ paraExtensionFlag = in.readBits(1);
+ parametricSpecificConfig = true;
+ }
+
+ private void parseErHvxcConfig(int samplingFrequencyIndex, int channelConfiguration, int audioObjectType, BitReaderBuffer in) throws IOException {
+ /*
+ ErHVXCconfig()
+ {
+ HVXCvarMode; 1 uimsbf
+ HVXCrateMode; 2 uimsbf
+ extensionFlag; 1 uimsbf
+ if (extensionFlag) {
+ var_ScalableFlag; 1 uimsbf
+ }
+ }
+ */
+ hvxcVarMode = in.readBits(1);
+ hvxcRateMode = in.readBits(2);
+ erHvxcExtensionFlag = in.readBits(1);
+
+ if (erHvxcExtensionFlag == 1) {
+ var_ScalableFlag = in.readBits(1);
+ }
+ }
+
+ private void parseHilnConfig(int samplingFrequencyIndex, int channelConfiguration, int audioObjectType, BitReaderBuffer in) throws IOException {
+ /*
+ HILNconfig()
+ {
+ HILNquantMode; 1 uimsbf
+ HILNmaxNumLine; 8 uimsbf
+ HILNsampleRateCode; 4 uimsbf
+ HILNframeLength; 12 uimsbf
+ HILNcontMode; 2 uimsbf
+ }
+ */
+ hilnQuantMode = in.readBits(1);
+ hilnMaxNumLine = in.readBits(8);
+ hilnSampleRateCode = in.readBits(4);
+ hilnFrameLength = in.readBits(12);
+ hilnContMode = in.readBits(2);
+ }
+
+ private void parseHilnEnexConfig(int samplingFrequencyIndex, int channelConfiguration, int audioObjectType, BitReaderBuffer in) throws IOException {
+ /*
+ HILNenexConfig()
+ {
+ HILNenhaLayer; 1 uimsbf
+ if (HILNenhaLayer) {
+ HILNenhaQuantMode; 2 uimsbf
+ }
+ }
+ */
+ hilnEnhaLayer = in.readBits(1);
+ if (hilnEnhaLayer == 1) {
+ hilnEnhaQuantMode = in.readBits(2);
+ }
+ }
+
+ public byte[] getConfigBytes() {
+ return configBytes;
+ }
+
+ public int getAudioObjectType() {
+ return audioObjectType;
+ }
+
+ public int getExtensionAudioObjectType() {
+ return extensionAudioObjectType;
+ }
+
+ public int getSbrPresentFlag() {
+ return sbrPresentFlag;
+ }
+
+ public int getPsPresentFlag() {
+ return psPresentFlag;
+ }
+
+ public void setAudioObjectType(int audioObjectType) {
+ this.audioObjectType = audioObjectType;
+ }
+
+ public void setSamplingFrequencyIndex(int samplingFrequencyIndex) {
+ this.samplingFrequencyIndex = samplingFrequencyIndex;
+ }
+
+ public void setSamplingFrequency(int samplingFrequency) {
+ this.samplingFrequency = samplingFrequency;
+ }
+
+ public void setChannelConfiguration(int channelConfiguration) {
+ this.channelConfiguration = channelConfiguration;
+ }
+
+ @Override
+ public String toString() {
+ final StringBuilder sb = new StringBuilder();
+ sb.append("AudioSpecificConfig");
+ sb.append("{configBytes=").append(Hex.encodeHex(configBytes));
+ sb.append(", audioObjectType=").append(audioObjectType).append(" (").append(audioObjectTypeMap.get(audioObjectType)).append(")");
+ sb.append(", samplingFrequencyIndex=").append(samplingFrequencyIndex).append(" (").append(samplingFrequencyIndexMap.get(samplingFrequencyIndex)).append(")");
+ sb.append(", samplingFrequency=").append(samplingFrequency);
+ sb.append(", channelConfiguration=").append(channelConfiguration);
+ if (extensionAudioObjectType > 0) {
+ sb.append(", extensionAudioObjectType=").append(extensionAudioObjectType).append(" (").append(audioObjectTypeMap.get(extensionAudioObjectType)).append(")");
+ sb.append(", sbrPresentFlag=").append(sbrPresentFlag);
+ sb.append(", psPresentFlag=").append(psPresentFlag);
+ sb.append(", extensionSamplingFrequencyIndex=").append(extensionSamplingFrequencyIndex).append(" (").append(samplingFrequencyIndexMap.get(extensionSamplingFrequencyIndex)).append(")");
+ sb.append(", extensionSamplingFrequency=").append(extensionSamplingFrequency);
+ sb.append(", extensionChannelConfiguration=").append(extensionChannelConfiguration);
+ }
+// sb.append(", sacPayloadEmbedding=").append(sacPayloadEmbedding);
+// sb.append(", fillBits=").append(fillBits);
+// sb.append(", epConfig=").append(epConfig);
+// sb.append(", directMapping=").append(directMapping);
+ sb.append(", syncExtensionType=").append(syncExtensionType);
+ if (gaSpecificConfig) {
+ sb.append(", frameLengthFlag=").append(frameLengthFlag);
+ sb.append(", dependsOnCoreCoder=").append(dependsOnCoreCoder);
+ sb.append(", coreCoderDelay=").append(coreCoderDelay);
+ sb.append(", extensionFlag=").append(extensionFlag);
+ sb.append(", layerNr=").append(layerNr);
+ sb.append(", numOfSubFrame=").append(numOfSubFrame);
+ sb.append(", layer_length=").append(layer_length);
+ sb.append(", aacSectionDataResilienceFlag=").append(aacSectionDataResilienceFlag);
+ sb.append(", aacScalefactorDataResilienceFlag=").append(aacScalefactorDataResilienceFlag);
+ sb.append(", aacSpectralDataResilienceFlag=").append(aacSpectralDataResilienceFlag);
+ sb.append(", extensionFlag3=").append(extensionFlag3);
+ }
+ if (parametricSpecificConfig) {
+ sb.append(", isBaseLayer=").append(isBaseLayer);
+ sb.append(", paraMode=").append(paraMode);
+ sb.append(", paraExtensionFlag=").append(paraExtensionFlag);
+ sb.append(", hvxcVarMode=").append(hvxcVarMode);
+ sb.append(", hvxcRateMode=").append(hvxcRateMode);
+ sb.append(", erHvxcExtensionFlag=").append(erHvxcExtensionFlag);
+ sb.append(", var_ScalableFlag=").append(var_ScalableFlag);
+ sb.append(", hilnQuantMode=").append(hilnQuantMode);
+ sb.append(", hilnMaxNumLine=").append(hilnMaxNumLine);
+ sb.append(", hilnSampleRateCode=").append(hilnSampleRateCode);
+ sb.append(", hilnFrameLength=").append(hilnFrameLength);
+ sb.append(", hilnContMode=").append(hilnContMode);
+ sb.append(", hilnEnhaLayer=").append(hilnEnhaLayer);
+ sb.append(", hilnEnhaQuantMode=").append(hilnEnhaQuantMode);
+ }
+ sb.append('}');
+ return sb.toString();
+ }
+
+ static {
+ // sampling_frequency_index sampling frequeny
+//0x0 96000
+//0x1 88200
+//0x2 64000
+//0x3 48000
+//0x4 44100
+//0x5 32000
+//0x6 24000
+//0x7 22050
+//0x8 16000
+//0x9 12000
+//0xa 11025
+//0xb 8000
+//0xc reserved
+//0xd reserved
+//0xe reserved
+//0xf reserved
+ samplingFrequencyIndexMap.put(0x0, 96000);
+ samplingFrequencyIndexMap.put(0x1, 88200);
+ samplingFrequencyIndexMap.put(0x2, 64000);
+ samplingFrequencyIndexMap.put(0x3, 48000);
+ samplingFrequencyIndexMap.put(0x4, 44100);
+ samplingFrequencyIndexMap.put(0x5, 32000);
+ samplingFrequencyIndexMap.put(0x6, 24000);
+ samplingFrequencyIndexMap.put(0x7, 22050);
+ samplingFrequencyIndexMap.put(0x8, 16000);
+ samplingFrequencyIndexMap.put(0x9, 12000);
+ samplingFrequencyIndexMap.put(0xa, 11025);
+ samplingFrequencyIndexMap.put(0xb, 8000);
+
+ /* audioObjectType IDs
+ 0 Null
+ 1 AAC main X X
+ 2 AAC LC X X X X X X X
+ 3 AAC SSR X X
+ 4 AAC LTP X X X X
+ 5 SBR X X
+ 6 AAC Scalable X X X X
+ 7 TwinVQ X X X
+ 8 CELP X X X X X X
+ 9 HVXC X X X X X
+ 10 (reserved)
+ 11 (reserved)
+ 12 TTSI X X X X X X
+ 13 Main synthetic X X
+ 14 Wavetable synthesis X* X*
+ 15 General MIDI X* X*
+ 16 Algorithmic Synthesis and Audio FX X* X*
+ 17 ER AAC LC X X X
+ 18 (reserved)
+ 19 ER AAC LTP X X
+ 20 ER AAC Scalable X X X
+ 21 ER TwinVQ X X
+ 22 ER BSAC X X
+ 23 ER AAC LD X X X X
+ 24 ER CELP X X X
+ 25 ER HVXC X X
+ 26 ER HILN X
+ 27 ER Parametric X
+ 28 SSC
+ 29 PS X
+ 30 MPEG Surround
+ 31 (escape)
+ 32 Layer-1
+ 33 Layer-2
+ 34 Layer-3
+ 35 DST
+ 36 ALS
+ 37 SLS
+ 38 SLS non-core
+ 39 ER AAC ELD
+ 40 SMR Simple
+ 41 SMR Main
+ */
+ audioObjectTypeMap.put(1, "AAC main");
+ audioObjectTypeMap.put(2, "AAC LC");
+ audioObjectTypeMap.put(3, "AAC SSR");
+ audioObjectTypeMap.put(4, "AAC LTP");
+ audioObjectTypeMap.put(5, "SBR");
+ audioObjectTypeMap.put(6, "AAC Scalable");
+ audioObjectTypeMap.put(7, "TwinVQ");
+ audioObjectTypeMap.put(8, "CELP");
+ audioObjectTypeMap.put(9, "HVXC");
+ audioObjectTypeMap.put(10, "(reserved)");
+ audioObjectTypeMap.put(11, "(reserved)");
+ audioObjectTypeMap.put(12, "TTSI");
+ audioObjectTypeMap.put(13, "Main synthetic");
+ audioObjectTypeMap.put(14, "Wavetable synthesis");
+ audioObjectTypeMap.put(15, "General MIDI");
+ audioObjectTypeMap.put(16, "Algorithmic Synthesis and Audio FX");
+ audioObjectTypeMap.put(17, "ER AAC LC");
+ audioObjectTypeMap.put(18, "(reserved)");
+ audioObjectTypeMap.put(19, "ER AAC LTP");
+ audioObjectTypeMap.put(20, "ER AAC Scalable");
+ audioObjectTypeMap.put(21, "ER TwinVQ");
+ audioObjectTypeMap.put(22, "ER BSAC");
+ audioObjectTypeMap.put(23, "ER AAC LD");
+ audioObjectTypeMap.put(24, "ER CELP");
+ audioObjectTypeMap.put(25, "ER HVXC");
+ audioObjectTypeMap.put(26, "ER HILN");
+ audioObjectTypeMap.put(27, "ER Parametric");
+ audioObjectTypeMap.put(28, "SSC");
+ audioObjectTypeMap.put(29, "PS");
+ audioObjectTypeMap.put(30, "MPEG Surround");
+ audioObjectTypeMap.put(31, "(escape)");
+ audioObjectTypeMap.put(32, "Layer-1");
+ audioObjectTypeMap.put(33, "Layer-2");
+ audioObjectTypeMap.put(34, "Layer-3");
+ audioObjectTypeMap.put(35, "DST");
+ audioObjectTypeMap.put(36, "ALS");
+ audioObjectTypeMap.put(37, "SLS");
+ audioObjectTypeMap.put(38, "SLS non-core");
+ audioObjectTypeMap.put(39, "ER AAC ELD");
+ audioObjectTypeMap.put(40, "SMR Simple");
+ audioObjectTypeMap.put(41, "SMR Main");
+
+ /* profileLevelIds
+ 0x00 Reserved for ISO use -
+ 0x01 Main Audio Profile L1
+ 0x02 Main Audio Profile L2
+ 0x03 Main Audio Profile L3
+ 0x04 Main Audio Profile L4
+ 0x05 Scalable Audio Profile L1
+ 0x06 Scalable Audio Profile L2
+ 0x07 Scalable Audio Profile L3
+ 0x08 Scalable Audio Profile L4
+ 0x09 Speech Audio Profile L1
+ 0x0A Speech Audio Profile L2
+ 0x0B Synthetic Audio Profile L1
+ 0x0C Synthetic Audio Profile L2
+ 0x0D Synthetic Audio Profile L3
+ 0x0E High Quality Audio Profile L1
+ 0x0F High Quality Audio Profile L2
+ 0x10 High Quality Audio Profile L3
+ 0x11 High Quality Audio Profile L4
+ 0x12 High Quality Audio Profile L5
+ 0x13 High Quality Audio Profile L6
+ 0x14 High Quality Audio Profile L7
+ 0x15 High Quality Audio Profile L8
+ 0x16 Low Delay Audio Profile L1
+ 0x17 Low Delay Audio Profile L2
+ 0x18 Low Delay Audio Profile L3
+ 0x19 Low Delay Audio Profile L4
+ 0x1A Low Delay Audio Profile L5
+ 0x1B Low Delay Audio Profile L6
+ 0x1C Low Delay Audio Profile L7
+ 0x1D Low Delay Audio Profile L8
+ 0x1E Natural Audio Profile L1
+ 0x1F Natural Audio Profile L2
+ 0x20 Natural Audio Profile L3
+ 0x21 Natural Audio Profile L4
+ 0x22 Mobile Audio Internetworking Profile L1
+ 0x23 Mobile Audio Internetworking Profile L2
+ 0x24 Mobile Audio Internetworking Profile L3
+ 0x25 Mobile Audio Internetworking Profile L4
+ 0x26 Mobile Audio Internetworking Profile L5
+ 0x27 Mobile Audio Internetworking Profile L6
+ 0x28 AAC Profile L1
+ 0x29 AAC Profile L2
+ 0x2A AAC Profile L4
+ 0x2B AAC Profile L5
+ 0x2C High Efficiency AAC Profile L2
+ 0x2D High Efficiency AAC Profile L3
+ 0x2E High Efficiency AAC Profile L4
+ 0x2F High Efficiency AAC Profile L5
+ 0x30 High Efficiency AAC v2 Profile L2
+ 0x31 High Efficiency AAC v2 Profile L3
+ 0x32 High Efficiency AAC v2 Profile L4
+ 0x33 High Efficiency AAC v2 Profile L5
+ 0x34 Low Delay AAC Profile L1
+ 0x35 Baseline MPEG Surround Profile (see ISO/IEC
+ 23003-1)
+ L1
+ 0x36 Baseline MPEG Surround Profile (see ISO/IEC
+ 23003-1)
+ L2
+ 0x37 Baseline MPEG Surround Profile (see ISO/IEC
+ 23003-1)
+ L3
+ 0x38 Baseline MPEG Surround Profile (see ISO/IEC
+ 23003-1)
+ L4
+ 0c39 Baseline MPEG Surround Profile (see ISO/IEC
+ 23003-1)
+ L5
+ 0x3A Baseline MPEG Surround Profile (see ISO/IEC
+ 23003-1)
+ L6
+ 0x3B - 0x7F reserved for ISO use -
+ 0x80 - 0xFD user private -
+ 0xFE no audio profile specified -
+ 0xFF no audio capability required -
+
+ */
+ }
+
+
+ public int getSamplingFrequency() {
+ return samplingFrequencyIndex == 0xf ? samplingFrequency : samplingFrequencyIndexMap.get(samplingFrequencyIndex);
+ }
+
+ public int getChannelConfiguration() {
+ return channelConfiguration;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+
+ AudioSpecificConfig that = (AudioSpecificConfig) o;
+
+ if (aacScalefactorDataResilienceFlag != that.aacScalefactorDataResilienceFlag) {
+ return false;
+ }
+ if (aacSectionDataResilienceFlag != that.aacSectionDataResilienceFlag) {
+ return false;
+ }
+ if (aacSpectralDataResilienceFlag != that.aacSpectralDataResilienceFlag) {
+ return false;
+ }
+ if (audioObjectType != that.audioObjectType) {
+ return false;
+ }
+ if (channelConfiguration != that.channelConfiguration) {
+ return false;
+ }
+ if (coreCoderDelay != that.coreCoderDelay) {
+ return false;
+ }
+ if (dependsOnCoreCoder != that.dependsOnCoreCoder) {
+ return false;
+ }
+ if (directMapping != that.directMapping) {
+ return false;
+ }
+ if (epConfig != that.epConfig) {
+ return false;
+ }
+ if (erHvxcExtensionFlag != that.erHvxcExtensionFlag) {
+ return false;
+ }
+ if (extensionAudioObjectType != that.extensionAudioObjectType) {
+ return false;
+ }
+ if (extensionChannelConfiguration != that.extensionChannelConfiguration) {
+ return false;
+ }
+ if (extensionFlag != that.extensionFlag) {
+ return false;
+ }
+ if (extensionFlag3 != that.extensionFlag3) {
+ return false;
+ }
+ if (extensionSamplingFrequency != that.extensionSamplingFrequency) {
+ return false;
+ }
+ if (extensionSamplingFrequencyIndex != that.extensionSamplingFrequencyIndex) {
+ return false;
+ }
+ if (fillBits != that.fillBits) {
+ return false;
+ }
+ if (frameLengthFlag != that.frameLengthFlag) {
+ return false;
+ }
+ if (gaSpecificConfig != that.gaSpecificConfig) {
+ return false;
+ }
+ if (hilnContMode != that.hilnContMode) {
+ return false;
+ }
+ if (hilnEnhaLayer != that.hilnEnhaLayer) {
+ return false;
+ }
+ if (hilnEnhaQuantMode != that.hilnEnhaQuantMode) {
+ return false;
+ }
+ if (hilnFrameLength != that.hilnFrameLength) {
+ return false;
+ }
+ if (hilnMaxNumLine != that.hilnMaxNumLine) {
+ return false;
+ }
+ if (hilnQuantMode != that.hilnQuantMode) {
+ return false;
+ }
+ if (hilnSampleRateCode != that.hilnSampleRateCode) {
+ return false;
+ }
+ if (hvxcRateMode != that.hvxcRateMode) {
+ return false;
+ }
+ if (hvxcVarMode != that.hvxcVarMode) {
+ return false;
+ }
+ if (isBaseLayer != that.isBaseLayer) {
+ return false;
+ }
+ if (layerNr != that.layerNr) {
+ return false;
+ }
+ if (layer_length != that.layer_length) {
+ return false;
+ }
+ if (numOfSubFrame != that.numOfSubFrame) {
+ return false;
+ }
+ if (paraExtensionFlag != that.paraExtensionFlag) {
+ return false;
+ }
+ if (paraMode != that.paraMode) {
+ return false;
+ }
+ if (parametricSpecificConfig != that.parametricSpecificConfig) {
+ return false;
+ }
+ if (psPresentFlag != that.psPresentFlag) {
+ return false;
+ }
+ if (sacPayloadEmbedding != that.sacPayloadEmbedding) {
+ return false;
+ }
+ if (samplingFrequency != that.samplingFrequency) {
+ return false;
+ }
+ if (samplingFrequencyIndex != that.samplingFrequencyIndex) {
+ return false;
+ }
+ if (sbrPresentFlag != that.sbrPresentFlag) {
+ return false;
+ }
+ if (syncExtensionType != that.syncExtensionType) {
+ return false;
+ }
+ if (var_ScalableFlag != that.var_ScalableFlag) {
+ return false;
+ }
+ if (!Arrays.equals(configBytes, that.configBytes)) {
+ return false;
+ }
+
+ return true;
+ }
+
+ @Override
+ public int hashCode() {
+ int result = configBytes != null ? Arrays.hashCode(configBytes) : 0;
+ result = 31 * result + audioObjectType;
+ result = 31 * result + samplingFrequencyIndex;
+ result = 31 * result + samplingFrequency;
+ result = 31 * result + channelConfiguration;
+ result = 31 * result + extensionAudioObjectType;
+ result = 31 * result + sbrPresentFlag;
+ result = 31 * result + psPresentFlag;
+ result = 31 * result + extensionSamplingFrequencyIndex;
+ result = 31 * result + extensionSamplingFrequency;
+ result = 31 * result + extensionChannelConfiguration;
+ result = 31 * result + sacPayloadEmbedding;
+ result = 31 * result + fillBits;
+ result = 31 * result + epConfig;
+ result = 31 * result + directMapping;
+ result = 31 * result + syncExtensionType;
+ result = 31 * result + frameLengthFlag;
+ result = 31 * result + dependsOnCoreCoder;
+ result = 31 * result + coreCoderDelay;
+ result = 31 * result + extensionFlag;
+ result = 31 * result + layerNr;
+ result = 31 * result + numOfSubFrame;
+ result = 31 * result + layer_length;
+ result = 31 * result + aacSectionDataResilienceFlag;
+ result = 31 * result + aacScalefactorDataResilienceFlag;
+ result = 31 * result + aacSpectralDataResilienceFlag;
+ result = 31 * result + extensionFlag3;
+ result = 31 * result + (gaSpecificConfig ? 1 : 0);
+ result = 31 * result + isBaseLayer;
+ result = 31 * result + paraMode;
+ result = 31 * result + paraExtensionFlag;
+ result = 31 * result + hvxcVarMode;
+ result = 31 * result + hvxcRateMode;
+ result = 31 * result + erHvxcExtensionFlag;
+ result = 31 * result + var_ScalableFlag;
+ result = 31 * result + hilnQuantMode;
+ result = 31 * result + hilnMaxNumLine;
+ result = 31 * result + hilnSampleRateCode;
+ result = 31 * result + hilnFrameLength;
+ result = 31 * result + hilnContMode;
+ result = 31 * result + hilnEnhaLayer;
+ result = 31 * result + hilnEnhaQuantMode;
+ result = 31 * result + (parametricSpecificConfig ? 1 : 0);
+ return result;
+ }
+}
diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/boxes/mp4/objectdescriptors/.svn/text-base/BaseDescriptor.java.svn-base b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/mp4/objectdescriptors/.svn/text-base/BaseDescriptor.java.svn-base
new file mode 100644
index 0000000..6d94680
--- /dev/null
+++ b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/mp4/objectdescriptors/.svn/text-base/BaseDescriptor.java.svn-base
@@ -0,0 +1,99 @@
+/*
+ * Copyright 2011 castLabs, 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.googlecode.mp4parser.boxes.mp4.objectdescriptors;
+
+import com.coremedia.iso.IsoTypeReader;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+
+/*
+abstract aligned(8) expandable(228-1) class BaseDescriptor : bit(8) tag=0 {
+// empty. To be filled by classes extending this class.
+}
+
+int sizeOfInstance = 0;
+bit(1) nextByte;
+bit(7) sizeOfInstance;
+while(nextByte) {
+bit(1) nextByte;
+bit(7) sizeByte;
+sizeOfInstance = sizeOfInstance<<7 | sizeByte;
+}
+ */
+@Descriptor(tags = 0x00)
+public abstract class BaseDescriptor {
+ int tag;
+ int sizeOfInstance;
+ int sizeBytes;
+
+ public BaseDescriptor() {
+ }
+
+ public int getTag() {
+ return tag;
+ }
+
+ public int getSize() {
+ return sizeOfInstance
+ + 1//1 for the tag
+ + sizeBytes;
+ }
+
+ public int getSizeOfInstance() {
+ return sizeOfInstance;
+ }
+
+ public int getSizeBytes() {
+ return sizeBytes;
+ }
+
+ public final void parse(int tag, ByteBuffer bb) throws IOException {
+ this.tag = tag;
+
+ int i = 0;
+ int tmp = IsoTypeReader.readUInt8(bb);
+ i++;
+ sizeOfInstance = tmp & 0x7f;
+ while (tmp >>> 7 == 1) { //nextbyte indicator bit
+ tmp = IsoTypeReader.readUInt8(bb);
+ i++;
+ //sizeOfInstance = sizeOfInstance<<7 | sizeByte;
+ sizeOfInstance = sizeOfInstance << 7 | tmp & 0x7f;
+ }
+ sizeBytes = i;
+ ByteBuffer detailSource = bb.slice();
+ detailSource.limit(sizeOfInstance);
+ parseDetail(detailSource);
+ assert detailSource.remaining() == 0: this.getClass().getSimpleName() + " has not been fully parsed";
+ bb.position(bb.position() + sizeOfInstance);
+ }
+
+ public abstract void parseDetail(ByteBuffer bb) throws IOException;
+
+
+
+ @Override
+ public String toString() {
+ final StringBuilder sb = new StringBuilder();
+ sb.append("BaseDescriptor");
+ sb.append("{tag=").append(tag);
+ sb.append(", sizeOfInstance=").append(sizeOfInstance);
+ sb.append('}');
+ return sb.toString();
+ }
+}
diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/boxes/mp4/objectdescriptors/.svn/text-base/BitReaderBuffer.java.svn-base b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/mp4/objectdescriptors/.svn/text-base/BitReaderBuffer.java.svn-base
new file mode 100644
index 0000000..7221503
--- /dev/null
+++ b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/mp4/objectdescriptors/.svn/text-base/BitReaderBuffer.java.svn-base
@@ -0,0 +1,51 @@
+package com.googlecode.mp4parser.boxes.mp4.objectdescriptors;
+
+import java.nio.ByteBuffer;
+
+public class BitReaderBuffer {
+
+ private ByteBuffer buffer;
+ int initialPos;
+ int position;
+
+ public BitReaderBuffer(ByteBuffer buffer) {
+ this.buffer = buffer;
+ initialPos = buffer.position();
+ }
+
+ public int readBits(int i) {
+ byte b = buffer.get(initialPos + position / 8);
+ int v = b < 0 ? b + 256 : b;
+ int left = 8 - position % 8;
+ int rc;
+ if (i <= left) {
+ rc = (v << (position % 8) & 0xFF) >> ((position % 8) + (left - i));
+ position += i;
+ } else {
+ int now = left;
+ int then = i - left;
+ rc = readBits(now);
+ rc = rc << then;
+ rc += readBits(then);
+ }
+ buffer.position(initialPos + (int) Math.ceil((double) position / 8));
+ return rc;
+ }
+
+ public int getPosition() {
+ return position;
+ }
+
+ public int byteSync() {
+ int left = 8 - position % 8;
+ if (left == 8) {
+ left = 0;
+ }
+ readBits(left);
+ return left;
+ }
+
+ public int remainingBits() {
+ return buffer.limit() * 8 - position;
+ }
+}
diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/boxes/mp4/objectdescriptors/.svn/text-base/BitWriterBuffer.java.svn-base b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/mp4/objectdescriptors/.svn/text-base/BitWriterBuffer.java.svn-base
new file mode 100644
index 0000000..e6ea67f
--- /dev/null
+++ b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/mp4/objectdescriptors/.svn/text-base/BitWriterBuffer.java.svn-base
@@ -0,0 +1,36 @@
+package com.googlecode.mp4parser.boxes.mp4.objectdescriptors;
+
+import java.nio.ByteBuffer;
+
+public class BitWriterBuffer {
+
+ private ByteBuffer buffer;
+ int initialPos;
+ int position = 0;
+
+ public BitWriterBuffer(ByteBuffer buffer) {
+ this.buffer = buffer;
+ this.initialPos = buffer.position();
+ }
+
+ public void writeBits(int i, int numBits) {
+ assert i <= ((1 << numBits)-1): String.format("Trying to write a value bigger (%s) than the number bits (%s) allows. " +
+ "Please mask the value before writing it and make your code is really working as intended.", i, (1<<numBits)-1);
+
+ int left = 8 - position % 8;
+ if (numBits <= left) {
+ int current = (buffer.get(initialPos + position / 8));
+ current = current < 0 ? current + 256 : current;
+ current += i << (left - numBits);
+ buffer.put(initialPos + position / 8, (byte) (current > 127 ? current - 256 : current));
+ position += numBits;
+ } else {
+ int bitsSecondWrite = numBits - left;
+ writeBits(i >> bitsSecondWrite, left);
+ writeBits(i & (1 << bitsSecondWrite) - 1, bitsSecondWrite);
+ }
+ buffer.position(initialPos + position / 8 + ((position % 8 > 0) ? 1 : 0));
+ }
+
+
+}
diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/boxes/mp4/objectdescriptors/.svn/text-base/DecoderConfigDescriptor.java.svn-base b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/mp4/objectdescriptors/.svn/text-base/DecoderConfigDescriptor.java.svn-base
new file mode 100644
index 0000000..69d603a
--- /dev/null
+++ b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/mp4/objectdescriptors/.svn/text-base/DecoderConfigDescriptor.java.svn-base
@@ -0,0 +1,262 @@
+/*
+ * Copyright 2011 castLabs, 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.googlecode.mp4parser.boxes.mp4.objectdescriptors;
+
+import com.coremedia.iso.Hex;
+import com.coremedia.iso.IsoTypeReader;
+import com.coremedia.iso.IsoTypeWriter;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.logging.Logger;
+
+/**
+ * class DecoderConfigDescriptor extends BaseDescriptor : bit(8)
+ * tag=DecoderConfigDescrTag {
+ * bit(8) objectTypeIndication;
+ * bit(6) streamType;
+ * bit(1) upStream;
+ * const bit(1) reserved=1;
+ * bit(24) bufferSizeDB;
+ * bit(32) maxBitrate;
+ * bit(32) avgBitrate;
+ * DecoderSpecificInfo decSpecificInfo[0 .. 1];
+ * profileLevelIndicationIndexDescriptor profileLevelIndicationIndexDescr
+ * [0..255];
+ * }
+ */
+@Descriptor(tags = {0x04})
+public class DecoderConfigDescriptor extends BaseDescriptor {
+ private static Logger log = Logger.getLogger(DecoderConfigDescriptor.class.getName());
+
+
+ int objectTypeIndication;
+ int streamType;
+ int upStream;
+ int bufferSizeDB;
+ long maxBitRate;
+ long avgBitRate;
+
+ DecoderSpecificInfo decoderSpecificInfo;
+ AudioSpecificConfig audioSpecificInfo;
+ List<ProfileLevelIndicationDescriptor> profileLevelIndicationDescriptors = new ArrayList<ProfileLevelIndicationDescriptor>();
+ byte[] configDescriptorDeadBytes;
+
+ @Override
+ public void parseDetail(ByteBuffer bb) throws IOException {
+ objectTypeIndication = IsoTypeReader.readUInt8(bb);
+
+ int data = IsoTypeReader.readUInt8(bb);
+ streamType = data >>> 2;
+ upStream = (data >> 1) & 0x1;
+
+ bufferSizeDB = IsoTypeReader.readUInt24(bb);
+ maxBitRate = IsoTypeReader.readUInt32(bb);
+ avgBitRate = IsoTypeReader.readUInt32(bb);
+
+
+
+ BaseDescriptor descriptor;
+ if (bb.remaining() > 2) { //1byte tag + at least 1byte size
+ final int begin = bb.position();
+ descriptor = ObjectDescriptorFactory.createFrom(objectTypeIndication, bb);
+ final int read = bb.position() - begin;
+ log.finer(descriptor + " - DecoderConfigDescr1 read: " + read + ", size: " + (descriptor != null ? descriptor.getSize() : null));
+ if (descriptor != null) {
+ final int size = descriptor.getSize();
+ if (read < size) {
+ //skip
+ configDescriptorDeadBytes = new byte[size - read];
+ bb.get(configDescriptorDeadBytes);
+ }
+ }
+ if (descriptor instanceof DecoderSpecificInfo) {
+ decoderSpecificInfo = (DecoderSpecificInfo) descriptor;
+ }
+ if (descriptor instanceof AudioSpecificConfig) {
+ audioSpecificInfo = (AudioSpecificConfig) descriptor;
+ }
+ }
+
+ while (bb.remaining() > 2) {
+ final long begin = bb.position();
+ descriptor = ObjectDescriptorFactory.createFrom(objectTypeIndication, bb);
+ final long read = bb.position() - begin;
+ log.finer(descriptor + " - DecoderConfigDescr2 read: " + read + ", size: " + (descriptor != null ? descriptor.getSize() : null));
+ if (descriptor instanceof ProfileLevelIndicationDescriptor) {
+ profileLevelIndicationDescriptors.add((ProfileLevelIndicationDescriptor) descriptor);
+ }
+ }
+ }
+ public int serializedSize() {
+ return 15 + audioSpecificInfo.serializedSize();
+ }
+
+ public ByteBuffer serialize() {
+ ByteBuffer out = ByteBuffer.allocate(serializedSize());
+ IsoTypeWriter.writeUInt8(out, 4);
+ IsoTypeWriter.writeUInt8(out, serializedSize() - 2);
+ IsoTypeWriter.writeUInt8(out, objectTypeIndication);
+ int flags = (streamType << 2) | (upStream << 1) | 1;
+ IsoTypeWriter.writeUInt8(out, flags);
+ IsoTypeWriter.writeUInt24(out, bufferSizeDB);
+ IsoTypeWriter.writeUInt32(out, maxBitRate);
+ IsoTypeWriter.writeUInt32(out, avgBitRate);
+ out.put(audioSpecificInfo.serialize().array());
+ return out;
+ }
+
+ public DecoderSpecificInfo getDecoderSpecificInfo() {
+ return decoderSpecificInfo;
+ }
+
+ public AudioSpecificConfig getAudioSpecificInfo() {
+ return audioSpecificInfo;
+ }
+
+ public void setAudioSpecificInfo(AudioSpecificConfig audioSpecificInfo) {
+ this.audioSpecificInfo = audioSpecificInfo;
+ }
+
+ public List<ProfileLevelIndicationDescriptor> getProfileLevelIndicationDescriptors() {
+ return profileLevelIndicationDescriptors;
+ }
+
+ public int getObjectTypeIndication() {
+ return objectTypeIndication;
+ }
+
+ public void setObjectTypeIndication(int objectTypeIndication) {
+ this.objectTypeIndication = objectTypeIndication;
+ }
+
+ public int getStreamType() {
+ return streamType;
+ }
+
+ public void setStreamType(int streamType) {
+ this.streamType = streamType;
+ }
+
+ public int getUpStream() {
+ return upStream;
+ }
+
+ public void setUpStream(int upStream) {
+ this.upStream = upStream;
+ }
+
+ public int getBufferSizeDB() {
+ return bufferSizeDB;
+ }
+
+ public void setBufferSizeDB(int 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;
+ }
+
+ @Override
+ public String toString() {
+ final StringBuilder sb = new StringBuilder();
+ sb.append("DecoderConfigDescriptor");
+ sb.append("{objectTypeIndication=").append(objectTypeIndication);
+ sb.append(", streamType=").append(streamType);
+ sb.append(", upStream=").append(upStream);
+ sb.append(", bufferSizeDB=").append(bufferSizeDB);
+ sb.append(", maxBitRate=").append(maxBitRate);
+ sb.append(", avgBitRate=").append(avgBitRate);
+ sb.append(", decoderSpecificInfo=").append(decoderSpecificInfo);
+ sb.append(", audioSpecificInfo=").append(audioSpecificInfo);
+ sb.append(", configDescriptorDeadBytes=").append(Hex.encodeHex(configDescriptorDeadBytes != null ? configDescriptorDeadBytes : new byte[]{}));
+ sb.append(", profileLevelIndicationDescriptors=").append(profileLevelIndicationDescriptors == null ? "null" : Arrays.asList(profileLevelIndicationDescriptors).toString());
+ sb.append('}');
+ return sb.toString();
+ }
+ /*objectTypeIndication values
+ 0x00 Forbidden
+ 0x01 Systems ISO/IEC 14496-1 a
+ 0x02 Systems ISO/IEC 14496-1 b
+ 0x03 Interaction Stream
+ 0x04 Systems ISO/IEC 14496-1 Extended BIFS Configuration c
+ 0x05 Systems ISO/IEC 14496-1 AFX d
+ 0x06 Font Data Stream
+ 0x07 Synthesized Texture Stream
+ 0x08 Streaming Text Stream
+ 0x09-0x1F reserved for ISO use
+ 0x20 Visual ISO/IEC 14496-2 e
+ 0x21 Visual ITU-T Recommendation H.264 | ISO/IEC 14496-10 f
+ 0x22 Parameter Sets for ITU-T Recommendation H.264 | ISO/IEC 14496-10 f
+ 0x23-0x3F reserved for ISO use
+ 0x40 Audio ISO/IEC 14496-3 g
+ 0x41-0x5F reserved for ISO use
+ 0x60 Visual ISO/IEC 13818-2 Simple Profile
+ 0x61 Visual ISO/IEC 13818-2 Main Profile
+ 0x62 Visual ISO/IEC 13818-2 SNR Profile
+ 0x63 Visual ISO/IEC 13818-2 Spatial Profile
+ 0x64 Visual ISO/IEC 13818-2 High Profile
+ 0x65 Visual ISO/IEC 13818-2 422 Profile
+ 0x66 Audio ISO/IEC 13818-7 Main Profile
+ 0x67 Audio ISO/IEC 13818-7 LowComplexity Profile
+ 0x68 Audio ISO/IEC 13818-7 Scaleable Sampling Rate Profile
+ 0x69 Audio ISO/IEC 13818-3
+ 0x6A Visual ISO/IEC 11172-2
+ 0x6B Audio ISO/IEC 11172-3
+ 0x6C Visual ISO/IEC 10918-1
+ 0x6D reserved for registration authority i
+ 0x6E Visual ISO/IEC 15444-1
+ 0x6F - 0x9F reserved for ISO use
+ 0xA0 - 0xBF reserved for registration authority i
+ 0xC0 - 0xE0 user private
+ 0xE1 reserved for registration authority i
+ 0xE2 - 0xFE user private
+ 0xFF no object type specified h
+ */
+ /* streamType values
+ 0x00 Forbidden
+ 0x01 ObjectDescriptorStream (see 7.2.5)
+ 0x02 ClockReferenceStream (see 7.3.2.5)
+ 0x03 SceneDescriptionStream (see ISO/IEC 14496-11)
+ 0x04 VisualStream
+ 0x05 AudioStream
+ 0x06 MPEG7Stream
+ 0x07 IPMPStream (see 7.2.3.2)
+ 0x08 ObjectContentInfoStream (see 7.2.4.2)
+ 0x09 MPEGJStream
+ 0x0A Interaction Stream
+ 0x0B IPMPToolStream (see [ISO/IEC 14496-13])
+ 0x0C - 0x1F reserved for ISO use
+ 0x20 - 0x3F user private
+ */
+}
diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/boxes/mp4/objectdescriptors/.svn/text-base/DecoderSpecificInfo.java.svn-base b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/mp4/objectdescriptors/.svn/text-base/DecoderSpecificInfo.java.svn-base
new file mode 100644
index 0000000..574943c
--- /dev/null
+++ b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/mp4/objectdescriptors/.svn/text-base/DecoderSpecificInfo.java.svn-base
@@ -0,0 +1,85 @@
+/*
+ * Copyright 2011 castLabs, 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.googlecode.mp4parser.boxes.mp4.objectdescriptors;
+
+import com.coremedia.iso.Hex;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.util.Arrays;
+
+/**
+ * abstract class DecoderSpecificInfo extends BaseDescriptor : bit(8)
+ * tag=DecSpecificInfoTag
+ * {
+ * // empty. To be filled by classes extending this class.
+ * }
+ */
+@Descriptor(tags = 0x05)
+public class DecoderSpecificInfo extends BaseDescriptor {
+ byte[] bytes;
+
+ @Override
+ public void parseDetail(ByteBuffer bb) throws IOException {
+ if (sizeOfInstance > 0) {
+ bytes = new byte[sizeOfInstance];
+ bb.get(bytes);
+ }
+ }
+
+ public int serializedSize() {
+ return bytes.length;
+ }
+
+ public ByteBuffer serialize() {
+ ByteBuffer out = ByteBuffer.wrap(bytes);
+
+ return out;
+ }
+
+ @Override
+ public String toString() {
+ final StringBuilder sb = new StringBuilder();
+ sb.append("DecoderSpecificInfo");
+ sb.append("{bytes=").append(bytes == null ? "null" : Hex.encodeHex(bytes));
+ sb.append('}');
+ return sb.toString();
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+
+ DecoderSpecificInfo that = (DecoderSpecificInfo) o;
+
+ if (!Arrays.equals(bytes, that.bytes)) {
+ return false;
+ }
+
+ return true;
+ }
+
+ @Override
+ public int hashCode() {
+ return bytes != null ? Arrays.hashCode(bytes) : 0;
+ }
+}
diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/boxes/mp4/objectdescriptors/.svn/text-base/Descriptor.java.svn-base b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/mp4/objectdescriptors/.svn/text-base/Descriptor.java.svn-base
new file mode 100644
index 0000000..11020c7
--- /dev/null
+++ b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/mp4/objectdescriptors/.svn/text-base/Descriptor.java.svn-base
@@ -0,0 +1,39 @@
+/*
+ * Copyright 2011 castLabs, 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.googlecode.mp4parser.boxes.mp4.objectdescriptors;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Created by IntelliJ IDEA.
+ * User: mstattma
+ * Date: 06.08.2010
+ * Time: 06:54:58
+ * To change this template use File | Settings | File Templates.
+ */
+@Documented
+@Target(ElementType.TYPE)
+@Retention(RetentionPolicy.RUNTIME)
+public @interface Descriptor {
+ int[] tags();
+
+ int objectTypeIndication() default -1;
+}
diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/boxes/mp4/objectdescriptors/.svn/text-base/ESDescriptor.java.svn-base b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/mp4/objectdescriptors/.svn/text-base/ESDescriptor.java.svn-base
new file mode 100644
index 0000000..3bb4821
--- /dev/null
+++ b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/mp4/objectdescriptors/.svn/text-base/ESDescriptor.java.svn-base
@@ -0,0 +1,376 @@
+/*
+ * Copyright 2011 castLabs, 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.googlecode.mp4parser.boxes.mp4.objectdescriptors;
+
+import com.coremedia.iso.IsoTypeReader;
+import com.coremedia.iso.IsoTypeWriter;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.logging.Logger;
+
+/*
+class ES_Descriptor extends BaseDescriptor : bit(8) tag=ES_DescrTag {
+bit(16) ES_ID;
+bit(1) streamDependenceFlag;
+bit(1) URL_Flag;
+bit(1) OCRstreamFlag;
+bit(5) streamPriority;
+if (streamDependenceFlag)
+bit(16) dependsOn_ES_ID;
+if (URL_Flag) {
+bit(8) URLlength;
+bit(8) URLstring[URLlength];
+}
+if (OCRstreamFlag)
+bit(16) OCR_ES_Id;
+DecoderConfigDescriptor decConfigDescr;
+if (ODProfileLevelIndication==0x01) //no SL extension.
+{
+SLConfigDescriptor slConfigDescr;
+}
+else // SL extension is possible.
+{
+SLConfigDescriptor slConfigDescr;
+}
+IPI_DescrPointer ipiPtr[0 .. 1];
+IP_IdentificationDataSet ipIDS[0 .. 255];
+IPMP_DescriptorPointer ipmpDescrPtr[0 .. 255];
+LanguageDescriptor langDescr[0 .. 255];
+QoS_Descriptor qosDescr[0 .. 1];
+RegistrationDescriptor regDescr[0 .. 1];
+ExtensionDescriptor extDescr[0 .. 255];
+}
+ */
+@Descriptor(tags = {0x03})
+public class ESDescriptor extends BaseDescriptor {
+ private static Logger log = Logger.getLogger(ESDescriptor.class.getName());
+
+ int esId;
+ int streamDependenceFlag;
+ int URLFlag;
+ int oCRstreamFlag;
+ int streamPriority;
+
+
+ int URLLength = 0;
+ String URLString;
+ int remoteODFlag;
+
+ int dependsOnEsId;
+ int oCREsId;
+
+ DecoderConfigDescriptor decoderConfigDescriptor;
+ SLConfigDescriptor slConfigDescriptor;
+ List<BaseDescriptor> otherDescriptors = new ArrayList<BaseDescriptor>();
+
+ @Override
+ public void parseDetail(ByteBuffer bb) throws IOException {
+ esId = IsoTypeReader.readUInt16(bb);
+
+ int data = IsoTypeReader.readUInt8(bb);
+ streamDependenceFlag = data >>> 7;
+ URLFlag = (data >>> 6) & 0x1;
+ oCRstreamFlag = (data >>> 5) & 0x1;
+ streamPriority = data & 0x1f;
+
+ if (streamDependenceFlag == 1) {
+ dependsOnEsId = IsoTypeReader.readUInt16(bb);
+ }
+ if (URLFlag == 1) {
+ URLLength = IsoTypeReader.readUInt8(bb);
+ URLString = IsoTypeReader.readString(bb, URLLength);
+ }
+ if (oCRstreamFlag == 1) {
+ oCREsId = IsoTypeReader.readUInt16(bb);
+ }
+
+ int baseSize = 1 /*tag*/ + getSizeBytes() + 2 + 1 + (streamDependenceFlag == 1 ? 2 : 0) + (URLFlag == 1 ? 1 + URLLength : 0) + (oCRstreamFlag == 1 ? 2 : 0);
+
+ int begin = bb.position();
+ if (getSize() > baseSize + 2) {
+ BaseDescriptor descriptor = ObjectDescriptorFactory.createFrom(-1, bb);
+ final long read = bb.position() - begin;
+ log.finer(descriptor + " - ESDescriptor1 read: " + read + ", size: " + (descriptor != null ? descriptor.getSize() : null));
+ if (descriptor != null) {
+ final int size = descriptor.getSize();
+ bb.position(begin + size);
+ baseSize += size;
+ } else {
+ baseSize += read;
+ }
+ if (descriptor instanceof DecoderConfigDescriptor) {
+ decoderConfigDescriptor = (DecoderConfigDescriptor) descriptor;
+ }
+ }
+
+ begin = bb.position();
+ if (getSize() > baseSize + 2) {
+ BaseDescriptor descriptor = ObjectDescriptorFactory.createFrom(-1, bb);
+ final long read = bb.position() - begin;
+ log.finer(descriptor + " - ESDescriptor2 read: " + read + ", size: " + (descriptor != null ? descriptor.getSize() : null));
+ if (descriptor != null) {
+ final int size = descriptor.getSize();
+ bb.position(begin + size);
+ baseSize += size;
+ } else {
+ baseSize += read;
+ }
+ if (descriptor instanceof SLConfigDescriptor) {
+ slConfigDescriptor = (SLConfigDescriptor) descriptor;
+ }
+ } else {
+ log.warning("SLConfigDescriptor is missing!");
+ }
+
+ while (getSize() - baseSize > 2) {
+ begin = bb.position();
+ BaseDescriptor descriptor = ObjectDescriptorFactory.createFrom(-1, bb);
+ final long read = bb.position() - begin;
+ log.finer(descriptor + " - ESDescriptor3 read: " + read + ", size: " + (descriptor != null ? descriptor.getSize() : null));
+ if (descriptor != null) {
+ final int size = descriptor.getSize();
+ bb.position(begin + size);
+ baseSize += size;
+ } else {
+ baseSize += read;
+ }
+ otherDescriptors.add(descriptor);
+ }
+ }
+ public int serializedSize() {
+ int out = 5;
+ if (streamDependenceFlag > 0) {
+ out += 2;
+ }
+ if (URLFlag > 0) {
+ out += 1 + URLLength;
+ }
+ if (oCRstreamFlag > 0) {
+ out += 2;
+ }
+
+ out += decoderConfigDescriptor.serializedSize();
+ out += slConfigDescriptor.serializedSize();
+
+ // Doesn't handle other descriptors yet
+
+ return out;
+ }
+
+ public ByteBuffer serialize() {
+ ByteBuffer out = ByteBuffer.allocate(serializedSize()); // Usually is around 30 bytes, so 200 should be enough...
+ IsoTypeWriter.writeUInt8(out, 3);
+ IsoTypeWriter.writeUInt8(out, serializedSize() - 2); // Not OK for longer sizes!
+ IsoTypeWriter.writeUInt16(out, esId);
+ int flags = (streamDependenceFlag << 7) | (URLFlag << 6) | (oCRstreamFlag << 5) | (streamPriority & 0x1f);
+ IsoTypeWriter.writeUInt8(out, flags);
+ if (streamDependenceFlag > 0) {
+ IsoTypeWriter.writeUInt16(out, dependsOnEsId);
+ }
+ if (URLFlag > 0) {
+ IsoTypeWriter.writeUInt8(out, URLLength);
+ IsoTypeWriter.writeUtf8String(out, URLString);
+ }
+ if (oCRstreamFlag > 0) {
+ IsoTypeWriter.writeUInt16(out, oCREsId);
+ }
+
+ ByteBuffer dec = decoderConfigDescriptor.serialize();
+ ByteBuffer sl = slConfigDescriptor.serialize();
+ out.put(dec.array());
+ out.put(sl.array());
+
+ // Doesn't handle other descriptors yet
+
+ return out;
+ }
+
+// @Override
+// public int getSize() {
+// return 3 + (streamDependenceFlag == 1 ? 2 : 0) +
+// (URLFlag == 1 ? 1 + 8 * URLLength : 0) +
+// (oCRstreamFlag == 1 ? 2 : 0);
+// }
+
+ public DecoderConfigDescriptor getDecoderConfigDescriptor() {
+ return decoderConfigDescriptor;
+ }
+
+ public SLConfigDescriptor getSlConfigDescriptor() {
+ return slConfigDescriptor;
+ }
+
+ public void setDecoderConfigDescriptor(DecoderConfigDescriptor decoderConfigDescriptor) {
+ this.decoderConfigDescriptor = decoderConfigDescriptor;
+ }
+
+ public void setSlConfigDescriptor(SLConfigDescriptor slConfigDescriptor) {
+ this.slConfigDescriptor = slConfigDescriptor;
+ }
+
+ public List<BaseDescriptor> getOtherDescriptors() {
+ return otherDescriptors;
+ }
+
+ public int getoCREsId() {
+ return oCREsId;
+ }
+
+ public void setoCREsId(int oCREsId) {
+ this.oCREsId = oCREsId;
+ }
+
+ public int getEsId() {
+ return esId;
+ }
+
+ public void setEsId(int esId) {
+ this.esId = esId;
+ }
+
+ public int getStreamDependenceFlag() {
+ return streamDependenceFlag;
+ }
+
+ public void setStreamDependenceFlag(int streamDependenceFlag) {
+ this.streamDependenceFlag = streamDependenceFlag;
+ }
+
+ public int getURLFlag() {
+ return URLFlag;
+ }
+
+ public void setURLFlag(int URLFlag) {
+ this.URLFlag = URLFlag;
+ }
+
+ public int getoCRstreamFlag() {
+ return oCRstreamFlag;
+ }
+
+ public void setoCRstreamFlag(int oCRstreamFlag) {
+ this.oCRstreamFlag = oCRstreamFlag;
+ }
+
+ public int getStreamPriority() {
+ return streamPriority;
+ }
+
+ public void setStreamPriority(int streamPriority) {
+ this.streamPriority = streamPriority;
+ }
+
+ public int getURLLength() {
+ return URLLength;
+ }
+
+ public void setURLLength(int URLLength) {
+ this.URLLength = URLLength;
+ }
+
+ public String getURLString() {
+ return URLString;
+ }
+
+ public void setURLString(String URLString) {
+ this.URLString = URLString;
+ }
+
+ public int getRemoteODFlag() {
+ return remoteODFlag;
+ }
+
+ public void setRemoteODFlag(int remoteODFlag) {
+ this.remoteODFlag = remoteODFlag;
+ }
+
+ public int getDependsOnEsId() {
+ return dependsOnEsId;
+ }
+
+ public void setDependsOnEsId(int dependsOnEsId) {
+ this.dependsOnEsId = dependsOnEsId;
+ }
+
+ @Override
+ public String toString() {
+ final StringBuilder sb = new StringBuilder();
+ sb.append("ESDescriptor");
+ sb.append("{esId=").append(esId);
+ sb.append(", streamDependenceFlag=").append(streamDependenceFlag);
+ sb.append(", URLFlag=").append(URLFlag);
+ sb.append(", oCRstreamFlag=").append(oCRstreamFlag);
+ sb.append(", streamPriority=").append(streamPriority);
+ sb.append(", URLLength=").append(URLLength);
+ sb.append(", URLString='").append(URLString).append('\'');
+ sb.append(", remoteODFlag=").append(remoteODFlag);
+ sb.append(", dependsOnEsId=").append(dependsOnEsId);
+ sb.append(", oCREsId=").append(oCREsId);
+ sb.append(", decoderConfigDescriptor=").append(decoderConfigDescriptor);
+ sb.append(", slConfigDescriptor=").append(slConfigDescriptor);
+ sb.append('}');
+ return sb.toString();
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+
+ ESDescriptor that = (ESDescriptor) o;
+
+ if (URLFlag != that.URLFlag) return false;
+ if (URLLength != that.URLLength) return false;
+ if (dependsOnEsId != that.dependsOnEsId) return false;
+ if (esId != that.esId) return false;
+ if (oCREsId != that.oCREsId) return false;
+ if (oCRstreamFlag != that.oCRstreamFlag) return false;
+ if (remoteODFlag != that.remoteODFlag) return false;
+ if (streamDependenceFlag != that.streamDependenceFlag) return false;
+ if (streamPriority != that.streamPriority) return false;
+ if (URLString != null ? !URLString.equals(that.URLString) : that.URLString != null) return false;
+ if (decoderConfigDescriptor != null ? !decoderConfigDescriptor.equals(that.decoderConfigDescriptor) : that.decoderConfigDescriptor != null)
+ return false;
+ if (otherDescriptors != null ? !otherDescriptors.equals(that.otherDescriptors) : that.otherDescriptors != null)
+ return false;
+ if (slConfigDescriptor != null ? !slConfigDescriptor.equals(that.slConfigDescriptor) : that.slConfigDescriptor != null)
+ return false;
+
+ return true;
+ }
+
+ @Override
+ public int hashCode() {
+ int result = esId;
+ result = 31 * result + streamDependenceFlag;
+ result = 31 * result + URLFlag;
+ result = 31 * result + oCRstreamFlag;
+ result = 31 * result + streamPriority;
+ result = 31 * result + URLLength;
+ result = 31 * result + (URLString != null ? URLString.hashCode() : 0);
+ result = 31 * result + remoteODFlag;
+ result = 31 * result + dependsOnEsId;
+ result = 31 * result + oCREsId;
+ result = 31 * result + (decoderConfigDescriptor != null ? decoderConfigDescriptor.hashCode() : 0);
+ result = 31 * result + (slConfigDescriptor != null ? slConfigDescriptor.hashCode() : 0);
+ result = 31 * result + (otherDescriptors != null ? otherDescriptors.hashCode() : 0);
+ return result;
+ }
+}
diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/boxes/mp4/objectdescriptors/.svn/text-base/ExtensionDescriptor.java.svn-base b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/mp4/objectdescriptors/.svn/text-base/ExtensionDescriptor.java.svn-base
new file mode 100644
index 0000000..7933f5a
--- /dev/null
+++ b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/mp4/objectdescriptors/.svn/text-base/ExtensionDescriptor.java.svn-base
@@ -0,0 +1,73 @@
+/*
+ * Copyright 2011 castLabs, 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.googlecode.mp4parser.boxes.mp4.objectdescriptors;
+
+import com.coremedia.iso.Hex;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.util.logging.Logger;
+
+/**
+ * abstract class ExtensionDescriptor extends BaseDescriptor
+ * : bit(8) tag = ExtensionProfileLevelDescrTag, ExtDescrTagStartRange ..
+ * ExtDescrTagEndRange {
+ * // empty. To be filled by classes extending this class.
+ * }
+ */
+@Descriptor(tags = {0x13, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253})
+public class ExtensionDescriptor extends BaseDescriptor {
+ private static Logger log = Logger.getLogger(ExtensionDescriptor.class.getName());
+
+ byte[] bytes;
+
+
+ //todo: add this better to the tags list?
+ //14496-1:2010 p.20:
+ //0x6A-0xBF Reserved for ISO use
+ //0xC0-0xFE User private
+ //
+ //ExtDescrTagStartRange = 0x6A
+ //ExtDescrTagEndRange = 0xFE
+ static int[] allTags() {
+ int[] ints = new int[0xFE - 0x6A];
+
+ for (int i = 0x6A; i < 0xFE; i++) {
+ final int pos = i - 0x6A;
+ log.finest("pos:" + pos);
+ ints[pos] = i;
+ }
+ return ints;
+ }
+
+ @Override
+ public void parseDetail(ByteBuffer bb) throws IOException {
+ if (getSize() > 0) {
+ bytes = new byte[sizeOfInstance];
+ bb.get(bytes);
+ }
+ }
+
+ @Override
+ public String toString() {
+ final StringBuilder sb = new StringBuilder();
+ sb.append("ExtensionDescriptor");
+ sb.append("{bytes=").append(bytes == null ? "null" : Hex.encodeHex(bytes));
+ sb.append('}');
+ return sb.toString();
+ }
+}
diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/boxes/mp4/objectdescriptors/.svn/text-base/ExtensionProfileLevelDescriptor.java.svn-base b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/mp4/objectdescriptors/.svn/text-base/ExtensionProfileLevelDescriptor.java.svn-base
new file mode 100644
index 0000000..0cf4915
--- /dev/null
+++ b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/mp4/objectdescriptors/.svn/text-base/ExtensionProfileLevelDescriptor.java.svn-base
@@ -0,0 +1,51 @@
+/*
+ * Copyright 2011 castLabs, 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.googlecode.mp4parser.boxes.mp4.objectdescriptors;
+
+import com.coremedia.iso.Hex;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+
+/**
+ * abstract class ExtensionDescriptor extends BaseDescriptor
+ * : bit(8) tag = ExtensionProfileLevelDescrTag, ExtDescrTagStartRange ..
+ * ExtDescrTagEndRange {
+ * // empty. To be filled by classes extending this class.
+ * }
+ */
+@Descriptor(tags = {0x13})
+public class ExtensionProfileLevelDescriptor extends BaseDescriptor {
+ byte[] bytes;
+
+ @Override
+ public void parseDetail(ByteBuffer bb) throws IOException {
+ if (getSize() > 0) {
+ bytes = new byte[getSize()];
+ bb.get(bytes);
+ }
+ }
+
+ @Override
+ public String toString() {
+ final StringBuilder sb = new StringBuilder();
+ sb.append("ExtensionDescriptor");
+ sb.append("{bytes=").append(bytes == null ? "null" : Hex.encodeHex(bytes));
+ sb.append('}');
+ return sb.toString();
+ }
+}
diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/boxes/mp4/objectdescriptors/.svn/text-base/InitialObjectDescriptor.java.svn-base b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/mp4/objectdescriptors/.svn/text-base/InitialObjectDescriptor.java.svn-base
new file mode 100644
index 0000000..7a1f094
--- /dev/null
+++ b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/mp4/objectdescriptors/.svn/text-base/InitialObjectDescriptor.java.svn-base
@@ -0,0 +1,136 @@
+/*
+ * Copyright 2011 castLabs, 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.googlecode.mp4parser.boxes.mp4.objectdescriptors;
+
+
+import com.coremedia.iso.IsoTypeReader;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
+import java.util.List;
+
+/*
+class InitialObjectDescriptor extends ObjectDescriptorBase : bit(8)
+tag=InitialObjectDescrTag {
+bit(10) ObjectDescriptorID;
+bit(1) URL_Flag;
+bit(1) includeInlineProfileLevelFlag;
+const bit(4) reserved=0b1111;
+if (URL_Flag) {
+bit(8) URLlength;
+bit(8) URLstring[URLlength];
+} else {
+bit(8) ODProfileLevelIndication;
+bit(8) sceneProfileLevelIndication;
+bit(8) audioProfileLevelIndication;
+bit(8) visualProfileLevelIndication;
+bit(8) graphicsProfileLevelIndication;
+ES_Descriptor esDescr[1 .. 255];
+OCI_Descriptor ociDescr[0 .. 255];
+IPMP_DescriptorPointer ipmpDescrPtr[0 .. 255];
+IPMP_Descriptor ipmpDescr [0 .. 255];
+IPMP_ToolListDescriptor toolListDescr[0 .. 1];
+}
+ExtensionDescriptor extDescr[0 .. 255];
+}
+*/
+//@Descriptor(tags = {0x02, 0x10})
+public class InitialObjectDescriptor extends ObjectDescriptorBase {
+ private int objectDescriptorId;
+ int urlFlag;
+ int includeInlineProfileLevelFlag;
+
+ int urlLength;
+ String urlString;
+
+ int oDProfileLevelIndication;
+ int sceneProfileLevelIndication;
+ int audioProfileLevelIndication;
+ int visualProfileLevelIndication;
+ int graphicsProfileLevelIndication;
+
+ List<ESDescriptor> esDescriptors = new ArrayList<ESDescriptor>();
+
+ List<ExtensionDescriptor> extensionDescriptors = new ArrayList<ExtensionDescriptor>();
+
+ List<BaseDescriptor> unknownDescriptors = new ArrayList<BaseDescriptor>();
+
+ @Override
+ public void parseDetail(ByteBuffer bb) throws IOException {
+ int data = IsoTypeReader.readUInt16(bb);
+ objectDescriptorId = (data & 0xFFC0) >> 6;
+
+ urlFlag = (data & 0x3F) >> 5;
+ includeInlineProfileLevelFlag = (data & 0x1F) >> 4;
+
+ int sizeLeft = getSize() - 2;
+ if (urlFlag == 1) {
+ urlLength = IsoTypeReader.readUInt8(bb);
+ urlString = IsoTypeReader.readString(bb, urlLength);
+ sizeLeft = sizeLeft - (1 + urlLength);
+ } else {
+ oDProfileLevelIndication = IsoTypeReader.readUInt8(bb);
+ sceneProfileLevelIndication = IsoTypeReader.readUInt8(bb);
+ audioProfileLevelIndication = IsoTypeReader.readUInt8(bb);
+ visualProfileLevelIndication = IsoTypeReader.readUInt8(bb);
+ graphicsProfileLevelIndication = IsoTypeReader.readUInt8(bb);
+
+ sizeLeft = sizeLeft - 5;
+
+ if (sizeLeft > 2) {
+ final BaseDescriptor descriptor = ObjectDescriptorFactory.createFrom(-1, bb);
+ sizeLeft = sizeLeft - descriptor.getSize();
+ if (descriptor instanceof ESDescriptor) {
+ esDescriptors.add((ESDescriptor) descriptor);
+ } else {
+ unknownDescriptors.add(descriptor);
+ }
+ }
+ }
+
+ if (sizeLeft > 2) {
+ final BaseDescriptor descriptor = ObjectDescriptorFactory.createFrom(-1, bb);
+ if (descriptor instanceof ExtensionDescriptor) {
+ extensionDescriptors.add((ExtensionDescriptor) descriptor);
+ } else {
+ unknownDescriptors.add(descriptor);
+ }
+ }
+ }
+
+ @Override
+ public String toString() {
+ final StringBuilder sb = new StringBuilder();
+ sb.append("InitialObjectDescriptor");
+ sb.append("{objectDescriptorId=").append(objectDescriptorId);
+ sb.append(", urlFlag=").append(urlFlag);
+ sb.append(", includeInlineProfileLevelFlag=").append(includeInlineProfileLevelFlag);
+ sb.append(", urlLength=").append(urlLength);
+ sb.append(", urlString='").append(urlString).append('\'');
+ sb.append(", oDProfileLevelIndication=").append(oDProfileLevelIndication);
+ sb.append(", sceneProfileLevelIndication=").append(sceneProfileLevelIndication);
+ sb.append(", audioProfileLevelIndication=").append(audioProfileLevelIndication);
+ sb.append(", visualProfileLevelIndication=").append(visualProfileLevelIndication);
+ sb.append(", graphicsProfileLevelIndication=").append(graphicsProfileLevelIndication);
+ sb.append(", esDescriptors=").append(esDescriptors);
+ sb.append(", extensionDescriptors=").append(extensionDescriptors);
+ sb.append(", unknownDescriptors=").append(unknownDescriptors);
+ sb.append('}');
+ return sb.toString();
+ }
+}
diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/boxes/mp4/objectdescriptors/.svn/text-base/ObjectDescriptor.java_bak.svn-base b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/mp4/objectdescriptors/.svn/text-base/ObjectDescriptor.java_bak.svn-base
new file mode 100644
index 0000000..c5cb586
--- /dev/null
+++ b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/mp4/objectdescriptors/.svn/text-base/ObjectDescriptor.java_bak.svn-base
@@ -0,0 +1,104 @@
+/*
+ * Copyright 2011 castLabs, 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.googlecode.mp4parser.boxes.mp4.objectdescriptors;
+
+import com.coremedia.iso.IsoTypeReader;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
+import java.util.List;
+
+/*
+class ObjectDescriptor extends ObjectDescriptorBase : bit(8) tag=ObjectDescrTag {
+bit(10) ObjectDescriptorID;
+bit(1) URL_Flag;
+const bit(5) reserved=0b1111.1;
+if (URL_Flag) {
+bit(8) URLlength;
+bit(8) URLstring[URLlength];
+} else {
+ES_Descriptor esDescr[1 .. 255];
+OCI_Descriptor ociDescr[0 .. 255];
+IPMP_DescriptorPointer ipmpDescrPtr[0 .. 255];
+IPMP_Descriptor ipmpDescr [0 .. 255];
+}
+ExtensionDescriptor extDescr[0 .. 255];
+}
+*/
+@Descriptor(tags = {0x01, 0x11})
+public class ObjectDescriptor extends ObjectDescriptorBase {
+ private int objectDescriptorId;
+ int objectDescriptorUrlFlag;
+ int objectDescriptorUrlLength;
+ String objectDescriptorUrlString;
+
+
+ private int streamCount;
+ private int extensionFlag;
+ private List<ESDescriptor> esDescriptors = new ArrayList<ESDescriptor>();
+
+ private int descriptorLength;
+ private List<ExtensionDescriptor> extensionDescriptors = new ArrayList<ExtensionDescriptor>();
+
+ public static ObjectDescriptor createFrom(ByteBuffer in) throws IOException {
+/*
+ tmp = in.readUInt16();
+ esDescriptor.objectDescriptorId = tmp & 0x3f;
+ esDescriptor.objectDescriptorUrlFlag = (tmp >> 5) & 0x1;
+ if (esDescriptor.objectDescriptorUrlFlag == 1) {
+ esDescriptor.objectDescriptorUrlLength = in.readUInt8();
+ esDescriptor.objectDescriptorUrlString = new String(in.read(esDescriptor.objectDescriptorUrlLength));
+ }
+ */
+
+ ObjectDescriptor objectDescriptor = new ObjectDescriptor();
+
+ int data = IsoTypeReader.readUInt16(in);
+
+ objectDescriptor.objectDescriptorId = data & 0xFFC0;
+ objectDescriptor.streamCount = data & 0x3E;
+ objectDescriptor.extensionFlag = data & 0x1;
+
+// for (int i = 0; i < objectDescriptor.streamCount; i++) {
+// objectDescriptor.esDescriptors.add(ESDescriptor.createFrom(in));
+// }
+//
+// if (objectDescriptor.extensionFlag == 1) {
+// objectDescriptor.descriptorLength = in.readUInt8();
+// for (int i = 0; i < objectDescriptor.descriptorLength;) {
+// ExtensionDescriptor extensionDescriptor = ExtensionDescriptor.createFrom(in);
+// objectDescriptor.extensionDescriptors.add(extensionDescriptor);
+// i = i + extensionDescriptor.descriptorDataLength + 1;
+// }
+// }
+
+ return objectDescriptor;
+ }
+
+ @Override
+ public String toString() {
+ return "ObjectDescriptor{" +
+ "objectDescriptorId=" + objectDescriptorId +
+ ", streamCount=" + streamCount +
+ ", extensionFlag=" + extensionFlag +
+ ", esDescriptors=" + esDescriptors +
+ ", descriptorLength=" + descriptorLength +
+ ", extensionDescriptors=" + extensionDescriptors +
+ '}';
+ }
+}
diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/boxes/mp4/objectdescriptors/.svn/text-base/ObjectDescriptorBase.java.svn-base b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/mp4/objectdescriptors/.svn/text-base/ObjectDescriptorBase.java.svn-base
new file mode 100644
index 0000000..69a8684
--- /dev/null
+++ b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/mp4/objectdescriptors/.svn/text-base/ObjectDescriptorBase.java.svn-base
@@ -0,0 +1,27 @@
+/*
+ * Copyright 2011 castLabs, 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.googlecode.mp4parser.boxes.mp4.objectdescriptors;
+
+/*
+abstract class ObjectDescriptorBase extends BaseDescriptor : bit(8)
+tag=[ObjectDescrTag..InitialObjectDescrTag] {
+// empty. To be filled by classes extending this class.
+}
+ */
+@Descriptor(tags = 0x00)
+public abstract class ObjectDescriptorBase extends BaseDescriptor {
+}
diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/boxes/mp4/objectdescriptors/.svn/text-base/ObjectDescriptorFactory.java.svn-base b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/mp4/objectdescriptors/.svn/text-base/ObjectDescriptorFactory.java.svn-base
new file mode 100644
index 0000000..6afba55
--- /dev/null
+++ b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/mp4/objectdescriptors/.svn/text-base/ObjectDescriptorFactory.java.svn-base
@@ -0,0 +1,189 @@
+/*
+ * Copyright 2011 castLabs, 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.googlecode.mp4parser.boxes.mp4.objectdescriptors;
+
+import com.coremedia.iso.IsoTypeReader;
+
+import java.io.IOException;
+import java.lang.reflect.Modifier;
+import java.nio.ByteBuffer;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+/* class tag values of 14496-1
+0x00 Forbidden
+0x01 ObjectDescrTag
+0x02 InitialObjectDescrTag
+0x03 ES_DescrTag
+0x04 DecoderConfigDescrTag
+0x05 DecSpecificInfoTag
+0x06 SLConfigDescrTag
+0x07 ContentIdentDescrTag
+0x08 SupplContentIdentDescrTag
+0x09 IPI_DescrPointerTag
+0x0A IPMP_DescrPointerTag
+0x0B IPMP_DescrTag
+0x0C QoS_DescrTag
+0x0D RegistrationDescrTag
+0x0E ES_ID_IncTag
+0x0F ES_ID_RefTag
+0x10 MP4_IOD_Tag
+0x11 MP4_OD_Tag
+0x12 IPL_DescrPointerRefTag
+0x13 ExtensionProfileLevelDescrTag
+0x14 profileLevelIndicationIndexDescrTag
+0x15-0x3F Reserved for ISO use
+0x40 ContentClassificationDescrTag
+0x41 KeyWordDescrTag
+0x42 RatingDescrTag
+0x43 LanguageDescrTag
+0x44 ShortTextualDescrTag
+0x45 ExpandedTextualDescrTag
+0x46 ContentCreatorNameDescrTag
+0x47 ContentCreationDateDescrTag
+0x48 OCICreatorNameDescrTag
+0x49 OCICreationDateDescrTag
+0x4A SmpteCameraPositionDescrTag
+0x4B SegmentDescrTag
+0x4C MediaTimeDescrTag
+0x4D-0x5F Reserved for ISO use (OCI extensions)
+0x60 IPMP_ToolsListDescrTag
+0x61 IPMP_ToolTag
+0x62 M4MuxTimingDescrTag
+0x63 M4MuxCodeTableDescrTag
+0x64 ExtSLConfigDescrTag
+0x65 M4MuxBufferSizeDescrTag
+0x66 M4MuxIdentDescrTag
+0x67 DependencyPointerTag
+0x68 DependencyMarkerTag
+0x69 M4MuxChannelDescrTag
+0x6A-0xBF Reserved for ISO use
+0xC0-0xFE User private
+0xFF Forbidden
+ */
+
+/* objectTypeIndication as of 14496-1
+0x00 Forbidden
+0x01 Systems ISO/IEC 14496-1 a
+0x02 Systems ISO/IEC 14496-1 b
+0x03 Interaction Stream
+0x04 Systems ISO/IEC 14496-1 Extended BIFS Configuration c
+0x05 Systems ISO/IEC 14496-1 AFX d
+0x06 Font Data Stream
+0x07 Synthesized Texture Stream
+0x08 Streaming Text Stream
+0x09-0x1F reserved for ISO use
+0x20 Visual ISO/IEC 14496-2 e
+0x21 Visual ITU-T Recommendation H.264 | ISO/IEC 14496-10 f
+0x22 Parameter Sets for ITU-T Recommendation H.264 | ISO/IEC 14496-10 f
+0x23-0x3F reserved for ISO use
+0x40 Audio ISO/IEC 14496-3 g
+0x41-0x5F reserved for ISO use
+0x60 Visual ISO/IEC 13818-2 Simple Profile
+0x61 Visual ISO/IEC 13818-2 Main Profile
+0x62 Visual ISO/IEC 13818-2 SNR Profile
+0x63 Visual ISO/IEC 13818-2 Spatial Profile
+0x64 Visual ISO/IEC 13818-2 High Profile
+0x65 Visual ISO/IEC 13818-2 422 Profile
+0x66 Audio ISO/IEC 13818-7 Main Profile
+0x67 Audio ISO/IEC 13818-7 LowComplexity Profile
+0x68 Audio ISO/IEC 13818-7 Scaleable Sampling Rate Profile
+0x69 Audio ISO/IEC 13818-3
+0x6A Visual ISO/IEC 11172-2
+0x6B Audio ISO/IEC 11172-3
+0x6C Visual ISO/IEC 10918-1
+0x6D reserved for registration authority
+0x6E Visual ISO/IEC 15444-1
+0x6F - 0x9F reserved for ISO use
+0xA0 - 0xBF reserved for registration authority i
+0xC0 - 0xE0 user private
+0xE1 reserved for registration authority i
+0xE2 - 0xFE user private
+0xFF no object type specified h
+ */
+public class ObjectDescriptorFactory {
+ protected static Logger log = Logger.getLogger(ObjectDescriptorFactory.class.getName());
+
+ protected static Map<Integer, Map<Integer, Class<? extends BaseDescriptor>>> descriptorRegistry = new HashMap<Integer, Map<Integer, Class<? extends BaseDescriptor>>>();
+
+ static {
+ Set<Class<? extends BaseDescriptor>> annotated = new HashSet<Class<? extends BaseDescriptor>>();
+
+ annotated.add(DecoderSpecificInfo.class);
+ annotated.add(SLConfigDescriptor.class);
+ annotated.add(BaseDescriptor.class);
+ annotated.add(ExtensionDescriptor.class);
+ annotated.add(ObjectDescriptorBase.class);
+ annotated.add(ProfileLevelIndicationDescriptor.class);
+ annotated.add(AudioSpecificConfig.class);
+ annotated.add(ExtensionProfileLevelDescriptor.class);
+ annotated.add(ESDescriptor.class);
+ annotated.add(DecoderConfigDescriptor.class);
+ //annotated.add(ObjectDescriptor.class);
+
+ for (Class<? extends BaseDescriptor> clazz : annotated) {
+ final Descriptor descriptor = clazz.getAnnotation(Descriptor.class);
+ final int[] tags = descriptor.tags();
+ final int objectTypeInd = descriptor.objectTypeIndication();
+
+ Map<Integer, Class<? extends BaseDescriptor>> tagMap = descriptorRegistry.get(objectTypeInd);
+ if (tagMap == null) {
+ tagMap = new HashMap<Integer, Class<? extends BaseDescriptor>>();
+ }
+ for (int tag : tags) {
+ tagMap.put(tag, clazz);
+ }
+ descriptorRegistry.put(objectTypeInd, tagMap);
+ }
+ }
+
+ public static BaseDescriptor createFrom(int objectTypeIndication, ByteBuffer bb) throws IOException {
+ int tag = IsoTypeReader.readUInt8(bb);
+
+ Map<Integer, Class<? extends BaseDescriptor>> tagMap = descriptorRegistry.get(objectTypeIndication);
+ if (tagMap == null) {
+ tagMap = descriptorRegistry.get(-1);
+ }
+ Class<? extends BaseDescriptor> aClass = tagMap.get(tag);
+
+// if (tag == 0x00) {
+// log.warning("Found illegal tag 0x00! objectTypeIndication " + Integer.toHexString(objectTypeIndication) +
+// " and tag " + Integer.toHexString(tag) + " using: " + aClass);
+// aClass = BaseDescriptor.class;
+// }
+
+ BaseDescriptor baseDescriptor;
+ if (aClass == null || aClass.isInterface() || Modifier.isAbstract(aClass.getModifiers())) {
+ log.warning("No ObjectDescriptor found for objectTypeIndication " + Integer.toHexString(objectTypeIndication) +
+ " and tag " + Integer.toHexString(tag) + " found: " + aClass);
+ baseDescriptor = new UnknownDescriptor();
+ } else {
+ try {
+ baseDescriptor = aClass.newInstance();
+ } catch (Exception e) {
+ log.log(Level.SEVERE, "Couldn't instantiate BaseDescriptor class " + aClass + " for objectTypeIndication " + objectTypeIndication + " and tag " + tag, e);
+ throw new RuntimeException(e);
+ }
+ }
+ baseDescriptor.parse(tag, bb);
+ return baseDescriptor;
+ }
+}
diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/boxes/mp4/objectdescriptors/.svn/text-base/ProfileLevelIndicationDescriptor.java.svn-base b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/mp4/objectdescriptors/.svn/text-base/ProfileLevelIndicationDescriptor.java.svn-base
new file mode 100644
index 0000000..625277e
--- /dev/null
+++ b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/mp4/objectdescriptors/.svn/text-base/ProfileLevelIndicationDescriptor.java.svn-base
@@ -0,0 +1,70 @@
+/*
+ * Copyright 2011 castLabs, 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.googlecode.mp4parser.boxes.mp4.objectdescriptors;
+
+import com.coremedia.iso.IsoTypeReader;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+
+/**
+ * class ProfileLevelIndicationIndexDescriptor () extends BaseDescriptor
+ * : bit(8) ProfileLevelIndicationIndexDescrTag {
+ * bit(8) profileLevelIndicationIndex;
+ * }
+ */
+@Descriptor(tags = 0x14)
+public class ProfileLevelIndicationDescriptor extends BaseDescriptor {
+ int profileLevelIndicationIndex;
+
+ @Override
+ public void parseDetail( ByteBuffer bb) throws IOException {
+ profileLevelIndicationIndex = IsoTypeReader.readUInt8(bb);
+ }
+
+ @Override
+ public String toString() {
+ final StringBuilder sb = new StringBuilder();
+ sb.append("ProfileLevelIndicationDescriptor");
+ sb.append("{profileLevelIndicationIndex=").append(Integer.toHexString(profileLevelIndicationIndex));
+ sb.append('}');
+ return sb.toString();
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+
+ ProfileLevelIndicationDescriptor that = (ProfileLevelIndicationDescriptor) o;
+
+ if (profileLevelIndicationIndex != that.profileLevelIndicationIndex) {
+ return false;
+ }
+
+ return true;
+ }
+
+ @Override
+ public int hashCode() {
+ return profileLevelIndicationIndex;
+ }
+}
diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/boxes/mp4/objectdescriptors/.svn/text-base/SLConfigDescriptor.java.svn-base b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/mp4/objectdescriptors/.svn/text-base/SLConfigDescriptor.java.svn-base
new file mode 100644
index 0000000..70a58e6
--- /dev/null
+++ b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/mp4/objectdescriptors/.svn/text-base/SLConfigDescriptor.java.svn-base
@@ -0,0 +1,119 @@
+/*
+ * Copyright 2011 castLabs, 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.googlecode.mp4parser.boxes.mp4.objectdescriptors;
+
+import com.coremedia.iso.IsoTypeReader;
+import com.coremedia.iso.IsoTypeWriter;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+
+/**
+ * class SLConfigDescriptor extends BaseDescriptor : bit(8) tag=SLConfigDescrTag {
+ * bit(8) predefined;
+ * if (predefined==0) {
+ * bit(1) useAccessUnitStartFlag;
+ * bit(1) useAccessUnitEndFlag;
+ * bit(1) useRandomAccessPointFlag;
+ * bit(1) hasRandomAccessUnitsOnlyFlag;
+ * bit(1) usePaddingFlag;
+ * bit(1) useTimeStampsFlag;
+ * bit(1) useIdleFlag;
+ * bit(1) durationFlag;
+ * bit(32) timeStampResolution;
+ * bit(32) OCRResolution;
+ * bit(8) timeStampLength; // must be ≤ 64
+ * bit(8) OCRLength; // must be ≤ 64
+ * bit(8) AU_Length; // must be ≤ 32
+ * bit(8) instantBitrateLength;
+ * bit(4) degradationPriorityLength;
+ * bit(5) AU_seqNumLength; // must be ≤ 16
+ * bit(5) packetSeqNumLength; // must be ≤ 16
+ * bit(2) reserved=0b11;
+ * }
+ * if (durationFlag) {
+ * bit(32) timeScale;
+ * bit(16) accessUnitDuration;
+ * bit(16) compositionUnitDuration;
+ * }
+ * if (!useTimeStampsFlag) {
+ * bit(timeStampLength) startDecodingTimeStamp;
+ * bit(timeStampLength) startCompositionTimeStamp;
+ * }
+ * }
+ */
+@Descriptor(tags = {0x06})
+public class SLConfigDescriptor extends BaseDescriptor {
+ int predefined;
+
+ public int getPredefined() {
+ return predefined;
+ }
+
+ public void setPredefined(int predefined) {
+ this.predefined = predefined;
+ }
+
+ @Override
+ public void parseDetail(ByteBuffer bb) throws IOException {
+ predefined = IsoTypeReader.readUInt8(bb);
+ }
+
+ public int serializedSize() {
+ return 3;
+ }
+
+ public ByteBuffer serialize() {
+ ByteBuffer out = ByteBuffer.allocate(3);
+ IsoTypeWriter.writeUInt8(out, 6);
+ IsoTypeWriter.writeUInt8(out, 1);
+ IsoTypeWriter.writeUInt8(out, predefined);
+ return out;
+ }
+
+ @Override
+ public String toString() {
+ final StringBuilder sb = new StringBuilder();
+ sb.append("SLConfigDescriptor");
+ sb.append("{predefined=").append(predefined);
+ sb.append('}');
+ return sb.toString();
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+
+ SLConfigDescriptor that = (SLConfigDescriptor) o;
+
+ if (predefined != that.predefined) {
+ return false;
+ }
+
+ return true;
+ }
+
+ @Override
+ public int hashCode() {
+ return predefined;
+ }
+}
diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/boxes/mp4/objectdescriptors/.svn/text-base/UnknownDescriptor.java.svn-base b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/mp4/objectdescriptors/.svn/text-base/UnknownDescriptor.java.svn-base
new file mode 100644
index 0000000..dd75a0f
--- /dev/null
+++ b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/mp4/objectdescriptors/.svn/text-base/UnknownDescriptor.java.svn-base
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2011 castLabs, 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.googlecode.mp4parser.boxes.mp4.objectdescriptors;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.util.logging.Logger;
+
+public class UnknownDescriptor extends BaseDescriptor {
+ private ByteBuffer data;
+ private static Logger log = Logger.getLogger(UnknownDescriptor.class.getName());
+
+ @Override
+ public void parseDetail(ByteBuffer bb) throws IOException {
+ data = (ByteBuffer) bb.slice().limit(this.getSizeOfInstance());
+ }
+
+ @Override
+ public String toString() {
+ final StringBuilder sb = new StringBuilder();
+ sb.append("UnknownDescriptor");
+ sb.append("{tag=").append(tag);
+ sb.append(", sizeOfInstance=").append(sizeOfInstance);
+ sb.append(", data=").append(data);
+ sb.append('}');
+ return sb.toString();
+ }
+}
diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/boxes/mp4/objectdescriptors/AudioSpecificConfig.java b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/mp4/objectdescriptors/AudioSpecificConfig.java
new file mode 100644
index 0000000..86e319e
--- /dev/null
+++ b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/mp4/objectdescriptors/AudioSpecificConfig.java
@@ -0,0 +1,1176 @@
+/*
+ * Copyright 2011 castLabs, 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.googlecode.mp4parser.boxes.mp4.objectdescriptors;
+
+import com.coremedia.iso.Hex;
+import com.coremedia.iso.IsoTypeWriter;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Map;
+
+
+//
+//GetAudioObjectType()
+//{
+//audioObjectType; 5 uimsbf
+//if (audioObjectType == 31) {
+//audioObjectType = 32 + audioObjectTypeExt; 6 uimsbf
+//}
+//return audioObjectType;
+//}
+//AudioSpecificConfig ()
+//{
+//audioObjectType = GetAudioObjectType();
+//samplingFrequencyIndex; 4 bslbf
+//if ( samplingFrequencyIndex == 0xf ) {
+//samplingFrequency; 24 uimsbf
+//}
+//channelConfiguration; 4 bslbf
+//sbrPresentFlag = -1;
+//psPresentFlag = -1;
+//if ( audioObjectType == 5 ||
+//audioObjectType == 29 ) {
+//extensionAudioObjectType = 5;
+//sbrPresentFlag = 1;
+//if ( audioObjectType == 29 ) {
+//psPresentFlag = 1;
+//}
+//extensionSamplingFrequencyIndex; 4 uimsbf
+//if ( extensionSamplingFrequencyIndex == 0xf )
+//extensionSamplingFrequency; 24 uimsbf
+//audioObjectType = GetAudioObjectType();
+//if ( audioObjectType == 22 )
+//extensionChannelConfiguration; 4 uimsbf
+//}
+//else {
+//extensionAudioObjectType = 0;
+//}
+//switch (audioObjectType) {
+//case 1:
+//case 2:
+//case 3:
+//case 4:
+//case 6:
+//case 7:
+//case 17:
+//case 19:
+//case 20:
+//case 21:
+//case 22:
+//case 23:
+//GASpecificConfig();
+//break:
+//case 8:
+//CelpSpecificConfig();
+//break;
+//case 9:
+//HvxcSpecificConfig();
+//break:
+//case 12:
+//TTSSpecificConfig();
+//break;
+//case 13:
+//case 14:
+//case 15:
+//case 16:
+//StructuredAudioSpecificConfig();
+//break;
+//case 24:
+//ErrorResilientCelpSpecificConfig();
+//break;
+//case 25:
+//ErrorResilientHvxcSpecificConfig();
+//break;
+//case 26:
+//case 27:
+//ParametricSpecificConfig();
+//break;
+// case 28:
+//SSCSpecificConfig();
+//break;
+//case 30:
+//sacPayloadEmbedding; 1 uimsbf
+//SpatialSpecificConfig();
+//break;
+//case 32:
+//case 33:
+//case 34:
+//MPEG_1_2_SpecificConfig();
+//break;
+//case 35:
+//DSTSpecificConfig();
+//break;
+//case 36:
+//fillBits; 5 bslbf
+//ALSSpecificConfig();
+//break;
+//case 37:
+//case 38:
+//SLSSpecificConfig();
+//break;
+//case 39:
+//ELDSpecificConfig(channelConfiguration);
+//break:
+//case 40:
+//case 41:
+//SymbolicMusicSpecificConfig();
+//break;
+//default:
+///* reserved */
+//}
+//switch (audioObjectType) {
+//case 17:
+//case 19:
+//case 20:
+//case 21:
+//case 22:
+//case 23:
+//case 24:
+//case 25:
+//case 26:
+//case 27:
+//case 39:
+//epConfig; 2 bslbf
+//if ( epConfig == 2 || epConfig == 3 ) {
+//ErrorProtectionSpecificConfig();
+//}
+//if ( epConfig == 3 ) {
+//directMapping; 1 bslbf
+//if ( ! directMapping ) {
+///* tbd */
+//}
+//}
+//}
+//if ( extensionAudioObjectType != 5 && bits_to_decode() >= 16 ) {
+//syncExtensionType; 11 bslbf
+//if (syncExtensionType == 0x2b7) {
+// extensionAudioObjectType = GetAudioObjectType();
+//if ( extensionAudioObjectType == 5 ) {
+//sbrPresentFlag; 1 uimsbf
+//if (sbrPresentFlag == 1) {
+//extensionSamplingFrequencyIndex; 4 uimsbf
+//if ( extensionSamplingFrequencyIndex == 0xf ) {
+//extensionSamplingFrequency; 24 uimsbf
+//}
+//if ( bits_to_decode() >= 12 ) {
+//syncExtensionType; 11 bslbf
+//if (syncExtesionType == 0x548) {
+//psPresentFlag; 1 uimsbf
+//}
+//}
+//}
+//}
+//if ( extensionAudioObjectType == 22 ) {
+//sbrPresentFlag; 1 uimsbf
+//if (sbrPresentFlag == 1) {
+//extensionSamplingFrequencyIndex; 4 uimsbf
+//if ( extensionSamplingFrequencyIndex == 0xf ) {
+//extensionSamplingFrequency; 24 uimsbf
+//}
+//}
+//extensionChannelConfiguration; 4 uimsbf
+//}
+//}
+//}
+//}
+// }
+//
+// TFCodingType
+//0x0 AAC scaleable
+//0x1 BSAC
+//0x2 TwinVQ
+//0x3 AAC non scaleable (i.e. multichannel)
+//
+// class TFSpecificConfig( uint(4) samplingFrequencyIndex, uint(4) channelConfiguration ) {
+//uint(2) TFCodingType;
+//uint(1) frameLength;
+//uint(1) dependsOnCoreCoder;
+//if (dependsOnCoreCoder == 1){
+//uint(14)coreCoderDelay
+//}
+//if (TFCodingType==BSAC) {
+//uint(11) lslayer_length
+//}
+//uint (1) extensionFlag;
+//if (channelConfiguration == 0 ){
+//program_config_element();
+//}
+//if (extensionFlag==1){
+//<to be defined in mpeg4 phase 2>
+//}
+//}
+//
+//program_config_element()
+//{
+//element_instance_tag 4 uimsbf
+//profile 2 uimsbf
+//sampling_frequency_index 4 uimsbf
+//num_front_channel_elements 4 uimsbf
+//num_side_channel_elements 4 uimsbf
+//num_back_channel_elements 4 uimsbf
+// num_lfe_channel_elements 2 uimsbf
+//num_assoc_data_elements 3 uimsbf
+//num_valid_cc_elements 4 uimsbf
+//mono_mixdown_present 1 uimsbf
+//if ( mono_mixdown_present == 1 )
+//mono_mixdown_element_number 4 uimsbf
+//stereo_mixdown_present 1 uimsbf
+//if ( stereo_mixdown_present == 1 )
+//stereo_mixdown_element_number 4 uimsbf
+//matrix_mixdown_idx_present 1 uimsbf
+//if ( matrix_mixdown_idx_present == 1 ) {
+//matrix_mixdown_idx 2 uimsbf
+//pseudo_surround_enable 1 uimsbf
+//}
+//for ( i = 0; i < num_front_channel_elements; i++) {
+//front_element_is_cpe[i]; 1 bslbf
+//front_element_tag_select[i]; 4 uimsbf
+//}
+//for ( i = 0; i < num_side_channel_elements; i++) {
+//side_element_is_cpe[i]; 1 bslbf
+//side_element_tag_select[i]; 4 uimsbf
+//}
+//for ( i = 0; i < num_back_channel_elements; i++) {
+//back_element_is_cpe[i]; 1 bslbf
+//back_element_tag_select[i]; 4 uimsbf
+//}
+//for ( i = 0; i < num_lfe_channel_elements; i++)
+//lfe_element_tag_select[i]; 4 uimsbf
+//for ( i = 0; i < num_assoc_data_elements; i++)
+//assoc_data_element_tag_select[i]; 4 uimsbf
+//for ( i = 0; i < num_valid_cc_elements; i++) {
+//cc_element_is_ind_sw[i]; 1 uimsbf
+//valid_cc_element_tag_select[i]; 4 uimsbf
+//}
+//byte_alignment()
+//comment_field_bytes 8 uimsbf
+//for ( i = 0; i < comment_field_bytes; i++)
+//comment_field_data[i]; 8 uimsbf
+//}
+
+@Descriptor(tags = 0x5, objectTypeIndication = 0x40)
+public class AudioSpecificConfig extends BaseDescriptor {
+ byte[] configBytes;
+
+ public static Map<Integer, Integer> samplingFrequencyIndexMap = new HashMap<Integer, Integer>();
+ public static Map<Integer, String> audioObjectTypeMap = new HashMap<Integer, String>();
+ int audioObjectType;
+ int samplingFrequencyIndex;
+ int samplingFrequency;
+ int channelConfiguration;
+ int extensionAudioObjectType;
+ int sbrPresentFlag;
+ int psPresentFlag;
+ int extensionSamplingFrequencyIndex;
+ int extensionSamplingFrequency;
+ int extensionChannelConfiguration;
+ int sacPayloadEmbedding;
+ int fillBits;
+ int epConfig;
+ int directMapping;
+ int syncExtensionType;
+
+ //GASpecificConfig
+ int frameLengthFlag;
+ int dependsOnCoreCoder;
+ int coreCoderDelay;
+ int extensionFlag;
+ int layerNr;
+ int numOfSubFrame;
+ int layer_length;
+ int aacSectionDataResilienceFlag;
+ int aacScalefactorDataResilienceFlag;
+ int aacSpectralDataResilienceFlag;
+ int extensionFlag3;
+ boolean gaSpecificConfig;
+
+ //ParametricSpecificConfig
+ int isBaseLayer;
+ int paraMode;
+ int paraExtensionFlag;
+ int hvxcVarMode;
+ int hvxcRateMode;
+ int erHvxcExtensionFlag;
+ int var_ScalableFlag;
+ int hilnQuantMode;
+ int hilnMaxNumLine;
+ int hilnSampleRateCode;
+ int hilnFrameLength;
+ int hilnContMode;
+ int hilnEnhaLayer;
+ int hilnEnhaQuantMode;
+ boolean parametricSpecificConfig;
+
+ @Override
+ public void parseDetail(ByteBuffer bb) throws IOException {
+ ByteBuffer configBytes = bb.slice();
+ configBytes.limit(sizeOfInstance);
+ bb.position(bb.position() + sizeOfInstance);
+
+ //copy original bytes to internal array for constructing codec config strings (todo until writing of the config is supported)
+ this.configBytes = new byte[sizeOfInstance];
+ configBytes.get(this.configBytes);
+ configBytes.rewind();
+
+ BitReaderBuffer bitReaderBuffer = new BitReaderBuffer(configBytes);
+ audioObjectType = getAudioObjectType(bitReaderBuffer);
+ samplingFrequencyIndex = bitReaderBuffer.readBits(4);
+
+ if (samplingFrequencyIndex == 0xf) {
+ samplingFrequency = bitReaderBuffer.readBits(24);
+ }
+
+ channelConfiguration = bitReaderBuffer.readBits(4);
+
+ if (audioObjectType == 5 ||
+ audioObjectType == 29) {
+ extensionAudioObjectType = 5;
+ sbrPresentFlag = 1;
+ if (audioObjectType == 29) {
+ psPresentFlag = 1;
+ }
+ extensionSamplingFrequencyIndex = bitReaderBuffer.readBits(4);
+ if (extensionSamplingFrequencyIndex == 0xf)
+ extensionSamplingFrequency = bitReaderBuffer.readBits(24);
+ audioObjectType = getAudioObjectType(bitReaderBuffer);
+ if (audioObjectType == 22)
+ extensionChannelConfiguration = bitReaderBuffer.readBits(4);
+ } else {
+ extensionAudioObjectType = 0;
+ }
+
+ switch (audioObjectType) {
+ case 1:
+ case 2:
+ case 3:
+ case 4:
+ case 6:
+ case 7:
+ case 17:
+ case 19:
+ case 20:
+ case 21:
+ case 22:
+ case 23:
+ parseGaSpecificConfig(samplingFrequencyIndex, channelConfiguration, audioObjectType, bitReaderBuffer);
+ //GASpecificConfig();
+ break;
+ case 8:
+ throw new UnsupportedOperationException("can't parse CelpSpecificConfig yet");
+ //CelpSpecificConfig();
+ //break;
+ case 9:
+ throw new UnsupportedOperationException("can't parse HvxcSpecificConfig yet");
+ //HvxcSpecificConfig();
+ //break;
+ case 12:
+ throw new UnsupportedOperationException("can't parse TTSSpecificConfig yet");
+ //TTSSpecificConfig();
+ //break;
+ case 13:
+ case 14:
+ case 15:
+ case 16:
+ throw new UnsupportedOperationException("can't parse StructuredAudioSpecificConfig yet");
+ //StructuredAudioSpecificConfig();
+ //break;
+ case 24:
+ throw new UnsupportedOperationException("can't parse ErrorResilientCelpSpecificConfig yet");
+ //ErrorResilientCelpSpecificConfig();
+ //break;
+ case 25:
+ throw new UnsupportedOperationException("can't parse ErrorResilientHvxcSpecificConfig yet");
+ //ErrorResilientHvxcSpecificConfig();
+ //break;
+ case 26:
+ case 27:
+ parseParametricSpecificConfig(samplingFrequencyIndex, channelConfiguration, audioObjectType, bitReaderBuffer);
+ //ParametricSpecificConfig();
+ break;
+ case 28:
+ throw new UnsupportedOperationException("can't parse SSCSpecificConfig yet");
+ //SSCSpecificConfig();
+ //break;
+ case 30:
+ sacPayloadEmbedding = bitReaderBuffer.readBits(1);
+ throw new UnsupportedOperationException("can't parse SpatialSpecificConfig yet");
+ //SpatialSpecificConfig();
+ //break;
+ case 32:
+ case 33:
+ case 34:
+ throw new UnsupportedOperationException("can't parse MPEG_1_2_SpecificConfig yet");
+ //MPEG_1_2_SpecificConfig();
+ //break;
+ case 35:
+ throw new UnsupportedOperationException("can't parse DSTSpecificConfig yet");
+ //DSTSpecificConfig();
+ //break;
+ case 36:
+ fillBits = bitReaderBuffer.readBits(5);
+ throw new UnsupportedOperationException("can't parse ALSSpecificConfig yet");
+ //ALSSpecificConfig();
+ //break;
+ case 37:
+ case 38:
+ throw new UnsupportedOperationException("can't parse SLSSpecificConfig yet");
+ //SLSSpecificConfig();
+ //break;
+ case 39:
+ throw new UnsupportedOperationException("can't parse ELDSpecificConfig yet");
+ //ELDSpecificConfig(channelConfiguration);
+ //break;
+ case 40:
+ case 41:
+ throw new UnsupportedOperationException("can't parse SymbolicMusicSpecificConfig yet");
+ //SymbolicMusicSpecificConfig();
+ //break;
+ default:
+ /* reserved */
+ }
+
+ switch (audioObjectType) {
+ case 17:
+ case 19:
+ case 20:
+ case 21:
+ case 22:
+ case 23:
+ case 24:
+ case 25:
+ case 26:
+ case 27:
+ case 39:
+ epConfig = bitReaderBuffer.readBits(2);
+ if (epConfig == 2 || epConfig == 3) {
+ throw new UnsupportedOperationException("can't parse ErrorProtectionSpecificConfig yet");
+ //ErrorProtectionSpecificConfig();
+ }
+ if (epConfig == 3) {
+ directMapping = bitReaderBuffer.readBits(1);
+ if (directMapping == 0) {
+ /* tbd */
+ throw new RuntimeException("not implemented");
+ }
+ }
+ }
+
+ if (extensionAudioObjectType != 5 && bitReaderBuffer.remainingBits() >= 16) {
+ syncExtensionType = bitReaderBuffer.readBits(11);
+ if (syncExtensionType == 0x2b7) {
+ extensionAudioObjectType = getAudioObjectType(bitReaderBuffer);
+ if (extensionAudioObjectType == 5) {
+ sbrPresentFlag = bitReaderBuffer.readBits(1);
+ if (sbrPresentFlag == 1) {
+ extensionSamplingFrequencyIndex = bitReaderBuffer.readBits(4);
+ if (extensionSamplingFrequencyIndex == 0xf) {
+ extensionSamplingFrequency = bitReaderBuffer.readBits(24);
+ }
+ if (bitReaderBuffer.remainingBits() >= 12) {
+ syncExtensionType = bitReaderBuffer.readBits(11); //10101001000
+ if (syncExtensionType == 0x548) {
+ psPresentFlag = bitReaderBuffer.readBits(1);
+ }
+ }
+ }
+ }
+ if (extensionAudioObjectType == 22) {
+ sbrPresentFlag = bitReaderBuffer.readBits(1);
+ if (sbrPresentFlag == 1) {
+ extensionSamplingFrequencyIndex = bitReaderBuffer.readBits(4);
+ if (extensionSamplingFrequencyIndex == 0xf) {
+ extensionSamplingFrequency = bitReaderBuffer.readBits(24);
+ }
+ }
+ extensionChannelConfiguration = bitReaderBuffer.readBits(4);
+ }
+ }
+ }
+ }
+
+ private int gaSpecificConfigSize() {
+ return 0;
+ }
+
+ public int serializedSize() {
+ int out = 4;
+ if (audioObjectType == 2) {
+ out += gaSpecificConfigSize();
+ } else {
+ throw new UnsupportedOperationException("can't serialize that yet");
+ }
+ return out;
+ }
+
+ public ByteBuffer serialize() {
+ ByteBuffer out = ByteBuffer.allocate(serializedSize());
+ IsoTypeWriter.writeUInt8(out, 5);
+ IsoTypeWriter.writeUInt8(out, serializedSize() - 2);
+ BitWriterBuffer bwb = new BitWriterBuffer(out);
+ bwb.writeBits(audioObjectType, 5);
+ bwb.writeBits(samplingFrequencyIndex, 4);
+ if (samplingFrequencyIndex == 0xf) {
+ throw new UnsupportedOperationException("can't serialize that yet");
+ }
+ bwb.writeBits(channelConfiguration, 4);
+
+ // Don't support any extensions, unusual GASpecificConfig other than the default or anything...
+
+ return out;
+ }
+
+ private int getAudioObjectType(BitReaderBuffer in) throws IOException {
+ int audioObjectType = in.readBits(5);
+ if (audioObjectType == 31) {
+ audioObjectType = 32 + in.readBits(6);
+ }
+ return audioObjectType;
+ }
+
+ private void parseGaSpecificConfig(int samplingFrequencyIndex, int channelConfiguration, int audioObjectType, BitReaderBuffer in) throws IOException {
+// GASpecificConfig (samplingFrequencyIndex,
+// channelConfiguration,
+// audioObjectType)
+// {
+ frameLengthFlag = in.readBits(1);
+ dependsOnCoreCoder = in.readBits(1);
+ if (dependsOnCoreCoder == 1) {
+ coreCoderDelay = in.readBits(14);
+ }
+ extensionFlag = in.readBits(1);
+ if (channelConfiguration == 0) {
+ throw new UnsupportedOperationException("can't parse program_config_element yet");
+ //program_config_element ();
+ }
+ if ((audioObjectType == 6) || (audioObjectType == 20)) {
+ layerNr = in.readBits(3);
+ }
+ if (extensionFlag == 1) {
+ if (audioObjectType == 22) {
+ numOfSubFrame = in.readBits(5);
+ layer_length = in.readBits(11);
+ }
+ if (audioObjectType == 17 || audioObjectType == 19 ||
+ audioObjectType == 20 || audioObjectType == 23) {
+ aacSectionDataResilienceFlag = in.readBits(1);
+ aacScalefactorDataResilienceFlag = in.readBits(1);
+ aacSpectralDataResilienceFlag = in.readBits(1);
+ }
+ extensionFlag3 = in.readBits(1);
+ if (extensionFlag3 == 1) {
+ /* tbd in version 3 */
+ }
+ }
+// }
+ gaSpecificConfig = true;
+ }
+
+ private void parseParametricSpecificConfig(int samplingFrequencyIndex, int channelConfiguration, int audioObjectType, BitReaderBuffer in) throws IOException {
+ /*
+ ParametricSpecificConfig() {
+ isBaseLayer; 1 uimsbf
+ if (isBaseLayer) {
+ PARAconfig();
+ } else {
+ HILNenexConfig();
+ }
+ }
+ */
+ isBaseLayer = in.readBits(1);
+ if (isBaseLayer == 1) {
+ parseParaConfig(samplingFrequencyIndex, channelConfiguration, audioObjectType, in);
+ } else {
+ parseHilnEnexConfig(samplingFrequencyIndex, channelConfiguration, audioObjectType, in);
+ }
+ }
+
+ private void parseParaConfig(int samplingFrequencyIndex, int channelConfiguration, int audioObjectType, BitReaderBuffer in) throws IOException {
+ /*
+ PARAconfig()
+ {
+ PARAmode; 2 uimsbf
+ if (PARAmode != 1) {
+ ErHVXCconfig();
+ }
+ if (PARAmode != 0) {
+ HILNconfig();
+ }
+ PARAextensionFlag; 1 uimsbf
+ if (PARAextensionFlag) {
+ // to be defined in MPEG-4 Phase 3
+ }
+ }
+ */
+ paraMode = in.readBits(2);
+
+ if (paraMode != 1) {
+ parseErHvxcConfig(samplingFrequencyIndex, channelConfiguration, audioObjectType, in);
+ }
+ if (paraMode != 0) {
+ parseHilnConfig(samplingFrequencyIndex, channelConfiguration, audioObjectType, in);
+ }
+
+ paraExtensionFlag = in.readBits(1);
+ parametricSpecificConfig = true;
+ }
+
+ private void parseErHvxcConfig(int samplingFrequencyIndex, int channelConfiguration, int audioObjectType, BitReaderBuffer in) throws IOException {
+ /*
+ ErHVXCconfig()
+ {
+ HVXCvarMode; 1 uimsbf
+ HVXCrateMode; 2 uimsbf
+ extensionFlag; 1 uimsbf
+ if (extensionFlag) {
+ var_ScalableFlag; 1 uimsbf
+ }
+ }
+ */
+ hvxcVarMode = in.readBits(1);
+ hvxcRateMode = in.readBits(2);
+ erHvxcExtensionFlag = in.readBits(1);
+
+ if (erHvxcExtensionFlag == 1) {
+ var_ScalableFlag = in.readBits(1);
+ }
+ }
+
+ private void parseHilnConfig(int samplingFrequencyIndex, int channelConfiguration, int audioObjectType, BitReaderBuffer in) throws IOException {
+ /*
+ HILNconfig()
+ {
+ HILNquantMode; 1 uimsbf
+ HILNmaxNumLine; 8 uimsbf
+ HILNsampleRateCode; 4 uimsbf
+ HILNframeLength; 12 uimsbf
+ HILNcontMode; 2 uimsbf
+ }
+ */
+ hilnQuantMode = in.readBits(1);
+ hilnMaxNumLine = in.readBits(8);
+ hilnSampleRateCode = in.readBits(4);
+ hilnFrameLength = in.readBits(12);
+ hilnContMode = in.readBits(2);
+ }
+
+ private void parseHilnEnexConfig(int samplingFrequencyIndex, int channelConfiguration, int audioObjectType, BitReaderBuffer in) throws IOException {
+ /*
+ HILNenexConfig()
+ {
+ HILNenhaLayer; 1 uimsbf
+ if (HILNenhaLayer) {
+ HILNenhaQuantMode; 2 uimsbf
+ }
+ }
+ */
+ hilnEnhaLayer = in.readBits(1);
+ if (hilnEnhaLayer == 1) {
+ hilnEnhaQuantMode = in.readBits(2);
+ }
+ }
+
+ public byte[] getConfigBytes() {
+ return configBytes;
+ }
+
+ public int getAudioObjectType() {
+ return audioObjectType;
+ }
+
+ public int getExtensionAudioObjectType() {
+ return extensionAudioObjectType;
+ }
+
+ public int getSbrPresentFlag() {
+ return sbrPresentFlag;
+ }
+
+ public int getPsPresentFlag() {
+ return psPresentFlag;
+ }
+
+ public void setAudioObjectType(int audioObjectType) {
+ this.audioObjectType = audioObjectType;
+ }
+
+ public void setSamplingFrequencyIndex(int samplingFrequencyIndex) {
+ this.samplingFrequencyIndex = samplingFrequencyIndex;
+ }
+
+ public void setSamplingFrequency(int samplingFrequency) {
+ this.samplingFrequency = samplingFrequency;
+ }
+
+ public void setChannelConfiguration(int channelConfiguration) {
+ this.channelConfiguration = channelConfiguration;
+ }
+
+ @Override
+ public String toString() {
+ final StringBuilder sb = new StringBuilder();
+ sb.append("AudioSpecificConfig");
+ sb.append("{configBytes=").append(Hex.encodeHex(configBytes));
+ sb.append(", audioObjectType=").append(audioObjectType).append(" (").append(audioObjectTypeMap.get(audioObjectType)).append(")");
+ sb.append(", samplingFrequencyIndex=").append(samplingFrequencyIndex).append(" (").append(samplingFrequencyIndexMap.get(samplingFrequencyIndex)).append(")");
+ sb.append(", samplingFrequency=").append(samplingFrequency);
+ sb.append(", channelConfiguration=").append(channelConfiguration);
+ if (extensionAudioObjectType > 0) {
+ sb.append(", extensionAudioObjectType=").append(extensionAudioObjectType).append(" (").append(audioObjectTypeMap.get(extensionAudioObjectType)).append(")");
+ sb.append(", sbrPresentFlag=").append(sbrPresentFlag);
+ sb.append(", psPresentFlag=").append(psPresentFlag);
+ sb.append(", extensionSamplingFrequencyIndex=").append(extensionSamplingFrequencyIndex).append(" (").append(samplingFrequencyIndexMap.get(extensionSamplingFrequencyIndex)).append(")");
+ sb.append(", extensionSamplingFrequency=").append(extensionSamplingFrequency);
+ sb.append(", extensionChannelConfiguration=").append(extensionChannelConfiguration);
+ }
+// sb.append(", sacPayloadEmbedding=").append(sacPayloadEmbedding);
+// sb.append(", fillBits=").append(fillBits);
+// sb.append(", epConfig=").append(epConfig);
+// sb.append(", directMapping=").append(directMapping);
+ sb.append(", syncExtensionType=").append(syncExtensionType);
+ if (gaSpecificConfig) {
+ sb.append(", frameLengthFlag=").append(frameLengthFlag);
+ sb.append(", dependsOnCoreCoder=").append(dependsOnCoreCoder);
+ sb.append(", coreCoderDelay=").append(coreCoderDelay);
+ sb.append(", extensionFlag=").append(extensionFlag);
+ sb.append(", layerNr=").append(layerNr);
+ sb.append(", numOfSubFrame=").append(numOfSubFrame);
+ sb.append(", layer_length=").append(layer_length);
+ sb.append(", aacSectionDataResilienceFlag=").append(aacSectionDataResilienceFlag);
+ sb.append(", aacScalefactorDataResilienceFlag=").append(aacScalefactorDataResilienceFlag);
+ sb.append(", aacSpectralDataResilienceFlag=").append(aacSpectralDataResilienceFlag);
+ sb.append(", extensionFlag3=").append(extensionFlag3);
+ }
+ if (parametricSpecificConfig) {
+ sb.append(", isBaseLayer=").append(isBaseLayer);
+ sb.append(", paraMode=").append(paraMode);
+ sb.append(", paraExtensionFlag=").append(paraExtensionFlag);
+ sb.append(", hvxcVarMode=").append(hvxcVarMode);
+ sb.append(", hvxcRateMode=").append(hvxcRateMode);
+ sb.append(", erHvxcExtensionFlag=").append(erHvxcExtensionFlag);
+ sb.append(", var_ScalableFlag=").append(var_ScalableFlag);
+ sb.append(", hilnQuantMode=").append(hilnQuantMode);
+ sb.append(", hilnMaxNumLine=").append(hilnMaxNumLine);
+ sb.append(", hilnSampleRateCode=").append(hilnSampleRateCode);
+ sb.append(", hilnFrameLength=").append(hilnFrameLength);
+ sb.append(", hilnContMode=").append(hilnContMode);
+ sb.append(", hilnEnhaLayer=").append(hilnEnhaLayer);
+ sb.append(", hilnEnhaQuantMode=").append(hilnEnhaQuantMode);
+ }
+ sb.append('}');
+ return sb.toString();
+ }
+
+ static {
+ // sampling_frequency_index sampling frequeny
+//0x0 96000
+//0x1 88200
+//0x2 64000
+//0x3 48000
+//0x4 44100
+//0x5 32000
+//0x6 24000
+//0x7 22050
+//0x8 16000
+//0x9 12000
+//0xa 11025
+//0xb 8000
+//0xc reserved
+//0xd reserved
+//0xe reserved
+//0xf reserved
+ samplingFrequencyIndexMap.put(0x0, 96000);
+ samplingFrequencyIndexMap.put(0x1, 88200);
+ samplingFrequencyIndexMap.put(0x2, 64000);
+ samplingFrequencyIndexMap.put(0x3, 48000);
+ samplingFrequencyIndexMap.put(0x4, 44100);
+ samplingFrequencyIndexMap.put(0x5, 32000);
+ samplingFrequencyIndexMap.put(0x6, 24000);
+ samplingFrequencyIndexMap.put(0x7, 22050);
+ samplingFrequencyIndexMap.put(0x8, 16000);
+ samplingFrequencyIndexMap.put(0x9, 12000);
+ samplingFrequencyIndexMap.put(0xa, 11025);
+ samplingFrequencyIndexMap.put(0xb, 8000);
+
+ /* audioObjectType IDs
+ 0 Null
+ 1 AAC main X X
+ 2 AAC LC X X X X X X X
+ 3 AAC SSR X X
+ 4 AAC LTP X X X X
+ 5 SBR X X
+ 6 AAC Scalable X X X X
+ 7 TwinVQ X X X
+ 8 CELP X X X X X X
+ 9 HVXC X X X X X
+ 10 (reserved)
+ 11 (reserved)
+ 12 TTSI X X X X X X
+ 13 Main synthetic X X
+ 14 Wavetable synthesis X* X*
+ 15 General MIDI X* X*
+ 16 Algorithmic Synthesis and Audio FX X* X*
+ 17 ER AAC LC X X X
+ 18 (reserved)
+ 19 ER AAC LTP X X
+ 20 ER AAC Scalable X X X
+ 21 ER TwinVQ X X
+ 22 ER BSAC X X
+ 23 ER AAC LD X X X X
+ 24 ER CELP X X X
+ 25 ER HVXC X X
+ 26 ER HILN X
+ 27 ER Parametric X
+ 28 SSC
+ 29 PS X
+ 30 MPEG Surround
+ 31 (escape)
+ 32 Layer-1
+ 33 Layer-2
+ 34 Layer-3
+ 35 DST
+ 36 ALS
+ 37 SLS
+ 38 SLS non-core
+ 39 ER AAC ELD
+ 40 SMR Simple
+ 41 SMR Main
+ */
+ audioObjectTypeMap.put(1, "AAC main");
+ audioObjectTypeMap.put(2, "AAC LC");
+ audioObjectTypeMap.put(3, "AAC SSR");
+ audioObjectTypeMap.put(4, "AAC LTP");
+ audioObjectTypeMap.put(5, "SBR");
+ audioObjectTypeMap.put(6, "AAC Scalable");
+ audioObjectTypeMap.put(7, "TwinVQ");
+ audioObjectTypeMap.put(8, "CELP");
+ audioObjectTypeMap.put(9, "HVXC");
+ audioObjectTypeMap.put(10, "(reserved)");
+ audioObjectTypeMap.put(11, "(reserved)");
+ audioObjectTypeMap.put(12, "TTSI");
+ audioObjectTypeMap.put(13, "Main synthetic");
+ audioObjectTypeMap.put(14, "Wavetable synthesis");
+ audioObjectTypeMap.put(15, "General MIDI");
+ audioObjectTypeMap.put(16, "Algorithmic Synthesis and Audio FX");
+ audioObjectTypeMap.put(17, "ER AAC LC");
+ audioObjectTypeMap.put(18, "(reserved)");
+ audioObjectTypeMap.put(19, "ER AAC LTP");
+ audioObjectTypeMap.put(20, "ER AAC Scalable");
+ audioObjectTypeMap.put(21, "ER TwinVQ");
+ audioObjectTypeMap.put(22, "ER BSAC");
+ audioObjectTypeMap.put(23, "ER AAC LD");
+ audioObjectTypeMap.put(24, "ER CELP");
+ audioObjectTypeMap.put(25, "ER HVXC");
+ audioObjectTypeMap.put(26, "ER HILN");
+ audioObjectTypeMap.put(27, "ER Parametric");
+ audioObjectTypeMap.put(28, "SSC");
+ audioObjectTypeMap.put(29, "PS");
+ audioObjectTypeMap.put(30, "MPEG Surround");
+ audioObjectTypeMap.put(31, "(escape)");
+ audioObjectTypeMap.put(32, "Layer-1");
+ audioObjectTypeMap.put(33, "Layer-2");
+ audioObjectTypeMap.put(34, "Layer-3");
+ audioObjectTypeMap.put(35, "DST");
+ audioObjectTypeMap.put(36, "ALS");
+ audioObjectTypeMap.put(37, "SLS");
+ audioObjectTypeMap.put(38, "SLS non-core");
+ audioObjectTypeMap.put(39, "ER AAC ELD");
+ audioObjectTypeMap.put(40, "SMR Simple");
+ audioObjectTypeMap.put(41, "SMR Main");
+
+ /* profileLevelIds
+ 0x00 Reserved for ISO use -
+ 0x01 Main Audio Profile L1
+ 0x02 Main Audio Profile L2
+ 0x03 Main Audio Profile L3
+ 0x04 Main Audio Profile L4
+ 0x05 Scalable Audio Profile L1
+ 0x06 Scalable Audio Profile L2
+ 0x07 Scalable Audio Profile L3
+ 0x08 Scalable Audio Profile L4
+ 0x09 Speech Audio Profile L1
+ 0x0A Speech Audio Profile L2
+ 0x0B Synthetic Audio Profile L1
+ 0x0C Synthetic Audio Profile L2
+ 0x0D Synthetic Audio Profile L3
+ 0x0E High Quality Audio Profile L1
+ 0x0F High Quality Audio Profile L2
+ 0x10 High Quality Audio Profile L3
+ 0x11 High Quality Audio Profile L4
+ 0x12 High Quality Audio Profile L5
+ 0x13 High Quality Audio Profile L6
+ 0x14 High Quality Audio Profile L7
+ 0x15 High Quality Audio Profile L8
+ 0x16 Low Delay Audio Profile L1
+ 0x17 Low Delay Audio Profile L2
+ 0x18 Low Delay Audio Profile L3
+ 0x19 Low Delay Audio Profile L4
+ 0x1A Low Delay Audio Profile L5
+ 0x1B Low Delay Audio Profile L6
+ 0x1C Low Delay Audio Profile L7
+ 0x1D Low Delay Audio Profile L8
+ 0x1E Natural Audio Profile L1
+ 0x1F Natural Audio Profile L2
+ 0x20 Natural Audio Profile L3
+ 0x21 Natural Audio Profile L4
+ 0x22 Mobile Audio Internetworking Profile L1
+ 0x23 Mobile Audio Internetworking Profile L2
+ 0x24 Mobile Audio Internetworking Profile L3
+ 0x25 Mobile Audio Internetworking Profile L4
+ 0x26 Mobile Audio Internetworking Profile L5
+ 0x27 Mobile Audio Internetworking Profile L6
+ 0x28 AAC Profile L1
+ 0x29 AAC Profile L2
+ 0x2A AAC Profile L4
+ 0x2B AAC Profile L5
+ 0x2C High Efficiency AAC Profile L2
+ 0x2D High Efficiency AAC Profile L3
+ 0x2E High Efficiency AAC Profile L4
+ 0x2F High Efficiency AAC Profile L5
+ 0x30 High Efficiency AAC v2 Profile L2
+ 0x31 High Efficiency AAC v2 Profile L3
+ 0x32 High Efficiency AAC v2 Profile L4
+ 0x33 High Efficiency AAC v2 Profile L5
+ 0x34 Low Delay AAC Profile L1
+ 0x35 Baseline MPEG Surround Profile (see ISO/IEC
+ 23003-1)
+ L1
+ 0x36 Baseline MPEG Surround Profile (see ISO/IEC
+ 23003-1)
+ L2
+ 0x37 Baseline MPEG Surround Profile (see ISO/IEC
+ 23003-1)
+ L3
+ 0x38 Baseline MPEG Surround Profile (see ISO/IEC
+ 23003-1)
+ L4
+ 0c39 Baseline MPEG Surround Profile (see ISO/IEC
+ 23003-1)
+ L5
+ 0x3A Baseline MPEG Surround Profile (see ISO/IEC
+ 23003-1)
+ L6
+ 0x3B - 0x7F reserved for ISO use -
+ 0x80 - 0xFD user private -
+ 0xFE no audio profile specified -
+ 0xFF no audio capability required -
+
+ */
+ }
+
+
+ public int getSamplingFrequency() {
+ return samplingFrequencyIndex == 0xf ? samplingFrequency : samplingFrequencyIndexMap.get(samplingFrequencyIndex);
+ }
+
+ public int getChannelConfiguration() {
+ return channelConfiguration;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+
+ AudioSpecificConfig that = (AudioSpecificConfig) o;
+
+ if (aacScalefactorDataResilienceFlag != that.aacScalefactorDataResilienceFlag) {
+ return false;
+ }
+ if (aacSectionDataResilienceFlag != that.aacSectionDataResilienceFlag) {
+ return false;
+ }
+ if (aacSpectralDataResilienceFlag != that.aacSpectralDataResilienceFlag) {
+ return false;
+ }
+ if (audioObjectType != that.audioObjectType) {
+ return false;
+ }
+ if (channelConfiguration != that.channelConfiguration) {
+ return false;
+ }
+ if (coreCoderDelay != that.coreCoderDelay) {
+ return false;
+ }
+ if (dependsOnCoreCoder != that.dependsOnCoreCoder) {
+ return false;
+ }
+ if (directMapping != that.directMapping) {
+ return false;
+ }
+ if (epConfig != that.epConfig) {
+ return false;
+ }
+ if (erHvxcExtensionFlag != that.erHvxcExtensionFlag) {
+ return false;
+ }
+ if (extensionAudioObjectType != that.extensionAudioObjectType) {
+ return false;
+ }
+ if (extensionChannelConfiguration != that.extensionChannelConfiguration) {
+ return false;
+ }
+ if (extensionFlag != that.extensionFlag) {
+ return false;
+ }
+ if (extensionFlag3 != that.extensionFlag3) {
+ return false;
+ }
+ if (extensionSamplingFrequency != that.extensionSamplingFrequency) {
+ return false;
+ }
+ if (extensionSamplingFrequencyIndex != that.extensionSamplingFrequencyIndex) {
+ return false;
+ }
+ if (fillBits != that.fillBits) {
+ return false;
+ }
+ if (frameLengthFlag != that.frameLengthFlag) {
+ return false;
+ }
+ if (gaSpecificConfig != that.gaSpecificConfig) {
+ return false;
+ }
+ if (hilnContMode != that.hilnContMode) {
+ return false;
+ }
+ if (hilnEnhaLayer != that.hilnEnhaLayer) {
+ return false;
+ }
+ if (hilnEnhaQuantMode != that.hilnEnhaQuantMode) {
+ return false;
+ }
+ if (hilnFrameLength != that.hilnFrameLength) {
+ return false;
+ }
+ if (hilnMaxNumLine != that.hilnMaxNumLine) {
+ return false;
+ }
+ if (hilnQuantMode != that.hilnQuantMode) {
+ return false;
+ }
+ if (hilnSampleRateCode != that.hilnSampleRateCode) {
+ return false;
+ }
+ if (hvxcRateMode != that.hvxcRateMode) {
+ return false;
+ }
+ if (hvxcVarMode != that.hvxcVarMode) {
+ return false;
+ }
+ if (isBaseLayer != that.isBaseLayer) {
+ return false;
+ }
+ if (layerNr != that.layerNr) {
+ return false;
+ }
+ if (layer_length != that.layer_length) {
+ return false;
+ }
+ if (numOfSubFrame != that.numOfSubFrame) {
+ return false;
+ }
+ if (paraExtensionFlag != that.paraExtensionFlag) {
+ return false;
+ }
+ if (paraMode != that.paraMode) {
+ return false;
+ }
+ if (parametricSpecificConfig != that.parametricSpecificConfig) {
+ return false;
+ }
+ if (psPresentFlag != that.psPresentFlag) {
+ return false;
+ }
+ if (sacPayloadEmbedding != that.sacPayloadEmbedding) {
+ return false;
+ }
+ if (samplingFrequency != that.samplingFrequency) {
+ return false;
+ }
+ if (samplingFrequencyIndex != that.samplingFrequencyIndex) {
+ return false;
+ }
+ if (sbrPresentFlag != that.sbrPresentFlag) {
+ return false;
+ }
+ if (syncExtensionType != that.syncExtensionType) {
+ return false;
+ }
+ if (var_ScalableFlag != that.var_ScalableFlag) {
+ return false;
+ }
+ if (!Arrays.equals(configBytes, that.configBytes)) {
+ return false;
+ }
+
+ return true;
+ }
+
+ @Override
+ public int hashCode() {
+ int result = configBytes != null ? Arrays.hashCode(configBytes) : 0;
+ result = 31 * result + audioObjectType;
+ result = 31 * result + samplingFrequencyIndex;
+ result = 31 * result + samplingFrequency;
+ result = 31 * result + channelConfiguration;
+ result = 31 * result + extensionAudioObjectType;
+ result = 31 * result + sbrPresentFlag;
+ result = 31 * result + psPresentFlag;
+ result = 31 * result + extensionSamplingFrequencyIndex;
+ result = 31 * result + extensionSamplingFrequency;
+ result = 31 * result + extensionChannelConfiguration;
+ result = 31 * result + sacPayloadEmbedding;
+ result = 31 * result + fillBits;
+ result = 31 * result + epConfig;
+ result = 31 * result + directMapping;
+ result = 31 * result + syncExtensionType;
+ result = 31 * result + frameLengthFlag;
+ result = 31 * result + dependsOnCoreCoder;
+ result = 31 * result + coreCoderDelay;
+ result = 31 * result + extensionFlag;
+ result = 31 * result + layerNr;
+ result = 31 * result + numOfSubFrame;
+ result = 31 * result + layer_length;
+ result = 31 * result + aacSectionDataResilienceFlag;
+ result = 31 * result + aacScalefactorDataResilienceFlag;
+ result = 31 * result + aacSpectralDataResilienceFlag;
+ result = 31 * result + extensionFlag3;
+ result = 31 * result + (gaSpecificConfig ? 1 : 0);
+ result = 31 * result + isBaseLayer;
+ result = 31 * result + paraMode;
+ result = 31 * result + paraExtensionFlag;
+ result = 31 * result + hvxcVarMode;
+ result = 31 * result + hvxcRateMode;
+ result = 31 * result + erHvxcExtensionFlag;
+ result = 31 * result + var_ScalableFlag;
+ result = 31 * result + hilnQuantMode;
+ result = 31 * result + hilnMaxNumLine;
+ result = 31 * result + hilnSampleRateCode;
+ result = 31 * result + hilnFrameLength;
+ result = 31 * result + hilnContMode;
+ result = 31 * result + hilnEnhaLayer;
+ result = 31 * result + hilnEnhaQuantMode;
+ result = 31 * result + (parametricSpecificConfig ? 1 : 0);
+ return result;
+ }
+}
diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/boxes/mp4/objectdescriptors/BaseDescriptor.java b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/mp4/objectdescriptors/BaseDescriptor.java
new file mode 100644
index 0000000..6d94680
--- /dev/null
+++ b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/mp4/objectdescriptors/BaseDescriptor.java
@@ -0,0 +1,99 @@
+/*
+ * Copyright 2011 castLabs, 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.googlecode.mp4parser.boxes.mp4.objectdescriptors;
+
+import com.coremedia.iso.IsoTypeReader;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+
+/*
+abstract aligned(8) expandable(228-1) class BaseDescriptor : bit(8) tag=0 {
+// empty. To be filled by classes extending this class.
+}
+
+int sizeOfInstance = 0;
+bit(1) nextByte;
+bit(7) sizeOfInstance;
+while(nextByte) {
+bit(1) nextByte;
+bit(7) sizeByte;
+sizeOfInstance = sizeOfInstance<<7 | sizeByte;
+}
+ */
+@Descriptor(tags = 0x00)
+public abstract class BaseDescriptor {
+ int tag;
+ int sizeOfInstance;
+ int sizeBytes;
+
+ public BaseDescriptor() {
+ }
+
+ public int getTag() {
+ return tag;
+ }
+
+ public int getSize() {
+ return sizeOfInstance
+ + 1//1 for the tag
+ + sizeBytes;
+ }
+
+ public int getSizeOfInstance() {
+ return sizeOfInstance;
+ }
+
+ public int getSizeBytes() {
+ return sizeBytes;
+ }
+
+ public final void parse(int tag, ByteBuffer bb) throws IOException {
+ this.tag = tag;
+
+ int i = 0;
+ int tmp = IsoTypeReader.readUInt8(bb);
+ i++;
+ sizeOfInstance = tmp & 0x7f;
+ while (tmp >>> 7 == 1) { //nextbyte indicator bit
+ tmp = IsoTypeReader.readUInt8(bb);
+ i++;
+ //sizeOfInstance = sizeOfInstance<<7 | sizeByte;
+ sizeOfInstance = sizeOfInstance << 7 | tmp & 0x7f;
+ }
+ sizeBytes = i;
+ ByteBuffer detailSource = bb.slice();
+ detailSource.limit(sizeOfInstance);
+ parseDetail(detailSource);
+ assert detailSource.remaining() == 0: this.getClass().getSimpleName() + " has not been fully parsed";
+ bb.position(bb.position() + sizeOfInstance);
+ }
+
+ public abstract void parseDetail(ByteBuffer bb) throws IOException;
+
+
+
+ @Override
+ public String toString() {
+ final StringBuilder sb = new StringBuilder();
+ sb.append("BaseDescriptor");
+ sb.append("{tag=").append(tag);
+ sb.append(", sizeOfInstance=").append(sizeOfInstance);
+ sb.append('}');
+ return sb.toString();
+ }
+}
diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/boxes/mp4/objectdescriptors/BitReaderBuffer.java b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/mp4/objectdescriptors/BitReaderBuffer.java
new file mode 100644
index 0000000..7221503
--- /dev/null
+++ b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/mp4/objectdescriptors/BitReaderBuffer.java
@@ -0,0 +1,51 @@
+package com.googlecode.mp4parser.boxes.mp4.objectdescriptors;
+
+import java.nio.ByteBuffer;
+
+public class BitReaderBuffer {
+
+ private ByteBuffer buffer;
+ int initialPos;
+ int position;
+
+ public BitReaderBuffer(ByteBuffer buffer) {
+ this.buffer = buffer;
+ initialPos = buffer.position();
+ }
+
+ public int readBits(int i) {
+ byte b = buffer.get(initialPos + position / 8);
+ int v = b < 0 ? b + 256 : b;
+ int left = 8 - position % 8;
+ int rc;
+ if (i <= left) {
+ rc = (v << (position % 8) & 0xFF) >> ((position % 8) + (left - i));
+ position += i;
+ } else {
+ int now = left;
+ int then = i - left;
+ rc = readBits(now);
+ rc = rc << then;
+ rc += readBits(then);
+ }
+ buffer.position(initialPos + (int) Math.ceil((double) position / 8));
+ return rc;
+ }
+
+ public int getPosition() {
+ return position;
+ }
+
+ public int byteSync() {
+ int left = 8 - position % 8;
+ if (left == 8) {
+ left = 0;
+ }
+ readBits(left);
+ return left;
+ }
+
+ public int remainingBits() {
+ return buffer.limit() * 8 - position;
+ }
+}
diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/boxes/mp4/objectdescriptors/BitWriterBuffer.java b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/mp4/objectdescriptors/BitWriterBuffer.java
new file mode 100644
index 0000000..e6ea67f
--- /dev/null
+++ b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/mp4/objectdescriptors/BitWriterBuffer.java
@@ -0,0 +1,36 @@
+package com.googlecode.mp4parser.boxes.mp4.objectdescriptors;
+
+import java.nio.ByteBuffer;
+
+public class BitWriterBuffer {
+
+ private ByteBuffer buffer;
+ int initialPos;
+ int position = 0;
+
+ public BitWriterBuffer(ByteBuffer buffer) {
+ this.buffer = buffer;
+ this.initialPos = buffer.position();
+ }
+
+ public void writeBits(int i, int numBits) {
+ assert i <= ((1 << numBits)-1): String.format("Trying to write a value bigger (%s) than the number bits (%s) allows. " +
+ "Please mask the value before writing it and make your code is really working as intended.", i, (1<<numBits)-1);
+
+ int left = 8 - position % 8;
+ if (numBits <= left) {
+ int current = (buffer.get(initialPos + position / 8));
+ current = current < 0 ? current + 256 : current;
+ current += i << (left - numBits);
+ buffer.put(initialPos + position / 8, (byte) (current > 127 ? current - 256 : current));
+ position += numBits;
+ } else {
+ int bitsSecondWrite = numBits - left;
+ writeBits(i >> bitsSecondWrite, left);
+ writeBits(i & (1 << bitsSecondWrite) - 1, bitsSecondWrite);
+ }
+ buffer.position(initialPos + position / 8 + ((position % 8 > 0) ? 1 : 0));
+ }
+
+
+}
diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/boxes/mp4/objectdescriptors/DecoderConfigDescriptor.java b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/mp4/objectdescriptors/DecoderConfigDescriptor.java
new file mode 100644
index 0000000..69d603a
--- /dev/null
+++ b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/mp4/objectdescriptors/DecoderConfigDescriptor.java
@@ -0,0 +1,262 @@
+/*
+ * Copyright 2011 castLabs, 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.googlecode.mp4parser.boxes.mp4.objectdescriptors;
+
+import com.coremedia.iso.Hex;
+import com.coremedia.iso.IsoTypeReader;
+import com.coremedia.iso.IsoTypeWriter;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.logging.Logger;
+
+/**
+ * class DecoderConfigDescriptor extends BaseDescriptor : bit(8)
+ * tag=DecoderConfigDescrTag {
+ * bit(8) objectTypeIndication;
+ * bit(6) streamType;
+ * bit(1) upStream;
+ * const bit(1) reserved=1;
+ * bit(24) bufferSizeDB;
+ * bit(32) maxBitrate;
+ * bit(32) avgBitrate;
+ * DecoderSpecificInfo decSpecificInfo[0 .. 1];
+ * profileLevelIndicationIndexDescriptor profileLevelIndicationIndexDescr
+ * [0..255];
+ * }
+ */
+@Descriptor(tags = {0x04})
+public class DecoderConfigDescriptor extends BaseDescriptor {
+ private static Logger log = Logger.getLogger(DecoderConfigDescriptor.class.getName());
+
+
+ int objectTypeIndication;
+ int streamType;
+ int upStream;
+ int bufferSizeDB;
+ long maxBitRate;
+ long avgBitRate;
+
+ DecoderSpecificInfo decoderSpecificInfo;
+ AudioSpecificConfig audioSpecificInfo;
+ List<ProfileLevelIndicationDescriptor> profileLevelIndicationDescriptors = new ArrayList<ProfileLevelIndicationDescriptor>();
+ byte[] configDescriptorDeadBytes;
+
+ @Override
+ public void parseDetail(ByteBuffer bb) throws IOException {
+ objectTypeIndication = IsoTypeReader.readUInt8(bb);
+
+ int data = IsoTypeReader.readUInt8(bb);
+ streamType = data >>> 2;
+ upStream = (data >> 1) & 0x1;
+
+ bufferSizeDB = IsoTypeReader.readUInt24(bb);
+ maxBitRate = IsoTypeReader.readUInt32(bb);
+ avgBitRate = IsoTypeReader.readUInt32(bb);
+
+
+
+ BaseDescriptor descriptor;
+ if (bb.remaining() > 2) { //1byte tag + at least 1byte size
+ final int begin = bb.position();
+ descriptor = ObjectDescriptorFactory.createFrom(objectTypeIndication, bb);
+ final int read = bb.position() - begin;
+ log.finer(descriptor + " - DecoderConfigDescr1 read: " + read + ", size: " + (descriptor != null ? descriptor.getSize() : null));
+ if (descriptor != null) {
+ final int size = descriptor.getSize();
+ if (read < size) {
+ //skip
+ configDescriptorDeadBytes = new byte[size - read];
+ bb.get(configDescriptorDeadBytes);
+ }
+ }
+ if (descriptor instanceof DecoderSpecificInfo) {
+ decoderSpecificInfo = (DecoderSpecificInfo) descriptor;
+ }
+ if (descriptor instanceof AudioSpecificConfig) {
+ audioSpecificInfo = (AudioSpecificConfig) descriptor;
+ }
+ }
+
+ while (bb.remaining() > 2) {
+ final long begin = bb.position();
+ descriptor = ObjectDescriptorFactory.createFrom(objectTypeIndication, bb);
+ final long read = bb.position() - begin;
+ log.finer(descriptor + " - DecoderConfigDescr2 read: " + read + ", size: " + (descriptor != null ? descriptor.getSize() : null));
+ if (descriptor instanceof ProfileLevelIndicationDescriptor) {
+ profileLevelIndicationDescriptors.add((ProfileLevelIndicationDescriptor) descriptor);
+ }
+ }
+ }
+ public int serializedSize() {
+ return 15 + audioSpecificInfo.serializedSize();
+ }
+
+ public ByteBuffer serialize() {
+ ByteBuffer out = ByteBuffer.allocate(serializedSize());
+ IsoTypeWriter.writeUInt8(out, 4);
+ IsoTypeWriter.writeUInt8(out, serializedSize() - 2);
+ IsoTypeWriter.writeUInt8(out, objectTypeIndication);
+ int flags = (streamType << 2) | (upStream << 1) | 1;
+ IsoTypeWriter.writeUInt8(out, flags);
+ IsoTypeWriter.writeUInt24(out, bufferSizeDB);
+ IsoTypeWriter.writeUInt32(out, maxBitRate);
+ IsoTypeWriter.writeUInt32(out, avgBitRate);
+ out.put(audioSpecificInfo.serialize().array());
+ return out;
+ }
+
+ public DecoderSpecificInfo getDecoderSpecificInfo() {
+ return decoderSpecificInfo;
+ }
+
+ public AudioSpecificConfig getAudioSpecificInfo() {
+ return audioSpecificInfo;
+ }
+
+ public void setAudioSpecificInfo(AudioSpecificConfig audioSpecificInfo) {
+ this.audioSpecificInfo = audioSpecificInfo;
+ }
+
+ public List<ProfileLevelIndicationDescriptor> getProfileLevelIndicationDescriptors() {
+ return profileLevelIndicationDescriptors;
+ }
+
+ public int getObjectTypeIndication() {
+ return objectTypeIndication;
+ }
+
+ public void setObjectTypeIndication(int objectTypeIndication) {
+ this.objectTypeIndication = objectTypeIndication;
+ }
+
+ public int getStreamType() {
+ return streamType;
+ }
+
+ public void setStreamType(int streamType) {
+ this.streamType = streamType;
+ }
+
+ public int getUpStream() {
+ return upStream;
+ }
+
+ public void setUpStream(int upStream) {
+ this.upStream = upStream;
+ }
+
+ public int getBufferSizeDB() {
+ return bufferSizeDB;
+ }
+
+ public void setBufferSizeDB(int 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;
+ }
+
+ @Override
+ public String toString() {
+ final StringBuilder sb = new StringBuilder();
+ sb.append("DecoderConfigDescriptor");
+ sb.append("{objectTypeIndication=").append(objectTypeIndication);
+ sb.append(", streamType=").append(streamType);
+ sb.append(", upStream=").append(upStream);
+ sb.append(", bufferSizeDB=").append(bufferSizeDB);
+ sb.append(", maxBitRate=").append(maxBitRate);
+ sb.append(", avgBitRate=").append(avgBitRate);
+ sb.append(", decoderSpecificInfo=").append(decoderSpecificInfo);
+ sb.append(", audioSpecificInfo=").append(audioSpecificInfo);
+ sb.append(", configDescriptorDeadBytes=").append(Hex.encodeHex(configDescriptorDeadBytes != null ? configDescriptorDeadBytes : new byte[]{}));
+ sb.append(", profileLevelIndicationDescriptors=").append(profileLevelIndicationDescriptors == null ? "null" : Arrays.asList(profileLevelIndicationDescriptors).toString());
+ sb.append('}');
+ return sb.toString();
+ }
+ /*objectTypeIndication values
+ 0x00 Forbidden
+ 0x01 Systems ISO/IEC 14496-1 a
+ 0x02 Systems ISO/IEC 14496-1 b
+ 0x03 Interaction Stream
+ 0x04 Systems ISO/IEC 14496-1 Extended BIFS Configuration c
+ 0x05 Systems ISO/IEC 14496-1 AFX d
+ 0x06 Font Data Stream
+ 0x07 Synthesized Texture Stream
+ 0x08 Streaming Text Stream
+ 0x09-0x1F reserved for ISO use
+ 0x20 Visual ISO/IEC 14496-2 e
+ 0x21 Visual ITU-T Recommendation H.264 | ISO/IEC 14496-10 f
+ 0x22 Parameter Sets for ITU-T Recommendation H.264 | ISO/IEC 14496-10 f
+ 0x23-0x3F reserved for ISO use
+ 0x40 Audio ISO/IEC 14496-3 g
+ 0x41-0x5F reserved for ISO use
+ 0x60 Visual ISO/IEC 13818-2 Simple Profile
+ 0x61 Visual ISO/IEC 13818-2 Main Profile
+ 0x62 Visual ISO/IEC 13818-2 SNR Profile
+ 0x63 Visual ISO/IEC 13818-2 Spatial Profile
+ 0x64 Visual ISO/IEC 13818-2 High Profile
+ 0x65 Visual ISO/IEC 13818-2 422 Profile
+ 0x66 Audio ISO/IEC 13818-7 Main Profile
+ 0x67 Audio ISO/IEC 13818-7 LowComplexity Profile
+ 0x68 Audio ISO/IEC 13818-7 Scaleable Sampling Rate Profile
+ 0x69 Audio ISO/IEC 13818-3
+ 0x6A Visual ISO/IEC 11172-2
+ 0x6B Audio ISO/IEC 11172-3
+ 0x6C Visual ISO/IEC 10918-1
+ 0x6D reserved for registration authority i
+ 0x6E Visual ISO/IEC 15444-1
+ 0x6F - 0x9F reserved for ISO use
+ 0xA0 - 0xBF reserved for registration authority i
+ 0xC0 - 0xE0 user private
+ 0xE1 reserved for registration authority i
+ 0xE2 - 0xFE user private
+ 0xFF no object type specified h
+ */
+ /* streamType values
+ 0x00 Forbidden
+ 0x01 ObjectDescriptorStream (see 7.2.5)
+ 0x02 ClockReferenceStream (see 7.3.2.5)
+ 0x03 SceneDescriptionStream (see ISO/IEC 14496-11)
+ 0x04 VisualStream
+ 0x05 AudioStream
+ 0x06 MPEG7Stream
+ 0x07 IPMPStream (see 7.2.3.2)
+ 0x08 ObjectContentInfoStream (see 7.2.4.2)
+ 0x09 MPEGJStream
+ 0x0A Interaction Stream
+ 0x0B IPMPToolStream (see [ISO/IEC 14496-13])
+ 0x0C - 0x1F reserved for ISO use
+ 0x20 - 0x3F user private
+ */
+}
diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/boxes/mp4/objectdescriptors/DecoderSpecificInfo.java b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/mp4/objectdescriptors/DecoderSpecificInfo.java
new file mode 100644
index 0000000..574943c
--- /dev/null
+++ b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/mp4/objectdescriptors/DecoderSpecificInfo.java
@@ -0,0 +1,85 @@
+/*
+ * Copyright 2011 castLabs, 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.googlecode.mp4parser.boxes.mp4.objectdescriptors;
+
+import com.coremedia.iso.Hex;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.util.Arrays;
+
+/**
+ * abstract class DecoderSpecificInfo extends BaseDescriptor : bit(8)
+ * tag=DecSpecificInfoTag
+ * {
+ * // empty. To be filled by classes extending this class.
+ * }
+ */
+@Descriptor(tags = 0x05)
+public class DecoderSpecificInfo extends BaseDescriptor {
+ byte[] bytes;
+
+ @Override
+ public void parseDetail(ByteBuffer bb) throws IOException {
+ if (sizeOfInstance > 0) {
+ bytes = new byte[sizeOfInstance];
+ bb.get(bytes);
+ }
+ }
+
+ public int serializedSize() {
+ return bytes.length;
+ }
+
+ public ByteBuffer serialize() {
+ ByteBuffer out = ByteBuffer.wrap(bytes);
+
+ return out;
+ }
+
+ @Override
+ public String toString() {
+ final StringBuilder sb = new StringBuilder();
+ sb.append("DecoderSpecificInfo");
+ sb.append("{bytes=").append(bytes == null ? "null" : Hex.encodeHex(bytes));
+ sb.append('}');
+ return sb.toString();
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+
+ DecoderSpecificInfo that = (DecoderSpecificInfo) o;
+
+ if (!Arrays.equals(bytes, that.bytes)) {
+ return false;
+ }
+
+ return true;
+ }
+
+ @Override
+ public int hashCode() {
+ return bytes != null ? Arrays.hashCode(bytes) : 0;
+ }
+}
diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/boxes/mp4/objectdescriptors/Descriptor.java b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/mp4/objectdescriptors/Descriptor.java
new file mode 100644
index 0000000..11020c7
--- /dev/null
+++ b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/mp4/objectdescriptors/Descriptor.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright 2011 castLabs, 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.googlecode.mp4parser.boxes.mp4.objectdescriptors;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Created by IntelliJ IDEA.
+ * User: mstattma
+ * Date: 06.08.2010
+ * Time: 06:54:58
+ * To change this template use File | Settings | File Templates.
+ */
+@Documented
+@Target(ElementType.TYPE)
+@Retention(RetentionPolicy.RUNTIME)
+public @interface Descriptor {
+ int[] tags();
+
+ int objectTypeIndication() default -1;
+}
diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/boxes/mp4/objectdescriptors/ESDescriptor.java b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/mp4/objectdescriptors/ESDescriptor.java
new file mode 100644
index 0000000..3bb4821
--- /dev/null
+++ b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/mp4/objectdescriptors/ESDescriptor.java
@@ -0,0 +1,376 @@
+/*
+ * Copyright 2011 castLabs, 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.googlecode.mp4parser.boxes.mp4.objectdescriptors;
+
+import com.coremedia.iso.IsoTypeReader;
+import com.coremedia.iso.IsoTypeWriter;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.logging.Logger;
+
+/*
+class ES_Descriptor extends BaseDescriptor : bit(8) tag=ES_DescrTag {
+bit(16) ES_ID;
+bit(1) streamDependenceFlag;
+bit(1) URL_Flag;
+bit(1) OCRstreamFlag;
+bit(5) streamPriority;
+if (streamDependenceFlag)
+bit(16) dependsOn_ES_ID;
+if (URL_Flag) {
+bit(8) URLlength;
+bit(8) URLstring[URLlength];
+}
+if (OCRstreamFlag)
+bit(16) OCR_ES_Id;
+DecoderConfigDescriptor decConfigDescr;
+if (ODProfileLevelIndication==0x01) //no SL extension.
+{
+SLConfigDescriptor slConfigDescr;
+}
+else // SL extension is possible.
+{
+SLConfigDescriptor slConfigDescr;
+}
+IPI_DescrPointer ipiPtr[0 .. 1];
+IP_IdentificationDataSet ipIDS[0 .. 255];
+IPMP_DescriptorPointer ipmpDescrPtr[0 .. 255];
+LanguageDescriptor langDescr[0 .. 255];
+QoS_Descriptor qosDescr[0 .. 1];
+RegistrationDescriptor regDescr[0 .. 1];
+ExtensionDescriptor extDescr[0 .. 255];
+}
+ */
+@Descriptor(tags = {0x03})
+public class ESDescriptor extends BaseDescriptor {
+ private static Logger log = Logger.getLogger(ESDescriptor.class.getName());
+
+ int esId;
+ int streamDependenceFlag;
+ int URLFlag;
+ int oCRstreamFlag;
+ int streamPriority;
+
+
+ int URLLength = 0;
+ String URLString;
+ int remoteODFlag;
+
+ int dependsOnEsId;
+ int oCREsId;
+
+ DecoderConfigDescriptor decoderConfigDescriptor;
+ SLConfigDescriptor slConfigDescriptor;
+ List<BaseDescriptor> otherDescriptors = new ArrayList<BaseDescriptor>();
+
+ @Override
+ public void parseDetail(ByteBuffer bb) throws IOException {
+ esId = IsoTypeReader.readUInt16(bb);
+
+ int data = IsoTypeReader.readUInt8(bb);
+ streamDependenceFlag = data >>> 7;
+ URLFlag = (data >>> 6) & 0x1;
+ oCRstreamFlag = (data >>> 5) & 0x1;
+ streamPriority = data & 0x1f;
+
+ if (streamDependenceFlag == 1) {
+ dependsOnEsId = IsoTypeReader.readUInt16(bb);
+ }
+ if (URLFlag == 1) {
+ URLLength = IsoTypeReader.readUInt8(bb);
+ URLString = IsoTypeReader.readString(bb, URLLength);
+ }
+ if (oCRstreamFlag == 1) {
+ oCREsId = IsoTypeReader.readUInt16(bb);
+ }
+
+ int baseSize = 1 /*tag*/ + getSizeBytes() + 2 + 1 + (streamDependenceFlag == 1 ? 2 : 0) + (URLFlag == 1 ? 1 + URLLength : 0) + (oCRstreamFlag == 1 ? 2 : 0);
+
+ int begin = bb.position();
+ if (getSize() > baseSize + 2) {
+ BaseDescriptor descriptor = ObjectDescriptorFactory.createFrom(-1, bb);
+ final long read = bb.position() - begin;
+ log.finer(descriptor + " - ESDescriptor1 read: " + read + ", size: " + (descriptor != null ? descriptor.getSize() : null));
+ if (descriptor != null) {
+ final int size = descriptor.getSize();
+ bb.position(begin + size);
+ baseSize += size;
+ } else {
+ baseSize += read;
+ }
+ if (descriptor instanceof DecoderConfigDescriptor) {
+ decoderConfigDescriptor = (DecoderConfigDescriptor) descriptor;
+ }
+ }
+
+ begin = bb.position();
+ if (getSize() > baseSize + 2) {
+ BaseDescriptor descriptor = ObjectDescriptorFactory.createFrom(-1, bb);
+ final long read = bb.position() - begin;
+ log.finer(descriptor + " - ESDescriptor2 read: " + read + ", size: " + (descriptor != null ? descriptor.getSize() : null));
+ if (descriptor != null) {
+ final int size = descriptor.getSize();
+ bb.position(begin + size);
+ baseSize += size;
+ } else {
+ baseSize += read;
+ }
+ if (descriptor instanceof SLConfigDescriptor) {
+ slConfigDescriptor = (SLConfigDescriptor) descriptor;
+ }
+ } else {
+ log.warning("SLConfigDescriptor is missing!");
+ }
+
+ while (getSize() - baseSize > 2) {
+ begin = bb.position();
+ BaseDescriptor descriptor = ObjectDescriptorFactory.createFrom(-1, bb);
+ final long read = bb.position() - begin;
+ log.finer(descriptor + " - ESDescriptor3 read: " + read + ", size: " + (descriptor != null ? descriptor.getSize() : null));
+ if (descriptor != null) {
+ final int size = descriptor.getSize();
+ bb.position(begin + size);
+ baseSize += size;
+ } else {
+ baseSize += read;
+ }
+ otherDescriptors.add(descriptor);
+ }
+ }
+ public int serializedSize() {
+ int out = 5;
+ if (streamDependenceFlag > 0) {
+ out += 2;
+ }
+ if (URLFlag > 0) {
+ out += 1 + URLLength;
+ }
+ if (oCRstreamFlag > 0) {
+ out += 2;
+ }
+
+ out += decoderConfigDescriptor.serializedSize();
+ out += slConfigDescriptor.serializedSize();
+
+ // Doesn't handle other descriptors yet
+
+ return out;
+ }
+
+ public ByteBuffer serialize() {
+ ByteBuffer out = ByteBuffer.allocate(serializedSize()); // Usually is around 30 bytes, so 200 should be enough...
+ IsoTypeWriter.writeUInt8(out, 3);
+ IsoTypeWriter.writeUInt8(out, serializedSize() - 2); // Not OK for longer sizes!
+ IsoTypeWriter.writeUInt16(out, esId);
+ int flags = (streamDependenceFlag << 7) | (URLFlag << 6) | (oCRstreamFlag << 5) | (streamPriority & 0x1f);
+ IsoTypeWriter.writeUInt8(out, flags);
+ if (streamDependenceFlag > 0) {
+ IsoTypeWriter.writeUInt16(out, dependsOnEsId);
+ }
+ if (URLFlag > 0) {
+ IsoTypeWriter.writeUInt8(out, URLLength);
+ IsoTypeWriter.writeUtf8String(out, URLString);
+ }
+ if (oCRstreamFlag > 0) {
+ IsoTypeWriter.writeUInt16(out, oCREsId);
+ }
+
+ ByteBuffer dec = decoderConfigDescriptor.serialize();
+ ByteBuffer sl = slConfigDescriptor.serialize();
+ out.put(dec.array());
+ out.put(sl.array());
+
+ // Doesn't handle other descriptors yet
+
+ return out;
+ }
+
+// @Override
+// public int getSize() {
+// return 3 + (streamDependenceFlag == 1 ? 2 : 0) +
+// (URLFlag == 1 ? 1 + 8 * URLLength : 0) +
+// (oCRstreamFlag == 1 ? 2 : 0);
+// }
+
+ public DecoderConfigDescriptor getDecoderConfigDescriptor() {
+ return decoderConfigDescriptor;
+ }
+
+ public SLConfigDescriptor getSlConfigDescriptor() {
+ return slConfigDescriptor;
+ }
+
+ public void setDecoderConfigDescriptor(DecoderConfigDescriptor decoderConfigDescriptor) {
+ this.decoderConfigDescriptor = decoderConfigDescriptor;
+ }
+
+ public void setSlConfigDescriptor(SLConfigDescriptor slConfigDescriptor) {
+ this.slConfigDescriptor = slConfigDescriptor;
+ }
+
+ public List<BaseDescriptor> getOtherDescriptors() {
+ return otherDescriptors;
+ }
+
+ public int getoCREsId() {
+ return oCREsId;
+ }
+
+ public void setoCREsId(int oCREsId) {
+ this.oCREsId = oCREsId;
+ }
+
+ public int getEsId() {
+ return esId;
+ }
+
+ public void setEsId(int esId) {
+ this.esId = esId;
+ }
+
+ public int getStreamDependenceFlag() {
+ return streamDependenceFlag;
+ }
+
+ public void setStreamDependenceFlag(int streamDependenceFlag) {
+ this.streamDependenceFlag = streamDependenceFlag;
+ }
+
+ public int getURLFlag() {
+ return URLFlag;
+ }
+
+ public void setURLFlag(int URLFlag) {
+ this.URLFlag = URLFlag;
+ }
+
+ public int getoCRstreamFlag() {
+ return oCRstreamFlag;
+ }
+
+ public void setoCRstreamFlag(int oCRstreamFlag) {
+ this.oCRstreamFlag = oCRstreamFlag;
+ }
+
+ public int getStreamPriority() {
+ return streamPriority;
+ }
+
+ public void setStreamPriority(int streamPriority) {
+ this.streamPriority = streamPriority;
+ }
+
+ public int getURLLength() {
+ return URLLength;
+ }
+
+ public void setURLLength(int URLLength) {
+ this.URLLength = URLLength;
+ }
+
+ public String getURLString() {
+ return URLString;
+ }
+
+ public void setURLString(String URLString) {
+ this.URLString = URLString;
+ }
+
+ public int getRemoteODFlag() {
+ return remoteODFlag;
+ }
+
+ public void setRemoteODFlag(int remoteODFlag) {
+ this.remoteODFlag = remoteODFlag;
+ }
+
+ public int getDependsOnEsId() {
+ return dependsOnEsId;
+ }
+
+ public void setDependsOnEsId(int dependsOnEsId) {
+ this.dependsOnEsId = dependsOnEsId;
+ }
+
+ @Override
+ public String toString() {
+ final StringBuilder sb = new StringBuilder();
+ sb.append("ESDescriptor");
+ sb.append("{esId=").append(esId);
+ sb.append(", streamDependenceFlag=").append(streamDependenceFlag);
+ sb.append(", URLFlag=").append(URLFlag);
+ sb.append(", oCRstreamFlag=").append(oCRstreamFlag);
+ sb.append(", streamPriority=").append(streamPriority);
+ sb.append(", URLLength=").append(URLLength);
+ sb.append(", URLString='").append(URLString).append('\'');
+ sb.append(", remoteODFlag=").append(remoteODFlag);
+ sb.append(", dependsOnEsId=").append(dependsOnEsId);
+ sb.append(", oCREsId=").append(oCREsId);
+ sb.append(", decoderConfigDescriptor=").append(decoderConfigDescriptor);
+ sb.append(", slConfigDescriptor=").append(slConfigDescriptor);
+ sb.append('}');
+ return sb.toString();
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+
+ ESDescriptor that = (ESDescriptor) o;
+
+ if (URLFlag != that.URLFlag) return false;
+ if (URLLength != that.URLLength) return false;
+ if (dependsOnEsId != that.dependsOnEsId) return false;
+ if (esId != that.esId) return false;
+ if (oCREsId != that.oCREsId) return false;
+ if (oCRstreamFlag != that.oCRstreamFlag) return false;
+ if (remoteODFlag != that.remoteODFlag) return false;
+ if (streamDependenceFlag != that.streamDependenceFlag) return false;
+ if (streamPriority != that.streamPriority) return false;
+ if (URLString != null ? !URLString.equals(that.URLString) : that.URLString != null) return false;
+ if (decoderConfigDescriptor != null ? !decoderConfigDescriptor.equals(that.decoderConfigDescriptor) : that.decoderConfigDescriptor != null)
+ return false;
+ if (otherDescriptors != null ? !otherDescriptors.equals(that.otherDescriptors) : that.otherDescriptors != null)
+ return false;
+ if (slConfigDescriptor != null ? !slConfigDescriptor.equals(that.slConfigDescriptor) : that.slConfigDescriptor != null)
+ return false;
+
+ return true;
+ }
+
+ @Override
+ public int hashCode() {
+ int result = esId;
+ result = 31 * result + streamDependenceFlag;
+ result = 31 * result + URLFlag;
+ result = 31 * result + oCRstreamFlag;
+ result = 31 * result + streamPriority;
+ result = 31 * result + URLLength;
+ result = 31 * result + (URLString != null ? URLString.hashCode() : 0);
+ result = 31 * result + remoteODFlag;
+ result = 31 * result + dependsOnEsId;
+ result = 31 * result + oCREsId;
+ result = 31 * result + (decoderConfigDescriptor != null ? decoderConfigDescriptor.hashCode() : 0);
+ result = 31 * result + (slConfigDescriptor != null ? slConfigDescriptor.hashCode() : 0);
+ result = 31 * result + (otherDescriptors != null ? otherDescriptors.hashCode() : 0);
+ return result;
+ }
+}
diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/boxes/mp4/objectdescriptors/ExtensionDescriptor.java b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/mp4/objectdescriptors/ExtensionDescriptor.java
new file mode 100644
index 0000000..7933f5a
--- /dev/null
+++ b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/mp4/objectdescriptors/ExtensionDescriptor.java
@@ -0,0 +1,73 @@
+/*
+ * Copyright 2011 castLabs, 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.googlecode.mp4parser.boxes.mp4.objectdescriptors;
+
+import com.coremedia.iso.Hex;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.util.logging.Logger;
+
+/**
+ * abstract class ExtensionDescriptor extends BaseDescriptor
+ * : bit(8) tag = ExtensionProfileLevelDescrTag, ExtDescrTagStartRange ..
+ * ExtDescrTagEndRange {
+ * // empty. To be filled by classes extending this class.
+ * }
+ */
+@Descriptor(tags = {0x13, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253})
+public class ExtensionDescriptor extends BaseDescriptor {
+ private static Logger log = Logger.getLogger(ExtensionDescriptor.class.getName());
+
+ byte[] bytes;
+
+
+ //todo: add this better to the tags list?
+ //14496-1:2010 p.20:
+ //0x6A-0xBF Reserved for ISO use
+ //0xC0-0xFE User private
+ //
+ //ExtDescrTagStartRange = 0x6A
+ //ExtDescrTagEndRange = 0xFE
+ static int[] allTags() {
+ int[] ints = new int[0xFE - 0x6A];
+
+ for (int i = 0x6A; i < 0xFE; i++) {
+ final int pos = i - 0x6A;
+ log.finest("pos:" + pos);
+ ints[pos] = i;
+ }
+ return ints;
+ }
+
+ @Override
+ public void parseDetail(ByteBuffer bb) throws IOException {
+ if (getSize() > 0) {
+ bytes = new byte[sizeOfInstance];
+ bb.get(bytes);
+ }
+ }
+
+ @Override
+ public String toString() {
+ final StringBuilder sb = new StringBuilder();
+ sb.append("ExtensionDescriptor");
+ sb.append("{bytes=").append(bytes == null ? "null" : Hex.encodeHex(bytes));
+ sb.append('}');
+ return sb.toString();
+ }
+}
diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/boxes/mp4/objectdescriptors/ExtensionProfileLevelDescriptor.java b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/mp4/objectdescriptors/ExtensionProfileLevelDescriptor.java
new file mode 100644
index 0000000..0cf4915
--- /dev/null
+++ b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/mp4/objectdescriptors/ExtensionProfileLevelDescriptor.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright 2011 castLabs, 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.googlecode.mp4parser.boxes.mp4.objectdescriptors;
+
+import com.coremedia.iso.Hex;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+
+/**
+ * abstract class ExtensionDescriptor extends BaseDescriptor
+ * : bit(8) tag = ExtensionProfileLevelDescrTag, ExtDescrTagStartRange ..
+ * ExtDescrTagEndRange {
+ * // empty. To be filled by classes extending this class.
+ * }
+ */
+@Descriptor(tags = {0x13})
+public class ExtensionProfileLevelDescriptor extends BaseDescriptor {
+ byte[] bytes;
+
+ @Override
+ public void parseDetail(ByteBuffer bb) throws IOException {
+ if (getSize() > 0) {
+ bytes = new byte[getSize()];
+ bb.get(bytes);
+ }
+ }
+
+ @Override
+ public String toString() {
+ final StringBuilder sb = new StringBuilder();
+ sb.append("ExtensionDescriptor");
+ sb.append("{bytes=").append(bytes == null ? "null" : Hex.encodeHex(bytes));
+ sb.append('}');
+ return sb.toString();
+ }
+}
diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/boxes/mp4/objectdescriptors/InitialObjectDescriptor.java b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/mp4/objectdescriptors/InitialObjectDescriptor.java
new file mode 100644
index 0000000..7a1f094
--- /dev/null
+++ b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/mp4/objectdescriptors/InitialObjectDescriptor.java
@@ -0,0 +1,136 @@
+/*
+ * Copyright 2011 castLabs, 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.googlecode.mp4parser.boxes.mp4.objectdescriptors;
+
+
+import com.coremedia.iso.IsoTypeReader;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
+import java.util.List;
+
+/*
+class InitialObjectDescriptor extends ObjectDescriptorBase : bit(8)
+tag=InitialObjectDescrTag {
+bit(10) ObjectDescriptorID;
+bit(1) URL_Flag;
+bit(1) includeInlineProfileLevelFlag;
+const bit(4) reserved=0b1111;
+if (URL_Flag) {
+bit(8) URLlength;
+bit(8) URLstring[URLlength];
+} else {
+bit(8) ODProfileLevelIndication;
+bit(8) sceneProfileLevelIndication;
+bit(8) audioProfileLevelIndication;
+bit(8) visualProfileLevelIndication;
+bit(8) graphicsProfileLevelIndication;
+ES_Descriptor esDescr[1 .. 255];
+OCI_Descriptor ociDescr[0 .. 255];
+IPMP_DescriptorPointer ipmpDescrPtr[0 .. 255];
+IPMP_Descriptor ipmpDescr [0 .. 255];
+IPMP_ToolListDescriptor toolListDescr[0 .. 1];
+}
+ExtensionDescriptor extDescr[0 .. 255];
+}
+*/
+//@Descriptor(tags = {0x02, 0x10})
+public class InitialObjectDescriptor extends ObjectDescriptorBase {
+ private int objectDescriptorId;
+ int urlFlag;
+ int includeInlineProfileLevelFlag;
+
+ int urlLength;
+ String urlString;
+
+ int oDProfileLevelIndication;
+ int sceneProfileLevelIndication;
+ int audioProfileLevelIndication;
+ int visualProfileLevelIndication;
+ int graphicsProfileLevelIndication;
+
+ List<ESDescriptor> esDescriptors = new ArrayList<ESDescriptor>();
+
+ List<ExtensionDescriptor> extensionDescriptors = new ArrayList<ExtensionDescriptor>();
+
+ List<BaseDescriptor> unknownDescriptors = new ArrayList<BaseDescriptor>();
+
+ @Override
+ public void parseDetail(ByteBuffer bb) throws IOException {
+ int data = IsoTypeReader.readUInt16(bb);
+ objectDescriptorId = (data & 0xFFC0) >> 6;
+
+ urlFlag = (data & 0x3F) >> 5;
+ includeInlineProfileLevelFlag = (data & 0x1F) >> 4;
+
+ int sizeLeft = getSize() - 2;
+ if (urlFlag == 1) {
+ urlLength = IsoTypeReader.readUInt8(bb);
+ urlString = IsoTypeReader.readString(bb, urlLength);
+ sizeLeft = sizeLeft - (1 + urlLength);
+ } else {
+ oDProfileLevelIndication = IsoTypeReader.readUInt8(bb);
+ sceneProfileLevelIndication = IsoTypeReader.readUInt8(bb);
+ audioProfileLevelIndication = IsoTypeReader.readUInt8(bb);
+ visualProfileLevelIndication = IsoTypeReader.readUInt8(bb);
+ graphicsProfileLevelIndication = IsoTypeReader.readUInt8(bb);
+
+ sizeLeft = sizeLeft - 5;
+
+ if (sizeLeft > 2) {
+ final BaseDescriptor descriptor = ObjectDescriptorFactory.createFrom(-1, bb);
+ sizeLeft = sizeLeft - descriptor.getSize();
+ if (descriptor instanceof ESDescriptor) {
+ esDescriptors.add((ESDescriptor) descriptor);
+ } else {
+ unknownDescriptors.add(descriptor);
+ }
+ }
+ }
+
+ if (sizeLeft > 2) {
+ final BaseDescriptor descriptor = ObjectDescriptorFactory.createFrom(-1, bb);
+ if (descriptor instanceof ExtensionDescriptor) {
+ extensionDescriptors.add((ExtensionDescriptor) descriptor);
+ } else {
+ unknownDescriptors.add(descriptor);
+ }
+ }
+ }
+
+ @Override
+ public String toString() {
+ final StringBuilder sb = new StringBuilder();
+ sb.append("InitialObjectDescriptor");
+ sb.append("{objectDescriptorId=").append(objectDescriptorId);
+ sb.append(", urlFlag=").append(urlFlag);
+ sb.append(", includeInlineProfileLevelFlag=").append(includeInlineProfileLevelFlag);
+ sb.append(", urlLength=").append(urlLength);
+ sb.append(", urlString='").append(urlString).append('\'');
+ sb.append(", oDProfileLevelIndication=").append(oDProfileLevelIndication);
+ sb.append(", sceneProfileLevelIndication=").append(sceneProfileLevelIndication);
+ sb.append(", audioProfileLevelIndication=").append(audioProfileLevelIndication);
+ sb.append(", visualProfileLevelIndication=").append(visualProfileLevelIndication);
+ sb.append(", graphicsProfileLevelIndication=").append(graphicsProfileLevelIndication);
+ sb.append(", esDescriptors=").append(esDescriptors);
+ sb.append(", extensionDescriptors=").append(extensionDescriptors);
+ sb.append(", unknownDescriptors=").append(unknownDescriptors);
+ sb.append('}');
+ return sb.toString();
+ }
+}
diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/boxes/mp4/objectdescriptors/ObjectDescriptor.java_bak b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/mp4/objectdescriptors/ObjectDescriptor.java_bak
new file mode 100644
index 0000000..c5cb586
--- /dev/null
+++ b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/mp4/objectdescriptors/ObjectDescriptor.java_bak
@@ -0,0 +1,104 @@
+/*
+ * Copyright 2011 castLabs, 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.googlecode.mp4parser.boxes.mp4.objectdescriptors;
+
+import com.coremedia.iso.IsoTypeReader;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
+import java.util.List;
+
+/*
+class ObjectDescriptor extends ObjectDescriptorBase : bit(8) tag=ObjectDescrTag {
+bit(10) ObjectDescriptorID;
+bit(1) URL_Flag;
+const bit(5) reserved=0b1111.1;
+if (URL_Flag) {
+bit(8) URLlength;
+bit(8) URLstring[URLlength];
+} else {
+ES_Descriptor esDescr[1 .. 255];
+OCI_Descriptor ociDescr[0 .. 255];
+IPMP_DescriptorPointer ipmpDescrPtr[0 .. 255];
+IPMP_Descriptor ipmpDescr [0 .. 255];
+}
+ExtensionDescriptor extDescr[0 .. 255];
+}
+*/
+@Descriptor(tags = {0x01, 0x11})
+public class ObjectDescriptor extends ObjectDescriptorBase {
+ private int objectDescriptorId;
+ int objectDescriptorUrlFlag;
+ int objectDescriptorUrlLength;
+ String objectDescriptorUrlString;
+
+
+ private int streamCount;
+ private int extensionFlag;
+ private List<ESDescriptor> esDescriptors = new ArrayList<ESDescriptor>();
+
+ private int descriptorLength;
+ private List<ExtensionDescriptor> extensionDescriptors = new ArrayList<ExtensionDescriptor>();
+
+ public static ObjectDescriptor createFrom(ByteBuffer in) throws IOException {
+/*
+ tmp = in.readUInt16();
+ esDescriptor.objectDescriptorId = tmp & 0x3f;
+ esDescriptor.objectDescriptorUrlFlag = (tmp >> 5) & 0x1;
+ if (esDescriptor.objectDescriptorUrlFlag == 1) {
+ esDescriptor.objectDescriptorUrlLength = in.readUInt8();
+ esDescriptor.objectDescriptorUrlString = new String(in.read(esDescriptor.objectDescriptorUrlLength));
+ }
+ */
+
+ ObjectDescriptor objectDescriptor = new ObjectDescriptor();
+
+ int data = IsoTypeReader.readUInt16(in);
+
+ objectDescriptor.objectDescriptorId = data & 0xFFC0;
+ objectDescriptor.streamCount = data & 0x3E;
+ objectDescriptor.extensionFlag = data & 0x1;
+
+// for (int i = 0; i < objectDescriptor.streamCount; i++) {
+// objectDescriptor.esDescriptors.add(ESDescriptor.createFrom(in));
+// }
+//
+// if (objectDescriptor.extensionFlag == 1) {
+// objectDescriptor.descriptorLength = in.readUInt8();
+// for (int i = 0; i < objectDescriptor.descriptorLength;) {
+// ExtensionDescriptor extensionDescriptor = ExtensionDescriptor.createFrom(in);
+// objectDescriptor.extensionDescriptors.add(extensionDescriptor);
+// i = i + extensionDescriptor.descriptorDataLength + 1;
+// }
+// }
+
+ return objectDescriptor;
+ }
+
+ @Override
+ public String toString() {
+ return "ObjectDescriptor{" +
+ "objectDescriptorId=" + objectDescriptorId +
+ ", streamCount=" + streamCount +
+ ", extensionFlag=" + extensionFlag +
+ ", esDescriptors=" + esDescriptors +
+ ", descriptorLength=" + descriptorLength +
+ ", extensionDescriptors=" + extensionDescriptors +
+ '}';
+ }
+}
diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/boxes/mp4/objectdescriptors/ObjectDescriptorBase.java b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/mp4/objectdescriptors/ObjectDescriptorBase.java
new file mode 100644
index 0000000..69a8684
--- /dev/null
+++ b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/mp4/objectdescriptors/ObjectDescriptorBase.java
@@ -0,0 +1,27 @@
+/*
+ * Copyright 2011 castLabs, 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.googlecode.mp4parser.boxes.mp4.objectdescriptors;
+
+/*
+abstract class ObjectDescriptorBase extends BaseDescriptor : bit(8)
+tag=[ObjectDescrTag..InitialObjectDescrTag] {
+// empty. To be filled by classes extending this class.
+}
+ */
+@Descriptor(tags = 0x00)
+public abstract class ObjectDescriptorBase extends BaseDescriptor {
+}
diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/boxes/mp4/objectdescriptors/ObjectDescriptorFactory.java b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/mp4/objectdescriptors/ObjectDescriptorFactory.java
new file mode 100644
index 0000000..6afba55
--- /dev/null
+++ b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/mp4/objectdescriptors/ObjectDescriptorFactory.java
@@ -0,0 +1,189 @@
+/*
+ * Copyright 2011 castLabs, 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.googlecode.mp4parser.boxes.mp4.objectdescriptors;
+
+import com.coremedia.iso.IsoTypeReader;
+
+import java.io.IOException;
+import java.lang.reflect.Modifier;
+import java.nio.ByteBuffer;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+/* class tag values of 14496-1
+0x00 Forbidden
+0x01 ObjectDescrTag
+0x02 InitialObjectDescrTag
+0x03 ES_DescrTag
+0x04 DecoderConfigDescrTag
+0x05 DecSpecificInfoTag
+0x06 SLConfigDescrTag
+0x07 ContentIdentDescrTag
+0x08 SupplContentIdentDescrTag
+0x09 IPI_DescrPointerTag
+0x0A IPMP_DescrPointerTag
+0x0B IPMP_DescrTag
+0x0C QoS_DescrTag
+0x0D RegistrationDescrTag
+0x0E ES_ID_IncTag
+0x0F ES_ID_RefTag
+0x10 MP4_IOD_Tag
+0x11 MP4_OD_Tag
+0x12 IPL_DescrPointerRefTag
+0x13 ExtensionProfileLevelDescrTag
+0x14 profileLevelIndicationIndexDescrTag
+0x15-0x3F Reserved for ISO use
+0x40 ContentClassificationDescrTag
+0x41 KeyWordDescrTag
+0x42 RatingDescrTag
+0x43 LanguageDescrTag
+0x44 ShortTextualDescrTag
+0x45 ExpandedTextualDescrTag
+0x46 ContentCreatorNameDescrTag
+0x47 ContentCreationDateDescrTag
+0x48 OCICreatorNameDescrTag
+0x49 OCICreationDateDescrTag
+0x4A SmpteCameraPositionDescrTag
+0x4B SegmentDescrTag
+0x4C MediaTimeDescrTag
+0x4D-0x5F Reserved for ISO use (OCI extensions)
+0x60 IPMP_ToolsListDescrTag
+0x61 IPMP_ToolTag
+0x62 M4MuxTimingDescrTag
+0x63 M4MuxCodeTableDescrTag
+0x64 ExtSLConfigDescrTag
+0x65 M4MuxBufferSizeDescrTag
+0x66 M4MuxIdentDescrTag
+0x67 DependencyPointerTag
+0x68 DependencyMarkerTag
+0x69 M4MuxChannelDescrTag
+0x6A-0xBF Reserved for ISO use
+0xC0-0xFE User private
+0xFF Forbidden
+ */
+
+/* objectTypeIndication as of 14496-1
+0x00 Forbidden
+0x01 Systems ISO/IEC 14496-1 a
+0x02 Systems ISO/IEC 14496-1 b
+0x03 Interaction Stream
+0x04 Systems ISO/IEC 14496-1 Extended BIFS Configuration c
+0x05 Systems ISO/IEC 14496-1 AFX d
+0x06 Font Data Stream
+0x07 Synthesized Texture Stream
+0x08 Streaming Text Stream
+0x09-0x1F reserved for ISO use
+0x20 Visual ISO/IEC 14496-2 e
+0x21 Visual ITU-T Recommendation H.264 | ISO/IEC 14496-10 f
+0x22 Parameter Sets for ITU-T Recommendation H.264 | ISO/IEC 14496-10 f
+0x23-0x3F reserved for ISO use
+0x40 Audio ISO/IEC 14496-3 g
+0x41-0x5F reserved for ISO use
+0x60 Visual ISO/IEC 13818-2 Simple Profile
+0x61 Visual ISO/IEC 13818-2 Main Profile
+0x62 Visual ISO/IEC 13818-2 SNR Profile
+0x63 Visual ISO/IEC 13818-2 Spatial Profile
+0x64 Visual ISO/IEC 13818-2 High Profile
+0x65 Visual ISO/IEC 13818-2 422 Profile
+0x66 Audio ISO/IEC 13818-7 Main Profile
+0x67 Audio ISO/IEC 13818-7 LowComplexity Profile
+0x68 Audio ISO/IEC 13818-7 Scaleable Sampling Rate Profile
+0x69 Audio ISO/IEC 13818-3
+0x6A Visual ISO/IEC 11172-2
+0x6B Audio ISO/IEC 11172-3
+0x6C Visual ISO/IEC 10918-1
+0x6D reserved for registration authority
+0x6E Visual ISO/IEC 15444-1
+0x6F - 0x9F reserved for ISO use
+0xA0 - 0xBF reserved for registration authority i
+0xC0 - 0xE0 user private
+0xE1 reserved for registration authority i
+0xE2 - 0xFE user private
+0xFF no object type specified h
+ */
+public class ObjectDescriptorFactory {
+ protected static Logger log = Logger.getLogger(ObjectDescriptorFactory.class.getName());
+
+ protected static Map<Integer, Map<Integer, Class<? extends BaseDescriptor>>> descriptorRegistry = new HashMap<Integer, Map<Integer, Class<? extends BaseDescriptor>>>();
+
+ static {
+ Set<Class<? extends BaseDescriptor>> annotated = new HashSet<Class<? extends BaseDescriptor>>();
+
+ annotated.add(DecoderSpecificInfo.class);
+ annotated.add(SLConfigDescriptor.class);
+ annotated.add(BaseDescriptor.class);
+ annotated.add(ExtensionDescriptor.class);
+ annotated.add(ObjectDescriptorBase.class);
+ annotated.add(ProfileLevelIndicationDescriptor.class);
+ annotated.add(AudioSpecificConfig.class);
+ annotated.add(ExtensionProfileLevelDescriptor.class);
+ annotated.add(ESDescriptor.class);
+ annotated.add(DecoderConfigDescriptor.class);
+ //annotated.add(ObjectDescriptor.class);
+
+ for (Class<? extends BaseDescriptor> clazz : annotated) {
+ final Descriptor descriptor = clazz.getAnnotation(Descriptor.class);
+ final int[] tags = descriptor.tags();
+ final int objectTypeInd = descriptor.objectTypeIndication();
+
+ Map<Integer, Class<? extends BaseDescriptor>> tagMap = descriptorRegistry.get(objectTypeInd);
+ if (tagMap == null) {
+ tagMap = new HashMap<Integer, Class<? extends BaseDescriptor>>();
+ }
+ for (int tag : tags) {
+ tagMap.put(tag, clazz);
+ }
+ descriptorRegistry.put(objectTypeInd, tagMap);
+ }
+ }
+
+ public static BaseDescriptor createFrom(int objectTypeIndication, ByteBuffer bb) throws IOException {
+ int tag = IsoTypeReader.readUInt8(bb);
+
+ Map<Integer, Class<? extends BaseDescriptor>> tagMap = descriptorRegistry.get(objectTypeIndication);
+ if (tagMap == null) {
+ tagMap = descriptorRegistry.get(-1);
+ }
+ Class<? extends BaseDescriptor> aClass = tagMap.get(tag);
+
+// if (tag == 0x00) {
+// log.warning("Found illegal tag 0x00! objectTypeIndication " + Integer.toHexString(objectTypeIndication) +
+// " and tag " + Integer.toHexString(tag) + " using: " + aClass);
+// aClass = BaseDescriptor.class;
+// }
+
+ BaseDescriptor baseDescriptor;
+ if (aClass == null || aClass.isInterface() || Modifier.isAbstract(aClass.getModifiers())) {
+ log.warning("No ObjectDescriptor found for objectTypeIndication " + Integer.toHexString(objectTypeIndication) +
+ " and tag " + Integer.toHexString(tag) + " found: " + aClass);
+ baseDescriptor = new UnknownDescriptor();
+ } else {
+ try {
+ baseDescriptor = aClass.newInstance();
+ } catch (Exception e) {
+ log.log(Level.SEVERE, "Couldn't instantiate BaseDescriptor class " + aClass + " for objectTypeIndication " + objectTypeIndication + " and tag " + tag, e);
+ throw new RuntimeException(e);
+ }
+ }
+ baseDescriptor.parse(tag, bb);
+ return baseDescriptor;
+ }
+}
diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/boxes/mp4/objectdescriptors/ProfileLevelIndicationDescriptor.java b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/mp4/objectdescriptors/ProfileLevelIndicationDescriptor.java
new file mode 100644
index 0000000..625277e
--- /dev/null
+++ b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/mp4/objectdescriptors/ProfileLevelIndicationDescriptor.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright 2011 castLabs, 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.googlecode.mp4parser.boxes.mp4.objectdescriptors;
+
+import com.coremedia.iso.IsoTypeReader;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+
+/**
+ * class ProfileLevelIndicationIndexDescriptor () extends BaseDescriptor
+ * : bit(8) ProfileLevelIndicationIndexDescrTag {
+ * bit(8) profileLevelIndicationIndex;
+ * }
+ */
+@Descriptor(tags = 0x14)
+public class ProfileLevelIndicationDescriptor extends BaseDescriptor {
+ int profileLevelIndicationIndex;
+
+ @Override
+ public void parseDetail( ByteBuffer bb) throws IOException {
+ profileLevelIndicationIndex = IsoTypeReader.readUInt8(bb);
+ }
+
+ @Override
+ public String toString() {
+ final StringBuilder sb = new StringBuilder();
+ sb.append("ProfileLevelIndicationDescriptor");
+ sb.append("{profileLevelIndicationIndex=").append(Integer.toHexString(profileLevelIndicationIndex));
+ sb.append('}');
+ return sb.toString();
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+
+ ProfileLevelIndicationDescriptor that = (ProfileLevelIndicationDescriptor) o;
+
+ if (profileLevelIndicationIndex != that.profileLevelIndicationIndex) {
+ return false;
+ }
+
+ return true;
+ }
+
+ @Override
+ public int hashCode() {
+ return profileLevelIndicationIndex;
+ }
+}
diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/boxes/mp4/objectdescriptors/SLConfigDescriptor.java b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/mp4/objectdescriptors/SLConfigDescriptor.java
new file mode 100644
index 0000000..70a58e6
--- /dev/null
+++ b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/mp4/objectdescriptors/SLConfigDescriptor.java
@@ -0,0 +1,119 @@
+/*
+ * Copyright 2011 castLabs, 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.googlecode.mp4parser.boxes.mp4.objectdescriptors;
+
+import com.coremedia.iso.IsoTypeReader;
+import com.coremedia.iso.IsoTypeWriter;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+
+/**
+ * class SLConfigDescriptor extends BaseDescriptor : bit(8) tag=SLConfigDescrTag {
+ * bit(8) predefined;
+ * if (predefined==0) {
+ * bit(1) useAccessUnitStartFlag;
+ * bit(1) useAccessUnitEndFlag;
+ * bit(1) useRandomAccessPointFlag;
+ * bit(1) hasRandomAccessUnitsOnlyFlag;
+ * bit(1) usePaddingFlag;
+ * bit(1) useTimeStampsFlag;
+ * bit(1) useIdleFlag;
+ * bit(1) durationFlag;
+ * bit(32) timeStampResolution;
+ * bit(32) OCRResolution;
+ * bit(8) timeStampLength; // must be ≤ 64
+ * bit(8) OCRLength; // must be ≤ 64
+ * bit(8) AU_Length; // must be ≤ 32
+ * bit(8) instantBitrateLength;
+ * bit(4) degradationPriorityLength;
+ * bit(5) AU_seqNumLength; // must be ≤ 16
+ * bit(5) packetSeqNumLength; // must be ≤ 16
+ * bit(2) reserved=0b11;
+ * }
+ * if (durationFlag) {
+ * bit(32) timeScale;
+ * bit(16) accessUnitDuration;
+ * bit(16) compositionUnitDuration;
+ * }
+ * if (!useTimeStampsFlag) {
+ * bit(timeStampLength) startDecodingTimeStamp;
+ * bit(timeStampLength) startCompositionTimeStamp;
+ * }
+ * }
+ */
+@Descriptor(tags = {0x06})
+public class SLConfigDescriptor extends BaseDescriptor {
+ int predefined;
+
+ public int getPredefined() {
+ return predefined;
+ }
+
+ public void setPredefined(int predefined) {
+ this.predefined = predefined;
+ }
+
+ @Override
+ public void parseDetail(ByteBuffer bb) throws IOException {
+ predefined = IsoTypeReader.readUInt8(bb);
+ }
+
+ public int serializedSize() {
+ return 3;
+ }
+
+ public ByteBuffer serialize() {
+ ByteBuffer out = ByteBuffer.allocate(3);
+ IsoTypeWriter.writeUInt8(out, 6);
+ IsoTypeWriter.writeUInt8(out, 1);
+ IsoTypeWriter.writeUInt8(out, predefined);
+ return out;
+ }
+
+ @Override
+ public String toString() {
+ final StringBuilder sb = new StringBuilder();
+ sb.append("SLConfigDescriptor");
+ sb.append("{predefined=").append(predefined);
+ sb.append('}');
+ return sb.toString();
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+
+ SLConfigDescriptor that = (SLConfigDescriptor) o;
+
+ if (predefined != that.predefined) {
+ return false;
+ }
+
+ return true;
+ }
+
+ @Override
+ public int hashCode() {
+ return predefined;
+ }
+}
diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/boxes/mp4/objectdescriptors/UnknownDescriptor.java b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/mp4/objectdescriptors/UnknownDescriptor.java
new file mode 100644
index 0000000..dd75a0f
--- /dev/null
+++ b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/mp4/objectdescriptors/UnknownDescriptor.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2011 castLabs, 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.googlecode.mp4parser.boxes.mp4.objectdescriptors;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.util.logging.Logger;
+
+public class UnknownDescriptor extends BaseDescriptor {
+ private ByteBuffer data;
+ private static Logger log = Logger.getLogger(UnknownDescriptor.class.getName());
+
+ @Override
+ public void parseDetail(ByteBuffer bb) throws IOException {
+ data = (ByteBuffer) bb.slice().limit(this.getSizeOfInstance());
+ }
+
+ @Override
+ public String toString() {
+ final StringBuilder sb = new StringBuilder();
+ sb.append("UnknownDescriptor");
+ sb.append("{tag=").append(tag);
+ sb.append(", sizeOfInstance=").append(sizeOfInstance);
+ sb.append(", data=").append(data);
+ sb.append('}');
+ return sb.toString();
+ }
+}
diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/boxes/mp4/samplegrouping/.svn/all-wcprops b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/mp4/samplegrouping/.svn/all-wcprops
new file mode 100644
index 0000000..7ac0085
--- /dev/null
+++ b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/mp4/samplegrouping/.svn/all-wcprops
@@ -0,0 +1,59 @@
+K 25
+svn:wc:ra_dav:version-url
+V 97
+/svn/!svn/ver/770/trunk/isoparser/src/main/java/com/googlecode/mp4parser/boxes/mp4/samplegrouping
+END
+RateShareEntry.java
+K 25
+svn:wc:ra_dav:version-url
+V 117
+/svn/!svn/ver/726/trunk/isoparser/src/main/java/com/googlecode/mp4parser/boxes/mp4/samplegrouping/RateShareEntry.java
+END
+UnknownEntry.java
+K 25
+svn:wc:ra_dav:version-url
+V 115
+/svn/!svn/ver/726/trunk/isoparser/src/main/java/com/googlecode/mp4parser/boxes/mp4/samplegrouping/UnknownEntry.java
+END
+VisualRandomAccessEntry.java
+K 25
+svn:wc:ra_dav:version-url
+V 126
+/svn/!svn/ver/770/trunk/isoparser/src/main/java/com/googlecode/mp4parser/boxes/mp4/samplegrouping/VisualRandomAccessEntry.java
+END
+RollRecoveryEntry.java
+K 25
+svn:wc:ra_dav:version-url
+V 120
+/svn/!svn/ver/726/trunk/isoparser/src/main/java/com/googlecode/mp4parser/boxes/mp4/samplegrouping/RollRecoveryEntry.java
+END
+SampleToGroupBox.java
+K 25
+svn:wc:ra_dav:version-url
+V 119
+/svn/!svn/ver/726/trunk/isoparser/src/main/java/com/googlecode/mp4parser/boxes/mp4/samplegrouping/SampleToGroupBox.java
+END
+CencSampleEncryptionInformationGroupEntry.java
+K 25
+svn:wc:ra_dav:version-url
+V 144
+/svn/!svn/ver/726/trunk/isoparser/src/main/java/com/googlecode/mp4parser/boxes/mp4/samplegrouping/CencSampleEncryptionInformationGroupEntry.java
+END
+SampleGroupDescriptionBox.java
+K 25
+svn:wc:ra_dav:version-url
+V 128
+/svn/!svn/ver/770/trunk/isoparser/src/main/java/com/googlecode/mp4parser/boxes/mp4/samplegrouping/SampleGroupDescriptionBox.java
+END
+TemporalLevelEntry.java
+K 25
+svn:wc:ra_dav:version-url
+V 121
+/svn/!svn/ver/770/trunk/isoparser/src/main/java/com/googlecode/mp4parser/boxes/mp4/samplegrouping/TemporalLevelEntry.java
+END
+GroupEntry.java
+K 25
+svn:wc:ra_dav:version-url
+V 113
+/svn/!svn/ver/726/trunk/isoparser/src/main/java/com/googlecode/mp4parser/boxes/mp4/samplegrouping/GroupEntry.java
+END
diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/boxes/mp4/samplegrouping/.svn/entries b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/mp4/samplegrouping/.svn/entries
new file mode 100644
index 0000000..05c761e
--- /dev/null
+++ b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/mp4/samplegrouping/.svn/entries
@@ -0,0 +1,334 @@
+10
+
+dir
+778
+http://mp4parser.googlecode.com/svn/trunk/isoparser/src/main/java/com/googlecode/mp4parser/boxes/mp4/samplegrouping
+http://mp4parser.googlecode.com/svn
+
+
+
+2012-08-31T05:20:57.236953Z
+770
+michael.stattmann@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+7decde4b-c250-0410-a0da-51896bc88be6
+
+RateShareEntry.java
+file
+
+
+
+
+2012-09-14T17:27:51.127228Z
+800d0a2f813152ba00d293052be8b937
+2012-07-31T09:37:53.699964Z
+726
+Sebastian.Annies@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+8043
+
+UnknownEntry.java
+file
+
+
+
+
+2012-09-14T17:27:51.127228Z
+92c8a49a5fb8f163a1a38714e8776de1
+2012-07-31T09:37:53.699964Z
+726
+Sebastian.Annies@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+2046
+
+VisualRandomAccessEntry.java
+file
+
+
+
+
+2012-09-14T17:27:51.127228Z
+544b84d4026c3b8926ba2a44b11ebfcb
+2012-08-31T05:20:57.236953Z
+770
+michael.stattmann@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+3781
+
+RollRecoveryEntry.java
+file
+
+
+
+
+2012-09-14T17:27:51.127228Z
+9233a1017082e95aff5d23c84d635589
+2012-07-31T09:37:53.699964Z
+726
+Sebastian.Annies@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+2417
+
+SampleToGroupBox.java
+file
+
+
+
+
+2012-09-14T17:27:51.127228Z
+5eca2acada7e010970a7037166d46bc1
+2012-07-31T09:37:53.699964Z
+726
+Sebastian.Annies@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+5685
+
+CencSampleEncryptionInformationGroupEntry.java
+file
+
+
+
+
+2012-09-14T17:27:51.127228Z
+fc1a2ad8992cd88b104626d531df492b
+2012-07-31T09:37:53.699964Z
+726
+Sebastian.Annies@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+3641
+
+SampleGroupDescriptionBox.java
+file
+
+
+
+
+2012-09-14T17:27:51.127228Z
+07cd2c76b48eea326d9865d4ba5320e3
+2012-08-31T05:20:57.236953Z
+770
+michael.stattmann@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+7107
+
+TemporalLevelEntry.java
+file
+
+
+
+
+2012-09-14T17:27:51.127228Z
+4657c50c8e3abaf12747fc9413eb83a0
+2012-08-31T05:20:57.236953Z
+770
+michael.stattmann@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+3101
+
+GroupEntry.java
+file
+
+
+
+
+2012-09-14T17:27:51.127228Z
+a699e1a559c1de4043b594f65d462a82
+2012-07-31T09:37:53.699964Z
+726
+Sebastian.Annies@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+877
+
diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/boxes/mp4/samplegrouping/.svn/text-base/CencSampleEncryptionInformationGroupEntry.java.svn-base b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/mp4/samplegrouping/.svn/text-base/CencSampleEncryptionInformationGroupEntry.java.svn-base
new file mode 100644
index 0000000..b54f4d9
--- /dev/null
+++ b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/mp4/samplegrouping/.svn/text-base/CencSampleEncryptionInformationGroupEntry.java.svn-base
@@ -0,0 +1,125 @@
+/*
+ * Copyright 2012 castLabs, 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.googlecode.mp4parser.boxes.mp4.samplegrouping;
+
+import com.coremedia.iso.Hex;
+import com.coremedia.iso.IsoTypeReader;
+import com.coremedia.iso.IsoTypeWriter;
+
+import java.nio.ByteBuffer;
+import java.util.Arrays;
+
+/**
+ * Each sample in a protected track shall be associated with an IsEncrypted flag, IV_Size, and KID.
+ * This can be accomplished by (a) relying on the default values in the TrackEncryptionBox
+ * (see 8.2), or (b) specifying the parameters by sample group, or (c) using a combination of these two techniques.
+ * <p/>
+ * When specifying the parameters by sample group, the SampleToGroupBox in the sample table or track
+ * fragment specifies which samples use which sample group description from the SampleGroupDescriptionBox.
+ */
+public class CencSampleEncryptionInformationGroupEntry extends GroupEntry {
+ public static final String TYPE = "seig";
+
+ private int isEncrypted;
+ private byte ivSize;
+ private byte[] kid = new byte[16];
+
+ @Override
+ public void parse(ByteBuffer byteBuffer) {
+ isEncrypted = IsoTypeReader.readUInt24(byteBuffer);
+ ivSize = (byte) IsoTypeReader.readUInt8(byteBuffer);
+ kid = new byte[16];
+ byteBuffer.get(kid);
+
+ }
+
+ @Override
+ public ByteBuffer get() {
+ ByteBuffer byteBuffer = ByteBuffer.allocate(20);
+ IsoTypeWriter.writeUInt24(byteBuffer, isEncrypted);
+ IsoTypeWriter.writeUInt8(byteBuffer, ivSize);
+ byteBuffer.put(kid);
+ byteBuffer.rewind();
+ return byteBuffer;
+ }
+
+ public int getEncrypted() {
+ return isEncrypted;
+ }
+
+ public void setEncrypted(int encrypted) {
+ isEncrypted = encrypted;
+ }
+
+ public byte getIvSize() {
+ return ivSize;
+ }
+
+ public void setIvSize(byte ivSize) {
+ this.ivSize = ivSize;
+ }
+
+ public byte[] getKid() {
+ return kid;
+ }
+
+ public void setKid(byte[] kid) {
+ assert kid.length == 16;
+ this.kid = kid;
+ }
+
+ @Override
+ public String toString() {
+ return "CencSampleEncryptionInformationGroupEntry{" +
+ "isEncrypted=" + isEncrypted +
+ ", ivSize=" + ivSize +
+ ", kid=" + Hex.encodeHex(kid) +
+ '}';
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+
+ CencSampleEncryptionInformationGroupEntry that = (CencSampleEncryptionInformationGroupEntry) o;
+
+ if (isEncrypted != that.isEncrypted) {
+ return false;
+ }
+ if (ivSize != that.ivSize) {
+ return false;
+ }
+ if (!Arrays.equals(kid, that.kid)) {
+ return false;
+ }
+
+ return true;
+ }
+
+ @Override
+ public int hashCode() {
+ int result = isEncrypted;
+ result = 31 * result + (int) ivSize;
+ result = 31 * result + (kid != null ? Arrays.hashCode(kid) : 0);
+ return result;
+ }
+}
diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/boxes/mp4/samplegrouping/.svn/text-base/GroupEntry.java.svn-base b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/mp4/samplegrouping/.svn/text-base/GroupEntry.java.svn-base
new file mode 100644
index 0000000..0d78d25
--- /dev/null
+++ b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/mp4/samplegrouping/.svn/text-base/GroupEntry.java.svn-base
@@ -0,0 +1,28 @@
+/*
+ * Copyright 2012 castLabs, 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.googlecode.mp4parser.boxes.mp4.samplegrouping;
+
+import java.nio.ByteBuffer;
+
+public abstract class GroupEntry {
+ public abstract void parse(ByteBuffer byteBuffer);
+ public abstract ByteBuffer get();
+
+ public int size() {
+ return get().limit();
+ }
+}
diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/boxes/mp4/samplegrouping/.svn/text-base/RateShareEntry.java.svn-base b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/mp4/samplegrouping/.svn/text-base/RateShareEntry.java.svn-base
new file mode 100644
index 0000000..ae5d380
--- /dev/null
+++ b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/mp4/samplegrouping/.svn/text-base/RateShareEntry.java.svn-base
@@ -0,0 +1,246 @@
+/*
+ * Copyright 2012 castLabs, 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.googlecode.mp4parser.boxes.mp4.samplegrouping;
+
+import com.coremedia.iso.IsoTypeReader;
+import com.coremedia.iso.IsoTypeWriter;
+
+import java.nio.ByteBuffer;
+import java.util.LinkedList;
+import java.util.List;
+
+import static com.googlecode.mp4parser.util.CastUtils.l2i;
+
+/**
+ * Each sample of a track may be associated to (zero or) one of a number of sample group descriptions, each of
+ * which defines a record of rate-share information. Typically the same rate-share information applies to many
+ * consecutive samples and it may therefore be enough to define two or three sample group descriptions that
+ * can be used at different time intervals.
+ * <p/>
+ * The grouping type 'rash' (short for rate share) is defined as the grouping criterion for rate share information.
+ * Zero or one sample-to-group box ('sbgp') for the grouping type 'rash' can be contained in the sample
+ * table box ('stbl') of a track. It shall reside in a hint track, if a hint track is used, otherwise in a media track.
+ * <p/>
+ * Target rate share may be specified for several operation points that are defined in terms of the total available
+ * bitrate, i.e., the bitrate that should be shared. If only one operation point is defined, the target rate share
+ * applies to all available bitrates. If several operation points are defined, then each operation point specifies a
+ * target rate share. Target rate share values specified for the first and the last operation points also specify the
+ * target rate share values at lower and higher available bitrates, respectively. The target rate share between two
+ * operation points is specified to be in the range between the target rate shares of those operation points. One
+ * possibility is to estimate with linear interpolation.
+ */
+public class RateShareEntry extends GroupEntry {
+ public static final String TYPE = "rash";
+
+ private short operationPointCut;
+ private short targetRateShare;
+ private List<Entry> entries = new LinkedList<Entry>();
+ private int maximumBitrate;
+ private int minimumBitrate;
+ private short discardPriority;
+
+
+ @Override
+ public void parse(ByteBuffer byteBuffer) {
+ operationPointCut = byteBuffer.getShort();
+ if (operationPointCut == 1) {
+ targetRateShare = byteBuffer.getShort();
+ } else {
+ int entriesLeft = operationPointCut;
+ while (entriesLeft-- > 0) {
+ entries.add(new Entry(l2i(IsoTypeReader.readUInt32(byteBuffer)), byteBuffer.getShort()));
+ }
+ }
+ maximumBitrate = l2i(IsoTypeReader.readUInt32(byteBuffer));
+ minimumBitrate = l2i(IsoTypeReader.readUInt32(byteBuffer));
+ discardPriority = (short) IsoTypeReader.readUInt8(byteBuffer);
+ }
+
+ @Override
+ public ByteBuffer get() {
+ ByteBuffer buf = ByteBuffer.allocate(operationPointCut == 1?13:(operationPointCut * 6 + 11 ));
+ buf.putShort(operationPointCut);
+ if (operationPointCut == 1) {
+ buf.putShort(targetRateShare );
+ } else {
+ for (Entry entry : entries) {
+ buf.putInt(entry.getAvailableBitrate());
+ buf.putShort(entry.getTargetRateShare());
+ }
+ }
+ buf.putInt(maximumBitrate);
+ buf.putInt(minimumBitrate);
+ IsoTypeWriter.writeUInt8(buf, discardPriority);
+ buf.rewind();
+ return buf;
+ }
+
+ public static class Entry {
+ public Entry(int availableBitrate, short targetRateShare) {
+ this.availableBitrate = availableBitrate;
+ this.targetRateShare = targetRateShare;
+ }
+
+ int availableBitrate;
+ short targetRateShare;
+
+ @Override
+ public String toString() {
+ return "{" +
+ "availableBitrate=" + availableBitrate +
+ ", targetRateShare=" + targetRateShare +
+ '}';
+ }
+
+ public int getAvailableBitrate() {
+ return availableBitrate;
+ }
+
+ public void setAvailableBitrate(int availableBitrate) {
+ this.availableBitrate = availableBitrate;
+ }
+
+ public short getTargetRateShare() {
+ return targetRateShare;
+ }
+
+ public void setTargetRateShare(short targetRateShare) {
+ this.targetRateShare = targetRateShare;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+
+ Entry entry = (Entry) o;
+
+ if (availableBitrate != entry.availableBitrate) {
+ return false;
+ }
+ if (targetRateShare != entry.targetRateShare) {
+ return false;
+ }
+
+ return true;
+ }
+
+ @Override
+ public int hashCode() {
+ int result = availableBitrate;
+ result = 31 * result + (int) targetRateShare;
+ return result;
+ }
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+
+ RateShareEntry that = (RateShareEntry) o;
+
+ if (discardPriority != that.discardPriority) {
+ return false;
+ }
+ if (maximumBitrate != that.maximumBitrate) {
+ return false;
+ }
+ if (minimumBitrate != that.minimumBitrate) {
+ return false;
+ }
+ if (operationPointCut != that.operationPointCut) {
+ return false;
+ }
+ if (targetRateShare != that.targetRateShare) {
+ return false;
+ }
+ if (entries != null ? !entries.equals(that.entries) : that.entries != null) {
+ return false;
+ }
+
+ return true;
+ }
+
+ @Override
+ public int hashCode() {
+ int result = (int) operationPointCut;
+ result = 31 * result + (int) targetRateShare;
+ result = 31 * result + (entries != null ? entries.hashCode() : 0);
+ result = 31 * result + maximumBitrate;
+ result = 31 * result + minimumBitrate;
+ result = 31 * result + (int) discardPriority;
+ return result;
+ }
+
+ public short getOperationPointCut() {
+ return operationPointCut;
+ }
+
+ public void setOperationPointCut(short operationPointCut) {
+ this.operationPointCut = operationPointCut;
+ }
+
+ public short getTargetRateShare() {
+ return targetRateShare;
+ }
+
+ public void setTargetRateShare(short targetRateShare) {
+ this.targetRateShare = targetRateShare;
+ }
+
+ public List<Entry> getEntries() {
+ return entries;
+ }
+
+ public void setEntries(List<Entry> entries) {
+ this.entries = entries;
+ }
+
+ public int getMaximumBitrate() {
+ return maximumBitrate;
+ }
+
+ public void setMaximumBitrate(int maximumBitrate) {
+ this.maximumBitrate = maximumBitrate;
+ }
+
+ public int getMinimumBitrate() {
+ return minimumBitrate;
+ }
+
+ public void setMinimumBitrate(int minimumBitrate) {
+ this.minimumBitrate = minimumBitrate;
+ }
+
+ public short getDiscardPriority() {
+ return discardPriority;
+ }
+
+ public void setDiscardPriority(short discardPriority) {
+ this.discardPriority = discardPriority;
+ }
+}
diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/boxes/mp4/samplegrouping/.svn/text-base/RollRecoveryEntry.java.svn-base b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/mp4/samplegrouping/.svn/text-base/RollRecoveryEntry.java.svn-base
new file mode 100644
index 0000000..bd5b89e
--- /dev/null
+++ b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/mp4/samplegrouping/.svn/text-base/RollRecoveryEntry.java.svn-base
@@ -0,0 +1,77 @@
+/*
+ * Copyright 2012 castLabs, 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.googlecode.mp4parser.boxes.mp4.samplegrouping;
+
+import java.nio.ByteBuffer;
+
+/**
+ * roll_distance is a signed integer that gives the number of samples that must be decoded in order for
+ * a sample to be decoded correctly. A positive value indicates the number of samples after the sample
+ * that is a group member that must be decoded such that at the last of these recovery is complete, i.e.
+ * the last sample is correct. A negative value indicates the number of samples before the sample that is
+ * a group member that must be decoded in order for recovery to be complete at the marked sample.
+ * The value zero must not be used; the sync sample table documents random access points for which
+ * no recovery roll is needed.
+ */
+public class RollRecoveryEntry extends GroupEntry {
+ public static final String TYPE = "roll";
+ private short rollDistance;
+
+ public short getRollDistance() {
+ return rollDistance;
+ }
+
+ public void setRollDistance(short rollDistance) {
+ this.rollDistance = rollDistance;
+ }
+
+ @Override
+ public void parse(ByteBuffer byteBuffer) {
+ rollDistance = byteBuffer.getShort();
+ }
+
+ @Override
+ public ByteBuffer get() {
+ ByteBuffer content = ByteBuffer.allocate(2);
+ content.putShort(rollDistance);
+ content.rewind();
+ return content;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+
+ RollRecoveryEntry entry = (RollRecoveryEntry) o;
+
+ if (rollDistance != entry.rollDistance) {
+ return false;
+ }
+
+ return true;
+ }
+
+ @Override
+ public int hashCode() {
+ return (int) rollDistance;
+ }
+}
diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/boxes/mp4/samplegrouping/.svn/text-base/SampleGroupDescriptionBox.java.svn-base b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/mp4/samplegrouping/.svn/text-base/SampleGroupDescriptionBox.java.svn-base
new file mode 100644
index 0000000..df4a96f
--- /dev/null
+++ b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/mp4/samplegrouping/.svn/text-base/SampleGroupDescriptionBox.java.svn-base
@@ -0,0 +1,200 @@
+/*
+ * Copyright 2012 castLabs, 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.googlecode.mp4parser.boxes.mp4.samplegrouping;
+
+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;
+
+/**
+ * This description table gives information about the characteristics of sample groups. The descriptive
+ * information is any other information needed to define or characterize the sample group.
+ * <p/>
+ * There may be multiple instances of this box if there is more than one sample grouping for the samples in a
+ * track. Each instance of the SampleGroupDescription box has a type code that distinguishes different
+ * sample groupings. Within a track, there shall be at most one instance of this box with a particular grouping
+ * type. The associated SampleToGroup shall indicate the same value for the grouping type.
+ * <p/>
+ * The information is stored in the sample group description box after the entry-count. An abstract entry type is
+ * defined and sample groupings shall define derived types to represent the description of each sample group.
+ * For video tracks, an abstract VisualSampleGroupEntry is used with similar types for audio and hint tracks.
+ */
+public class SampleGroupDescriptionBox extends AbstractFullBox {
+ public static final String TYPE = "sgpd";
+
+ private String groupingType;
+ private int defaultLength;
+ private List<GroupEntry> groupEntries = new LinkedList<GroupEntry>();
+ private int descriptionLength;
+
+ public SampleGroupDescriptionBox() {
+ super(TYPE);
+ }
+
+ @Override
+ protected long getContentSize() {
+ long size = 8;
+ if (getVersion() == 1) {
+ size += 4;
+ }
+ size += 4; // entryCount
+ for (GroupEntry groupEntry : groupEntries) {
+ if (getVersion() == 1 && defaultLength == 0) {
+ size += 4;
+ }
+ size += groupEntry.size();
+ }
+ return size;
+ }
+
+ @Override
+ protected void getContent(ByteBuffer byteBuffer) {
+ writeVersionAndFlags(byteBuffer);
+ byteBuffer.put(groupingType.getBytes());
+ if (this.getVersion() == 1) {
+ IsoTypeWriter.writeUInt32(byteBuffer, defaultLength);
+ }
+ IsoTypeWriter.writeUInt32(byteBuffer, this.groupEntries.size());
+ for (GroupEntry entry : groupEntries) {
+ if (this.getVersion() == 1 && defaultLength == 0) {
+ IsoTypeWriter.writeUInt32(byteBuffer, entry.get().limit());
+ }
+ byteBuffer.put(entry.get());
+ }
+ }
+
+ @Override
+ protected void _parseDetails(ByteBuffer content) {
+ parseVersionAndFlags(content);
+ if (this.getVersion() != 1) {
+ throw new RuntimeException("SampleGroupDescriptionBox are only supported in version 1");
+ }
+ groupingType = IsoTypeReader.read4cc(content);
+ if (this.getVersion() == 1) {
+ defaultLength = l2i(IsoTypeReader.readUInt32(content));
+ }
+ long entryCount = IsoTypeReader.readUInt32(content);
+ while (entryCount-- > 0) {
+ int length = defaultLength;
+ if (this.getVersion() == 1) {
+ if (defaultLength == 0) {
+ descriptionLength = l2i(IsoTypeReader.readUInt32(content));
+ length = descriptionLength;
+ }
+ } else {
+ throw new RuntimeException("This should be implemented");
+ }
+ int finalPos = content.position() + length;
+ ByteBuffer parseMe = content.slice();
+ parseMe.limit(length);
+ groupEntries.add(parseGroupEntry(parseMe, groupingType));
+ content.position(finalPos);
+ }
+
+ }
+
+ private GroupEntry parseGroupEntry(ByteBuffer content, String groupingType) {
+ GroupEntry groupEntry;
+ if (RollRecoveryEntry.TYPE.equals(groupingType)) {
+ groupEntry = new RollRecoveryEntry();
+ } else if (RateShareEntry.TYPE.equals(groupingType)) {
+ groupEntry = new RateShareEntry();
+ } else if (CencSampleEncryptionInformationGroupEntry.TYPE.equals(groupingType)) {
+ groupEntry = new CencSampleEncryptionInformationGroupEntry();
+ } else if (VisualRandomAccessEntry.TYPE.equals(groupingType)) {
+ groupEntry = new VisualRandomAccessEntry();
+ } else if (TemporalLevelEntry.TYPE.equals(groupingType)) {
+ groupEntry = new TemporalLevelEntry();
+ } else {
+ groupEntry = new UnknownEntry();
+ }
+ groupEntry.parse(content);
+ return groupEntry;
+ }
+
+
+ public String getGroupingType() {
+ return groupingType;
+ }
+
+ public void setGroupingType(String groupingType) {
+ this.groupingType = groupingType;
+ }
+
+ public int getDefaultLength() {
+ return defaultLength;
+ }
+
+ public void setDefaultLength(int defaultLength) {
+ this.defaultLength = defaultLength;
+ }
+
+ public List<GroupEntry> getGroupEntries() {
+ return groupEntries;
+ }
+
+ public void setGroupEntries(List<GroupEntry> groupEntries) {
+ this.groupEntries = groupEntries;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+
+ SampleGroupDescriptionBox that = (SampleGroupDescriptionBox) o;
+
+ if (defaultLength != that.defaultLength) {
+ return false;
+ }
+ if (groupEntries != null ? !groupEntries.equals(that.groupEntries) : that.groupEntries != null) {
+ return false;
+ }
+ if (groupingType != null ? !groupingType.equals(that.groupingType) : that.groupingType != null) {
+ return false;
+ }
+
+ return true;
+ }
+
+ @Override
+ public int hashCode() {
+ int result = groupingType != null ? groupingType.hashCode() : 0;
+ result = 31 * result + defaultLength;
+ result = 31 * result + (groupEntries != null ? groupEntries.hashCode() : 0);
+ return result;
+ }
+
+ @Override
+ public String toString() {
+ return "SampleGroupDescriptionBox{" +
+ "groupingType='" + groupingType + '\'' +
+ ", defaultLength=" + defaultLength +
+ ", groupEntries=" + groupEntries +
+ '}';
+ }
+}
diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/boxes/mp4/samplegrouping/.svn/text-base/SampleToGroupBox.java.svn-base b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/mp4/samplegrouping/.svn/text-base/SampleToGroupBox.java.svn-base
new file mode 100644
index 0000000..0fa059e
--- /dev/null
+++ b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/mp4/samplegrouping/.svn/text-base/SampleToGroupBox.java.svn-base
@@ -0,0 +1,174 @@
+/*
+ * Copyright 2012 castLabs, 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.googlecode.mp4parser.boxes.mp4.samplegrouping;
+
+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;
+
+/**
+ * This table can be used to find the group that a sample belongs to and the associated description of that
+ * sample group. The table is compactly coded with each entry giving the index of the first sample of a run of
+ * samples with the same sample group descriptor. The sample group description ID is an index that refers to a
+ * SampleGroupDescription box, which contains entries describing the characteristics of each sample group.
+ * <p/>
+ * There may be multiple instances of this box if there is more than one sample grouping for the samples in a
+ * track. Each instance of the SampleToGroup box has a type code that distinguishes different sample
+ * groupings. Within a track, there shall be at most one instance of this box with a particular grouping type. The
+ * associated SampleGroupDescription shall indicate the same value for the grouping type.
+ * <p/>
+ * Version 1 of this box should only be used if a grouping type parameter is needed.
+ */
+public class SampleToGroupBox extends AbstractFullBox {
+ public static final String TYPE = "sbgp";
+
+
+ private String groupingType;
+ private String groupingTypeParameter;
+
+ List<Entry> entries = new LinkedList<Entry>();
+
+ public SampleToGroupBox() {
+ super(TYPE);
+
+ }
+
+ @Override
+ protected long getContentSize() {
+ return this.getVersion() == 1 ? entries.size() * 8 + 16 : entries.size() * 8 + 12;
+ }
+
+ @Override
+ protected void getContent(ByteBuffer byteBuffer) {
+ writeVersionAndFlags(byteBuffer);
+ byteBuffer.put(groupingType.getBytes());
+ if (this.getVersion() == 1) {
+ byteBuffer.put(groupingTypeParameter.getBytes());
+ }
+ IsoTypeWriter.writeUInt32(byteBuffer, entries.size());
+ for (Entry entry : entries) {
+ IsoTypeWriter.writeUInt32(byteBuffer, entry.getSampleCount());
+ IsoTypeWriter.writeUInt32(byteBuffer, entry.getGroupDescriptionIndex());
+ }
+
+ }
+
+ @Override
+ protected void _parseDetails(ByteBuffer content) {
+ parseVersionAndFlags(content);
+ groupingType = IsoTypeReader.read4cc(content);
+ if (this.getVersion() == 1) {
+ groupingTypeParameter = IsoTypeReader.read4cc(content);
+ }
+ long entryCount = IsoTypeReader.readUInt32(content);
+ while (entryCount-- > 0) {
+ entries.add(new Entry(l2i(IsoTypeReader.readUInt32(content)), l2i(IsoTypeReader.readUInt32(content))));
+ }
+ }
+
+ public static class Entry {
+ private long sampleCount;
+ private int groupDescriptionIndex;
+
+ public Entry(long sampleCount, int groupDescriptionIndex) {
+ this.sampleCount = sampleCount;
+ this.groupDescriptionIndex = groupDescriptionIndex;
+ }
+
+ public long getSampleCount() {
+ return sampleCount;
+ }
+
+ public void setSampleCount(long sampleCount) {
+ this.sampleCount = sampleCount;
+ }
+
+ public int getGroupDescriptionIndex() {
+ return groupDescriptionIndex;
+ }
+
+ public void setGroupDescriptionIndex(int groupDescriptionIndex) {
+ this.groupDescriptionIndex = groupDescriptionIndex;
+ }
+
+ @Override
+ public String toString() {
+ return "Entry{" +
+ "sampleCount=" + sampleCount +
+ ", groupDescriptionIndex=" + groupDescriptionIndex +
+ '}';
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+
+ Entry entry = (Entry) o;
+
+ if (groupDescriptionIndex != entry.groupDescriptionIndex) {
+ return false;
+ }
+ if (sampleCount != entry.sampleCount) {
+ return false;
+ }
+
+ return true;
+ }
+
+ @Override
+ public int hashCode() {
+ int result = (int) (sampleCount ^ (sampleCount >>> 32));
+ result = 31 * result + groupDescriptionIndex;
+ return result;
+ }
+ }
+
+ public String getGroupingType() {
+ return groupingType;
+ }
+
+ public void setGroupingType(String groupingType) {
+ this.groupingType = groupingType;
+ }
+
+ public String getGroupingTypeParameter() {
+ return groupingTypeParameter;
+ }
+
+ public void setGroupingTypeParameter(String groupingTypeParameter) {
+ this.groupingTypeParameter = groupingTypeParameter;
+ }
+
+ public List<Entry> getEntries() {
+ return entries;
+ }
+
+ public void setEntries(List<Entry> entries) {
+ this.entries = entries;
+ }
+}
diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/boxes/mp4/samplegrouping/.svn/text-base/TemporalLevelEntry.java.svn-base b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/mp4/samplegrouping/.svn/text-base/TemporalLevelEntry.java.svn-base
new file mode 100644
index 0000000..798fd9c
--- /dev/null
+++ b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/mp4/samplegrouping/.svn/text-base/TemporalLevelEntry.java.svn-base
@@ -0,0 +1,82 @@
+/*
+ * Copyright 2012 castLabs, 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.googlecode.mp4parser.boxes.mp4.samplegrouping;
+
+import java.nio.ByteBuffer;
+
+/**
+ * The Temporal Level sample grouping ('tele') provides a codec-independent sample grouping that can be used to group samples (access units) in a track (and potential track fragments) according to temporal level, where samples of one temporal level have no coding dependencies on samples of higher temporal levels. The temporal level equals the sample group description index (taking values 1, 2, 3, etc). The bitstream containing only the access units from the first temporal level to a higher temporal level remains conforming to the coding standard.
+ *
+ * A grouping according to temporal level facilitates easy extraction of temporal subsequences, for instance using the Subsegment Indexing box in 0.
+ *
+ */
+public class TemporalLevelEntry extends GroupEntry {
+ public static final String TYPE = "tele";
+ private boolean levelIndependentlyDecodable;
+ private short reserved;
+
+ public boolean isLevelIndependentlyDecodable() {
+ return levelIndependentlyDecodable;
+ }
+
+ public void setLevelIndependentlyDecodable(boolean levelIndependentlyDecodable) {
+ this.levelIndependentlyDecodable = levelIndependentlyDecodable;
+ }
+
+ @Override
+ public void parse(ByteBuffer byteBuffer) {
+ final byte b = byteBuffer.get();
+ levelIndependentlyDecodable = ((b & 0x80) == 0x80);
+ }
+
+ @Override
+ public ByteBuffer get() {
+ ByteBuffer content = ByteBuffer.allocate(1);
+ content.put((byte) (levelIndependentlyDecodable ? 0x80 : 0x00));
+ content.rewind();
+ return content;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+
+ TemporalLevelEntry that = (TemporalLevelEntry) o;
+
+ if (levelIndependentlyDecodable != that.levelIndependentlyDecodable) return false;
+ if (reserved != that.reserved) return false;
+
+ return true;
+ }
+
+ @Override
+ public int hashCode() {
+ int result = (levelIndependentlyDecodable ? 1 : 0);
+ result = 31 * result + (int) reserved;
+ return result;
+ }
+
+ @Override
+ public String toString() {
+ final StringBuilder sb = new StringBuilder();
+ sb.append("TemporalLevelEntry");
+ sb.append("{levelIndependentlyDecodable=").append(levelIndependentlyDecodable);
+ sb.append('}');
+ return sb.toString();
+ }
+}
diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/boxes/mp4/samplegrouping/.svn/text-base/UnknownEntry.java.svn-base b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/mp4/samplegrouping/.svn/text-base/UnknownEntry.java.svn-base
new file mode 100644
index 0000000..9efcbea
--- /dev/null
+++ b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/mp4/samplegrouping/.svn/text-base/UnknownEntry.java.svn-base
@@ -0,0 +1,83 @@
+/*
+ * Copyright 2012 castLabs, 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.googlecode.mp4parser.boxes.mp4.samplegrouping;
+
+import com.coremedia.iso.Hex;
+
+import java.nio.ByteBuffer;
+
+/**
+ *
+ */
+public class UnknownEntry extends GroupEntry {
+ private ByteBuffer content;
+
+ public UnknownEntry() {
+ }
+
+ public ByteBuffer getContent() {
+ return content;
+ }
+
+ public void setContent(ByteBuffer content) {
+ this.content = (ByteBuffer) content.duplicate().rewind();
+ }
+
+ @Override
+ public void parse(ByteBuffer byteBuffer) {
+ this.content = (ByteBuffer) byteBuffer.duplicate().rewind();
+ }
+
+ @Override
+ public ByteBuffer get() {
+ return content.duplicate();
+ }
+
+ @Override
+ public String toString() {
+ ByteBuffer bb = content.duplicate();
+ bb.rewind();
+ byte[] b = new byte[bb.limit()];
+ bb.get(b);
+ return "UnknownEntry{" +
+ "content=" + Hex.encodeHex(b) +
+ '}';
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+
+ UnknownEntry that = (UnknownEntry) o;
+
+ if (content != null ? !content.equals(that.content) : that.content != null) {
+ return false;
+ }
+
+ return true;
+ }
+
+ @Override
+ public int hashCode() {
+ return content != null ? content.hashCode() : 0;
+ }
+}
diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/boxes/mp4/samplegrouping/.svn/text-base/VisualRandomAccessEntry.java.svn-base b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/mp4/samplegrouping/.svn/text-base/VisualRandomAccessEntry.java.svn-base
new file mode 100644
index 0000000..ed5d199
--- /dev/null
+++ b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/mp4/samplegrouping/.svn/text-base/VisualRandomAccessEntry.java.svn-base
@@ -0,0 +1,94 @@
+/*
+ * Copyright 2012 castLabs, 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.googlecode.mp4parser.boxes.mp4.samplegrouping;
+
+import com.coremedia.iso.IsoTypeReader;
+
+import java.nio.ByteBuffer;
+
+/**
+ * For some coding systems a sync sample is specified to be a random access point after which all samples in decoding order can be correctly decoded. However, it may be possible to encode an “open” random access point, after which all samples in output order can be correctly decoded, but some samples following the random access point in decoding order and preceding the random access point in output order need not be correctly decodable. For example, an intra picture starting an open group of pictures can be followed in decoding order by (bi-)predicted pictures that however precede the intra picture in output order; though they possibly cannot be correctly decoded if the decoding starts from the intra picture, they are not needed.
+ *
+ * Such “open” random-access samples can be marked by being a member of this group. Samples marked by this group must be random access points, and may also be sync points (i.e. it is not required that samples marked by the sync sample table be excluded).
+ *
+ */
+public class VisualRandomAccessEntry extends GroupEntry {
+ public static final String TYPE = "rap ";
+ private boolean numLeadingSamplesKnown;
+ private short numLeadingSamples;
+
+ public boolean isNumLeadingSamplesKnown() {
+ return numLeadingSamplesKnown;
+ }
+
+ public void setNumLeadingSamplesKnown(boolean numLeadingSamplesKnown) {
+ this.numLeadingSamplesKnown = numLeadingSamplesKnown;
+ }
+
+ public short getNumLeadingSamples() {
+ return numLeadingSamples;
+ }
+
+ public void setNumLeadingSamples(short numLeadingSamples) {
+ this.numLeadingSamples = numLeadingSamples;
+ }
+
+ @Override
+ public void parse(ByteBuffer byteBuffer) {
+ final byte b = byteBuffer.get();
+ numLeadingSamplesKnown = ((b & 0x80) == 0x80);
+ numLeadingSamples = (short) (b & 0x7f);
+ }
+
+ @Override
+ public ByteBuffer get() {
+ ByteBuffer content = ByteBuffer.allocate(1);
+ content.put((byte) ((numLeadingSamplesKnown? 0x80 : 0x00)| (numLeadingSamples & 0x7f)));
+ content.rewind();
+ return content;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+
+ VisualRandomAccessEntry that = (VisualRandomAccessEntry) o;
+
+ if (numLeadingSamples != that.numLeadingSamples) return false;
+ if (numLeadingSamplesKnown != that.numLeadingSamplesKnown) return false;
+
+ return true;
+ }
+
+ @Override
+ public int hashCode() {
+ int result = (numLeadingSamplesKnown ? 1 : 0);
+ result = 31 * result + (int) numLeadingSamples;
+ return result;
+ }
+
+ @Override
+ public String toString() {
+ final StringBuilder sb = new StringBuilder();
+ sb.append("VisualRandomAccessEntry");
+ sb.append("{numLeadingSamplesKnown=").append(numLeadingSamplesKnown);
+ sb.append(", numLeadingSamples=").append(numLeadingSamples);
+ sb.append('}');
+ return sb.toString();
+ }
+}
diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/boxes/mp4/samplegrouping/CencSampleEncryptionInformationGroupEntry.java b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/mp4/samplegrouping/CencSampleEncryptionInformationGroupEntry.java
new file mode 100644
index 0000000..b54f4d9
--- /dev/null
+++ b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/mp4/samplegrouping/CencSampleEncryptionInformationGroupEntry.java
@@ -0,0 +1,125 @@
+/*
+ * Copyright 2012 castLabs, 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.googlecode.mp4parser.boxes.mp4.samplegrouping;
+
+import com.coremedia.iso.Hex;
+import com.coremedia.iso.IsoTypeReader;
+import com.coremedia.iso.IsoTypeWriter;
+
+import java.nio.ByteBuffer;
+import java.util.Arrays;
+
+/**
+ * Each sample in a protected track shall be associated with an IsEncrypted flag, IV_Size, and KID.
+ * This can be accomplished by (a) relying on the default values in the TrackEncryptionBox
+ * (see 8.2), or (b) specifying the parameters by sample group, or (c) using a combination of these two techniques.
+ * <p/>
+ * When specifying the parameters by sample group, the SampleToGroupBox in the sample table or track
+ * fragment specifies which samples use which sample group description from the SampleGroupDescriptionBox.
+ */
+public class CencSampleEncryptionInformationGroupEntry extends GroupEntry {
+ public static final String TYPE = "seig";
+
+ private int isEncrypted;
+ private byte ivSize;
+ private byte[] kid = new byte[16];
+
+ @Override
+ public void parse(ByteBuffer byteBuffer) {
+ isEncrypted = IsoTypeReader.readUInt24(byteBuffer);
+ ivSize = (byte) IsoTypeReader.readUInt8(byteBuffer);
+ kid = new byte[16];
+ byteBuffer.get(kid);
+
+ }
+
+ @Override
+ public ByteBuffer get() {
+ ByteBuffer byteBuffer = ByteBuffer.allocate(20);
+ IsoTypeWriter.writeUInt24(byteBuffer, isEncrypted);
+ IsoTypeWriter.writeUInt8(byteBuffer, ivSize);
+ byteBuffer.put(kid);
+ byteBuffer.rewind();
+ return byteBuffer;
+ }
+
+ public int getEncrypted() {
+ return isEncrypted;
+ }
+
+ public void setEncrypted(int encrypted) {
+ isEncrypted = encrypted;
+ }
+
+ public byte getIvSize() {
+ return ivSize;
+ }
+
+ public void setIvSize(byte ivSize) {
+ this.ivSize = ivSize;
+ }
+
+ public byte[] getKid() {
+ return kid;
+ }
+
+ public void setKid(byte[] kid) {
+ assert kid.length == 16;
+ this.kid = kid;
+ }
+
+ @Override
+ public String toString() {
+ return "CencSampleEncryptionInformationGroupEntry{" +
+ "isEncrypted=" + isEncrypted +
+ ", ivSize=" + ivSize +
+ ", kid=" + Hex.encodeHex(kid) +
+ '}';
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+
+ CencSampleEncryptionInformationGroupEntry that = (CencSampleEncryptionInformationGroupEntry) o;
+
+ if (isEncrypted != that.isEncrypted) {
+ return false;
+ }
+ if (ivSize != that.ivSize) {
+ return false;
+ }
+ if (!Arrays.equals(kid, that.kid)) {
+ return false;
+ }
+
+ return true;
+ }
+
+ @Override
+ public int hashCode() {
+ int result = isEncrypted;
+ result = 31 * result + (int) ivSize;
+ result = 31 * result + (kid != null ? Arrays.hashCode(kid) : 0);
+ return result;
+ }
+}
diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/boxes/mp4/samplegrouping/GroupEntry.java b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/mp4/samplegrouping/GroupEntry.java
new file mode 100644
index 0000000..0d78d25
--- /dev/null
+++ b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/mp4/samplegrouping/GroupEntry.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright 2012 castLabs, 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.googlecode.mp4parser.boxes.mp4.samplegrouping;
+
+import java.nio.ByteBuffer;
+
+public abstract class GroupEntry {
+ public abstract void parse(ByteBuffer byteBuffer);
+ public abstract ByteBuffer get();
+
+ public int size() {
+ return get().limit();
+ }
+}
diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/boxes/mp4/samplegrouping/RateShareEntry.java b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/mp4/samplegrouping/RateShareEntry.java
new file mode 100644
index 0000000..ae5d380
--- /dev/null
+++ b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/mp4/samplegrouping/RateShareEntry.java
@@ -0,0 +1,246 @@
+/*
+ * Copyright 2012 castLabs, 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.googlecode.mp4parser.boxes.mp4.samplegrouping;
+
+import com.coremedia.iso.IsoTypeReader;
+import com.coremedia.iso.IsoTypeWriter;
+
+import java.nio.ByteBuffer;
+import java.util.LinkedList;
+import java.util.List;
+
+import static com.googlecode.mp4parser.util.CastUtils.l2i;
+
+/**
+ * Each sample of a track may be associated to (zero or) one of a number of sample group descriptions, each of
+ * which defines a record of rate-share information. Typically the same rate-share information applies to many
+ * consecutive samples and it may therefore be enough to define two or three sample group descriptions that
+ * can be used at different time intervals.
+ * <p/>
+ * The grouping type 'rash' (short for rate share) is defined as the grouping criterion for rate share information.
+ * Zero or one sample-to-group box ('sbgp') for the grouping type 'rash' can be contained in the sample
+ * table box ('stbl') of a track. It shall reside in a hint track, if a hint track is used, otherwise in a media track.
+ * <p/>
+ * Target rate share may be specified for several operation points that are defined in terms of the total available
+ * bitrate, i.e., the bitrate that should be shared. If only one operation point is defined, the target rate share
+ * applies to all available bitrates. If several operation points are defined, then each operation point specifies a
+ * target rate share. Target rate share values specified for the first and the last operation points also specify the
+ * target rate share values at lower and higher available bitrates, respectively. The target rate share between two
+ * operation points is specified to be in the range between the target rate shares of those operation points. One
+ * possibility is to estimate with linear interpolation.
+ */
+public class RateShareEntry extends GroupEntry {
+ public static final String TYPE = "rash";
+
+ private short operationPointCut;
+ private short targetRateShare;
+ private List<Entry> entries = new LinkedList<Entry>();
+ private int maximumBitrate;
+ private int minimumBitrate;
+ private short discardPriority;
+
+
+ @Override
+ public void parse(ByteBuffer byteBuffer) {
+ operationPointCut = byteBuffer.getShort();
+ if (operationPointCut == 1) {
+ targetRateShare = byteBuffer.getShort();
+ } else {
+ int entriesLeft = operationPointCut;
+ while (entriesLeft-- > 0) {
+ entries.add(new Entry(l2i(IsoTypeReader.readUInt32(byteBuffer)), byteBuffer.getShort()));
+ }
+ }
+ maximumBitrate = l2i(IsoTypeReader.readUInt32(byteBuffer));
+ minimumBitrate = l2i(IsoTypeReader.readUInt32(byteBuffer));
+ discardPriority = (short) IsoTypeReader.readUInt8(byteBuffer);
+ }
+
+ @Override
+ public ByteBuffer get() {
+ ByteBuffer buf = ByteBuffer.allocate(operationPointCut == 1?13:(operationPointCut * 6 + 11 ));
+ buf.putShort(operationPointCut);
+ if (operationPointCut == 1) {
+ buf.putShort(targetRateShare );
+ } else {
+ for (Entry entry : entries) {
+ buf.putInt(entry.getAvailableBitrate());
+ buf.putShort(entry.getTargetRateShare());
+ }
+ }
+ buf.putInt(maximumBitrate);
+ buf.putInt(minimumBitrate);
+ IsoTypeWriter.writeUInt8(buf, discardPriority);
+ buf.rewind();
+ return buf;
+ }
+
+ public static class Entry {
+ public Entry(int availableBitrate, short targetRateShare) {
+ this.availableBitrate = availableBitrate;
+ this.targetRateShare = targetRateShare;
+ }
+
+ int availableBitrate;
+ short targetRateShare;
+
+ @Override
+ public String toString() {
+ return "{" +
+ "availableBitrate=" + availableBitrate +
+ ", targetRateShare=" + targetRateShare +
+ '}';
+ }
+
+ public int getAvailableBitrate() {
+ return availableBitrate;
+ }
+
+ public void setAvailableBitrate(int availableBitrate) {
+ this.availableBitrate = availableBitrate;
+ }
+
+ public short getTargetRateShare() {
+ return targetRateShare;
+ }
+
+ public void setTargetRateShare(short targetRateShare) {
+ this.targetRateShare = targetRateShare;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+
+ Entry entry = (Entry) o;
+
+ if (availableBitrate != entry.availableBitrate) {
+ return false;
+ }
+ if (targetRateShare != entry.targetRateShare) {
+ return false;
+ }
+
+ return true;
+ }
+
+ @Override
+ public int hashCode() {
+ int result = availableBitrate;
+ result = 31 * result + (int) targetRateShare;
+ return result;
+ }
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+
+ RateShareEntry that = (RateShareEntry) o;
+
+ if (discardPriority != that.discardPriority) {
+ return false;
+ }
+ if (maximumBitrate != that.maximumBitrate) {
+ return false;
+ }
+ if (minimumBitrate != that.minimumBitrate) {
+ return false;
+ }
+ if (operationPointCut != that.operationPointCut) {
+ return false;
+ }
+ if (targetRateShare != that.targetRateShare) {
+ return false;
+ }
+ if (entries != null ? !entries.equals(that.entries) : that.entries != null) {
+ return false;
+ }
+
+ return true;
+ }
+
+ @Override
+ public int hashCode() {
+ int result = (int) operationPointCut;
+ result = 31 * result + (int) targetRateShare;
+ result = 31 * result + (entries != null ? entries.hashCode() : 0);
+ result = 31 * result + maximumBitrate;
+ result = 31 * result + minimumBitrate;
+ result = 31 * result + (int) discardPriority;
+ return result;
+ }
+
+ public short getOperationPointCut() {
+ return operationPointCut;
+ }
+
+ public void setOperationPointCut(short operationPointCut) {
+ this.operationPointCut = operationPointCut;
+ }
+
+ public short getTargetRateShare() {
+ return targetRateShare;
+ }
+
+ public void setTargetRateShare(short targetRateShare) {
+ this.targetRateShare = targetRateShare;
+ }
+
+ public List<Entry> getEntries() {
+ return entries;
+ }
+
+ public void setEntries(List<Entry> entries) {
+ this.entries = entries;
+ }
+
+ public int getMaximumBitrate() {
+ return maximumBitrate;
+ }
+
+ public void setMaximumBitrate(int maximumBitrate) {
+ this.maximumBitrate = maximumBitrate;
+ }
+
+ public int getMinimumBitrate() {
+ return minimumBitrate;
+ }
+
+ public void setMinimumBitrate(int minimumBitrate) {
+ this.minimumBitrate = minimumBitrate;
+ }
+
+ public short getDiscardPriority() {
+ return discardPriority;
+ }
+
+ public void setDiscardPriority(short discardPriority) {
+ this.discardPriority = discardPriority;
+ }
+}
diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/boxes/mp4/samplegrouping/RollRecoveryEntry.java b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/mp4/samplegrouping/RollRecoveryEntry.java
new file mode 100644
index 0000000..bd5b89e
--- /dev/null
+++ b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/mp4/samplegrouping/RollRecoveryEntry.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright 2012 castLabs, 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.googlecode.mp4parser.boxes.mp4.samplegrouping;
+
+import java.nio.ByteBuffer;
+
+/**
+ * roll_distance is a signed integer that gives the number of samples that must be decoded in order for
+ * a sample to be decoded correctly. A positive value indicates the number of samples after the sample
+ * that is a group member that must be decoded such that at the last of these recovery is complete, i.e.
+ * the last sample is correct. A negative value indicates the number of samples before the sample that is
+ * a group member that must be decoded in order for recovery to be complete at the marked sample.
+ * The value zero must not be used; the sync sample table documents random access points for which
+ * no recovery roll is needed.
+ */
+public class RollRecoveryEntry extends GroupEntry {
+ public static final String TYPE = "roll";
+ private short rollDistance;
+
+ public short getRollDistance() {
+ return rollDistance;
+ }
+
+ public void setRollDistance(short rollDistance) {
+ this.rollDistance = rollDistance;
+ }
+
+ @Override
+ public void parse(ByteBuffer byteBuffer) {
+ rollDistance = byteBuffer.getShort();
+ }
+
+ @Override
+ public ByteBuffer get() {
+ ByteBuffer content = ByteBuffer.allocate(2);
+ content.putShort(rollDistance);
+ content.rewind();
+ return content;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+
+ RollRecoveryEntry entry = (RollRecoveryEntry) o;
+
+ if (rollDistance != entry.rollDistance) {
+ return false;
+ }
+
+ return true;
+ }
+
+ @Override
+ public int hashCode() {
+ return (int) rollDistance;
+ }
+}
diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/boxes/mp4/samplegrouping/SampleGroupDescriptionBox.java b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/mp4/samplegrouping/SampleGroupDescriptionBox.java
new file mode 100644
index 0000000..df4a96f
--- /dev/null
+++ b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/mp4/samplegrouping/SampleGroupDescriptionBox.java
@@ -0,0 +1,200 @@
+/*
+ * Copyright 2012 castLabs, 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.googlecode.mp4parser.boxes.mp4.samplegrouping;
+
+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;
+
+/**
+ * This description table gives information about the characteristics of sample groups. The descriptive
+ * information is any other information needed to define or characterize the sample group.
+ * <p/>
+ * There may be multiple instances of this box if there is more than one sample grouping for the samples in a
+ * track. Each instance of the SampleGroupDescription box has a type code that distinguishes different
+ * sample groupings. Within a track, there shall be at most one instance of this box with a particular grouping
+ * type. The associated SampleToGroup shall indicate the same value for the grouping type.
+ * <p/>
+ * The information is stored in the sample group description box after the entry-count. An abstract entry type is
+ * defined and sample groupings shall define derived types to represent the description of each sample group.
+ * For video tracks, an abstract VisualSampleGroupEntry is used with similar types for audio and hint tracks.
+ */
+public class SampleGroupDescriptionBox extends AbstractFullBox {
+ public static final String TYPE = "sgpd";
+
+ private String groupingType;
+ private int defaultLength;
+ private List<GroupEntry> groupEntries = new LinkedList<GroupEntry>();
+ private int descriptionLength;
+
+ public SampleGroupDescriptionBox() {
+ super(TYPE);
+ }
+
+ @Override
+ protected long getContentSize() {
+ long size = 8;
+ if (getVersion() == 1) {
+ size += 4;
+ }
+ size += 4; // entryCount
+ for (GroupEntry groupEntry : groupEntries) {
+ if (getVersion() == 1 && defaultLength == 0) {
+ size += 4;
+ }
+ size += groupEntry.size();
+ }
+ return size;
+ }
+
+ @Override
+ protected void getContent(ByteBuffer byteBuffer) {
+ writeVersionAndFlags(byteBuffer);
+ byteBuffer.put(groupingType.getBytes());
+ if (this.getVersion() == 1) {
+ IsoTypeWriter.writeUInt32(byteBuffer, defaultLength);
+ }
+ IsoTypeWriter.writeUInt32(byteBuffer, this.groupEntries.size());
+ for (GroupEntry entry : groupEntries) {
+ if (this.getVersion() == 1 && defaultLength == 0) {
+ IsoTypeWriter.writeUInt32(byteBuffer, entry.get().limit());
+ }
+ byteBuffer.put(entry.get());
+ }
+ }
+
+ @Override
+ protected void _parseDetails(ByteBuffer content) {
+ parseVersionAndFlags(content);
+ if (this.getVersion() != 1) {
+ throw new RuntimeException("SampleGroupDescriptionBox are only supported in version 1");
+ }
+ groupingType = IsoTypeReader.read4cc(content);
+ if (this.getVersion() == 1) {
+ defaultLength = l2i(IsoTypeReader.readUInt32(content));
+ }
+ long entryCount = IsoTypeReader.readUInt32(content);
+ while (entryCount-- > 0) {
+ int length = defaultLength;
+ if (this.getVersion() == 1) {
+ if (defaultLength == 0) {
+ descriptionLength = l2i(IsoTypeReader.readUInt32(content));
+ length = descriptionLength;
+ }
+ } else {
+ throw new RuntimeException("This should be implemented");
+ }
+ int finalPos = content.position() + length;
+ ByteBuffer parseMe = content.slice();
+ parseMe.limit(length);
+ groupEntries.add(parseGroupEntry(parseMe, groupingType));
+ content.position(finalPos);
+ }
+
+ }
+
+ private GroupEntry parseGroupEntry(ByteBuffer content, String groupingType) {
+ GroupEntry groupEntry;
+ if (RollRecoveryEntry.TYPE.equals(groupingType)) {
+ groupEntry = new RollRecoveryEntry();
+ } else if (RateShareEntry.TYPE.equals(groupingType)) {
+ groupEntry = new RateShareEntry();
+ } else if (CencSampleEncryptionInformationGroupEntry.TYPE.equals(groupingType)) {
+ groupEntry = new CencSampleEncryptionInformationGroupEntry();
+ } else if (VisualRandomAccessEntry.TYPE.equals(groupingType)) {
+ groupEntry = new VisualRandomAccessEntry();
+ } else if (TemporalLevelEntry.TYPE.equals(groupingType)) {
+ groupEntry = new TemporalLevelEntry();
+ } else {
+ groupEntry = new UnknownEntry();
+ }
+ groupEntry.parse(content);
+ return groupEntry;
+ }
+
+
+ public String getGroupingType() {
+ return groupingType;
+ }
+
+ public void setGroupingType(String groupingType) {
+ this.groupingType = groupingType;
+ }
+
+ public int getDefaultLength() {
+ return defaultLength;
+ }
+
+ public void setDefaultLength(int defaultLength) {
+ this.defaultLength = defaultLength;
+ }
+
+ public List<GroupEntry> getGroupEntries() {
+ return groupEntries;
+ }
+
+ public void setGroupEntries(List<GroupEntry> groupEntries) {
+ this.groupEntries = groupEntries;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+
+ SampleGroupDescriptionBox that = (SampleGroupDescriptionBox) o;
+
+ if (defaultLength != that.defaultLength) {
+ return false;
+ }
+ if (groupEntries != null ? !groupEntries.equals(that.groupEntries) : that.groupEntries != null) {
+ return false;
+ }
+ if (groupingType != null ? !groupingType.equals(that.groupingType) : that.groupingType != null) {
+ return false;
+ }
+
+ return true;
+ }
+
+ @Override
+ public int hashCode() {
+ int result = groupingType != null ? groupingType.hashCode() : 0;
+ result = 31 * result + defaultLength;
+ result = 31 * result + (groupEntries != null ? groupEntries.hashCode() : 0);
+ return result;
+ }
+
+ @Override
+ public String toString() {
+ return "SampleGroupDescriptionBox{" +
+ "groupingType='" + groupingType + '\'' +
+ ", defaultLength=" + defaultLength +
+ ", groupEntries=" + groupEntries +
+ '}';
+ }
+}
diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/boxes/mp4/samplegrouping/SampleToGroupBox.java b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/mp4/samplegrouping/SampleToGroupBox.java
new file mode 100644
index 0000000..0fa059e
--- /dev/null
+++ b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/mp4/samplegrouping/SampleToGroupBox.java
@@ -0,0 +1,174 @@
+/*
+ * Copyright 2012 castLabs, 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.googlecode.mp4parser.boxes.mp4.samplegrouping;
+
+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;
+
+/**
+ * This table can be used to find the group that a sample belongs to and the associated description of that
+ * sample group. The table is compactly coded with each entry giving the index of the first sample of a run of
+ * samples with the same sample group descriptor. The sample group description ID is an index that refers to a
+ * SampleGroupDescription box, which contains entries describing the characteristics of each sample group.
+ * <p/>
+ * There may be multiple instances of this box if there is more than one sample grouping for the samples in a
+ * track. Each instance of the SampleToGroup box has a type code that distinguishes different sample
+ * groupings. Within a track, there shall be at most one instance of this box with a particular grouping type. The
+ * associated SampleGroupDescription shall indicate the same value for the grouping type.
+ * <p/>
+ * Version 1 of this box should only be used if a grouping type parameter is needed.
+ */
+public class SampleToGroupBox extends AbstractFullBox {
+ public static final String TYPE = "sbgp";
+
+
+ private String groupingType;
+ private String groupingTypeParameter;
+
+ List<Entry> entries = new LinkedList<Entry>();
+
+ public SampleToGroupBox() {
+ super(TYPE);
+
+ }
+
+ @Override
+ protected long getContentSize() {
+ return this.getVersion() == 1 ? entries.size() * 8 + 16 : entries.size() * 8 + 12;
+ }
+
+ @Override
+ protected void getContent(ByteBuffer byteBuffer) {
+ writeVersionAndFlags(byteBuffer);
+ byteBuffer.put(groupingType.getBytes());
+ if (this.getVersion() == 1) {
+ byteBuffer.put(groupingTypeParameter.getBytes());
+ }
+ IsoTypeWriter.writeUInt32(byteBuffer, entries.size());
+ for (Entry entry : entries) {
+ IsoTypeWriter.writeUInt32(byteBuffer, entry.getSampleCount());
+ IsoTypeWriter.writeUInt32(byteBuffer, entry.getGroupDescriptionIndex());
+ }
+
+ }
+
+ @Override
+ protected void _parseDetails(ByteBuffer content) {
+ parseVersionAndFlags(content);
+ groupingType = IsoTypeReader.read4cc(content);
+ if (this.getVersion() == 1) {
+ groupingTypeParameter = IsoTypeReader.read4cc(content);
+ }
+ long entryCount = IsoTypeReader.readUInt32(content);
+ while (entryCount-- > 0) {
+ entries.add(new Entry(l2i(IsoTypeReader.readUInt32(content)), l2i(IsoTypeReader.readUInt32(content))));
+ }
+ }
+
+ public static class Entry {
+ private long sampleCount;
+ private int groupDescriptionIndex;
+
+ public Entry(long sampleCount, int groupDescriptionIndex) {
+ this.sampleCount = sampleCount;
+ this.groupDescriptionIndex = groupDescriptionIndex;
+ }
+
+ public long getSampleCount() {
+ return sampleCount;
+ }
+
+ public void setSampleCount(long sampleCount) {
+ this.sampleCount = sampleCount;
+ }
+
+ public int getGroupDescriptionIndex() {
+ return groupDescriptionIndex;
+ }
+
+ public void setGroupDescriptionIndex(int groupDescriptionIndex) {
+ this.groupDescriptionIndex = groupDescriptionIndex;
+ }
+
+ @Override
+ public String toString() {
+ return "Entry{" +
+ "sampleCount=" + sampleCount +
+ ", groupDescriptionIndex=" + groupDescriptionIndex +
+ '}';
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+
+ Entry entry = (Entry) o;
+
+ if (groupDescriptionIndex != entry.groupDescriptionIndex) {
+ return false;
+ }
+ if (sampleCount != entry.sampleCount) {
+ return false;
+ }
+
+ return true;
+ }
+
+ @Override
+ public int hashCode() {
+ int result = (int) (sampleCount ^ (sampleCount >>> 32));
+ result = 31 * result + groupDescriptionIndex;
+ return result;
+ }
+ }
+
+ public String getGroupingType() {
+ return groupingType;
+ }
+
+ public void setGroupingType(String groupingType) {
+ this.groupingType = groupingType;
+ }
+
+ public String getGroupingTypeParameter() {
+ return groupingTypeParameter;
+ }
+
+ public void setGroupingTypeParameter(String groupingTypeParameter) {
+ this.groupingTypeParameter = groupingTypeParameter;
+ }
+
+ public List<Entry> getEntries() {
+ return entries;
+ }
+
+ public void setEntries(List<Entry> entries) {
+ this.entries = entries;
+ }
+}
diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/boxes/mp4/samplegrouping/TemporalLevelEntry.java b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/mp4/samplegrouping/TemporalLevelEntry.java
new file mode 100644
index 0000000..798fd9c
--- /dev/null
+++ b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/mp4/samplegrouping/TemporalLevelEntry.java
@@ -0,0 +1,82 @@
+/*
+ * Copyright 2012 castLabs, 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.googlecode.mp4parser.boxes.mp4.samplegrouping;
+
+import java.nio.ByteBuffer;
+
+/**
+ * The Temporal Level sample grouping ('tele') provides a codec-independent sample grouping that can be used to group samples (access units) in a track (and potential track fragments) according to temporal level, where samples of one temporal level have no coding dependencies on samples of higher temporal levels. The temporal level equals the sample group description index (taking values 1, 2, 3, etc). The bitstream containing only the access units from the first temporal level to a higher temporal level remains conforming to the coding standard.
+ *
+ * A grouping according to temporal level facilitates easy extraction of temporal subsequences, for instance using the Subsegment Indexing box in 0.
+ *
+ */
+public class TemporalLevelEntry extends GroupEntry {
+ public static final String TYPE = "tele";
+ private boolean levelIndependentlyDecodable;
+ private short reserved;
+
+ public boolean isLevelIndependentlyDecodable() {
+ return levelIndependentlyDecodable;
+ }
+
+ public void setLevelIndependentlyDecodable(boolean levelIndependentlyDecodable) {
+ this.levelIndependentlyDecodable = levelIndependentlyDecodable;
+ }
+
+ @Override
+ public void parse(ByteBuffer byteBuffer) {
+ final byte b = byteBuffer.get();
+ levelIndependentlyDecodable = ((b & 0x80) == 0x80);
+ }
+
+ @Override
+ public ByteBuffer get() {
+ ByteBuffer content = ByteBuffer.allocate(1);
+ content.put((byte) (levelIndependentlyDecodable ? 0x80 : 0x00));
+ content.rewind();
+ return content;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+
+ TemporalLevelEntry that = (TemporalLevelEntry) o;
+
+ if (levelIndependentlyDecodable != that.levelIndependentlyDecodable) return false;
+ if (reserved != that.reserved) return false;
+
+ return true;
+ }
+
+ @Override
+ public int hashCode() {
+ int result = (levelIndependentlyDecodable ? 1 : 0);
+ result = 31 * result + (int) reserved;
+ return result;
+ }
+
+ @Override
+ public String toString() {
+ final StringBuilder sb = new StringBuilder();
+ sb.append("TemporalLevelEntry");
+ sb.append("{levelIndependentlyDecodable=").append(levelIndependentlyDecodable);
+ sb.append('}');
+ return sb.toString();
+ }
+}
diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/boxes/mp4/samplegrouping/UnknownEntry.java b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/mp4/samplegrouping/UnknownEntry.java
new file mode 100644
index 0000000..9efcbea
--- /dev/null
+++ b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/mp4/samplegrouping/UnknownEntry.java
@@ -0,0 +1,83 @@
+/*
+ * Copyright 2012 castLabs, 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.googlecode.mp4parser.boxes.mp4.samplegrouping;
+
+import com.coremedia.iso.Hex;
+
+import java.nio.ByteBuffer;
+
+/**
+ *
+ */
+public class UnknownEntry extends GroupEntry {
+ private ByteBuffer content;
+
+ public UnknownEntry() {
+ }
+
+ public ByteBuffer getContent() {
+ return content;
+ }
+
+ public void setContent(ByteBuffer content) {
+ this.content = (ByteBuffer) content.duplicate().rewind();
+ }
+
+ @Override
+ public void parse(ByteBuffer byteBuffer) {
+ this.content = (ByteBuffer) byteBuffer.duplicate().rewind();
+ }
+
+ @Override
+ public ByteBuffer get() {
+ return content.duplicate();
+ }
+
+ @Override
+ public String toString() {
+ ByteBuffer bb = content.duplicate();
+ bb.rewind();
+ byte[] b = new byte[bb.limit()];
+ bb.get(b);
+ return "UnknownEntry{" +
+ "content=" + Hex.encodeHex(b) +
+ '}';
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+
+ UnknownEntry that = (UnknownEntry) o;
+
+ if (content != null ? !content.equals(that.content) : that.content != null) {
+ return false;
+ }
+
+ return true;
+ }
+
+ @Override
+ public int hashCode() {
+ return content != null ? content.hashCode() : 0;
+ }
+}
diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/boxes/mp4/samplegrouping/VisualRandomAccessEntry.java b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/mp4/samplegrouping/VisualRandomAccessEntry.java
new file mode 100644
index 0000000..ed5d199
--- /dev/null
+++ b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/mp4/samplegrouping/VisualRandomAccessEntry.java
@@ -0,0 +1,94 @@
+/*
+ * Copyright 2012 castLabs, 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.googlecode.mp4parser.boxes.mp4.samplegrouping;
+
+import com.coremedia.iso.IsoTypeReader;
+
+import java.nio.ByteBuffer;
+
+/**
+ * For some coding systems a sync sample is specified to be a random access point after which all samples in decoding order can be correctly decoded. However, it may be possible to encode an “open” random access point, after which all samples in output order can be correctly decoded, but some samples following the random access point in decoding order and preceding the random access point in output order need not be correctly decodable. For example, an intra picture starting an open group of pictures can be followed in decoding order by (bi-)predicted pictures that however precede the intra picture in output order; though they possibly cannot be correctly decoded if the decoding starts from the intra picture, they are not needed.
+ *
+ * Such “open” random-access samples can be marked by being a member of this group. Samples marked by this group must be random access points, and may also be sync points (i.e. it is not required that samples marked by the sync sample table be excluded).
+ *
+ */
+public class VisualRandomAccessEntry extends GroupEntry {
+ public static final String TYPE = "rap ";
+ private boolean numLeadingSamplesKnown;
+ private short numLeadingSamples;
+
+ public boolean isNumLeadingSamplesKnown() {
+ return numLeadingSamplesKnown;
+ }
+
+ public void setNumLeadingSamplesKnown(boolean numLeadingSamplesKnown) {
+ this.numLeadingSamplesKnown = numLeadingSamplesKnown;
+ }
+
+ public short getNumLeadingSamples() {
+ return numLeadingSamples;
+ }
+
+ public void setNumLeadingSamples(short numLeadingSamples) {
+ this.numLeadingSamples = numLeadingSamples;
+ }
+
+ @Override
+ public void parse(ByteBuffer byteBuffer) {
+ final byte b = byteBuffer.get();
+ numLeadingSamplesKnown = ((b & 0x80) == 0x80);
+ numLeadingSamples = (short) (b & 0x7f);
+ }
+
+ @Override
+ public ByteBuffer get() {
+ ByteBuffer content = ByteBuffer.allocate(1);
+ content.put((byte) ((numLeadingSamplesKnown? 0x80 : 0x00)| (numLeadingSamples & 0x7f)));
+ content.rewind();
+ return content;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+
+ VisualRandomAccessEntry that = (VisualRandomAccessEntry) o;
+
+ if (numLeadingSamples != that.numLeadingSamples) return false;
+ if (numLeadingSamplesKnown != that.numLeadingSamplesKnown) return false;
+
+ return true;
+ }
+
+ @Override
+ public int hashCode() {
+ int result = (numLeadingSamplesKnown ? 1 : 0);
+ result = 31 * result + (int) numLeadingSamples;
+ return result;
+ }
+
+ @Override
+ public String toString() {
+ final StringBuilder sb = new StringBuilder();
+ sb.append("VisualRandomAccessEntry");
+ sb.append("{numLeadingSamplesKnown=").append(numLeadingSamplesKnown);
+ sb.append(", numLeadingSamples=").append(numLeadingSamples);
+ sb.append('}');
+ return sb.toString();
+ }
+}