Initial drop the compilable version of mp4parser, with least modification

bug:7093055

Change-Id: Id9b1b4ec91e26ae6e9fd75d86696aa30f30897b3
diff --git a/Android.mk b/Android.mk
new file mode 100644
index 0000000..6c6a6e9
--- /dev/null
+++ b/Android.mk
@@ -0,0 +1,26 @@
+# Copyright (C) 2012 The Android Open Source Project
+#
+# 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.
+
+LOCAL_PATH := $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := mp4parser
+LOCAL_SDK_VERSION := 9
+LOCAL_SRC_FILES := $(call all-java-files-under, isoparser/src/main/java)
+
+include $(BUILD_STATIC_JAVA_LIBRARY)
+
+# Include this library in the build server's output directory
+$(call dist-for-goals, dist_files, $(LOCAL_BUILT_MODULE):mp4parser.jar)
+
diff --git a/NOTICE b/NOTICE
new file mode 100644
index 0000000..a766aa1
--- /dev/null
+++ b/NOTICE
@@ -0,0 +1,29 @@
+   =========================================================================

+   ==  NOTICE file corresponding to the section 4 d of                    ==

+   ==  the Apache License, Version 2.0,                                   ==

+   ==  in this case for the Apache Maven distribution.                    ==

+   =========================================================================

+

+This product includes software developed by

+CoreMedia AG (http://www.coremedia.com/).

+

+This product includes software developed by

+castLabs GmbH (http://www.castlabs.com/).

+

+This product includes software developed by

+Sebastian Annies (Sebastian.Annies@gmail.com)

+

+This product includes software (Base64 Encoder extracted from commons-codec) developed by

+The Apache Software Foundation (http://www.apache.org/).

+

+This product includes software (Hex Encoder extracted from commons-codec) developed by

+The Apache Software Foundation (http://www.apache.org/).

+

+This product includes software (package com.googlecode.mp4parser.h264) developed by

+Stanislav Vitvitskiy and originally licensed under MIT license (http://www.opensource.org/licenses/mit-license.php)

+

+

+

+

+

+

diff --git a/README.android b/README.android
new file mode 100644
index 0000000..812bd9b
--- /dev/null
+++ b/README.android
@@ -0,0 +1,14 @@
+URL: http://code.google.com/p/mp4parser/source/checkout
+Version: 1.0-RC-16
+License: Apache 2
+Description: "Provides a Java API for parsing MP4 files"
+
+Local Modifications:
+    Only taking the isoparser/src/main/ part, remove others.
+    Remove the RequiresParseDetailAspect.java file since we don't have the aspectJ yet.
+
+Originally written by Sebastian Annies, this isoparser API can read and write
+the MP4 file structure. It is a low level tool dealing with the so called boxes
+but it is as well as dealing with structure like tracks and movies.
+
+This code is built as a static library.
diff --git a/isoparser/.svn/all-wcprops b/isoparser/.svn/all-wcprops
new file mode 100644
index 0000000..2bfa0c8
--- /dev/null
+++ b/isoparser/.svn/all-wcprops
@@ -0,0 +1,11 @@
+K 25
+svn:wc:ra_dav:version-url
+V 33
+/svn/!svn/ver/777/trunk/isoparser
+END
+pom.xml
+K 25
+svn:wc:ra_dav:version-url
+V 41
+/svn/!svn/ver/769/trunk/isoparser/pom.xml
+END
diff --git a/isoparser/.svn/entries b/isoparser/.svn/entries
new file mode 100644
index 0000000..05cf69e
--- /dev/null
+++ b/isoparser/.svn/entries
@@ -0,0 +1,65 @@
+10
+
+dir
+778
+http://mp4parser.googlecode.com/svn/trunk/isoparser
+http://mp4parser.googlecode.com/svn
+
+
+
+2012-09-10T14:56:10.036617Z
+777
+sebastian.annies@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+7decde4b-c250-0410-a0da-51896bc88be6
+
+src
+dir
+
+pom.xml
+file
+
+
+
+
+2012-09-14T17:27:53.197257Z
+8306066f873fcc4800174913b5da7a38
+2012-08-30T16:19:35.300438Z
+769
+sebastian.annies@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+10194
+
diff --git a/isoparser/.svn/text-base/pom.xml.svn-base b/isoparser/.svn/text-base/pom.xml.svn-base
new file mode 100644
index 0000000..a1920d2
--- /dev/null
+++ b/isoparser/.svn/text-base/pom.xml.svn-base
@@ -0,0 +1,283 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+    <groupId>com.googlecode.mp4parser</groupId>
+    <artifactId>isoparser</artifactId>
+    <packaging>jar</packaging>
+    <name>ISO Parser</name>
+    <description>A generic parser and writer for all ISO 14496 based files (MP4, Quicktime, DCF, PDCF, ...)
+    </description>
+    <url>http://code.google.com/p/mp4parser/</url>
+    <version>1.0-RC-16-SNAPSHOT</version>
+
+    <properties>
+        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+    </properties>
+
+    <build>
+        <resources>
+            <resource>
+                <directory>src/main/resources</directory>
+                <filtering>true</filtering>
+            </resource>
+        </resources>
+        <defaultGoal>install</defaultGoal>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-site-plugin</artifactId>
+                <version>3.0</version>
+                <configuration>
+                    <reportPlugins>
+                        <plugin>
+                            <groupId>org.apache.maven.plugins</groupId>
+                            <artifactId>maven-jxr-plugin</artifactId>
+                            <version>2.3</version>
+                            <reportSets>
+                                <reportSet>
+                                    <id>html</id>
+                                    <reports>
+                                        <report>jxr</report>
+                                    </reports>
+                                </reportSet>
+                            </reportSets>
+                        </plugin>
+                        <plugin>
+                            <groupId>org.apache.maven.plugins</groupId>
+                            <artifactId>maven-javadoc-plugin</artifactId>
+                            <version>2.8.1</version>
+                            <reportSets>
+                                <reportSet>
+                                    <id>html</id>
+                                    <reports>
+                                        <report>javadoc</report>
+                                    </reports>
+                                </reportSet>
+                            </reportSets>
+                        </plugin>
+                    </reportPlugins>
+                </configuration>
+            </plugin>
+            <plugin>
+                <groupId>org.codehaus.mojo</groupId>
+                <artifactId>aspectj-maven-plugin</artifactId>
+                <version>1.4</version>
+                <executions>
+                    <execution>
+                        <goals>
+                            <goal>compile</goal>
+                        </goals>
+                    </execution>
+                </executions>
+                <dependencies>
+
+                    <dependency>
+                        <groupId>org.aspectj</groupId>
+                        <artifactId>aspectjtools</artifactId>
+                        <version>1.7.0</version>
+                    </dependency>
+
+                </dependencies>
+                <configuration>
+                    <source>1.5</source>
+                </configuration>
+            </plugin>
+
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-resources-plugin</artifactId>
+                <version>2.5</version>
+            </plugin>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-compiler-plugin</artifactId>
+                <version>2.3.2</version>
+                <configuration>
+                    <source>1.5</source>
+                    <target>1.5</target>
+                </configuration>
+            </plugin>
+            <plugin>
+                <inherited>true</inherited>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-source-plugin</artifactId>
+                <version>2.1.2</version>
+                <executions>
+                    <execution>
+                        <id>attach-sources</id>
+                        <phase>verify</phase>
+                        <goals>
+                            <goal>jar</goal>
+                        </goals>
+                    </execution>
+                </executions>
+            </plugin>
+        </plugins>
+        <extensions>
+            <extension>
+                <groupId>com.google.code.maven-svn-wagon</groupId>
+                <artifactId>maven-svn-wagon</artifactId>
+                <version>1.4</version>
+            </extension>
+        </extensions>
+
+    </build>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.aspectj</groupId>
+            <artifactId>aspectjrt</artifactId>
+            <version>1.7.0</version>
+        </dependency>
+        <dependency>
+            <groupId>junit</groupId>
+            <artifactId>junit</artifactId>
+            <version>4.10</version>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>commons-io</groupId>
+            <artifactId>commons-io</artifactId>
+            <version>2.1</version>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>commons-codec</groupId>
+            <artifactId>commons-codec</artifactId>
+            <version>1.5</version>
+            <scope>test</scope>
+        </dependency>
+    </dependencies>
+
+    <profiles>
+        <profile>
+            <id>release-sign-artifacts</id>
+            <activation>
+                <property>
+                    <name>performRelease</name>
+                    <value>true</value>
+                </property>
+            </activation>
+            <build>
+
+                <plugins>
+
+                    <plugin>
+                        <groupId>org.apache.maven.plugins</groupId>
+                        <artifactId>maven-source-plugin</artifactId>
+                        <version>2.1.2</version>
+                        <executions>
+                            <execution>
+                                <id>attach-sources</id>
+                                <goals>
+                                    <goal>jar-no-fork</goal>
+                                </goals>
+                            </execution>
+                        </executions>
+                    </plugin>
+                    <plugin>
+                        <groupId>org.apache.maven.plugins</groupId>
+                        <artifactId>maven-gpg-plugin</artifactId>
+                        <executions>
+                            <execution>
+                                <id>sign-artifacts</id>
+                                <phase>verify</phase>
+                                <goals>
+                                    <goal>sign</goal>
+                                </goals>
+                            </execution>
+                        </executions>
+                    </plugin>
+                </plugins>
+            </build>
+        </profile>
+    </profiles>
+
+    <reporting>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-jxr-plugin</artifactId>
+                <version>2.3</version>
+                <reportSets>
+                    <reportSet>
+                        <id>html</id>
+                        <reports>
+                            <report>jxr</report>
+                        </reports>
+                    </reportSet>
+                </reportSets>
+
+            </plugin>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-javadoc-plugin</artifactId>
+                <version>2.8.1</version>
+                <reportSets>
+                    <reportSet>
+                        <id>html</id>
+                        <reports>
+                            <report>javadoc</report>
+                        </reports>
+                    </reportSet>
+                </reportSets>
+
+            </plugin>
+        </plugins>
+    </reporting>
+
+    <scm>
+        <url>http://code.google.com/p/mp4parser/source/browse/</url>
+        <connection>scm:svn:https://mp4parser.googlecode.com/svn/trunk/isoparser</connection>
+    </scm>
+
+    <ciManagement>
+        <system>jenkins</system>
+        <url>https://sannies.ci.cloudbees.com/job/IsoParser/</url>
+    </ciManagement>
+
+    <mailingLists>
+        <mailingList>
+            <name>mp4parser-discussion</name>
+            <post>https://groups.google.com/forum/?fromgroups#!forum/mp4parser-discussion</post>
+        </mailingList>
+    </mailingLists>
+
+    <issueManagement>
+        <system>google-code</system>
+        <url>http://code.google.com/p/mp4parser/issues/list</url>
+    </issueManagement>
+
+    <developers>
+        <developer>
+            <id>sannies</id>
+            <email>Sebastian.Annies@googlemail.com</email>
+        </developer>
+    </developers>
+
+    <distributionManagement>
+        <snapshotRepository>
+            <id>sonatype-nexus-snapshots</id>
+            <name>Sonatype Nexus Snapshots</name>
+            <url>http://oss.sonatype.org/content/repositories/snapshots</url>
+        </snapshotRepository>
+        <repository>
+            <id>sonatype-nexus-staging</id>
+            <name>Nexus Release Repository</name>
+            <url>http://oss.sonatype.org/service/local/staging/deploy/maven2/</url>
+        </repository>
+        <site>
+            <id>mp4parser-svn</id>
+            <name>MP4Parser SVN repository</name>
+            <url>svn:https://mp4parser.googlecode.com/svn/site/${project.version}</url>
+        </site>
+    </distributionManagement>
+
+    <licenses>
+        <license>
+            <name>Apache 2</name>
+            <url>http://www.apache.org/licenses/LICENSE-2.0.txt</url>
+            <distribution>repo</distribution>
+            <comments>A business-friendly OSS license</comments>
+        </license>
+    </licenses>
+</project>
diff --git a/isoparser/src/.svn/all-wcprops b/isoparser/src/.svn/all-wcprops
new file mode 100644
index 0000000..1dfb026
--- /dev/null
+++ b/isoparser/src/.svn/all-wcprops
@@ -0,0 +1,5 @@
+K 25
+svn:wc:ra_dav:version-url
+V 37
+/svn/!svn/ver/777/trunk/isoparser/src
+END
diff --git a/isoparser/src/.svn/entries b/isoparser/src/.svn/entries
new file mode 100644
index 0000000..6d491e3
--- /dev/null
+++ b/isoparser/src/.svn/entries
@@ -0,0 +1,37 @@
+10
+
+dir
+778
+http://mp4parser.googlecode.com/svn/trunk/isoparser/src
+http://mp4parser.googlecode.com/svn
+
+
+
+2012-09-10T14:56:10.036617Z
+777
+sebastian.annies@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+7decde4b-c250-0410-a0da-51896bc88be6
+
+test
+dir
+
+main
+dir
+
+etc
+dir
+
diff --git a/isoparser/src/main/.svn/all-wcprops b/isoparser/src/main/.svn/all-wcprops
new file mode 100644
index 0000000..2245283
--- /dev/null
+++ b/isoparser/src/main/.svn/all-wcprops
@@ -0,0 +1,5 @@
+K 25
+svn:wc:ra_dav:version-url
+V 42
+/svn/!svn/ver/777/trunk/isoparser/src/main
+END
diff --git a/isoparser/src/main/.svn/entries b/isoparser/src/main/.svn/entries
new file mode 100644
index 0000000..e928a4e
--- /dev/null
+++ b/isoparser/src/main/.svn/entries
@@ -0,0 +1,34 @@
+10
+
+dir
+778
+http://mp4parser.googlecode.com/svn/trunk/isoparser/src/main
+http://mp4parser.googlecode.com/svn
+
+
+
+2012-09-10T14:56:10.036617Z
+777
+sebastian.annies@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+7decde4b-c250-0410-a0da-51896bc88be6
+
+java
+dir
+
+resources
+dir
+
diff --git a/isoparser/src/main/java/.svn/all-wcprops b/isoparser/src/main/java/.svn/all-wcprops
new file mode 100644
index 0000000..3a3281a
--- /dev/null
+++ b/isoparser/src/main/java/.svn/all-wcprops
@@ -0,0 +1,5 @@
+K 25
+svn:wc:ra_dav:version-url
+V 47
+/svn/!svn/ver/777/trunk/isoparser/src/main/java
+END
diff --git a/isoparser/src/main/java/.svn/entries b/isoparser/src/main/java/.svn/entries
new file mode 100644
index 0000000..4727ce8
--- /dev/null
+++ b/isoparser/src/main/java/.svn/entries
@@ -0,0 +1,31 @@
+10
+
+dir
+778
+http://mp4parser.googlecode.com/svn/trunk/isoparser/src/main/java
+http://mp4parser.googlecode.com/svn
+
+
+
+2012-09-10T14:56:10.036617Z
+777
+sebastian.annies@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+7decde4b-c250-0410-a0da-51896bc88be6
+
+com
+dir
+
diff --git a/isoparser/src/main/java/com/.svn/all-wcprops b/isoparser/src/main/java/com/.svn/all-wcprops
new file mode 100644
index 0000000..3f5fd1b
--- /dev/null
+++ b/isoparser/src/main/java/com/.svn/all-wcprops
@@ -0,0 +1,5 @@
+K 25
+svn:wc:ra_dav:version-url
+V 51
+/svn/!svn/ver/777/trunk/isoparser/src/main/java/com
+END
diff --git a/isoparser/src/main/java/com/.svn/entries b/isoparser/src/main/java/com/.svn/entries
new file mode 100644
index 0000000..7097c8c
--- /dev/null
+++ b/isoparser/src/main/java/com/.svn/entries
@@ -0,0 +1,34 @@
+10
+
+dir
+778
+http://mp4parser.googlecode.com/svn/trunk/isoparser/src/main/java/com
+http://mp4parser.googlecode.com/svn
+
+
+
+2012-09-10T14:56:10.036617Z
+777
+sebastian.annies@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+7decde4b-c250-0410-a0da-51896bc88be6
+
+googlecode
+dir
+
+coremedia
+dir
+
diff --git a/isoparser/src/main/java/com/coremedia/.svn/all-wcprops b/isoparser/src/main/java/com/coremedia/.svn/all-wcprops
new file mode 100644
index 0000000..95a5b8f
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/.svn/all-wcprops
@@ -0,0 +1,5 @@
+K 25
+svn:wc:ra_dav:version-url
+V 61
+/svn/!svn/ver/777/trunk/isoparser/src/main/java/com/coremedia
+END
diff --git a/isoparser/src/main/java/com/coremedia/.svn/entries b/isoparser/src/main/java/com/coremedia/.svn/entries
new file mode 100644
index 0000000..08e6e56
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/.svn/entries
@@ -0,0 +1,31 @@
+10
+
+dir
+778
+http://mp4parser.googlecode.com/svn/trunk/isoparser/src/main/java/com/coremedia
+http://mp4parser.googlecode.com/svn
+
+
+
+2012-09-10T14:56:10.036617Z
+777
+sebastian.annies@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+7decde4b-c250-0410-a0da-51896bc88be6
+
+iso
+dir
+
diff --git a/isoparser/src/main/java/com/coremedia/iso/.svn/all-wcprops b/isoparser/src/main/java/com/coremedia/iso/.svn/all-wcprops
new file mode 100644
index 0000000..9b50c5a
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/.svn/all-wcprops
@@ -0,0 +1,77 @@
+K 25
+svn:wc:ra_dav:version-url
+V 65
+/svn/!svn/ver/777/trunk/isoparser/src/main/java/com/coremedia/iso
+END
+IsoTypeReader.java
+K 25
+svn:wc:ra_dav:version-url
+V 84
+/svn/!svn/ver/659/trunk/isoparser/src/main/java/com/coremedia/iso/IsoTypeReader.java
+END
+IsoTypeWriterVariable.java
+K 25
+svn:wc:ra_dav:version-url
+V 92
+/svn/!svn/ver/426/trunk/isoparser/src/main/java/com/coremedia/iso/IsoTypeWriterVariable.java
+END
+Hex.java
+K 25
+svn:wc:ra_dav:version-url
+V 74
+/svn/!svn/ver/619/trunk/isoparser/src/main/java/com/coremedia/iso/Hex.java
+END
+IsoTypeReaderVariable.java
+K 25
+svn:wc:ra_dav:version-url
+V 92
+/svn/!svn/ver/419/trunk/isoparser/src/main/java/com/coremedia/iso/IsoTypeReaderVariable.java
+END
+BoxParser.java
+K 25
+svn:wc:ra_dav:version-url
+V 80
+/svn/!svn/ver/419/trunk/isoparser/src/main/java/com/coremedia/iso/BoxParser.java
+END
+Utf8.java
+K 25
+svn:wc:ra_dav:version-url
+V 75
+/svn/!svn/ver/419/trunk/isoparser/src/main/java/com/coremedia/iso/Utf8.java
+END
+Ascii.java
+K 25
+svn:wc:ra_dav:version-url
+V 76
+/svn/!svn/ver/419/trunk/isoparser/src/main/java/com/coremedia/iso/Ascii.java
+END
+ChannelHelper.java
+K 25
+svn:wc:ra_dav:version-url
+V 84
+/svn/!svn/ver/505/trunk/isoparser/src/main/java/com/coremedia/iso/ChannelHelper.java
+END
+IsoTypeWriter.java
+K 25
+svn:wc:ra_dav:version-url
+V 84
+/svn/!svn/ver/692/trunk/isoparser/src/main/java/com/coremedia/iso/IsoTypeWriter.java
+END
+AbstractBoxParser.java
+K 25
+svn:wc:ra_dav:version-url
+V 88
+/svn/!svn/ver/505/trunk/isoparser/src/main/java/com/coremedia/iso/AbstractBoxParser.java
+END
+IsoFile.java
+K 25
+svn:wc:ra_dav:version-url
+V 78
+/svn/!svn/ver/742/trunk/isoparser/src/main/java/com/coremedia/iso/IsoFile.java
+END
+PropertyBoxParserImpl.java
+K 25
+svn:wc:ra_dav:version-url
+V 92
+/svn/!svn/ver/505/trunk/isoparser/src/main/java/com/coremedia/iso/PropertyBoxParserImpl.java
+END
diff --git a/isoparser/src/main/java/com/coremedia/iso/.svn/entries b/isoparser/src/main/java/com/coremedia/iso/.svn/entries
new file mode 100644
index 0000000..0114cad
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/.svn/entries
@@ -0,0 +1,442 @@
+10
+
+dir
+778
+http://mp4parser.googlecode.com/svn/trunk/isoparser/src/main/java/com/coremedia/iso
+http://mp4parser.googlecode.com/svn
+
+
+
+2012-09-10T14:56:10.036617Z
+777
+sebastian.annies@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+7decde4b-c250-0410-a0da-51896bc88be6
+
+IsoTypeReader.java
+file
+
+
+
+
+2012-09-14T17:27:53.147256Z
+1b3832056109e2538ddb064410e145a3
+2012-06-06T10:36:53.498661Z
+659
+Sebastian.Annies@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+4181
+
+IsoTypeWriterVariable.java
+file
+
+
+
+
+2012-09-14T17:27:53.157256Z
+dc08bcfd952e251e81f54d6876cf2822
+2012-03-12T12:55:40.927472Z
+426
+hoemmagnus@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+1471
+
+boxes
+dir
+
+Hex.java
+file
+
+
+
+
+2012-09-14T17:27:53.157256Z
+834508c38dadb7747ba2a9e611a29f75
+2012-05-20T18:32:15.672660Z
+619
+Sebastian.Annies@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+2026
+
+mdta
+dir
+
+IsoTypeReaderVariable.java
+file
+
+
+
+
+2012-09-14T17:27:53.157256Z
+a2e5fe2ff8d860e485a09fe069b23b67
+2012-03-11T20:58:41.111953Z
+419
+Sebastian.Annies@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+1283
+
+BoxParser.java
+file
+
+
+
+
+2012-09-14T17:27:53.157256Z
+7ffb4de0f5409f6be08384c50ed1f239
+2012-03-11T20:58:41.111953Z
+419
+Sebastian.Annies@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+1089
+
+Utf8.java
+file
+
+
+
+
+2012-09-14T17:27:53.157256Z
+7e580cd68183dc1f3927fb0866b2030b
+2012-03-11T20:58:41.111953Z
+419
+Sebastian.Annies@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+1712
+
+Ascii.java
+file
+
+
+
+
+2012-09-14T17:27:53.157256Z
+30e0990932cfaaf6df4603a5aabbd724
+2012-03-11T20:58:41.111953Z
+419
+Sebastian.Annies@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+1274
+
+ChannelHelper.java
+file
+
+
+
+
+2012-09-14T17:27:53.157256Z
+363efdcb385f027569cf4748273c9533
+2012-04-21T21:18:31.685061Z
+505
+Sebastian.Annies@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+2750
+
+IsoTypeWriter.java
+file
+
+
+
+
+2012-09-14T17:27:53.157256Z
+746a167bf3de7edb454855bed18ec21b
+2012-06-25T03:13:15.796438Z
+692
+michael.stattmann@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+2840
+
+AbstractBoxParser.java
+file
+
+
+
+
+2012-09-14T17:27:53.157256Z
+e5bf90052f2d10b984827de45560b8b8
+2012-04-21T21:18:31.685061Z
+505
+Sebastian.Annies@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+4828
+
+IsoFile.java
+file
+
+
+
+
+2012-09-14T17:27:53.157256Z
+fa74e86d8e2f3f19c2a91319ee286b38
+2012-08-12T09:16:02.229115Z
+742
+Sebastian.Annies@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+5567
+
+PropertyBoxParserImpl.java
+file
+
+
+
+
+2012-09-14T17:27:53.157256Z
+e93996880a8025f186a835bbff195141
+2012-04-21T21:18:31.685061Z
+505
+Sebastian.Annies@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+7247
+
diff --git a/isoparser/src/main/java/com/coremedia/iso/.svn/text-base/AbstractBoxParser.java.svn-base b/isoparser/src/main/java/com/coremedia/iso/.svn/text-base/AbstractBoxParser.java.svn-base
new file mode 100644
index 0000000..6d92acd
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/.svn/text-base/AbstractBoxParser.java.svn-base
@@ -0,0 +1,130 @@
+/*
+ * Copyright 2012 Sebastian Annies, Hamburg
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.coremedia.iso;
+
+import com.coremedia.iso.boxes.Box;
+import com.coremedia.iso.boxes.ContainerBox;
+import com.coremedia.iso.boxes.UserBox;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.nio.channels.FileChannel;
+import java.nio.channels.ReadableByteChannel;
+import java.util.logging.Logger;
+
+import static com.googlecode.mp4parser.util.CastUtils.l2i;
+
+/**
+ * This BoxParser handles the basic stuff like reading size and extracting box type.
+ */
+public abstract class AbstractBoxParser implements BoxParser {
+
+    private static Logger LOG = Logger.getLogger(AbstractBoxParser.class.getName());
+
+    public abstract Box createBox(String type, byte[] userType, String parent);
+
+    /**
+     * Parses the next size and type, creates a box instance and parses the box's content.
+     *
+     * @param byteChannel the FileChannel pointing to the ISO file
+     * @param parent      the current box's parent (null if no parent)
+     * @return the box just parsed
+     * @throws java.io.IOException if reading from <code>in</code> fails
+     */
+    public Box parseBox(ReadableByteChannel byteChannel, ContainerBox parent) throws IOException {
+
+
+        ByteBuffer header = ChannelHelper.readFully(byteChannel, 8);
+
+        long size = IsoTypeReader.readUInt32(header);
+        // do plausibility check
+        if (size < 8 && size > 1) {
+            LOG.severe("Plausibility check failed: size < 8 (size = " + size + "). Stop parsing!");
+            return null;
+        }
+
+
+        String type = IsoTypeReader.read4cc(header);
+        byte[] usertype = null;
+        long contentSize;
+
+        if (size == 1) {
+            ByteBuffer bb = ByteBuffer.allocate(8);
+            byteChannel.read(bb);
+            bb.rewind();
+            size = IsoTypeReader.readUInt64(bb);
+            contentSize = size - 16;
+        } else if (size == 0) {
+            if (byteChannel instanceof FileChannel) {
+                size = ((FileChannel) byteChannel).size() - ((FileChannel) byteChannel).position() - 8;
+            } else {
+                throw new RuntimeException("Only FileChannel inputs may use size == 0 (box reaches to the end of file)");
+            }
+            contentSize = size - 8;
+        } else {
+            contentSize = size - 8;
+        }
+        if (UserBox.TYPE.equals(type)) {
+            ByteBuffer bb = ByteBuffer.allocate(16);
+            byteChannel.read(bb);
+            bb.rewind();
+            usertype = bb.array();
+            contentSize -= 16;
+        }
+        Box box = createBox(type, usertype, parent.getType());
+        box.setParent(parent);
+        LOG.finest("Parsing " + box.getType());
+        // System.out.println("parsing " + Arrays.toString(box.getType()) + " " + box.getClass().getName() + " size=" + size);
+
+
+        if (l2i(size - contentSize) == 8) {
+            // default - no large box - no uuid
+            // do nothing header's already correct
+            header.rewind();
+        } else if (l2i(size - contentSize) == 16) {
+            header = ByteBuffer.allocate(16);
+            IsoTypeWriter.writeUInt32(header, 1);
+            header.put(IsoFile.fourCCtoBytes(type));
+            IsoTypeWriter.writeUInt64(header, size);
+        } else if (l2i(size - contentSize) == 24) {
+            header = ByteBuffer.allocate(24);
+            IsoTypeWriter.writeUInt32(header, size);
+            header.put(IsoFile.fourCCtoBytes(type));
+            header.put(usertype);
+        } else if (l2i(size - contentSize) == 32) {
+            header = ByteBuffer.allocate(32);
+            IsoTypeWriter.writeUInt32(header, size);
+            header.put(IsoFile.fourCCtoBytes(type));
+            IsoTypeWriter.writeUInt64(header, size);
+            header.put(usertype);
+        } else {
+            throw new RuntimeException("I didn't expect that");
+        }
+
+
+        box.parse(byteChannel, header, contentSize, this);
+        // System.out.println("box = " + box);
+
+
+        assert size == box.getSize() :
+                "Reconstructed Size is not x to the number of parsed bytes! (" +
+                        box.getType() + ")"
+                        + " Actual Box size: " + size + " Calculated size: " + box.getSize();
+        return box;
+    }
+
+
+}
diff --git a/isoparser/src/main/java/com/coremedia/iso/.svn/text-base/Ascii.java.svn-base b/isoparser/src/main/java/com/coremedia/iso/.svn/text-base/Ascii.java.svn-base
new file mode 100644
index 0000000..2a659d7
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/.svn/text-base/Ascii.java.svn-base
@@ -0,0 +1,47 @@
+/*
+ * Copyright 2012 Sebastian Annies, Hamburg
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.coremedia.iso;
+
+import java.io.UnsupportedEncodingException;
+
+/**
+ * Converts <code>byte[]</code> -> <code>String</code> and vice versa.
+ */
+public final class Ascii {
+  public static byte[] convert(String s) {
+    try {
+      if (s != null) {
+        return s.getBytes("us-ascii");
+      } else {
+        return null;
+      }
+    } catch (UnsupportedEncodingException e) {
+      throw new Error(e);
+    }
+  }
+
+  public static String convert(byte[] b) {
+    try {
+      if (b != null) {
+        return new String(b, "us-ascii");
+      } else {
+        return null;
+      }
+    } catch (UnsupportedEncodingException e) {
+      throw new Error(e);
+    }
+  }
+}
\ No newline at end of file
diff --git a/isoparser/src/main/java/com/coremedia/iso/.svn/text-base/BoxParser.java.svn-base b/isoparser/src/main/java/com/coremedia/iso/.svn/text-base/BoxParser.java.svn-base
new file mode 100644
index 0000000..cbe9a6f
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/.svn/text-base/BoxParser.java.svn-base
@@ -0,0 +1,31 @@
+/*
+ * Copyright 2012 Sebastian Annies, Hamburg
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.coremedia.iso;
+
+import com.coremedia.iso.boxes.Box;
+import com.coremedia.iso.boxes.ContainerBox;
+
+import java.io.IOException;
+import java.nio.channels.ReadableByteChannel;
+
+/**
+ * Basic interface to create boxes from a <code>IsoBufferWrapper</code> and its parent.
+ */
+public interface BoxParser {
+    Class<? extends Box> getClassForFourCc(String type, byte[] userType, String parent);
+
+    Box parseBox(ReadableByteChannel in, ContainerBox parent) throws IOException;
+}
diff --git a/isoparser/src/main/java/com/coremedia/iso/.svn/text-base/ChannelHelper.java.svn-base b/isoparser/src/main/java/com/coremedia/iso/.svn/text-base/ChannelHelper.java.svn-base
new file mode 100644
index 0000000..2ec1d05
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/.svn/text-base/ChannelHelper.java.svn-base
@@ -0,0 +1,90 @@
+/*
+ * Copyright 2012 Sebastian Annies, Hamburg
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.coremedia.iso;
+
+import java.io.EOFException;
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.nio.channels.FileChannel;
+import java.nio.channels.ReadableByteChannel;
+import java.nio.channels.SelectionKey;
+import java.nio.channels.WritableByteChannel;
+
+import static com.googlecode.mp4parser.util.CastUtils.l2i;
+
+
+public class ChannelHelper {
+    public static ByteBuffer readFully(final ReadableByteChannel channel, long size) throws IOException {
+
+        if (channel instanceof FileChannel && size > 1024 * 1024) {
+            ByteBuffer bb = ((FileChannel) channel).map(FileChannel.MapMode.READ_ONLY, ((FileChannel) channel).position(), size);
+            ((FileChannel) channel).position(((FileChannel) channel).position() + size);
+            return bb;
+        } else {
+            ByteBuffer buf = ByteBuffer.allocate(l2i(size));
+            readFully(channel, buf, buf.limit());
+            buf.rewind();
+            assert buf.limit() == size;
+
+            return buf;
+        }
+
+    }
+
+
+    public static void readFully(final ReadableByteChannel channel, final ByteBuffer buf)
+            throws IOException {
+        readFully(channel, buf, buf.remaining());
+    }
+
+    public static int readFully(final ReadableByteChannel channel, final ByteBuffer buf, final int length)
+            throws IOException {
+        int n, count = 0;
+        while (-1 != (n = channel.read(buf))) {
+            count += n;
+            if (count == length) {
+                break;
+            }
+        }
+        if (n == -1) {
+            throw new EOFException("End of file. No more boxes.");
+        }
+        return count;
+    }
+
+
+    public static void writeFully(final WritableByteChannel channel, final ByteBuffer buf)
+            throws IOException {
+        do {
+            int written = channel.write(buf);
+            if (written < 0) {
+                throw new EOFException();
+            }
+        } while (buf.hasRemaining());
+    }
+
+
+    public static void close(SelectionKey key) {
+        try {
+            key.channel().close();
+        } catch (IOException e) {
+            // nop
+        }
+
+    }
+
+
+}
\ No newline at end of file
diff --git a/isoparser/src/main/java/com/coremedia/iso/.svn/text-base/Hex.java.svn-base b/isoparser/src/main/java/com/coremedia/iso/.svn/text-base/Hex.java.svn-base
new file mode 100644
index 0000000..b3d55ef
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/.svn/text-base/Hex.java.svn-base
@@ -0,0 +1,58 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.
+ */
+
+/*
+Extracted from commons-codec
+ */
+package com.coremedia.iso;
+
+import java.io.ByteArrayOutputStream;
+
+/**
+ * Converts hexadecimal Strings.
+ */
+public class Hex {
+    private static final char[] DIGITS = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};
+
+    public static String encodeHex(byte[] data) {
+        return encodeHex(data, 0);
+    }
+
+    public static String encodeHex(byte[] data, int group) {
+        int l = data.length;
+        char[] out = new char[(l << 1) + (group > 0 ? (l / group) : 0)];
+        // two characters form the hex value.
+        for (int i = 0, j = 0; i < l; i++) {
+            if ((group > 0) && ((i % group) == 0) && j > 0) {
+                out[j++] = '-';
+            }
+
+            out[j++] = DIGITS[(0xF0 & data[i]) >>> 4];
+            out[j++] = DIGITS[0x0F & data[i]];
+        }
+        return new String(out);
+    }
+
+    public static byte[] decodeHex(String hexString) {
+        ByteArrayOutputStream bas = new ByteArrayOutputStream();
+        for (int i = 0; i < hexString.length(); i += 2) {
+            int b = Integer.parseInt(hexString.substring(i, i + 2), 16);
+            bas.write(b);
+        }
+        return bas.toByteArray();
+    }
+}
diff --git a/isoparser/src/main/java/com/coremedia/iso/.svn/text-base/IsoFile.java.svn-base b/isoparser/src/main/java/com/coremedia/iso/.svn/text-base/IsoFile.java.svn-base
new file mode 100644
index 0000000..a6f4b2b
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/.svn/text-base/IsoFile.java.svn-base
@@ -0,0 +1,195 @@
+/*  
+ * Copyright 2008 CoreMedia AG, Hamburg
+ *
+ * Licensed under the Apache License, Version 2.0 (the License); 
+ * you may not use this file except in compliance with the License. 
+ * You may obtain a copy of the License at 
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0 
+ * 
+ * Unless required by applicable law or agreed to in writing, software 
+ * distributed under the License is distributed on an AS IS BASIS, 
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+ * See the License for the specific language governing permissions and 
+ * limitations under the License. 
+ */
+
+package com.coremedia.iso;
+
+import com.googlecode.mp4parser.AbstractContainerBox;
+import com.coremedia.iso.boxes.Box;
+import com.coremedia.iso.boxes.MovieBox;
+import com.googlecode.mp4parser.annotations.DoNotParseDetail;
+
+import java.io.*;
+import java.nio.ByteBuffer;
+import java.nio.channels.FileChannel;
+import java.nio.channels.ReadableByteChannel;
+import java.nio.channels.WritableByteChannel;
+
+/**
+ * The most upper container for ISO Boxes. It is a container box that is a file.
+ * Uses IsoBufferWrapper  to access the underlying file.
+ */
+@DoNotParseDetail
+public class IsoFile extends AbstractContainerBox implements Closeable {
+    protected BoxParser boxParser = new PropertyBoxParserImpl();
+    ReadableByteChannel byteChannel;
+
+    public IsoFile() {
+        super("");
+    }
+
+    public IsoFile(File f) throws IOException {
+        super("");
+        this.byteChannel = new FileInputStream(f).getChannel();
+        boxParser = createBoxParser();
+        parse();
+    }
+
+    public IsoFile(ReadableByteChannel byteChannel) throws IOException {
+        super("");
+        this.byteChannel = byteChannel;
+        boxParser = createBoxParser();
+        parse();
+    }
+
+    public IsoFile(ReadableByteChannel byteChannel, BoxParser boxParser) throws IOException {
+        super("");
+        this.byteChannel = byteChannel;
+        this.boxParser = boxParser;
+        parse();
+
+
+    }
+
+    protected BoxParser createBoxParser() {
+        return new PropertyBoxParserImpl();
+    }
+
+
+    @Override
+    public void _parseDetails(ByteBuffer content) {
+        // there are no details to parse we should be just file
+    }
+
+    public void parse(ReadableByteChannel inFC, ByteBuffer header, long contentSize, AbstractBoxParser abstractBoxParser) throws IOException {
+        throw new IOException("This method is not meant to be called. Use #parse() directly.");
+    }
+
+    private void parse() throws IOException {
+
+        boolean done = false;
+        while (!done) {
+            try {
+                Box box = boxParser.parseBox(byteChannel, this);
+                if (box != null) {
+                    //  System.err.println(box.getType());
+                    boxes.add(box);
+                } else {
+                    done = true;
+                }
+            } catch (EOFException e) {
+                done = true;
+            }
+        }
+    }
+
+    @DoNotParseDetail
+    public String toString() {
+        StringBuilder buffer = new StringBuilder();
+        buffer.append("IsoFile[");
+        if (boxes == null) {
+            buffer.append("unparsed");
+        } else {
+            for (int i = 0; i < boxes.size(); i++) {
+                if (i > 0) {
+                    buffer.append(";");
+                }
+                buffer.append(boxes.get(i).toString());
+            }
+        }
+        buffer.append("]");
+        return buffer.toString();
+    }
+
+    @DoNotParseDetail
+    public static byte[] fourCCtoBytes(String fourCC) {
+        byte[] result = new byte[4];
+        if (fourCC != null) {
+            for (int i = 0; i < Math.min(4, fourCC.length()); i++) {
+                result[i] = (byte) fourCC.charAt(i);
+            }
+        }
+        return result;
+    }
+
+    @DoNotParseDetail
+    public static String bytesToFourCC(byte[] type) {
+        byte[] result = new byte[]{0, 0, 0, 0};
+        if (type != null) {
+            System.arraycopy(type, 0, result, 0, Math.min(type.length, 4));
+        }
+        try {
+            return new String(result, "ISO-8859-1");
+        } catch (UnsupportedEncodingException e) {
+            throw new Error("Required character encoding is missing", e);
+        }
+    }
+
+
+    @Override
+    public long getNumOfBytesToFirstChild() {
+        return 0;
+    }
+
+    @Override
+    public long getSize() {
+        long size = 0;
+        for (Box box : boxes) {
+            size += box.getSize();
+        }
+        return size;
+    }
+
+    @Override
+    public IsoFile getIsoFile() {
+        return this;
+    }
+
+
+    /**
+     * Shortcut to get the MovieBox since it is often needed and present in
+     * nearly all ISO 14496 files (at least if they are derived from MP4 ).
+     *
+     * @return the MovieBox or <code>null</code>
+     */
+    @DoNotParseDetail
+    public MovieBox getMovieBox() {
+        for (Box box : boxes) {
+            if (box instanceof MovieBox) {
+                return (MovieBox) box;
+            }
+        }
+        return null;
+    }
+
+    public void getBox(WritableByteChannel os) throws IOException {
+        for (Box box : boxes) {
+
+            if (os instanceof FileChannel) {
+                long startPos = ((FileChannel) os).position();
+                box.getBox(os);
+                long size = ((FileChannel) os).position() - startPos;
+                assert size == box.getSize();
+            } else {
+                box.getBox(os);
+            }
+
+        }
+    }
+
+    public void close() throws IOException {
+        this.byteChannel.close();
+    }
+}
diff --git a/isoparser/src/main/java/com/coremedia/iso/.svn/text-base/IsoTypeReader.java.svn-base b/isoparser/src/main/java/com/coremedia/iso/.svn/text-base/IsoTypeReader.java.svn-base
new file mode 100644
index 0000000..6d9e86e
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/.svn/text-base/IsoTypeReader.java.svn-base
@@ -0,0 +1,147 @@
+/*
+ * Copyright 2012 Sebastian Annies, Hamburg
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.coremedia.iso;
+
+import java.io.ByteArrayOutputStream;
+import java.nio.ByteBuffer;
+
+public final class IsoTypeReader {
+
+
+    public static long readUInt32BE(ByteBuffer bb) {
+        long ch1 = readUInt8(bb);
+        long ch2 = readUInt8(bb);
+        long ch3 = readUInt8(bb);
+        long ch4 = readUInt8(bb);
+        return ((ch4 << 24) + (ch3 << 16) + (ch2 << 8) + (ch1 << 0));
+
+    }
+
+
+    public static long readUInt32(ByteBuffer bb) {
+        long i = bb.getInt();
+        if (i < 0) {
+            i += 1l<<32;
+        }
+        return i;
+    }
+
+    public static int readUInt24(ByteBuffer bb) {
+        int result = 0;
+        result += readUInt16(bb) << 8;
+        result += byte2int(bb.get());
+        return result;
+    }
+
+
+    public static int readUInt16(ByteBuffer bb) {
+        int result = 0;
+        result += byte2int(bb.get()) << 8;
+        result += byte2int(bb.get());
+        return result;
+    }
+
+    public static int readUInt16BE(ByteBuffer bb) {
+        int result = 0;
+        result += byte2int(bb.get());
+        result += byte2int(bb.get()) << 8;
+        return result;
+    }
+
+    public static int readUInt8(ByteBuffer bb) {
+        return byte2int(bb.get());
+    }
+
+    public static int byte2int(byte b) {
+        return b < 0 ? b + 256 : b;
+    }
+
+
+    /**
+     * Reads a zero terminated UTF-8 string.
+     *
+     * @param byteBuffer the data source
+     * @return the string readByte
+     * @throws Error in case of an error in the underlying stream
+     */
+    public static String readString(ByteBuffer byteBuffer) {
+
+        ByteArrayOutputStream out = new ByteArrayOutputStream();
+        int read;
+        while ((read = byteBuffer.get()) != 0) {
+            out.write(read);
+        }
+        return Utf8.convert(out.toByteArray());
+    }
+
+    public static String readString(ByteBuffer byteBuffer, int length) {
+        byte[] buffer = new byte[length];
+        byteBuffer.get(buffer);
+        return Utf8.convert(buffer);
+
+    }
+
+    public static long readUInt64(ByteBuffer byteBuffer) {
+        long result = 0;
+        // thanks to Erik Nicolas for finding a bug! Cast to long is definitivly needed
+        result += readUInt32(byteBuffer) << 32;
+        if (result < 0) {
+            throw new RuntimeException("I don't know how to deal with UInt64! long is not sufficient and I don't want to use BigInt");
+        }
+        result += readUInt32(byteBuffer);
+
+        return result;
+    }
+
+    public static double readFixedPoint1616(ByteBuffer bb) {
+        byte[] bytes = new byte[4];
+        bb.get(bytes);
+
+        int result = 0;
+        result |= ((bytes[0] << 24) & 0xFF000000);
+        result |= ((bytes[1] << 16) & 0xFF0000);
+        result |= ((bytes[2] << 8) & 0xFF00);
+        result |= ((bytes[3]) & 0xFF);
+        return ((double) result) / 65536;
+
+    }
+
+    public static float readFixedPoint88(ByteBuffer bb) {
+        byte[] bytes = new byte[2];
+        bb.get(bytes);
+        short result = 0;
+        result |= ((bytes[0] << 8) & 0xFF00);
+        result |= ((bytes[1]) & 0xFF);
+        return ((float) result) / 256;
+    }
+
+    public static String readIso639(ByteBuffer bb) {
+        int bits = readUInt16(bb);
+        StringBuilder result = new StringBuilder();
+        for (int i = 0; i < 3; i++) {
+            int c = (bits >> (2 - i) * 5) & 0x1f;
+            result.append((char) (c + 0x60));
+        }
+        return result.toString();
+    }
+
+    public static String read4cc(ByteBuffer bb) {
+        byte[] b = new byte[4];
+        bb.get(b);
+        return IsoFile.bytesToFourCC(b);
+    }
+
+}
diff --git a/isoparser/src/main/java/com/coremedia/iso/.svn/text-base/IsoTypeReaderVariable.java.svn-base b/isoparser/src/main/java/com/coremedia/iso/.svn/text-base/IsoTypeReaderVariable.java.svn-base
new file mode 100644
index 0000000..a2e4681
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/.svn/text-base/IsoTypeReaderVariable.java.svn-base
@@ -0,0 +1,39 @@
+/*
+ * Copyright 2012 Sebastian Annies, Hamburg
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.coremedia.iso;
+
+import java.nio.ByteBuffer;
+
+public final class IsoTypeReaderVariable {
+
+    public static long read(ByteBuffer bb, int bytes) {
+        switch (bytes) {
+            case 1:
+                return IsoTypeReader.readUInt8(bb);
+            case 2:
+                return IsoTypeReader.readUInt16(bb);
+            case 3:
+                return IsoTypeReader.readUInt24(bb);
+            case 4:
+                return IsoTypeReader.readUInt32(bb);
+            case 8:
+                return IsoTypeReader.readUInt64(bb);
+            default:
+                throw new RuntimeException("I don't know how to read " + bytes + " bytes");
+        }
+
+    }
+}
diff --git a/isoparser/src/main/java/com/coremedia/iso/.svn/text-base/IsoTypeWriter.java.svn-base b/isoparser/src/main/java/com/coremedia/iso/.svn/text-base/IsoTypeWriter.java.svn-base
new file mode 100644
index 0000000..6da6998
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/.svn/text-base/IsoTypeWriter.java.svn-base
@@ -0,0 +1,95 @@
+/*
+ * Copyright 2012 Sebastian Annies, Hamburg
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.coremedia.iso;
+
+import java.nio.ByteBuffer;
+
+public final class IsoTypeWriter {
+
+    public static void writeUInt64(ByteBuffer bb, long u) {
+        bb.putLong(u);
+    }
+
+    public static void writeUInt32(ByteBuffer bb, long u) {
+        bb.putInt((int) u);
+
+    }
+
+    public static void writeUInt32BE(ByteBuffer bb, long u) {
+        assert u >= 0 && u <= 1L << 32 : "The given long is not in the range of uint32 (" + u + ")";
+        writeUInt16BE(bb, (int) u & 0xFFFF);
+        writeUInt16BE(bb, (int) ((u >> 16) & 0xFFFF));
+
+    }
+
+
+    public static void writeUInt24(ByteBuffer bb, int i) {
+        i = i & 0xFFFFFF;
+        writeUInt16(bb, i >> 8);
+        writeUInt8(bb, i);
+
+    }
+
+
+    public static void writeUInt16(ByteBuffer bb, int i) {
+        i = i & 0xFFFF;
+        writeUInt8(bb, i >> 8);
+        writeUInt8(bb, i & 0xFF);
+    }
+
+    public static void writeUInt16BE(ByteBuffer bb, int i) {
+        i = i & 0xFFFF;
+        writeUInt8(bb, i & 0xFF);
+        writeUInt8(bb, i >> 8);
+    }
+
+    public static void writeUInt8(ByteBuffer bb, int i) {
+        i = i & 0xFF;
+        bb.put((byte) i);
+    }
+
+
+    public static void writeFixedPont1616(ByteBuffer bb, double v) {
+        int result = (int) (v * 65536);
+        bb.put((byte) ((result & 0xFF000000) >> 24));
+        bb.put((byte) ((result & 0x00FF0000) >> 16));
+        bb.put((byte) ((result & 0x0000FF00) >> 8));
+        bb.put((byte) ((result & 0x000000FF)));
+    }
+
+    public static void writeFixedPont88(ByteBuffer bb, double v) {
+        short result = (short) (v * 256);
+        bb.put((byte) ((result & 0xFF00) >> 8));
+        bb.put((byte) ((result & 0x00FF)));
+    }
+
+    public static void writeIso639(ByteBuffer bb, String language) {
+        if (language.getBytes().length != 3) {
+            throw new IllegalArgumentException("\"" + language + "\" language string isn't exactly 3 characters long!");
+        }
+        int bits = 0;
+        for (int i = 0; i < 3; i++) {
+            bits += (language.getBytes()[i] - 0x60) << (2 - i) * 5;
+        }
+        writeUInt16(bb, bits);
+    }
+
+    public static void writeUtf8String(ByteBuffer bb, String string) {
+
+        bb.put(Utf8.convert(string));
+        writeUInt8(bb, 0);
+    }
+}
diff --git a/isoparser/src/main/java/com/coremedia/iso/.svn/text-base/IsoTypeWriterVariable.java.svn-base b/isoparser/src/main/java/com/coremedia/iso/.svn/text-base/IsoTypeWriterVariable.java.svn-base
new file mode 100644
index 0000000..3b3bdd4
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/.svn/text-base/IsoTypeWriterVariable.java.svn-base
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2012 Sebastian Annies, Hamburg
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.coremedia.iso;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+
+public final class IsoTypeWriterVariable {
+
+    public static void write(long v, ByteBuffer bb, int bytes) {
+        switch (bytes) {
+            case 1:
+                IsoTypeWriter.writeUInt8(bb, (int) (v & 0xff));
+                break;
+            case 2:
+                IsoTypeWriter.writeUInt16(bb, (int) (v & 0xffff));
+                break;
+            case 3:
+                IsoTypeWriter.writeUInt24(bb, (int) (v & 0xffffff));
+                break;
+            case 4:
+                IsoTypeWriter.writeUInt32(bb, v);
+                break;
+            case 8:
+                IsoTypeWriter.writeUInt64(bb, v);
+                break;
+            default:
+                throw new RuntimeException("I don't know how to read " + bytes + " bytes");
+        }
+
+    }
+}
diff --git a/isoparser/src/main/java/com/coremedia/iso/.svn/text-base/PropertyBoxParserImpl.java.svn-base b/isoparser/src/main/java/com/coremedia/iso/.svn/text-base/PropertyBoxParserImpl.java.svn-base
new file mode 100644
index 0000000..f1bcc01
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/.svn/text-base/PropertyBoxParserImpl.java.svn-base
@@ -0,0 +1,199 @@
+/*
+ * Copyright 2012 Sebastian Annies, Hamburg
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.coremedia.iso;
+
+import com.googlecode.mp4parser.AbstractBox;
+import com.coremedia.iso.boxes.Box;
+
+import java.io.BufferedInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationTargetException;
+import java.net.URL;
+import java.util.Enumeration;
+import java.util.Properties;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * A Property file based BoxFactory
+ */
+public class PropertyBoxParserImpl extends AbstractBoxParser {
+    Properties mapping;
+
+    public PropertyBoxParserImpl(String... customProperties) {
+        InputStream is = new BufferedInputStream(getClass().getResourceAsStream("/isoparser-default.properties"));
+        try {
+            mapping = new Properties();
+            try {
+                mapping.load(is);
+                Enumeration<URL> enumeration = Thread.currentThread().getContextClassLoader().getResources("isoparser-custom.properties");
+
+                while (enumeration.hasMoreElements()) {
+                    URL url = enumeration.nextElement();
+                    InputStream customIS = new BufferedInputStream(url.openStream());
+                    try {
+                        mapping.load(customIS);
+                    } finally {
+                        customIS.close();
+                    }
+                }
+                for (String customProperty : customProperties) {
+                    mapping.load(new BufferedInputStream(getClass().getResourceAsStream(customProperty)));
+                }
+            } catch (IOException e) {
+                throw new RuntimeException(e);
+            }
+        } finally {
+            try {
+                is.close();
+            } catch (IOException e) {
+                e.printStackTrace();
+                // ignore - I can't help
+            }
+        }
+    }
+
+    public PropertyBoxParserImpl(Properties mapping) {
+        this.mapping = mapping;
+    }
+
+    Pattern p = Pattern.compile("(.*)\\((.*?)\\)");
+
+    @SuppressWarnings("unchecked")
+    public Class<? extends Box> getClassForFourCc(String type, byte[] userType, String parent) {
+        FourCcToBox fourCcToBox = new FourCcToBox(type, userType, parent).invoke();
+        try {
+            return (Class<? extends Box>) Class.forName(fourCcToBox.clazzName);
+        } catch (ClassNotFoundException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    @Override
+    public Box createBox(String type, byte[] userType, String parent) {
+
+        FourCcToBox fourCcToBox = new FourCcToBox(type, userType, parent).invoke();
+        String[] param = fourCcToBox.getParam();
+        String clazzName = fourCcToBox.getClazzName();
+        try {
+            if (param[0].trim().length() == 0) {
+                param = new String[]{};
+            }
+            Class clazz = Class.forName(clazzName);
+
+            Class[] constructorArgsClazz = new Class[param.length];
+            Object[] constructorArgs = new Object[param.length];
+            for (int i = 0; i < param.length; i++) {
+
+                if ("userType".equals(param[i])) {
+                    constructorArgs[i] = userType;
+                    constructorArgsClazz[i] = byte[].class;
+                } else if ("type".equals(param[i])) {
+                    constructorArgs[i] = type;
+                    constructorArgsClazz[i] = String.class;
+                } else if ("parent".equals(param[i])) {
+                    constructorArgs[i] = parent;
+                    constructorArgsClazz[i] = String.class;
+                } else {
+                    throw new InternalError("No such param: " + param[i]);
+                }
+
+
+            }
+            Constructor<AbstractBox> constructorObject;
+            try {
+                if (param.length > 0) {
+                    constructorObject = clazz.getConstructor(constructorArgsClazz);
+                } else {
+                    constructorObject = clazz.getConstructor();
+                }
+
+                return constructorObject.newInstance(constructorArgs);
+            } catch (NoSuchMethodException e) {
+                throw new RuntimeException(e);
+            } catch (InvocationTargetException e) {
+                throw new RuntimeException(e);
+            } catch (InstantiationException e) {
+                throw new RuntimeException(e);
+            } catch (IllegalAccessException e) {
+                throw new RuntimeException(e);
+            }
+
+
+        } catch (ClassNotFoundException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    private class FourCcToBox {
+        private String type;
+        private byte[] userType;
+        private String parent;
+        private String clazzName;
+        private String[] param;
+
+        public FourCcToBox(String type, byte[] userType, String parent) {
+            this.type = type;
+            this.parent = parent;
+            this.userType = userType;
+        }
+
+        public String getClazzName() {
+            return clazzName;
+        }
+
+        public String[] getParam() {
+            return param;
+        }
+
+        public FourCcToBox invoke() {
+            String constructor;
+            if (userType != null) {
+                if (!"uuid".equals((type))) {
+                    throw new RuntimeException("we have a userType but no uuid box type. Something's wrong");
+                }
+                constructor = mapping.getProperty((parent) + "-uuid[" + Hex.encodeHex(userType).toUpperCase() + "]");
+                if (constructor == null) {
+                    constructor = mapping.getProperty("uuid[" + Hex.encodeHex(userType).toUpperCase() + "]");
+                }
+                if (constructor == null) {
+                    constructor = mapping.getProperty("uuid");
+                }
+            } else {
+                constructor = mapping.getProperty((parent) + "-" + (type));
+                if (constructor == null) {
+                    constructor = mapping.getProperty((type));
+                }
+            }
+            if (constructor == null) {
+                constructor = mapping.getProperty("default");
+            }
+            if (constructor == null) {
+                throw new RuntimeException("No box object found for " + type);
+            }
+            Matcher m = p.matcher(constructor);
+            boolean matches = m.matches();
+            if (!matches) {
+                throw new RuntimeException("Cannot work with that constructor: " + constructor);
+            }
+            clazzName = m.group(1);
+            param = m.group(2).split(",");
+            return this;
+        }
+    }
+}
diff --git a/isoparser/src/main/java/com/coremedia/iso/.svn/text-base/Utf8.java.svn-base b/isoparser/src/main/java/com/coremedia/iso/.svn/text-base/Utf8.java.svn-base
new file mode 100644
index 0000000..a30497e
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/.svn/text-base/Utf8.java.svn-base
@@ -0,0 +1,59 @@
+/*
+ * Copyright 2012 Sebastian Annies, Hamburg
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.coremedia.iso;
+
+import java.io.UnsupportedEncodingException;
+
+/**
+ * Converts <code>byte[]</code> -> <code>String</code> and vice versa.
+ */
+public final class Utf8 {
+    public static byte[] convert(String s) {
+        try {
+            if (s != null) {
+                return s.getBytes("UTF-8");
+            } else {
+                return null;
+            }
+        } catch (UnsupportedEncodingException e) {
+            throw new Error(e);
+        }
+    }
+
+    public static String convert(byte[] b) {
+        try {
+            if (b != null) {
+                return new String(b, "UTF-8");
+            } else {
+                return null;
+            }
+        } catch (UnsupportedEncodingException e) {
+            throw new Error(e);
+        }
+    }
+
+    public static int utf8StringLengthInBytes(String utf8) {
+        try {
+            if (utf8 != null) {
+                return utf8.getBytes("UTF-8").length;
+            } else {
+                return 0;
+            }
+        } catch (UnsupportedEncodingException e) {
+            throw new RuntimeException();
+        }
+    }
+}
diff --git a/isoparser/src/main/java/com/coremedia/iso/AbstractBoxParser.java b/isoparser/src/main/java/com/coremedia/iso/AbstractBoxParser.java
new file mode 100644
index 0000000..6d92acd
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/AbstractBoxParser.java
@@ -0,0 +1,130 @@
+/*
+ * Copyright 2012 Sebastian Annies, Hamburg
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.coremedia.iso;
+
+import com.coremedia.iso.boxes.Box;
+import com.coremedia.iso.boxes.ContainerBox;
+import com.coremedia.iso.boxes.UserBox;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.nio.channels.FileChannel;
+import java.nio.channels.ReadableByteChannel;
+import java.util.logging.Logger;
+
+import static com.googlecode.mp4parser.util.CastUtils.l2i;
+
+/**
+ * This BoxParser handles the basic stuff like reading size and extracting box type.
+ */
+public abstract class AbstractBoxParser implements BoxParser {
+
+    private static Logger LOG = Logger.getLogger(AbstractBoxParser.class.getName());
+
+    public abstract Box createBox(String type, byte[] userType, String parent);
+
+    /**
+     * Parses the next size and type, creates a box instance and parses the box's content.
+     *
+     * @param byteChannel the FileChannel pointing to the ISO file
+     * @param parent      the current box's parent (null if no parent)
+     * @return the box just parsed
+     * @throws java.io.IOException if reading from <code>in</code> fails
+     */
+    public Box parseBox(ReadableByteChannel byteChannel, ContainerBox parent) throws IOException {
+
+
+        ByteBuffer header = ChannelHelper.readFully(byteChannel, 8);
+
+        long size = IsoTypeReader.readUInt32(header);
+        // do plausibility check
+        if (size < 8 && size > 1) {
+            LOG.severe("Plausibility check failed: size < 8 (size = " + size + "). Stop parsing!");
+            return null;
+        }
+
+
+        String type = IsoTypeReader.read4cc(header);
+        byte[] usertype = null;
+        long contentSize;
+
+        if (size == 1) {
+            ByteBuffer bb = ByteBuffer.allocate(8);
+            byteChannel.read(bb);
+            bb.rewind();
+            size = IsoTypeReader.readUInt64(bb);
+            contentSize = size - 16;
+        } else if (size == 0) {
+            if (byteChannel instanceof FileChannel) {
+                size = ((FileChannel) byteChannel).size() - ((FileChannel) byteChannel).position() - 8;
+            } else {
+                throw new RuntimeException("Only FileChannel inputs may use size == 0 (box reaches to the end of file)");
+            }
+            contentSize = size - 8;
+        } else {
+            contentSize = size - 8;
+        }
+        if (UserBox.TYPE.equals(type)) {
+            ByteBuffer bb = ByteBuffer.allocate(16);
+            byteChannel.read(bb);
+            bb.rewind();
+            usertype = bb.array();
+            contentSize -= 16;
+        }
+        Box box = createBox(type, usertype, parent.getType());
+        box.setParent(parent);
+        LOG.finest("Parsing " + box.getType());
+        // System.out.println("parsing " + Arrays.toString(box.getType()) + " " + box.getClass().getName() + " size=" + size);
+
+
+        if (l2i(size - contentSize) == 8) {
+            // default - no large box - no uuid
+            // do nothing header's already correct
+            header.rewind();
+        } else if (l2i(size - contentSize) == 16) {
+            header = ByteBuffer.allocate(16);
+            IsoTypeWriter.writeUInt32(header, 1);
+            header.put(IsoFile.fourCCtoBytes(type));
+            IsoTypeWriter.writeUInt64(header, size);
+        } else if (l2i(size - contentSize) == 24) {
+            header = ByteBuffer.allocate(24);
+            IsoTypeWriter.writeUInt32(header, size);
+            header.put(IsoFile.fourCCtoBytes(type));
+            header.put(usertype);
+        } else if (l2i(size - contentSize) == 32) {
+            header = ByteBuffer.allocate(32);
+            IsoTypeWriter.writeUInt32(header, size);
+            header.put(IsoFile.fourCCtoBytes(type));
+            IsoTypeWriter.writeUInt64(header, size);
+            header.put(usertype);
+        } else {
+            throw new RuntimeException("I didn't expect that");
+        }
+
+
+        box.parse(byteChannel, header, contentSize, this);
+        // System.out.println("box = " + box);
+
+
+        assert size == box.getSize() :
+                "Reconstructed Size is not x to the number of parsed bytes! (" +
+                        box.getType() + ")"
+                        + " Actual Box size: " + size + " Calculated size: " + box.getSize();
+        return box;
+    }
+
+
+}
diff --git a/isoparser/src/main/java/com/coremedia/iso/Ascii.java b/isoparser/src/main/java/com/coremedia/iso/Ascii.java
new file mode 100644
index 0000000..2a659d7
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/Ascii.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright 2012 Sebastian Annies, Hamburg
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.coremedia.iso;
+
+import java.io.UnsupportedEncodingException;
+
+/**
+ * Converts <code>byte[]</code> -> <code>String</code> and vice versa.
+ */
+public final class Ascii {
+  public static byte[] convert(String s) {
+    try {
+      if (s != null) {
+        return s.getBytes("us-ascii");
+      } else {
+        return null;
+      }
+    } catch (UnsupportedEncodingException e) {
+      throw new Error(e);
+    }
+  }
+
+  public static String convert(byte[] b) {
+    try {
+      if (b != null) {
+        return new String(b, "us-ascii");
+      } else {
+        return null;
+      }
+    } catch (UnsupportedEncodingException e) {
+      throw new Error(e);
+    }
+  }
+}
\ No newline at end of file
diff --git a/isoparser/src/main/java/com/coremedia/iso/BoxParser.java b/isoparser/src/main/java/com/coremedia/iso/BoxParser.java
new file mode 100644
index 0000000..cbe9a6f
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/BoxParser.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright 2012 Sebastian Annies, Hamburg
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.coremedia.iso;
+
+import com.coremedia.iso.boxes.Box;
+import com.coremedia.iso.boxes.ContainerBox;
+
+import java.io.IOException;
+import java.nio.channels.ReadableByteChannel;
+
+/**
+ * Basic interface to create boxes from a <code>IsoBufferWrapper</code> and its parent.
+ */
+public interface BoxParser {
+    Class<? extends Box> getClassForFourCc(String type, byte[] userType, String parent);
+
+    Box parseBox(ReadableByteChannel in, ContainerBox parent) throws IOException;
+}
diff --git a/isoparser/src/main/java/com/coremedia/iso/ChannelHelper.java b/isoparser/src/main/java/com/coremedia/iso/ChannelHelper.java
new file mode 100644
index 0000000..2ec1d05
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/ChannelHelper.java
@@ -0,0 +1,90 @@
+/*
+ * Copyright 2012 Sebastian Annies, Hamburg
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.coremedia.iso;
+
+import java.io.EOFException;
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.nio.channels.FileChannel;
+import java.nio.channels.ReadableByteChannel;
+import java.nio.channels.SelectionKey;
+import java.nio.channels.WritableByteChannel;
+
+import static com.googlecode.mp4parser.util.CastUtils.l2i;
+
+
+public class ChannelHelper {
+    public static ByteBuffer readFully(final ReadableByteChannel channel, long size) throws IOException {
+
+        if (channel instanceof FileChannel && size > 1024 * 1024) {
+            ByteBuffer bb = ((FileChannel) channel).map(FileChannel.MapMode.READ_ONLY, ((FileChannel) channel).position(), size);
+            ((FileChannel) channel).position(((FileChannel) channel).position() + size);
+            return bb;
+        } else {
+            ByteBuffer buf = ByteBuffer.allocate(l2i(size));
+            readFully(channel, buf, buf.limit());
+            buf.rewind();
+            assert buf.limit() == size;
+
+            return buf;
+        }
+
+    }
+
+
+    public static void readFully(final ReadableByteChannel channel, final ByteBuffer buf)
+            throws IOException {
+        readFully(channel, buf, buf.remaining());
+    }
+
+    public static int readFully(final ReadableByteChannel channel, final ByteBuffer buf, final int length)
+            throws IOException {
+        int n, count = 0;
+        while (-1 != (n = channel.read(buf))) {
+            count += n;
+            if (count == length) {
+                break;
+            }
+        }
+        if (n == -1) {
+            throw new EOFException("End of file. No more boxes.");
+        }
+        return count;
+    }
+
+
+    public static void writeFully(final WritableByteChannel channel, final ByteBuffer buf)
+            throws IOException {
+        do {
+            int written = channel.write(buf);
+            if (written < 0) {
+                throw new EOFException();
+            }
+        } while (buf.hasRemaining());
+    }
+
+
+    public static void close(SelectionKey key) {
+        try {
+            key.channel().close();
+        } catch (IOException e) {
+            // nop
+        }
+
+    }
+
+
+}
\ No newline at end of file
diff --git a/isoparser/src/main/java/com/coremedia/iso/Hex.java b/isoparser/src/main/java/com/coremedia/iso/Hex.java
new file mode 100644
index 0000000..b3d55ef
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/Hex.java
@@ -0,0 +1,58 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.
+ */
+
+/*
+Extracted from commons-codec
+ */
+package com.coremedia.iso;
+
+import java.io.ByteArrayOutputStream;
+
+/**
+ * Converts hexadecimal Strings.
+ */
+public class Hex {
+    private static final char[] DIGITS = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};
+
+    public static String encodeHex(byte[] data) {
+        return encodeHex(data, 0);
+    }
+
+    public static String encodeHex(byte[] data, int group) {
+        int l = data.length;
+        char[] out = new char[(l << 1) + (group > 0 ? (l / group) : 0)];
+        // two characters form the hex value.
+        for (int i = 0, j = 0; i < l; i++) {
+            if ((group > 0) && ((i % group) == 0) && j > 0) {
+                out[j++] = '-';
+            }
+
+            out[j++] = DIGITS[(0xF0 & data[i]) >>> 4];
+            out[j++] = DIGITS[0x0F & data[i]];
+        }
+        return new String(out);
+    }
+
+    public static byte[] decodeHex(String hexString) {
+        ByteArrayOutputStream bas = new ByteArrayOutputStream();
+        for (int i = 0; i < hexString.length(); i += 2) {
+            int b = Integer.parseInt(hexString.substring(i, i + 2), 16);
+            bas.write(b);
+        }
+        return bas.toByteArray();
+    }
+}
diff --git a/isoparser/src/main/java/com/coremedia/iso/IsoFile.java b/isoparser/src/main/java/com/coremedia/iso/IsoFile.java
new file mode 100644
index 0000000..a6f4b2b
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/IsoFile.java
@@ -0,0 +1,195 @@
+/*  
+ * Copyright 2008 CoreMedia AG, Hamburg
+ *
+ * Licensed under the Apache License, Version 2.0 (the License); 
+ * you may not use this file except in compliance with the License. 
+ * You may obtain a copy of the License at 
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0 
+ * 
+ * Unless required by applicable law or agreed to in writing, software 
+ * distributed under the License is distributed on an AS IS BASIS, 
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+ * See the License for the specific language governing permissions and 
+ * limitations under the License. 
+ */
+
+package com.coremedia.iso;
+
+import com.googlecode.mp4parser.AbstractContainerBox;
+import com.coremedia.iso.boxes.Box;
+import com.coremedia.iso.boxes.MovieBox;
+import com.googlecode.mp4parser.annotations.DoNotParseDetail;
+
+import java.io.*;
+import java.nio.ByteBuffer;
+import java.nio.channels.FileChannel;
+import java.nio.channels.ReadableByteChannel;
+import java.nio.channels.WritableByteChannel;
+
+/**
+ * The most upper container for ISO Boxes. It is a container box that is a file.
+ * Uses IsoBufferWrapper  to access the underlying file.
+ */
+@DoNotParseDetail
+public class IsoFile extends AbstractContainerBox implements Closeable {
+    protected BoxParser boxParser = new PropertyBoxParserImpl();
+    ReadableByteChannel byteChannel;
+
+    public IsoFile() {
+        super("");
+    }
+
+    public IsoFile(File f) throws IOException {
+        super("");
+        this.byteChannel = new FileInputStream(f).getChannel();
+        boxParser = createBoxParser();
+        parse();
+    }
+
+    public IsoFile(ReadableByteChannel byteChannel) throws IOException {
+        super("");
+        this.byteChannel = byteChannel;
+        boxParser = createBoxParser();
+        parse();
+    }
+
+    public IsoFile(ReadableByteChannel byteChannel, BoxParser boxParser) throws IOException {
+        super("");
+        this.byteChannel = byteChannel;
+        this.boxParser = boxParser;
+        parse();
+
+
+    }
+
+    protected BoxParser createBoxParser() {
+        return new PropertyBoxParserImpl();
+    }
+
+
+    @Override
+    public void _parseDetails(ByteBuffer content) {
+        // there are no details to parse we should be just file
+    }
+
+    public void parse(ReadableByteChannel inFC, ByteBuffer header, long contentSize, AbstractBoxParser abstractBoxParser) throws IOException {
+        throw new IOException("This method is not meant to be called. Use #parse() directly.");
+    }
+
+    private void parse() throws IOException {
+
+        boolean done = false;
+        while (!done) {
+            try {
+                Box box = boxParser.parseBox(byteChannel, this);
+                if (box != null) {
+                    //  System.err.println(box.getType());
+                    boxes.add(box);
+                } else {
+                    done = true;
+                }
+            } catch (EOFException e) {
+                done = true;
+            }
+        }
+    }
+
+    @DoNotParseDetail
+    public String toString() {
+        StringBuilder buffer = new StringBuilder();
+        buffer.append("IsoFile[");
+        if (boxes == null) {
+            buffer.append("unparsed");
+        } else {
+            for (int i = 0; i < boxes.size(); i++) {
+                if (i > 0) {
+                    buffer.append(";");
+                }
+                buffer.append(boxes.get(i).toString());
+            }
+        }
+        buffer.append("]");
+        return buffer.toString();
+    }
+
+    @DoNotParseDetail
+    public static byte[] fourCCtoBytes(String fourCC) {
+        byte[] result = new byte[4];
+        if (fourCC != null) {
+            for (int i = 0; i < Math.min(4, fourCC.length()); i++) {
+                result[i] = (byte) fourCC.charAt(i);
+            }
+        }
+        return result;
+    }
+
+    @DoNotParseDetail
+    public static String bytesToFourCC(byte[] type) {
+        byte[] result = new byte[]{0, 0, 0, 0};
+        if (type != null) {
+            System.arraycopy(type, 0, result, 0, Math.min(type.length, 4));
+        }
+        try {
+            return new String(result, "ISO-8859-1");
+        } catch (UnsupportedEncodingException e) {
+            throw new Error("Required character encoding is missing", e);
+        }
+    }
+
+
+    @Override
+    public long getNumOfBytesToFirstChild() {
+        return 0;
+    }
+
+    @Override
+    public long getSize() {
+        long size = 0;
+        for (Box box : boxes) {
+            size += box.getSize();
+        }
+        return size;
+    }
+
+    @Override
+    public IsoFile getIsoFile() {
+        return this;
+    }
+
+
+    /**
+     * Shortcut to get the MovieBox since it is often needed and present in
+     * nearly all ISO 14496 files (at least if they are derived from MP4 ).
+     *
+     * @return the MovieBox or <code>null</code>
+     */
+    @DoNotParseDetail
+    public MovieBox getMovieBox() {
+        for (Box box : boxes) {
+            if (box instanceof MovieBox) {
+                return (MovieBox) box;
+            }
+        }
+        return null;
+    }
+
+    public void getBox(WritableByteChannel os) throws IOException {
+        for (Box box : boxes) {
+
+            if (os instanceof FileChannel) {
+                long startPos = ((FileChannel) os).position();
+                box.getBox(os);
+                long size = ((FileChannel) os).position() - startPos;
+                assert size == box.getSize();
+            } else {
+                box.getBox(os);
+            }
+
+        }
+    }
+
+    public void close() throws IOException {
+        this.byteChannel.close();
+    }
+}
diff --git a/isoparser/src/main/java/com/coremedia/iso/IsoTypeReader.java b/isoparser/src/main/java/com/coremedia/iso/IsoTypeReader.java
new file mode 100644
index 0000000..6d9e86e
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/IsoTypeReader.java
@@ -0,0 +1,147 @@
+/*
+ * Copyright 2012 Sebastian Annies, Hamburg
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.coremedia.iso;
+
+import java.io.ByteArrayOutputStream;
+import java.nio.ByteBuffer;
+
+public final class IsoTypeReader {
+
+
+    public static long readUInt32BE(ByteBuffer bb) {
+        long ch1 = readUInt8(bb);
+        long ch2 = readUInt8(bb);
+        long ch3 = readUInt8(bb);
+        long ch4 = readUInt8(bb);
+        return ((ch4 << 24) + (ch3 << 16) + (ch2 << 8) + (ch1 << 0));
+
+    }
+
+
+    public static long readUInt32(ByteBuffer bb) {
+        long i = bb.getInt();
+        if (i < 0) {
+            i += 1l<<32;
+        }
+        return i;
+    }
+
+    public static int readUInt24(ByteBuffer bb) {
+        int result = 0;
+        result += readUInt16(bb) << 8;
+        result += byte2int(bb.get());
+        return result;
+    }
+
+
+    public static int readUInt16(ByteBuffer bb) {
+        int result = 0;
+        result += byte2int(bb.get()) << 8;
+        result += byte2int(bb.get());
+        return result;
+    }
+
+    public static int readUInt16BE(ByteBuffer bb) {
+        int result = 0;
+        result += byte2int(bb.get());
+        result += byte2int(bb.get()) << 8;
+        return result;
+    }
+
+    public static int readUInt8(ByteBuffer bb) {
+        return byte2int(bb.get());
+    }
+
+    public static int byte2int(byte b) {
+        return b < 0 ? b + 256 : b;
+    }
+
+
+    /**
+     * Reads a zero terminated UTF-8 string.
+     *
+     * @param byteBuffer the data source
+     * @return the string readByte
+     * @throws Error in case of an error in the underlying stream
+     */
+    public static String readString(ByteBuffer byteBuffer) {
+
+        ByteArrayOutputStream out = new ByteArrayOutputStream();
+        int read;
+        while ((read = byteBuffer.get()) != 0) {
+            out.write(read);
+        }
+        return Utf8.convert(out.toByteArray());
+    }
+
+    public static String readString(ByteBuffer byteBuffer, int length) {
+        byte[] buffer = new byte[length];
+        byteBuffer.get(buffer);
+        return Utf8.convert(buffer);
+
+    }
+
+    public static long readUInt64(ByteBuffer byteBuffer) {
+        long result = 0;
+        // thanks to Erik Nicolas for finding a bug! Cast to long is definitivly needed
+        result += readUInt32(byteBuffer) << 32;
+        if (result < 0) {
+            throw new RuntimeException("I don't know how to deal with UInt64! long is not sufficient and I don't want to use BigInt");
+        }
+        result += readUInt32(byteBuffer);
+
+        return result;
+    }
+
+    public static double readFixedPoint1616(ByteBuffer bb) {
+        byte[] bytes = new byte[4];
+        bb.get(bytes);
+
+        int result = 0;
+        result |= ((bytes[0] << 24) & 0xFF000000);
+        result |= ((bytes[1] << 16) & 0xFF0000);
+        result |= ((bytes[2] << 8) & 0xFF00);
+        result |= ((bytes[3]) & 0xFF);
+        return ((double) result) / 65536;
+
+    }
+
+    public static float readFixedPoint88(ByteBuffer bb) {
+        byte[] bytes = new byte[2];
+        bb.get(bytes);
+        short result = 0;
+        result |= ((bytes[0] << 8) & 0xFF00);
+        result |= ((bytes[1]) & 0xFF);
+        return ((float) result) / 256;
+    }
+
+    public static String readIso639(ByteBuffer bb) {
+        int bits = readUInt16(bb);
+        StringBuilder result = new StringBuilder();
+        for (int i = 0; i < 3; i++) {
+            int c = (bits >> (2 - i) * 5) & 0x1f;
+            result.append((char) (c + 0x60));
+        }
+        return result.toString();
+    }
+
+    public static String read4cc(ByteBuffer bb) {
+        byte[] b = new byte[4];
+        bb.get(b);
+        return IsoFile.bytesToFourCC(b);
+    }
+
+}
diff --git a/isoparser/src/main/java/com/coremedia/iso/IsoTypeReaderVariable.java b/isoparser/src/main/java/com/coremedia/iso/IsoTypeReaderVariable.java
new file mode 100644
index 0000000..a2e4681
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/IsoTypeReaderVariable.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright 2012 Sebastian Annies, Hamburg
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.coremedia.iso;
+
+import java.nio.ByteBuffer;
+
+public final class IsoTypeReaderVariable {
+
+    public static long read(ByteBuffer bb, int bytes) {
+        switch (bytes) {
+            case 1:
+                return IsoTypeReader.readUInt8(bb);
+            case 2:
+                return IsoTypeReader.readUInt16(bb);
+            case 3:
+                return IsoTypeReader.readUInt24(bb);
+            case 4:
+                return IsoTypeReader.readUInt32(bb);
+            case 8:
+                return IsoTypeReader.readUInt64(bb);
+            default:
+                throw new RuntimeException("I don't know how to read " + bytes + " bytes");
+        }
+
+    }
+}
diff --git a/isoparser/src/main/java/com/coremedia/iso/IsoTypeWriter.java b/isoparser/src/main/java/com/coremedia/iso/IsoTypeWriter.java
new file mode 100644
index 0000000..6da6998
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/IsoTypeWriter.java
@@ -0,0 +1,95 @@
+/*
+ * Copyright 2012 Sebastian Annies, Hamburg
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.coremedia.iso;
+
+import java.nio.ByteBuffer;
+
+public final class IsoTypeWriter {
+
+    public static void writeUInt64(ByteBuffer bb, long u) {
+        bb.putLong(u);
+    }
+
+    public static void writeUInt32(ByteBuffer bb, long u) {
+        bb.putInt((int) u);
+
+    }
+
+    public static void writeUInt32BE(ByteBuffer bb, long u) {
+        assert u >= 0 && u <= 1L << 32 : "The given long is not in the range of uint32 (" + u + ")";
+        writeUInt16BE(bb, (int) u & 0xFFFF);
+        writeUInt16BE(bb, (int) ((u >> 16) & 0xFFFF));
+
+    }
+
+
+    public static void writeUInt24(ByteBuffer bb, int i) {
+        i = i & 0xFFFFFF;
+        writeUInt16(bb, i >> 8);
+        writeUInt8(bb, i);
+
+    }
+
+
+    public static void writeUInt16(ByteBuffer bb, int i) {
+        i = i & 0xFFFF;
+        writeUInt8(bb, i >> 8);
+        writeUInt8(bb, i & 0xFF);
+    }
+
+    public static void writeUInt16BE(ByteBuffer bb, int i) {
+        i = i & 0xFFFF;
+        writeUInt8(bb, i & 0xFF);
+        writeUInt8(bb, i >> 8);
+    }
+
+    public static void writeUInt8(ByteBuffer bb, int i) {
+        i = i & 0xFF;
+        bb.put((byte) i);
+    }
+
+
+    public static void writeFixedPont1616(ByteBuffer bb, double v) {
+        int result = (int) (v * 65536);
+        bb.put((byte) ((result & 0xFF000000) >> 24));
+        bb.put((byte) ((result & 0x00FF0000) >> 16));
+        bb.put((byte) ((result & 0x0000FF00) >> 8));
+        bb.put((byte) ((result & 0x000000FF)));
+    }
+
+    public static void writeFixedPont88(ByteBuffer bb, double v) {
+        short result = (short) (v * 256);
+        bb.put((byte) ((result & 0xFF00) >> 8));
+        bb.put((byte) ((result & 0x00FF)));
+    }
+
+    public static void writeIso639(ByteBuffer bb, String language) {
+        if (language.getBytes().length != 3) {
+            throw new IllegalArgumentException("\"" + language + "\" language string isn't exactly 3 characters long!");
+        }
+        int bits = 0;
+        for (int i = 0; i < 3; i++) {
+            bits += (language.getBytes()[i] - 0x60) << (2 - i) * 5;
+        }
+        writeUInt16(bb, bits);
+    }
+
+    public static void writeUtf8String(ByteBuffer bb, String string) {
+
+        bb.put(Utf8.convert(string));
+        writeUInt8(bb, 0);
+    }
+}
diff --git a/isoparser/src/main/java/com/coremedia/iso/IsoTypeWriterVariable.java b/isoparser/src/main/java/com/coremedia/iso/IsoTypeWriterVariable.java
new file mode 100644
index 0000000..3b3bdd4
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/IsoTypeWriterVariable.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2012 Sebastian Annies, Hamburg
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.coremedia.iso;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+
+public final class IsoTypeWriterVariable {
+
+    public static void write(long v, ByteBuffer bb, int bytes) {
+        switch (bytes) {
+            case 1:
+                IsoTypeWriter.writeUInt8(bb, (int) (v & 0xff));
+                break;
+            case 2:
+                IsoTypeWriter.writeUInt16(bb, (int) (v & 0xffff));
+                break;
+            case 3:
+                IsoTypeWriter.writeUInt24(bb, (int) (v & 0xffffff));
+                break;
+            case 4:
+                IsoTypeWriter.writeUInt32(bb, v);
+                break;
+            case 8:
+                IsoTypeWriter.writeUInt64(bb, v);
+                break;
+            default:
+                throw new RuntimeException("I don't know how to read " + bytes + " bytes");
+        }
+
+    }
+}
diff --git a/isoparser/src/main/java/com/coremedia/iso/PropertyBoxParserImpl.java b/isoparser/src/main/java/com/coremedia/iso/PropertyBoxParserImpl.java
new file mode 100644
index 0000000..f1bcc01
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/PropertyBoxParserImpl.java
@@ -0,0 +1,199 @@
+/*
+ * Copyright 2012 Sebastian Annies, Hamburg
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.coremedia.iso;
+
+import com.googlecode.mp4parser.AbstractBox;
+import com.coremedia.iso.boxes.Box;
+
+import java.io.BufferedInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationTargetException;
+import java.net.URL;
+import java.util.Enumeration;
+import java.util.Properties;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * A Property file based BoxFactory
+ */
+public class PropertyBoxParserImpl extends AbstractBoxParser {
+    Properties mapping;
+
+    public PropertyBoxParserImpl(String... customProperties) {
+        InputStream is = new BufferedInputStream(getClass().getResourceAsStream("/isoparser-default.properties"));
+        try {
+            mapping = new Properties();
+            try {
+                mapping.load(is);
+                Enumeration<URL> enumeration = Thread.currentThread().getContextClassLoader().getResources("isoparser-custom.properties");
+
+                while (enumeration.hasMoreElements()) {
+                    URL url = enumeration.nextElement();
+                    InputStream customIS = new BufferedInputStream(url.openStream());
+                    try {
+                        mapping.load(customIS);
+                    } finally {
+                        customIS.close();
+                    }
+                }
+                for (String customProperty : customProperties) {
+                    mapping.load(new BufferedInputStream(getClass().getResourceAsStream(customProperty)));
+                }
+            } catch (IOException e) {
+                throw new RuntimeException(e);
+            }
+        } finally {
+            try {
+                is.close();
+            } catch (IOException e) {
+                e.printStackTrace();
+                // ignore - I can't help
+            }
+        }
+    }
+
+    public PropertyBoxParserImpl(Properties mapping) {
+        this.mapping = mapping;
+    }
+
+    Pattern p = Pattern.compile("(.*)\\((.*?)\\)");
+
+    @SuppressWarnings("unchecked")
+    public Class<? extends Box> getClassForFourCc(String type, byte[] userType, String parent) {
+        FourCcToBox fourCcToBox = new FourCcToBox(type, userType, parent).invoke();
+        try {
+            return (Class<? extends Box>) Class.forName(fourCcToBox.clazzName);
+        } catch (ClassNotFoundException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    @Override
+    public Box createBox(String type, byte[] userType, String parent) {
+
+        FourCcToBox fourCcToBox = new FourCcToBox(type, userType, parent).invoke();
+        String[] param = fourCcToBox.getParam();
+        String clazzName = fourCcToBox.getClazzName();
+        try {
+            if (param[0].trim().length() == 0) {
+                param = new String[]{};
+            }
+            Class clazz = Class.forName(clazzName);
+
+            Class[] constructorArgsClazz = new Class[param.length];
+            Object[] constructorArgs = new Object[param.length];
+            for (int i = 0; i < param.length; i++) {
+
+                if ("userType".equals(param[i])) {
+                    constructorArgs[i] = userType;
+                    constructorArgsClazz[i] = byte[].class;
+                } else if ("type".equals(param[i])) {
+                    constructorArgs[i] = type;
+                    constructorArgsClazz[i] = String.class;
+                } else if ("parent".equals(param[i])) {
+                    constructorArgs[i] = parent;
+                    constructorArgsClazz[i] = String.class;
+                } else {
+                    throw new InternalError("No such param: " + param[i]);
+                }
+
+
+            }
+            Constructor<AbstractBox> constructorObject;
+            try {
+                if (param.length > 0) {
+                    constructorObject = clazz.getConstructor(constructorArgsClazz);
+                } else {
+                    constructorObject = clazz.getConstructor();
+                }
+
+                return constructorObject.newInstance(constructorArgs);
+            } catch (NoSuchMethodException e) {
+                throw new RuntimeException(e);
+            } catch (InvocationTargetException e) {
+                throw new RuntimeException(e);
+            } catch (InstantiationException e) {
+                throw new RuntimeException(e);
+            } catch (IllegalAccessException e) {
+                throw new RuntimeException(e);
+            }
+
+
+        } catch (ClassNotFoundException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    private class FourCcToBox {
+        private String type;
+        private byte[] userType;
+        private String parent;
+        private String clazzName;
+        private String[] param;
+
+        public FourCcToBox(String type, byte[] userType, String parent) {
+            this.type = type;
+            this.parent = parent;
+            this.userType = userType;
+        }
+
+        public String getClazzName() {
+            return clazzName;
+        }
+
+        public String[] getParam() {
+            return param;
+        }
+
+        public FourCcToBox invoke() {
+            String constructor;
+            if (userType != null) {
+                if (!"uuid".equals((type))) {
+                    throw new RuntimeException("we have a userType but no uuid box type. Something's wrong");
+                }
+                constructor = mapping.getProperty((parent) + "-uuid[" + Hex.encodeHex(userType).toUpperCase() + "]");
+                if (constructor == null) {
+                    constructor = mapping.getProperty("uuid[" + Hex.encodeHex(userType).toUpperCase() + "]");
+                }
+                if (constructor == null) {
+                    constructor = mapping.getProperty("uuid");
+                }
+            } else {
+                constructor = mapping.getProperty((parent) + "-" + (type));
+                if (constructor == null) {
+                    constructor = mapping.getProperty((type));
+                }
+            }
+            if (constructor == null) {
+                constructor = mapping.getProperty("default");
+            }
+            if (constructor == null) {
+                throw new RuntimeException("No box object found for " + type);
+            }
+            Matcher m = p.matcher(constructor);
+            boolean matches = m.matches();
+            if (!matches) {
+                throw new RuntimeException("Cannot work with that constructor: " + constructor);
+            }
+            clazzName = m.group(1);
+            param = m.group(2).split(",");
+            return this;
+        }
+    }
+}
diff --git a/isoparser/src/main/java/com/coremedia/iso/Utf8.java b/isoparser/src/main/java/com/coremedia/iso/Utf8.java
new file mode 100644
index 0000000..a30497e
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/Utf8.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright 2012 Sebastian Annies, Hamburg
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.coremedia.iso;
+
+import java.io.UnsupportedEncodingException;
+
+/**
+ * Converts <code>byte[]</code> -> <code>String</code> and vice versa.
+ */
+public final class Utf8 {
+    public static byte[] convert(String s) {
+        try {
+            if (s != null) {
+                return s.getBytes("UTF-8");
+            } else {
+                return null;
+            }
+        } catch (UnsupportedEncodingException e) {
+            throw new Error(e);
+        }
+    }
+
+    public static String convert(byte[] b) {
+        try {
+            if (b != null) {
+                return new String(b, "UTF-8");
+            } else {
+                return null;
+            }
+        } catch (UnsupportedEncodingException e) {
+            throw new Error(e);
+        }
+    }
+
+    public static int utf8StringLengthInBytes(String utf8) {
+        try {
+            if (utf8 != null) {
+                return utf8.getBytes("UTF-8").length;
+            } else {
+                return 0;
+            }
+        } catch (UnsupportedEncodingException e) {
+            throw new RuntimeException();
+        }
+    }
+}
diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/.svn/all-wcprops b/isoparser/src/main/java/com/coremedia/iso/boxes/.svn/all-wcprops
new file mode 100644
index 0000000..8c356fa
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/.svn/all-wcprops
@@ -0,0 +1,443 @@
+K 25
+svn:wc:ra_dav:version-url
+V 71
+/svn/!svn/ver/777/trunk/isoparser/src/main/java/com/coremedia/iso/boxes
+END
+DataReferenceBox.java
+K 25
+svn:wc:ra_dav:version-url
+V 93
+/svn/!svn/ver/507/trunk/isoparser/src/main/java/com/coremedia/iso/boxes/DataReferenceBox.java
+END
+ChunkOffset64BitBox.java
+K 25
+svn:wc:ra_dav:version-url
+V 96
+/svn/!svn/ver/507/trunk/isoparser/src/main/java/com/coremedia/iso/boxes/ChunkOffset64BitBox.java
+END
+ItemDataBox.java
+K 25
+svn:wc:ra_dav:version-url
+V 88
+/svn/!svn/ver/507/trunk/isoparser/src/main/java/com/coremedia/iso/boxes/ItemDataBox.java
+END
+BitRateBox.java
+K 25
+svn:wc:ra_dav:version-url
+V 87
+/svn/!svn/ver/507/trunk/isoparser/src/main/java/com/coremedia/iso/boxes/BitRateBox.java
+END
+UnknownBox.java
+K 25
+svn:wc:ra_dav:version-url
+V 87
+/svn/!svn/ver/507/trunk/isoparser/src/main/java/com/coremedia/iso/boxes/UnknownBox.java
+END
+XmlBox.java
+K 25
+svn:wc:ra_dav:version-url
+V 83
+/svn/!svn/ver/624/trunk/isoparser/src/main/java/com/coremedia/iso/boxes/XmlBox.java
+END
+CompositionShiftLeastGreatestAtom.java
+K 25
+svn:wc:ra_dav:version-url
+V 110
+/svn/!svn/ver/507/trunk/isoparser/src/main/java/com/coremedia/iso/boxes/CompositionShiftLeastGreatestAtom.java
+END
+TrackBox.java
+K 25
+svn:wc:ra_dav:version-url
+V 85
+/svn/!svn/ver/505/trunk/isoparser/src/main/java/com/coremedia/iso/boxes/TrackBox.java
+END
+ItemProtectionBox.java
+K 25
+svn:wc:ra_dav:version-url
+V 94
+/svn/!svn/ver/507/trunk/isoparser/src/main/java/com/coremedia/iso/boxes/ItemProtectionBox.java
+END
+SampleAuxiliaryInformationOffsetsBox.java
+K 25
+svn:wc:ra_dav:version-url
+V 113
+/svn/!svn/ver/507/trunk/isoparser/src/main/java/com/coremedia/iso/boxes/SampleAuxiliaryInformationOffsetsBox.java
+END
+SchemeInformationBox.java
+K 25
+svn:wc:ra_dav:version-url
+V 97
+/svn/!svn/ver/505/trunk/isoparser/src/main/java/com/coremedia/iso/boxes/SchemeInformationBox.java
+END
+OmaDrmAccessUnitFormatBox.java
+K 25
+svn:wc:ra_dav:version-url
+V 102
+/svn/!svn/ver/507/trunk/isoparser/src/main/java/com/coremedia/iso/boxes/OmaDrmAccessUnitFormatBox.java
+END
+HintMediaHeaderBox.java
+K 25
+svn:wc:ra_dav:version-url
+V 95
+/svn/!svn/ver/507/trunk/isoparser/src/main/java/com/coremedia/iso/boxes/HintMediaHeaderBox.java
+END
+SampleSizeBox.java
+K 25
+svn:wc:ra_dav:version-url
+V 90
+/svn/!svn/ver/507/trunk/isoparser/src/main/java/com/coremedia/iso/boxes/SampleSizeBox.java
+END
+TrackHeaderBox.java
+K 25
+svn:wc:ra_dav:version-url
+V 91
+/svn/!svn/ver/507/trunk/isoparser/src/main/java/com/coremedia/iso/boxes/TrackHeaderBox.java
+END
+CompositionTimeToSample.java
+K 25
+svn:wc:ra_dav:version-url
+V 100
+/svn/!svn/ver/507/trunk/isoparser/src/main/java/com/coremedia/iso/boxes/CompositionTimeToSample.java
+END
+UserBox.java
+K 25
+svn:wc:ra_dav:version-url
+V 84
+/svn/!svn/ver/507/trunk/isoparser/src/main/java/com/coremedia/iso/boxes/UserBox.java
+END
+MediaBox.java
+K 25
+svn:wc:ra_dav:version-url
+V 85
+/svn/!svn/ver/505/trunk/isoparser/src/main/java/com/coremedia/iso/boxes/MediaBox.java
+END
+DataInformationBox.java
+K 25
+svn:wc:ra_dav:version-url
+V 95
+/svn/!svn/ver/505/trunk/isoparser/src/main/java/com/coremedia/iso/boxes/DataInformationBox.java
+END
+FileTypeBox.java
+K 25
+svn:wc:ra_dav:version-url
+V 88
+/svn/!svn/ver/580/trunk/isoparser/src/main/java/com/coremedia/iso/boxes/FileTypeBox.java
+END
+FreeBox.java
+K 25
+svn:wc:ra_dav:version-url
+V 84
+/svn/!svn/ver/668/trunk/isoparser/src/main/java/com/coremedia/iso/boxes/FreeBox.java
+END
+TitleBox.java
+K 25
+svn:wc:ra_dav:version-url
+V 85
+/svn/!svn/ver/507/trunk/isoparser/src/main/java/com/coremedia/iso/boxes/TitleBox.java
+END
+NullMediaHeaderBox.java
+K 25
+svn:wc:ra_dav:version-url
+V 95
+/svn/!svn/ver/507/trunk/isoparser/src/main/java/com/coremedia/iso/boxes/NullMediaHeaderBox.java
+END
+SampleDescriptionBox.java
+K 25
+svn:wc:ra_dav:version-url
+V 97
+/svn/!svn/ver/507/trunk/isoparser/src/main/java/com/coremedia/iso/boxes/SampleDescriptionBox.java
+END
+StaticChunkOffsetBox.java
+K 25
+svn:wc:ra_dav:version-url
+V 97
+/svn/!svn/ver/507/trunk/isoparser/src/main/java/com/coremedia/iso/boxes/StaticChunkOffsetBox.java
+END
+WriteListener.java
+K 25
+svn:wc:ra_dav:version-url
+V 89
+/svn/!svn/ver/98/trunk/isoparser/src/main/java/com/coremedia/iso/boxes/WriteListener.java
+END
+RecordingYearBox.java
+K 25
+svn:wc:ra_dav:version-url
+V 93
+/svn/!svn/ver/507/trunk/isoparser/src/main/java/com/coremedia/iso/boxes/RecordingYearBox.java
+END
+PerformerBox.java
+K 25
+svn:wc:ra_dav:version-url
+V 89
+/svn/!svn/ver/507/trunk/isoparser/src/main/java/com/coremedia/iso/boxes/PerformerBox.java
+END
+AuthorBox.java
+K 25
+svn:wc:ra_dav:version-url
+V 86
+/svn/!svn/ver/507/trunk/isoparser/src/main/java/com/coremedia/iso/boxes/AuthorBox.java
+END
+SubtitleMediaHeaderBox.java
+K 25
+svn:wc:ra_dav:version-url
+V 99
+/svn/!svn/ver/507/trunk/isoparser/src/main/java/com/coremedia/iso/boxes/SubtitleMediaHeaderBox.java
+END
+ObjectDescriptorBox.java
+K 25
+svn:wc:ra_dav:version-url
+V 95
+/svn/!svn/ver/84/trunk/isoparser/src/main/java/com/coremedia/iso/boxes/ObjectDescriptorBox.java
+END
+SchemeTypeBox.java
+K 25
+svn:wc:ra_dav:version-url
+V 90
+/svn/!svn/ver/507/trunk/isoparser/src/main/java/com/coremedia/iso/boxes/SchemeTypeBox.java
+END
+KeywordsBox.java
+K 25
+svn:wc:ra_dav:version-url
+V 88
+/svn/!svn/ver/507/trunk/isoparser/src/main/java/com/coremedia/iso/boxes/KeywordsBox.java
+END
+AbstractMediaHeaderBox.java
+K 25
+svn:wc:ra_dav:version-url
+V 99
+/svn/!svn/ver/505/trunk/isoparser/src/main/java/com/coremedia/iso/boxes/AbstractMediaHeaderBox.java
+END
+HandlerBox.java
+K 25
+svn:wc:ra_dav:version-url
+V 87
+/svn/!svn/ver/507/trunk/isoparser/src/main/java/com/coremedia/iso/boxes/HandlerBox.java
+END
+OriginalFormatBox.java
+K 25
+svn:wc:ra_dav:version-url
+V 94
+/svn/!svn/ver/507/trunk/isoparser/src/main/java/com/coremedia/iso/boxes/OriginalFormatBox.java
+END
+SampleToChunkBox.java
+K 25
+svn:wc:ra_dav:version-url
+V 93
+/svn/!svn/ver/507/trunk/isoparser/src/main/java/com/coremedia/iso/boxes/SampleToChunkBox.java
+END
+Box.java
+K 25
+svn:wc:ra_dav:version-url
+V 80
+/svn/!svn/ver/510/trunk/isoparser/src/main/java/com/coremedia/iso/boxes/Box.java
+END
+DescriptionBox.java
+K 25
+svn:wc:ra_dav:version-url
+V 91
+/svn/!svn/ver/507/trunk/isoparser/src/main/java/com/coremedia/iso/boxes/DescriptionBox.java
+END
+EditBox.java
+K 25
+svn:wc:ra_dav:version-url
+V 84
+/svn/!svn/ver/505/trunk/isoparser/src/main/java/com/coremedia/iso/boxes/EditBox.java
+END
+ItemLocationBox.java
+K 25
+svn:wc:ra_dav:version-url
+V 92
+/svn/!svn/ver/507/trunk/isoparser/src/main/java/com/coremedia/iso/boxes/ItemLocationBox.java
+END
+MovieHeaderBox.java
+K 25
+svn:wc:ra_dav:version-url
+V 91
+/svn/!svn/ver/688/trunk/isoparser/src/main/java/com/coremedia/iso/boxes/MovieHeaderBox.java
+END
+ClassificationBox.java
+K 25
+svn:wc:ra_dav:version-url
+V 94
+/svn/!svn/ver/507/trunk/isoparser/src/main/java/com/coremedia/iso/boxes/ClassificationBox.java
+END
+odf-boxes.zip
+K 25
+svn:wc:ra_dav:version-url
+V 85
+/svn/!svn/ver/377/trunk/isoparser/src/main/java/com/coremedia/iso/boxes/odf-boxes.zip
+END
+GenreBox.java
+K 25
+svn:wc:ra_dav:version-url
+V 85
+/svn/!svn/ver/507/trunk/isoparser/src/main/java/com/coremedia/iso/boxes/GenreBox.java
+END
+AlbumBox.java
+K 25
+svn:wc:ra_dav:version-url
+V 85
+/svn/!svn/ver/507/trunk/isoparser/src/main/java/com/coremedia/iso/boxes/AlbumBox.java
+END
+SubSampleInformationBox.java
+K 25
+svn:wc:ra_dav:version-url
+V 100
+/svn/!svn/ver/507/trunk/isoparser/src/main/java/com/coremedia/iso/boxes/SubSampleInformationBox.java
+END
+FullBox.java
+K 25
+svn:wc:ra_dav:version-url
+V 84
+/svn/!svn/ver/505/trunk/isoparser/src/main/java/com/coremedia/iso/boxes/FullBox.java
+END
+TimeToSampleBox.java
+K 25
+svn:wc:ra_dav:version-url
+V 92
+/svn/!svn/ver/507/trunk/isoparser/src/main/java/com/coremedia/iso/boxes/TimeToSampleBox.java
+END
+UserDataBox.java
+K 25
+svn:wc:ra_dav:version-url
+V 88
+/svn/!svn/ver/507/trunk/isoparser/src/main/java/com/coremedia/iso/boxes/UserDataBox.java
+END
+CopyrightBox.java
+K 25
+svn:wc:ra_dav:version-url
+V 89
+/svn/!svn/ver/507/trunk/isoparser/src/main/java/com/coremedia/iso/boxes/CopyrightBox.java
+END
+SyncSampleBox.java
+K 25
+svn:wc:ra_dav:version-url
+V 90
+/svn/!svn/ver/507/trunk/isoparser/src/main/java/com/coremedia/iso/boxes/SyncSampleBox.java
+END
+ChunkOffsetBox.java
+K 25
+svn:wc:ra_dav:version-url
+V 91
+/svn/!svn/ver/505/trunk/isoparser/src/main/java/com/coremedia/iso/boxes/ChunkOffsetBox.java
+END
+RatingBox.java
+K 25
+svn:wc:ra_dav:version-url
+V 86
+/svn/!svn/ver/507/trunk/isoparser/src/main/java/com/coremedia/iso/boxes/RatingBox.java
+END
+TrackReferenceTypeBox.java
+K 25
+svn:wc:ra_dav:version-url
+V 98
+/svn/!svn/ver/507/trunk/isoparser/src/main/java/com/coremedia/iso/boxes/TrackReferenceTypeBox.java
+END
+MetaBox.java
+K 25
+svn:wc:ra_dav:version-url
+V 84
+/svn/!svn/ver/507/trunk/isoparser/src/main/java/com/coremedia/iso/boxes/MetaBox.java
+END
+MediaHeaderBox.java
+K 25
+svn:wc:ra_dav:version-url
+V 91
+/svn/!svn/ver/616/trunk/isoparser/src/main/java/com/coremedia/iso/boxes/MediaHeaderBox.java
+END
+SampleTableBox.java
+K 25
+svn:wc:ra_dav:version-url
+V 91
+/svn/!svn/ver/505/trunk/isoparser/src/main/java/com/coremedia/iso/boxes/SampleTableBox.java
+END
+rtp-boxes.zip
+K 25
+svn:wc:ra_dav:version-url
+V 85
+/svn/!svn/ver/377/trunk/isoparser/src/main/java/com/coremedia/iso/boxes/rtp-boxes.zip
+END
+FreeSpaceBox.java
+K 25
+svn:wc:ra_dav:version-url
+V 89
+/svn/!svn/ver/507/trunk/isoparser/src/main/java/com/coremedia/iso/boxes/FreeSpaceBox.java
+END
+SampleAuxiliaryInformationSizesBox.java
+K 25
+svn:wc:ra_dav:version-url
+V 111
+/svn/!svn/ver/727/trunk/isoparser/src/main/java/com/coremedia/iso/boxes/SampleAuxiliaryInformationSizesBox.java
+END
+SoundMediaHeaderBox.java
+K 25
+svn:wc:ra_dav:version-url
+V 96
+/svn/!svn/ver/507/trunk/isoparser/src/main/java/com/coremedia/iso/boxes/SoundMediaHeaderBox.java
+END
+ProgressiveDownloadInformationBox.java
+K 25
+svn:wc:ra_dav:version-url
+V 110
+/svn/!svn/ver/507/trunk/isoparser/src/main/java/com/coremedia/iso/boxes/ProgressiveDownloadInformationBox.java
+END
+DataEntryUrlBox.java
+K 25
+svn:wc:ra_dav:version-url
+V 92
+/svn/!svn/ver/507/trunk/isoparser/src/main/java/com/coremedia/iso/boxes/DataEntryUrlBox.java
+END
+VideoMediaHeaderBox.java
+K 25
+svn:wc:ra_dav:version-url
+V 96
+/svn/!svn/ver/507/trunk/isoparser/src/main/java/com/coremedia/iso/boxes/VideoMediaHeaderBox.java
+END
+MovieBox.java
+K 25
+svn:wc:ra_dav:version-url
+V 85
+/svn/!svn/ver/505/trunk/isoparser/src/main/java/com/coremedia/iso/boxes/MovieBox.java
+END
+DataEntryUrnBox.java
+K 25
+svn:wc:ra_dav:version-url
+V 92
+/svn/!svn/ver/507/trunk/isoparser/src/main/java/com/coremedia/iso/boxes/DataEntryUrnBox.java
+END
+ProtectionSchemeInformationBox.java
+K 25
+svn:wc:ra_dav:version-url
+V 107
+/svn/!svn/ver/505/trunk/isoparser/src/main/java/com/coremedia/iso/boxes/ProtectionSchemeInformationBox.java
+END
+EditListBox.java
+K 25
+svn:wc:ra_dav:version-url
+V 88
+/svn/!svn/ver/507/trunk/isoparser/src/main/java/com/coremedia/iso/boxes/EditListBox.java
+END
+SampleDependencyTypeBox.java
+K 25
+svn:wc:ra_dav:version-url
+V 100
+/svn/!svn/ver/507/trunk/isoparser/src/main/java/com/coremedia/iso/boxes/SampleDependencyTypeBox.java
+END
+ContainerBox.java
+K 25
+svn:wc:ra_dav:version-url
+V 89
+/svn/!svn/ver/132/trunk/isoparser/src/main/java/com/coremedia/iso/boxes/ContainerBox.java
+END
+TrackReferenceBox.java
+K 25
+svn:wc:ra_dav:version-url
+V 94
+/svn/!svn/ver/505/trunk/isoparser/src/main/java/com/coremedia/iso/boxes/TrackReferenceBox.java
+END
+MediaInformationBox.java
+K 25
+svn:wc:ra_dav:version-url
+V 96
+/svn/!svn/ver/505/trunk/isoparser/src/main/java/com/coremedia/iso/boxes/MediaInformationBox.java
+END
diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/.svn/entries b/isoparser/src/main/java/com/coremedia/iso/boxes/.svn/entries
new file mode 100644
index 0000000..abb566b
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/.svn/entries
@@ -0,0 +1,2534 @@
+10
+
+dir
+778
+http://mp4parser.googlecode.com/svn/trunk/isoparser/src/main/java/com/coremedia/iso/boxes
+http://mp4parser.googlecode.com/svn
+
+
+
+2012-09-10T14:56:10.036617Z
+777
+sebastian.annies@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+7decde4b-c250-0410-a0da-51896bc88be6
+
+DataReferenceBox.java
+file
+
+
+
+
+2012-09-14T17:27:53.057255Z
+9903c0a889788836ccc2cb2265196393
+2012-04-21T22:05:38.425329Z
+507
+Sebastian.Annies@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+2206
+
+ChunkOffset64BitBox.java
+file
+
+
+
+
+2012-09-14T17:27:53.057255Z
+01fec67b09938a06c351b1f61ddd3eca
+2012-04-21T22:05:38.425329Z
+507
+Sebastian.Annies@gmail.com
+has-props
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+1288
+
+ItemDataBox.java
+file
+
+
+
+
+2012-09-14T17:27:53.057255Z
+d89b6e2c38b3dcd74a3574131391d0c0
+2012-04-21T22:05:38.425329Z
+507
+Sebastian.Annies@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+823
+
+BitRateBox.java
+file
+
+
+
+
+2012-09-14T17:27:53.057255Z
+8b80a19e9d0180804dd3e8cdd51fe652
+2012-04-21T22:05:38.425329Z
+507
+Sebastian.Annies@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+2585
+
+UnknownBox.java
+file
+
+
+
+
+2012-09-14T17:27:53.057255Z
+6f1e688b0e1c8a5b4cb76b7e734f50d2
+2012-04-21T22:05:38.425329Z
+507
+Sebastian.Annies@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+1539
+
+XmlBox.java
+file
+
+
+
+
+2012-09-14T17:27:53.057255Z
+3466d3b5e977ee5cc212d3846f16f387
+2012-05-21T11:57:37.647327Z
+624
+Sebastian.Annies@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+1079
+
+CompositionShiftLeastGreatestAtom.java
+file
+
+
+
+
+2012-09-14T17:27:53.057255Z
+409e9d1a7bf3d4c309d7d7f5847816d3
+2012-04-21T22:05:38.425329Z
+507
+Sebastian.Annies@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+3179
+
+TrackBox.java
+file
+
+
+
+
+2012-09-14T17:27:53.057255Z
+fee5b44d47cf99419d838238864e696c
+2012-04-21T21:18:31.685061Z
+505
+Sebastian.Annies@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+2234
+
+ItemProtectionBox.java
+file
+
+
+
+
+2012-09-14T17:27:53.057255Z
+78f95c81797d21680e71c2476caf5a19
+2012-04-21T22:05:38.425329Z
+507
+Sebastian.Annies@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+1810
+
+vodafone
+dir
+
+apple
+dir
+
+SampleAuxiliaryInformationOffsetsBox.java
+file
+
+
+
+
+2012-09-14T17:27:53.057255Z
+96eb95e44d49e9cf2cc480ad6e6a44a1
+2012-04-21T22:05:38.425329Z
+507
+Sebastian.Annies@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+3773
+
+fragment
+dir
+
+OmaDrmAccessUnitFormatBox.java
+file
+
+
+
+
+2012-09-14T17:27:53.057255Z
+71e60410948a327722a34931d6b6690d
+2012-04-21T22:05:38.425329Z
+507
+Sebastian.Annies@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+2554
+
+SchemeInformationBox.java
+file
+
+
+
+
+2012-09-14T17:27:53.067255Z
+2b7467575e1b4ae45e2021528a5660ae
+2012-04-21T21:18:31.685061Z
+505
+Sebastian.Annies@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+1216
+
+HintMediaHeaderBox.java
+file
+
+
+
+
+2012-09-14T17:27:53.067255Z
+a2face08c70d66256f2c0dc7fa9397c1
+2012-04-21T22:05:38.425329Z
+507
+Sebastian.Annies@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+2682
+
+SampleSizeBox.java
+file
+
+
+
+
+2012-09-14T17:27:53.067255Z
+8574502d967dcb457f9760c4613e9c60
+2012-04-21T22:05:38.425329Z
+507
+Sebastian.Annies@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+3416
+
+TrackHeaderBox.java
+file
+
+
+
+
+2012-09-14T17:27:53.067255Z
+c545735fa9f6b46b6ddaa97fa191b6ed
+2012-04-21T22:05:38.425329Z
+507
+Sebastian.Annies@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+7950
+
+CompositionTimeToSample.java
+file
+
+
+
+
+2012-09-14T17:27:53.067255Z
+24d6bf8af948cf9724c9c6b963d60e05
+2012-04-21T22:05:38.425329Z
+507
+Sebastian.Annies@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+4123
+
+UserBox.java
+file
+
+
+
+
+2012-09-14T17:27:53.067255Z
+b2c4353c1cdfb1ae08f404b7d4c6e88a
+2012-04-21T22:05:38.425329Z
+507
+Sebastian.Annies@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+1629
+
+MediaBox.java
+file
+
+
+
+
+2012-09-14T17:27:53.067255Z
+8903b483282e444e19e09019396588e3
+2012-04-21T21:18:31.685061Z
+505
+Sebastian.Annies@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+1675
+
+DataInformationBox.java
+file
+
+
+
+
+2012-09-14T17:27:53.067255Z
+c06ffa206dbc8a97dab729e7e9d16127
+2012-04-21T21:18:31.685061Z
+505
+Sebastian.Annies@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+1169
+
+FileTypeBox.java
+file
+
+
+
+
+2012-09-14T17:27:53.067255Z
+019751b42d06e4caa726c38102be4820
+2012-05-04T18:32:18.338607Z
+580
+Sebastian.Annies@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+4381
+
+FreeBox.java
+file
+
+
+
+
+2012-09-14T17:27:53.067255Z
+05c03ad86d424b209975515c10e27143
+2012-06-08T10:14:31.301984Z
+668
+Sebastian.Annies@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+3395
+
+TitleBox.java
+file
+
+
+
+
+2012-09-14T17:27:53.067255Z
+f4b9dbcee26737350024b0d15e2aed1c
+2012-04-21T22:05:38.425329Z
+507
+Sebastian.Annies@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+2326
+
+NullMediaHeaderBox.java
+file
+
+
+
+
+2012-09-14T17:27:53.067255Z
+2085a3a59a3ad7387eabc995525b0ac3
+2012-04-21T22:05:38.425329Z
+507
+Sebastian.Annies@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+1228
+
+SampleDescriptionBox.java
+file
+
+
+
+
+2012-09-14T17:27:53.067255Z
+a0c4559c8d7c474e32f6c491a82b78c7
+2012-04-21T22:05:38.425329Z
+507
+Sebastian.Annies@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+3328
+
+WriteListener.java
+file
+
+
+
+
+2012-09-14T17:27:53.067255Z
+3af0a5ef179d43c4bcbec9f9981dc397
+2011-03-09T17:58:20.876792Z
+98
+Sebastian.Annies@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+277
+
+StaticChunkOffsetBox.java
+file
+
+
+
+
+2012-09-14T17:27:53.067255Z
+fdb4124cdbd7503e86559be883fabbe9
+2012-04-21T22:05:38.425329Z
+507
+Sebastian.Annies@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+2079
+
+mdat
+dir
+
+RecordingYearBox.java
+file
+
+
+
+
+2012-09-14T17:27:53.067255Z
+18244842b093dc4f2afed5e2fe83051f
+2012-04-21T22:05:38.425329Z
+507
+Sebastian.Annies@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+1602
+
+PerformerBox.java
+file
+
+
+
+
+2012-09-14T17:27:53.067255Z
+d1807b59f86c3b1c078f5424485504f3
+2012-04-21T22:05:38.425329Z
+507
+Sebastian.Annies@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+2225
+
+AuthorBox.java
+file
+
+
+
+
+2012-09-14T17:27:53.067255Z
+d277c32f45368d98c0e7f284b53af023
+2012-04-21T22:05:38.425329Z
+507
+Sebastian.Annies@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+2625
+
+SubtitleMediaHeaderBox.java
+file
+
+
+
+
+2012-09-14T17:27:53.067255Z
+2d0a0d6508e401d64bba308335167c8f
+2012-04-21T22:05:38.425329Z
+507
+Sebastian.Annies@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+619
+
+ObjectDescriptorBox.java
+file
+
+
+
+
+2012-09-14T17:27:53.067255Z
+d41d8cd98f00b204e9800998ecf8427e
+2011-02-24T14:29:07.487725Z
+84
+Sebastian.Annies@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+0
+
+SchemeTypeBox.java
+file
+
+
+
+
+2012-09-14T17:27:53.067255Z
+e5aac0ed26846099c0c9b3901c605d34
+2012-04-21T22:05:38.425329Z
+507
+Sebastian.Annies@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+3147
+
+KeywordsBox.java
+file
+
+
+
+
+2012-09-14T17:27:53.067255Z
+1b30dd2dd9a4a2cc71dbbd93673454c5
+2012-04-21T22:05:38.425329Z
+507
+Sebastian.Annies@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+2884
+
+dece
+dir
+
+sampleentry
+dir
+
+AbstractMediaHeaderBox.java
+file
+
+
+
+
+2012-09-14T17:27:53.067255Z
+fae5d0df177984d5429ec108759ff0ea
+2012-04-21T21:18:31.685061Z
+505
+Sebastian.Annies@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+989
+
+HandlerBox.java
+file
+
+
+
+
+2012-09-14T17:27:53.067255Z
+7d0687f791f2a2a762df2ddb743fa15f
+2012-04-21T22:05:38.425329Z
+507
+Sebastian.Annies@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+5425
+
+OriginalFormatBox.java
+file
+
+
+
+
+2012-09-14T17:27:53.067255Z
+ddb06cb6a4fdf016e8d74b02a916f026
+2012-04-21T22:05:38.425329Z
+507
+Sebastian.Annies@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+1844
+
+SampleToChunkBox.java
+file
+
+
+
+
+2012-09-14T17:27:53.067255Z
+bfe8cb30f157785f58eacf5e7e61033a
+2012-04-21T22:05:38.425329Z
+507
+Sebastian.Annies@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+5178
+
+Box.java
+file
+
+
+
+
+2012-09-14T17:27:53.067255Z
+85e9f91cd74a90a0796c556689a72972
+2012-04-22T09:16:09.151890Z
+510
+Sebastian.Annies@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+1677
+
+DescriptionBox.java
+file
+
+
+
+
+2012-09-14T17:27:53.067255Z
+64c10e153fbfc1dea0c14fe48ebf0a55
+2012-04-21T22:05:38.425329Z
+507
+Sebastian.Annies@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+2207
+
+EditBox.java
+file
+
+
+
+
+2012-09-14T17:27:53.067255Z
+75252edf8148360e335ebac2f838118f
+2012-04-21T21:18:31.685061Z
+505
+Sebastian.Annies@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+1066
+
+ItemLocationBox.java
+file
+
+
+
+
+2012-09-14T17:27:53.067255Z
+3e27a64bf1fd101c7fd324d9cdbb7f21
+2012-04-21T22:05:38.425329Z
+507
+Sebastian.Annies@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+10845
+
+MovieHeaderBox.java
+file
+
+
+
+
+2012-09-14T17:27:53.067255Z
+d1eececbea781c89399d83dca0ecf5a0
+2012-06-24T21:02:28.697657Z
+688
+Sebastian.Annies@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+8025
+
+h264
+dir
+
+ClassificationBox.java
+file
+
+
+
+
+2012-09-14T17:27:53.067255Z
+a61f9cac340a30bfe69bbd3866a8179e
+2012-04-21T22:05:38.425329Z
+507
+Sebastian.Annies@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+3544
+
+odf-boxes.zip
+file
+
+
+
+
+2012-09-14T17:27:53.067255Z
+4c8dc9b701c5de0144269f58d168f621
+2012-03-05T23:28:24.666173Z
+377
+Sebastian.Annies@gmail.com
+has-props
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+37706
+
+GenreBox.java
+file
+
+
+
+
+2012-09-14T17:27:53.077255Z
+8a42cc14e1f999aa99bbe26675991dc7
+2012-04-21T22:05:38.425329Z
+507
+Sebastian.Annies@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+2162
+
+AlbumBox.java
+file
+
+
+
+
+2012-09-14T17:27:53.067255Z
+063882f7ab178937a59190ff933ed1cf
+2012-04-21T22:05:38.425329Z
+507
+Sebastian.Annies@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+3360
+
+SubSampleInformationBox.java
+file
+
+
+
+
+2012-09-14T17:27:53.077255Z
+62c871d625fa41c8c5667b60e1a96084
+2012-04-21T22:05:38.425329Z
+507
+Sebastian.Annies@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+7003
+
+FullBox.java
+file
+
+
+
+
+2012-09-14T17:27:53.077255Z
+b25b6cfe0af3936de4507b280c9a80f9
+2012-04-21T21:18:31.685061Z
+505
+Sebastian.Annies@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+375
+
+TimeToSampleBox.java
+file
+
+
+
+
+2012-09-14T17:27:53.077255Z
+87761496666ed6ed43d1055c39daec07
+2012-04-21T22:05:38.425329Z
+507
+Sebastian.Annies@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+4719
+
+UserDataBox.java
+file
+
+
+
+
+2012-09-14T17:27:53.077255Z
+44ba8dc0558f53582186a9fb4bd937e5
+2012-04-21T22:05:38.425329Z
+507
+Sebastian.Annies@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+2209
+
+CopyrightBox.java
+file
+
+
+
+
+2012-09-14T17:27:53.077255Z
+d3fa4843e4ca4973476a0243b1e90c76
+2012-04-21T22:05:38.425329Z
+507
+Sebastian.Annies@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+2386
+
+SyncSampleBox.java
+file
+
+
+
+
+2012-09-14T17:27:53.077255Z
+e88379417c7537d02c2bdd14c16d2d98
+2012-04-21T22:05:38.425329Z
+507
+Sebastian.Annies@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+2444
+
+ChunkOffsetBox.java
+file
+
+
+
+
+2012-09-14T17:27:53.077255Z
+2a7cb5f28a7c28ff4125e73e44027e00
+2012-04-21T21:18:31.685061Z
+505
+Sebastian.Annies@gmail.com
+has-props
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+440
+
+RatingBox.java
+file
+
+
+
+
+2012-09-14T17:27:53.077255Z
+77d5aae6d65403599af0d0e62f65b44b
+2012-04-21T22:05:38.425329Z
+507
+Sebastian.Annies@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+3812
+
+TrackReferenceTypeBox.java
+file
+
+
+
+
+2012-09-14T17:27:53.077255Z
+01ff3b9bf0898d65ca27f199d4baee40
+2012-04-21T22:05:38.425329Z
+507
+Sebastian.Annies@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+2193
+
+MetaBox.java
+file
+
+
+
+
+2012-09-14T17:27:53.077255Z
+bd6ccb4b26b177f64b960d16da5f5a30
+2012-04-21T22:05:38.425329Z
+507
+Sebastian.Annies@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+3224
+
+threegpp26244
+dir
+
+MediaHeaderBox.java
+file
+
+
+
+
+2012-09-14T17:27:53.077255Z
+9381ac78989b7089d482c2b44526c282
+2012-05-17T09:04:15.805545Z
+616
+Sebastian.Annies@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+4561
+
+SampleTableBox.java
+file
+
+
+
+
+2012-09-14T17:27:53.077255Z
+7c86e7ceab9e74c9f681fed071a4dc0c
+2012-04-21T21:18:31.685061Z
+505
+Sebastian.Annies@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+4313
+
+rtp-boxes.zip
+file
+
+
+
+
+2012-09-14T17:27:53.077255Z
+b6fbe151f5fec8953cb3ce9e58784729
+2012-03-05T23:28:24.666173Z
+377
+Sebastian.Annies@gmail.com
+has-props
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+31772
+
+SampleAuxiliaryInformationSizesBox.java
+file
+
+
+
+
+2012-09-14T17:27:53.077255Z
+31f750177546a2e82ca8de769972f872
+2012-08-08T07:05:08.133759Z
+727
+Sebastian.Annies@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+4409
+
+FreeSpaceBox.java
+file
+
+
+
+
+2012-09-14T17:27:53.077255Z
+54792878d4a9e36d969c58ddd86692bf
+2012-04-21T22:05:38.425329Z
+507
+Sebastian.Annies@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+1724
+
+SoundMediaHeaderBox.java
+file
+
+
+
+
+2012-09-14T17:27:53.077255Z
+a997902bd90b258f996ef83e827e8580
+2012-04-21T22:05:38.425329Z
+507
+Sebastian.Annies@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+1639
+
+ProgressiveDownloadInformationBox.java
+file
+
+
+
+
+2012-09-14T17:27:53.077255Z
+8f230a1e42bea52f81bab49a91236f89
+2012-04-21T22:05:38.425329Z
+507
+Sebastian.Annies@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+2339
+
+DataEntryUrlBox.java
+file
+
+
+
+
+2012-09-14T17:27:53.077255Z
+c95d854ae68f925b06282c6aafdc07f6
+2012-04-21T22:05:38.425329Z
+507
+Sebastian.Annies@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+1389
+
+VideoMediaHeaderBox.java
+file
+
+
+
+
+2012-09-14T17:27:53.077255Z
+fce940b90e4ffe11ec8553c13cc9e357
+2012-04-21T22:05:38.425329Z
+507
+Sebastian.Annies@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+2420
+
+MovieBox.java
+file
+
+
+
+
+2012-09-14T17:27:53.077255Z
+847eb9e7c4bb29f730913b57ec25a68b
+2012-04-21T21:18:31.685061Z
+505
+Sebastian.Annies@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+2152
+
+DataEntryUrnBox.java
+file
+
+
+
+
+2012-09-14T17:27:53.077255Z
+af48983c19d5b39783baea8517578f53
+2012-04-21T22:05:38.425329Z
+507
+Sebastian.Annies@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+1956
+
+ProtectionSchemeInformationBox.java
+file
+
+
+
+
+2012-09-14T17:27:53.077255Z
+e2b7ff1f04405872d0da3dd9a22e1ac4
+2012-04-21T21:18:31.685061Z
+505
+Sebastian.Annies@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+1623
+
+EditListBox.java
+file
+
+
+
+
+2012-09-14T17:27:53.077255Z
+1b135924d295a0f357d8744a6b49ec3f
+2012-04-21T22:05:38.425329Z
+507
+Sebastian.Annies@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+8432
+
+SampleDependencyTypeBox.java
+file
+
+
+
+
+2012-09-14T17:27:53.077255Z
+035c90e133e9799d14c92b5388cf4353
+2012-04-21T22:05:38.425329Z
+507
+Sebastian.Annies@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+3701
+
+ContainerBox.java
+file
+
+
+
+
+2012-09-14T17:27:53.077255Z
+77b4f7d07f35cfebac08c440d56986a0
+2011-05-13T11:05:56.209382Z
+132
+Sebastian.Annies@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+2239
+
+TrackReferenceBox.java
+file
+
+
+
+
+2012-09-14T17:27:53.077255Z
+ea9697511c11cbe5115c898455b4f2e3
+2012-04-21T21:18:31.685061Z
+505
+Sebastian.Annies@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+1584
+
+MediaInformationBox.java
+file
+
+
+
+
+2012-09-14T17:27:53.077255Z
+c21e4a8822e8391001fcc3c1817a69ff
+2012-04-21T21:18:31.685061Z
+505
+Sebastian.Annies@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+1468
+
diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/.svn/prop-base/ChunkOffset64BitBox.java.svn-base b/isoparser/src/main/java/com/coremedia/iso/boxes/.svn/prop-base/ChunkOffset64BitBox.java.svn-base
new file mode 100644
index 0000000..869ac71
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/.svn/prop-base/ChunkOffset64BitBox.java.svn-base
@@ -0,0 +1,5 @@
+K 14
+svn:executable
+V 1
+*
+END
diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/.svn/prop-base/ChunkOffsetBox.java.svn-base b/isoparser/src/main/java/com/coremedia/iso/boxes/.svn/prop-base/ChunkOffsetBox.java.svn-base
new file mode 100644
index 0000000..869ac71
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/.svn/prop-base/ChunkOffsetBox.java.svn-base
@@ -0,0 +1,5 @@
+K 14
+svn:executable
+V 1
+*
+END
diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/.svn/prop-base/odf-boxes.zip.svn-base b/isoparser/src/main/java/com/coremedia/iso/boxes/.svn/prop-base/odf-boxes.zip.svn-base
new file mode 100644
index 0000000..5e9587e
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/.svn/prop-base/odf-boxes.zip.svn-base
@@ -0,0 +1,5 @@
+K 13
+svn:mime-type
+V 24
+application/octet-stream
+END
diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/.svn/prop-base/rtp-boxes.zip.svn-base b/isoparser/src/main/java/com/coremedia/iso/boxes/.svn/prop-base/rtp-boxes.zip.svn-base
new file mode 100644
index 0000000..5e9587e
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/.svn/prop-base/rtp-boxes.zip.svn-base
@@ -0,0 +1,5 @@
+K 13
+svn:mime-type
+V 24
+application/octet-stream
+END
diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/.svn/text-base/AbstractMediaHeaderBox.java.svn-base b/isoparser/src/main/java/com/coremedia/iso/boxes/.svn/text-base/AbstractMediaHeaderBox.java.svn-base
new file mode 100644
index 0000000..cc141ae
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/.svn/text-base/AbstractMediaHeaderBox.java.svn-base
@@ -0,0 +1,29 @@
+/*
+ * Copyright 2011 Sebastian Annies, Hamburg, Germany
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.coremedia.iso.boxes;
+
+import com.googlecode.mp4parser.AbstractFullBox;
+
+/**
+ * A common superclass for all MediaInformationHeaderBoxes. E.g.
+ * VideoMediaHeaderBox, SoundMediaHeaderBox & HintMediaHeaderBox
+ */
+public abstract class AbstractMediaHeaderBox extends AbstractFullBox {
+    protected AbstractMediaHeaderBox(String type) {
+        super(type);
+    }
+}
diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/.svn/text-base/AlbumBox.java.svn-base b/isoparser/src/main/java/com/coremedia/iso/boxes/.svn/text-base/AlbumBox.java.svn-base
new file mode 100644
index 0000000..d666806
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/.svn/text-base/AlbumBox.java.svn-base
@@ -0,0 +1,112 @@
+/*  
+ * Copyright 2008 CoreMedia AG, Hamburg
+ *
+ * Licensed under the Apache License, Version 2.0 (the License); 
+ * you may not use this file except in compliance with the License. 
+ * You may obtain a copy of the License at 
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0 
+ * 
+ * Unless required by applicable law or agreed to in writing, software 
+ * distributed under the License is distributed on an AS IS BASIS, 
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+ * See the License for the specific language governing permissions and 
+ * limitations under the License. 
+ */
+
+package com.coremedia.iso.boxes;
+
+import com.coremedia.iso.IsoTypeReader;
+import com.coremedia.iso.IsoTypeWriter;
+import com.coremedia.iso.Utf8;
+import com.googlecode.mp4parser.AbstractFullBox;
+
+import java.nio.ByteBuffer;
+
+/**
+ * Meta information in a 'udta' box about a track.
+ * Defined in 3GPP 26.244.
+ *
+ * @see com.coremedia.iso.boxes.UserDataBox
+ */
+public class AlbumBox extends AbstractFullBox {
+    public static final String TYPE = "albm";
+
+    private String language;
+    private String albumTitle;
+    private int trackNumber;
+
+    public AlbumBox() {
+        super(TYPE);
+    }
+
+    /**
+     * Declares the language code for the {@link #getAlbumTitle()} return value. See ISO 639-2/T for the set of three
+     * character codes.Each character is packed as the difference between its ASCII value and 0x60. The code is
+     * confined to being three lower-case letters, so these values are strictly positive.
+     *
+     * @return the language code
+     */
+    public String getLanguage() {
+        return language;
+    }
+
+    public String getAlbumTitle() {
+        return albumTitle;
+    }
+
+    public int getTrackNumber() {
+        return trackNumber;
+    }
+
+    public void setLanguage(String language) {
+        this.language = language;
+    }
+
+    public void setAlbumTitle(String albumTitle) {
+        this.albumTitle = albumTitle;
+    }
+
+    public void setTrackNumber(int trackNumber) {
+        this.trackNumber = trackNumber;
+    }
+
+    protected long getContentSize() {
+        return 6 + Utf8.utf8StringLengthInBytes(albumTitle) + 1 + (trackNumber == -1 ? 0 : 1);
+    }
+
+    @Override
+    public void _parseDetails(ByteBuffer content) {
+        parseVersionAndFlags(content);
+        language = IsoTypeReader.readIso639(content);
+        albumTitle = IsoTypeReader.readString(content);
+
+        if (content.remaining() > 0) {
+            trackNumber = IsoTypeReader.readUInt8(content);
+        } else {
+            trackNumber = -1;
+        }
+    }
+
+    @Override
+    protected void getContent(ByteBuffer byteBuffer) {
+        writeVersionAndFlags(byteBuffer);
+        IsoTypeWriter.writeIso639(byteBuffer, language);
+        byteBuffer.put(Utf8.convert(albumTitle));
+        byteBuffer.put((byte) 0);
+        if (trackNumber != -1) {
+            IsoTypeWriter.writeUInt8(byteBuffer, trackNumber);
+        }
+    }
+
+    public String toString() {
+        StringBuilder buffer = new StringBuilder();
+        buffer.append("AlbumBox[language=").append(getLanguage()).append(";");
+        buffer.append("albumTitle=").append(getAlbumTitle());
+        if (trackNumber >= 0) {
+            buffer.append(";trackNumber=").append(getTrackNumber());
+        }
+        buffer.append("]");
+        return buffer.toString();
+    }
+}
diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/.svn/text-base/AuthorBox.java.svn-base b/isoparser/src/main/java/com/coremedia/iso/boxes/.svn/text-base/AuthorBox.java.svn-base
new file mode 100644
index 0000000..672cde2
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/.svn/text-base/AuthorBox.java.svn-base
@@ -0,0 +1,94 @@
+/*  
+ * Copyright 2008 CoreMedia AG, Hamburg
+ *
+ * Licensed under the Apache License, Version 2.0 (the License); 
+ * you may not use this file except in compliance with the License. 
+ * You may obtain a copy of the License at 
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0 
+ * 
+ * Unless required by applicable law or agreed to in writing, software 
+ * distributed under the License is distributed on an AS IS BASIS, 
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+ * See the License for the specific language governing permissions and 
+ * limitations under the License. 
+ */
+
+package com.coremedia.iso.boxes;
+
+
+import com.coremedia.iso.IsoTypeReader;
+import com.coremedia.iso.IsoTypeWriter;
+import com.coremedia.iso.Utf8;
+import com.googlecode.mp4parser.AbstractFullBox;
+
+import java.nio.ByteBuffer;
+
+/**
+ * Meta information in a 'udta' box about a track.
+ * Defined in 3GPP 26.244.
+ *
+ * @see com.coremedia.iso.boxes.UserDataBox
+ */
+public class AuthorBox extends AbstractFullBox {
+    public static final String TYPE = "auth";
+
+    private String language;
+    private String author;
+
+    public AuthorBox() {
+        super(TYPE);
+    }
+
+    /**
+     * Declares the language code for the {@link #getAuthor()} return value. See ISO 639-2/T for the set of three
+     * character codes.Each character is packed as the difference between its ASCII value and 0x60. The code is
+     * confined to being three lower-case letters, so these values are strictly positive.
+     *
+     * @return the language code
+     */
+    public String getLanguage() {
+        return language;
+    }
+
+    /**
+     * Author information.
+     *
+     * @return the author
+     */
+    public String getAuthor() {
+        return author;
+    }
+
+    public void setLanguage(String language) {
+        this.language = language;
+    }
+
+    public void setAuthor(String author) {
+        this.author = author;
+    }
+
+    protected long getContentSize() {
+        return 7 + Utf8.utf8StringLengthInBytes(author);
+    }
+
+    @Override
+    public void _parseDetails(ByteBuffer content) {
+        parseVersionAndFlags(content);
+        language = IsoTypeReader.readIso639(content);
+        author = IsoTypeReader.readString(content);
+    }
+
+    @Override
+    protected void getContent(ByteBuffer byteBuffer) {
+        writeVersionAndFlags(byteBuffer);
+        IsoTypeWriter.writeIso639(byteBuffer, language);
+        byteBuffer.put(Utf8.convert(author));
+        byteBuffer.put((byte) 0);
+    }
+
+
+    public String toString() {
+        return "AuthorBox[language=" + getLanguage() + ";author=" + getAuthor() + "]";
+    }
+}
diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/.svn/text-base/BitRateBox.java.svn-base b/isoparser/src/main/java/com/coremedia/iso/boxes/.svn/text-base/BitRateBox.java.svn-base
new file mode 100644
index 0000000..6c4b0e6
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/.svn/text-base/BitRateBox.java.svn-base
@@ -0,0 +1,91 @@
+/*  
+ * Copyright 2008 CoreMedia AG, Hamburg
+ *
+ * Licensed under the Apache License, Version 2.0 (the License); 
+ * you may not use this file except in compliance with the License. 
+ * You may obtain a copy of the License at 
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0 
+ * 
+ * Unless required by applicable law or agreed to in writing, software 
+ * distributed under the License is distributed on an AS IS BASIS, 
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+ * See the License for the specific language governing permissions and 
+ * limitations under the License. 
+ */
+
+package com.coremedia.iso.boxes;
+
+import com.coremedia.iso.IsoTypeReader;
+import com.coremedia.iso.IsoTypeWriter;
+import com.googlecode.mp4parser.AbstractBox;
+
+import java.nio.ByteBuffer;
+
+/**
+ * <code>class BitRateBox extends Box('btrt') {<br/>
+ * unsigned int(32) bufferSizeDB;<br/>
+ * // gives the size of the decoding buffer for<br/>
+ * // the elementary stream in bytes.<br/>
+ * unsigned int(32) maxBitrate;<br/>
+ * // gives the maximum rate in bits/second <br/>
+ * // over any window of one second.<br/>
+ * unsigned int(32) avgBitrate;<br/>
+ * // avgBitrate gives the average rate in <br/>
+ * // bits/second over the entire presentation.<br/>
+ * }</code>
+ */
+
+public final class BitRateBox extends AbstractBox {
+    public static final String TYPE = "btrt";
+
+    private long bufferSizeDb;
+    private long maxBitrate;
+    private long avgBitrate;
+
+    public BitRateBox() {
+        super(TYPE);
+    }
+
+    protected long getContentSize() {
+        return 12;
+    }
+
+    @Override
+    public void _parseDetails(ByteBuffer content) {
+        bufferSizeDb = IsoTypeReader.readUInt32(content);
+        maxBitrate = IsoTypeReader.readUInt32(content);
+        avgBitrate = IsoTypeReader.readUInt32(content);
+    }
+
+    @Override
+    protected void getContent(ByteBuffer byteBuffer) {
+        IsoTypeWriter.writeUInt32(byteBuffer, bufferSizeDb);
+        IsoTypeWriter.writeUInt32(byteBuffer, maxBitrate);
+        IsoTypeWriter.writeUInt32(byteBuffer, avgBitrate);
+    }
+
+    public long getBufferSizeDb() {
+        return bufferSizeDb;
+    }
+
+    public void setBufferSizeDb(long bufferSizeDb) {
+        this.bufferSizeDb = bufferSizeDb;
+    }
+
+    public long getMaxBitrate() {
+        return maxBitrate;
+    }
+
+    public void setMaxBitrate(long maxBitrate) {
+        this.maxBitrate = maxBitrate;
+    }
+
+    public long getAvgBitrate() {
+        return avgBitrate;
+    }
+
+    public void setAvgBitrate(long avgBitrate) {
+        this.avgBitrate = avgBitrate;
+    }
+}
diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/.svn/text-base/Box.java.svn-base b/isoparser/src/main/java/com/coremedia/iso/boxes/.svn/text-base/Box.java.svn-base
new file mode 100644
index 0000000..f6ca302
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/.svn/text-base/Box.java.svn-base
@@ -0,0 +1,51 @@
+/*  
+ * Copyright 2008 CoreMedia AG, Hamburg
+ *
+ * Licensed under the Apache License, Version 2.0 (the License); 
+ * you may not use this file except in compliance with the License. 
+ * You may obtain a copy of the License at 
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0 
+ * 
+ * Unless required by applicable law or agreed to in writing, software 
+ * distributed under the License is distributed on an AS IS BASIS, 
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+ * See the License for the specific language governing permissions and 
+ * limitations under the License. 
+ */
+
+package com.coremedia.iso.boxes;
+
+import com.coremedia.iso.BoxParser;
+import com.coremedia.iso.boxes.ContainerBox;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.nio.channels.ReadableByteChannel;
+import java.nio.channels.WritableByteChannel;
+
+/**
+ * Defines basic interaction possibilities for any ISO box. Each box has a parent box and a type.
+ */
+public interface Box {
+    ContainerBox getParent();
+
+    void setParent(ContainerBox parent);
+
+    long getSize();
+
+    /**
+     * The box's 4-cc type.
+     * @return the 4 character type of the box
+     */
+    String getType();
+
+    /**
+     * Writes the complete box - size | 4-cc | content - to the given <code>writableByteChannel</code>.
+     * @param writableByteChannel the box's sink
+     * @throws IOException in case of problems with the <code>Channel</code>
+     */
+    void getBox(WritableByteChannel writableByteChannel) throws IOException;
+
+    void parse(ReadableByteChannel readableByteChannel, ByteBuffer header, long contentSize, BoxParser boxParser) throws IOException;
+}
diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/.svn/text-base/ChunkOffset64BitBox.java.svn-base b/isoparser/src/main/java/com/coremedia/iso/boxes/.svn/text-base/ChunkOffset64BitBox.java.svn-base
new file mode 100644
index 0000000..f2340b9
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/.svn/text-base/ChunkOffset64BitBox.java.svn-base
@@ -0,0 +1,51 @@
+package com.coremedia.iso.boxes;
+
+import com.coremedia.iso.IsoTypeReader;
+import com.coremedia.iso.IsoTypeWriter;
+
+import java.nio.ByteBuffer;
+
+import static com.googlecode.mp4parser.util.CastUtils.l2i;
+
+/**
+ * Abstract Chunk Offset Box
+ */
+public class ChunkOffset64BitBox extends ChunkOffsetBox {
+    public static final String TYPE = "co64";
+    private long[] chunkOffsets;
+
+    public ChunkOffset64BitBox() {
+        super(TYPE);
+    }
+
+    @Override
+    public long[] getChunkOffsets() {
+        return chunkOffsets;
+    }
+
+    @Override
+    protected long getContentSize() {
+        return 8 + 8 * chunkOffsets.length;
+    }
+
+    @Override
+    public void _parseDetails(ByteBuffer content) {
+        parseVersionAndFlags(content);
+        int entryCount = l2i(IsoTypeReader.readUInt32(content));
+        chunkOffsets = new long[entryCount];
+        for (int i = 0; i < entryCount; i++) {
+            chunkOffsets[i] = IsoTypeReader.readUInt64(content);
+        }
+    }
+
+    @Override
+    protected void getContent(ByteBuffer byteBuffer) {
+        writeVersionAndFlags(byteBuffer);
+        IsoTypeWriter.writeUInt32(byteBuffer, chunkOffsets.length);
+        for (long chunkOffset : chunkOffsets) {
+            IsoTypeWriter.writeUInt64(byteBuffer, chunkOffset);
+        }
+    }
+
+
+}
diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/.svn/text-base/ChunkOffsetBox.java.svn-base b/isoparser/src/main/java/com/coremedia/iso/boxes/.svn/text-base/ChunkOffsetBox.java.svn-base
new file mode 100644
index 0000000..01f5ae4
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/.svn/text-base/ChunkOffsetBox.java.svn-base
@@ -0,0 +1,21 @@
+package com.coremedia.iso.boxes;
+
+import com.googlecode.mp4parser.AbstractFullBox;
+
+/**
+ * Abstract Chunk Offset Box
+ */
+public abstract class ChunkOffsetBox extends AbstractFullBox {
+
+    public ChunkOffsetBox(String type) {
+        super(type);
+    }
+
+    public abstract long[] getChunkOffsets();
+
+
+    public String toString() {
+        return this.getClass().getSimpleName() + "[entryCount=" + getChunkOffsets().length + "]";
+    }
+
+}
diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/.svn/text-base/ClassificationBox.java.svn-base b/isoparser/src/main/java/com/coremedia/iso/boxes/.svn/text-base/ClassificationBox.java.svn-base
new file mode 100644
index 0000000..a20feca
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/.svn/text-base/ClassificationBox.java.svn-base
@@ -0,0 +1,110 @@
+/*  
+ * Copyright 2008 CoreMedia AG, Hamburg
+ *
+ * Licensed under the Apache License, Version 2.0 (the License); 
+ * you may not use this file except in compliance with the License. 
+ * You may obtain a copy of the License at 
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0 
+ * 
+ * Unless required by applicable law or agreed to in writing, software 
+ * distributed under the License is distributed on an AS IS BASIS, 
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+ * See the License for the specific language governing permissions and 
+ * limitations under the License. 
+ */
+
+package com.coremedia.iso.boxes;
+
+import com.coremedia.iso.IsoFile;
+import com.coremedia.iso.IsoTypeReader;
+import com.coremedia.iso.IsoTypeWriter;
+import com.coremedia.iso.Utf8;
+import com.googlecode.mp4parser.AbstractFullBox;
+
+import java.nio.ByteBuffer;
+
+/**
+ * Classification of the media according to 3GPP 26.244.
+ */
+public class ClassificationBox extends AbstractFullBox {
+    public static final String TYPE = "clsf";
+
+
+    private String classificationEntity;
+    private int classificationTableIndex;
+    private String language;
+    private String classificationInfo;
+
+    public ClassificationBox() {
+        super(TYPE);
+    }
+
+    public String getLanguage() {
+        return language;
+    }
+
+    public String getClassificationEntity() {
+        return classificationEntity;
+    }
+
+    public int getClassificationTableIndex() {
+        return classificationTableIndex;
+    }
+
+    public String getClassificationInfo() {
+        return classificationInfo;
+    }
+
+    public void setClassificationEntity(String classificationEntity) {
+        this.classificationEntity = classificationEntity;
+    }
+
+    public void setClassificationTableIndex(int classificationTableIndex) {
+        this.classificationTableIndex = classificationTableIndex;
+    }
+
+    public void setLanguage(String language) {
+        this.language = language;
+    }
+
+    public void setClassificationInfo(String classificationInfo) {
+        this.classificationInfo = classificationInfo;
+    }
+
+    protected long getContentSize() {
+        return 4 + 2 + 2 + Utf8.utf8StringLengthInBytes(classificationInfo) + 1;
+    }
+
+    @Override
+    public void _parseDetails(ByteBuffer content) {
+        parseVersionAndFlags(content);
+        byte[] cE = new byte[4];
+        content.get(cE);
+        classificationEntity = IsoFile.bytesToFourCC(cE);
+        classificationTableIndex = IsoTypeReader.readUInt16(content);
+        language = IsoTypeReader.readIso639(content);
+        classificationInfo = IsoTypeReader.readString(content);
+    }
+
+    @Override
+    protected void getContent(ByteBuffer byteBuffer) {
+        byteBuffer.put(IsoFile.fourCCtoBytes(classificationEntity));
+        IsoTypeWriter.writeUInt16(byteBuffer, classificationTableIndex);
+        IsoTypeWriter.writeIso639(byteBuffer, language);
+        byteBuffer.put(Utf8.convert(classificationInfo));
+        byteBuffer.put((byte) 0);
+    }
+
+
+    public String toString() {
+        StringBuilder buffer = new StringBuilder();
+        buffer.append("ClassificationBox[language=").append(getLanguage());
+        buffer.append("classificationEntity=").append(getClassificationEntity());
+        buffer.append(";classificationTableIndex=").append(getClassificationTableIndex());
+        buffer.append(";language=").append(getLanguage());
+        buffer.append(";classificationInfo=").append(getClassificationInfo());
+        buffer.append("]");
+        return buffer.toString();
+    }
+}
diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/.svn/text-base/CompositionShiftLeastGreatestAtom.java.svn-base b/isoparser/src/main/java/com/coremedia/iso/boxes/.svn/text-base/CompositionShiftLeastGreatestAtom.java.svn-base
new file mode 100644
index 0000000..3534b7f
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/.svn/text-base/CompositionShiftLeastGreatestAtom.java.svn-base
@@ -0,0 +1,101 @@
+package com.coremedia.iso.boxes;
+
+import com.googlecode.mp4parser.AbstractFullBox;
+
+import java.nio.ByteBuffer;
+
+/**
+ * The optional composition shift least greatest atom summarizes the calculated
+ * minimum and maximum offsets between decode and composition time, as well as
+ * the start and end times, for all samples. This allows a reader to determine
+ * the minimum required time for decode to obtain proper presentation order without
+ * needing to scan the sample table for the range of offsets. The type of the
+ * composition shift least greatest atom is ‘cslg’.
+ */
+public class CompositionShiftLeastGreatestAtom extends AbstractFullBox {
+    public CompositionShiftLeastGreatestAtom() {
+        super("cslg");
+    }
+
+    // A 32-bit unsigned integer that specifies the calculated value.
+    int compositionOffsetToDisplayOffsetShift;
+
+    // A 32-bit signed integer that specifies the calculated value.
+    int leastDisplayOffset;
+
+    // A 32-bit signed integer that specifies the calculated value.
+    int greatestDisplayOffset;
+
+    //A 32-bit signed integer that specifies the calculated value.
+    int displayStartTime;
+
+    //A 32-bit signed integer that specifies the calculated value.
+    int displayEndTime;
+
+
+    @Override
+    protected long getContentSize() {
+        return 24;
+    }
+
+    @Override
+    public void _parseDetails(ByteBuffer content) {
+        parseVersionAndFlags(content);
+        compositionOffsetToDisplayOffsetShift = content.getInt();
+        leastDisplayOffset = content.getInt();
+        greatestDisplayOffset = content.getInt();
+        displayStartTime = content.getInt();
+        displayEndTime = content.getInt();
+    }
+
+    @Override
+    protected void getContent(ByteBuffer byteBuffer) {
+        writeVersionAndFlags(byteBuffer);
+        byteBuffer.putInt(compositionOffsetToDisplayOffsetShift);
+        byteBuffer.putInt(leastDisplayOffset);
+        byteBuffer.putInt(greatestDisplayOffset);
+        byteBuffer.putInt(displayStartTime);
+        byteBuffer.putInt(displayEndTime);
+    }
+
+
+    public int getCompositionOffsetToDisplayOffsetShift() {
+        return compositionOffsetToDisplayOffsetShift;
+    }
+
+    public void setCompositionOffsetToDisplayOffsetShift(int compositionOffsetToDisplayOffsetShift) {
+        this.compositionOffsetToDisplayOffsetShift = compositionOffsetToDisplayOffsetShift;
+    }
+
+    public int getLeastDisplayOffset() {
+        return leastDisplayOffset;
+    }
+
+    public void setLeastDisplayOffset(int leastDisplayOffset) {
+        this.leastDisplayOffset = leastDisplayOffset;
+    }
+
+    public int getGreatestDisplayOffset() {
+        return greatestDisplayOffset;
+    }
+
+    public void setGreatestDisplayOffset(int greatestDisplayOffset) {
+        this.greatestDisplayOffset = greatestDisplayOffset;
+    }
+
+    public int getDisplayStartTime() {
+        return displayStartTime;
+    }
+
+    public void setDisplayStartTime(int displayStartTime) {
+        this.displayStartTime = displayStartTime;
+    }
+
+    public int getDisplayEndTime() {
+        return displayEndTime;
+    }
+
+    public void setDisplayEndTime(int displayEndTime) {
+        this.displayEndTime = displayEndTime;
+    }
+}
diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/.svn/text-base/CompositionTimeToSample.java.svn-base b/isoparser/src/main/java/com/coremedia/iso/boxes/.svn/text-base/CompositionTimeToSample.java.svn-base
new file mode 100644
index 0000000..411bfe9
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/.svn/text-base/CompositionTimeToSample.java.svn-base
@@ -0,0 +1,150 @@
+package com.coremedia.iso.boxes;
+
+import com.coremedia.iso.IsoTypeReader;
+import com.coremedia.iso.IsoTypeWriter;
+import com.googlecode.mp4parser.AbstractFullBox;
+
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import static com.googlecode.mp4parser.util.CastUtils.l2i;
+
+/**
+ * <pre>
+ * aligned(8) class CompositionOffsetBox
+ * extends FullBox(‘ctts’, version = 0, 0) {
+ *  unsigned int(32) entry_count;
+ *  int i;
+ *  if (version==0) {
+ *   for (i=0; i < entry_count; i++) {
+ *    unsigned int(32) sample_count;
+ *    unsigned int(32) sample_offset;
+ *   }
+ *  }
+ *  else if (version == 1) {
+ *   for (i=0; i < entry_count; i++) {
+ *    unsigned int(32) sample_count;
+ *    signed int(32) sample_offset;
+ *   }
+ *  }
+ * }
+ * </pre>
+ * <p/>
+ * This box provides the offset between decoding time and composition time.
+ * In version 0 of this box the decoding time must be less than the composition time, and
+ * the offsets are expressed as unsigned numbers such that
+ * CT(n) = DT(n) + CTTS(n) where CTTS(n) is the (uncompressed) table entry for sample n.
+ * <p/>
+ * In version 1 of this box, the composition timeline and the decoding timeline are
+ * still derived from each other, but the offsets are signed.
+ * It is recommended that for the computed composition timestamps, there is
+ * exactly one with the value 0 (zero).
+ */
+public class CompositionTimeToSample extends AbstractFullBox {
+    public static final String TYPE = "ctts";
+
+    List<Entry> entries = Collections.emptyList();
+
+    public CompositionTimeToSample() {
+        super(TYPE);
+    }
+
+    protected long getContentSize() {
+        return 8 + 8 * entries.size();
+    }
+
+    public List<Entry> getEntries() {
+        return entries;
+    }
+
+    public void setEntries(List<Entry> entries) {
+        this.entries = entries;
+    }
+
+    @Override
+    public void _parseDetails(ByteBuffer content) {
+        parseVersionAndFlags(content);
+        int numberOfEntries = l2i(IsoTypeReader.readUInt32(content));
+        entries = new ArrayList<Entry>(numberOfEntries);
+        for (int i = 0; i < numberOfEntries; i++) {
+            Entry e = new Entry(l2i(IsoTypeReader.readUInt32(content)), content.getInt());
+            entries.add(e);
+        }
+    }
+
+    @Override
+    protected void getContent(ByteBuffer byteBuffer) {
+        writeVersionAndFlags(byteBuffer);
+        IsoTypeWriter.writeUInt32(byteBuffer, entries.size());
+
+        for (Entry entry : entries) {
+            IsoTypeWriter.writeUInt32(byteBuffer, entry.getCount());
+            byteBuffer.putInt(entry.getOffset());
+        }
+
+    }
+
+
+    public static class Entry {
+        int count;
+        int offset;
+
+        public Entry(int count, int offset) {
+            this.count = count;
+            this.offset = offset;
+        }
+
+        public int getCount() {
+            return count;
+        }
+
+        public int getOffset() {
+            return offset;
+        }
+
+        public void setCount(int count) {
+            this.count = count;
+        }
+
+        public void setOffset(int offset) {
+            this.offset = offset;
+        }
+
+        @Override
+        public String toString() {
+            return "Entry{" +
+                    "count=" + count +
+                    ", offset=" + offset +
+                    '}';
+        }
+    }
+
+
+    /**
+     * Decompresses the list of entries and returns the list of composition times.
+     *
+     * @return decoding time per sample
+     */
+    public static int[] blowupCompositionTimes(List<CompositionTimeToSample.Entry> entries) {
+        long numOfSamples = 0;
+        for (CompositionTimeToSample.Entry entry : entries) {
+            numOfSamples += entry.getCount();
+        }
+        assert numOfSamples <= Integer.MAX_VALUE;
+        int[] decodingTime = new int[(int) numOfSamples];
+
+        int current = 0;
+
+
+        for (CompositionTimeToSample.Entry entry : entries) {
+            for (int i = 0; i < entry.getCount(); i++) {
+                decodingTime[current++] = entry.getOffset();
+            }
+        }
+
+        return decodingTime;
+    }
+
+}
diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/.svn/text-base/ContainerBox.java.svn-base b/isoparser/src/main/java/com/coremedia/iso/boxes/.svn/text-base/ContainerBox.java.svn-base
new file mode 100644
index 0000000..a016374
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/.svn/text-base/ContainerBox.java.svn-base
@@ -0,0 +1,74 @@
+/*  
+ * Copyright 2008 CoreMedia AG, Hamburg
+ *
+ * Licensed under the Apache License, Version 2.0 (the License); 
+ * you may not use this file except in compliance with the License. 
+ * You may obtain a copy of the License at 
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0 
+ * 
+ * Unless required by applicable law or agreed to in writing, software 
+ * distributed under the License is distributed on an AS IS BASIS, 
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+ * See the License for the specific language governing permissions and 
+ * limitations under the License. 
+ */
+
+package com.coremedia.iso.boxes;
+
+import com.coremedia.iso.IsoFile;
+
+import java.util.List;
+
+/**
+ * Interface for all ISO boxes that may contain other boxes.
+ */
+public interface ContainerBox extends Box {
+
+    /**
+     * Gets all child boxes. May not return <code>null</code>.
+     *
+     * @return an array of boxes, empty array in case of no children.
+     */
+    List<Box> getBoxes();
+
+    /**
+     * Sets all boxes and removes all previous child boxes.
+     * @param boxes the new list of children
+     */
+    void setBoxes(List<Box> boxes);
+
+    /**
+     * Gets all child boxes of the given type. May not return <code>null</code>.
+     *
+     * @param clazz child box's type
+     * @return an array of boxes, empty array in case of no children.
+     */
+    <T extends Box> List<T> getBoxes(Class<T> clazz);
+
+    /**
+     * Gets all child boxes of the given type. May not return <code>null</code>.
+     *
+     * @param clazz     child box's type
+     * @param recursive step down the tree
+     * @return an array of boxes, empty array in case of no children.
+     */
+    <T extends Box> List<T> getBoxes(Class<T> clazz, boolean recursive);
+
+    /**
+     * Gets the parent box. May be <code>null</code> in case of the
+     * {@link com.coremedia.iso.IsoFile} itself.
+     *
+     * @return a <code>ContainerBox</code> that contains <code>this</code>
+     */
+    ContainerBox getParent();
+
+    /**
+     * Returns the number of bytes from the start of the box to start of the first child.
+     *
+     * @return offset of first child from box start
+     */
+    long getNumOfBytesToFirstChild();
+
+    IsoFile getIsoFile();
+}
diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/.svn/text-base/CopyrightBox.java.svn-base b/isoparser/src/main/java/com/coremedia/iso/boxes/.svn/text-base/CopyrightBox.java.svn-base
new file mode 100644
index 0000000..86bc215
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/.svn/text-base/CopyrightBox.java.svn-base
@@ -0,0 +1,86 @@
+/*  
+ * Copyright 2008 CoreMedia AG, Hamburg
+ *
+ * Licensed under the Apache License, Version 2.0 (the License); 
+ * you may not use this file except in compliance with the License. 
+ * You may obtain a copy of the License at 
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0 
+ * 
+ * Unless required by applicable law or agreed to in writing, software 
+ * distributed under the License is distributed on an AS IS BASIS, 
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+ * See the License for the specific language governing permissions and 
+ * limitations under the License. 
+ */
+
+package com.coremedia.iso.boxes;
+
+
+import com.coremedia.iso.IsoTypeReader;
+import com.coremedia.iso.IsoTypeWriter;
+import com.coremedia.iso.Utf8;
+import com.googlecode.mp4parser.AbstractFullBox;
+
+import java.nio.ByteBuffer;
+
+/**
+ * The copyright box contains a copyright declaration which applies to the entire presentation, when contained
+ * within the MovieBox, or, when contained in a track, to that entire track. There may be multple boxes using
+ * different language codes.
+ *
+ * @see MovieBox
+ * @see TrackBox
+ */
+public class CopyrightBox extends AbstractFullBox {
+    public static final String TYPE = "cprt";
+
+    private String language;
+    private String copyright;
+
+    public CopyrightBox() {
+        super(TYPE);
+    }
+
+    public String getLanguage() {
+        return language;
+    }
+
+    public String getCopyright() {
+        return copyright;
+    }
+
+    public void setLanguage(String language) {
+        this.language = language;
+    }
+
+    public void setCopyright(String copyright) {
+        this.copyright = copyright;
+    }
+
+    protected long getContentSize() {
+        return 7 + Utf8.utf8StringLengthInBytes(copyright);
+    }
+
+    @Override
+    public void _parseDetails(ByteBuffer content) {
+        parseVersionAndFlags(content);
+        language = IsoTypeReader.readIso639(content);
+        copyright = IsoTypeReader.readString(content);
+    }
+
+    @Override
+    protected void getContent(ByteBuffer byteBuffer) {
+        writeVersionAndFlags(byteBuffer);
+        IsoTypeWriter.writeIso639(byteBuffer, language);
+        byteBuffer.put(Utf8.convert(copyright));
+        byteBuffer.put((byte) 0);
+    }
+
+    public String toString() {
+        return "CopyrightBox[language=" + getLanguage() + ";copyright=" + getCopyright() + "]";
+    }
+
+
+
+}
diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/.svn/text-base/DataEntryUrlBox.java.svn-base b/isoparser/src/main/java/com/coremedia/iso/boxes/.svn/text-base/DataEntryUrlBox.java.svn-base
new file mode 100644
index 0000000..b58608d
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/.svn/text-base/DataEntryUrlBox.java.svn-base
@@ -0,0 +1,53 @@
+/*  
+ * Copyright 2008 CoreMedia AG, Hamburg
+ *
+ * Licensed under the Apache License, Version 2.0 (the License); 
+ * you may not use this file except in compliance with the License. 
+ * You may obtain a copy of the License at 
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0 
+ * 
+ * Unless required by applicable law or agreed to in writing, software 
+ * distributed under the License is distributed on an AS IS BASIS, 
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+ * See the License for the specific language governing permissions and 
+ * limitations under the License. 
+ */
+
+package com.coremedia.iso.boxes;
+
+import com.googlecode.mp4parser.AbstractFullBox;
+
+import java.nio.ByteBuffer;
+
+/**
+ * Only used within the DataReferenceBox. Find more information there.
+ *
+ * @see com.coremedia.iso.boxes.DataReferenceBox
+ */
+public class DataEntryUrlBox extends AbstractFullBox {
+    public static final String TYPE = "url ";
+
+    public DataEntryUrlBox() {
+        super(TYPE);
+    }
+
+    @Override
+    public void _parseDetails(ByteBuffer content) {
+        parseVersionAndFlags(content);
+    }
+
+
+    @Override
+    protected void getContent(ByteBuffer byteBuffer) {
+        writeVersionAndFlags(byteBuffer);
+    }
+
+    protected long getContentSize() {
+        return 4;
+    }
+
+    public String toString() {
+        return "DataEntryUrlBox[]";
+    }
+}
diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/.svn/text-base/DataEntryUrnBox.java.svn-base b/isoparser/src/main/java/com/coremedia/iso/boxes/.svn/text-base/DataEntryUrnBox.java.svn-base
new file mode 100644
index 0000000..042a972
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/.svn/text-base/DataEntryUrnBox.java.svn-base
@@ -0,0 +1,69 @@
+/*  
+ * Copyright 2008 CoreMedia AG, Hamburg
+ *
+ * Licensed under the Apache License, Version 2.0 (the License); 
+ * you may not use this file except in compliance with the License. 
+ * You may obtain a copy of the License at 
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0 
+ * 
+ * Unless required by applicable law or agreed to in writing, software 
+ * distributed under the License is distributed on an AS IS BASIS, 
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+ * See the License for the specific language governing permissions and 
+ * limitations under the License. 
+ */
+
+package com.coremedia.iso.boxes;
+
+import com.coremedia.iso.IsoTypeReader;
+import com.coremedia.iso.Utf8;
+import com.googlecode.mp4parser.AbstractFullBox;
+
+import java.nio.ByteBuffer;
+
+/**
+ * Only used within the DataReferenceBox. Find more information there.
+ *
+ * @see com.coremedia.iso.boxes.DataReferenceBox
+ */
+public class DataEntryUrnBox extends AbstractFullBox {
+    private String name;
+    private String location;
+    public static final String TYPE = "urn ";
+
+    public DataEntryUrnBox() {
+        super(TYPE);
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public String getLocation() {
+        return location;
+    }
+
+    protected long getContentSize() {
+        return Utf8.utf8StringLengthInBytes(name) + 1 + Utf8.utf8StringLengthInBytes(location) + 1;
+    }
+
+    @Override
+    public void _parseDetails(ByteBuffer content) {
+        name = IsoTypeReader.readString(content);
+        location = IsoTypeReader.readString(content);
+
+    }
+
+    @Override
+    protected void getContent(ByteBuffer byteBuffer) {
+        byteBuffer.put(Utf8.convert(name));
+        byteBuffer.put((byte) 0);
+        byteBuffer.put(Utf8.convert(location));
+        byteBuffer.put((byte) 0);
+    }
+
+    public String toString() {
+        return "DataEntryUrlBox[name=" + getName() + ";location=" + getLocation() + "]";
+    }
+}
diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/.svn/text-base/DataInformationBox.java.svn-base b/isoparser/src/main/java/com/coremedia/iso/boxes/.svn/text-base/DataInformationBox.java.svn-base
new file mode 100644
index 0000000..7f058eb
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/.svn/text-base/DataInformationBox.java.svn-base
@@ -0,0 +1,36 @@
+/*  
+ * Copyright 2008 CoreMedia AG, Hamburg
+ *
+ * Licensed under the Apache License, Version 2.0 (the License); 
+ * you may not use this file except in compliance with the License. 
+ * You may obtain a copy of the License at 
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0 
+ * 
+ * Unless required by applicable law or agreed to in writing, software 
+ * distributed under the License is distributed on an AS IS BASIS, 
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+ * See the License for the specific language governing permissions and 
+ * limitations under the License. 
+ */
+
+package com.coremedia.iso.boxes;
+
+import com.googlecode.mp4parser.AbstractContainerBox;
+
+/**
+ * <code>
+ * Box Type: 'dinf'<br>
+ * Container: {@link com.coremedia.iso.boxes.MediaInformationBox} ('minf')<br>
+ * Mandatory: Yes<br>
+ * Quantity: Exactly one<br><br></code>
+ * The data information box contains objects that declare the location of the media information in a track.
+ */
+public class DataInformationBox extends AbstractContainerBox {
+    public static final String TYPE = "dinf";
+
+    public DataInformationBox() {
+        super(TYPE);
+    }
+
+}
diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/.svn/text-base/DataReferenceBox.java.svn-base b/isoparser/src/main/java/com/coremedia/iso/boxes/.svn/text-base/DataReferenceBox.java.svn-base
new file mode 100644
index 0000000..8156d3f
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/.svn/text-base/DataReferenceBox.java.svn-base
@@ -0,0 +1,65 @@
+/*  
+ * Copyright 2008 CoreMedia AG, Hamburg
+ *
+ * Licensed under the Apache License, Version 2.0 (the License); 
+ * you may not use this file except in compliance with the License. 
+ * You may obtain a copy of the License at 
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0 
+ * 
+ * Unless required by applicable law or agreed to in writing, software 
+ * distributed under the License is distributed on an AS IS BASIS, 
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+ * See the License for the specific language governing permissions and 
+ * limitations under the License. 
+ */
+
+package com.coremedia.iso.boxes;
+
+
+import com.coremedia.iso.IsoTypeWriter;
+import com.googlecode.mp4parser.FullContainerBox;
+
+import java.nio.ByteBuffer;
+
+/**
+ * The data reference object contains a table of data references (normally URLs) that declare the location(s) of
+ * the media data used within the presentation. The data reference index in the sample description ties entries in
+ * this table to the samples in the track. A track may be split over several sources in this way.
+ * If the flag is set indicating that the data is in the same file as this box, then no string (not even an empty one)
+ * shall be supplied in the entry field.
+ * The DataEntryBox within the DataReferenceBox shall be either a DataEntryUrnBox or a DataEntryUrlBox.
+ *
+ * @see com.coremedia.iso.boxes.DataEntryUrlBox
+ * @see com.coremedia.iso.boxes.DataEntryUrnBox
+ */
+public class DataReferenceBox extends FullContainerBox {
+
+    public static final String TYPE = "dref";
+
+    public DataReferenceBox() {
+        super(TYPE);
+
+    }
+
+    @Override
+    protected long getContentSize() {
+        return super.getContentSize() + 4;
+    }
+
+    @Override
+    public void _parseDetails(ByteBuffer content) {
+        parseVersionAndFlags(content);
+        content.get(new byte[4]); // basically a skip of 4 bytes signaling the number of child boxes
+        parseChildBoxes(content);
+    }
+
+
+    @Override
+    protected void getContent(ByteBuffer byteBuffer) {
+        writeVersionAndFlags(byteBuffer);
+        IsoTypeWriter.writeUInt32(byteBuffer, getBoxes().size());
+        writeChildBoxes(byteBuffer);
+    }
+
+}
diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/.svn/text-base/DescriptionBox.java.svn-base b/isoparser/src/main/java/com/coremedia/iso/boxes/.svn/text-base/DescriptionBox.java.svn-base
new file mode 100644
index 0000000..8352051
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/.svn/text-base/DescriptionBox.java.svn-base
@@ -0,0 +1,77 @@
+/*  
+ * Copyright 2008 CoreMedia AG, Hamburg
+ *
+ * Licensed under the Apache License, Version 2.0 (the License); 
+ * you may not use this file except in compliance with the License. 
+ * You may obtain a copy of the License at 
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0 
+ * 
+ * Unless required by applicable law or agreed to in writing, software 
+ * distributed under the License is distributed on an AS IS BASIS, 
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+ * See the License for the specific language governing permissions and 
+ * limitations under the License. 
+ */
+
+package com.coremedia.iso.boxes;
+
+import com.coremedia.iso.IsoTypeReader;
+import com.coremedia.iso.IsoTypeWriter;
+import com.coremedia.iso.Utf8;
+import com.googlecode.mp4parser.AbstractFullBox;
+
+import java.nio.ByteBuffer;
+
+/**
+ * Gives a language dependent description of the media contained in the ISO file.
+ */
+public class DescriptionBox extends AbstractFullBox {
+    public static final String TYPE = "dscp";
+
+    private String language;
+    private String description;
+
+    public DescriptionBox() {
+        super(TYPE);
+    }
+
+    public String getLanguage() {
+        return language;
+    }
+
+    public String getDescription() {
+        return description;
+    }
+
+    protected long getContentSize() {
+        return 7 + Utf8.utf8StringLengthInBytes(description);
+    }
+
+    @Override
+    public void _parseDetails(ByteBuffer content) {
+        parseVersionAndFlags(content);
+        language = IsoTypeReader.readIso639(content);
+        description = IsoTypeReader.readString(content);
+    }
+
+    @Override
+    protected void getContent(ByteBuffer byteBuffer) {
+        writeVersionAndFlags(byteBuffer);
+        IsoTypeWriter.writeIso639(byteBuffer, language);
+        byteBuffer.put(Utf8.convert(description));
+        byteBuffer.put((byte) 0);
+    }
+
+    public String toString() {
+        return "DescriptionBox[language=" + getLanguage() + ";description=" + getDescription() + "]";
+    }
+
+    public void setLanguage(String language) {
+        this.language = language;
+    }
+
+    public void setDescription(String description) {
+        this.description = description;
+    }
+}
diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/.svn/text-base/EditBox.java.svn-base b/isoparser/src/main/java/com/coremedia/iso/boxes/.svn/text-base/EditBox.java.svn-base
new file mode 100644
index 0000000..db3bc25
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/.svn/text-base/EditBox.java.svn-base
@@ -0,0 +1,34 @@
+/*  
+ * Copyright 2008 CoreMedia AG, Hamburg
+ *
+ * Licensed under the Apache License, Version 2.0 (the License); 
+ * you may not use this file except in compliance with the License. 
+ * You may obtain a copy of the License at 
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0 
+ * 
+ * Unless required by applicable law or agreed to in writing, software 
+ * distributed under the License is distributed on an AS IS BASIS, 
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+ * See the License for the specific language governing permissions and 
+ * limitations under the License. 
+ */
+
+package com.coremedia.iso.boxes;
+
+import com.googlecode.mp4parser.AbstractContainerBox;
+
+/**
+ * An Edit Box maps the presentation time-line to the media time-line as it is stored in the file.
+ * The Edit Box is a container fpr the edit lists. Defined in ISO/IEC 14496-12.
+ *
+ * @see EditListBox
+ */
+public class EditBox extends AbstractContainerBox {
+    public static final String TYPE = "edts";
+
+    public EditBox() {
+        super(TYPE);
+    }
+
+}
diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/.svn/text-base/EditListBox.java.svn-base b/isoparser/src/main/java/com/coremedia/iso/boxes/.svn/text-base/EditListBox.java.svn-base
new file mode 100644
index 0000000..231f8be
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/.svn/text-base/EditListBox.java.svn-base
@@ -0,0 +1,248 @@
+/*  
+ * Copyright 2008 CoreMedia AG, Hamburg
+ *
+ * Licensed under the Apache License, Version 2.0 (the License); 
+ * you may not use this file except in compliance with the License. 
+ * You may obtain a copy of the License at 
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0 
+ * 
+ * Unless required by applicable law or agreed to in writing, software 
+ * distributed under the License is distributed on an AS IS BASIS, 
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+ * See the License for the specific language governing permissions and 
+ * limitations under the License. 
+ */
+
+package com.coremedia.iso.boxes;
+
+
+import com.coremedia.iso.IsoTypeReader;
+import com.coremedia.iso.IsoTypeWriter;
+import com.googlecode.mp4parser.AbstractFullBox;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.util.LinkedList;
+import java.util.List;
+
+import static com.googlecode.mp4parser.util.CastUtils.l2i;
+
+/**
+ * <code>
+ * Box Type  : 'elst'<br>
+ * Container: {@link EditBox}('edts')<br>
+ * Mandatory: No<br>
+ * Quantity  : Zero or one</code><br><br>
+ * This box contains an explicit timeline map. Each entry defines part of the track time-line: by mapping part of
+ * the media time-line, or by indicating 'empty' time, or by defining a 'dwell', where a single time-point in the
+ * media is held for a period.<br>
+ * Note that edits are not restricted to fall on sample times. This means that when entering an edit, it can be
+ * necessary to (a) back up to a sync point, and pre-roll from there and then (b) be careful about the duration of
+ * the first sample - it might have been truncated if the edit enters it during its normal duration. If this is audio,
+ * that frame might need to be decoded, and then the final slicing done. Likewise, the duration of the last sample
+ * in an edit might need slicing. <br>
+ * Starting offsets for tracks (streams) are represented by an initial empty edit. For example, to play a track from
+ * its start for 30 seconds, but at 10 seconds into the presentation, we have the following edit list:<br>
+ * <p/>
+ * <li>Entry-count = 2</li>
+ * <li>Segment-duration = 10 seconds</li>
+ * <li>Media-Time = -1</li>
+ * <li>Media-Rate = 1</li>
+ * <li>Segment-duration = 30 seconds (could be the length of the whole track)</li>
+ * <li>Media-Time = 0 seconds</li>
+ * <li>Media-Rate = 1</li>
+ */
+public class EditListBox extends AbstractFullBox {
+    private List<Entry> entries = new LinkedList<Entry>();
+    public static final String TYPE = "elst";
+
+    public EditListBox() {
+        super(TYPE);
+    }
+
+
+    public List<Entry> getEntries() {
+        return entries;
+    }
+
+    public void setEntries(List<Entry> entries) {
+        this.entries = entries;
+    }
+
+    protected long getContentSize() {
+        long contentSize = 8;
+        if (getVersion() == 1) {
+            contentSize += entries.size() * 20;
+        } else {
+            contentSize += entries.size() * 12;
+        }
+
+        return contentSize;
+    }
+
+    @Override
+    public void _parseDetails(ByteBuffer content) {
+        parseVersionAndFlags(content);
+        int entryCount = l2i(IsoTypeReader.readUInt32(content));
+        entries = new LinkedList<Entry>();
+        for (int i = 0; i < entryCount; i++) {
+            entries.add(new Entry(this, content));
+
+        }
+    }
+
+    @Override
+    protected void getContent(ByteBuffer byteBuffer) {
+        writeVersionAndFlags(byteBuffer);
+        IsoTypeWriter.writeUInt32(byteBuffer, entries.size());
+        for (Entry entry : entries) {
+            entry.getContent(byteBuffer);
+        }
+    }
+
+    @Override
+    public String toString() {
+        return "EditListBox{" +
+                "entries=" + entries +
+                '}';
+    }
+
+    public static class Entry {
+        private long segmentDuration;
+        private long mediaTime;
+        private double mediaRate;
+        EditListBox editListBox;
+
+        /**
+         * Creates a new <code>Entry</code> with all values set.
+         *
+         * @param segmentDuration duration in movie timescale
+         * @param mediaTime       starting time
+         * @param mediaRate       relative play rate
+         */
+        public Entry(EditListBox editListBox, long segmentDuration, long mediaTime, double mediaRate) {
+            this.segmentDuration = segmentDuration;
+            this.mediaTime = mediaTime;
+            this.mediaRate = mediaRate;
+            this.editListBox = editListBox;
+        }
+
+        public Entry(EditListBox editListBox, ByteBuffer bb) {
+            if (editListBox.getVersion() == 1) {
+                segmentDuration = IsoTypeReader.readUInt64(bb);
+                mediaTime = IsoTypeReader.readUInt64(bb);
+                mediaRate = IsoTypeReader.readFixedPoint1616(bb);
+            } else {
+                segmentDuration = IsoTypeReader.readUInt32(bb);
+                mediaTime = IsoTypeReader.readUInt32(bb);
+                mediaRate = IsoTypeReader.readFixedPoint1616(bb);
+            }
+            this.editListBox = editListBox;
+        }
+
+        /**
+         * The segment duration is an integer that specifies the duration
+         * of this edit segment in units of the timescale in the Movie
+         * Header Box
+         *
+         * @return segment duration in movie timescale
+         */
+        public long getSegmentDuration() {
+            return segmentDuration;
+        }
+
+        /**
+         * The segment duration is an integer that specifies the duration
+         * of this edit segment in units of the timescale in the Movie
+         * Header Box
+         *
+         * @param segmentDuration new segment duration in movie timescale
+         */
+        public void setSegmentDuration(long segmentDuration) {
+            this.segmentDuration = segmentDuration;
+        }
+
+        /**
+         * The media time is an integer containing the starting time
+         * within the media of a specific edit segment(in media time
+         * scale units, in composition time)
+         *
+         * @return starting time
+         */
+        public long getMediaTime() {
+            return mediaTime;
+        }
+
+        /**
+         * The media time is an integer containing the starting time
+         * within the media of a specific edit segment(in media time
+         * scale units, in composition time)
+         *
+         * @param mediaTime starting time
+         */
+        public void setMediaTime(long mediaTime) {
+            this.mediaTime = mediaTime;
+        }
+
+        /**
+         * The media rate specifies the relative rate at which to play the
+         * media corresponding to a specific edit segment.
+         *
+         * @return relative play rate
+         */
+        public double getMediaRate() {
+            return mediaRate;
+        }
+
+        /**
+         * The media rate specifies the relative rate at which to play the
+         * media corresponding to a specific edit segment.
+         *
+         * @param mediaRate new relative play rate
+         */
+        public void setMediaRate(double mediaRate) {
+            this.mediaRate = mediaRate;
+        }
+
+        @Override
+        public boolean equals(Object o) {
+            if (this == o) return true;
+            if (o == null || getClass() != o.getClass()) return false;
+
+            Entry entry = (Entry) o;
+
+            if (mediaTime != entry.mediaTime) return false;
+            if (segmentDuration != entry.segmentDuration) return false;
+
+            return true;
+        }
+
+        @Override
+        public int hashCode() {
+            int result = (int) (segmentDuration ^ (segmentDuration >>> 32));
+            result = 31 * result + (int) (mediaTime ^ (mediaTime >>> 32));
+            return result;
+        }
+
+        public void getContent(ByteBuffer bb)  {
+            if (editListBox.getVersion() == 1) {
+                IsoTypeWriter.writeUInt64(bb, segmentDuration);
+                IsoTypeWriter.writeUInt64(bb, mediaTime);
+            } else {
+                IsoTypeWriter.writeUInt32(bb, l2i(segmentDuration));
+                bb.putInt(l2i(mediaTime));
+            }
+            IsoTypeWriter.writeFixedPont1616(bb, mediaRate);
+        }
+
+        @Override
+        public String toString() {
+            return "Entry{" +
+                    "segmentDuration=" + segmentDuration +
+                    ", mediaTime=" + mediaTime +
+                    ", mediaRate=" + mediaRate +
+                    '}';
+        }
+    }
+}
diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/.svn/text-base/FileTypeBox.java.svn-base b/isoparser/src/main/java/com/coremedia/iso/boxes/.svn/text-base/FileTypeBox.java.svn-base
new file mode 100644
index 0000000..e6eed20
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/.svn/text-base/FileTypeBox.java.svn-base
@@ -0,0 +1,144 @@
+/*  
+ * Copyright 2008 CoreMedia AG, Hamburg
+ *
+ * Licensed under the Apache License, Version 2.0 (the License); 
+ * you may not use this file except in compliance with the License. 
+ * You may obtain a copy of the License at 
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0 
+ * 
+ * Unless required by applicable law or agreed to in writing, software 
+ * distributed under the License is distributed on an AS IS BASIS, 
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+ * See the License for the specific language governing permissions and 
+ * limitations under the License. 
+ */
+
+package com.coremedia.iso.boxes;
+
+import com.coremedia.iso.IsoFile;
+import com.coremedia.iso.IsoTypeReader;
+import com.coremedia.iso.IsoTypeWriter;
+import com.googlecode.mp4parser.AbstractBox;
+import com.googlecode.mp4parser.annotations.DoNotParseDetail;
+
+import java.nio.ByteBuffer;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.LinkedList;
+import java.util.List;
+
+/**
+ * This box identifies the specifications to which this file complies. <br>
+ * Each brand is a printable four-character code, registered with ISO, that
+ * identifies a precise specification.
+ */
+public class FileTypeBox extends AbstractBox {
+    public static final String TYPE = "ftyp";
+
+    private String majorBrand;
+    private long minorVersion;
+    private List<String> compatibleBrands = Collections.emptyList();
+
+    public FileTypeBox() {
+        super(TYPE);
+    }
+
+    public FileTypeBox(String majorBrand, long minorVersion, List<String> compatibleBrands) {
+        super(TYPE);
+        this.majorBrand = majorBrand;
+        this.minorVersion = minorVersion;
+        this.compatibleBrands = compatibleBrands;
+    }
+
+    protected long getContentSize() {
+        return 8 + compatibleBrands.size() * 4;
+
+    }
+
+    @Override
+    public void _parseDetails(ByteBuffer content) {
+        majorBrand = IsoTypeReader.read4cc(content);
+        minorVersion = IsoTypeReader.readUInt32(content);
+        int compatibleBrandsCount = content.remaining() / 4;
+        compatibleBrands = new LinkedList<String>();
+        for (int i = 0; i < compatibleBrandsCount; i++) {
+            compatibleBrands.add(IsoTypeReader.read4cc(content));
+        }
+    }
+
+    @Override
+    protected void getContent(ByteBuffer byteBuffer) {
+        byteBuffer.put(IsoFile.fourCCtoBytes(majorBrand));
+        IsoTypeWriter.writeUInt32(byteBuffer, minorVersion);
+        for (String compatibleBrand : compatibleBrands) {
+            byteBuffer.put(IsoFile.fourCCtoBytes(compatibleBrand));
+        }
+
+    }
+
+    /**
+     * Gets the brand identifier.
+     *
+     * @return the brand identifier
+     */
+    public String getMajorBrand() {
+        return majorBrand;
+    }
+
+    /**
+     * Sets the major brand of the file used to determine an appropriate reader.
+     *
+     * @param majorBrand the new major brand
+     */
+    public void setMajorBrand(String majorBrand) {
+        this.majorBrand = majorBrand;
+    }
+
+    /**
+     * Sets the "informative integer for the minor version of the major brand".
+     *
+     * @param minorVersion the version number of the major brand
+     */
+    public void setMinorVersion(int minorVersion) {
+        this.minorVersion = minorVersion;
+    }
+
+    /**
+     * Gets an informative integer for the minor version of the major brand.
+     *
+     * @return an informative integer
+     * @see FileTypeBox#getMajorBrand()
+     */
+    public long getMinorVersion() {
+        return minorVersion;
+    }
+
+    /**
+     * Gets an array of 4-cc brands.
+     *
+     * @return the compatible brands
+     */
+    public List<String> getCompatibleBrands() {
+        return compatibleBrands;
+    }
+
+    public void setCompatibleBrands(List<String> compatibleBrands) {
+        this.compatibleBrands = compatibleBrands;
+    }
+
+    @DoNotParseDetail
+    public String toString() {
+        StringBuilder result = new StringBuilder();
+        result.append("FileTypeBox[");
+        result.append("majorBrand=").append(getMajorBrand());
+        result.append(";");
+        result.append("minorVersion=").append(getMinorVersion());
+        for (String compatibleBrand : compatibleBrands) {
+            result.append(";");
+            result.append("compatibleBrand=").append(compatibleBrand);
+        }
+        result.append("]");
+        return result.toString();
+    }
+}
diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/.svn/text-base/FreeBox.java.svn-base b/isoparser/src/main/java/com/coremedia/iso/boxes/.svn/text-base/FreeBox.java.svn-base
new file mode 100644
index 0000000..636c9a7
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/.svn/text-base/FreeBox.java.svn-base
@@ -0,0 +1,114 @@
+/*  
+ * Copyright 2008 CoreMedia AG, Hamburg
+ *
+ * Licensed under the Apache License, Version 2.0 (the License); 
+ * you may not use this file except in compliance with the License. 
+ * You may obtain a copy of the License at 
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0 
+ * 
+ * Unless required by applicable law or agreed to in writing, software 
+ * distributed under the License is distributed on an AS IS BASIS, 
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+ * See the License for the specific language governing permissions and 
+ * limitations under the License. 
+ */
+
+package com.coremedia.iso.boxes;
+
+
+import com.coremedia.iso.BoxParser;
+import com.coremedia.iso.ChannelHelper;
+import com.coremedia.iso.IsoTypeWriter;
+import com.googlecode.mp4parser.AbstractBox;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.nio.channels.FileChannel;
+import java.nio.channels.ReadableByteChannel;
+import java.nio.channels.WritableByteChannel;
+import java.util.LinkedList;
+import java.util.List;
+
+import static com.googlecode.mp4parser.util.CastUtils.l2i;
+
+/**
+ * A free box. Just a placeholder to enable editing without rewriting the whole file.
+ */
+public class FreeBox implements Box {
+    public static final String TYPE = "free";
+    ByteBuffer data;
+    List<Box> replacers = new LinkedList<Box>();
+    private ContainerBox parent;
+
+    public FreeBox() {
+    }
+
+    public FreeBox(int size) {
+        this.data = ByteBuffer.allocate(size);
+    }
+
+
+    public ByteBuffer getData() {
+        return data;
+    }
+
+    public void setData(ByteBuffer data) {
+        this.data = data;
+    }
+
+    public void getBox(WritableByteChannel os) throws IOException {
+        for (Box replacer : replacers) {
+            replacer.getBox(os);
+        }
+        ByteBuffer header = ByteBuffer.allocate(8);
+        IsoTypeWriter.writeUInt32(header, 8 + data.limit());
+        header.put(TYPE.getBytes());
+        header.rewind();
+        os.write(header);
+        data.rewind();
+        os.write(data);
+
+    }
+
+    public ContainerBox getParent() {
+        return parent;
+    }
+
+    public void setParent(ContainerBox parent) {
+        this.parent = parent;
+    }
+
+    public long getSize() {
+        long size = 8;
+        for (Box replacer : replacers) {
+            size += replacer.getSize();
+        }
+        size += data.limit();
+        return size;
+    }
+
+    public String getType() {
+        return TYPE;
+    }
+
+    public void parse(ReadableByteChannel readableByteChannel, ByteBuffer header, long contentSize, BoxParser boxParser) throws IOException {
+        if (readableByteChannel instanceof FileChannel && contentSize > 1024 * 1024) {
+            // It's quite expensive to map a file into the memory. Just do it when the box is larger than a MB.
+            data = ((FileChannel) readableByteChannel).map(FileChannel.MapMode.READ_ONLY, ((FileChannel) readableByteChannel).position(), contentSize);
+            ((FileChannel) readableByteChannel).position(((FileChannel) readableByteChannel).position() + contentSize);
+        } else {
+            assert contentSize < Integer.MAX_VALUE;
+            data = ChannelHelper.readFully(readableByteChannel, contentSize);
+        }
+    }
+
+
+    public void addAndReplace(Box box) {
+        data.position(l2i(box.getSize()));
+        data = data.slice();
+        replacers.add(box);
+    }
+
+
+}
\ No newline at end of file
diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/.svn/text-base/FreeSpaceBox.java.svn-base b/isoparser/src/main/java/com/coremedia/iso/boxes/.svn/text-base/FreeSpaceBox.java.svn-base
new file mode 100644
index 0000000..ed42bf9
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/.svn/text-base/FreeSpaceBox.java.svn-base
@@ -0,0 +1,63 @@
+/*  
+ * Copyright 2008 CoreMedia AG, Hamburg
+ *
+ * Licensed under the Apache License, Version 2.0 (the License); 
+ * you may not use this file except in compliance with the License. 
+ * You may obtain a copy of the License at 
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0 
+ * 
+ * Unless required by applicable law or agreed to in writing, software 
+ * distributed under the License is distributed on an AS IS BASIS, 
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+ * See the License for the specific language governing permissions and 
+ * limitations under the License. 
+ */
+
+package com.coremedia.iso.boxes;
+
+import com.googlecode.mp4parser.AbstractBox;
+
+import java.nio.ByteBuffer;
+
+/**
+ * The contents of a free-space box are irrelevant and may be ignored, or the object deleted, without affecting the
+ * presentation. Care should be excercized when deleting the object, as this may invalidate the offsets used in the
+ * sample table.
+ */
+public class FreeSpaceBox extends AbstractBox {
+    public static final String TYPE = "skip";
+
+    byte[] data;
+
+    protected long getContentSize() {
+        return data.length;
+    }
+
+    public FreeSpaceBox() {
+        super(TYPE);
+    }
+
+    public void setData(byte[] data) {
+        this.data = data;
+    }
+
+    public byte[] getData() {
+        return data;
+    }
+
+    @Override
+    public void _parseDetails(ByteBuffer content) {
+        data = new byte[content.remaining()];
+        content.get(data);
+    }
+
+    @Override
+    protected void getContent(ByteBuffer byteBuffer) {
+        byteBuffer.put(data);
+    }
+
+    public String toString() {
+        return "FreeSpaceBox[size=" + data.length + ";type=" + getType() + "]";
+    }
+}
diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/.svn/text-base/FullBox.java.svn-base b/isoparser/src/main/java/com/coremedia/iso/boxes/.svn/text-base/FullBox.java.svn-base
new file mode 100644
index 0000000..1515d76
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/.svn/text-base/FullBox.java.svn-base
@@ -0,0 +1,17 @@
+package com.coremedia.iso.boxes;
+
+import com.coremedia.iso.boxes.Box;
+
+/**
+ * The <code>FullBox</code> contains all getters and setters specific
+ * to a so-called full box according to the ISO/IEC 14496/12 specification.
+ */
+public interface FullBox extends Box {
+    int getVersion();
+
+    void setVersion(int version);
+
+    int getFlags();
+
+    void setFlags(int flags);
+}
diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/.svn/text-base/GenreBox.java.svn-base b/isoparser/src/main/java/com/coremedia/iso/boxes/.svn/text-base/GenreBox.java.svn-base
new file mode 100644
index 0000000..e2d1faf
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/.svn/text-base/GenreBox.java.svn-base
@@ -0,0 +1,80 @@
+/*  
+ * Copyright 2008 CoreMedia AG, Hamburg
+ *
+ * Licensed under the Apache License, Version 2.0 (the License); 
+ * you may not use this file except in compliance with the License. 
+ * You may obtain a copy of the License at 
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0 
+ * 
+ * Unless required by applicable law or agreed to in writing, software 
+ * distributed under the License is distributed on an AS IS BASIS, 
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+ * See the License for the specific language governing permissions and 
+ * limitations under the License. 
+ */
+
+package com.coremedia.iso.boxes;
+
+import com.coremedia.iso.IsoTypeReader;
+import com.coremedia.iso.IsoTypeWriter;
+import com.coremedia.iso.Utf8;
+import com.googlecode.mp4parser.AbstractFullBox;
+
+import java.nio.ByteBuffer;
+
+/**
+ * Containing genre information and contained in the <code>UserDataBox</code>.
+ *
+ * @see com.coremedia.iso.boxes.UserDataBox
+ */
+public class GenreBox extends AbstractFullBox {
+    public static final String TYPE = "gnre";
+
+    private String language;
+    private String genre;
+
+    public GenreBox() {
+        super(TYPE);
+    }
+
+    public String getLanguage() {
+        return language;
+    }
+
+    public String getGenre() {
+        return genre;
+    }
+
+    public void setLanguage(String language) {
+        this.language = language;
+    }
+
+    public void setGenre(String genre) {
+        this.genre = genre;
+    }
+
+    protected long getContentSize() {
+        return 7 + Utf8.utf8StringLengthInBytes(genre);
+    }
+
+    @Override
+    public void _parseDetails(ByteBuffer content) {
+        parseVersionAndFlags(content);
+        language = IsoTypeReader.readIso639(content);
+        genre = IsoTypeReader.readString(content);
+    }
+
+    @Override
+    protected void getContent(ByteBuffer byteBuffer) {
+        writeVersionAndFlags(byteBuffer);
+        IsoTypeWriter.writeIso639(byteBuffer, language);
+        byteBuffer.put(Utf8.convert(genre));
+        byteBuffer.put((byte) 0);
+    }
+
+    public String toString() {
+        return "GenreBox[language=" + getLanguage() + ";genre=" + getGenre() + "]";
+    }
+
+}
diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/.svn/text-base/HandlerBox.java.svn-base b/isoparser/src/main/java/com/coremedia/iso/boxes/.svn/text-base/HandlerBox.java.svn-base
new file mode 100644
index 0000000..01dcaca
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/.svn/text-base/HandlerBox.java.svn-base
@@ -0,0 +1,151 @@
+/*  
+ * Copyright 2008 CoreMedia AG, Hamburg
+ *
+ * Licensed under the Apache License, Version 2.0 (the License); 
+ * you may not use this file except in compliance with the License. 
+ * You may obtain a copy of the License at 
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0 
+ * 
+ * Unless required by applicable law or agreed to in writing, software 
+ * distributed under the License is distributed on an AS IS BASIS, 
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+ * See the License for the specific language governing permissions and 
+ * limitations under the License. 
+ */
+
+package com.coremedia.iso.boxes;
+
+
+import com.coremedia.iso.IsoFile;
+import com.coremedia.iso.IsoTypeReader;
+import com.coremedia.iso.IsoTypeWriter;
+import com.coremedia.iso.Utf8;
+import com.googlecode.mp4parser.AbstractFullBox;
+
+import java.nio.ByteBuffer;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * This box within a Media Box declares the process by which the media-data in the track is presented,
+ * and thus, the nature of the media in a track.
+ * This Box when present in a Meta Box, declares the structure or format of the 'meta' box contents.
+ * See ISO/IEC 14496-12 for details.
+ *
+ * @see MetaBox
+ * @see MediaBox
+ */
+public class HandlerBox extends AbstractFullBox {
+    public static final String TYPE = "hdlr";
+    public static final Map<String, String> readableTypes;
+
+    static {
+        HashMap<String, String> hm = new HashMap<String, String>();
+        hm.put("odsm", "ObjectDescriptorStream - defined in ISO/IEC JTC1/SC29/WG11 - CODING OF MOVING PICTURES AND AUDIO");
+        hm.put("crsm", "ClockReferenceStream - defined in ISO/IEC JTC1/SC29/WG11 - CODING OF MOVING PICTURES AND AUDIO");
+        hm.put("sdsm", "SceneDescriptionStream - defined in ISO/IEC JTC1/SC29/WG11 - CODING OF MOVING PICTURES AND AUDIO");
+        hm.put("m7sm", "MPEG7Stream - defined in ISO/IEC JTC1/SC29/WG11 - CODING OF MOVING PICTURES AND AUDIO");
+        hm.put("ocsm", "ObjectContentInfoStream - defined in ISO/IEC JTC1/SC29/WG11 - CODING OF MOVING PICTURES AND AUDIO");
+        hm.put("ipsm", "IPMP Stream - defined in ISO/IEC JTC1/SC29/WG11 - CODING OF MOVING PICTURES AND AUDIO");
+        hm.put("mjsm", "MPEG-J Stream - defined in ISO/IEC JTC1/SC29/WG11 - CODING OF MOVING PICTURES AND AUDIO");
+        hm.put("mdir", "Apple Meta Data iTunes Reader");
+        hm.put("mp7b", "MPEG-7 binary XML");
+        hm.put("mp7t", "MPEG-7 XML");
+        hm.put("vide", "Video Track");
+        hm.put("soun", "Sound Track");
+        hm.put("hint", "Hint Track");
+        hm.put("appl", "Apple specific");
+        hm.put("meta", "Timed Metadata track - defined in ISO/IEC JTC1/SC29/WG11 - CODING OF MOVING PICTURES AND AUDIO");
+
+        readableTypes = Collections.unmodifiableMap(hm);
+
+    }
+
+    private String handlerType;
+    private String name = null;
+    private long a, b, c;
+    private boolean zeroTerm = true;
+
+    private long shouldBeZeroButAppleWritesHereSomeValue;
+
+    public HandlerBox() {
+        super(TYPE);
+    }
+
+    public String getHandlerType() {
+        return handlerType;
+    }
+
+    /**
+     * You are required to add a '\0' string termination by yourself.
+     *
+     * @param name the new human readable name
+     */
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    public void setHandlerType(String handlerType) {
+        this.handlerType = handlerType;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public String getHumanReadableTrackType() {
+        return readableTypes.get(handlerType) != null ? readableTypes.get(handlerType) : "Unknown Handler Type";
+    }
+
+    protected long getContentSize() {
+        if (zeroTerm) {
+            return 25 + Utf8.utf8StringLengthInBytes(name);
+        } else {
+            return 24 + Utf8.utf8StringLengthInBytes(name);
+        }
+
+    }
+
+    @Override
+    public void _parseDetails(ByteBuffer content) {
+        parseVersionAndFlags(content);
+        shouldBeZeroButAppleWritesHereSomeValue = IsoTypeReader.readUInt32(content);
+        handlerType = IsoTypeReader.read4cc(content);
+        a = IsoTypeReader.readUInt32(content);
+        b = IsoTypeReader.readUInt32(content);
+        c = IsoTypeReader.readUInt32(content);
+        if (content.remaining() > 0) {
+            name = IsoTypeReader.readString(content, content.remaining());
+            if (name.endsWith("\0")) {
+                name = name.substring(0, name.length() - 1);
+                zeroTerm = true;
+            } else {
+                zeroTerm = false;
+            }
+        } else {
+            zeroTerm = false; //No string at all, not even zero term char
+        }
+    }
+
+    @Override
+    protected void getContent(ByteBuffer byteBuffer) {
+        writeVersionAndFlags(byteBuffer);
+        IsoTypeWriter.writeUInt32(byteBuffer, shouldBeZeroButAppleWritesHereSomeValue);
+        byteBuffer.put(IsoFile.fourCCtoBytes(handlerType));
+        IsoTypeWriter.writeUInt32(byteBuffer, a);
+        IsoTypeWriter.writeUInt32(byteBuffer, b);
+        IsoTypeWriter.writeUInt32(byteBuffer, c);
+        if (name != null) {
+            byteBuffer.put(Utf8.convert(name));
+        }
+        if (zeroTerm) {
+            byteBuffer.put((byte) 0);
+        }
+    }
+
+    public String toString() {
+        return "HandlerBox[handlerType=" + getHandlerType() + ";name=" + getName() + "]";
+    }
+}
diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/.svn/text-base/HintMediaHeaderBox.java.svn-base b/isoparser/src/main/java/com/coremedia/iso/boxes/.svn/text-base/HintMediaHeaderBox.java.svn-base
new file mode 100644
index 0000000..3477738
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/.svn/text-base/HintMediaHeaderBox.java.svn-base
@@ -0,0 +1,91 @@
+/*  
+ * Copyright 2008 CoreMedia AG, Hamburg
+ *
+ * Licensed under the Apache License, Version 2.0 (the License); 
+ * you may not use this file except in compliance with the License. 
+ * You may obtain a copy of the License at 
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0 
+ * 
+ * Unless required by applicable law or agreed to in writing, software 
+ * distributed under the License is distributed on an AS IS BASIS, 
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+ * See the License for the specific language governing permissions and 
+ * limitations under the License. 
+ */
+
+package com.coremedia.iso.boxes;
+
+import com.coremedia.iso.IsoTypeReader;
+import com.coremedia.iso.IsoTypeWriter;
+
+import java.nio.ByteBuffer;
+
+/**
+ * The hint media header contains general information, independent of the protocaol, for hint tracks. Resides
+ * in Media Information Box.
+ *
+ * @see com.coremedia.iso.boxes.MediaInformationBox
+ */
+public class HintMediaHeaderBox extends AbstractMediaHeaderBox {
+    private int maxPduSize;
+    private int avgPduSize;
+    private long maxBitrate;
+    private long avgBitrate;
+    public static final String TYPE = "hmhd";
+
+    public HintMediaHeaderBox() {
+        super(TYPE);
+    }
+
+    public int getMaxPduSize() {
+        return maxPduSize;
+    }
+
+    public int getAvgPduSize() {
+        return avgPduSize;
+    }
+
+    public long getMaxBitrate() {
+        return maxBitrate;
+    }
+
+    public long getAvgBitrate() {
+        return avgBitrate;
+    }
+
+    protected long getContentSize() {
+        return 20;
+    }
+
+    @Override
+    public void _parseDetails(ByteBuffer content) {
+        parseVersionAndFlags(content);
+        maxPduSize = IsoTypeReader.readUInt16(content);
+        avgPduSize = IsoTypeReader.readUInt16(content);
+        maxBitrate = IsoTypeReader.readUInt32(content);
+        avgBitrate = IsoTypeReader.readUInt32(content);
+        IsoTypeReader.readUInt32(content);    // reserved!
+
+    }
+
+    @Override
+    protected void getContent(ByteBuffer byteBuffer) {
+        writeVersionAndFlags(byteBuffer);
+        IsoTypeWriter.writeUInt16(byteBuffer, maxPduSize);
+        IsoTypeWriter.writeUInt16(byteBuffer, avgPduSize);
+        IsoTypeWriter.writeUInt32(byteBuffer, maxBitrate);
+        IsoTypeWriter.writeUInt32(byteBuffer, avgBitrate);
+        IsoTypeWriter.writeUInt32(byteBuffer, 0);
+    }
+
+    @Override
+    public String toString() {
+        return "HintMediaHeaderBox{" +
+                "maxPduSize=" + maxPduSize +
+                ", avgPduSize=" + avgPduSize +
+                ", maxBitrate=" + maxBitrate +
+                ", avgBitrate=" + avgBitrate +
+                '}';
+    }
+}
diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/.svn/text-base/ItemDataBox.java.svn-base b/isoparser/src/main/java/com/coremedia/iso/boxes/.svn/text-base/ItemDataBox.java.svn-base
new file mode 100644
index 0000000..46097cc
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/.svn/text-base/ItemDataBox.java.svn-base
@@ -0,0 +1,43 @@
+package com.coremedia.iso.boxes;
+
+import com.googlecode.mp4parser.AbstractBox;
+
+import java.nio.ByteBuffer;
+
+/**
+ *
+ */
+public class ItemDataBox extends AbstractBox {
+    ByteBuffer data = ByteBuffer.allocate(0);
+    public static final String TYPE = "idat";
+
+
+    public ItemDataBox() {
+        super(TYPE);
+    }
+
+    public ByteBuffer getData() {
+        return data;
+    }
+
+    public void setData(ByteBuffer data) {
+        this.data = data;
+    }
+
+    @Override
+    protected long getContentSize() {
+        return data.limit();
+    }
+
+
+    @Override
+    public void _parseDetails(ByteBuffer content) {
+        data = content.slice();
+        content.position(content.position() + content.remaining());
+    }
+
+    @Override
+    protected void getContent(ByteBuffer byteBuffer) {
+        byteBuffer.put(data);
+    }
+}
diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/.svn/text-base/ItemLocationBox.java.svn-base b/isoparser/src/main/java/com/coremedia/iso/boxes/.svn/text-base/ItemLocationBox.java.svn-base
new file mode 100644
index 0000000..6dcee6f
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/.svn/text-base/ItemLocationBox.java.svn-base
@@ -0,0 +1,360 @@
+/*  
+ * Copyright 2008 CoreMedia AG, Hamburg
+ *
+ * Licensed under the Apache License, Version 2.0 (the License); 
+ * you may not use this file except in compliance with the License. 
+ * You may obtain a copy of the License at 
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0 
+ * 
+ * Unless required by applicable law or agreed to in writing, software 
+ * distributed under the License is distributed on an AS IS BASIS, 
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+ * See the License for the specific language governing permissions and 
+ * limitations under the License. 
+ */
+
+package com.coremedia.iso.boxes;
+
+
+import com.coremedia.iso.IsoTypeReader;
+import com.coremedia.iso.IsoTypeReaderVariable;
+import com.coremedia.iso.IsoTypeWriter;
+import com.coremedia.iso.IsoTypeWriterVariable;
+import com.googlecode.mp4parser.AbstractFullBox;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.util.LinkedList;
+import java.util.List;
+
+/**
+ * aligned(8) class ItemLocationBox extends FullBox(‘iloc’, version, 0) {
+ * unsigned int(4) offset_size;
+ * unsigned int(4) length_size;
+ * unsigned int(4) base_offset_size;
+ * if (version == 1)
+ * unsigned int(4) index_size;
+ * else
+ * unsigned int(4) reserved;
+ * unsigned int(16) item_count;
+ * for (i=0; i<item_count; i++) {
+ * unsigned int(16) item_ID;
+ * if (version == 1) {
+ * unsigned int(12) reserved = 0;
+ * unsigned int(4) construction_method;
+ * }
+ * unsigned int(16) data_reference_index;
+ * unsigned int(base_offset_size*8) base_offset;
+ * unsigned int(16) extent_count;
+ * for (j=0; j<extent_count; j++) {
+ * if ((version == 1) && (index_size > 0)) {
+ * unsigned int(index_size*8) extent_index;
+ * }
+ * unsigned int(offset_size*8) extent_offset;
+ * unsigned int(length_size*8) extent_length;
+ * }
+ * }
+ * }
+ */
+public class ItemLocationBox extends AbstractFullBox {
+    public int offsetSize = 8;
+    public int lengthSize = 8;
+    public int baseOffsetSize = 8;
+    public int indexSize = 0;
+    public List<Item> items = new LinkedList<Item>();
+
+    public static final String TYPE = "iloc";
+
+    public ItemLocationBox() {
+        super(TYPE);
+    }
+
+    @Override
+    protected long getContentSize() {
+        long size = 8;
+        for (Item item : items) {
+            size += item.getSize();
+        }
+        return size;
+    }
+
+
+    @Override
+    protected void getContent(ByteBuffer byteBuffer) {
+        writeVersionAndFlags(byteBuffer);
+        IsoTypeWriter.writeUInt8(byteBuffer, ((offsetSize << 4) | lengthSize));
+        if (getVersion() == 1) {
+            IsoTypeWriter.writeUInt8(byteBuffer, (baseOffsetSize << 4 | indexSize));
+        } else {
+            IsoTypeWriter.writeUInt8(byteBuffer, (baseOffsetSize << 4));
+        }
+        IsoTypeWriter.writeUInt16(byteBuffer, items.size());
+        for (Item item : items) {
+            item.getContent(byteBuffer);
+        }
+    }
+
+    @Override
+    public void _parseDetails(ByteBuffer content) {
+        parseVersionAndFlags(content);
+        int tmp = IsoTypeReader.readUInt8(content);
+        offsetSize = tmp >>> 4;
+        lengthSize = tmp & 0xf;
+        tmp = IsoTypeReader.readUInt8(content);
+        baseOffsetSize = tmp >>> 4;
+
+        if (getVersion() == 1) {
+            indexSize = tmp & 0xf;
+        }
+        int itemCount = IsoTypeReader.readUInt16(content);
+        for (int i = 0; i < itemCount; i++) {
+            items.add(new Item(content));
+        }
+    }
+
+
+    public int getOffsetSize() {
+        return offsetSize;
+    }
+
+    public void setOffsetSize(int offsetSize) {
+        this.offsetSize = offsetSize;
+    }
+
+    public int getLengthSize() {
+        return lengthSize;
+    }
+
+    public void setLengthSize(int lengthSize) {
+        this.lengthSize = lengthSize;
+    }
+
+    public int getBaseOffsetSize() {
+        return baseOffsetSize;
+    }
+
+    public void setBaseOffsetSize(int baseOffsetSize) {
+        this.baseOffsetSize = baseOffsetSize;
+    }
+
+    public int getIndexSize() {
+        return indexSize;
+    }
+
+    public void setIndexSize(int indexSize) {
+        this.indexSize = indexSize;
+    }
+
+    public List<Item> getItems() {
+        return items;
+    }
+
+    public void setItems(List<Item> items) {
+        this.items = items;
+    }
+
+
+    public Item createItem(int itemId, int constructionMethod, int dataReferenceIndex, long baseOffset, List<Extent> extents) {
+        return new Item(itemId, constructionMethod, dataReferenceIndex, baseOffset, extents);
+    }
+
+    Item createItem(ByteBuffer bb) {
+        return new Item(bb);
+    }
+
+    public class Item {
+        public int itemId;
+        public int constructionMethod;
+        public int dataReferenceIndex;
+        public long baseOffset;
+        public List<Extent> extents = new LinkedList<Extent>();
+
+        public Item(ByteBuffer in) {
+            itemId = IsoTypeReader.readUInt16(in);
+
+            if (getVersion() == 1) {
+                int tmp = IsoTypeReader.readUInt16(in);
+                constructionMethod = tmp & 0xf;
+            }
+
+            dataReferenceIndex = IsoTypeReader.readUInt16(in);
+            if (baseOffsetSize > 0) {
+                baseOffset = IsoTypeReaderVariable.read(in, baseOffsetSize);
+            } else {
+                baseOffset = 0;
+            }
+            int extentCount = IsoTypeReader.readUInt16(in);
+
+
+            for (int i = 0; i < extentCount; i++) {
+                extents.add(new Extent(in));
+            }
+        }
+
+        public Item(int itemId, int constructionMethod, int dataReferenceIndex, long baseOffset, List<Extent> extents) {
+            this.itemId = itemId;
+            this.constructionMethod = constructionMethod;
+            this.dataReferenceIndex = dataReferenceIndex;
+            this.baseOffset = baseOffset;
+            this.extents = extents;
+        }
+
+        public int getSize() {
+            int size = 2;
+
+            if (getVersion() == 1) {
+                size += 2;
+            }
+
+            size += 2;
+            size += baseOffsetSize;
+            size += 2;
+
+
+            for (Extent extent : extents) {
+                size += extent.getSize();
+            }
+            return size;
+        }
+
+        public void setBaseOffset(long baseOffset) {
+            this.baseOffset = baseOffset;
+        }
+
+        public void getContent(ByteBuffer bb)  {
+            IsoTypeWriter.writeUInt16(bb, itemId);
+
+            if (getVersion() == 1) {
+                IsoTypeWriter.writeUInt16(bb, constructionMethod);
+            }
+
+
+            IsoTypeWriter.writeUInt16(bb, dataReferenceIndex);
+            if (baseOffsetSize > 0) {
+                IsoTypeWriterVariable.write(baseOffset, bb, baseOffsetSize);
+            }
+            IsoTypeWriter.writeUInt16(bb, extents.size());
+
+            for (Extent extent : extents) {
+                extent.getContent(bb);
+            }
+        }
+
+        @Override
+        public boolean equals(Object o) {
+            if (this == o) return true;
+            if (o == null || getClass() != o.getClass()) return false;
+
+            Item item = (Item) o;
+
+            if (baseOffset != item.baseOffset) return false;
+            if (constructionMethod != item.constructionMethod) return false;
+            if (dataReferenceIndex != item.dataReferenceIndex) return false;
+            if (itemId != item.itemId) return false;
+            if (extents != null ? !extents.equals(item.extents) : item.extents != null) return false;
+
+            return true;
+        }
+
+        @Override
+        public int hashCode() {
+            int result = itemId;
+            result = 31 * result + constructionMethod;
+            result = 31 * result + dataReferenceIndex;
+            result = 31 * result + (int) (baseOffset ^ (baseOffset >>> 32));
+            result = 31 * result + (extents != null ? extents.hashCode() : 0);
+            return result;
+        }
+
+        @Override
+        public String toString() {
+            return "Item{" +
+                    "baseOffset=" + baseOffset +
+                    ", itemId=" + itemId +
+                    ", constructionMethod=" + constructionMethod +
+                    ", dataReferenceIndex=" + dataReferenceIndex +
+                    ", extents=" + extents +
+                    '}';
+        }
+    }
+
+
+    public Extent createExtent(long extentOffset, long extentLength, long extentIndex) {
+        return new Extent(extentOffset, extentLength, extentIndex);
+    }
+
+    Extent createExtent(ByteBuffer bb) {
+        return new Extent(bb);
+    }
+
+
+    public class Extent {
+        public long extentOffset;
+        public long extentLength;
+        public long extentIndex;
+
+        public Extent(long extentOffset, long extentLength, long extentIndex) {
+            this.extentOffset = extentOffset;
+            this.extentLength = extentLength;
+            this.extentIndex = extentIndex;
+        }
+
+
+        public Extent(ByteBuffer in) {
+            if ((getVersion() == 1) && indexSize > 0) {
+                extentIndex = IsoTypeReaderVariable.read(in, indexSize);
+            }
+            extentOffset = IsoTypeReaderVariable.read(in, offsetSize);
+            extentLength = IsoTypeReaderVariable.read(in, lengthSize);
+        }
+
+        public void getContent(ByteBuffer os)  {
+            if ((getVersion() == 1) && indexSize > 0) {
+                IsoTypeWriterVariable.write(extentIndex, os, indexSize);
+            }
+            IsoTypeWriterVariable.write(extentOffset, os, offsetSize);
+            IsoTypeWriterVariable.write(extentLength, os, lengthSize);
+        }
+
+        public int getSize() {
+            return (indexSize > 0 ? indexSize : 0) + offsetSize + lengthSize;
+        }
+
+
+        @Override
+        public boolean equals(Object o) {
+            if (this == o) return true;
+            if (o == null || getClass() != o.getClass()) return false;
+
+            Extent extent = (Extent) o;
+
+            if (extentIndex != extent.extentIndex) return false;
+            if (extentLength != extent.extentLength) return false;
+            if (extentOffset != extent.extentOffset) return false;
+
+            return true;
+        }
+
+        @Override
+        public int hashCode() {
+            int result = (int) (extentOffset ^ (extentOffset >>> 32));
+            result = 31 * result + (int) (extentLength ^ (extentLength >>> 32));
+            result = 31 * result + (int) (extentIndex ^ (extentIndex >>> 32));
+            return result;
+        }
+
+        @Override
+        public String toString() {
+            final StringBuilder sb = new StringBuilder();
+            sb.append("Extent");
+            sb.append("{extentOffset=").append(extentOffset);
+            sb.append(", extentLength=").append(extentLength);
+            sb.append(", extentIndex=").append(extentIndex);
+            sb.append('}');
+            return sb.toString();
+        }
+    }
+
+
+}
diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/.svn/text-base/ItemProtectionBox.java.svn-base b/isoparser/src/main/java/com/coremedia/iso/boxes/.svn/text-base/ItemProtectionBox.java.svn-base
new file mode 100644
index 0000000..7eed790
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/.svn/text-base/ItemProtectionBox.java.svn-base
@@ -0,0 +1,61 @@
+/*  
+ * Copyright 2008 CoreMedia AG, Hamburg
+ *
+ * Licensed under the Apache License, Version 2.0 (the License); 
+ * you may not use this file except in compliance with the License. 
+ * You may obtain a copy of the License at 
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0 
+ * 
+ * Unless required by applicable law or agreed to in writing, software 
+ * distributed under the License is distributed on an AS IS BASIS, 
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+ * See the License for the specific language governing permissions and 
+ * limitations under the License. 
+ */
+
+package com.coremedia.iso.boxes;
+
+import com.coremedia.iso.IsoTypeReader;
+import com.coremedia.iso.IsoTypeWriter;
+import com.googlecode.mp4parser.FullContainerBox;
+
+import java.nio.ByteBuffer;
+
+/**
+ * The Item Protection Box provides an array of item protection information, for use by the Item Information Box.
+ *
+ * @see com.coremedia.iso.boxes.ItemProtectionBox
+ */
+public class ItemProtectionBox extends FullContainerBox {
+
+    public static final String TYPE = "ipro";
+
+    public ItemProtectionBox() {
+        super(TYPE);
+    }
+
+    public SchemeInformationBox getItemProtectionScheme() {
+        if (!getBoxes(SchemeInformationBox.class).isEmpty()) {
+            return getBoxes(SchemeInformationBox.class).get(0);
+        } else {
+            return null;
+        }
+    }
+
+    @Override
+    public void _parseDetails(ByteBuffer content) {
+        parseVersionAndFlags(content);
+        IsoTypeReader.readUInt16(content);
+        parseChildBoxes(content);
+    }
+
+
+    @Override
+    protected void getContent(ByteBuffer byteBuffer) {
+        writeVersionAndFlags(byteBuffer);
+        IsoTypeWriter.writeUInt16(byteBuffer, getBoxes().size());
+        writeChildBoxes(byteBuffer);
+    }
+
+}
diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/.svn/text-base/KeywordsBox.java.svn-base b/isoparser/src/main/java/com/coremedia/iso/boxes/.svn/text-base/KeywordsBox.java.svn-base
new file mode 100644
index 0000000..d9b7c0c
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/.svn/text-base/KeywordsBox.java.svn-base
@@ -0,0 +1,95 @@
+/*  
+ * Copyright 2008 CoreMedia AG, Hamburg
+ *
+ * Licensed under the Apache License, Version 2.0 (the License); 
+ * you may not use this file except in compliance with the License. 
+ * You may obtain a copy of the License at 
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0 
+ * 
+ * Unless required by applicable law or agreed to in writing, software 
+ * distributed under the License is distributed on an AS IS BASIS, 
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+ * See the License for the specific language governing permissions and 
+ * limitations under the License. 
+ */
+
+package com.coremedia.iso.boxes;
+
+import com.coremedia.iso.IsoTypeReader;
+import com.coremedia.iso.IsoTypeWriter;
+import com.coremedia.iso.Utf8;
+import com.googlecode.mp4parser.AbstractFullBox;
+
+import java.nio.ByteBuffer;
+
+/**
+ * List of keywords according to 3GPP 26.244.
+ */
+public class KeywordsBox extends AbstractFullBox {
+    public static final String TYPE = "kywd";
+
+    private String language;
+    private String[] keywords;
+
+    public KeywordsBox() {
+        super(TYPE);
+    }
+
+    public String getLanguage() {
+        return language;
+    }
+
+    public String[] getKeywords() {
+        return keywords;
+    }
+
+    public void setLanguage(String language) {
+        this.language = language;
+    }
+
+    public void setKeywords(String[] keywords) {
+        this.keywords = keywords;
+    }
+
+    protected long getContentSize() {
+        long contentSize = 7;
+        for (String keyword : keywords) {
+            contentSize += 1 + Utf8.utf8StringLengthInBytes(keyword) + 1;
+        }
+        return contentSize;
+    }
+
+    @Override
+    public void _parseDetails(ByteBuffer content) {
+        parseVersionAndFlags(content);
+        language = IsoTypeReader.readIso639(content);
+        int keywordCount = IsoTypeReader.readUInt8(content);
+        keywords = new String[keywordCount];
+        for (int i = 0; i < keywordCount; i++) {
+            IsoTypeReader.readUInt8(content);
+            keywords[i] = IsoTypeReader.readString(content);
+        }
+    }
+
+    @Override
+    protected void getContent(ByteBuffer byteBuffer) {
+        writeVersionAndFlags(byteBuffer);
+        IsoTypeWriter.writeIso639(byteBuffer, language);
+        IsoTypeWriter.writeUInt8(byteBuffer, keywords.length);
+        for (String keyword : keywords) {
+            IsoTypeWriter.writeUInt8(byteBuffer, Utf8.utf8StringLengthInBytes(keyword) + 1);
+            byteBuffer.put(Utf8.convert(keyword));
+        }
+    }
+
+    public String toString() {
+        StringBuffer buffer = new StringBuffer();
+        buffer.append("KeywordsBox[language=").append(getLanguage());
+        for (int i = 0; i < keywords.length; i++) {
+            buffer.append(";keyword").append(i).append("=").append(keywords[i]);
+        }
+        buffer.append("]");
+        return buffer.toString();
+    }
+}
diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/.svn/text-base/MediaBox.java.svn-base b/isoparser/src/main/java/com/coremedia/iso/boxes/.svn/text-base/MediaBox.java.svn-base
new file mode 100644
index 0000000..fa5642c
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/.svn/text-base/MediaBox.java.svn-base
@@ -0,0 +1,61 @@
+/*  
+ * Copyright 2008 CoreMedia AG, Hamburg
+ *
+ * Licensed under the Apache License, Version 2.0 (the License); 
+ * you may not use this file except in compliance with the License. 
+ * You may obtain a copy of the License at 
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0 
+ * 
+ * Unless required by applicable law or agreed to in writing, software 
+ * distributed under the License is distributed on an AS IS BASIS, 
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+ * See the License for the specific language governing permissions and 
+ * limitations under the License. 
+ */
+
+package com.coremedia.iso.boxes;
+
+
+import com.googlecode.mp4parser.AbstractContainerBox;
+
+/**
+ * The media declaration container contains all the objects that declare information about the media data within a
+ * track.
+ */
+public class MediaBox extends AbstractContainerBox {
+    public static final String TYPE = "mdia";
+
+    public MediaBox() {
+        super(TYPE);
+    }
+
+    public MediaInformationBox getMediaInformationBox() {
+        for (Box box : boxes) {
+            if (box instanceof MediaInformationBox) {
+                return (MediaInformationBox) box;
+            }
+        }
+        return null;
+    }
+
+    public MediaHeaderBox getMediaHeaderBox() {
+        for (Box box : boxes) {
+            if (box instanceof MediaHeaderBox) {
+                return (MediaHeaderBox) box;
+            }
+        }
+        return null;
+    }
+
+    public HandlerBox getHandlerBox() {
+        for (Box box : boxes) {
+            if (box instanceof HandlerBox) {
+                return (HandlerBox) box;
+            }
+        }
+        return null;
+    }
+
+
+}
diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/.svn/text-base/MediaHeaderBox.java.svn-base b/isoparser/src/main/java/com/coremedia/iso/boxes/.svn/text-base/MediaHeaderBox.java.svn-base
new file mode 100644
index 0000000..69b538b
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/.svn/text-base/MediaHeaderBox.java.svn-base
@@ -0,0 +1,147 @@
+/*  
+ * Copyright 2008 CoreMedia AG, Hamburg
+ *
+ * Licensed under the Apache License, Version 2.0 (the License); 
+ * you may not use this file except in compliance with the License. 
+ * You may obtain a copy of the License at 
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0 
+ * 
+ * Unless required by applicable law or agreed to in writing, software 
+ * distributed under the License is distributed on an AS IS BASIS, 
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+ * See the License for the specific language governing permissions and 
+ * limitations under the License. 
+ */
+
+package com.coremedia.iso.boxes;
+
+import com.coremedia.iso.IsoTypeReader;
+import com.coremedia.iso.IsoTypeWriter;
+import com.googlecode.mp4parser.AbstractFullBox;
+
+import java.nio.ByteBuffer;
+
+/**
+ * This box defines overall information which is media-independent, and relevant to the entire presentation
+ * considered as a whole.
+ */
+public class MediaHeaderBox extends AbstractFullBox {
+    public static final String TYPE = "mdhd";
+
+
+    private long creationTime;
+    private long modificationTime;
+    private long timescale;
+    private long duration;
+    private String language;
+
+    public MediaHeaderBox() {
+        super(TYPE);
+    }
+
+    public long getCreationTime() {
+        return creationTime;
+    }
+
+    public long getModificationTime() {
+        return modificationTime;
+    }
+
+    public long getTimescale() {
+        return timescale;
+    }
+
+    public long getDuration() {
+        return duration;
+    }
+
+    public String getLanguage() {
+        return language;
+    }
+
+    protected long getContentSize() {
+        long contentSize = 4;
+        if (getVersion() == 1) {
+            contentSize += 8 + 8 + 4 + 8;
+        } else {
+            contentSize += 4 + 4 + 4 + 4;
+        }
+        contentSize += 2;
+        contentSize += 2;
+        return contentSize;
+
+    }
+
+    public void setCreationTime(long creationTime) {
+        this.creationTime = creationTime;
+    }
+
+    public void setModificationTime(long modificationTime) {
+        this.modificationTime = modificationTime;
+    }
+
+    public void setTimescale(long timescale) {
+        this.timescale = timescale;
+    }
+
+    public void setDuration(long duration) {
+        this.duration = duration;
+    }
+
+    public void setLanguage(String language) {
+        this.language = language;
+    }
+
+    @Override
+    public void _parseDetails(ByteBuffer content) {
+        parseVersionAndFlags(content);
+        if (getVersion() == 1) {
+            creationTime = IsoTypeReader.readUInt64(content);
+            modificationTime = IsoTypeReader.readUInt64(content);
+            timescale = IsoTypeReader.readUInt32(content);
+            duration = IsoTypeReader.readUInt64(content);
+        } else {
+            creationTime = IsoTypeReader.readUInt32(content);
+            modificationTime = IsoTypeReader.readUInt32(content);
+            timescale = IsoTypeReader.readUInt32(content);
+            duration = IsoTypeReader.readUInt32(content);
+        }
+        language = IsoTypeReader.readIso639(content);
+        IsoTypeReader.readUInt16(content);
+    }
+
+
+    public String toString() {
+        StringBuilder result = new StringBuilder();
+        result.append("MediaHeaderBox[");
+        result.append("creationTime=").append(getCreationTime());
+        result.append(";");
+        result.append("modificationTime=").append(getModificationTime());
+        result.append(";");
+        result.append("timescale=").append(getTimescale());
+        result.append(";");
+        result.append("duration=").append(getDuration());
+        result.append(";");
+        result.append("language=").append(getLanguage());
+        result.append("]");
+        return result.toString();
+    }
+
+    protected void getContent(ByteBuffer byteBuffer) {
+        writeVersionAndFlags(byteBuffer);
+        if (getVersion() == 1) {
+            IsoTypeWriter.writeUInt64(byteBuffer, creationTime);
+            IsoTypeWriter.writeUInt64(byteBuffer, modificationTime);
+            IsoTypeWriter.writeUInt32(byteBuffer, timescale);
+            IsoTypeWriter.writeUInt64(byteBuffer, duration);
+        } else {
+            IsoTypeWriter.writeUInt32(byteBuffer, creationTime);
+            IsoTypeWriter.writeUInt32(byteBuffer, modificationTime);
+            IsoTypeWriter.writeUInt32(byteBuffer, timescale);
+            IsoTypeWriter.writeUInt32(byteBuffer, duration);
+        }
+        IsoTypeWriter.writeIso639(byteBuffer, language);
+        IsoTypeWriter.writeUInt16(byteBuffer, 0);
+    }
+}
diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/.svn/text-base/MediaInformationBox.java.svn-base b/isoparser/src/main/java/com/coremedia/iso/boxes/.svn/text-base/MediaInformationBox.java.svn-base
new file mode 100644
index 0000000..ed25051
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/.svn/text-base/MediaInformationBox.java.svn-base
@@ -0,0 +1,49 @@
+/*  
+ * Copyright 2008 CoreMedia AG, Hamburg
+ *
+ * Licensed under the Apache License, Version 2.0 (the License); 
+ * you may not use this file except in compliance with the License. 
+ * You may obtain a copy of the License at 
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0 
+ * 
+ * Unless required by applicable law or agreed to in writing, software 
+ * distributed under the License is distributed on an AS IS BASIS, 
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+ * See the License for the specific language governing permissions and 
+ * limitations under the License. 
+ */
+
+package com.coremedia.iso.boxes;
+
+import com.googlecode.mp4parser.AbstractContainerBox;
+
+/**
+ * This box contains all the objects that declare characteristic information of the media in the track.
+ */
+public class MediaInformationBox extends AbstractContainerBox {
+    public static final String TYPE = "minf";
+
+    public MediaInformationBox() {
+        super(TYPE);
+    }
+
+    public SampleTableBox getSampleTableBox() {
+        for (Box box : boxes) {
+            if (box instanceof SampleTableBox) {
+                return (SampleTableBox) box;
+            }
+        }
+        return null;
+    }
+
+    public AbstractMediaHeaderBox getMediaHeaderBox() {
+        for (Box box : boxes) {
+            if (box instanceof AbstractMediaHeaderBox) {
+                return (AbstractMediaHeaderBox) box;
+            }
+        }
+        return null;
+    }
+
+}
diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/.svn/text-base/MetaBox.java.svn-base b/isoparser/src/main/java/com/coremedia/iso/boxes/.svn/text-base/MetaBox.java.svn-base
new file mode 100644
index 0000000..35499ec
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/.svn/text-base/MetaBox.java.svn-base
@@ -0,0 +1,113 @@
+/*  
+ * Copyright 2008 CoreMedia AG, Hamburg
+ *
+ * Licensed under the Apache License, Version 2.0 (the License); 
+ * you may not use this file except in compliance with the License. 
+ * You may obtain a copy of the License at 
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0 
+ * 
+ * Unless required by applicable law or agreed to in writing, software 
+ * distributed under the License is distributed on an AS IS BASIS, 
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+ * See the License for the specific language governing permissions and 
+ * limitations under the License. 
+ */
+
+package com.coremedia.iso.boxes;
+
+import com.coremedia.iso.IsoTypeReader;
+import com.coremedia.iso.IsoTypeWriter;
+import com.googlecode.mp4parser.AbstractContainerBox;
+import com.googlecode.mp4parser.util.ByteBufferByteChannel;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+
+
+/**
+ * A common base structure to contain general metadata. See ISO/IEC 14496-12 Ch. 8.44.1.
+ */
+public class MetaBox extends AbstractContainerBox {
+    private int version = 0;
+    private int flags = 0;
+
+    public static final String TYPE = "meta";
+
+    public MetaBox() {
+        super(TYPE);
+    }
+
+    @Override
+    public long getContentSize() {
+        if (isMp4Box()) {
+            // it's a fullbox
+            return 4 + super.getContentSize();
+        } else {
+            // it's an apple metabox
+            return super.getContentSize();
+        }
+    }
+
+    @Override
+    public long getNumOfBytesToFirstChild() {
+        if (isMp4Box()) {
+            // it's a fullbox
+            return 12;
+        } else {
+            // it's an apple metabox
+            return 8;
+        }
+    }
+
+    @Override
+    public void _parseDetails(ByteBuffer content) {
+        int pos = content.position();
+        content.get(new byte[4]);
+        String isHdlr = IsoTypeReader.read4cc(content);
+        if ("hdlr".equals(isHdlr)) {
+            //  this is apple bullshit - it's NO FULLBOX
+            content.position(pos);
+            version = -1;
+            flags = -1;
+        } else {
+            content.position(pos);
+            version = IsoTypeReader.readUInt8(content);
+            flags = IsoTypeReader.readUInt24(content);
+        }
+        while (content.remaining() >= 8) {
+            try {
+                boxes.add(boxParser.parseBox(new ByteBufferByteChannel(content), this));
+            } catch (IOException e) {
+                throw new RuntimeException("Sebastian needs to fix 7518765283");
+            }
+        }
+        if (content.remaining() > 0) {
+            throw new RuntimeException("Sebastian needs to fix it 90732r26537");
+        }
+    }
+
+    @Override
+    protected void getContent(ByteBuffer byteBuffer) {
+        if (isMp4Box()) {
+            IsoTypeWriter.writeUInt8(byteBuffer, version);
+            IsoTypeWriter.writeUInt24(byteBuffer, flags);
+        }
+        writeChildBoxes(byteBuffer);
+    }
+
+
+    public boolean isMp4Box() {
+        return version != -1 && flags != -1;
+    }
+
+    public void setMp4Box(boolean mp4) {
+        if (mp4) {
+            version = 0;
+            flags = 0;
+        } else {
+            version = -1;
+            flags = -1;
+        }
+    }
+}
diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/.svn/text-base/MovieBox.java.svn-base b/isoparser/src/main/java/com/coremedia/iso/boxes/.svn/text-base/MovieBox.java.svn-base
new file mode 100644
index 0000000..3aff7d8
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/.svn/text-base/MovieBox.java.svn-base
@@ -0,0 +1,67 @@
+/*  
+ * Copyright 2008 CoreMedia AG, Hamburg
+ *
+ * Licensed under the Apache License, Version 2.0 (the License); 
+ * you may not use this file except in compliance with the License. 
+ * You may obtain a copy of the License at 
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0 
+ * 
+ * Unless required by applicable law or agreed to in writing, software 
+ * distributed under the License is distributed on an AS IS BASIS, 
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+ * See the License for the specific language governing permissions and 
+ * limitations under the License. 
+ */
+
+package com.coremedia.iso.boxes;
+
+
+import com.googlecode.mp4parser.AbstractBox;
+import com.googlecode.mp4parser.AbstractContainerBox;
+
+import java.util.List;
+
+/**
+ * The metadata for a presentation is stored in the single Movie Box which occurs at the top-level of a file.
+ * Normally this box is close to the beginning or end of the file, though this is not required.
+ */
+public class MovieBox extends AbstractContainerBox {
+    public static final String TYPE = "moov";
+
+    public MovieBox() {
+        super(TYPE);
+    }
+
+    public int getTrackCount() {
+        return getBoxes(TrackBox.class).size();
+    }
+
+
+    /**
+     * Returns the track numbers associated with this <code>MovieBox</code>.
+     *
+     * @return the tracknumbers (IDs) of the tracks in their order of appearance in the file
+     */
+    public long[] getTrackNumbers() {
+
+        List<TrackBox> trackBoxes = this.getBoxes(TrackBox.class);
+        long[] trackNumbers = new long[trackBoxes.size()];
+        for (int trackCounter = 0; trackCounter < trackBoxes.size(); trackCounter++) {
+            AbstractBox trackBoxe = trackBoxes.get(trackCounter);
+            TrackBox trackBox = (TrackBox) trackBoxe;
+            trackNumbers[trackCounter] = trackBox.getTrackHeaderBox().getTrackId();
+        }
+        return trackNumbers;
+    }
+
+    public MovieHeaderBox getMovieHeaderBox() {
+        for (Box box : boxes) {
+            if (box instanceof MovieHeaderBox) {
+                return (MovieHeaderBox) box;
+            }
+        }
+        return null;
+    }
+
+}
diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/.svn/text-base/MovieHeaderBox.java.svn-base b/isoparser/src/main/java/com/coremedia/iso/boxes/.svn/text-base/MovieHeaderBox.java.svn-base
new file mode 100644
index 0000000..30fbe8c
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/.svn/text-base/MovieHeaderBox.java.svn-base
@@ -0,0 +1,278 @@
+/*  
+ * Copyright 2008 CoreMedia AG, Hamburg
+ *
+ * Licensed under the Apache License, Version 2.0 (the License); 
+ * you may not use this file except in compliance with the License. 
+ * You may obtain a copy of the License at 
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0 
+ * 
+ * Unless required by applicable law or agreed to in writing, software 
+ * distributed under the License is distributed on an AS IS BASIS, 
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+ * See the License for the specific language governing permissions and 
+ * limitations under the License. 
+ */
+
+package com.coremedia.iso.boxes;
+
+import com.coremedia.iso.IsoTypeReader;
+import com.coremedia.iso.IsoTypeWriter;
+import com.googlecode.mp4parser.AbstractFullBox;
+
+import java.nio.ByteBuffer;
+
+/**
+ * <code>
+ * Box Type: 'mvhd'<br>
+ * Container: {@link MovieBox} ('moov')<br>
+ * Mandatory: Yes<br>
+ * Quantity: Exactly one<br><br>
+ * </code>
+ * This box defines overall information which is media-independent, and relevant to the entire presentation
+ * considered as a whole.
+ */
+public class MovieHeaderBox extends AbstractFullBox {
+    private long creationTime;
+    private long modificationTime;
+    private long timescale;
+    private long duration;
+    private double rate = 1.0;
+    private float volume = 1.0f;
+    private long[] matrix = new long[]{0x00010000, 0, 0, 0, 0x00010000, 0, 0, 0, 0x40000000};
+    private long nextTrackId;
+
+    private int previewTime;
+    private int previewDuration;
+    private int posterTime;
+    private int selectionTime;
+    private int selectionDuration;
+    private int currentTime;
+
+
+    public static final String TYPE = "mvhd";
+
+    public MovieHeaderBox() {
+        super(TYPE);
+    }
+
+    public long getCreationTime() {
+        return creationTime;
+    }
+
+    public long getModificationTime() {
+        return modificationTime;
+    }
+
+    public long getTimescale() {
+        return timescale;
+    }
+
+    public long getDuration() {
+        return duration;
+    }
+
+    public double getRate() {
+        return rate;
+    }
+
+    public float getVolume() {
+        return volume;
+    }
+
+    public long[] getMatrix() {
+        return matrix;
+    }
+
+    public long getNextTrackId() {
+        return nextTrackId;
+    }
+
+    protected long getContentSize() {
+        long contentSize = 4;
+        if (getVersion() == 1) {
+            contentSize += 28;
+        } else {
+            contentSize += 16;
+        }
+        contentSize += 80;
+        return contentSize;
+    }
+
+    @Override
+    public void _parseDetails(ByteBuffer content) {
+        parseVersionAndFlags(content);
+        if (getVersion() == 1) {
+            creationTime = IsoTypeReader.readUInt64(content);
+            modificationTime = IsoTypeReader.readUInt64(content);
+            timescale = IsoTypeReader.readUInt32(content);
+            duration = IsoTypeReader.readUInt64(content);
+        } else {
+            creationTime = IsoTypeReader.readUInt32(content);
+            modificationTime = IsoTypeReader.readUInt32(content);
+            timescale = IsoTypeReader.readUInt32(content);
+            duration = IsoTypeReader.readUInt32(content);
+        }
+        rate = IsoTypeReader.readFixedPoint1616(content);
+        volume = IsoTypeReader.readFixedPoint88(content);
+        IsoTypeReader.readUInt16(content);
+        IsoTypeReader.readUInt32(content);
+        IsoTypeReader.readUInt32(content);
+        matrix = new long[9];
+        for (int i = 0; i < 9; i++) {
+            matrix[i] = IsoTypeReader.readUInt32(content);
+        }
+
+        previewTime = content.getInt();
+        previewDuration = content.getInt();
+        posterTime = content.getInt();
+        selectionTime = content.getInt();
+        selectionDuration = content.getInt();
+        currentTime = content.getInt();
+
+        nextTrackId = IsoTypeReader.readUInt32(content);
+
+    }
+
+    public String toString() {
+        StringBuilder result = new StringBuilder();
+        result.append("MovieHeaderBox[");
+        result.append("creationTime=").append(getCreationTime());
+        result.append(";");
+        result.append("modificationTime=").append(getModificationTime());
+        result.append(";");
+        result.append("timescale=").append(getTimescale());
+        result.append(";");
+        result.append("duration=").append(getDuration());
+        result.append(";");
+        result.append("rate=").append(getRate());
+        result.append(";");
+        result.append("volume=").append(getVolume());
+        for (int i = 0; i < matrix.length; i++) {
+            result.append(";");
+            result.append("matrix").append(i).append("=").append(matrix[i]);
+        }
+        result.append(";");
+        result.append("nextTrackId=").append(getNextTrackId());
+        result.append("]");
+        return result.toString();
+    }
+
+
+    @Override
+    protected void getContent(ByteBuffer byteBuffer) {
+        writeVersionAndFlags(byteBuffer);
+        if (getVersion() == 1) {
+            IsoTypeWriter.writeUInt64(byteBuffer, creationTime);
+            IsoTypeWriter.writeUInt64(byteBuffer, modificationTime);
+            IsoTypeWriter.writeUInt32(byteBuffer, timescale);
+            IsoTypeWriter.writeUInt64(byteBuffer, duration);
+        } else {
+            IsoTypeWriter.writeUInt32(byteBuffer, creationTime);
+            IsoTypeWriter.writeUInt32(byteBuffer, modificationTime);
+            IsoTypeWriter.writeUInt32(byteBuffer, timescale);
+            IsoTypeWriter.writeUInt32(byteBuffer, duration);
+        }
+        IsoTypeWriter.writeFixedPont1616(byteBuffer, rate);
+        IsoTypeWriter.writeFixedPont88(byteBuffer, volume);
+        IsoTypeWriter.writeUInt16(byteBuffer, 0);
+        IsoTypeWriter.writeUInt32(byteBuffer, 0);
+        IsoTypeWriter.writeUInt32(byteBuffer, 0);
+
+
+        for (int i = 0; i < 9; i++) {
+            IsoTypeWriter.writeUInt32(byteBuffer, matrix[i]);
+        }
+
+
+        byteBuffer.putInt(previewTime);
+        byteBuffer.putInt(previewDuration);
+        byteBuffer.putInt(posterTime);
+        byteBuffer.putInt(selectionTime);
+        byteBuffer.putInt(selectionDuration);
+        byteBuffer.putInt(currentTime);
+
+        IsoTypeWriter.writeUInt32(byteBuffer, nextTrackId);
+    }
+
+
+    public void setCreationTime(long creationTime) {
+        this.creationTime = creationTime;
+    }
+
+    public void setModificationTime(long modificationTime) {
+        this.modificationTime = modificationTime;
+    }
+
+    public void setTimescale(long timescale) {
+        this.timescale = timescale;
+    }
+
+    public void setDuration(long duration) {
+        this.duration = duration;
+    }
+
+    public void setRate(double rate) {
+        this.rate = rate;
+    }
+
+    public void setVolume(float volume) {
+        this.volume = volume;
+    }
+
+    public void setMatrix(long[] matrix) {
+        this.matrix = matrix;
+    }
+
+    public void setNextTrackId(long nextTrackId) {
+        this.nextTrackId = nextTrackId;
+    }
+
+    public int getPreviewTime() {
+        return previewTime;
+    }
+
+    public void setPreviewTime(int previewTime) {
+        this.previewTime = previewTime;
+    }
+
+    public int getPreviewDuration() {
+        return previewDuration;
+    }
+
+    public void setPreviewDuration(int previewDuration) {
+        this.previewDuration = previewDuration;
+    }
+
+    public int getPosterTime() {
+        return posterTime;
+    }
+
+    public void setPosterTime(int posterTime) {
+        this.posterTime = posterTime;
+    }
+
+    public int getSelectionTime() {
+        return selectionTime;
+    }
+
+    public void setSelectionTime(int selectionTime) {
+        this.selectionTime = selectionTime;
+    }
+
+    public int getSelectionDuration() {
+        return selectionDuration;
+    }
+
+    public void setSelectionDuration(int selectionDuration) {
+        this.selectionDuration = selectionDuration;
+    }
+
+    public int getCurrentTime() {
+        return currentTime;
+    }
+
+    public void setCurrentTime(int currentTime) {
+        this.currentTime = currentTime;
+    }
+}
diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/.svn/text-base/NullMediaHeaderBox.java.svn-base b/isoparser/src/main/java/com/coremedia/iso/boxes/.svn/text-base/NullMediaHeaderBox.java.svn-base
new file mode 100644
index 0000000..562f8d4
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/.svn/text-base/NullMediaHeaderBox.java.svn-base
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2011 Sebastian Annies, Hamburg, Germany
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.coremedia.iso.boxes;
+
+import java.nio.ByteBuffer;
+
+/**
+ * Streams other than visual and audio (e.g., timed metadata streams) may use a
+ * Null Media Header Box.
+ */
+public class NullMediaHeaderBox extends AbstractMediaHeaderBox {
+    public NullMediaHeaderBox() {
+        super("nmhd");
+    }
+
+    @Override
+    protected long getContentSize() {
+        return 4;
+    }
+
+    @Override
+    public void _parseDetails(ByteBuffer content) {
+        parseVersionAndFlags(content);
+    }
+
+    @Override
+    protected void getContent(ByteBuffer byteBuffer) {
+        writeVersionAndFlags(byteBuffer);
+    }
+}
diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/.svn/text-base/ObjectDescriptorBox.java.svn-base b/isoparser/src/main/java/com/coremedia/iso/boxes/.svn/text-base/ObjectDescriptorBox.java.svn-base
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/.svn/text-base/ObjectDescriptorBox.java.svn-base
diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/.svn/text-base/OmaDrmAccessUnitFormatBox.java.svn-base b/isoparser/src/main/java/com/coremedia/iso/boxes/.svn/text-base/OmaDrmAccessUnitFormatBox.java.svn-base
new file mode 100644
index 0000000..020881b
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/.svn/text-base/OmaDrmAccessUnitFormatBox.java.svn-base
@@ -0,0 +1,87 @@
+/*  
+ * Copyright 2008 CoreMedia AG, Hamburg
+ *
+ * Licensed under the Apache License, Version 2.0 (the License); 
+ * you may not use this file except in compliance with the License. 
+ * You may obtain a copy of the License at 
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0 
+ * 
+ * Unless required by applicable law or agreed to in writing, software 
+ * distributed under the License is distributed on an AS IS BASIS, 
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+ * See the License for the specific language governing permissions and 
+ * limitations under the License. 
+ */
+
+package com.coremedia.iso.boxes;
+
+import com.coremedia.iso.IsoTypeReader;
+import com.coremedia.iso.IsoTypeWriter;
+import com.googlecode.mp4parser.AbstractFullBox;
+
+import java.nio.ByteBuffer;
+
+/**
+ * Describes the format of media access units in PDCF files.
+ */
+public final class OmaDrmAccessUnitFormatBox extends AbstractFullBox {
+    public static final String TYPE = "odaf";
+
+    private boolean selectiveEncryption;
+    private byte allBits;
+
+    private int keyIndicatorLength;
+    private int initVectorLength;
+
+    protected long getContentSize() {
+        return 7;
+    }
+
+    public OmaDrmAccessUnitFormatBox() {
+        super("odaf");
+    }
+
+    public boolean isSelectiveEncryption() {
+        return selectiveEncryption;
+    }
+
+    public int getKeyIndicatorLength() {
+        return keyIndicatorLength;
+    }
+
+    public int getInitVectorLength() {
+        return initVectorLength;
+    }
+
+    public void setInitVectorLength(int initVectorLength) {
+        this.initVectorLength = initVectorLength;
+    }
+
+    public void setKeyIndicatorLength(int keyIndicatorLength) {
+        this.keyIndicatorLength = keyIndicatorLength;
+    }
+
+    public void setAllBits(byte allBits) {
+        this.allBits = allBits;
+        selectiveEncryption = (allBits & 0x80) == 0x80;
+    }
+
+    @Override
+    public void _parseDetails(ByteBuffer content) {
+        parseVersionAndFlags(content);
+        allBits = (byte) IsoTypeReader.readUInt8(content);
+        selectiveEncryption = (allBits & 0x80) == 0x80;
+        keyIndicatorLength = IsoTypeReader.readUInt8(content);
+        initVectorLength = IsoTypeReader.readUInt8(content);
+    }
+
+    @Override
+    protected void getContent(ByteBuffer byteBuffer) {
+        writeVersionAndFlags(byteBuffer);
+        IsoTypeWriter.writeUInt8(byteBuffer, allBits);
+        IsoTypeWriter.writeUInt8(byteBuffer, keyIndicatorLength);
+        IsoTypeWriter.writeUInt8(byteBuffer, initVectorLength);
+    }
+
+}
diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/.svn/text-base/OriginalFormatBox.java.svn-base b/isoparser/src/main/java/com/coremedia/iso/boxes/.svn/text-base/OriginalFormatBox.java.svn-base
new file mode 100644
index 0000000..004c6c2
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/.svn/text-base/OriginalFormatBox.java.svn-base
@@ -0,0 +1,69 @@
+/*  
+ * Copyright 2008 CoreMedia AG, Hamburg
+ *
+ * Licensed under the Apache License, Version 2.0 (the License); 
+ * you may not use this file except in compliance with the License. 
+ * You may obtain a copy of the License at 
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0 
+ * 
+ * Unless required by applicable law or agreed to in writing, software 
+ * distributed under the License is distributed on an AS IS BASIS, 
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+ * See the License for the specific language governing permissions and 
+ * limitations under the License. 
+ */
+
+package com.coremedia.iso.boxes;
+
+import com.coremedia.iso.IsoFile;
+import com.coremedia.iso.IsoTypeReader;
+import com.googlecode.mp4parser.AbstractBox;
+
+import java.nio.ByteBuffer;
+
+/**
+ * The Original Format Box contains the four-character-code of the original untransformed sample description.
+ * See ISO/IEC 14496-12 for details.
+ *
+ * @see ProtectionSchemeInformationBox
+ */
+
+public class OriginalFormatBox extends AbstractBox {
+    public static final String TYPE = "frma";
+
+    private String dataFormat = "    ";
+
+    public OriginalFormatBox() {
+        super("frma");
+    }
+
+    public String getDataFormat() {
+        return dataFormat;
+    }
+
+
+    public void setDataFormat(String dataFormat) {
+        assert dataFormat.length() == 4;
+        this.dataFormat = dataFormat;
+    }
+
+    protected long getContentSize() {
+        return 4;
+    }
+
+    @Override
+    public void _parseDetails(ByteBuffer content) {
+        dataFormat = IsoTypeReader.read4cc(content);
+    }
+
+    @Override
+    protected void getContent(ByteBuffer byteBuffer) {
+        byteBuffer.put(IsoFile.fourCCtoBytes(dataFormat));
+    }
+
+
+    public String toString() {
+        return "OriginalFormatBox[dataFormat=" + getDataFormat() + "]";
+    }
+}
diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/.svn/text-base/PerformerBox.java.svn-base b/isoparser/src/main/java/com/coremedia/iso/boxes/.svn/text-base/PerformerBox.java.svn-base
new file mode 100644
index 0000000..cf702dc
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/.svn/text-base/PerformerBox.java.svn-base
@@ -0,0 +1,78 @@
+/*  
+ * Copyright 2008 CoreMedia AG, Hamburg
+ *
+ * Licensed under the Apache License, Version 2.0 (the License); 
+ * you may not use this file except in compliance with the License. 
+ * You may obtain a copy of the License at 
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0 
+ * 
+ * Unless required by applicable law or agreed to in writing, software 
+ * distributed under the License is distributed on an AS IS BASIS, 
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+ * See the License for the specific language governing permissions and 
+ * limitations under the License. 
+ */
+
+package com.coremedia.iso.boxes;
+
+import com.coremedia.iso.IsoTypeReader;
+import com.coremedia.iso.IsoTypeWriter;
+import com.coremedia.iso.Utf8;
+import com.googlecode.mp4parser.AbstractFullBox;
+
+import java.nio.ByteBuffer;
+
+/**
+ * Used to give information about the performer. Mostly used in confunction with music files.
+ * See 3GPP 26.234 for details.
+ */
+public class PerformerBox extends AbstractFullBox {
+    public static final String TYPE = "perf";
+
+    private String language;
+    private String performer;
+
+    public PerformerBox() {
+        super(TYPE);
+    }
+
+    public String getLanguage() {
+        return language;
+    }
+
+    public String getPerformer() {
+        return performer;
+    }
+
+    public void setLanguage(String language) {
+        this.language = language;
+    }
+
+    public void setPerformer(String performer) {
+        this.performer = performer;
+    }
+
+    protected long getContentSize() {
+        return 6 + Utf8.utf8StringLengthInBytes(performer) + 1;
+    }
+
+    @Override
+    protected void getContent(ByteBuffer byteBuffer) {
+        writeVersionAndFlags(byteBuffer);
+        IsoTypeWriter.writeIso639(byteBuffer, language);
+        byteBuffer.put(Utf8.convert(performer));
+        byteBuffer.put((byte) 0);
+    }
+
+    @Override
+    public void _parseDetails(ByteBuffer content) {
+        parseVersionAndFlags(content);
+        language = IsoTypeReader.readIso639(content);
+        performer = IsoTypeReader.readString(content);
+    }
+
+    public String toString() {
+        return "PerformerBox[language=" + getLanguage() + ";performer=" + getPerformer() + "]";
+    }
+}
diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/.svn/text-base/ProgressiveDownloadInformationBox.java.svn-base b/isoparser/src/main/java/com/coremedia/iso/boxes/.svn/text-base/ProgressiveDownloadInformationBox.java.svn-base
new file mode 100644
index 0000000..7acd7ed
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/.svn/text-base/ProgressiveDownloadInformationBox.java.svn-base
@@ -0,0 +1,95 @@
+package com.coremedia.iso.boxes;
+
+import com.coremedia.iso.IsoTypeReader;
+import com.coremedia.iso.IsoTypeWriter;
+import com.googlecode.mp4parser.AbstractFullBox;
+
+import java.nio.ByteBuffer;
+import java.util.Collections;
+import java.util.LinkedList;
+import java.util.List;
+
+public class ProgressiveDownloadInformationBox extends AbstractFullBox {
+
+
+    List<Entry> entries = Collections.emptyList();
+
+    public ProgressiveDownloadInformationBox() {
+        super("pdin");
+    }
+
+    @Override
+    protected long getContentSize() {
+        return 4 + entries.size() * 8;
+    }
+
+    @Override
+    protected void getContent(ByteBuffer byteBuffer) {
+        writeVersionAndFlags(byteBuffer);
+        for (Entry entry : entries) {
+            IsoTypeWriter.writeUInt32(byteBuffer, entry.getRate());
+            IsoTypeWriter.writeUInt32(byteBuffer, entry.getInitialDelay());
+        }
+    }
+
+    public List<Entry> getEntries() {
+        return entries;
+    }
+
+    public void setEntries(List<Entry> entries) {
+        this.entries = entries;
+    }
+
+    @Override
+    public void _parseDetails(ByteBuffer content) {
+        parseVersionAndFlags(content);
+        entries = new LinkedList<Entry>();
+        while (content.remaining() >= 8) {
+            Entry entry = new Entry(IsoTypeReader.readUInt32(content), IsoTypeReader.readUInt32(content));
+            entries.add(entry);
+        }
+    }
+
+
+    public static class Entry {
+        long rate;
+        long initialDelay;
+
+        public Entry(long rate, long initialDelay) {
+            this.rate = rate;
+            this.initialDelay = initialDelay;
+        }
+
+        public long getRate() {
+            return rate;
+        }
+
+        public void setRate(long rate) {
+            this.rate = rate;
+        }
+
+        public long getInitialDelay() {
+            return initialDelay;
+        }
+
+        public void setInitialDelay(long initialDelay) {
+            this.initialDelay = initialDelay;
+        }
+
+        @Override
+        public String toString() {
+            return "Entry{" +
+                    "rate=" + rate +
+                    ", initialDelay=" + initialDelay +
+                    '}';
+        }
+    }
+
+    @Override
+    public String toString() {
+        return "ProgressiveDownloadInfoBox{" +
+                "entries=" + entries +
+                '}';
+    }
+
+}
\ No newline at end of file
diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/.svn/text-base/ProtectionSchemeInformationBox.java.svn-base b/isoparser/src/main/java/com/coremedia/iso/boxes/.svn/text-base/ProtectionSchemeInformationBox.java.svn-base
new file mode 100644
index 0000000..87069d3
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/.svn/text-base/ProtectionSchemeInformationBox.java.svn-base
@@ -0,0 +1,42 @@
+/*  
+ * Copyright 2008 CoreMedia AG, Hamburg
+ *
+ * Licensed under the Apache License, Version 2.0 (the License); 
+ * you may not use this file except in compliance with the License. 
+ * You may obtain a copy of the License at 
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0 
+ * 
+ * Unless required by applicable law or agreed to in writing, software 
+ * distributed under the License is distributed on an AS IS BASIS, 
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+ * See the License for the specific language governing permissions and 
+ * limitations under the License. 
+ */
+
+package com.coremedia.iso.boxes;
+
+import com.googlecode.mp4parser.AbstractContainerBox;
+
+/**
+ * The <code>ProtectionSchemeInformationBox</code> contains all the information required both
+ * to understand the encryption transform applied and its parameters, and also to find other
+ * information such as the kind and location of the key management system. It also documents the
+ * the original (unencrypted) format of the media. The <code>ProtectionSchemeInformationBox</code>
+ * is a container box. It is mandatory in a sample entry that uses a code idicating a
+ * protected stream.
+ *
+ * @see com.coremedia.iso.boxes.odf.OmaDrmKeyManagenentSystemBox
+ * @see com.coremedia.iso.boxes.sampleentry.AudioSampleEntry#TYPE_ENCRYPTED
+ * @see com.coremedia.iso.boxes.sampleentry.VisualSampleEntry#TYPE_ENCRYPTED
+ */
+public class ProtectionSchemeInformationBox extends AbstractContainerBox {
+    public static final String TYPE = "sinf";
+
+    public ProtectionSchemeInformationBox() {
+        super(TYPE);
+
+    }
+
+
+}
diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/.svn/text-base/RatingBox.java.svn-base b/isoparser/src/main/java/com/coremedia/iso/boxes/.svn/text-base/RatingBox.java.svn-base
new file mode 100644
index 0000000..ad32749
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/.svn/text-base/RatingBox.java.svn-base
@@ -0,0 +1,124 @@
+/*  
+ * Copyright 2008 CoreMedia AG, Hamburg
+ *
+ * Licensed under the Apache License, Version 2.0 (the License); 
+ * you may not use this file except in compliance with the License. 
+ * You may obtain a copy of the License at 
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0 
+ * 
+ * Unless required by applicable law or agreed to in writing, software 
+ * distributed under the License is distributed on an AS IS BASIS, 
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+ * See the License for the specific language governing permissions and 
+ * limitations under the License. 
+ */
+
+package com.coremedia.iso.boxes;
+
+import com.coremedia.iso.IsoFile;
+import com.coremedia.iso.IsoTypeReader;
+import com.coremedia.iso.IsoTypeWriter;
+import com.coremedia.iso.Utf8;
+import com.googlecode.mp4parser.AbstractFullBox;
+
+import java.nio.ByteBuffer;
+
+
+/**
+ * Contained a the <code>UserDataBox</code> and containing information about the media's rating. E.g.
+ * PG13or FSK16.
+ */
+public class RatingBox extends AbstractFullBox {
+    public static final String TYPE = "rtng";
+
+    private String ratingEntity;
+    private String ratingCriteria;
+    private String language;
+    private String ratingInfo;
+
+    public RatingBox() {
+        super(TYPE);
+    }
+
+
+    public void setRatingEntity(String ratingEntity) {
+        this.ratingEntity = ratingEntity;
+    }
+
+    public void setRatingCriteria(String ratingCriteria) {
+        this.ratingCriteria = ratingCriteria;
+    }
+
+    public void setLanguage(String language) {
+        this.language = language;
+    }
+
+    public void setRatingInfo(String ratingInfo) {
+        this.ratingInfo = ratingInfo;
+    }
+
+    public String getLanguage() {
+        return language;
+    }
+
+    /**
+     * Gets a four-character code that indicates the rating entity grading the asset, e.g., 'BBFC'. The values of this
+     * field should follow common names of worldwide movie rating systems, such as those mentioned in
+     * [http://www.movie-ratings.net/, October 2002].
+     *
+     * @return the rating organization
+     */
+    public String getRatingEntity() {
+        return ratingEntity;
+    }
+
+    /**
+     * Gets the four-character code that indicates which rating criteria are being used for the corresponding rating
+     * entity, e.g., 'PG13'.
+     *
+     * @return the actual rating
+     */
+    public String getRatingCriteria() {
+        return ratingCriteria;
+    }
+
+    public String getRatingInfo() {
+        return ratingInfo;
+    }
+
+    protected long getContentSize() {
+        return 15 + Utf8.utf8StringLengthInBytes(ratingInfo);
+    }
+
+    @Override
+    public void _parseDetails(ByteBuffer content) {
+        parseVersionAndFlags(content);
+        ratingEntity = IsoTypeReader.read4cc(content);
+        ratingCriteria = IsoTypeReader.read4cc(content);
+        language = IsoTypeReader.readIso639(content);
+        ratingInfo = IsoTypeReader.readString(content);
+
+    }
+
+    @Override
+    protected void getContent(ByteBuffer byteBuffer) {
+        writeVersionAndFlags(byteBuffer);
+        byteBuffer.put(IsoFile.fourCCtoBytes(ratingEntity));
+        byteBuffer.put(IsoFile.fourCCtoBytes(ratingCriteria));
+        IsoTypeWriter.writeIso639(byteBuffer, language);
+        byteBuffer.put(Utf8.convert(ratingInfo));
+        byteBuffer.put((byte) 0);
+    }
+
+    public String toString() {
+        StringBuilder buffer = new StringBuilder();
+        buffer.append("RatingBox[language=").append(getLanguage());
+        buffer.append("ratingEntity=").append(getRatingEntity());
+        buffer.append(";ratingCriteria=").append(getRatingCriteria());
+        buffer.append(";language=").append(getLanguage());
+        buffer.append(";ratingInfo=").append(getRatingInfo());
+        buffer.append("]");
+        return buffer.toString();
+    }
+}
diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/.svn/text-base/RecordingYearBox.java.svn-base b/isoparser/src/main/java/com/coremedia/iso/boxes/.svn/text-base/RecordingYearBox.java.svn-base
new file mode 100644
index 0000000..e2dcbd9
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/.svn/text-base/RecordingYearBox.java.svn-base
@@ -0,0 +1,63 @@
+/*  
+ * Copyright 2008 CoreMedia AG, Hamburg
+ *
+ * Licensed under the Apache License, Version 2.0 (the License); 
+ * you may not use this file except in compliance with the License. 
+ * You may obtain a copy of the License at 
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0 
+ * 
+ * Unless required by applicable law or agreed to in writing, software 
+ * distributed under the License is distributed on an AS IS BASIS, 
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+ * See the License for the specific language governing permissions and 
+ * limitations under the License. 
+ */
+
+package com.coremedia.iso.boxes;
+
+import com.coremedia.iso.IsoTypeReader;
+import com.coremedia.iso.IsoTypeWriter;
+import com.googlecode.mp4parser.AbstractFullBox;
+
+import java.nio.ByteBuffer;
+
+/**
+ *
+ */
+public class RecordingYearBox extends AbstractFullBox {
+    public static final String TYPE = "yrrc";
+
+    int recordingYear;
+
+    public RecordingYearBox() {
+        super(TYPE);
+    }
+
+
+    protected long getContentSize() {
+        return 6;
+    }
+
+    public int getRecordingYear() {
+        return recordingYear;
+    }
+
+    public void setRecordingYear(int recordingYear) {
+        this.recordingYear = recordingYear;
+    }
+
+
+    @Override
+    public void _parseDetails(ByteBuffer content) {
+        parseVersionAndFlags(content);
+        recordingYear = IsoTypeReader.readUInt16(content);
+    }
+
+    @Override
+    protected void getContent(ByteBuffer byteBuffer) {
+        writeVersionAndFlags(byteBuffer);
+        IsoTypeWriter.writeUInt16(byteBuffer, recordingYear);
+    }
+
+}
diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/.svn/text-base/SampleAuxiliaryInformationOffsetsBox.java.svn-base b/isoparser/src/main/java/com/coremedia/iso/boxes/.svn/text-base/SampleAuxiliaryInformationOffsetsBox.java.svn-base
new file mode 100644
index 0000000..517bc03
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/.svn/text-base/SampleAuxiliaryInformationOffsetsBox.java.svn-base
@@ -0,0 +1,127 @@
+/*
+ * Copyright 2009 castLabs GmbH, Berlin
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.coremedia.iso.boxes;
+
+import com.coremedia.iso.IsoTypeReader;
+import com.coremedia.iso.IsoTypeWriter;
+import com.googlecode.mp4parser.AbstractFullBox;
+
+import java.nio.ByteBuffer;
+import java.util.LinkedList;
+import java.util.List;
+
+import static com.googlecode.mp4parser.util.CastUtils.l2i;
+
+/*
+aligned(8) class SampleAuxiliaryInformationOffsetsBox
+            extends FullBox(‘saio’, version, flags)
+{
+            if (flags & 1) {
+                        unsigned int(32) aux_info_type;
+                        unsigned int(32) aux_info_type_parameter;
+            }
+            unsigned int(32) entry_count;
+            if ( version == 0 )
+            {
+                        unsigned int(32) offset[ entry_count ];
+            }
+            else
+            {
+                        unsigned int(64) offset[ entry_count ];
+            }
+}
+ */
+public class SampleAuxiliaryInformationOffsetsBox extends AbstractFullBox {
+    public static final String TYPE = "saio";
+
+    private List<Long> offsets = new LinkedList<Long>();
+    private long auxInfoType;
+    private long auxInfoTypeParameter;
+
+    public SampleAuxiliaryInformationOffsetsBox() {
+        super(TYPE);
+    }
+
+    @Override
+    protected long getContentSize() {
+        return 8 + (getVersion() == 0 ? 4 * offsets.size() : 8 * offsets.size()) + ((getFlags() & 1) == 1 ? 8 : 0);
+    }
+
+    @Override
+    protected void getContent(ByteBuffer byteBuffer) {
+        writeVersionAndFlags(byteBuffer);
+        if ((getFlags() & 1) == 1) {
+            IsoTypeWriter.writeUInt32(byteBuffer, auxInfoType);
+            IsoTypeWriter.writeUInt32(byteBuffer, auxInfoTypeParameter);
+        }
+
+        IsoTypeWriter.writeUInt32(byteBuffer, offsets.size());
+        for (Long offset : offsets) {
+            if (getVersion() == 0) {
+                IsoTypeWriter.writeUInt32(byteBuffer, offset);
+            } else {
+                IsoTypeWriter.writeUInt64(byteBuffer, offset);
+            }
+        }
+    }
+
+    @Override
+    public void _parseDetails(ByteBuffer content) {
+        parseVersionAndFlags(content);
+
+        if ((getFlags() & 1) == 1) {
+            auxInfoType = IsoTypeReader.readUInt32(content);
+            auxInfoTypeParameter = IsoTypeReader.readUInt32(content);
+        }
+
+        int entryCount = l2i(IsoTypeReader.readUInt32(content));
+        offsets.clear();
+
+        for (int i = 0; i < entryCount; i++) {
+            if (getVersion() == 0) {
+                offsets.add(IsoTypeReader.readUInt32(content));
+            } else {
+                offsets.add(IsoTypeReader.readUInt64(content));
+            }
+        }
+    }
+
+
+    public long getAuxInfoType() {
+        return auxInfoType;
+    }
+
+    public void setAuxInfoType(long auxInfoType) {
+        this.auxInfoType = auxInfoType;
+    }
+
+    public long getAuxInfoTypeParameter() {
+        return auxInfoTypeParameter;
+    }
+
+    public void setAuxInfoTypeParameter(long auxInfoTypeParameter) {
+        this.auxInfoTypeParameter = auxInfoTypeParameter;
+    }
+
+    public List<Long> getOffsets() {
+        return offsets;
+    }
+
+    public void setOffsets(List<Long> offsets) {
+        this.offsets = offsets;
+    }
+}
diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/.svn/text-base/SampleAuxiliaryInformationSizesBox.java.svn-base b/isoparser/src/main/java/com/coremedia/iso/boxes/.svn/text-base/SampleAuxiliaryInformationSizesBox.java.svn-base
new file mode 100644
index 0000000..4032d01
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/.svn/text-base/SampleAuxiliaryInformationSizesBox.java.svn-base
@@ -0,0 +1,145 @@
+/*
+ * Copyright 2009 castLabs GmbH, Berlin
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.coremedia.iso.boxes;
+
+import com.coremedia.iso.IsoFile;
+import com.coremedia.iso.IsoTypeReader;
+import com.coremedia.iso.IsoTypeWriter;
+import com.googlecode.mp4parser.AbstractFullBox;
+
+import java.nio.ByteBuffer;
+import java.util.LinkedList;
+import java.util.List;
+
+import static com.googlecode.mp4parser.util.CastUtils.l2i;
+
+public class SampleAuxiliaryInformationSizesBox extends AbstractFullBox {
+    public static final String TYPE = "saiz";
+
+    private int defaultSampleInfoSize;
+    private List<Short> sampleInfoSizes = new LinkedList<Short>();
+    private int sampleCount;
+    private String auxInfoType;
+    private String auxInfoTypeParameter;
+
+    public SampleAuxiliaryInformationSizesBox() {
+        super(TYPE);
+    }
+
+    @Override
+    protected long getContentSize() {
+        int size = 4;
+        if ((getFlags() & 1) == 1) {
+            size += 8;
+        }
+
+        size += 5;
+        size += defaultSampleInfoSize == 0 ? sampleInfoSizes.size() : 0;
+        return size;
+    }
+
+    @Override
+    protected void getContent(ByteBuffer byteBuffer) {
+        writeVersionAndFlags(byteBuffer);
+        if ((getFlags() & 1) == 1) {
+            byteBuffer.put(IsoFile.fourCCtoBytes(auxInfoType));
+            byteBuffer.put(IsoFile.fourCCtoBytes(auxInfoTypeParameter));
+        }
+
+        IsoTypeWriter.writeUInt8(byteBuffer, defaultSampleInfoSize);
+
+        if (defaultSampleInfoSize == 0) {
+            IsoTypeWriter.writeUInt32(byteBuffer, sampleInfoSizes.size());
+            for (short sampleInfoSize : sampleInfoSizes) {
+                IsoTypeWriter.writeUInt8(byteBuffer, sampleInfoSize);
+            }
+        } else {
+            IsoTypeWriter.writeUInt32(byteBuffer, sampleCount);
+        }
+    }
+
+    @Override
+    public void _parseDetails(ByteBuffer content) {
+        parseVersionAndFlags(content);
+        if ((getFlags() & 1) == 1) {
+            auxInfoType = IsoTypeReader.read4cc(content);
+            auxInfoTypeParameter = IsoTypeReader.read4cc(content);
+        }
+
+        defaultSampleInfoSize = (short) IsoTypeReader.readUInt8(content);
+        sampleCount = l2i(IsoTypeReader.readUInt32(content));
+
+        sampleInfoSizes.clear();
+
+        if (defaultSampleInfoSize == 0) {
+            for (int i = 0; i < sampleCount; i++) {
+                sampleInfoSizes.add((short) IsoTypeReader.readUInt8(content));
+            }
+        }
+    }
+
+    public String getAuxInfoType() {
+        return auxInfoType;
+    }
+
+    public void setAuxInfoType(String auxInfoType) {
+        this.auxInfoType = auxInfoType;
+    }
+
+    public String getAuxInfoTypeParameter() {
+        return auxInfoTypeParameter;
+    }
+
+    public void setAuxInfoTypeParameter(String auxInfoTypeParameter) {
+        this.auxInfoTypeParameter = auxInfoTypeParameter;
+    }
+
+    public int getDefaultSampleInfoSize() {
+        return defaultSampleInfoSize;
+    }
+
+    public void setDefaultSampleInfoSize(int defaultSampleInfoSize) {
+        assert defaultSampleInfoSize <= 255;
+        this.defaultSampleInfoSize = defaultSampleInfoSize;
+    }
+
+    public List<Short> getSampleInfoSizes() {
+        return sampleInfoSizes;
+    }
+
+    public void setSampleInfoSizes(List<Short> sampleInfoSizes) {
+        this.sampleInfoSizes = sampleInfoSizes;
+    }
+
+    public int getSampleCount() {
+        return sampleCount;
+    }
+
+    public void setSampleCount(int sampleCount) {
+        this.sampleCount = sampleCount;
+    }
+
+    @Override
+    public String toString() {
+        return "SampleAuxiliaryInformationSizesBox{" +
+                "defaultSampleInfoSize=" + defaultSampleInfoSize +
+                ", sampleCount=" + sampleCount +
+                ", auxInfoType='" + auxInfoType + '\'' +
+                ", auxInfoTypeParameter='" + auxInfoTypeParameter + '\'' +
+                '}';
+    }
+}
diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/.svn/text-base/SampleDependencyTypeBox.java.svn-base b/isoparser/src/main/java/com/coremedia/iso/boxes/.svn/text-base/SampleDependencyTypeBox.java.svn-base
new file mode 100644
index 0000000..bb38d8c
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/.svn/text-base/SampleDependencyTypeBox.java.svn-base
@@ -0,0 +1,136 @@
+/*
+ * Copyright 2009 castLabs GmbH, Berlin
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.coremedia.iso.boxes;
+
+import com.coremedia.iso.IsoTypeReader;
+import com.coremedia.iso.IsoTypeWriter;
+import com.googlecode.mp4parser.AbstractFullBox;
+
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * aligned(8) class SampleDependencyTypeBox
+ * extends FullBox('sdtp', version = 0, 0) {
+ * for (i=0; i < sample_count; i++){
+ * unsigned int(2) reserved = 0;
+ * unsigned int(2) sample_depends_on;
+ * unsigned int(2) sample_is_depended_on;
+ * unsigned int(2) sample_has_redundancy;
+ * }
+ * }
+ */
+public class SampleDependencyTypeBox extends AbstractFullBox {
+    public static final String TYPE = "sdtp";
+
+    private List<Entry> entries = new ArrayList<Entry>();
+
+    public static class Entry {
+
+        public Entry(int value) {
+            this.value = value;
+        }
+
+        private int value;
+
+
+        public int getReserved() {
+            return (value >> 6) & 0x03;
+        }
+
+        public void setReserved(int res) {
+            value = (res & 0x03) << 6 | value & 0x3f;
+        }
+
+        public int getSampleDependsOn() {
+            return (value >> 4) & 0x03;
+        }
+
+        public void setSampleDependsOn(int sdo) {
+            value = (sdo & 0x03) << 4 | value & 0xcf;
+        }
+
+        public int getSampleIsDependentOn() {
+            return (value >> 2) & 0x03;
+        }
+
+        public void setSampleIsDependentOn(int sido) {
+            value = (sido & 0x03) << 2 | value & 0xf3;
+        }
+
+        public int getSampleHasRedundancy() {
+            return value & 0x03;
+        }
+
+        public void setSampleHasRedundancy(int shr) {
+            value = shr & 0x03 | value & 0xfc;
+        }
+
+        @Override
+        public String toString() {
+            return "Entry{" +
+                    "reserved=" + getReserved() +
+                    ", sampleDependsOn=" + getSampleDependsOn() +
+                    ", sampleIsDependentOn=" + getSampleIsDependentOn() +
+                    ", sampleHasRedundancy=" + getSampleHasRedundancy() +
+                    '}';
+        }
+    }
+
+    public SampleDependencyTypeBox() {
+        super(TYPE);
+    }
+
+    @Override
+    protected long getContentSize() {
+        return 4 + entries.size();
+    }
+
+    @Override
+    protected void getContent(ByteBuffer byteBuffer) {
+        writeVersionAndFlags(byteBuffer);
+        for (Entry entry : entries) {
+            IsoTypeWriter.writeUInt8(byteBuffer, entry.value);
+        }
+    }
+
+    @Override
+    public void _parseDetails(ByteBuffer content) {
+        parseVersionAndFlags(content);
+        while (content.remaining() > 0) {
+            entries.add(new Entry(IsoTypeReader.readUInt8(content)));
+        }
+    }
+
+    public List<Entry> getEntries() {
+        return entries;
+    }
+
+    public void setEntries(List<Entry> entries) {
+        this.entries = entries;
+    }
+
+    @Override
+    public String toString() {
+        final StringBuilder sb = new StringBuilder();
+        sb.append("SampleDependencyTypeBox");
+        sb.append("{entries=").append(entries);
+        sb.append('}');
+        return sb.toString();
+    }
+}
diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/.svn/text-base/SampleDescriptionBox.java.svn-base b/isoparser/src/main/java/com/coremedia/iso/boxes/.svn/text-base/SampleDescriptionBox.java.svn-base
new file mode 100644
index 0000000..662fa99
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/.svn/text-base/SampleDescriptionBox.java.svn-base
@@ -0,0 +1,81 @@
+/*  
+ * Copyright 2008 CoreMedia AG, Hamburg
+ *
+ * Licensed under the Apache License, Version 2.0 (the License); 
+ * you may not use this file except in compliance with the License. 
+ * You may obtain a copy of the License at 
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0 
+ * 
+ * Unless required by applicable law or agreed to in writing, software 
+ * distributed under the License is distributed on an AS IS BASIS, 
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+ * See the License for the specific language governing permissions and 
+ * limitations under the License. 
+ */
+
+package com.coremedia.iso.boxes;
+
+import com.coremedia.iso.IsoTypeWriter;
+import com.coremedia.iso.boxes.sampleentry.SampleEntry;
+import com.googlecode.mp4parser.FullContainerBox;
+
+import java.nio.ByteBuffer;
+
+/**
+ * The sample description table gives detailed information about the coding type used, and any initialization
+ * information needed for that coding. <br>
+ * The information stored in the sample description box after the entry-count is both track-type specific as
+ * documented here, and can also have variants within a track type (e.g. different codings may use different
+ * specific information after some common fields, even within a video track).<br>
+ * For video tracks, a VisualSampleEntry is used; for audio tracks, an AudioSampleEntry. Hint tracks use an
+ * entry format specific to their protocol, with an appropriate name. Timed Text tracks use a TextSampleEntry
+ * For hint tracks, the sample description contains appropriate declarative data for the streaming protocol being
+ * used, and the format of the hint track. The definition of the sample description is specific to the protocol.
+ * Multiple descriptions may be used within a track.<br>
+ * The 'protocol' and 'codingname' fields are registered identifiers that uniquely identify the streaming protocol or
+ * compression format decoder to be used. A given protocol or codingname may have optional or required
+ * extensions to the sample description (e.g. codec initialization parameters). All such extensions shall be within
+ * boxes; these boxes occur after the required fields. Unrecognized boxes shall be ignored.
+ * <br>
+ * Defined in ISO/IEC 14496-12
+ *
+ * @see com.coremedia.iso.boxes.sampleentry.VisualSampleEntry
+ * @see com.coremedia.iso.boxes.sampleentry.TextSampleEntry
+ * @see com.coremedia.iso.boxes.sampleentry.AudioSampleEntry
+ */
+public class SampleDescriptionBox extends FullContainerBox {
+    public static final String TYPE = "stsd";
+
+    public SampleDescriptionBox() {
+        super(TYPE);
+    }
+
+    @Override
+    protected long getContentSize() {
+        return super.getContentSize() + 4;
+    }
+
+    @Override
+    public void _parseDetails(ByteBuffer content) {
+        parseVersionAndFlags(content);
+        content.get(new byte[4]);
+        parseChildBoxes(content);
+    }
+
+    @Override
+    protected void getContent(ByteBuffer byteBuffer) {
+        writeVersionAndFlags(byteBuffer);
+        IsoTypeWriter.writeUInt32(byteBuffer, boxes.size());
+        writeChildBoxes(byteBuffer);
+    }
+
+    public SampleEntry getSampleEntry() {
+        for (Box box : boxes) {
+            if (box instanceof SampleEntry) {
+                return (SampleEntry) box;
+            }
+        }
+        return null;
+    }
+}
diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/.svn/text-base/SampleSizeBox.java.svn-base b/isoparser/src/main/java/com/coremedia/iso/boxes/.svn/text-base/SampleSizeBox.java.svn-base
new file mode 100644
index 0000000..3bc1df0
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/.svn/text-base/SampleSizeBox.java.svn-base
@@ -0,0 +1,121 @@
+/*  
+ * Copyright 2008 CoreMedia AG, Hamburg
+ *
+ * Licensed under the Apache License, Version 2.0 (the License); 
+ * you may not use this file except in compliance with the License. 
+ * You may obtain a copy of the License at 
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0 
+ * 
+ * Unless required by applicable law or agreed to in writing, software 
+ * distributed under the License is distributed on an AS IS BASIS, 
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+ * See the License for the specific language governing permissions and 
+ * limitations under the License. 
+ */
+
+package com.coremedia.iso.boxes;
+
+
+import com.coremedia.iso.IsoTypeReader;
+import com.coremedia.iso.IsoTypeWriter;
+import com.googlecode.mp4parser.AbstractFullBox;
+
+import java.nio.ByteBuffer;
+
+import static com.googlecode.mp4parser.util.CastUtils.l2i;
+
+/**
+ * This box containes the sample count and a table giving the size in bytes of each sample.
+ * Defined in ISO/IEC 14496-12.
+ */
+public class SampleSizeBox extends AbstractFullBox {
+    private long sampleSize;
+    private long[] sampleSizes = new long[0];
+    public static final String TYPE = "stsz";
+    int sampleCount;
+
+    public SampleSizeBox() {
+        super(TYPE);
+    }
+
+    /**
+     * Returns the field sample size.
+     * If sampleSize > 0 every sample has the same size.
+     * If sampleSize == 0 the samples have different size as stated in the sampleSizes field.
+     *
+     * @return the sampleSize field
+     */
+    public long getSampleSize() {
+        return sampleSize;
+    }
+
+    public void setSampleSize(long sampleSize) {
+        this.sampleSize = sampleSize;
+    }
+
+
+    public long getSampleSizeAtIndex(int index) {
+        if (sampleSize > 0) {
+            return sampleSize;
+        } else {
+            return sampleSizes[index];
+        }
+    }
+
+    public long getSampleCount() {
+        if (sampleSize > 0) {
+            return sampleCount;
+        } else {
+            return sampleSizes.length;
+        }
+
+    }
+
+    public long[] getSampleSizes() {
+        return sampleSizes;
+    }
+
+    public void setSampleSizes(long[] sampleSizes) {
+        this.sampleSizes = sampleSizes;
+    }
+
+    protected long getContentSize() {
+        return 12 + (sampleSize == 0 ? sampleSizes.length * 4 : 0);
+    }
+
+    @Override
+    public void _parseDetails(ByteBuffer content) {
+        parseVersionAndFlags(content);
+        sampleSize = IsoTypeReader.readUInt32(content);
+        sampleCount = l2i(IsoTypeReader.readUInt32(content));
+
+        if (sampleSize == 0) {
+            sampleSizes = new long[(int) sampleCount];
+
+            for (int i = 0; i < sampleCount; i++) {
+                sampleSizes[i] = IsoTypeReader.readUInt32(content);
+            }
+        }
+    }
+
+    @Override
+    protected void getContent(ByteBuffer byteBuffer) {
+        writeVersionAndFlags(byteBuffer);
+        IsoTypeWriter.writeUInt32(byteBuffer, sampleSize);
+
+        if (sampleSize == 0) {
+            IsoTypeWriter.writeUInt32(byteBuffer, sampleSizes.length);
+            for (long sampleSize1 : sampleSizes) {
+                IsoTypeWriter.writeUInt32(byteBuffer, sampleSize1);
+            }
+        } else {
+            IsoTypeWriter.writeUInt32(byteBuffer, sampleCount);
+        }
+
+    }
+
+    public String toString() {
+        return "SampleSizeBox[sampleSize=" + getSampleSize() + ";sampleCount=" + getSampleCount() + "]";
+    }
+}
diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/.svn/text-base/SampleTableBox.java.svn-base b/isoparser/src/main/java/com/coremedia/iso/boxes/.svn/text-base/SampleTableBox.java.svn-base
new file mode 100644
index 0000000..33968b3
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/.svn/text-base/SampleTableBox.java.svn-base
@@ -0,0 +1,124 @@
+/*  
+ * Copyright 2008 CoreMedia AG, Hamburg
+ *
+ * Licensed under the Apache License, Version 2.0 (the License); 
+ * you may not use this file except in compliance with the License. 
+ * You may obtain a copy of the License at 
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0 
+ * 
+ * Unless required by applicable law or agreed to in writing, software 
+ * distributed under the License is distributed on an AS IS BASIS, 
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+ * See the License for the specific language governing permissions and 
+ * limitations under the License. 
+ */
+
+package com.coremedia.iso.boxes;
+
+import com.googlecode.mp4parser.AbstractContainerBox;
+
+/**
+ * The sample table contains all the time and data indexing of the media samples in a track. Using the tables
+ * here, it is possible to locate samples in time, determine their type (e.g. I-frame or not), and determine their
+ * size, container, and offset into that container.  <br>
+ * If the track that contains the Sample Table Box references no data, then the Sample Table Box does not need
+ * to contain any sub-boxes (this is not a very useful media track).                                          <br>
+ * If the track that the Sample Table Box is contained in does reference data, then the following sub-boxes are
+ * required: Sample Description, Sample Size, Sample To Chunk, and Chunk Offset. Further, the Sample
+ * Description Box shall contain at least one entry. A Sample Description Box is required because it contains the
+ * data reference index field which indicates which Data Reference Box to use to retrieve the media samples.
+ * Without the Sample Description, it is not possible to determine where the media samples are stored. The Sync
+ * Sample Box is optional. If the Sync Sample Box is not present, all samples are sync samples.<br>
+ * Annex A provides a narrative description of random access using the structures defined in the Sample Table
+ * Box.
+ */
+public class SampleTableBox extends AbstractContainerBox {
+    public static final String TYPE = "stbl";
+
+    public SampleTableBox() {
+        super(TYPE);
+    }
+
+    public SampleDescriptionBox getSampleDescriptionBox() {
+        for (Box box : boxes) {
+            if (box instanceof SampleDescriptionBox) {
+                return (SampleDescriptionBox) box;
+            }
+        }
+        return null;
+    }
+
+    public SampleSizeBox getSampleSizeBox() {
+        for (Box box : boxes) {
+            if (box instanceof SampleSizeBox) {
+                return (SampleSizeBox) box;
+            }
+        }
+        return null;
+    }
+
+    public SampleToChunkBox getSampleToChunkBox() {
+        for (Box box : boxes) {
+            if (box instanceof SampleToChunkBox) {
+                return (SampleToChunkBox) box;
+            }
+        }
+        return null;
+    }
+
+    public ChunkOffsetBox getChunkOffsetBox() {
+        for (Box box : boxes) {
+            if (box instanceof ChunkOffsetBox) {
+                return (ChunkOffsetBox) box;
+            }
+        }
+        return null;
+    }
+
+    public void setChunkOffsetBox(ChunkOffsetBox b) {
+        for (int i = 0; i < boxes.size(); i++) {
+            Box box = boxes.get(i);
+            if (box instanceof ChunkOffsetBox) {
+                boxes.set(i, b);
+            }
+        }
+    }
+
+    public TimeToSampleBox getTimeToSampleBox() {
+        for (Box box : boxes) {
+            if (box instanceof TimeToSampleBox) {
+                return (TimeToSampleBox) box;
+            }
+        }
+        return null;
+    }
+
+    public SyncSampleBox getSyncSampleBox() {
+        for (Box box : boxes) {
+            if (box instanceof SyncSampleBox) {
+                return (SyncSampleBox) box;
+            }
+        }
+        return null;
+    }
+
+    public CompositionTimeToSample getCompositionTimeToSample() {
+        for (Box box : boxes) {
+            if (box instanceof CompositionTimeToSample) {
+                return (CompositionTimeToSample) box;
+            }
+        }
+        return null;
+    }
+
+    public SampleDependencyTypeBox getSampleDependencyTypeBox() {
+        for (Box box : boxes) {
+            if (box instanceof SampleDependencyTypeBox) {
+                return (SampleDependencyTypeBox) box;
+            }
+        }
+        return null;
+    }
+
+}
diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/.svn/text-base/SampleToChunkBox.java.svn-base b/isoparser/src/main/java/com/coremedia/iso/boxes/.svn/text-base/SampleToChunkBox.java.svn-base
new file mode 100644
index 0000000..593504d
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/.svn/text-base/SampleToChunkBox.java.svn-base
@@ -0,0 +1,156 @@
+/*  
+ * Copyright 2008 CoreMedia AG, Hamburg
+ *
+ * Licensed under the Apache License, Version 2.0 (the License); 
+ * you may not use this file except in compliance with the License. 
+ * You may obtain a copy of the License at 
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0 
+ * 
+ * Unless required by applicable law or agreed to in writing, software 
+ * distributed under the License is distributed on an AS IS BASIS, 
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+ * See the License for the specific language governing permissions and 
+ * limitations under the License. 
+ */
+
+package com.coremedia.iso.boxes;
+
+import com.coremedia.iso.IsoTypeReader;
+import com.coremedia.iso.IsoTypeWriter;
+import com.googlecode.mp4parser.AbstractFullBox;
+
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+
+import static com.googlecode.mp4parser.util.CastUtils.l2i;
+
+/**
+ * Samples within the media data are grouped into chunks. Chunks can be of different sizes, and the
+ * samples within a chunk can have different sizes. This table can be used to find the chunk that
+ * contains a sample, its position, and the associated sample description. Defined in ISO/IEC 14496-12.
+ */
+public class SampleToChunkBox extends AbstractFullBox {
+    List<Entry> entries = Collections.emptyList();
+
+    public static final String TYPE = "stsc";
+
+    public SampleToChunkBox() {
+        super(TYPE);
+    }
+
+    public List<Entry> getEntries() {
+        return entries;
+    }
+
+    public void setEntries(List<Entry> entries) {
+        this.entries = entries;
+    }
+
+    protected long getContentSize() {
+        return entries.size() * 12 + 8;
+    }
+
+    @Override
+    public void _parseDetails(ByteBuffer content) {
+        parseVersionAndFlags(content);
+
+        int entryCount = l2i(IsoTypeReader.readUInt32(content));
+        entries = new ArrayList<Entry>(entryCount);
+        for (int i = 0; i < entryCount; i++) {
+            entries.add(new Entry(
+                    IsoTypeReader.readUInt32(content),
+                    IsoTypeReader.readUInt32(content),
+                    IsoTypeReader.readUInt32(content)));
+        }
+    }
+
+    @Override
+    protected void getContent(ByteBuffer byteBuffer) {
+        writeVersionAndFlags(byteBuffer);
+        IsoTypeWriter.writeUInt32(byteBuffer, entries.size());
+        for (Entry entry : entries) {
+            IsoTypeWriter.writeUInt32(byteBuffer, entry.getFirstChunk());
+            IsoTypeWriter.writeUInt32(byteBuffer, entry.getSamplesPerChunk());
+            IsoTypeWriter.writeUInt32(byteBuffer, entry.getSampleDescriptionIndex());
+        }
+    }
+
+    public String toString() {
+        return "SampleToChunkBox[entryCount=" + entries.size() + "]";
+    }
+
+    /**
+     * Decompresses the list of entries and returns the number of samples per chunk for
+     * every single chunk.
+     *
+     * @param chunkCount overall number of chunks
+     * @return number of samples per chunk
+     */
+    public long[] blowup(int chunkCount) {
+        long[] numberOfSamples = new long[chunkCount];
+        int j = 0;
+        List<SampleToChunkBox.Entry> sampleToChunkEntries = new LinkedList<Entry>(entries);
+        Collections.reverse(sampleToChunkEntries);
+        Iterator<Entry> iterator = sampleToChunkEntries.iterator();
+        SampleToChunkBox.Entry currentEntry = iterator.next();
+
+        for (int i = numberOfSamples.length; i > 1; i--) {
+            numberOfSamples[i - 1] = currentEntry.getSamplesPerChunk();
+            if (i == currentEntry.getFirstChunk()) {
+                currentEntry = iterator.next();
+            }
+        }
+        numberOfSamples[0] = currentEntry.getSamplesPerChunk();
+        return numberOfSamples;
+    }
+
+    public static class Entry {
+        long firstChunk;
+        long samplesPerChunk;
+        long sampleDescriptionIndex;
+
+        public Entry(long firstChunk, long samplesPerChunk, long sampleDescriptionIndex) {
+            this.firstChunk = firstChunk;
+            this.samplesPerChunk = samplesPerChunk;
+            this.sampleDescriptionIndex = sampleDescriptionIndex;
+        }
+
+        public long getFirstChunk() {
+            return firstChunk;
+        }
+
+        public void setFirstChunk(long firstChunk) {
+            this.firstChunk = firstChunk;
+        }
+
+        public long getSamplesPerChunk() {
+            return samplesPerChunk;
+        }
+
+        public void setSamplesPerChunk(long samplesPerChunk) {
+            this.samplesPerChunk = samplesPerChunk;
+        }
+
+        public long getSampleDescriptionIndex() {
+            return sampleDescriptionIndex;
+        }
+
+        public void setSampleDescriptionIndex(long sampleDescriptionIndex) {
+            this.sampleDescriptionIndex = sampleDescriptionIndex;
+        }
+
+        @Override
+        public String toString() {
+            return "Entry{" +
+                    "firstChunk=" + firstChunk +
+                    ", samplesPerChunk=" + samplesPerChunk +
+                    ", sampleDescriptionIndex=" + sampleDescriptionIndex +
+                    '}';
+        }
+    }
+}
diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/.svn/text-base/SchemeInformationBox.java.svn-base b/isoparser/src/main/java/com/coremedia/iso/boxes/.svn/text-base/SchemeInformationBox.java.svn-base
new file mode 100644
index 0000000..5e3565e
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/.svn/text-base/SchemeInformationBox.java.svn-base
@@ -0,0 +1,33 @@
+/*  
+ * Copyright 2008 CoreMedia AG, Hamburg
+ *
+ * Licensed under the Apache License, Version 2.0 (the License); 
+ * you may not use this file except in compliance with the License. 
+ * You may obtain a copy of the License at 
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0 
+ * 
+ * Unless required by applicable law or agreed to in writing, software 
+ * distributed under the License is distributed on an AS IS BASIS, 
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+ * See the License for the specific language governing permissions and 
+ * limitations under the License. 
+ */
+
+package com.coremedia.iso.boxes;
+
+import com.googlecode.mp4parser.AbstractContainerBox;
+
+/**
+ * The Scheme Information Box is a container box that is only interpreted by the scheme beeing used.
+ * Any information the encryption system needs is stored here. The content of this box is a series of
+ * boxexes whose type annd format are defined by the scheme declared in the {@link com.coremedia.iso.boxes.SchemeTypeBox}.
+ */
+public class SchemeInformationBox extends AbstractContainerBox {
+    public static final String TYPE = "schi";
+
+    public SchemeInformationBox() {
+        super(TYPE);
+    }
+
+}
diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/.svn/text-base/SchemeTypeBox.java.svn-base b/isoparser/src/main/java/com/coremedia/iso/boxes/.svn/text-base/SchemeTypeBox.java.svn-base
new file mode 100644
index 0000000..ed517da
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/.svn/text-base/SchemeTypeBox.java.svn-base
@@ -0,0 +1,101 @@
+/*  
+ * Copyright 2008 CoreMedia AG, Hamburg
+ *
+ * Licensed under the Apache License, Version 2.0 (the License); 
+ * you may not use this file except in compliance with the License. 
+ * You may obtain a copy of the License at 
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0 
+ * 
+ * Unless required by applicable law or agreed to in writing, software 
+ * distributed under the License is distributed on an AS IS BASIS, 
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+ * See the License for the specific language governing permissions and 
+ * limitations under the License. 
+ */
+
+package com.coremedia.iso.boxes;
+
+import com.coremedia.iso.IsoFile;
+import com.coremedia.iso.IsoTypeReader;
+import com.coremedia.iso.IsoTypeWriter;
+import com.coremedia.iso.Utf8;
+import com.googlecode.mp4parser.AbstractFullBox;
+
+import java.nio.ByteBuffer;
+
+/**
+ * The Scheme Type Box identifies the protection scheme. Resides in  a Protection Scheme Information Box or
+ * an SRTP Process Box.
+ *
+ * @see com.coremedia.iso.boxes.SchemeInformationBox
+ */
+public class SchemeTypeBox extends AbstractFullBox {
+    public static final String TYPE = "schm";
+    String schemeType = "    ";
+    long schemeVersion;
+    String schemeUri = null;
+
+    public SchemeTypeBox() {
+        super(TYPE);
+    }
+
+    public String getSchemeType() {
+        return schemeType;
+    }
+
+    public long getSchemeVersion() {
+        return schemeVersion;
+    }
+
+    public String getSchemeUri() {
+        return schemeUri;
+    }
+
+    public void setSchemeType(String schemeType) {
+        assert schemeType != null && schemeType.length() == 4 : "SchemeType may not be null or not 4 bytes long";
+        this.schemeType = schemeType;
+    }
+
+    public void setSchemeVersion(int schemeVersion) {
+        this.schemeVersion = schemeVersion;
+    }
+
+    public void setSchemeUri(String schemeUri) {
+        this.schemeUri = schemeUri;
+    }
+
+    protected long getContentSize() {
+        return 12 + (((getFlags() & 1) == 1) ? Utf8.utf8StringLengthInBytes(schemeUri) + 1 : 0);
+    }
+
+    @Override
+    public void _parseDetails(ByteBuffer content) {
+        parseVersionAndFlags(content);
+        schemeType = IsoTypeReader.read4cc(content);
+        schemeVersion = IsoTypeReader.readUInt32(content);
+        if ((getFlags() & 1) == 1) {
+            schemeUri = IsoTypeReader.readString(content);
+        }
+    }
+
+    @Override
+    protected void getContent(ByteBuffer byteBuffer) {
+        writeVersionAndFlags(byteBuffer);
+        byteBuffer.put(IsoFile.fourCCtoBytes(schemeType));
+        IsoTypeWriter.writeUInt32(byteBuffer, schemeVersion);
+        if ((getFlags() & 1) == 1) {
+            byteBuffer.put(Utf8.convert(schemeUri));
+        }
+    }
+
+    public String toString() {
+        StringBuilder buffer = new StringBuilder();
+        buffer.append("Schema Type Box[");
+        buffer.append("schemeUri=").append(schemeUri).append("; ");
+        buffer.append("schemeType=").append(schemeType).append("; ");
+        buffer.append("schemeVersion=").append(schemeUri).append("; ");
+        buffer.append("]");
+        return buffer.toString();
+    }
+}
diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/.svn/text-base/SoundMediaHeaderBox.java.svn-base b/isoparser/src/main/java/com/coremedia/iso/boxes/.svn/text-base/SoundMediaHeaderBox.java.svn-base
new file mode 100644
index 0000000..c5fb88d
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/.svn/text-base/SoundMediaHeaderBox.java.svn-base
@@ -0,0 +1,58 @@
+/*  
+ * Copyright 2008 CoreMedia AG, Hamburg
+ *
+ * Licensed under the Apache License, Version 2.0 (the License); 
+ * you may not use this file except in compliance with the License. 
+ * You may obtain a copy of the License at 
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0 
+ * 
+ * Unless required by applicable law or agreed to in writing, software 
+ * distributed under the License is distributed on an AS IS BASIS, 
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+ * See the License for the specific language governing permissions and 
+ * limitations under the License. 
+ */
+
+package com.coremedia.iso.boxes;
+
+import com.coremedia.iso.IsoTypeReader;
+import com.coremedia.iso.IsoTypeWriter;
+
+import java.nio.ByteBuffer;
+
+public class SoundMediaHeaderBox extends AbstractMediaHeaderBox {
+
+    public static final String TYPE = "smhd";
+    private float balance;
+
+    public SoundMediaHeaderBox() {
+        super(TYPE);
+    }
+
+    public float getBalance() {
+        return balance;
+    }
+
+    protected long getContentSize() {
+        return 8;
+    }
+
+    @Override
+    public void _parseDetails(ByteBuffer content) {
+        parseVersionAndFlags(content);
+        balance = IsoTypeReader.readFixedPoint88(content);
+        IsoTypeReader.readUInt16(content);
+    }
+
+    @Override
+    protected void getContent(ByteBuffer byteBuffer) {
+        writeVersionAndFlags(byteBuffer);
+        IsoTypeWriter.writeFixedPont88(byteBuffer, balance);
+        IsoTypeWriter.writeUInt16(byteBuffer, 0);
+    }
+
+    public String toString() {
+        return "SoundMediaHeaderBox[balance=" + getBalance() + "]";
+    }
+}
diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/.svn/text-base/StaticChunkOffsetBox.java.svn-base b/isoparser/src/main/java/com/coremedia/iso/boxes/.svn/text-base/StaticChunkOffsetBox.java.svn-base
new file mode 100644
index 0000000..efcdd14
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/.svn/text-base/StaticChunkOffsetBox.java.svn-base
@@ -0,0 +1,71 @@
+/*  
+ * Copyright 2008 CoreMedia AG, Hamburg
+ *
+ * Licensed under the Apache License, Version 2.0 (the License); 
+ * you may not use this file except in compliance with the License. 
+ * You may obtain a copy of the License at 
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0 
+ * 
+ * Unless required by applicable law or agreed to in writing, software 
+ * distributed under the License is distributed on an AS IS BASIS, 
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+ * See the License for the specific language governing permissions and 
+ * limitations under the License. 
+ */
+
+package com.coremedia.iso.boxes;
+
+import com.coremedia.iso.IsoTypeReader;
+import com.coremedia.iso.IsoTypeWriter;
+
+import java.nio.ByteBuffer;
+
+import static com.googlecode.mp4parser.util.CastUtils.l2i;
+
+/**
+ * The chunk offset table gives the index of each chunk into the containing file. Defined in ISO/IEC 14496-12.
+ */
+public class StaticChunkOffsetBox extends ChunkOffsetBox {
+    public static final String TYPE = "stco";
+
+    private long[] chunkOffsets = new long[0];
+
+    public StaticChunkOffsetBox() {
+        super(TYPE);
+    }
+
+    public long[] getChunkOffsets() {
+        return chunkOffsets;
+    }
+
+    protected long getContentSize() {
+        return 8 + chunkOffsets.length * 4;
+    }
+
+    public void setChunkOffsets(long[] chunkOffsets) {
+        this.chunkOffsets = chunkOffsets;
+    }
+
+    @Override
+    public void _parseDetails(ByteBuffer content) {
+        parseVersionAndFlags(content);
+        int entryCount = l2i(IsoTypeReader.readUInt32(content));
+        chunkOffsets = new long[entryCount];
+        for (int i = 0; i < entryCount; i++) {
+            chunkOffsets[i] = IsoTypeReader.readUInt32(content);
+        }
+
+    }
+
+    @Override
+    protected void getContent(ByteBuffer byteBuffer) {
+        writeVersionAndFlags(byteBuffer);
+        IsoTypeWriter.writeUInt32(byteBuffer, chunkOffsets.length);
+        for (long chunkOffset : chunkOffsets) {
+            IsoTypeWriter.writeUInt32(byteBuffer, chunkOffset);
+        }
+    }
+
+
+}
diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/.svn/text-base/SubSampleInformationBox.java.svn-base b/isoparser/src/main/java/com/coremedia/iso/boxes/.svn/text-base/SubSampleInformationBox.java.svn-base
new file mode 100644
index 0000000..f5806eb
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/.svn/text-base/SubSampleInformationBox.java.svn-base
@@ -0,0 +1,208 @@
+package com.coremedia.iso.boxes;

+

+import com.coremedia.iso.IsoTypeReader;

+import com.coremedia.iso.IsoTypeWriter;

+import com.googlecode.mp4parser.AbstractFullBox;

+

+import java.nio.ByteBuffer;

+import java.util.ArrayList;

+import java.util.List;

+

+import static com.googlecode.mp4parser.util.CastUtils.l2i;

+

+/**

+ * aligned(8) class SubSampleInformationBox

+ * extends FullBox('subs', version, 0) {

+ * unsigned int(32) entry_count;

+ * int i,j;

+ * for (i=0; i < entry_count; i++) {

+ * unsigned int(32) sample_delta;

+ * unsigned int(16) subsample_count;

+ * if (subsample_count > 0) {

+ * for (j=0; j < subsample_count; j++) {

+ * if(version == 1)

+ * {

+ * unsigned int(32) subsample_size;

+ * }

+ * else

+ * {

+ * unsigned int(16) subsample_size;

+ * }

+ * unsigned int(8) subsample_priority;

+ * unsigned int(8) discardable;

+ * unsigned int(32) reserved = 0;

+ * }

+ * }

+ * }

+ * }

+ */

+public class SubSampleInformationBox extends AbstractFullBox {

+    public static final String TYPE = "subs";

+

+    private long entryCount;

+    private List<SampleEntry> entries = new ArrayList<SampleEntry>();

+

+    public SubSampleInformationBox() {

+        super(TYPE);

+    }

+

+    public List<SampleEntry> getEntries() {

+        return entries;

+    }

+

+    public void setEntries(List<SampleEntry> entries) {

+        this.entries = entries;

+        entryCount = entries.size();

+    }

+

+    @Override

+    protected long getContentSize() {

+        long entries = 8 + ((4 + 2) * entryCount);

+        int subsampleEntries = 0;

+        for (SampleEntry sampleEntry : this.entries) {

+            subsampleEntries += sampleEntry.getSubsampleCount() * (((getVersion() == 1) ? 4 : 2) + 1 + 1 + 4);

+        }

+        return entries + subsampleEntries;

+    }

+

+    @Override

+    public void _parseDetails(ByteBuffer content) {

+        parseVersionAndFlags(content);

+

+        entryCount = IsoTypeReader.readUInt32(content);

+

+        for (int i = 0; i < entryCount; i++) {

+            SampleEntry sampleEntry = new SampleEntry();

+            sampleEntry.setSampleDelta(IsoTypeReader.readUInt32(content));

+            int subsampleCount = IsoTypeReader.readUInt16(content);

+            for (int j = 0; j < subsampleCount; j++) {

+                SampleEntry.SubsampleEntry subsampleEntry = new SampleEntry.SubsampleEntry();

+                subsampleEntry.setSubsampleSize(getVersion() == 1 ? IsoTypeReader.readUInt32(content) : IsoTypeReader.readUInt16(content));

+                subsampleEntry.setSubsamplePriority(IsoTypeReader.readUInt8(content));

+                subsampleEntry.setDiscardable(IsoTypeReader.readUInt8(content));

+                subsampleEntry.setReserved(IsoTypeReader.readUInt32(content));

+                sampleEntry.addSubsampleEntry(subsampleEntry);

+            }

+            entries.add(sampleEntry);

+        }

+

+    }

+

+    @Override

+    protected void getContent(ByteBuffer byteBuffer) {

+        writeVersionAndFlags(byteBuffer);

+        IsoTypeWriter.writeUInt32(byteBuffer, entries.size());

+        for (SampleEntry sampleEntry : entries) {

+            IsoTypeWriter.writeUInt32(byteBuffer, sampleEntry.getSampleDelta());

+            IsoTypeWriter.writeUInt16(byteBuffer, sampleEntry.getSubsampleCount());

+            List<SampleEntry.SubsampleEntry> subsampleEntries = sampleEntry.getSubsampleEntries();

+            for (SampleEntry.SubsampleEntry subsampleEntry : subsampleEntries) {

+                if (getVersion() == 1) {

+                    IsoTypeWriter.writeUInt32(byteBuffer, subsampleEntry.getSubsampleSize());

+                } else {

+                    IsoTypeWriter.writeUInt16(byteBuffer, l2i(subsampleEntry.getSubsampleSize()));

+                }

+                IsoTypeWriter.writeUInt8(byteBuffer, subsampleEntry.getSubsamplePriority());

+                IsoTypeWriter.writeUInt8(byteBuffer, subsampleEntry.getDiscardable());

+                IsoTypeWriter.writeUInt32(byteBuffer, subsampleEntry.getReserved());

+            }

+        }

+    }

+

+    @Override

+    public String toString() {

+        return "SubSampleInformationBox{" +

+                "entryCount=" + entryCount +

+                ", entries=" + entries +

+                '}';

+    }

+

+    public static class SampleEntry {

+        private long sampleDelta;

+        private int subsampleCount;

+        private List<SubsampleEntry> subsampleEntries = new ArrayList<SubsampleEntry>();

+

+        public long getSampleDelta() {

+            return sampleDelta;

+        }

+

+        public void setSampleDelta(long sampleDelta) {

+            this.sampleDelta = sampleDelta;

+        }

+

+        public int getSubsampleCount() {

+            return subsampleCount;

+        }

+

+        public void setSubsampleCount(int subsampleCount) {

+            this.subsampleCount = subsampleCount;

+        }

+

+        public List<SubsampleEntry> getSubsampleEntries() {

+            return subsampleEntries;

+        }

+

+        public void addSubsampleEntry(SubsampleEntry subsampleEntry) {

+            subsampleEntries.add(subsampleEntry);

+            subsampleCount++;

+        }

+

+        public static class SubsampleEntry {

+            private long subsampleSize;

+            private int subsamplePriority;

+            private int discardable;

+            private long reserved;

+

+            public long getSubsampleSize() {

+                return subsampleSize;

+            }

+

+            public void setSubsampleSize(long subsampleSize) {

+                this.subsampleSize = subsampleSize;

+            }

+

+            public int getSubsamplePriority() {

+                return subsamplePriority;

+            }

+

+            public void setSubsamplePriority(int subsamplePriority) {

+                this.subsamplePriority = subsamplePriority;

+            }

+

+            public int getDiscardable() {

+                return discardable;

+            }

+

+            public void setDiscardable(int discardable) {

+                this.discardable = discardable;

+            }

+

+            public long getReserved() {

+                return reserved;

+            }

+

+            public void setReserved(long reserved) {

+                this.reserved = reserved;

+            }

+

+            @Override

+            public String toString() {

+                return "SubsampleEntry{" +

+                        "subsampleSize=" + subsampleSize +

+                        ", subsamplePriority=" + subsamplePriority +

+                        ", discardable=" + discardable +

+                        ", reserved=" + reserved +

+                        '}';

+            }

+        }

+

+        @Override

+        public String toString() {

+            return "SampleEntry{" +

+                    "sampleDelta=" + sampleDelta +

+                    ", subsampleCount=" + subsampleCount +

+                    ", subsampleEntries=" + subsampleEntries +

+                    '}';

+        }

+    }

+}

diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/.svn/text-base/SubtitleMediaHeaderBox.java.svn-base b/isoparser/src/main/java/com/coremedia/iso/boxes/.svn/text-base/SubtitleMediaHeaderBox.java.svn-base
new file mode 100644
index 0000000..fa25a5c
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/.svn/text-base/SubtitleMediaHeaderBox.java.svn-base
@@ -0,0 +1,30 @@
+package com.coremedia.iso.boxes;
+
+import java.nio.ByteBuffer;
+
+public class SubtitleMediaHeaderBox extends AbstractMediaHeaderBox {
+
+    public static final String TYPE = "sthd";
+
+    public SubtitleMediaHeaderBox() {
+        super(TYPE);
+    }
+
+    protected long getContentSize() {
+        return 4;
+    }
+
+    @Override
+    public void _parseDetails(ByteBuffer content) {
+        parseVersionAndFlags(content);
+    }
+
+    @Override
+    protected void getContent(ByteBuffer byteBuffer) {
+        writeVersionAndFlags(byteBuffer);
+    }
+
+    public String toString() {
+        return "SubtitleMediaHeaderBox";
+    }
+}
diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/.svn/text-base/SyncSampleBox.java.svn-base b/isoparser/src/main/java/com/coremedia/iso/boxes/.svn/text-base/SyncSampleBox.java.svn-base
new file mode 100644
index 0000000..5fc758b
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/.svn/text-base/SyncSampleBox.java.svn-base
@@ -0,0 +1,83 @@
+/*  
+ * Copyright 2008 CoreMedia AG, Hamburg
+ *
+ * Licensed under the Apache License, Version 2.0 (the License); 
+ * you may not use this file except in compliance with the License. 
+ * You may obtain a copy of the License at 
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0 
+ * 
+ * Unless required by applicable law or agreed to in writing, software 
+ * distributed under the License is distributed on an AS IS BASIS, 
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+ * See the License for the specific language governing permissions and 
+ * limitations under the License. 
+ */
+
+package com.coremedia.iso.boxes;
+
+import com.coremedia.iso.IsoTypeReader;
+import com.coremedia.iso.IsoTypeWriter;
+import com.googlecode.mp4parser.AbstractFullBox;
+
+import java.nio.ByteBuffer;
+
+import static com.googlecode.mp4parser.util.CastUtils.l2i;
+
+/**
+ * This box provides a compact marking of the random access points withinthe stream. The table is arranged in
+ * strictly decreasinf order of sample number. Defined in ISO/IEC 14496-12.
+ */
+public class SyncSampleBox extends AbstractFullBox {
+    public static final String TYPE = "stss";
+
+    private long[] sampleNumber;
+
+    public SyncSampleBox() {
+        super(TYPE);
+    }
+
+    /**
+     * Gives the numbers of the samples that are random access points in the stream.
+     *
+     * @return random access sample numbers.
+     */
+    public long[] getSampleNumber() {
+        return sampleNumber;
+    }
+
+    protected long getContentSize() {
+        return sampleNumber.length * 4 + 8;
+    }
+
+    @Override
+    public void _parseDetails(ByteBuffer content) {
+        parseVersionAndFlags(content);
+        int entryCount = l2i(IsoTypeReader.readUInt32(content));
+
+        sampleNumber = new long[entryCount];
+        for (int i = 0; i < entryCount; i++) {
+            sampleNumber[i] = IsoTypeReader.readUInt32(content);
+        }
+    }
+
+    @Override
+    protected void getContent(ByteBuffer byteBuffer) {
+        writeVersionAndFlags(byteBuffer);
+
+        IsoTypeWriter.writeUInt32(byteBuffer, sampleNumber.length);
+
+        for (long aSampleNumber : sampleNumber) {
+            IsoTypeWriter.writeUInt32(byteBuffer, aSampleNumber);
+        }
+
+    }
+
+    public String toString() {
+        return "SyncSampleBox[entryCount=" + sampleNumber.length + "]";
+    }
+
+    public void setSampleNumber(long[] sampleNumber) {
+        this.sampleNumber = sampleNumber;
+    }
+}
diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/.svn/text-base/TimeToSampleBox.java.svn-base b/isoparser/src/main/java/com/coremedia/iso/boxes/.svn/text-base/TimeToSampleBox.java.svn-base
new file mode 100644
index 0000000..8f4f97e
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/.svn/text-base/TimeToSampleBox.java.svn-base
@@ -0,0 +1,152 @@
+/*  
+ * Copyright 2008 CoreMedia AG, Hamburg
+ *
+ * Licensed under the Apache License, Version 2.0 (the License); 
+ * you may not use this file except in compliance with the License. 
+ * You may obtain a copy of the License at 
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0 
+ * 
+ * Unless required by applicable law or agreed to in writing, software 
+ * distributed under the License is distributed on an AS IS BASIS, 
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+ * See the License for the specific language governing permissions and 
+ * limitations under the License. 
+ */
+
+package com.coremedia.iso.boxes;
+
+
+import com.coremedia.iso.IsoTypeReader;
+import com.coremedia.iso.IsoTypeWriter;
+import com.googlecode.mp4parser.AbstractFullBox;
+
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import static com.googlecode.mp4parser.util.CastUtils.l2i;
+
+/**
+ * This box contains a compact version of a table that allows indexing from decoding time to sample number.
+ * Other tables give sample sizes and pointers, from the sample number. Each entry in the table gives the
+ * number of consecutive samples with the same time delta, and the delta of those samples. By adding the
+ * deltas a complete time-to-sample map may be built.<br>
+ * The Decoding Time to Sample Box contains decode time delta's: <code>DT(n+1) = DT(n) + STTS(n)</code> where STTS(n)
+ * is the (uncompressed) table entry for sample n.<br>
+ * The sample entries are ordered by decoding time stamps; therefore the deltas are all non-negative. <br>
+ * The DT axis has a zero origin; <code>DT(i) = SUM(for j=0 to i-1 of delta(j))</code>, and the sum of all
+ * deltas gives the length of the media in the track (not mapped to the overall timescale, and not considering
+ * any edit list).    <br>
+ * The Edit List Box provides the initial CT value if it is non-empty (non-zero).
+ */
+public class TimeToSampleBox extends AbstractFullBox {
+    public static final String TYPE = "stts";
+
+    List<Entry> entries = Collections.emptyList();
+
+
+    public TimeToSampleBox() {
+        super(TYPE);
+    }
+
+    protected long getContentSize() {
+        return 8 + entries.size() * 8;
+    }
+
+    @Override
+    public void _parseDetails(ByteBuffer content) {
+        parseVersionAndFlags(content);
+        int entryCount = l2i(IsoTypeReader.readUInt32(content));
+        entries = new ArrayList<Entry>(entryCount);
+
+        for (int i = 0; i < entryCount; i++) {
+            entries.add(new Entry(IsoTypeReader.readUInt32(content), IsoTypeReader.readUInt32(content)));
+        }
+
+    }
+
+    @Override
+    protected void getContent(ByteBuffer byteBuffer) {
+        writeVersionAndFlags(byteBuffer);
+        IsoTypeWriter.writeUInt32(byteBuffer, entries.size());
+        for (Entry entry : entries) {
+            IsoTypeWriter.writeUInt32(byteBuffer, entry.getCount());
+            IsoTypeWriter.writeUInt32(byteBuffer, entry.getDelta());
+        }
+    }
+
+    public List<Entry> getEntries() {
+        return entries;
+    }
+
+    public void setEntries(List<Entry> entries) {
+        this.entries = entries;
+    }
+
+    public String toString() {
+        return "TimeToSampleBox[entryCount=" + entries.size() + "]";
+    }
+
+    public static class Entry {
+        long count;
+        long delta;
+
+        public Entry(long count, long delta) {
+            this.count = count;
+            this.delta = delta;
+        }
+
+        public long getCount() {
+            return count;
+        }
+
+        public long getDelta() {
+            return delta;
+        }
+
+        public void setCount(long count) {
+            this.count = count;
+        }
+
+        public void setDelta(long delta) {
+            this.delta = delta;
+        }
+
+        @Override
+        public String toString() {
+            return "Entry{" +
+                    "count=" + count +
+                    ", delta=" + delta +
+                    '}';
+        }
+    }
+
+    /**
+     * Decompresses the list of entries and returns the list of decoding times.
+     *
+     * @return decoding time per sample
+     */
+    public static long[] blowupTimeToSamples(List<TimeToSampleBox.Entry> entries) {
+        long numOfSamples = 0;
+        for (TimeToSampleBox.Entry entry : entries) {
+            numOfSamples += entry.getCount();
+        }
+        assert numOfSamples <= Integer.MAX_VALUE;
+        long[] decodingTime = new long[(int) numOfSamples];
+
+        int current = 0;
+
+
+        for (TimeToSampleBox.Entry entry : entries) {
+            for (int i = 0; i < entry.getCount(); i++) {
+                decodingTime[current++] = entry.getDelta();
+            }
+        }
+
+        return decodingTime;
+    }
+
+
+}
diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/.svn/text-base/TitleBox.java.svn-base b/isoparser/src/main/java/com/coremedia/iso/boxes/.svn/text-base/TitleBox.java.svn-base
new file mode 100644
index 0000000..46ee5ee
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/.svn/text-base/TitleBox.java.svn-base
@@ -0,0 +1,89 @@
+/*  
+ * Copyright 2008 CoreMedia AG, Hamburg
+ *
+ * Licensed under the Apache License, Version 2.0 (the License); 
+ * you may not use this file except in compliance with the License. 
+ * You may obtain a copy of the License at 
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0 
+ * 
+ * Unless required by applicable law or agreed to in writing, software 
+ * distributed under the License is distributed on an AS IS BASIS, 
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+ * See the License for the specific language governing permissions and 
+ * limitations under the License. 
+ */
+
+package com.coremedia.iso.boxes;
+
+import com.coremedia.iso.IsoTypeReader;
+import com.coremedia.iso.IsoTypeWriter;
+import com.coremedia.iso.Utf8;
+import com.googlecode.mp4parser.AbstractFullBox;
+
+import java.nio.ByteBuffer;
+
+/**
+ * <code>
+ * Box Type: 'titl'<br>
+ * Container: {@link UserDataBox} ('udta')<br>
+ * Mandatory: No<br>
+ * Quantity: Zero or one<br><br>
+ * </code>
+ * <p/>
+ * Title for the media.
+ */
+public class TitleBox extends AbstractFullBox {
+    public static final String TYPE = "titl";
+
+    private String language;
+    private String title;
+
+    public TitleBox() {
+        super(TYPE);
+    }
+
+    public String getLanguage() {
+        return language;
+    }
+
+    public String getTitle() {
+        return title;
+    }
+
+    /**
+     * Sets the 3-letter ISO-639 language for this title.
+     *
+     * @param language 3-letter ISO-639 code
+     */
+    public void setLanguage(String language) {
+        this.language = language;
+    }
+
+    public void setTitle(String title) {
+        this.title = title;
+    }
+
+    protected long getContentSize() {
+        return 7 + Utf8.utf8StringLengthInBytes(title);
+    }
+
+
+    protected void getContent(ByteBuffer byteBuffer) {
+        writeVersionAndFlags(byteBuffer);
+        IsoTypeWriter.writeIso639(byteBuffer, language);
+        byteBuffer.put(Utf8.convert(title));
+        byteBuffer.put((byte) 0);
+    }
+
+    @Override
+    public void _parseDetails(ByteBuffer content) {
+        parseVersionAndFlags(content);
+        language = IsoTypeReader.readIso639(content);
+        title = IsoTypeReader.readString(content);
+    }
+
+    public String toString() {
+        return "TitleBox[language=" + getLanguage() + ";title=" + getTitle() + "]";
+    }
+}
diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/.svn/text-base/TrackBox.java.svn-base b/isoparser/src/main/java/com/coremedia/iso/boxes/.svn/text-base/TrackBox.java.svn-base
new file mode 100644
index 0000000..c2806b5
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/.svn/text-base/TrackBox.java.svn-base
@@ -0,0 +1,71 @@
+/*  
+ * Copyright 2008 CoreMedia AG, Hamburg
+ *
+ * Licensed under the Apache License, Version 2.0 (the License); 
+ * you may not use this file except in compliance with the License. 
+ * You may obtain a copy of the License at 
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0 
+ * 
+ * Unless required by applicable law or agreed to in writing, software 
+ * distributed under the License is distributed on an AS IS BASIS, 
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+ * See the License for the specific language governing permissions and 
+ * limitations under the License. 
+ */
+
+package com.coremedia.iso.boxes;
+
+import com.googlecode.mp4parser.AbstractContainerBox;
+
+/**
+ * Tracks are used for two purposes: (a) to contain media data (media tracks) and (b) to contain packetization
+ * information for streaming protocols (hint tracks).  <br>
+ * There shall be at least one media track within an ISO file, and all the media tracks that contributed to the hint
+ * tracks shall remain in the file, even if the media data within them is not referenced by the hint tracks; after
+ * deleting all hint tracks, the entire un-hinted presentation shall remain.
+ */
+public class TrackBox extends AbstractContainerBox {
+    public static final String TYPE = "trak";
+
+    public TrackBox() {
+        super(TYPE);
+    }
+
+    public TrackHeaderBox getTrackHeaderBox() {
+        for (Box box : boxes) {
+            if (box instanceof TrackHeaderBox) {
+                return (TrackHeaderBox) box;
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Gets the SampleTableBox at mdia/minf/stbl if existing.
+     *
+     * @return the SampleTableBox or <code>null</code>
+     */
+    public SampleTableBox getSampleTableBox() {
+        MediaBox mdia = getMediaBox();
+        if (mdia != null) {
+            MediaInformationBox minf = mdia.getMediaInformationBox();
+            if (minf != null) {
+                return minf.getSampleTableBox();
+            }
+        }
+        return null;
+
+    }
+
+
+    public MediaBox getMediaBox() {
+        for (Box box : boxes) {
+            if (box instanceof MediaBox) {
+                return (MediaBox) box;
+            }
+        }
+        return null;
+    }
+
+}
diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/.svn/text-base/TrackHeaderBox.java.svn-base b/isoparser/src/main/java/com/coremedia/iso/boxes/.svn/text-base/TrackHeaderBox.java.svn-base
new file mode 100644
index 0000000..8816bb9
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/.svn/text-base/TrackHeaderBox.java.svn-base
@@ -0,0 +1,249 @@
+/*  
+ * Copyright 2008 CoreMedia AG, Hamburg
+ *
+ * Licensed under the Apache License, Version 2.0 (the License); 
+ * you may not use this file except in compliance with the License. 
+ * You may obtain a copy of the License at 
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0 
+ * 
+ * Unless required by applicable law or agreed to in writing, software 
+ * distributed under the License is distributed on an AS IS BASIS, 
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+ * See the License for the specific language governing permissions and 
+ * limitations under the License. 
+ */
+
+package com.coremedia.iso.boxes;
+
+
+import com.coremedia.iso.IsoTypeReader;
+import com.coremedia.iso.IsoTypeWriter;
+import com.googlecode.mp4parser.AbstractFullBox;
+
+import java.nio.ByteBuffer;
+
+/**
+ * This box specifies the characteristics of a single track. Exactly one Track Header Box is contained in a track.<br>
+ * In the absence of an edit list, the presentation of a track starts at the beginning of the overall presentation. An
+ * empty edit is used to offset the start time of a track. <br>
+ * The default value of the track header flags for media tracks is 7 (track_enabled, track_in_movie,
+ * track_in_preview). If in a presentation all tracks have neither track_in_movie nor track_in_preview set, then all
+ * tracks shall be treated as if both flags were set on all tracks. Hint tracks should have the track header flags set
+ * to 0, so that they are ignored for local playback and preview.
+ */
+public class TrackHeaderBox extends AbstractFullBox {
+
+    public static final String TYPE = "tkhd";
+
+    private long creationTime;
+    private long modificationTime;
+    private long trackId;
+    private long duration;
+    private int layer;
+    private int alternateGroup;
+    private float volume;
+    private long[] matrix = new long[]{0x00010000, 0, 0, 0, 0x00010000, 0, 0, 0, 0x40000000};
+    private double width;
+    private double height;
+
+
+    public TrackHeaderBox() {
+        super(TYPE);
+
+    }
+
+    public long getCreationTime() {
+        return creationTime;
+    }
+
+    public long getModificationTime() {
+        return modificationTime;
+    }
+
+    public long getTrackId() {
+        return trackId;
+    }
+
+    public long getDuration() {
+        return duration;
+    }
+
+    public int getLayer() {
+        return layer;
+    }
+
+    public int getAlternateGroup() {
+        return alternateGroup;
+    }
+
+    public float getVolume() {
+        return volume;
+    }
+
+    public long[] getMatrix() {
+        return matrix;
+    }
+
+    public double getWidth() {
+        return width;
+    }
+
+    public double getHeight() {
+        return height;
+    }
+
+    protected long getContentSize() {
+        long contentSize = 4;
+        if (getVersion() == 1) {
+            contentSize += 32;
+        } else {
+            contentSize += 20;
+        }
+        contentSize += 60;
+        return contentSize;
+    }
+
+    @Override
+    public void _parseDetails(ByteBuffer content) {
+        parseVersionAndFlags(content);
+        if (getVersion() == 1) {
+            creationTime = IsoTypeReader.readUInt64(content);
+            modificationTime = IsoTypeReader.readUInt64(content);
+            trackId = IsoTypeReader.readUInt32(content);
+            IsoTypeReader.readUInt32(content);
+            duration = IsoTypeReader.readUInt64(content);
+        } else {
+            creationTime = IsoTypeReader.readUInt32(content);
+            modificationTime = IsoTypeReader.readUInt32(content);
+            trackId = IsoTypeReader.readUInt32(content);
+            IsoTypeReader.readUInt32(content);
+            duration = IsoTypeReader.readUInt32(content);
+        } // 196
+        IsoTypeReader.readUInt32(content);
+        IsoTypeReader.readUInt32(content);
+        layer = IsoTypeReader.readUInt16(content);    // 204
+        alternateGroup = IsoTypeReader.readUInt16(content);
+        volume = IsoTypeReader.readFixedPoint88(content);
+        IsoTypeReader.readUInt16(content);     // 212
+        matrix = new long[9];
+        for (int i = 0; i < 9; i++) {
+            matrix[i] = IsoTypeReader.readUInt32(content);
+        }
+        width = IsoTypeReader.readFixedPoint1616(content);    // 248
+        height = IsoTypeReader.readFixedPoint1616(content);
+    }
+
+    public void getContent(ByteBuffer byteBuffer) {
+        writeVersionAndFlags(byteBuffer);
+        if (getVersion() == 1) {
+            IsoTypeWriter.writeUInt64(byteBuffer, creationTime);
+            IsoTypeWriter.writeUInt64(byteBuffer, modificationTime);
+            IsoTypeWriter.writeUInt32(byteBuffer, trackId);
+            IsoTypeWriter.writeUInt32(byteBuffer, 0);
+            IsoTypeWriter.writeUInt64(byteBuffer, duration);
+        } else {
+            IsoTypeWriter.writeUInt32(byteBuffer, creationTime);
+            IsoTypeWriter.writeUInt32(byteBuffer, modificationTime);
+            IsoTypeWriter.writeUInt32(byteBuffer, trackId);
+            IsoTypeWriter.writeUInt32(byteBuffer, 0);
+            IsoTypeWriter.writeUInt32(byteBuffer, duration);
+        } // 196
+        IsoTypeWriter.writeUInt32(byteBuffer, 0);
+        IsoTypeWriter.writeUInt32(byteBuffer, 0);
+        IsoTypeWriter.writeUInt16(byteBuffer, layer);
+        IsoTypeWriter.writeUInt16(byteBuffer, alternateGroup);
+        IsoTypeWriter.writeFixedPont88(byteBuffer, volume);
+        IsoTypeWriter.writeUInt16(byteBuffer, 0);
+        for (int i = 0; i < 9; i++) {
+            IsoTypeWriter.writeUInt32(byteBuffer, matrix[i]);
+        }
+        IsoTypeWriter.writeFixedPont1616(byteBuffer, width);
+        IsoTypeWriter.writeFixedPont1616(byteBuffer, height);
+    }
+
+    public String toString() {
+        StringBuilder result = new StringBuilder();
+        result.append("TrackHeaderBox[");
+        result.append("creationTime=").append(getCreationTime());
+        result.append(";");
+        result.append("modificationTime=").append(getModificationTime());
+        result.append(";");
+        result.append("trackId=").append(getTrackId());
+        result.append(";");
+        result.append("duration=").append(getDuration());
+        result.append(";");
+        result.append("layer=").append(getLayer());
+        result.append(";");
+        result.append("alternateGroup=").append(getAlternateGroup());
+        result.append(";");
+        result.append("volume=").append(getVolume());
+        for (int i = 0; i < matrix.length; i++) {
+            result.append(";");
+            result.append("matrix").append(i).append("=").append(matrix[i]);
+        }
+        result.append(";");
+        result.append("width=").append(getWidth());
+        result.append(";");
+        result.append("height=").append(getHeight());
+        result.append("]");
+        return result.toString();
+    }
+
+    public void setCreationTime(long creationTime) {
+        this.creationTime = creationTime;
+    }
+
+    public void setModificationTime(long modificationTime) {
+        this.modificationTime = modificationTime;
+    }
+
+    public void setTrackId(long trackId) {
+        this.trackId = trackId;
+    }
+
+    public void setDuration(long duration) {
+        this.duration = duration;
+    }
+
+    public void setLayer(int layer) {
+        this.layer = layer;
+    }
+
+    public void setAlternateGroup(int alternateGroup) {
+        this.alternateGroup = alternateGroup;
+    }
+
+    public void setVolume(float volume) {
+        this.volume = volume;
+    }
+
+    public void setMatrix(long[] matrix) {
+        this.matrix = matrix;
+    }
+
+    public void setWidth(double width) {
+        this.width = width;
+    }
+
+    public void setHeight(double height) {
+        this.height = height;
+    }
+
+
+    public boolean isEnabled() {
+        return (getFlags() & 1) > 0;
+    }
+
+    public boolean isInMovie() {
+        return (getFlags() & 2) > 0;
+    }
+
+    public boolean isInPreview() {
+        return (getFlags() & 4) > 0;
+    }
+
+    public boolean isInPoster() {
+        return (getFlags() & 8) > 0;
+    }
+}
diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/.svn/text-base/TrackReferenceBox.java.svn-base b/isoparser/src/main/java/com/coremedia/iso/boxes/.svn/text-base/TrackReferenceBox.java.svn-base
new file mode 100644
index 0000000..1b4a7fb
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/.svn/text-base/TrackReferenceBox.java.svn-base
@@ -0,0 +1,41 @@
+/*  
+ * Copyright 2008 CoreMedia AG, Hamburg
+ *
+ * Licensed under the Apache License, Version 2.0 (the License); 
+ * you may not use this file except in compliance with the License. 
+ * You may obtain a copy of the License at 
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0 
+ * 
+ * Unless required by applicable law or agreed to in writing, software 
+ * distributed under the License is distributed on an AS IS BASIS, 
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+ * See the License for the specific language governing permissions and 
+ * limitations under the License. 
+ */
+
+package com.coremedia.iso.boxes;
+
+import com.googlecode.mp4parser.AbstractContainerBox;
+
+/**
+ * <code>
+ * Box Type: 'tref'<br>
+ * Container: {@link TrackBox} ('trak')<br>
+ * Mandatory: No<br>
+ * Quantity: Zero or one<br><br>
+ * </code>
+ * This box provides a reference from the containing track to another track in the presentation. These references
+ * are typed. A 'hint' reference links from the containing hint track to the media data that it hints. A content
+ * description reference 'cdsc' links a descriptive or metadata track to the content which it describes.
+ * Exactly one Track Reference Box can be contained within the Track Box.
+ * If this box is not present, the track is not referencing any other track in any way. The reference array is sized
+ * to fill the reference type box.
+ */
+public class TrackReferenceBox extends AbstractContainerBox {
+    public static final String TYPE = "tref";
+
+    public TrackReferenceBox() {
+        super(TYPE);
+    }
+}
diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/.svn/text-base/TrackReferenceTypeBox.java.svn-base b/isoparser/src/main/java/com/coremedia/iso/boxes/.svn/text-base/TrackReferenceTypeBox.java.svn-base
new file mode 100644
index 0000000..297932d
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/.svn/text-base/TrackReferenceTypeBox.java.svn-base
@@ -0,0 +1,76 @@
+/*  
+ * Copyright 2008 CoreMedia AG, Hamburg
+ *
+ * Licensed under the Apache License, Version 2.0 (the License); 
+ * you may not use this file except in compliance with the License. 
+ * You may obtain a copy of the License at 
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0 
+ * 
+ * Unless required by applicable law or agreed to in writing, software 
+ * distributed under the License is distributed on an AS IS BASIS, 
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+ * See the License for the specific language governing permissions and 
+ * limitations under the License. 
+ */
+
+package com.coremedia.iso.boxes;
+
+import com.coremedia.iso.IsoTypeReader;
+import com.coremedia.iso.IsoTypeWriter;
+import com.googlecode.mp4parser.AbstractBox;
+
+import java.nio.ByteBuffer;
+
+/**
+ * Contains a reference to a track. The type of the box gives the kind of reference.
+ */
+public class TrackReferenceTypeBox extends AbstractBox {
+
+    public static final String TYPE1 = "hint";
+    public static final String TYPE2 = "cdsc";
+
+    private long[] trackIds;
+
+    public TrackReferenceTypeBox(String type) {
+        super(type);
+    }
+
+    public long[] getTrackIds() {
+        return trackIds;
+    }
+
+    @Override
+    public void _parseDetails(ByteBuffer content) {
+        int count = (int) (content.remaining() / 4);
+        trackIds = new long[count];
+        for (int i = 0; i < count; i++) {
+            trackIds[i] = IsoTypeReader.readUInt32(content);
+        }
+    }
+
+    @Override
+    protected void getContent(ByteBuffer byteBuffer) {
+        for (long trackId : trackIds) {
+            IsoTypeWriter.writeUInt32(byteBuffer, trackId);
+        }
+    }
+
+
+    protected long getContentSize() {
+        return trackIds.length * 4;
+    }
+
+    public String toString() {
+        StringBuilder buffer = new StringBuilder();
+        buffer.append("TrackReferenceTypeBox[type=").append(getType());
+        for (int i = 0; i < trackIds.length; i++) {
+            buffer.append(";trackId");
+            buffer.append(i);
+            buffer.append("=");
+            buffer.append(trackIds[i]);
+        }
+        buffer.append("]");
+        return buffer.toString();
+    }
+}
diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/.svn/text-base/UnknownBox.java.svn-base b/isoparser/src/main/java/com/coremedia/iso/boxes/.svn/text-base/UnknownBox.java.svn-base
new file mode 100644
index 0000000..f76481c
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/.svn/text-base/UnknownBox.java.svn-base
@@ -0,0 +1,59 @@
+/*  
+ * Copyright 2008 CoreMedia AG, Hamburg
+ *
+ * Licensed under the Apache License, Version 2.0 (the License); 
+ * you may not use this file except in compliance with the License. 
+ * You may obtain a copy of the License at 
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0 
+ * 
+ * Unless required by applicable law or agreed to in writing, software 
+ * distributed under the License is distributed on an AS IS BASIS, 
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+ * See the License for the specific language governing permissions and 
+ * limitations under the License. 
+ */
+
+package com.coremedia.iso.boxes;
+
+
+import com.googlecode.mp4parser.AbstractBox;
+
+import java.nio.ByteBuffer;
+
+/**
+ * A box unknown to the ISO Parser. If there is no specific Box implementation for a Box this <code>UnknownBox</code>
+ * will just hold the box's data.
+ */
+public class UnknownBox extends AbstractBox {
+    ByteBuffer data;
+
+    public UnknownBox(String type) {
+        super(type);
+    }
+
+    @Override
+    protected long getContentSize() {
+        return data.limit();
+    }
+
+    @Override
+    public void _parseDetails(ByteBuffer content) {
+        data = content;
+        content.position(content.position() + content.remaining());
+    }
+
+    @Override
+    protected void getContent(ByteBuffer byteBuffer) {
+        data.rewind();
+        byteBuffer.put(data);
+    }
+
+    public ByteBuffer getData() {
+        return data;
+    }
+
+    public void setData(ByteBuffer data) {
+        this.data = data;
+    }
+}
diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/.svn/text-base/UserBox.java.svn-base b/isoparser/src/main/java/com/coremedia/iso/boxes/.svn/text-base/UserBox.java.svn-base
new file mode 100644
index 0000000..db0e741
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/.svn/text-base/UserBox.java.svn-base
@@ -0,0 +1,64 @@
+/*  
+ * Copyright 2008 CoreMedia AG, Hamburg
+ *
+ * Licensed under the Apache License, Version 2.0 (the License); 
+ * you may not use this file except in compliance with the License. 
+ * You may obtain a copy of the License at 
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0 
+ * 
+ * Unless required by applicable law or agreed to in writing, software 
+ * distributed under the License is distributed on an AS IS BASIS, 
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+ * See the License for the specific language governing permissions and 
+ * limitations under the License. 
+ */
+
+package com.coremedia.iso.boxes;
+
+import com.googlecode.mp4parser.AbstractBox;
+
+import java.nio.ByteBuffer;
+
+/**
+ * A user specifc box. See ISO/IEC 14496-12 for details.
+ */
+public class UserBox extends AbstractBox {
+    byte[] data;
+    public static final String TYPE = "uuid";
+
+    public UserBox(byte[] userType) {
+        super(TYPE, userType);
+    }
+
+
+    protected long getContentSize() {
+        return data.length;
+    }
+
+    public String toString() {
+        return "UserBox[type=" + (getType()) +
+                ";userType=" + new String(getUserType()) +
+                ";contentLength=" + data.length + "]";
+    }
+
+
+    public byte[] getData() {
+        return data;
+    }
+
+    public void setData(byte[] data) {
+        this.data = data;
+    }
+
+    @Override
+    public void _parseDetails(ByteBuffer content) {
+        data = new byte[content.remaining()];
+        content.get(data);
+    }
+
+    @Override
+    protected void getContent(ByteBuffer byteBuffer) {
+        byteBuffer.put(data);
+    }
+}
diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/.svn/text-base/UserDataBox.java.svn-base b/isoparser/src/main/java/com/coremedia/iso/boxes/.svn/text-base/UserDataBox.java.svn-base
new file mode 100644
index 0000000..65c5808
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/.svn/text-base/UserDataBox.java.svn-base
@@ -0,0 +1,59 @@
+/*  
+ * Copyright 2008 CoreMedia AG, Hamburg
+ *
+ * Licensed under the Apache License, Version 2.0 (the License); 
+ * you may not use this file except in compliance with the License. 
+ * You may obtain a copy of the License at 
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0 
+ * 
+ * Unless required by applicable law or agreed to in writing, software 
+ * distributed under the License is distributed on an AS IS BASIS, 
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+ * See the License for the specific language governing permissions and 
+ * limitations under the License. 
+ */
+
+package com.coremedia.iso.boxes;
+
+import com.coremedia.iso.BoxParser;
+import com.googlecode.mp4parser.AbstractContainerBox;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.nio.channels.ReadableByteChannel;
+
+/**
+ * This box contains objects that declare user information about the containing box and its data (presentation or
+ * track).<br>
+ * The User Data Box is a container box for informative user-data. This user data is formatted as a set of boxes
+ * with more specific box types, which declare more precisely their content
+ */
+public class UserDataBox extends AbstractContainerBox {
+    public static final String TYPE = "udta";
+
+    @Override
+    protected long getContentSize() {
+        return super.getContentSize();    //To change body of overridden methods use File | Settings | File Templates.
+    }
+
+    @Override
+    public void parse(ReadableByteChannel readableByteChannel, ByteBuffer header, long contentSize, BoxParser boxParser) throws IOException {
+        super.parse(readableByteChannel, header, contentSize, boxParser);    //To change body of overridden methods use File | Settings | File Templates.
+    }
+
+    @Override
+    public void _parseDetails(ByteBuffer content) {
+        super._parseDetails(content);    //To change body of overridden methods use File | Settings | File Templates.
+    }
+
+    @Override
+    protected void getContent(ByteBuffer byteBuffer) {
+        super.getContent(byteBuffer);    //To change body of overridden methods use File | Settings | File Templates.
+    }
+
+    public UserDataBox() {
+        super(TYPE);
+    }
+
+}
diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/.svn/text-base/VideoMediaHeaderBox.java.svn-base b/isoparser/src/main/java/com/coremedia/iso/boxes/.svn/text-base/VideoMediaHeaderBox.java.svn-base
new file mode 100644
index 0000000..421a67d
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/.svn/text-base/VideoMediaHeaderBox.java.svn-base
@@ -0,0 +1,81 @@
+/*  
+ * Copyright 2008 CoreMedia AG, Hamburg
+ *
+ * Licensed under the Apache License, Version 2.0 (the License); 
+ * you may not use this file except in compliance with the License. 
+ * You may obtain a copy of the License at 
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0 
+ * 
+ * Unless required by applicable law or agreed to in writing, software 
+ * distributed under the License is distributed on an AS IS BASIS, 
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+ * See the License for the specific language governing permissions and 
+ * limitations under the License. 
+ */
+
+package com.coremedia.iso.boxes;
+
+import com.coremedia.iso.IsoTypeReader;
+import com.coremedia.iso.IsoTypeWriter;
+
+import java.nio.ByteBuffer;
+
+/**
+ * The video media header contains general presentation information, independent of the coding, for video
+ * media. Note that the flags field has the value 1.
+ */
+public class VideoMediaHeaderBox extends AbstractMediaHeaderBox {
+    private int graphicsmode = 0;
+    private int[] opcolor = new int[]{0, 0, 0};
+    public static final String TYPE = "vmhd";
+
+    public VideoMediaHeaderBox() {
+        super(TYPE);
+        setFlags(1); // 1 is default.
+    }
+
+    public int getGraphicsmode() {
+        return graphicsmode;
+    }
+
+    public int[] getOpcolor() {
+        return opcolor;
+    }
+
+    protected long getContentSize() {
+        return 12;
+    }
+
+
+    @Override
+    public void _parseDetails(ByteBuffer content) {
+        parseVersionAndFlags(content);
+        graphicsmode = IsoTypeReader.readUInt16(content);
+        opcolor = new int[3];
+        for (int i = 0; i < 3; i++) {
+            opcolor[i] = IsoTypeReader.readUInt16(content);
+        }
+    }
+
+    @Override
+    protected void getContent(ByteBuffer byteBuffer) {
+        writeVersionAndFlags(byteBuffer);
+        IsoTypeWriter.writeUInt16(byteBuffer, graphicsmode);
+        for (int anOpcolor : opcolor) {
+            IsoTypeWriter.writeUInt16(byteBuffer, anOpcolor);
+        }
+    }
+
+    public String toString() {
+        return "VideoMediaHeaderBox[graphicsmode=" + getGraphicsmode() + ";opcolor0=" + getOpcolor()[0] + ";opcolor1=" + getOpcolor()[1] + ";opcolor2=" + getOpcolor()[2] + "]";
+    }
+
+    public void setOpcolor(int[] opcolor) {
+        this.opcolor = opcolor;
+    }
+
+    public void setGraphicsmode(int graphicsmode) {
+        this.graphicsmode = graphicsmode;
+    }
+}
diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/.svn/text-base/WriteListener.java.svn-base b/isoparser/src/main/java/com/coremedia/iso/boxes/.svn/text-base/WriteListener.java.svn-base
new file mode 100644
index 0000000..dc22d52
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/.svn/text-base/WriteListener.java.svn-base
@@ -0,0 +1,10 @@
+package com.coremedia.iso.boxes;
+
+/**
+ * The <class>WriteListener</class> is used to get the offset of
+ * a box before writing the box. This can be used if a box written
+ * later needs an offset.
+ */
+public interface WriteListener {
+    public void beforeWrite(long offset);
+}
diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/.svn/text-base/XmlBox.java.svn-base b/isoparser/src/main/java/com/coremedia/iso/boxes/.svn/text-base/XmlBox.java.svn-base
new file mode 100644
index 0000000..43727e1
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/.svn/text-base/XmlBox.java.svn-base
@@ -0,0 +1,51 @@
+package com.coremedia.iso.boxes;
+
+import com.coremedia.iso.IsoTypeReader;
+import com.coremedia.iso.Utf8;
+import com.googlecode.mp4parser.AbstractFullBox;
+
+import java.nio.ByteBuffer;
+
+/**
+ *
+ */
+public class XmlBox extends AbstractFullBox {
+    String xml = "";
+    public static final String TYPE = "xml ";
+
+    public XmlBox() {
+        super(TYPE);
+    }
+
+    public String getXml() {
+        return xml;
+    }
+
+    public void setXml(String xml) {
+        this.xml = xml;
+    }
+
+    @Override
+    protected long getContentSize() {
+        return 4 + Utf8.utf8StringLengthInBytes(xml);
+    }
+
+    @Override
+    public void _parseDetails(ByteBuffer content) {
+        parseVersionAndFlags(content);
+        xml = IsoTypeReader.readString(content, content.remaining());
+    }
+
+    @Override
+    protected void getContent(ByteBuffer byteBuffer) {
+        writeVersionAndFlags(byteBuffer);
+        byteBuffer.put(Utf8.convert(xml));
+    }
+
+    @Override
+    public String toString() {
+        return "XmlBox{" +
+                "xml='" + xml + '\'' +
+                '}';
+    }
+}
diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/.svn/text-base/odf-boxes.zip.svn-base b/isoparser/src/main/java/com/coremedia/iso/boxes/.svn/text-base/odf-boxes.zip.svn-base
new file mode 100644
index 0000000..04e0e5e
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/.svn/text-base/odf-boxes.zip.svn-base
Binary files differ
diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/.svn/text-base/rtp-boxes.zip.svn-base b/isoparser/src/main/java/com/coremedia/iso/boxes/.svn/text-base/rtp-boxes.zip.svn-base
new file mode 100644
index 0000000..be1a167
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/.svn/text-base/rtp-boxes.zip.svn-base
Binary files differ
diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/AbstractMediaHeaderBox.java b/isoparser/src/main/java/com/coremedia/iso/boxes/AbstractMediaHeaderBox.java
new file mode 100644
index 0000000..cc141ae
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/AbstractMediaHeaderBox.java
@@ -0,0 +1,29 @@
+/*
+ * Copyright 2011 Sebastian Annies, Hamburg, Germany
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.coremedia.iso.boxes;
+
+import com.googlecode.mp4parser.AbstractFullBox;
+
+/**
+ * A common superclass for all MediaInformationHeaderBoxes. E.g.
+ * VideoMediaHeaderBox, SoundMediaHeaderBox & HintMediaHeaderBox
+ */
+public abstract class AbstractMediaHeaderBox extends AbstractFullBox {
+    protected AbstractMediaHeaderBox(String type) {
+        super(type);
+    }
+}
diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/AlbumBox.java b/isoparser/src/main/java/com/coremedia/iso/boxes/AlbumBox.java
new file mode 100644
index 0000000..d666806
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/AlbumBox.java
@@ -0,0 +1,112 @@
+/*  
+ * Copyright 2008 CoreMedia AG, Hamburg
+ *
+ * Licensed under the Apache License, Version 2.0 (the License); 
+ * you may not use this file except in compliance with the License. 
+ * You may obtain a copy of the License at 
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0 
+ * 
+ * Unless required by applicable law or agreed to in writing, software 
+ * distributed under the License is distributed on an AS IS BASIS, 
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+ * See the License for the specific language governing permissions and 
+ * limitations under the License. 
+ */
+
+package com.coremedia.iso.boxes;
+
+import com.coremedia.iso.IsoTypeReader;
+import com.coremedia.iso.IsoTypeWriter;
+import com.coremedia.iso.Utf8;
+import com.googlecode.mp4parser.AbstractFullBox;
+
+import java.nio.ByteBuffer;
+
+/**
+ * Meta information in a 'udta' box about a track.
+ * Defined in 3GPP 26.244.
+ *
+ * @see com.coremedia.iso.boxes.UserDataBox
+ */
+public class AlbumBox extends AbstractFullBox {
+    public static final String TYPE = "albm";
+
+    private String language;
+    private String albumTitle;
+    private int trackNumber;
+
+    public AlbumBox() {
+        super(TYPE);
+    }
+
+    /**
+     * Declares the language code for the {@link #getAlbumTitle()} return value. See ISO 639-2/T for the set of three
+     * character codes.Each character is packed as the difference between its ASCII value and 0x60. The code is
+     * confined to being three lower-case letters, so these values are strictly positive.
+     *
+     * @return the language code
+     */
+    public String getLanguage() {
+        return language;
+    }
+
+    public String getAlbumTitle() {
+        return albumTitle;
+    }
+
+    public int getTrackNumber() {
+        return trackNumber;
+    }
+
+    public void setLanguage(String language) {
+        this.language = language;
+    }
+
+    public void setAlbumTitle(String albumTitle) {
+        this.albumTitle = albumTitle;
+    }
+
+    public void setTrackNumber(int trackNumber) {
+        this.trackNumber = trackNumber;
+    }
+
+    protected long getContentSize() {
+        return 6 + Utf8.utf8StringLengthInBytes(albumTitle) + 1 + (trackNumber == -1 ? 0 : 1);
+    }
+
+    @Override
+    public void _parseDetails(ByteBuffer content) {
+        parseVersionAndFlags(content);
+        language = IsoTypeReader.readIso639(content);
+        albumTitle = IsoTypeReader.readString(content);
+
+        if (content.remaining() > 0) {
+            trackNumber = IsoTypeReader.readUInt8(content);
+        } else {
+            trackNumber = -1;
+        }
+    }
+
+    @Override
+    protected void getContent(ByteBuffer byteBuffer) {
+        writeVersionAndFlags(byteBuffer);
+        IsoTypeWriter.writeIso639(byteBuffer, language);
+        byteBuffer.put(Utf8.convert(albumTitle));
+        byteBuffer.put((byte) 0);
+        if (trackNumber != -1) {
+            IsoTypeWriter.writeUInt8(byteBuffer, trackNumber);
+        }
+    }
+
+    public String toString() {
+        StringBuilder buffer = new StringBuilder();
+        buffer.append("AlbumBox[language=").append(getLanguage()).append(";");
+        buffer.append("albumTitle=").append(getAlbumTitle());
+        if (trackNumber >= 0) {
+            buffer.append(";trackNumber=").append(getTrackNumber());
+        }
+        buffer.append("]");
+        return buffer.toString();
+    }
+}
diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/AuthorBox.java b/isoparser/src/main/java/com/coremedia/iso/boxes/AuthorBox.java
new file mode 100644
index 0000000..672cde2
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/AuthorBox.java
@@ -0,0 +1,94 @@
+/*  
+ * Copyright 2008 CoreMedia AG, Hamburg
+ *
+ * Licensed under the Apache License, Version 2.0 (the License); 
+ * you may not use this file except in compliance with the License. 
+ * You may obtain a copy of the License at 
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0 
+ * 
+ * Unless required by applicable law or agreed to in writing, software 
+ * distributed under the License is distributed on an AS IS BASIS, 
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+ * See the License for the specific language governing permissions and 
+ * limitations under the License. 
+ */
+
+package com.coremedia.iso.boxes;
+
+
+import com.coremedia.iso.IsoTypeReader;
+import com.coremedia.iso.IsoTypeWriter;
+import com.coremedia.iso.Utf8;
+import com.googlecode.mp4parser.AbstractFullBox;
+
+import java.nio.ByteBuffer;
+
+/**
+ * Meta information in a 'udta' box about a track.
+ * Defined in 3GPP 26.244.
+ *
+ * @see com.coremedia.iso.boxes.UserDataBox
+ */
+public class AuthorBox extends AbstractFullBox {
+    public static final String TYPE = "auth";
+
+    private String language;
+    private String author;
+
+    public AuthorBox() {
+        super(TYPE);
+    }
+
+    /**
+     * Declares the language code for the {@link #getAuthor()} return value. See ISO 639-2/T for the set of three
+     * character codes.Each character is packed as the difference between its ASCII value and 0x60. The code is
+     * confined to being three lower-case letters, so these values are strictly positive.
+     *
+     * @return the language code
+     */
+    public String getLanguage() {
+        return language;
+    }
+
+    /**
+     * Author information.
+     *
+     * @return the author
+     */
+    public String getAuthor() {
+        return author;
+    }
+
+    public void setLanguage(String language) {
+        this.language = language;
+    }
+
+    public void setAuthor(String author) {
+        this.author = author;
+    }
+
+    protected long getContentSize() {
+        return 7 + Utf8.utf8StringLengthInBytes(author);
+    }
+
+    @Override
+    public void _parseDetails(ByteBuffer content) {
+        parseVersionAndFlags(content);
+        language = IsoTypeReader.readIso639(content);
+        author = IsoTypeReader.readString(content);
+    }
+
+    @Override
+    protected void getContent(ByteBuffer byteBuffer) {
+        writeVersionAndFlags(byteBuffer);
+        IsoTypeWriter.writeIso639(byteBuffer, language);
+        byteBuffer.put(Utf8.convert(author));
+        byteBuffer.put((byte) 0);
+    }
+
+
+    public String toString() {
+        return "AuthorBox[language=" + getLanguage() + ";author=" + getAuthor() + "]";
+    }
+}
diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/BitRateBox.java b/isoparser/src/main/java/com/coremedia/iso/boxes/BitRateBox.java
new file mode 100644
index 0000000..6c4b0e6
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/BitRateBox.java
@@ -0,0 +1,91 @@
+/*  
+ * Copyright 2008 CoreMedia AG, Hamburg
+ *
+ * Licensed under the Apache License, Version 2.0 (the License); 
+ * you may not use this file except in compliance with the License. 
+ * You may obtain a copy of the License at 
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0 
+ * 
+ * Unless required by applicable law or agreed to in writing, software 
+ * distributed under the License is distributed on an AS IS BASIS, 
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+ * See the License for the specific language governing permissions and 
+ * limitations under the License. 
+ */
+
+package com.coremedia.iso.boxes;
+
+import com.coremedia.iso.IsoTypeReader;
+import com.coremedia.iso.IsoTypeWriter;
+import com.googlecode.mp4parser.AbstractBox;
+
+import java.nio.ByteBuffer;
+
+/**
+ * <code>class BitRateBox extends Box('btrt') {<br/>
+ * unsigned int(32) bufferSizeDB;<br/>
+ * // gives the size of the decoding buffer for<br/>
+ * // the elementary stream in bytes.<br/>
+ * unsigned int(32) maxBitrate;<br/>
+ * // gives the maximum rate in bits/second <br/>
+ * // over any window of one second.<br/>
+ * unsigned int(32) avgBitrate;<br/>
+ * // avgBitrate gives the average rate in <br/>
+ * // bits/second over the entire presentation.<br/>
+ * }</code>
+ */
+
+public final class BitRateBox extends AbstractBox {
+    public static final String TYPE = "btrt";
+
+    private long bufferSizeDb;
+    private long maxBitrate;
+    private long avgBitrate;
+
+    public BitRateBox() {
+        super(TYPE);
+    }
+
+    protected long getContentSize() {
+        return 12;
+    }
+
+    @Override
+    public void _parseDetails(ByteBuffer content) {
+        bufferSizeDb = IsoTypeReader.readUInt32(content);
+        maxBitrate = IsoTypeReader.readUInt32(content);
+        avgBitrate = IsoTypeReader.readUInt32(content);
+    }
+
+    @Override
+    protected void getContent(ByteBuffer byteBuffer) {
+        IsoTypeWriter.writeUInt32(byteBuffer, bufferSizeDb);
+        IsoTypeWriter.writeUInt32(byteBuffer, maxBitrate);
+        IsoTypeWriter.writeUInt32(byteBuffer, avgBitrate);
+    }
+
+    public long getBufferSizeDb() {
+        return bufferSizeDb;
+    }
+
+    public void setBufferSizeDb(long bufferSizeDb) {
+        this.bufferSizeDb = bufferSizeDb;
+    }
+
+    public long getMaxBitrate() {
+        return maxBitrate;
+    }
+
+    public void setMaxBitrate(long maxBitrate) {
+        this.maxBitrate = maxBitrate;
+    }
+
+    public long getAvgBitrate() {
+        return avgBitrate;
+    }
+
+    public void setAvgBitrate(long avgBitrate) {
+        this.avgBitrate = avgBitrate;
+    }
+}
diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/Box.java b/isoparser/src/main/java/com/coremedia/iso/boxes/Box.java
new file mode 100644
index 0000000..f6ca302
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/Box.java
@@ -0,0 +1,51 @@
+/*  
+ * Copyright 2008 CoreMedia AG, Hamburg
+ *
+ * Licensed under the Apache License, Version 2.0 (the License); 
+ * you may not use this file except in compliance with the License. 
+ * You may obtain a copy of the License at 
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0 
+ * 
+ * Unless required by applicable law or agreed to in writing, software 
+ * distributed under the License is distributed on an AS IS BASIS, 
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+ * See the License for the specific language governing permissions and 
+ * limitations under the License. 
+ */
+
+package com.coremedia.iso.boxes;
+
+import com.coremedia.iso.BoxParser;
+import com.coremedia.iso.boxes.ContainerBox;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.nio.channels.ReadableByteChannel;
+import java.nio.channels.WritableByteChannel;
+
+/**
+ * Defines basic interaction possibilities for any ISO box. Each box has a parent box and a type.
+ */
+public interface Box {
+    ContainerBox getParent();
+
+    void setParent(ContainerBox parent);
+
+    long getSize();
+
+    /**
+     * The box's 4-cc type.
+     * @return the 4 character type of the box
+     */
+    String getType();
+
+    /**
+     * Writes the complete box - size | 4-cc | content - to the given <code>writableByteChannel</code>.
+     * @param writableByteChannel the box's sink
+     * @throws IOException in case of problems with the <code>Channel</code>
+     */
+    void getBox(WritableByteChannel writableByteChannel) throws IOException;
+
+    void parse(ReadableByteChannel readableByteChannel, ByteBuffer header, long contentSize, BoxParser boxParser) throws IOException;
+}
diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/ChunkOffset64BitBox.java b/isoparser/src/main/java/com/coremedia/iso/boxes/ChunkOffset64BitBox.java
new file mode 100755
index 0000000..f2340b9
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/ChunkOffset64BitBox.java
@@ -0,0 +1,51 @@
+package com.coremedia.iso.boxes;
+
+import com.coremedia.iso.IsoTypeReader;
+import com.coremedia.iso.IsoTypeWriter;
+
+import java.nio.ByteBuffer;
+
+import static com.googlecode.mp4parser.util.CastUtils.l2i;
+
+/**
+ * Abstract Chunk Offset Box
+ */
+public class ChunkOffset64BitBox extends ChunkOffsetBox {
+    public static final String TYPE = "co64";
+    private long[] chunkOffsets;
+
+    public ChunkOffset64BitBox() {
+        super(TYPE);
+    }
+
+    @Override
+    public long[] getChunkOffsets() {
+        return chunkOffsets;
+    }
+
+    @Override
+    protected long getContentSize() {
+        return 8 + 8 * chunkOffsets.length;
+    }
+
+    @Override
+    public void _parseDetails(ByteBuffer content) {
+        parseVersionAndFlags(content);
+        int entryCount = l2i(IsoTypeReader.readUInt32(content));
+        chunkOffsets = new long[entryCount];
+        for (int i = 0; i < entryCount; i++) {
+            chunkOffsets[i] = IsoTypeReader.readUInt64(content);
+        }
+    }
+
+    @Override
+    protected void getContent(ByteBuffer byteBuffer) {
+        writeVersionAndFlags(byteBuffer);
+        IsoTypeWriter.writeUInt32(byteBuffer, chunkOffsets.length);
+        for (long chunkOffset : chunkOffsets) {
+            IsoTypeWriter.writeUInt64(byteBuffer, chunkOffset);
+        }
+    }
+
+
+}
diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/ChunkOffsetBox.java b/isoparser/src/main/java/com/coremedia/iso/boxes/ChunkOffsetBox.java
new file mode 100755
index 0000000..01f5ae4
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/ChunkOffsetBox.java
@@ -0,0 +1,21 @@
+package com.coremedia.iso.boxes;
+
+import com.googlecode.mp4parser.AbstractFullBox;
+
+/**
+ * Abstract Chunk Offset Box
+ */
+public abstract class ChunkOffsetBox extends AbstractFullBox {
+
+    public ChunkOffsetBox(String type) {
+        super(type);
+    }
+
+    public abstract long[] getChunkOffsets();
+
+
+    public String toString() {
+        return this.getClass().getSimpleName() + "[entryCount=" + getChunkOffsets().length + "]";
+    }
+
+}
diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/ClassificationBox.java b/isoparser/src/main/java/com/coremedia/iso/boxes/ClassificationBox.java
new file mode 100644
index 0000000..a20feca
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/ClassificationBox.java
@@ -0,0 +1,110 @@
+/*  
+ * Copyright 2008 CoreMedia AG, Hamburg
+ *
+ * Licensed under the Apache License, Version 2.0 (the License); 
+ * you may not use this file except in compliance with the License. 
+ * You may obtain a copy of the License at 
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0 
+ * 
+ * Unless required by applicable law or agreed to in writing, software 
+ * distributed under the License is distributed on an AS IS BASIS, 
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+ * See the License for the specific language governing permissions and 
+ * limitations under the License. 
+ */
+
+package com.coremedia.iso.boxes;
+
+import com.coremedia.iso.IsoFile;
+import com.coremedia.iso.IsoTypeReader;
+import com.coremedia.iso.IsoTypeWriter;
+import com.coremedia.iso.Utf8;
+import com.googlecode.mp4parser.AbstractFullBox;
+
+import java.nio.ByteBuffer;
+
+/**
+ * Classification of the media according to 3GPP 26.244.
+ */
+public class ClassificationBox extends AbstractFullBox {
+    public static final String TYPE = "clsf";
+
+
+    private String classificationEntity;
+    private int classificationTableIndex;
+    private String language;
+    private String classificationInfo;
+
+    public ClassificationBox() {
+        super(TYPE);
+    }
+
+    public String getLanguage() {
+        return language;
+    }
+
+    public String getClassificationEntity() {
+        return classificationEntity;
+    }
+
+    public int getClassificationTableIndex() {
+        return classificationTableIndex;
+    }
+
+    public String getClassificationInfo() {
+        return classificationInfo;
+    }
+
+    public void setClassificationEntity(String classificationEntity) {
+        this.classificationEntity = classificationEntity;
+    }
+
+    public void setClassificationTableIndex(int classificationTableIndex) {
+        this.classificationTableIndex = classificationTableIndex;
+    }
+
+    public void setLanguage(String language) {
+        this.language = language;
+    }
+
+    public void setClassificationInfo(String classificationInfo) {
+        this.classificationInfo = classificationInfo;
+    }
+
+    protected long getContentSize() {
+        return 4 + 2 + 2 + Utf8.utf8StringLengthInBytes(classificationInfo) + 1;
+    }
+
+    @Override
+    public void _parseDetails(ByteBuffer content) {
+        parseVersionAndFlags(content);
+        byte[] cE = new byte[4];
+        content.get(cE);
+        classificationEntity = IsoFile.bytesToFourCC(cE);
+        classificationTableIndex = IsoTypeReader.readUInt16(content);
+        language = IsoTypeReader.readIso639(content);
+        classificationInfo = IsoTypeReader.readString(content);
+    }
+
+    @Override
+    protected void getContent(ByteBuffer byteBuffer) {
+        byteBuffer.put(IsoFile.fourCCtoBytes(classificationEntity));
+        IsoTypeWriter.writeUInt16(byteBuffer, classificationTableIndex);
+        IsoTypeWriter.writeIso639(byteBuffer, language);
+        byteBuffer.put(Utf8.convert(classificationInfo));
+        byteBuffer.put((byte) 0);
+    }
+
+
+    public String toString() {
+        StringBuilder buffer = new StringBuilder();
+        buffer.append("ClassificationBox[language=").append(getLanguage());
+        buffer.append("classificationEntity=").append(getClassificationEntity());
+        buffer.append(";classificationTableIndex=").append(getClassificationTableIndex());
+        buffer.append(";language=").append(getLanguage());
+        buffer.append(";classificationInfo=").append(getClassificationInfo());
+        buffer.append("]");
+        return buffer.toString();
+    }
+}
diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/CompositionShiftLeastGreatestAtom.java b/isoparser/src/main/java/com/coremedia/iso/boxes/CompositionShiftLeastGreatestAtom.java
new file mode 100644
index 0000000..3534b7f
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/CompositionShiftLeastGreatestAtom.java
@@ -0,0 +1,101 @@
+package com.coremedia.iso.boxes;
+
+import com.googlecode.mp4parser.AbstractFullBox;
+
+import java.nio.ByteBuffer;
+
+/**
+ * The optional composition shift least greatest atom summarizes the calculated
+ * minimum and maximum offsets between decode and composition time, as well as
+ * the start and end times, for all samples. This allows a reader to determine
+ * the minimum required time for decode to obtain proper presentation order without
+ * needing to scan the sample table for the range of offsets. The type of the
+ * composition shift least greatest atom is ‘cslg’.
+ */
+public class CompositionShiftLeastGreatestAtom extends AbstractFullBox {
+    public CompositionShiftLeastGreatestAtom() {
+        super("cslg");
+    }
+
+    // A 32-bit unsigned integer that specifies the calculated value.
+    int compositionOffsetToDisplayOffsetShift;
+
+    // A 32-bit signed integer that specifies the calculated value.
+    int leastDisplayOffset;
+
+    // A 32-bit signed integer that specifies the calculated value.
+    int greatestDisplayOffset;
+
+    //A 32-bit signed integer that specifies the calculated value.
+    int displayStartTime;
+
+    //A 32-bit signed integer that specifies the calculated value.
+    int displayEndTime;
+
+
+    @Override
+    protected long getContentSize() {
+        return 24;
+    }
+
+    @Override
+    public void _parseDetails(ByteBuffer content) {
+        parseVersionAndFlags(content);
+        compositionOffsetToDisplayOffsetShift = content.getInt();
+        leastDisplayOffset = content.getInt();
+        greatestDisplayOffset = content.getInt();
+        displayStartTime = content.getInt();
+        displayEndTime = content.getInt();
+    }
+
+    @Override
+    protected void getContent(ByteBuffer byteBuffer) {
+        writeVersionAndFlags(byteBuffer);
+        byteBuffer.putInt(compositionOffsetToDisplayOffsetShift);
+        byteBuffer.putInt(leastDisplayOffset);
+        byteBuffer.putInt(greatestDisplayOffset);
+        byteBuffer.putInt(displayStartTime);
+        byteBuffer.putInt(displayEndTime);
+    }
+
+
+    public int getCompositionOffsetToDisplayOffsetShift() {
+        return compositionOffsetToDisplayOffsetShift;
+    }
+
+    public void setCompositionOffsetToDisplayOffsetShift(int compositionOffsetToDisplayOffsetShift) {
+        this.compositionOffsetToDisplayOffsetShift = compositionOffsetToDisplayOffsetShift;
+    }
+
+    public int getLeastDisplayOffset() {
+        return leastDisplayOffset;
+    }
+
+    public void setLeastDisplayOffset(int leastDisplayOffset) {
+        this.leastDisplayOffset = leastDisplayOffset;
+    }
+
+    public int getGreatestDisplayOffset() {
+        return greatestDisplayOffset;
+    }
+
+    public void setGreatestDisplayOffset(int greatestDisplayOffset) {
+        this.greatestDisplayOffset = greatestDisplayOffset;
+    }
+
+    public int getDisplayStartTime() {
+        return displayStartTime;
+    }
+
+    public void setDisplayStartTime(int displayStartTime) {
+        this.displayStartTime = displayStartTime;
+    }
+
+    public int getDisplayEndTime() {
+        return displayEndTime;
+    }
+
+    public void setDisplayEndTime(int displayEndTime) {
+        this.displayEndTime = displayEndTime;
+    }
+}
diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/CompositionTimeToSample.java b/isoparser/src/main/java/com/coremedia/iso/boxes/CompositionTimeToSample.java
new file mode 100644
index 0000000..411bfe9
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/CompositionTimeToSample.java
@@ -0,0 +1,150 @@
+package com.coremedia.iso.boxes;
+
+import com.coremedia.iso.IsoTypeReader;
+import com.coremedia.iso.IsoTypeWriter;
+import com.googlecode.mp4parser.AbstractFullBox;
+
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import static com.googlecode.mp4parser.util.CastUtils.l2i;
+
+/**
+ * <pre>
+ * aligned(8) class CompositionOffsetBox
+ * extends FullBox(‘ctts’, version = 0, 0) {
+ *  unsigned int(32) entry_count;
+ *  int i;
+ *  if (version==0) {
+ *   for (i=0; i < entry_count; i++) {
+ *    unsigned int(32) sample_count;
+ *    unsigned int(32) sample_offset;
+ *   }
+ *  }
+ *  else if (version == 1) {
+ *   for (i=0; i < entry_count; i++) {
+ *    unsigned int(32) sample_count;
+ *    signed int(32) sample_offset;
+ *   }
+ *  }
+ * }
+ * </pre>
+ * <p/>
+ * This box provides the offset between decoding time and composition time.
+ * In version 0 of this box the decoding time must be less than the composition time, and
+ * the offsets are expressed as unsigned numbers such that
+ * CT(n) = DT(n) + CTTS(n) where CTTS(n) is the (uncompressed) table entry for sample n.
+ * <p/>
+ * In version 1 of this box, the composition timeline and the decoding timeline are
+ * still derived from each other, but the offsets are signed.
+ * It is recommended that for the computed composition timestamps, there is
+ * exactly one with the value 0 (zero).
+ */
+public class CompositionTimeToSample extends AbstractFullBox {
+    public static final String TYPE = "ctts";
+
+    List<Entry> entries = Collections.emptyList();
+
+    public CompositionTimeToSample() {
+        super(TYPE);
+    }
+
+    protected long getContentSize() {
+        return 8 + 8 * entries.size();
+    }
+
+    public List<Entry> getEntries() {
+        return entries;
+    }
+
+    public void setEntries(List<Entry> entries) {
+        this.entries = entries;
+    }
+
+    @Override
+    public void _parseDetails(ByteBuffer content) {
+        parseVersionAndFlags(content);
+        int numberOfEntries = l2i(IsoTypeReader.readUInt32(content));
+        entries = new ArrayList<Entry>(numberOfEntries);
+        for (int i = 0; i < numberOfEntries; i++) {
+            Entry e = new Entry(l2i(IsoTypeReader.readUInt32(content)), content.getInt());
+            entries.add(e);
+        }
+    }
+
+    @Override
+    protected void getContent(ByteBuffer byteBuffer) {
+        writeVersionAndFlags(byteBuffer);
+        IsoTypeWriter.writeUInt32(byteBuffer, entries.size());
+
+        for (Entry entry : entries) {
+            IsoTypeWriter.writeUInt32(byteBuffer, entry.getCount());
+            byteBuffer.putInt(entry.getOffset());
+        }
+
+    }
+
+
+    public static class Entry {
+        int count;
+        int offset;
+
+        public Entry(int count, int offset) {
+            this.count = count;
+            this.offset = offset;
+        }
+
+        public int getCount() {
+            return count;
+        }
+
+        public int getOffset() {
+            return offset;
+        }
+
+        public void setCount(int count) {
+            this.count = count;
+        }
+
+        public void setOffset(int offset) {
+            this.offset = offset;
+        }
+
+        @Override
+        public String toString() {
+            return "Entry{" +
+                    "count=" + count +
+                    ", offset=" + offset +
+                    '}';
+        }
+    }
+
+
+    /**
+     * Decompresses the list of entries and returns the list of composition times.
+     *
+     * @return decoding time per sample
+     */
+    public static int[] blowupCompositionTimes(List<CompositionTimeToSample.Entry> entries) {
+        long numOfSamples = 0;
+        for (CompositionTimeToSample.Entry entry : entries) {
+            numOfSamples += entry.getCount();
+        }
+        assert numOfSamples <= Integer.MAX_VALUE;
+        int[] decodingTime = new int[(int) numOfSamples];
+
+        int current = 0;
+
+
+        for (CompositionTimeToSample.Entry entry : entries) {
+            for (int i = 0; i < entry.getCount(); i++) {
+                decodingTime[current++] = entry.getOffset();
+            }
+        }
+
+        return decodingTime;
+    }
+
+}
diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/ContainerBox.java b/isoparser/src/main/java/com/coremedia/iso/boxes/ContainerBox.java
new file mode 100644
index 0000000..a016374
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/ContainerBox.java
@@ -0,0 +1,74 @@
+/*  
+ * Copyright 2008 CoreMedia AG, Hamburg
+ *
+ * Licensed under the Apache License, Version 2.0 (the License); 
+ * you may not use this file except in compliance with the License. 
+ * You may obtain a copy of the License at 
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0 
+ * 
+ * Unless required by applicable law or agreed to in writing, software 
+ * distributed under the License is distributed on an AS IS BASIS, 
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+ * See the License for the specific language governing permissions and 
+ * limitations under the License. 
+ */
+
+package com.coremedia.iso.boxes;
+
+import com.coremedia.iso.IsoFile;
+
+import java.util.List;
+
+/**
+ * Interface for all ISO boxes that may contain other boxes.
+ */
+public interface ContainerBox extends Box {
+
+    /**
+     * Gets all child boxes. May not return <code>null</code>.
+     *
+     * @return an array of boxes, empty array in case of no children.
+     */
+    List<Box> getBoxes();
+
+    /**
+     * Sets all boxes and removes all previous child boxes.
+     * @param boxes the new list of children
+     */
+    void setBoxes(List<Box> boxes);
+
+    /**
+     * Gets all child boxes of the given type. May not return <code>null</code>.
+     *
+     * @param clazz child box's type
+     * @return an array of boxes, empty array in case of no children.
+     */
+    <T extends Box> List<T> getBoxes(Class<T> clazz);
+
+    /**
+     * Gets all child boxes of the given type. May not return <code>null</code>.
+     *
+     * @param clazz     child box's type
+     * @param recursive step down the tree
+     * @return an array of boxes, empty array in case of no children.
+     */
+    <T extends Box> List<T> getBoxes(Class<T> clazz, boolean recursive);
+
+    /**
+     * Gets the parent box. May be <code>null</code> in case of the
+     * {@link com.coremedia.iso.IsoFile} itself.
+     *
+     * @return a <code>ContainerBox</code> that contains <code>this</code>
+     */
+    ContainerBox getParent();
+
+    /**
+     * Returns the number of bytes from the start of the box to start of the first child.
+     *
+     * @return offset of first child from box start
+     */
+    long getNumOfBytesToFirstChild();
+
+    IsoFile getIsoFile();
+}
diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/CopyrightBox.java b/isoparser/src/main/java/com/coremedia/iso/boxes/CopyrightBox.java
new file mode 100644
index 0000000..86bc215
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/CopyrightBox.java
@@ -0,0 +1,86 @@
+/*  
+ * Copyright 2008 CoreMedia AG, Hamburg
+ *
+ * Licensed under the Apache License, Version 2.0 (the License); 
+ * you may not use this file except in compliance with the License. 
+ * You may obtain a copy of the License at 
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0 
+ * 
+ * Unless required by applicable law or agreed to in writing, software 
+ * distributed under the License is distributed on an AS IS BASIS, 
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+ * See the License for the specific language governing permissions and 
+ * limitations under the License. 
+ */
+
+package com.coremedia.iso.boxes;
+
+
+import com.coremedia.iso.IsoTypeReader;
+import com.coremedia.iso.IsoTypeWriter;
+import com.coremedia.iso.Utf8;
+import com.googlecode.mp4parser.AbstractFullBox;
+
+import java.nio.ByteBuffer;
+
+/**
+ * The copyright box contains a copyright declaration which applies to the entire presentation, when contained
+ * within the MovieBox, or, when contained in a track, to that entire track. There may be multple boxes using
+ * different language codes.
+ *
+ * @see MovieBox
+ * @see TrackBox
+ */
+public class CopyrightBox extends AbstractFullBox {
+    public static final String TYPE = "cprt";
+
+    private String language;
+    private String copyright;
+
+    public CopyrightBox() {
+        super(TYPE);
+    }
+
+    public String getLanguage() {
+        return language;
+    }
+
+    public String getCopyright() {
+        return copyright;
+    }
+
+    public void setLanguage(String language) {
+        this.language = language;
+    }
+
+    public void setCopyright(String copyright) {
+        this.copyright = copyright;
+    }
+
+    protected long getContentSize() {
+        return 7 + Utf8.utf8StringLengthInBytes(copyright);
+    }
+
+    @Override
+    public void _parseDetails(ByteBuffer content) {
+        parseVersionAndFlags(content);
+        language = IsoTypeReader.readIso639(content);
+        copyright = IsoTypeReader.readString(content);
+    }
+
+    @Override
+    protected void getContent(ByteBuffer byteBuffer) {
+        writeVersionAndFlags(byteBuffer);
+        IsoTypeWriter.writeIso639(byteBuffer, language);
+        byteBuffer.put(Utf8.convert(copyright));
+        byteBuffer.put((byte) 0);
+    }
+
+    public String toString() {
+        return "CopyrightBox[language=" + getLanguage() + ";copyright=" + getCopyright() + "]";
+    }
+
+
+
+}
diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/DataEntryUrlBox.java b/isoparser/src/main/java/com/coremedia/iso/boxes/DataEntryUrlBox.java
new file mode 100644
index 0000000..b58608d
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/DataEntryUrlBox.java
@@ -0,0 +1,53 @@
+/*  
+ * Copyright 2008 CoreMedia AG, Hamburg
+ *
+ * Licensed under the Apache License, Version 2.0 (the License); 
+ * you may not use this file except in compliance with the License. 
+ * You may obtain a copy of the License at 
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0 
+ * 
+ * Unless required by applicable law or agreed to in writing, software 
+ * distributed under the License is distributed on an AS IS BASIS, 
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+ * See the License for the specific language governing permissions and 
+ * limitations under the License. 
+ */
+
+package com.coremedia.iso.boxes;
+
+import com.googlecode.mp4parser.AbstractFullBox;
+
+import java.nio.ByteBuffer;
+
+/**
+ * Only used within the DataReferenceBox. Find more information there.
+ *
+ * @see com.coremedia.iso.boxes.DataReferenceBox
+ */
+public class DataEntryUrlBox extends AbstractFullBox {
+    public static final String TYPE = "url ";
+
+    public DataEntryUrlBox() {
+        super(TYPE);
+    }
+
+    @Override
+    public void _parseDetails(ByteBuffer content) {
+        parseVersionAndFlags(content);
+    }
+
+
+    @Override
+    protected void getContent(ByteBuffer byteBuffer) {
+        writeVersionAndFlags(byteBuffer);
+    }
+
+    protected long getContentSize() {
+        return 4;
+    }
+
+    public String toString() {
+        return "DataEntryUrlBox[]";
+    }
+}
diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/DataEntryUrnBox.java b/isoparser/src/main/java/com/coremedia/iso/boxes/DataEntryUrnBox.java
new file mode 100644
index 0000000..042a972
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/DataEntryUrnBox.java
@@ -0,0 +1,69 @@
+/*  
+ * Copyright 2008 CoreMedia AG, Hamburg
+ *
+ * Licensed under the Apache License, Version 2.0 (the License); 
+ * you may not use this file except in compliance with the License. 
+ * You may obtain a copy of the License at 
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0 
+ * 
+ * Unless required by applicable law or agreed to in writing, software 
+ * distributed under the License is distributed on an AS IS BASIS, 
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+ * See the License for the specific language governing permissions and 
+ * limitations under the License. 
+ */
+
+package com.coremedia.iso.boxes;
+
+import com.coremedia.iso.IsoTypeReader;
+import com.coremedia.iso.Utf8;
+import com.googlecode.mp4parser.AbstractFullBox;
+
+import java.nio.ByteBuffer;
+
+/**
+ * Only used within the DataReferenceBox. Find more information there.
+ *
+ * @see com.coremedia.iso.boxes.DataReferenceBox
+ */
+public class DataEntryUrnBox extends AbstractFullBox {
+    private String name;
+    private String location;
+    public static final String TYPE = "urn ";
+
+    public DataEntryUrnBox() {
+        super(TYPE);
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public String getLocation() {
+        return location;
+    }
+
+    protected long getContentSize() {
+        return Utf8.utf8StringLengthInBytes(name) + 1 + Utf8.utf8StringLengthInBytes(location) + 1;
+    }
+
+    @Override
+    public void _parseDetails(ByteBuffer content) {
+        name = IsoTypeReader.readString(content);
+        location = IsoTypeReader.readString(content);
+
+    }
+
+    @Override
+    protected void getContent(ByteBuffer byteBuffer) {
+        byteBuffer.put(Utf8.convert(name));
+        byteBuffer.put((byte) 0);
+        byteBuffer.put(Utf8.convert(location));
+        byteBuffer.put((byte) 0);
+    }
+
+    public String toString() {
+        return "DataEntryUrlBox[name=" + getName() + ";location=" + getLocation() + "]";
+    }
+}
diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/DataInformationBox.java b/isoparser/src/main/java/com/coremedia/iso/boxes/DataInformationBox.java
new file mode 100644
index 0000000..7f058eb
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/DataInformationBox.java
@@ -0,0 +1,36 @@
+/*  
+ * Copyright 2008 CoreMedia AG, Hamburg
+ *
+ * Licensed under the Apache License, Version 2.0 (the License); 
+ * you may not use this file except in compliance with the License. 
+ * You may obtain a copy of the License at 
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0 
+ * 
+ * Unless required by applicable law or agreed to in writing, software 
+ * distributed under the License is distributed on an AS IS BASIS, 
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+ * See the License for the specific language governing permissions and 
+ * limitations under the License. 
+ */
+
+package com.coremedia.iso.boxes;
+
+import com.googlecode.mp4parser.AbstractContainerBox;
+
+/**
+ * <code>
+ * Box Type: 'dinf'<br>
+ * Container: {@link com.coremedia.iso.boxes.MediaInformationBox} ('minf')<br>
+ * Mandatory: Yes<br>
+ * Quantity: Exactly one<br><br></code>
+ * The data information box contains objects that declare the location of the media information in a track.
+ */
+public class DataInformationBox extends AbstractContainerBox {
+    public static final String TYPE = "dinf";
+
+    public DataInformationBox() {
+        super(TYPE);
+    }
+
+}
diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/DataReferenceBox.java b/isoparser/src/main/java/com/coremedia/iso/boxes/DataReferenceBox.java
new file mode 100644
index 0000000..8156d3f
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/DataReferenceBox.java
@@ -0,0 +1,65 @@
+/*  
+ * Copyright 2008 CoreMedia AG, Hamburg
+ *
+ * Licensed under the Apache License, Version 2.0 (the License); 
+ * you may not use this file except in compliance with the License. 
+ * You may obtain a copy of the License at 
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0 
+ * 
+ * Unless required by applicable law or agreed to in writing, software 
+ * distributed under the License is distributed on an AS IS BASIS, 
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+ * See the License for the specific language governing permissions and 
+ * limitations under the License. 
+ */
+
+package com.coremedia.iso.boxes;
+
+
+import com.coremedia.iso.IsoTypeWriter;
+import com.googlecode.mp4parser.FullContainerBox;
+
+import java.nio.ByteBuffer;
+
+/**
+ * The data reference object contains a table of data references (normally URLs) that declare the location(s) of
+ * the media data used within the presentation. The data reference index in the sample description ties entries in
+ * this table to the samples in the track. A track may be split over several sources in this way.
+ * If the flag is set indicating that the data is in the same file as this box, then no string (not even an empty one)
+ * shall be supplied in the entry field.
+ * The DataEntryBox within the DataReferenceBox shall be either a DataEntryUrnBox or a DataEntryUrlBox.
+ *
+ * @see com.coremedia.iso.boxes.DataEntryUrlBox
+ * @see com.coremedia.iso.boxes.DataEntryUrnBox
+ */
+public class DataReferenceBox extends FullContainerBox {
+
+    public static final String TYPE = "dref";
+
+    public DataReferenceBox() {
+        super(TYPE);
+
+    }
+
+    @Override
+    protected long getContentSize() {
+        return super.getContentSize() + 4;
+    }
+
+    @Override
+    public void _parseDetails(ByteBuffer content) {
+        parseVersionAndFlags(content);
+        content.get(new byte[4]); // basically a skip of 4 bytes signaling the number of child boxes
+        parseChildBoxes(content);
+    }
+
+
+    @Override
+    protected void getContent(ByteBuffer byteBuffer) {
+        writeVersionAndFlags(byteBuffer);
+        IsoTypeWriter.writeUInt32(byteBuffer, getBoxes().size());
+        writeChildBoxes(byteBuffer);
+    }
+
+}
diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/DescriptionBox.java b/isoparser/src/main/java/com/coremedia/iso/boxes/DescriptionBox.java
new file mode 100644
index 0000000..8352051
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/DescriptionBox.java
@@ -0,0 +1,77 @@
+/*  
+ * Copyright 2008 CoreMedia AG, Hamburg
+ *
+ * Licensed under the Apache License, Version 2.0 (the License); 
+ * you may not use this file except in compliance with the License. 
+ * You may obtain a copy of the License at 
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0 
+ * 
+ * Unless required by applicable law or agreed to in writing, software 
+ * distributed under the License is distributed on an AS IS BASIS, 
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+ * See the License for the specific language governing permissions and 
+ * limitations under the License. 
+ */
+
+package com.coremedia.iso.boxes;
+
+import com.coremedia.iso.IsoTypeReader;
+import com.coremedia.iso.IsoTypeWriter;
+import com.coremedia.iso.Utf8;
+import com.googlecode.mp4parser.AbstractFullBox;
+
+import java.nio.ByteBuffer;
+
+/**
+ * Gives a language dependent description of the media contained in the ISO file.
+ */
+public class DescriptionBox extends AbstractFullBox {
+    public static final String TYPE = "dscp";
+
+    private String language;
+    private String description;
+
+    public DescriptionBox() {
+        super(TYPE);
+    }
+
+    public String getLanguage() {
+        return language;
+    }
+
+    public String getDescription() {
+        return description;
+    }
+
+    protected long getContentSize() {
+        return 7 + Utf8.utf8StringLengthInBytes(description);
+    }
+
+    @Override
+    public void _parseDetails(ByteBuffer content) {
+        parseVersionAndFlags(content);
+        language = IsoTypeReader.readIso639(content);
+        description = IsoTypeReader.readString(content);
+    }
+
+    @Override
+    protected void getContent(ByteBuffer byteBuffer) {
+        writeVersionAndFlags(byteBuffer);
+        IsoTypeWriter.writeIso639(byteBuffer, language);
+        byteBuffer.put(Utf8.convert(description));
+        byteBuffer.put((byte) 0);
+    }
+
+    public String toString() {
+        return "DescriptionBox[language=" + getLanguage() + ";description=" + getDescription() + "]";
+    }
+
+    public void setLanguage(String language) {
+        this.language = language;
+    }
+
+    public void setDescription(String description) {
+        this.description = description;
+    }
+}
diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/EditBox.java b/isoparser/src/main/java/com/coremedia/iso/boxes/EditBox.java
new file mode 100644
index 0000000..db3bc25
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/EditBox.java
@@ -0,0 +1,34 @@
+/*  
+ * Copyright 2008 CoreMedia AG, Hamburg
+ *
+ * Licensed under the Apache License, Version 2.0 (the License); 
+ * you may not use this file except in compliance with the License. 
+ * You may obtain a copy of the License at 
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0 
+ * 
+ * Unless required by applicable law or agreed to in writing, software 
+ * distributed under the License is distributed on an AS IS BASIS, 
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+ * See the License for the specific language governing permissions and 
+ * limitations under the License. 
+ */
+
+package com.coremedia.iso.boxes;
+
+import com.googlecode.mp4parser.AbstractContainerBox;
+
+/**
+ * An Edit Box maps the presentation time-line to the media time-line as it is stored in the file.
+ * The Edit Box is a container fpr the edit lists. Defined in ISO/IEC 14496-12.
+ *
+ * @see EditListBox
+ */
+public class EditBox extends AbstractContainerBox {
+    public static final String TYPE = "edts";
+
+    public EditBox() {
+        super(TYPE);
+    }
+
+}
diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/EditListBox.java b/isoparser/src/main/java/com/coremedia/iso/boxes/EditListBox.java
new file mode 100644
index 0000000..231f8be
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/EditListBox.java
@@ -0,0 +1,248 @@
+/*  
+ * Copyright 2008 CoreMedia AG, Hamburg
+ *
+ * Licensed under the Apache License, Version 2.0 (the License); 
+ * you may not use this file except in compliance with the License. 
+ * You may obtain a copy of the License at 
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0 
+ * 
+ * Unless required by applicable law or agreed to in writing, software 
+ * distributed under the License is distributed on an AS IS BASIS, 
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+ * See the License for the specific language governing permissions and 
+ * limitations under the License. 
+ */
+
+package com.coremedia.iso.boxes;
+
+
+import com.coremedia.iso.IsoTypeReader;
+import com.coremedia.iso.IsoTypeWriter;
+import com.googlecode.mp4parser.AbstractFullBox;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.util.LinkedList;
+import java.util.List;
+
+import static com.googlecode.mp4parser.util.CastUtils.l2i;
+
+/**
+ * <code>
+ * Box Type  : 'elst'<br>
+ * Container: {@link EditBox}('edts')<br>
+ * Mandatory: No<br>
+ * Quantity  : Zero or one</code><br><br>
+ * This box contains an explicit timeline map. Each entry defines part of the track time-line: by mapping part of
+ * the media time-line, or by indicating 'empty' time, or by defining a 'dwell', where a single time-point in the
+ * media is held for a period.<br>
+ * Note that edits are not restricted to fall on sample times. This means that when entering an edit, it can be
+ * necessary to (a) back up to a sync point, and pre-roll from there and then (b) be careful about the duration of
+ * the first sample - it might have been truncated if the edit enters it during its normal duration. If this is audio,
+ * that frame might need to be decoded, and then the final slicing done. Likewise, the duration of the last sample
+ * in an edit might need slicing. <br>
+ * Starting offsets for tracks (streams) are represented by an initial empty edit. For example, to play a track from
+ * its start for 30 seconds, but at 10 seconds into the presentation, we have the following edit list:<br>
+ * <p/>
+ * <li>Entry-count = 2</li>
+ * <li>Segment-duration = 10 seconds</li>
+ * <li>Media-Time = -1</li>
+ * <li>Media-Rate = 1</li>
+ * <li>Segment-duration = 30 seconds (could be the length of the whole track)</li>
+ * <li>Media-Time = 0 seconds</li>
+ * <li>Media-Rate = 1</li>
+ */
+public class EditListBox extends AbstractFullBox {
+    private List<Entry> entries = new LinkedList<Entry>();
+    public static final String TYPE = "elst";
+
+    public EditListBox() {
+        super(TYPE);
+    }
+
+
+    public List<Entry> getEntries() {
+        return entries;
+    }
+
+    public void setEntries(List<Entry> entries) {
+        this.entries = entries;
+    }
+
+    protected long getContentSize() {
+        long contentSize = 8;
+        if (getVersion() == 1) {
+            contentSize += entries.size() * 20;
+        } else {
+            contentSize += entries.size() * 12;
+        }
+
+        return contentSize;
+    }
+
+    @Override
+    public void _parseDetails(ByteBuffer content) {
+        parseVersionAndFlags(content);
+        int entryCount = l2i(IsoTypeReader.readUInt32(content));
+        entries = new LinkedList<Entry>();
+        for (int i = 0; i < entryCount; i++) {
+            entries.add(new Entry(this, content));
+
+        }
+    }
+
+    @Override
+    protected void getContent(ByteBuffer byteBuffer) {
+        writeVersionAndFlags(byteBuffer);
+        IsoTypeWriter.writeUInt32(byteBuffer, entries.size());
+        for (Entry entry : entries) {
+            entry.getContent(byteBuffer);
+        }
+    }
+
+    @Override
+    public String toString() {
+        return "EditListBox{" +
+                "entries=" + entries +
+                '}';
+    }
+
+    public static class Entry {
+        private long segmentDuration;
+        private long mediaTime;
+        private double mediaRate;
+        EditListBox editListBox;
+
+        /**
+         * Creates a new <code>Entry</code> with all values set.
+         *
+         * @param segmentDuration duration in movie timescale
+         * @param mediaTime       starting time
+         * @param mediaRate       relative play rate
+         */
+        public Entry(EditListBox editListBox, long segmentDuration, long mediaTime, double mediaRate) {
+            this.segmentDuration = segmentDuration;
+            this.mediaTime = mediaTime;
+            this.mediaRate = mediaRate;
+            this.editListBox = editListBox;
+        }
+
+        public Entry(EditListBox editListBox, ByteBuffer bb) {
+            if (editListBox.getVersion() == 1) {
+                segmentDuration = IsoTypeReader.readUInt64(bb);
+                mediaTime = IsoTypeReader.readUInt64(bb);
+                mediaRate = IsoTypeReader.readFixedPoint1616(bb);
+            } else {
+                segmentDuration = IsoTypeReader.readUInt32(bb);
+                mediaTime = IsoTypeReader.readUInt32(bb);
+                mediaRate = IsoTypeReader.readFixedPoint1616(bb);
+            }
+            this.editListBox = editListBox;
+        }
+
+        /**
+         * The segment duration is an integer that specifies the duration
+         * of this edit segment in units of the timescale in the Movie
+         * Header Box
+         *
+         * @return segment duration in movie timescale
+         */
+        public long getSegmentDuration() {
+            return segmentDuration;
+        }
+
+        /**
+         * The segment duration is an integer that specifies the duration
+         * of this edit segment in units of the timescale in the Movie
+         * Header Box
+         *
+         * @param segmentDuration new segment duration in movie timescale
+         */
+        public void setSegmentDuration(long segmentDuration) {
+            this.segmentDuration = segmentDuration;
+        }
+
+        /**
+         * The media time is an integer containing the starting time
+         * within the media of a specific edit segment(in media time
+         * scale units, in composition time)
+         *
+         * @return starting time
+         */
+        public long getMediaTime() {
+            return mediaTime;
+        }
+
+        /**
+         * The media time is an integer containing the starting time
+         * within the media of a specific edit segment(in media time
+         * scale units, in composition time)
+         *
+         * @param mediaTime starting time
+         */
+        public void setMediaTime(long mediaTime) {
+            this.mediaTime = mediaTime;
+        }
+
+        /**
+         * The media rate specifies the relative rate at which to play the
+         * media corresponding to a specific edit segment.
+         *
+         * @return relative play rate
+         */
+        public double getMediaRate() {
+            return mediaRate;
+        }
+
+        /**
+         * The media rate specifies the relative rate at which to play the
+         * media corresponding to a specific edit segment.
+         *
+         * @param mediaRate new relative play rate
+         */
+        public void setMediaRate(double mediaRate) {
+            this.mediaRate = mediaRate;
+        }
+
+        @Override
+        public boolean equals(Object o) {
+            if (this == o) return true;
+            if (o == null || getClass() != o.getClass()) return false;
+
+            Entry entry = (Entry) o;
+
+            if (mediaTime != entry.mediaTime) return false;
+            if (segmentDuration != entry.segmentDuration) return false;
+
+            return true;
+        }
+
+        @Override
+        public int hashCode() {
+            int result = (int) (segmentDuration ^ (segmentDuration >>> 32));
+            result = 31 * result + (int) (mediaTime ^ (mediaTime >>> 32));
+            return result;
+        }
+
+        public void getContent(ByteBuffer bb)  {
+            if (editListBox.getVersion() == 1) {
+                IsoTypeWriter.writeUInt64(bb, segmentDuration);
+                IsoTypeWriter.writeUInt64(bb, mediaTime);
+            } else {
+                IsoTypeWriter.writeUInt32(bb, l2i(segmentDuration));
+                bb.putInt(l2i(mediaTime));
+            }
+            IsoTypeWriter.writeFixedPont1616(bb, mediaRate);
+        }
+
+        @Override
+        public String toString() {
+            return "Entry{" +
+                    "segmentDuration=" + segmentDuration +
+                    ", mediaTime=" + mediaTime +
+                    ", mediaRate=" + mediaRate +
+                    '}';
+        }
+    }
+}
diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/FileTypeBox.java b/isoparser/src/main/java/com/coremedia/iso/boxes/FileTypeBox.java
new file mode 100644
index 0000000..e6eed20
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/FileTypeBox.java
@@ -0,0 +1,144 @@
+/*  
+ * Copyright 2008 CoreMedia AG, Hamburg
+ *
+ * Licensed under the Apache License, Version 2.0 (the License); 
+ * you may not use this file except in compliance with the License. 
+ * You may obtain a copy of the License at 
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0 
+ * 
+ * Unless required by applicable law or agreed to in writing, software 
+ * distributed under the License is distributed on an AS IS BASIS, 
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+ * See the License for the specific language governing permissions and 
+ * limitations under the License. 
+ */
+
+package com.coremedia.iso.boxes;
+
+import com.coremedia.iso.IsoFile;
+import com.coremedia.iso.IsoTypeReader;
+import com.coremedia.iso.IsoTypeWriter;
+import com.googlecode.mp4parser.AbstractBox;
+import com.googlecode.mp4parser.annotations.DoNotParseDetail;
+
+import java.nio.ByteBuffer;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.LinkedList;
+import java.util.List;
+
+/**
+ * This box identifies the specifications to which this file complies. <br>
+ * Each brand is a printable four-character code, registered with ISO, that
+ * identifies a precise specification.
+ */
+public class FileTypeBox extends AbstractBox {
+    public static final String TYPE = "ftyp";
+
+    private String majorBrand;
+    private long minorVersion;
+    private List<String> compatibleBrands = Collections.emptyList();
+
+    public FileTypeBox() {
+        super(TYPE);
+    }
+
+    public FileTypeBox(String majorBrand, long minorVersion, List<String> compatibleBrands) {
+        super(TYPE);
+        this.majorBrand = majorBrand;
+        this.minorVersion = minorVersion;
+        this.compatibleBrands = compatibleBrands;
+    }
+
+    protected long getContentSize() {
+        return 8 + compatibleBrands.size() * 4;
+
+    }
+
+    @Override
+    public void _parseDetails(ByteBuffer content) {
+        majorBrand = IsoTypeReader.read4cc(content);
+        minorVersion = IsoTypeReader.readUInt32(content);
+        int compatibleBrandsCount = content.remaining() / 4;
+        compatibleBrands = new LinkedList<String>();
+        for (int i = 0; i < compatibleBrandsCount; i++) {
+            compatibleBrands.add(IsoTypeReader.read4cc(content));
+        }
+    }
+
+    @Override
+    protected void getContent(ByteBuffer byteBuffer) {
+        byteBuffer.put(IsoFile.fourCCtoBytes(majorBrand));
+        IsoTypeWriter.writeUInt32(byteBuffer, minorVersion);
+        for (String compatibleBrand : compatibleBrands) {
+            byteBuffer.put(IsoFile.fourCCtoBytes(compatibleBrand));
+        }
+
+    }
+
+    /**
+     * Gets the brand identifier.
+     *
+     * @return the brand identifier
+     */
+    public String getMajorBrand() {
+        return majorBrand;
+    }
+
+    /**
+     * Sets the major brand of the file used to determine an appropriate reader.
+     *
+     * @param majorBrand the new major brand
+     */
+    public void setMajorBrand(String majorBrand) {
+        this.majorBrand = majorBrand;
+    }
+
+    /**
+     * Sets the "informative integer for the minor version of the major brand".
+     *
+     * @param minorVersion the version number of the major brand
+     */
+    public void setMinorVersion(int minorVersion) {
+        this.minorVersion = minorVersion;
+    }
+
+    /**
+     * Gets an informative integer for the minor version of the major brand.
+     *
+     * @return an informative integer
+     * @see FileTypeBox#getMajorBrand()
+     */
+    public long getMinorVersion() {
+        return minorVersion;
+    }
+
+    /**
+     * Gets an array of 4-cc brands.
+     *
+     * @return the compatible brands
+     */
+    public List<String> getCompatibleBrands() {
+        return compatibleBrands;
+    }
+
+    public void setCompatibleBrands(List<String> compatibleBrands) {
+        this.compatibleBrands = compatibleBrands;
+    }
+
+    @DoNotParseDetail
+    public String toString() {
+        StringBuilder result = new StringBuilder();
+        result.append("FileTypeBox[");
+        result.append("majorBrand=").append(getMajorBrand());
+        result.append(";");
+        result.append("minorVersion=").append(getMinorVersion());
+        for (String compatibleBrand : compatibleBrands) {
+            result.append(";");
+            result.append("compatibleBrand=").append(compatibleBrand);
+        }
+        result.append("]");
+        return result.toString();
+    }
+}
diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/FreeBox.java b/isoparser/src/main/java/com/coremedia/iso/boxes/FreeBox.java
new file mode 100644
index 0000000..636c9a7
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/FreeBox.java
@@ -0,0 +1,114 @@
+/*  
+ * Copyright 2008 CoreMedia AG, Hamburg
+ *
+ * Licensed under the Apache License, Version 2.0 (the License); 
+ * you may not use this file except in compliance with the License. 
+ * You may obtain a copy of the License at 
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0 
+ * 
+ * Unless required by applicable law or agreed to in writing, software 
+ * distributed under the License is distributed on an AS IS BASIS, 
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+ * See the License for the specific language governing permissions and 
+ * limitations under the License. 
+ */
+
+package com.coremedia.iso.boxes;
+
+
+import com.coremedia.iso.BoxParser;
+import com.coremedia.iso.ChannelHelper;
+import com.coremedia.iso.IsoTypeWriter;
+import com.googlecode.mp4parser.AbstractBox;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.nio.channels.FileChannel;
+import java.nio.channels.ReadableByteChannel;
+import java.nio.channels.WritableByteChannel;
+import java.util.LinkedList;
+import java.util.List;
+
+import static com.googlecode.mp4parser.util.CastUtils.l2i;
+
+/**
+ * A free box. Just a placeholder to enable editing without rewriting the whole file.
+ */
+public class FreeBox implements Box {
+    public static final String TYPE = "free";
+    ByteBuffer data;
+    List<Box> replacers = new LinkedList<Box>();
+    private ContainerBox parent;
+
+    public FreeBox() {
+    }
+
+    public FreeBox(int size) {
+        this.data = ByteBuffer.allocate(size);
+    }
+
+
+    public ByteBuffer getData() {
+        return data;
+    }
+
+    public void setData(ByteBuffer data) {
+        this.data = data;
+    }
+
+    public void getBox(WritableByteChannel os) throws IOException {
+        for (Box replacer : replacers) {
+            replacer.getBox(os);
+        }
+        ByteBuffer header = ByteBuffer.allocate(8);
+        IsoTypeWriter.writeUInt32(header, 8 + data.limit());
+        header.put(TYPE.getBytes());
+        header.rewind();
+        os.write(header);
+        data.rewind();
+        os.write(data);
+
+    }
+
+    public ContainerBox getParent() {
+        return parent;
+    }
+
+    public void setParent(ContainerBox parent) {
+        this.parent = parent;
+    }
+
+    public long getSize() {
+        long size = 8;
+        for (Box replacer : replacers) {
+            size += replacer.getSize();
+        }
+        size += data.limit();
+        return size;
+    }
+
+    public String getType() {
+        return TYPE;
+    }
+
+    public void parse(ReadableByteChannel readableByteChannel, ByteBuffer header, long contentSize, BoxParser boxParser) throws IOException {
+        if (readableByteChannel instanceof FileChannel && contentSize > 1024 * 1024) {
+            // It's quite expensive to map a file into the memory. Just do it when the box is larger than a MB.
+            data = ((FileChannel) readableByteChannel).map(FileChannel.MapMode.READ_ONLY, ((FileChannel) readableByteChannel).position(), contentSize);
+            ((FileChannel) readableByteChannel).position(((FileChannel) readableByteChannel).position() + contentSize);
+        } else {
+            assert contentSize < Integer.MAX_VALUE;
+            data = ChannelHelper.readFully(readableByteChannel, contentSize);
+        }
+    }
+
+
+    public void addAndReplace(Box box) {
+        data.position(l2i(box.getSize()));
+        data = data.slice();
+        replacers.add(box);
+    }
+
+
+}
\ No newline at end of file
diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/FreeSpaceBox.java b/isoparser/src/main/java/com/coremedia/iso/boxes/FreeSpaceBox.java
new file mode 100644
index 0000000..ed42bf9
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/FreeSpaceBox.java
@@ -0,0 +1,63 @@
+/*  
+ * Copyright 2008 CoreMedia AG, Hamburg
+ *
+ * Licensed under the Apache License, Version 2.0 (the License); 
+ * you may not use this file except in compliance with the License. 
+ * You may obtain a copy of the License at 
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0 
+ * 
+ * Unless required by applicable law or agreed to in writing, software 
+ * distributed under the License is distributed on an AS IS BASIS, 
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+ * See the License for the specific language governing permissions and 
+ * limitations under the License. 
+ */
+
+package com.coremedia.iso.boxes;
+
+import com.googlecode.mp4parser.AbstractBox;
+
+import java.nio.ByteBuffer;
+
+/**
+ * The contents of a free-space box are irrelevant and may be ignored, or the object deleted, without affecting the
+ * presentation. Care should be excercized when deleting the object, as this may invalidate the offsets used in the
+ * sample table.
+ */
+public class FreeSpaceBox extends AbstractBox {
+    public static final String TYPE = "skip";
+
+    byte[] data;
+
+    protected long getContentSize() {
+        return data.length;
+    }
+
+    public FreeSpaceBox() {
+        super(TYPE);
+    }
+
+    public void setData(byte[] data) {
+        this.data = data;
+    }
+
+    public byte[] getData() {
+        return data;
+    }
+
+    @Override
+    public void _parseDetails(ByteBuffer content) {
+        data = new byte[content.remaining()];
+        content.get(data);
+    }
+
+    @Override
+    protected void getContent(ByteBuffer byteBuffer) {
+        byteBuffer.put(data);
+    }
+
+    public String toString() {
+        return "FreeSpaceBox[size=" + data.length + ";type=" + getType() + "]";
+    }
+}
diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/FullBox.java b/isoparser/src/main/java/com/coremedia/iso/boxes/FullBox.java
new file mode 100644
index 0000000..1515d76
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/FullBox.java
@@ -0,0 +1,17 @@
+package com.coremedia.iso.boxes;
+
+import com.coremedia.iso.boxes.Box;
+
+/**
+ * The <code>FullBox</code> contains all getters and setters specific
+ * to a so-called full box according to the ISO/IEC 14496/12 specification.
+ */
+public interface FullBox extends Box {
+    int getVersion();
+
+    void setVersion(int version);
+
+    int getFlags();
+
+    void setFlags(int flags);
+}
diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/GenreBox.java b/isoparser/src/main/java/com/coremedia/iso/boxes/GenreBox.java
new file mode 100644
index 0000000..e2d1faf
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/GenreBox.java
@@ -0,0 +1,80 @@
+/*  
+ * Copyright 2008 CoreMedia AG, Hamburg
+ *
+ * Licensed under the Apache License, Version 2.0 (the License); 
+ * you may not use this file except in compliance with the License. 
+ * You may obtain a copy of the License at 
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0 
+ * 
+ * Unless required by applicable law or agreed to in writing, software 
+ * distributed under the License is distributed on an AS IS BASIS, 
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+ * See the License for the specific language governing permissions and 
+ * limitations under the License. 
+ */
+
+package com.coremedia.iso.boxes;
+
+import com.coremedia.iso.IsoTypeReader;
+import com.coremedia.iso.IsoTypeWriter;
+import com.coremedia.iso.Utf8;
+import com.googlecode.mp4parser.AbstractFullBox;
+
+import java.nio.ByteBuffer;
+
+/**
+ * Containing genre information and contained in the <code>UserDataBox</code>.
+ *
+ * @see com.coremedia.iso.boxes.UserDataBox
+ */
+public class GenreBox extends AbstractFullBox {
+    public static final String TYPE = "gnre";
+
+    private String language;
+    private String genre;
+
+    public GenreBox() {
+        super(TYPE);
+    }
+
+    public String getLanguage() {
+        return language;
+    }
+
+    public String getGenre() {
+        return genre;
+    }
+
+    public void setLanguage(String language) {
+        this.language = language;
+    }
+
+    public void setGenre(String genre) {
+        this.genre = genre;
+    }
+
+    protected long getContentSize() {
+        return 7 + Utf8.utf8StringLengthInBytes(genre);
+    }
+
+    @Override
+    public void _parseDetails(ByteBuffer content) {
+        parseVersionAndFlags(content);
+        language = IsoTypeReader.readIso639(content);
+        genre = IsoTypeReader.readString(content);
+    }
+
+    @Override
+    protected void getContent(ByteBuffer byteBuffer) {
+        writeVersionAndFlags(byteBuffer);
+        IsoTypeWriter.writeIso639(byteBuffer, language);
+        byteBuffer.put(Utf8.convert(genre));
+        byteBuffer.put((byte) 0);
+    }
+
+    public String toString() {
+        return "GenreBox[language=" + getLanguage() + ";genre=" + getGenre() + "]";
+    }
+
+}
diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/HandlerBox.java b/isoparser/src/main/java/com/coremedia/iso/boxes/HandlerBox.java
new file mode 100644
index 0000000..01dcaca
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/HandlerBox.java
@@ -0,0 +1,151 @@
+/*  
+ * Copyright 2008 CoreMedia AG, Hamburg
+ *
+ * Licensed under the Apache License, Version 2.0 (the License); 
+ * you may not use this file except in compliance with the License. 
+ * You may obtain a copy of the License at 
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0 
+ * 
+ * Unless required by applicable law or agreed to in writing, software 
+ * distributed under the License is distributed on an AS IS BASIS, 
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+ * See the License for the specific language governing permissions and 
+ * limitations under the License. 
+ */
+
+package com.coremedia.iso.boxes;
+
+
+import com.coremedia.iso.IsoFile;
+import com.coremedia.iso.IsoTypeReader;
+import com.coremedia.iso.IsoTypeWriter;
+import com.coremedia.iso.Utf8;
+import com.googlecode.mp4parser.AbstractFullBox;
+
+import java.nio.ByteBuffer;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * This box within a Media Box declares the process by which the media-data in the track is presented,
+ * and thus, the nature of the media in a track.
+ * This Box when present in a Meta Box, declares the structure or format of the 'meta' box contents.
+ * See ISO/IEC 14496-12 for details.
+ *
+ * @see MetaBox
+ * @see MediaBox
+ */
+public class HandlerBox extends AbstractFullBox {
+    public static final String TYPE = "hdlr";
+    public static final Map<String, String> readableTypes;
+
+    static {
+        HashMap<String, String> hm = new HashMap<String, String>();
+        hm.put("odsm", "ObjectDescriptorStream - defined in ISO/IEC JTC1/SC29/WG11 - CODING OF MOVING PICTURES AND AUDIO");
+        hm.put("crsm", "ClockReferenceStream - defined in ISO/IEC JTC1/SC29/WG11 - CODING OF MOVING PICTURES AND AUDIO");
+        hm.put("sdsm", "SceneDescriptionStream - defined in ISO/IEC JTC1/SC29/WG11 - CODING OF MOVING PICTURES AND AUDIO");
+        hm.put("m7sm", "MPEG7Stream - defined in ISO/IEC JTC1/SC29/WG11 - CODING OF MOVING PICTURES AND AUDIO");
+        hm.put("ocsm", "ObjectContentInfoStream - defined in ISO/IEC JTC1/SC29/WG11 - CODING OF MOVING PICTURES AND AUDIO");
+        hm.put("ipsm", "IPMP Stream - defined in ISO/IEC JTC1/SC29/WG11 - CODING OF MOVING PICTURES AND AUDIO");
+        hm.put("mjsm", "MPEG-J Stream - defined in ISO/IEC JTC1/SC29/WG11 - CODING OF MOVING PICTURES AND AUDIO");
+        hm.put("mdir", "Apple Meta Data iTunes Reader");
+        hm.put("mp7b", "MPEG-7 binary XML");
+        hm.put("mp7t", "MPEG-7 XML");
+        hm.put("vide", "Video Track");
+        hm.put("soun", "Sound Track");
+        hm.put("hint", "Hint Track");
+        hm.put("appl", "Apple specific");
+        hm.put("meta", "Timed Metadata track - defined in ISO/IEC JTC1/SC29/WG11 - CODING OF MOVING PICTURES AND AUDIO");
+
+        readableTypes = Collections.unmodifiableMap(hm);
+
+    }
+
+    private String handlerType;
+    private String name = null;
+    private long a, b, c;
+    private boolean zeroTerm = true;
+
+    private long shouldBeZeroButAppleWritesHereSomeValue;
+
+    public HandlerBox() {
+        super(TYPE);
+    }
+
+    public String getHandlerType() {
+        return handlerType;
+    }
+
+    /**
+     * You are required to add a '\0' string termination by yourself.
+     *
+     * @param name the new human readable name
+     */
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    public void setHandlerType(String handlerType) {
+        this.handlerType = handlerType;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public String getHumanReadableTrackType() {
+        return readableTypes.get(handlerType) != null ? readableTypes.get(handlerType) : "Unknown Handler Type";
+    }
+
+    protected long getContentSize() {
+        if (zeroTerm) {
+            return 25 + Utf8.utf8StringLengthInBytes(name);
+        } else {
+            return 24 + Utf8.utf8StringLengthInBytes(name);
+        }
+
+    }
+
+    @Override
+    public void _parseDetails(ByteBuffer content) {
+        parseVersionAndFlags(content);
+        shouldBeZeroButAppleWritesHereSomeValue = IsoTypeReader.readUInt32(content);
+        handlerType = IsoTypeReader.read4cc(content);
+        a = IsoTypeReader.readUInt32(content);
+        b = IsoTypeReader.readUInt32(content);
+        c = IsoTypeReader.readUInt32(content);
+        if (content.remaining() > 0) {
+            name = IsoTypeReader.readString(content, content.remaining());
+            if (name.endsWith("\0")) {
+                name = name.substring(0, name.length() - 1);
+                zeroTerm = true;
+            } else {
+                zeroTerm = false;
+            }
+        } else {
+            zeroTerm = false; //No string at all, not even zero term char
+        }
+    }
+
+    @Override
+    protected void getContent(ByteBuffer byteBuffer) {
+        writeVersionAndFlags(byteBuffer);
+        IsoTypeWriter.writeUInt32(byteBuffer, shouldBeZeroButAppleWritesHereSomeValue);
+        byteBuffer.put(IsoFile.fourCCtoBytes(handlerType));
+        IsoTypeWriter.writeUInt32(byteBuffer, a);
+        IsoTypeWriter.writeUInt32(byteBuffer, b);
+        IsoTypeWriter.writeUInt32(byteBuffer, c);
+        if (name != null) {
+            byteBuffer.put(Utf8.convert(name));
+        }
+        if (zeroTerm) {
+            byteBuffer.put((byte) 0);
+        }
+    }
+
+    public String toString() {
+        return "HandlerBox[handlerType=" + getHandlerType() + ";name=" + getName() + "]";
+    }
+}
diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/HintMediaHeaderBox.java b/isoparser/src/main/java/com/coremedia/iso/boxes/HintMediaHeaderBox.java
new file mode 100644
index 0000000..3477738
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/HintMediaHeaderBox.java
@@ -0,0 +1,91 @@
+/*  
+ * Copyright 2008 CoreMedia AG, Hamburg
+ *
+ * Licensed under the Apache License, Version 2.0 (the License); 
+ * you may not use this file except in compliance with the License. 
+ * You may obtain a copy of the License at 
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0 
+ * 
+ * Unless required by applicable law or agreed to in writing, software 
+ * distributed under the License is distributed on an AS IS BASIS, 
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+ * See the License for the specific language governing permissions and 
+ * limitations under the License. 
+ */
+
+package com.coremedia.iso.boxes;
+
+import com.coremedia.iso.IsoTypeReader;
+import com.coremedia.iso.IsoTypeWriter;
+
+import java.nio.ByteBuffer;
+
+/**
+ * The hint media header contains general information, independent of the protocaol, for hint tracks. Resides
+ * in Media Information Box.
+ *
+ * @see com.coremedia.iso.boxes.MediaInformationBox
+ */
+public class HintMediaHeaderBox extends AbstractMediaHeaderBox {
+    private int maxPduSize;
+    private int avgPduSize;
+    private long maxBitrate;
+    private long avgBitrate;
+    public static final String TYPE = "hmhd";
+
+    public HintMediaHeaderBox() {
+        super(TYPE);
+    }
+
+    public int getMaxPduSize() {
+        return maxPduSize;
+    }
+
+    public int getAvgPduSize() {
+        return avgPduSize;
+    }
+
+    public long getMaxBitrate() {
+        return maxBitrate;
+    }
+
+    public long getAvgBitrate() {
+        return avgBitrate;
+    }
+
+    protected long getContentSize() {
+        return 20;
+    }
+
+    @Override
+    public void _parseDetails(ByteBuffer content) {
+        parseVersionAndFlags(content);
+        maxPduSize = IsoTypeReader.readUInt16(content);
+        avgPduSize = IsoTypeReader.readUInt16(content);
+        maxBitrate = IsoTypeReader.readUInt32(content);
+        avgBitrate = IsoTypeReader.readUInt32(content);
+        IsoTypeReader.readUInt32(content);    // reserved!
+
+    }
+
+    @Override
+    protected void getContent(ByteBuffer byteBuffer) {
+        writeVersionAndFlags(byteBuffer);
+        IsoTypeWriter.writeUInt16(byteBuffer, maxPduSize);
+        IsoTypeWriter.writeUInt16(byteBuffer, avgPduSize);
+        IsoTypeWriter.writeUInt32(byteBuffer, maxBitrate);
+        IsoTypeWriter.writeUInt32(byteBuffer, avgBitrate);
+        IsoTypeWriter.writeUInt32(byteBuffer, 0);
+    }
+
+    @Override
+    public String toString() {
+        return "HintMediaHeaderBox{" +
+                "maxPduSize=" + maxPduSize +
+                ", avgPduSize=" + avgPduSize +
+                ", maxBitrate=" + maxBitrate +
+                ", avgBitrate=" + avgBitrate +
+                '}';
+    }
+}
diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/ItemDataBox.java b/isoparser/src/main/java/com/coremedia/iso/boxes/ItemDataBox.java
new file mode 100644
index 0000000..46097cc
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/ItemDataBox.java
@@ -0,0 +1,43 @@
+package com.coremedia.iso.boxes;
+
+import com.googlecode.mp4parser.AbstractBox;
+
+import java.nio.ByteBuffer;
+
+/**
+ *
+ */
+public class ItemDataBox extends AbstractBox {
+    ByteBuffer data = ByteBuffer.allocate(0);
+    public static final String TYPE = "idat";
+
+
+    public ItemDataBox() {
+        super(TYPE);
+    }
+
+    public ByteBuffer getData() {
+        return data;
+    }
+
+    public void setData(ByteBuffer data) {
+        this.data = data;
+    }
+
+    @Override
+    protected long getContentSize() {
+        return data.limit();
+    }
+
+
+    @Override
+    public void _parseDetails(ByteBuffer content) {
+        data = content.slice();
+        content.position(content.position() + content.remaining());
+    }
+
+    @Override
+    protected void getContent(ByteBuffer byteBuffer) {
+        byteBuffer.put(data);
+    }
+}
diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/ItemLocationBox.java b/isoparser/src/main/java/com/coremedia/iso/boxes/ItemLocationBox.java
new file mode 100644
index 0000000..6dcee6f
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/ItemLocationBox.java
@@ -0,0 +1,360 @@
+/*  
+ * Copyright 2008 CoreMedia AG, Hamburg
+ *
+ * Licensed under the Apache License, Version 2.0 (the License); 
+ * you may not use this file except in compliance with the License. 
+ * You may obtain a copy of the License at 
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0 
+ * 
+ * Unless required by applicable law or agreed to in writing, software 
+ * distributed under the License is distributed on an AS IS BASIS, 
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+ * See the License for the specific language governing permissions and 
+ * limitations under the License. 
+ */
+
+package com.coremedia.iso.boxes;
+
+
+import com.coremedia.iso.IsoTypeReader;
+import com.coremedia.iso.IsoTypeReaderVariable;
+import com.coremedia.iso.IsoTypeWriter;
+import com.coremedia.iso.IsoTypeWriterVariable;
+import com.googlecode.mp4parser.AbstractFullBox;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.util.LinkedList;
+import java.util.List;
+
+/**
+ * aligned(8) class ItemLocationBox extends FullBox(‘iloc’, version, 0) {
+ * unsigned int(4) offset_size;
+ * unsigned int(4) length_size;
+ * unsigned int(4) base_offset_size;
+ * if (version == 1)
+ * unsigned int(4) index_size;
+ * else
+ * unsigned int(4) reserved;
+ * unsigned int(16) item_count;
+ * for (i=0; i<item_count; i++) {
+ * unsigned int(16) item_ID;
+ * if (version == 1) {
+ * unsigned int(12) reserved = 0;
+ * unsigned int(4) construction_method;
+ * }
+ * unsigned int(16) data_reference_index;
+ * unsigned int(base_offset_size*8) base_offset;
+ * unsigned int(16) extent_count;
+ * for (j=0; j<extent_count; j++) {
+ * if ((version == 1) && (index_size > 0)) {
+ * unsigned int(index_size*8) extent_index;
+ * }
+ * unsigned int(offset_size*8) extent_offset;
+ * unsigned int(length_size*8) extent_length;
+ * }
+ * }
+ * }
+ */
+public class ItemLocationBox extends AbstractFullBox {
+    public int offsetSize = 8;
+    public int lengthSize = 8;
+    public int baseOffsetSize = 8;
+    public int indexSize = 0;
+    public List<Item> items = new LinkedList<Item>();
+
+    public static final String TYPE = "iloc";
+
+    public ItemLocationBox() {
+        super(TYPE);
+    }
+
+    @Override
+    protected long getContentSize() {
+        long size = 8;
+        for (Item item : items) {
+            size += item.getSize();
+        }
+        return size;
+    }
+
+
+    @Override
+    protected void getContent(ByteBuffer byteBuffer) {
+        writeVersionAndFlags(byteBuffer);
+        IsoTypeWriter.writeUInt8(byteBuffer, ((offsetSize << 4) | lengthSize));
+        if (getVersion() == 1) {
+            IsoTypeWriter.writeUInt8(byteBuffer, (baseOffsetSize << 4 | indexSize));
+        } else {
+            IsoTypeWriter.writeUInt8(byteBuffer, (baseOffsetSize << 4));
+        }
+        IsoTypeWriter.writeUInt16(byteBuffer, items.size());
+        for (Item item : items) {
+            item.getContent(byteBuffer);
+        }
+    }
+
+    @Override
+    public void _parseDetails(ByteBuffer content) {
+        parseVersionAndFlags(content);
+        int tmp = IsoTypeReader.readUInt8(content);
+        offsetSize = tmp >>> 4;
+        lengthSize = tmp & 0xf;
+        tmp = IsoTypeReader.readUInt8(content);
+        baseOffsetSize = tmp >>> 4;
+
+        if (getVersion() == 1) {
+            indexSize = tmp & 0xf;
+        }
+        int itemCount = IsoTypeReader.readUInt16(content);
+        for (int i = 0; i < itemCount; i++) {
+            items.add(new Item(content));
+        }
+    }
+
+
+    public int getOffsetSize() {
+        return offsetSize;
+    }
+
+    public void setOffsetSize(int offsetSize) {
+        this.offsetSize = offsetSize;
+    }
+
+    public int getLengthSize() {
+        return lengthSize;
+    }
+
+    public void setLengthSize(int lengthSize) {
+        this.lengthSize = lengthSize;
+    }
+
+    public int getBaseOffsetSize() {
+        return baseOffsetSize;
+    }
+
+    public void setBaseOffsetSize(int baseOffsetSize) {
+        this.baseOffsetSize = baseOffsetSize;
+    }
+
+    public int getIndexSize() {
+        return indexSize;
+    }
+
+    public void setIndexSize(int indexSize) {
+        this.indexSize = indexSize;
+    }
+
+    public List<Item> getItems() {
+        return items;
+    }
+
+    public void setItems(List<Item> items) {
+        this.items = items;
+    }
+
+
+    public Item createItem(int itemId, int constructionMethod, int dataReferenceIndex, long baseOffset, List<Extent> extents) {
+        return new Item(itemId, constructionMethod, dataReferenceIndex, baseOffset, extents);
+    }
+
+    Item createItem(ByteBuffer bb) {
+        return new Item(bb);
+    }
+
+    public class Item {
+        public int itemId;
+        public int constructionMethod;
+        public int dataReferenceIndex;
+        public long baseOffset;
+        public List<Extent> extents = new LinkedList<Extent>();
+
+        public Item(ByteBuffer in) {
+            itemId = IsoTypeReader.readUInt16(in);
+
+            if (getVersion() == 1) {
+                int tmp = IsoTypeReader.readUInt16(in);
+                constructionMethod = tmp & 0xf;
+            }
+
+            dataReferenceIndex = IsoTypeReader.readUInt16(in);
+            if (baseOffsetSize > 0) {
+                baseOffset = IsoTypeReaderVariable.read(in, baseOffsetSize);
+            } else {
+                baseOffset = 0;
+            }
+            int extentCount = IsoTypeReader.readUInt16(in);
+
+
+            for (int i = 0; i < extentCount; i++) {
+                extents.add(new Extent(in));
+            }
+        }
+
+        public Item(int itemId, int constructionMethod, int dataReferenceIndex, long baseOffset, List<Extent> extents) {
+            this.itemId = itemId;
+            this.constructionMethod = constructionMethod;
+            this.dataReferenceIndex = dataReferenceIndex;
+            this.baseOffset = baseOffset;
+            this.extents = extents;
+        }
+
+        public int getSize() {
+            int size = 2;
+
+            if (getVersion() == 1) {
+                size += 2;
+            }
+
+            size += 2;
+            size += baseOffsetSize;
+            size += 2;
+
+
+            for (Extent extent : extents) {
+                size += extent.getSize();
+            }
+            return size;
+        }
+
+        public void setBaseOffset(long baseOffset) {
+            this.baseOffset = baseOffset;
+        }
+
+        public void getContent(ByteBuffer bb)  {
+            IsoTypeWriter.writeUInt16(bb, itemId);
+
+            if (getVersion() == 1) {
+                IsoTypeWriter.writeUInt16(bb, constructionMethod);
+            }
+
+
+            IsoTypeWriter.writeUInt16(bb, dataReferenceIndex);
+            if (baseOffsetSize > 0) {
+                IsoTypeWriterVariable.write(baseOffset, bb, baseOffsetSize);
+            }
+            IsoTypeWriter.writeUInt16(bb, extents.size());
+
+            for (Extent extent : extents) {
+                extent.getContent(bb);
+            }
+        }
+
+        @Override
+        public boolean equals(Object o) {
+            if (this == o) return true;
+            if (o == null || getClass() != o.getClass()) return false;
+
+            Item item = (Item) o;
+
+            if (baseOffset != item.baseOffset) return false;
+            if (constructionMethod != item.constructionMethod) return false;
+            if (dataReferenceIndex != item.dataReferenceIndex) return false;
+            if (itemId != item.itemId) return false;
+            if (extents != null ? !extents.equals(item.extents) : item.extents != null) return false;
+
+            return true;
+        }
+
+        @Override
+        public int hashCode() {
+            int result = itemId;
+            result = 31 * result + constructionMethod;
+            result = 31 * result + dataReferenceIndex;
+            result = 31 * result + (int) (baseOffset ^ (baseOffset >>> 32));
+            result = 31 * result + (extents != null ? extents.hashCode() : 0);
+            return result;
+        }
+
+        @Override
+        public String toString() {
+            return "Item{" +
+                    "baseOffset=" + baseOffset +
+                    ", itemId=" + itemId +
+                    ", constructionMethod=" + constructionMethod +
+                    ", dataReferenceIndex=" + dataReferenceIndex +
+                    ", extents=" + extents +
+                    '}';
+        }
+    }
+
+
+    public Extent createExtent(long extentOffset, long extentLength, long extentIndex) {
+        return new Extent(extentOffset, extentLength, extentIndex);
+    }
+
+    Extent createExtent(ByteBuffer bb) {
+        return new Extent(bb);
+    }
+
+
+    public class Extent {
+        public long extentOffset;
+        public long extentLength;
+        public long extentIndex;
+
+        public Extent(long extentOffset, long extentLength, long extentIndex) {
+            this.extentOffset = extentOffset;
+            this.extentLength = extentLength;
+            this.extentIndex = extentIndex;
+        }
+
+
+        public Extent(ByteBuffer in) {
+            if ((getVersion() == 1) && indexSize > 0) {
+                extentIndex = IsoTypeReaderVariable.read(in, indexSize);
+            }
+            extentOffset = IsoTypeReaderVariable.read(in, offsetSize);
+            extentLength = IsoTypeReaderVariable.read(in, lengthSize);
+        }
+
+        public void getContent(ByteBuffer os)  {
+            if ((getVersion() == 1) && indexSize > 0) {
+                IsoTypeWriterVariable.write(extentIndex, os, indexSize);
+            }
+            IsoTypeWriterVariable.write(extentOffset, os, offsetSize);
+            IsoTypeWriterVariable.write(extentLength, os, lengthSize);
+        }
+
+        public int getSize() {
+            return (indexSize > 0 ? indexSize : 0) + offsetSize + lengthSize;
+        }
+
+
+        @Override
+        public boolean equals(Object o) {
+            if (this == o) return true;
+            if (o == null || getClass() != o.getClass()) return false;
+
+            Extent extent = (Extent) o;
+
+            if (extentIndex != extent.extentIndex) return false;
+            if (extentLength != extent.extentLength) return false;
+            if (extentOffset != extent.extentOffset) return false;
+
+            return true;
+        }
+
+        @Override
+        public int hashCode() {
+            int result = (int) (extentOffset ^ (extentOffset >>> 32));
+            result = 31 * result + (int) (extentLength ^ (extentLength >>> 32));
+            result = 31 * result + (int) (extentIndex ^ (extentIndex >>> 32));
+            return result;
+        }
+
+        @Override
+        public String toString() {
+            final StringBuilder sb = new StringBuilder();
+            sb.append("Extent");
+            sb.append("{extentOffset=").append(extentOffset);
+            sb.append(", extentLength=").append(extentLength);
+            sb.append(", extentIndex=").append(extentIndex);
+            sb.append('}');
+            return sb.toString();
+        }
+    }
+
+
+}
diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/ItemProtectionBox.java b/isoparser/src/main/java/com/coremedia/iso/boxes/ItemProtectionBox.java
new file mode 100644
index 0000000..7eed790
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/ItemProtectionBox.java
@@ -0,0 +1,61 @@
+/*  
+ * Copyright 2008 CoreMedia AG, Hamburg
+ *
+ * Licensed under the Apache License, Version 2.0 (the License); 
+ * you may not use this file except in compliance with the License. 
+ * You may obtain a copy of the License at 
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0 
+ * 
+ * Unless required by applicable law or agreed to in writing, software 
+ * distributed under the License is distributed on an AS IS BASIS, 
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+ * See the License for the specific language governing permissions and 
+ * limitations under the License. 
+ */
+
+package com.coremedia.iso.boxes;
+
+import com.coremedia.iso.IsoTypeReader;
+import com.coremedia.iso.IsoTypeWriter;
+import com.googlecode.mp4parser.FullContainerBox;
+
+import java.nio.ByteBuffer;
+
+/**
+ * The Item Protection Box provides an array of item protection information, for use by the Item Information Box.
+ *
+ * @see com.coremedia.iso.boxes.ItemProtectionBox
+ */
+public class ItemProtectionBox extends FullContainerBox {
+
+    public static final String TYPE = "ipro";
+
+    public ItemProtectionBox() {
+        super(TYPE);
+    }
+
+    public SchemeInformationBox getItemProtectionScheme() {
+        if (!getBoxes(SchemeInformationBox.class).isEmpty()) {
+            return getBoxes(SchemeInformationBox.class).get(0);
+        } else {
+            return null;
+        }
+    }
+
+    @Override
+    public void _parseDetails(ByteBuffer content) {
+        parseVersionAndFlags(content);
+        IsoTypeReader.readUInt16(content);
+        parseChildBoxes(content);
+    }
+
+
+    @Override
+    protected void getContent(ByteBuffer byteBuffer) {
+        writeVersionAndFlags(byteBuffer);
+        IsoTypeWriter.writeUInt16(byteBuffer, getBoxes().size());
+        writeChildBoxes(byteBuffer);
+    }
+
+}
diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/KeywordsBox.java b/isoparser/src/main/java/com/coremedia/iso/boxes/KeywordsBox.java
new file mode 100644
index 0000000..d9b7c0c
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/KeywordsBox.java
@@ -0,0 +1,95 @@
+/*  
+ * Copyright 2008 CoreMedia AG, Hamburg
+ *
+ * Licensed under the Apache License, Version 2.0 (the License); 
+ * you may not use this file except in compliance with the License. 
+ * You may obtain a copy of the License at 
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0 
+ * 
+ * Unless required by applicable law or agreed to in writing, software 
+ * distributed under the License is distributed on an AS IS BASIS, 
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+ * See the License for the specific language governing permissions and 
+ * limitations under the License. 
+ */
+
+package com.coremedia.iso.boxes;
+
+import com.coremedia.iso.IsoTypeReader;
+import com.coremedia.iso.IsoTypeWriter;
+import com.coremedia.iso.Utf8;
+import com.googlecode.mp4parser.AbstractFullBox;
+
+import java.nio.ByteBuffer;
+
+/**
+ * List of keywords according to 3GPP 26.244.
+ */
+public class KeywordsBox extends AbstractFullBox {
+    public static final String TYPE = "kywd";
+
+    private String language;
+    private String[] keywords;
+
+    public KeywordsBox() {
+        super(TYPE);
+    }
+
+    public String getLanguage() {
+        return language;
+    }
+
+    public String[] getKeywords() {
+        return keywords;
+    }
+
+    public void setLanguage(String language) {
+        this.language = language;
+    }
+
+    public void setKeywords(String[] keywords) {
+        this.keywords = keywords;
+    }
+
+    protected long getContentSize() {
+        long contentSize = 7;
+        for (String keyword : keywords) {
+            contentSize += 1 + Utf8.utf8StringLengthInBytes(keyword) + 1;
+        }
+        return contentSize;
+    }
+
+    @Override
+    public void _parseDetails(ByteBuffer content) {
+        parseVersionAndFlags(content);
+        language = IsoTypeReader.readIso639(content);
+        int keywordCount = IsoTypeReader.readUInt8(content);
+        keywords = new String[keywordCount];
+        for (int i = 0; i < keywordCount; i++) {
+            IsoTypeReader.readUInt8(content);
+            keywords[i] = IsoTypeReader.readString(content);
+        }
+    }
+
+    @Override
+    protected void getContent(ByteBuffer byteBuffer) {
+        writeVersionAndFlags(byteBuffer);
+        IsoTypeWriter.writeIso639(byteBuffer, language);
+        IsoTypeWriter.writeUInt8(byteBuffer, keywords.length);
+        for (String keyword : keywords) {
+            IsoTypeWriter.writeUInt8(byteBuffer, Utf8.utf8StringLengthInBytes(keyword) + 1);
+            byteBuffer.put(Utf8.convert(keyword));
+        }
+    }
+
+    public String toString() {
+        StringBuffer buffer = new StringBuffer();
+        buffer.append("KeywordsBox[language=").append(getLanguage());
+        for (int i = 0; i < keywords.length; i++) {
+            buffer.append(";keyword").append(i).append("=").append(keywords[i]);
+        }
+        buffer.append("]");
+        return buffer.toString();
+    }
+}
diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/MediaBox.java b/isoparser/src/main/java/com/coremedia/iso/boxes/MediaBox.java
new file mode 100644
index 0000000..fa5642c
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/MediaBox.java
@@ -0,0 +1,61 @@
+/*  
+ * Copyright 2008 CoreMedia AG, Hamburg
+ *
+ * Licensed under the Apache License, Version 2.0 (the License); 
+ * you may not use this file except in compliance with the License. 
+ * You may obtain a copy of the License at 
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0 
+ * 
+ * Unless required by applicable law or agreed to in writing, software 
+ * distributed under the License is distributed on an AS IS BASIS, 
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+ * See the License for the specific language governing permissions and 
+ * limitations under the License. 
+ */
+
+package com.coremedia.iso.boxes;
+
+
+import com.googlecode.mp4parser.AbstractContainerBox;
+
+/**
+ * The media declaration container contains all the objects that declare information about the media data within a
+ * track.
+ */
+public class MediaBox extends AbstractContainerBox {
+    public static final String TYPE = "mdia";
+
+    public MediaBox() {
+        super(TYPE);
+    }
+
+    public MediaInformationBox getMediaInformationBox() {
+        for (Box box : boxes) {
+            if (box instanceof MediaInformationBox) {
+                return (MediaInformationBox) box;
+            }
+        }
+        return null;
+    }
+
+    public MediaHeaderBox getMediaHeaderBox() {
+        for (Box box : boxes) {
+            if (box instanceof MediaHeaderBox) {
+                return (MediaHeaderBox) box;
+            }
+        }
+        return null;
+    }
+
+    public HandlerBox getHandlerBox() {
+        for (Box box : boxes) {
+            if (box instanceof HandlerBox) {
+                return (HandlerBox) box;
+            }
+        }
+        return null;
+    }
+
+
+}
diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/MediaHeaderBox.java b/isoparser/src/main/java/com/coremedia/iso/boxes/MediaHeaderBox.java
new file mode 100644
index 0000000..69b538b
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/MediaHeaderBox.java
@@ -0,0 +1,147 @@
+/*  
+ * Copyright 2008 CoreMedia AG, Hamburg
+ *
+ * Licensed under the Apache License, Version 2.0 (the License); 
+ * you may not use this file except in compliance with the License. 
+ * You may obtain a copy of the License at 
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0 
+ * 
+ * Unless required by applicable law or agreed to in writing, software 
+ * distributed under the License is distributed on an AS IS BASIS, 
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+ * See the License for the specific language governing permissions and 
+ * limitations under the License. 
+ */
+
+package com.coremedia.iso.boxes;
+
+import com.coremedia.iso.IsoTypeReader;
+import com.coremedia.iso.IsoTypeWriter;
+import com.googlecode.mp4parser.AbstractFullBox;
+
+import java.nio.ByteBuffer;
+
+/**
+ * This box defines overall information which is media-independent, and relevant to the entire presentation
+ * considered as a whole.
+ */
+public class MediaHeaderBox extends AbstractFullBox {
+    public static final String TYPE = "mdhd";
+
+
+    private long creationTime;
+    private long modificationTime;
+    private long timescale;
+    private long duration;
+    private String language;
+
+    public MediaHeaderBox() {
+        super(TYPE);
+    }
+
+    public long getCreationTime() {
+        return creationTime;
+    }
+
+    public long getModificationTime() {
+        return modificationTime;
+    }
+
+    public long getTimescale() {
+        return timescale;
+    }
+
+    public long getDuration() {
+        return duration;
+    }
+
+    public String getLanguage() {
+        return language;
+    }
+
+    protected long getContentSize() {
+        long contentSize = 4;
+        if (getVersion() == 1) {
+            contentSize += 8 + 8 + 4 + 8;
+        } else {
+            contentSize += 4 + 4 + 4 + 4;
+        }
+        contentSize += 2;
+        contentSize += 2;
+        return contentSize;
+
+    }
+
+    public void setCreationTime(long creationTime) {
+        this.creationTime = creationTime;
+    }
+
+    public void setModificationTime(long modificationTime) {
+        this.modificationTime = modificationTime;
+    }
+
+    public void setTimescale(long timescale) {
+        this.timescale = timescale;
+    }
+
+    public void setDuration(long duration) {
+        this.duration = duration;
+    }
+
+    public void setLanguage(String language) {
+        this.language = language;
+    }
+
+    @Override
+    public void _parseDetails(ByteBuffer content) {
+        parseVersionAndFlags(content);
+        if (getVersion() == 1) {
+            creationTime = IsoTypeReader.readUInt64(content);
+            modificationTime = IsoTypeReader.readUInt64(content);
+            timescale = IsoTypeReader.readUInt32(content);
+            duration = IsoTypeReader.readUInt64(content);
+        } else {
+            creationTime = IsoTypeReader.readUInt32(content);
+            modificationTime = IsoTypeReader.readUInt32(content);
+            timescale = IsoTypeReader.readUInt32(content);
+            duration = IsoTypeReader.readUInt32(content);
+        }
+        language = IsoTypeReader.readIso639(content);
+        IsoTypeReader.readUInt16(content);
+    }
+
+
+    public String toString() {
+        StringBuilder result = new StringBuilder();
+        result.append("MediaHeaderBox[");
+        result.append("creationTime=").append(getCreationTime());
+        result.append(";");
+        result.append("modificationTime=").append(getModificationTime());
+        result.append(";");
+        result.append("timescale=").append(getTimescale());
+        result.append(";");
+        result.append("duration=").append(getDuration());
+        result.append(";");
+        result.append("language=").append(getLanguage());
+        result.append("]");
+        return result.toString();
+    }
+
+    protected void getContent(ByteBuffer byteBuffer) {
+        writeVersionAndFlags(byteBuffer);
+        if (getVersion() == 1) {
+            IsoTypeWriter.writeUInt64(byteBuffer, creationTime);
+            IsoTypeWriter.writeUInt64(byteBuffer, modificationTime);
+            IsoTypeWriter.writeUInt32(byteBuffer, timescale);
+            IsoTypeWriter.writeUInt64(byteBuffer, duration);
+        } else {
+            IsoTypeWriter.writeUInt32(byteBuffer, creationTime);
+            IsoTypeWriter.writeUInt32(byteBuffer, modificationTime);
+            IsoTypeWriter.writeUInt32(byteBuffer, timescale);
+            IsoTypeWriter.writeUInt32(byteBuffer, duration);
+        }
+        IsoTypeWriter.writeIso639(byteBuffer, language);
+        IsoTypeWriter.writeUInt16(byteBuffer, 0);
+    }
+}
diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/MediaInformationBox.java b/isoparser/src/main/java/com/coremedia/iso/boxes/MediaInformationBox.java
new file mode 100644
index 0000000..ed25051
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/MediaInformationBox.java
@@ -0,0 +1,49 @@
+/*  
+ * Copyright 2008 CoreMedia AG, Hamburg
+ *
+ * Licensed under the Apache License, Version 2.0 (the License); 
+ * you may not use this file except in compliance with the License. 
+ * You may obtain a copy of the License at 
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0 
+ * 
+ * Unless required by applicable law or agreed to in writing, software 
+ * distributed under the License is distributed on an AS IS BASIS, 
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+ * See the License for the specific language governing permissions and 
+ * limitations under the License. 
+ */
+
+package com.coremedia.iso.boxes;
+
+import com.googlecode.mp4parser.AbstractContainerBox;
+
+/**
+ * This box contains all the objects that declare characteristic information of the media in the track.
+ */
+public class MediaInformationBox extends AbstractContainerBox {
+    public static final String TYPE = "minf";
+
+    public MediaInformationBox() {
+        super(TYPE);
+    }
+
+    public SampleTableBox getSampleTableBox() {
+        for (Box box : boxes) {
+            if (box instanceof SampleTableBox) {
+                return (SampleTableBox) box;
+            }
+        }
+        return null;
+    }
+
+    public AbstractMediaHeaderBox getMediaHeaderBox() {
+        for (Box box : boxes) {
+            if (box instanceof AbstractMediaHeaderBox) {
+                return (AbstractMediaHeaderBox) box;
+            }
+        }
+        return null;
+    }
+
+}
diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/MetaBox.java b/isoparser/src/main/java/com/coremedia/iso/boxes/MetaBox.java
new file mode 100644
index 0000000..35499ec
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/MetaBox.java
@@ -0,0 +1,113 @@
+/*  
+ * Copyright 2008 CoreMedia AG, Hamburg
+ *
+ * Licensed under the Apache License, Version 2.0 (the License); 
+ * you may not use this file except in compliance with the License. 
+ * You may obtain a copy of the License at 
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0 
+ * 
+ * Unless required by applicable law or agreed to in writing, software 
+ * distributed under the License is distributed on an AS IS BASIS, 
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+ * See the License for the specific language governing permissions and 
+ * limitations under the License. 
+ */
+
+package com.coremedia.iso.boxes;
+
+import com.coremedia.iso.IsoTypeReader;
+import com.coremedia.iso.IsoTypeWriter;
+import com.googlecode.mp4parser.AbstractContainerBox;
+import com.googlecode.mp4parser.util.ByteBufferByteChannel;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+
+
+/**
+ * A common base structure to contain general metadata. See ISO/IEC 14496-12 Ch. 8.44.1.
+ */
+public class MetaBox extends AbstractContainerBox {
+    private int version = 0;
+    private int flags = 0;
+
+    public static final String TYPE = "meta";
+
+    public MetaBox() {
+        super(TYPE);
+    }
+
+    @Override
+    public long getContentSize() {
+        if (isMp4Box()) {
+            // it's a fullbox
+            return 4 + super.getContentSize();
+        } else {
+            // it's an apple metabox
+            return super.getContentSize();
+        }
+    }
+
+    @Override
+    public long getNumOfBytesToFirstChild() {
+        if (isMp4Box()) {
+            // it's a fullbox
+            return 12;
+        } else {
+            // it's an apple metabox
+            return 8;
+        }
+    }
+
+    @Override
+    public void _parseDetails(ByteBuffer content) {
+        int pos = content.position();
+        content.get(new byte[4]);
+        String isHdlr = IsoTypeReader.read4cc(content);
+        if ("hdlr".equals(isHdlr)) {
+            //  this is apple bullshit - it's NO FULLBOX
+            content.position(pos);
+            version = -1;
+            flags = -1;
+        } else {
+            content.position(pos);
+            version = IsoTypeReader.readUInt8(content);
+            flags = IsoTypeReader.readUInt24(content);
+        }
+        while (content.remaining() >= 8) {
+            try {
+                boxes.add(boxParser.parseBox(new ByteBufferByteChannel(content), this));
+            } catch (IOException e) {
+                throw new RuntimeException("Sebastian needs to fix 7518765283");
+            }
+        }
+        if (content.remaining() > 0) {
+            throw new RuntimeException("Sebastian needs to fix it 90732r26537");
+        }
+    }
+
+    @Override
+    protected void getContent(ByteBuffer byteBuffer) {
+        if (isMp4Box()) {
+            IsoTypeWriter.writeUInt8(byteBuffer, version);
+            IsoTypeWriter.writeUInt24(byteBuffer, flags);
+        }
+        writeChildBoxes(byteBuffer);
+    }
+
+
+    public boolean isMp4Box() {
+        return version != -1 && flags != -1;
+    }
+
+    public void setMp4Box(boolean mp4) {
+        if (mp4) {
+            version = 0;
+            flags = 0;
+        } else {
+            version = -1;
+            flags = -1;
+        }
+    }
+}
diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/MovieBox.java b/isoparser/src/main/java/com/coremedia/iso/boxes/MovieBox.java
new file mode 100644
index 0000000..3aff7d8
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/MovieBox.java
@@ -0,0 +1,67 @@
+/*  
+ * Copyright 2008 CoreMedia AG, Hamburg
+ *
+ * Licensed under the Apache License, Version 2.0 (the License); 
+ * you may not use this file except in compliance with the License. 
+ * You may obtain a copy of the License at 
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0 
+ * 
+ * Unless required by applicable law or agreed to in writing, software 
+ * distributed under the License is distributed on an AS IS BASIS, 
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+ * See the License for the specific language governing permissions and 
+ * limitations under the License. 
+ */
+
+package com.coremedia.iso.boxes;
+
+
+import com.googlecode.mp4parser.AbstractBox;
+import com.googlecode.mp4parser.AbstractContainerBox;
+
+import java.util.List;
+
+/**
+ * The metadata for a presentation is stored in the single Movie Box which occurs at the top-level of a file.
+ * Normally this box is close to the beginning or end of the file, though this is not required.
+ */
+public class MovieBox extends AbstractContainerBox {
+    public static final String TYPE = "moov";
+
+    public MovieBox() {
+        super(TYPE);
+    }
+
+    public int getTrackCount() {
+        return getBoxes(TrackBox.class).size();
+    }
+
+
+    /**
+     * Returns the track numbers associated with this <code>MovieBox</code>.
+     *
+     * @return the tracknumbers (IDs) of the tracks in their order of appearance in the file
+     */
+    public long[] getTrackNumbers() {
+
+        List<TrackBox> trackBoxes = this.getBoxes(TrackBox.class);
+        long[] trackNumbers = new long[trackBoxes.size()];
+        for (int trackCounter = 0; trackCounter < trackBoxes.size(); trackCounter++) {
+            AbstractBox trackBoxe = trackBoxes.get(trackCounter);
+            TrackBox trackBox = (TrackBox) trackBoxe;
+            trackNumbers[trackCounter] = trackBox.getTrackHeaderBox().getTrackId();
+        }
+        return trackNumbers;
+    }
+
+    public MovieHeaderBox getMovieHeaderBox() {
+        for (Box box : boxes) {
+            if (box instanceof MovieHeaderBox) {
+                return (MovieHeaderBox) box;
+            }
+        }
+        return null;
+    }
+
+}
diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/MovieHeaderBox.java b/isoparser/src/main/java/com/coremedia/iso/boxes/MovieHeaderBox.java
new file mode 100644
index 0000000..30fbe8c
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/MovieHeaderBox.java
@@ -0,0 +1,278 @@
+/*  
+ * Copyright 2008 CoreMedia AG, Hamburg
+ *
+ * Licensed under the Apache License, Version 2.0 (the License); 
+ * you may not use this file except in compliance with the License. 
+ * You may obtain a copy of the License at 
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0 
+ * 
+ * Unless required by applicable law or agreed to in writing, software 
+ * distributed under the License is distributed on an AS IS BASIS, 
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+ * See the License for the specific language governing permissions and 
+ * limitations under the License. 
+ */
+
+package com.coremedia.iso.boxes;
+
+import com.coremedia.iso.IsoTypeReader;
+import com.coremedia.iso.IsoTypeWriter;
+import com.googlecode.mp4parser.AbstractFullBox;
+
+import java.nio.ByteBuffer;
+
+/**
+ * <code>
+ * Box Type: 'mvhd'<br>
+ * Container: {@link MovieBox} ('moov')<br>
+ * Mandatory: Yes<br>
+ * Quantity: Exactly one<br><br>
+ * </code>
+ * This box defines overall information which is media-independent, and relevant to the entire presentation
+ * considered as a whole.
+ */
+public class MovieHeaderBox extends AbstractFullBox {
+    private long creationTime;
+    private long modificationTime;
+    private long timescale;
+    private long duration;
+    private double rate = 1.0;
+    private float volume = 1.0f;
+    private long[] matrix = new long[]{0x00010000, 0, 0, 0, 0x00010000, 0, 0, 0, 0x40000000};
+    private long nextTrackId;
+
+    private int previewTime;
+    private int previewDuration;
+    private int posterTime;
+    private int selectionTime;
+    private int selectionDuration;
+    private int currentTime;
+
+
+    public static final String TYPE = "mvhd";
+
+    public MovieHeaderBox() {
+        super(TYPE);
+    }
+
+    public long getCreationTime() {
+        return creationTime;
+    }
+
+    public long getModificationTime() {
+        return modificationTime;
+    }
+
+    public long getTimescale() {
+        return timescale;
+    }
+
+    public long getDuration() {
+        return duration;
+    }
+
+    public double getRate() {
+        return rate;
+    }
+
+    public float getVolume() {
+        return volume;
+    }
+
+    public long[] getMatrix() {
+        return matrix;
+    }
+
+    public long getNextTrackId() {
+        return nextTrackId;
+    }
+
+    protected long getContentSize() {
+        long contentSize = 4;
+        if (getVersion() == 1) {
+            contentSize += 28;
+        } else {
+            contentSize += 16;
+        }
+        contentSize += 80;
+        return contentSize;
+    }
+
+    @Override
+    public void _parseDetails(ByteBuffer content) {
+        parseVersionAndFlags(content);
+        if (getVersion() == 1) {
+            creationTime = IsoTypeReader.readUInt64(content);
+            modificationTime = IsoTypeReader.readUInt64(content);
+            timescale = IsoTypeReader.readUInt32(content);
+            duration = IsoTypeReader.readUInt64(content);
+        } else {
+            creationTime = IsoTypeReader.readUInt32(content);
+            modificationTime = IsoTypeReader.readUInt32(content);
+            timescale = IsoTypeReader.readUInt32(content);
+            duration = IsoTypeReader.readUInt32(content);
+        }
+        rate = IsoTypeReader.readFixedPoint1616(content);
+        volume = IsoTypeReader.readFixedPoint88(content);
+        IsoTypeReader.readUInt16(content);
+        IsoTypeReader.readUInt32(content);
+        IsoTypeReader.readUInt32(content);
+        matrix = new long[9];
+        for (int i = 0; i < 9; i++) {
+            matrix[i] = IsoTypeReader.readUInt32(content);
+        }
+
+        previewTime = content.getInt();
+        previewDuration = content.getInt();
+        posterTime = content.getInt();
+        selectionTime = content.getInt();
+        selectionDuration = content.getInt();
+        currentTime = content.getInt();
+
+        nextTrackId = IsoTypeReader.readUInt32(content);
+
+    }
+
+    public String toString() {
+        StringBuilder result = new StringBuilder();
+        result.append("MovieHeaderBox[");
+        result.append("creationTime=").append(getCreationTime());
+        result.append(";");
+        result.append("modificationTime=").append(getModificationTime());
+        result.append(";");
+        result.append("timescale=").append(getTimescale());
+        result.append(";");
+        result.append("duration=").append(getDuration());
+        result.append(";");
+        result.append("rate=").append(getRate());
+        result.append(";");
+        result.append("volume=").append(getVolume());
+        for (int i = 0; i < matrix.length; i++) {
+            result.append(";");
+            result.append("matrix").append(i).append("=").append(matrix[i]);
+        }
+        result.append(";");
+        result.append("nextTrackId=").append(getNextTrackId());
+        result.append("]");
+        return result.toString();
+    }
+
+
+    @Override
+    protected void getContent(ByteBuffer byteBuffer) {
+        writeVersionAndFlags(byteBuffer);
+        if (getVersion() == 1) {
+            IsoTypeWriter.writeUInt64(byteBuffer, creationTime);
+            IsoTypeWriter.writeUInt64(byteBuffer, modificationTime);
+            IsoTypeWriter.writeUInt32(byteBuffer, timescale);
+            IsoTypeWriter.writeUInt64(byteBuffer, duration);
+        } else {
+            IsoTypeWriter.writeUInt32(byteBuffer, creationTime);
+            IsoTypeWriter.writeUInt32(byteBuffer, modificationTime);
+            IsoTypeWriter.writeUInt32(byteBuffer, timescale);
+            IsoTypeWriter.writeUInt32(byteBuffer, duration);
+        }
+        IsoTypeWriter.writeFixedPont1616(byteBuffer, rate);
+        IsoTypeWriter.writeFixedPont88(byteBuffer, volume);
+        IsoTypeWriter.writeUInt16(byteBuffer, 0);
+        IsoTypeWriter.writeUInt32(byteBuffer, 0);
+        IsoTypeWriter.writeUInt32(byteBuffer, 0);
+
+
+        for (int i = 0; i < 9; i++) {
+            IsoTypeWriter.writeUInt32(byteBuffer, matrix[i]);
+        }
+
+
+        byteBuffer.putInt(previewTime);
+        byteBuffer.putInt(previewDuration);
+        byteBuffer.putInt(posterTime);
+        byteBuffer.putInt(selectionTime);
+        byteBuffer.putInt(selectionDuration);
+        byteBuffer.putInt(currentTime);
+
+        IsoTypeWriter.writeUInt32(byteBuffer, nextTrackId);
+    }
+
+
+    public void setCreationTime(long creationTime) {
+        this.creationTime = creationTime;
+    }
+
+    public void setModificationTime(long modificationTime) {
+        this.modificationTime = modificationTime;
+    }
+
+    public void setTimescale(long timescale) {
+        this.timescale = timescale;
+    }
+
+    public void setDuration(long duration) {
+        this.duration = duration;
+    }
+
+    public void setRate(double rate) {
+        this.rate = rate;
+    }
+
+    public void setVolume(float volume) {
+        this.volume = volume;
+    }
+
+    public void setMatrix(long[] matrix) {
+        this.matrix = matrix;
+    }
+
+    public void setNextTrackId(long nextTrackId) {
+        this.nextTrackId = nextTrackId;
+    }
+
+    public int getPreviewTime() {
+        return previewTime;
+    }
+
+    public void setPreviewTime(int previewTime) {
+        this.previewTime = previewTime;
+    }
+
+    public int getPreviewDuration() {
+        return previewDuration;
+    }
+
+    public void setPreviewDuration(int previewDuration) {
+        this.previewDuration = previewDuration;
+    }
+
+    public int getPosterTime() {
+        return posterTime;
+    }
+
+    public void setPosterTime(int posterTime) {
+        this.posterTime = posterTime;
+    }
+
+    public int getSelectionTime() {
+        return selectionTime;
+    }
+
+    public void setSelectionTime(int selectionTime) {
+        this.selectionTime = selectionTime;
+    }
+
+    public int getSelectionDuration() {
+        return selectionDuration;
+    }
+
+    public void setSelectionDuration(int selectionDuration) {
+        this.selectionDuration = selectionDuration;
+    }
+
+    public int getCurrentTime() {
+        return currentTime;
+    }
+
+    public void setCurrentTime(int currentTime) {
+        this.currentTime = currentTime;
+    }
+}
diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/NullMediaHeaderBox.java b/isoparser/src/main/java/com/coremedia/iso/boxes/NullMediaHeaderBox.java
new file mode 100644
index 0000000..562f8d4
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/NullMediaHeaderBox.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2011 Sebastian Annies, Hamburg, Germany
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.coremedia.iso.boxes;
+
+import java.nio.ByteBuffer;
+
+/**
+ * Streams other than visual and audio (e.g., timed metadata streams) may use a
+ * Null Media Header Box.
+ */
+public class NullMediaHeaderBox extends AbstractMediaHeaderBox {
+    public NullMediaHeaderBox() {
+        super("nmhd");
+    }
+
+    @Override
+    protected long getContentSize() {
+        return 4;
+    }
+
+    @Override
+    public void _parseDetails(ByteBuffer content) {
+        parseVersionAndFlags(content);
+    }
+
+    @Override
+    protected void getContent(ByteBuffer byteBuffer) {
+        writeVersionAndFlags(byteBuffer);
+    }
+}
diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/ObjectDescriptorBox.java b/isoparser/src/main/java/com/coremedia/iso/boxes/ObjectDescriptorBox.java
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/ObjectDescriptorBox.java
diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/OmaDrmAccessUnitFormatBox.java b/isoparser/src/main/java/com/coremedia/iso/boxes/OmaDrmAccessUnitFormatBox.java
new file mode 100644
index 0000000..020881b
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/OmaDrmAccessUnitFormatBox.java
@@ -0,0 +1,87 @@
+/*  
+ * Copyright 2008 CoreMedia AG, Hamburg
+ *
+ * Licensed under the Apache License, Version 2.0 (the License); 
+ * you may not use this file except in compliance with the License. 
+ * You may obtain a copy of the License at 
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0 
+ * 
+ * Unless required by applicable law or agreed to in writing, software 
+ * distributed under the License is distributed on an AS IS BASIS, 
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+ * See the License for the specific language governing permissions and 
+ * limitations under the License. 
+ */
+
+package com.coremedia.iso.boxes;
+
+import com.coremedia.iso.IsoTypeReader;
+import com.coremedia.iso.IsoTypeWriter;
+import com.googlecode.mp4parser.AbstractFullBox;
+
+import java.nio.ByteBuffer;
+
+/**
+ * Describes the format of media access units in PDCF files.
+ */
+public final class OmaDrmAccessUnitFormatBox extends AbstractFullBox {
+    public static final String TYPE = "odaf";
+
+    private boolean selectiveEncryption;
+    private byte allBits;
+
+    private int keyIndicatorLength;
+    private int initVectorLength;
+
+    protected long getContentSize() {
+        return 7;
+    }
+
+    public OmaDrmAccessUnitFormatBox() {
+        super("odaf");
+    }
+
+    public boolean isSelectiveEncryption() {
+        return selectiveEncryption;
+    }
+
+    public int getKeyIndicatorLength() {
+        return keyIndicatorLength;
+    }
+
+    public int getInitVectorLength() {
+        return initVectorLength;
+    }
+
+    public void setInitVectorLength(int initVectorLength) {
+        this.initVectorLength = initVectorLength;
+    }
+
+    public void setKeyIndicatorLength(int keyIndicatorLength) {
+        this.keyIndicatorLength = keyIndicatorLength;
+    }
+
+    public void setAllBits(byte allBits) {
+        this.allBits = allBits;
+        selectiveEncryption = (allBits & 0x80) == 0x80;
+    }
+
+    @Override
+    public void _parseDetails(ByteBuffer content) {
+        parseVersionAndFlags(content);
+        allBits = (byte) IsoTypeReader.readUInt8(content);
+        selectiveEncryption = (allBits & 0x80) == 0x80;
+        keyIndicatorLength = IsoTypeReader.readUInt8(content);
+        initVectorLength = IsoTypeReader.readUInt8(content);
+    }
+
+    @Override
+    protected void getContent(ByteBuffer byteBuffer) {
+        writeVersionAndFlags(byteBuffer);
+        IsoTypeWriter.writeUInt8(byteBuffer, allBits);
+        IsoTypeWriter.writeUInt8(byteBuffer, keyIndicatorLength);
+        IsoTypeWriter.writeUInt8(byteBuffer, initVectorLength);
+    }
+
+}
diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/OriginalFormatBox.java b/isoparser/src/main/java/com/coremedia/iso/boxes/OriginalFormatBox.java
new file mode 100644
index 0000000..004c6c2
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/OriginalFormatBox.java
@@ -0,0 +1,69 @@
+/*  
+ * Copyright 2008 CoreMedia AG, Hamburg
+ *
+ * Licensed under the Apache License, Version 2.0 (the License); 
+ * you may not use this file except in compliance with the License. 
+ * You may obtain a copy of the License at 
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0 
+ * 
+ * Unless required by applicable law or agreed to in writing, software 
+ * distributed under the License is distributed on an AS IS BASIS, 
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+ * See the License for the specific language governing permissions and 
+ * limitations under the License. 
+ */
+
+package com.coremedia.iso.boxes;
+
+import com.coremedia.iso.IsoFile;
+import com.coremedia.iso.IsoTypeReader;
+import com.googlecode.mp4parser.AbstractBox;
+
+import java.nio.ByteBuffer;
+
+/**
+ * The Original Format Box contains the four-character-code of the original untransformed sample description.
+ * See ISO/IEC 14496-12 for details.
+ *
+ * @see ProtectionSchemeInformationBox
+ */
+
+public class OriginalFormatBox extends AbstractBox {
+    public static final String TYPE = "frma";
+
+    private String dataFormat = "    ";
+
+    public OriginalFormatBox() {
+        super("frma");
+    }
+
+    public String getDataFormat() {
+        return dataFormat;
+    }
+
+
+    public void setDataFormat(String dataFormat) {
+        assert dataFormat.length() == 4;
+        this.dataFormat = dataFormat;
+    }
+
+    protected long getContentSize() {
+        return 4;
+    }
+
+    @Override
+    public void _parseDetails(ByteBuffer content) {
+        dataFormat = IsoTypeReader.read4cc(content);
+    }
+
+    @Override
+    protected void getContent(ByteBuffer byteBuffer) {
+        byteBuffer.put(IsoFile.fourCCtoBytes(dataFormat));
+    }
+
+
+    public String toString() {
+        return "OriginalFormatBox[dataFormat=" + getDataFormat() + "]";
+    }
+}
diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/PerformerBox.java b/isoparser/src/main/java/com/coremedia/iso/boxes/PerformerBox.java
new file mode 100644
index 0000000..cf702dc
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/PerformerBox.java
@@ -0,0 +1,78 @@
+/*  
+ * Copyright 2008 CoreMedia AG, Hamburg
+ *
+ * Licensed under the Apache License, Version 2.0 (the License); 
+ * you may not use this file except in compliance with the License. 
+ * You may obtain a copy of the License at 
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0 
+ * 
+ * Unless required by applicable law or agreed to in writing, software 
+ * distributed under the License is distributed on an AS IS BASIS, 
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+ * See the License for the specific language governing permissions and 
+ * limitations under the License. 
+ */
+
+package com.coremedia.iso.boxes;
+
+import com.coremedia.iso.IsoTypeReader;
+import com.coremedia.iso.IsoTypeWriter;
+import com.coremedia.iso.Utf8;
+import com.googlecode.mp4parser.AbstractFullBox;
+
+import java.nio.ByteBuffer;
+
+/**
+ * Used to give information about the performer. Mostly used in confunction with music files.
+ * See 3GPP 26.234 for details.
+ */
+public class PerformerBox extends AbstractFullBox {
+    public static final String TYPE = "perf";
+
+    private String language;
+    private String performer;
+
+    public PerformerBox() {
+        super(TYPE);
+    }
+
+    public String getLanguage() {
+        return language;
+    }
+
+    public String getPerformer() {
+        return performer;
+    }
+
+    public void setLanguage(String language) {
+        this.language = language;
+    }
+
+    public void setPerformer(String performer) {
+        this.performer = performer;
+    }
+
+    protected long getContentSize() {
+        return 6 + Utf8.utf8StringLengthInBytes(performer) + 1;
+    }
+
+    @Override
+    protected void getContent(ByteBuffer byteBuffer) {
+        writeVersionAndFlags(byteBuffer);
+        IsoTypeWriter.writeIso639(byteBuffer, language);
+        byteBuffer.put(Utf8.convert(performer));
+        byteBuffer.put((byte) 0);
+    }
+
+    @Override
+    public void _parseDetails(ByteBuffer content) {
+        parseVersionAndFlags(content);
+        language = IsoTypeReader.readIso639(content);
+        performer = IsoTypeReader.readString(content);
+    }
+
+    public String toString() {
+        return "PerformerBox[language=" + getLanguage() + ";performer=" + getPerformer() + "]";
+    }
+}
diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/ProgressiveDownloadInformationBox.java b/isoparser/src/main/java/com/coremedia/iso/boxes/ProgressiveDownloadInformationBox.java
new file mode 100644
index 0000000..7acd7ed
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/ProgressiveDownloadInformationBox.java
@@ -0,0 +1,95 @@
+package com.coremedia.iso.boxes;
+
+import com.coremedia.iso.IsoTypeReader;
+import com.coremedia.iso.IsoTypeWriter;
+import com.googlecode.mp4parser.AbstractFullBox;
+
+import java.nio.ByteBuffer;
+import java.util.Collections;
+import java.util.LinkedList;
+import java.util.List;
+
+public class ProgressiveDownloadInformationBox extends AbstractFullBox {
+
+
+    List<Entry> entries = Collections.emptyList();
+
+    public ProgressiveDownloadInformationBox() {
+        super("pdin");
+    }
+
+    @Override
+    protected long getContentSize() {
+        return 4 + entries.size() * 8;
+    }
+
+    @Override
+    protected void getContent(ByteBuffer byteBuffer) {
+        writeVersionAndFlags(byteBuffer);
+        for (Entry entry : entries) {
+            IsoTypeWriter.writeUInt32(byteBuffer, entry.getRate());
+            IsoTypeWriter.writeUInt32(byteBuffer, entry.getInitialDelay());
+        }
+    }
+
+    public List<Entry> getEntries() {
+        return entries;
+    }
+
+    public void setEntries(List<Entry> entries) {
+        this.entries = entries;
+    }
+
+    @Override
+    public void _parseDetails(ByteBuffer content) {
+        parseVersionAndFlags(content);
+        entries = new LinkedList<Entry>();
+        while (content.remaining() >= 8) {
+            Entry entry = new Entry(IsoTypeReader.readUInt32(content), IsoTypeReader.readUInt32(content));
+            entries.add(entry);
+        }
+    }
+
+
+    public static class Entry {
+        long rate;
+        long initialDelay;
+
+        public Entry(long rate, long initialDelay) {
+            this.rate = rate;
+            this.initialDelay = initialDelay;
+        }
+
+        public long getRate() {
+            return rate;
+        }
+
+        public void setRate(long rate) {
+            this.rate = rate;
+        }
+
+        public long getInitialDelay() {
+            return initialDelay;
+        }
+
+        public void setInitialDelay(long initialDelay) {
+            this.initialDelay = initialDelay;
+        }
+
+        @Override
+        public String toString() {
+            return "Entry{" +
+                    "rate=" + rate +
+                    ", initialDelay=" + initialDelay +
+                    '}';
+        }
+    }
+
+    @Override
+    public String toString() {
+        return "ProgressiveDownloadInfoBox{" +
+                "entries=" + entries +
+                '}';
+    }
+
+}
\ No newline at end of file
diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/ProtectionSchemeInformationBox.java b/isoparser/src/main/java/com/coremedia/iso/boxes/ProtectionSchemeInformationBox.java
new file mode 100644
index 0000000..87069d3
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/ProtectionSchemeInformationBox.java
@@ -0,0 +1,42 @@
+/*  
+ * Copyright 2008 CoreMedia AG, Hamburg
+ *
+ * Licensed under the Apache License, Version 2.0 (the License); 
+ * you may not use this file except in compliance with the License. 
+ * You may obtain a copy of the License at 
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0 
+ * 
+ * Unless required by applicable law or agreed to in writing, software 
+ * distributed under the License is distributed on an AS IS BASIS, 
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+ * See the License for the specific language governing permissions and 
+ * limitations under the License. 
+ */
+
+package com.coremedia.iso.boxes;
+
+import com.googlecode.mp4parser.AbstractContainerBox;
+
+/**
+ * The <code>ProtectionSchemeInformationBox</code> contains all the information required both
+ * to understand the encryption transform applied and its parameters, and also to find other
+ * information such as the kind and location of the key management system. It also documents the
+ * the original (unencrypted) format of the media. The <code>ProtectionSchemeInformationBox</code>
+ * is a container box. It is mandatory in a sample entry that uses a code idicating a
+ * protected stream.
+ *
+ * @see com.coremedia.iso.boxes.odf.OmaDrmKeyManagenentSystemBox
+ * @see com.coremedia.iso.boxes.sampleentry.AudioSampleEntry#TYPE_ENCRYPTED
+ * @see com.coremedia.iso.boxes.sampleentry.VisualSampleEntry#TYPE_ENCRYPTED
+ */
+public class ProtectionSchemeInformationBox extends AbstractContainerBox {
+    public static final String TYPE = "sinf";
+
+    public ProtectionSchemeInformationBox() {
+        super(TYPE);
+
+    }
+
+
+}
diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/RatingBox.java b/isoparser/src/main/java/com/coremedia/iso/boxes/RatingBox.java
new file mode 100644
index 0000000..ad32749
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/RatingBox.java
@@ -0,0 +1,124 @@
+/*  
+ * Copyright 2008 CoreMedia AG, Hamburg
+ *
+ * Licensed under the Apache License, Version 2.0 (the License); 
+ * you may not use this file except in compliance with the License. 
+ * You may obtain a copy of the License at 
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0 
+ * 
+ * Unless required by applicable law or agreed to in writing, software 
+ * distributed under the License is distributed on an AS IS BASIS, 
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+ * See the License for the specific language governing permissions and 
+ * limitations under the License. 
+ */
+
+package com.coremedia.iso.boxes;
+
+import com.coremedia.iso.IsoFile;
+import com.coremedia.iso.IsoTypeReader;
+import com.coremedia.iso.IsoTypeWriter;
+import com.coremedia.iso.Utf8;
+import com.googlecode.mp4parser.AbstractFullBox;
+
+import java.nio.ByteBuffer;
+
+
+/**
+ * Contained a the <code>UserDataBox</code> and containing information about the media's rating. E.g.
+ * PG13or FSK16.
+ */
+public class RatingBox extends AbstractFullBox {
+    public static final String TYPE = "rtng";
+
+    private String ratingEntity;
+    private String ratingCriteria;
+    private String language;
+    private String ratingInfo;
+
+    public RatingBox() {
+        super(TYPE);
+    }
+
+
+    public void setRatingEntity(String ratingEntity) {
+        this.ratingEntity = ratingEntity;
+    }
+
+    public void setRatingCriteria(String ratingCriteria) {
+        this.ratingCriteria = ratingCriteria;
+    }
+
+    public void setLanguage(String language) {
+        this.language = language;
+    }
+
+    public void setRatingInfo(String ratingInfo) {
+        this.ratingInfo = ratingInfo;
+    }
+
+    public String getLanguage() {
+        return language;
+    }
+
+    /**
+     * Gets a four-character code that indicates the rating entity grading the asset, e.g., 'BBFC'. The values of this
+     * field should follow common names of worldwide movie rating systems, such as those mentioned in
+     * [http://www.movie-ratings.net/, October 2002].
+     *
+     * @return the rating organization
+     */
+    public String getRatingEntity() {
+        return ratingEntity;
+    }
+
+    /**
+     * Gets the four-character code that indicates which rating criteria are being used for the corresponding rating
+     * entity, e.g., 'PG13'.
+     *
+     * @return the actual rating
+     */
+    public String getRatingCriteria() {
+        return ratingCriteria;
+    }
+
+    public String getRatingInfo() {
+        return ratingInfo;
+    }
+
+    protected long getContentSize() {
+        return 15 + Utf8.utf8StringLengthInBytes(ratingInfo);
+    }
+
+    @Override
+    public void _parseDetails(ByteBuffer content) {
+        parseVersionAndFlags(content);
+        ratingEntity = IsoTypeReader.read4cc(content);
+        ratingCriteria = IsoTypeReader.read4cc(content);
+        language = IsoTypeReader.readIso639(content);
+        ratingInfo = IsoTypeReader.readString(content);
+
+    }
+
+    @Override
+    protected void getContent(ByteBuffer byteBuffer) {
+        writeVersionAndFlags(byteBuffer);
+        byteBuffer.put(IsoFile.fourCCtoBytes(ratingEntity));
+        byteBuffer.put(IsoFile.fourCCtoBytes(ratingCriteria));
+        IsoTypeWriter.writeIso639(byteBuffer, language);
+        byteBuffer.put(Utf8.convert(ratingInfo));
+        byteBuffer.put((byte) 0);
+    }
+
+    public String toString() {
+        StringBuilder buffer = new StringBuilder();
+        buffer.append("RatingBox[language=").append(getLanguage());
+        buffer.append("ratingEntity=").append(getRatingEntity());
+        buffer.append(";ratingCriteria=").append(getRatingCriteria());
+        buffer.append(";language=").append(getLanguage());
+        buffer.append(";ratingInfo=").append(getRatingInfo());
+        buffer.append("]");
+        return buffer.toString();
+    }
+}
diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/RecordingYearBox.java b/isoparser/src/main/java/com/coremedia/iso/boxes/RecordingYearBox.java
new file mode 100644
index 0000000..e2dcbd9
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/RecordingYearBox.java
@@ -0,0 +1,63 @@
+/*  
+ * Copyright 2008 CoreMedia AG, Hamburg
+ *
+ * Licensed under the Apache License, Version 2.0 (the License); 
+ * you may not use this file except in compliance with the License. 
+ * You may obtain a copy of the License at 
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0 
+ * 
+ * Unless required by applicable law or agreed to in writing, software 
+ * distributed under the License is distributed on an AS IS BASIS, 
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+ * See the License for the specific language governing permissions and 
+ * limitations under the License. 
+ */
+
+package com.coremedia.iso.boxes;
+
+import com.coremedia.iso.IsoTypeReader;
+import com.coremedia.iso.IsoTypeWriter;
+import com.googlecode.mp4parser.AbstractFullBox;
+
+import java.nio.ByteBuffer;
+
+/**
+ *
+ */
+public class RecordingYearBox extends AbstractFullBox {
+    public static final String TYPE = "yrrc";
+
+    int recordingYear;
+
+    public RecordingYearBox() {
+        super(TYPE);
+    }
+
+
+    protected long getContentSize() {
+        return 6;
+    }
+
+    public int getRecordingYear() {
+        return recordingYear;
+    }
+
+    public void setRecordingYear(int recordingYear) {
+        this.recordingYear = recordingYear;
+    }
+
+
+    @Override
+    public void _parseDetails(ByteBuffer content) {
+        parseVersionAndFlags(content);
+        recordingYear = IsoTypeReader.readUInt16(content);
+    }
+
+    @Override
+    protected void getContent(ByteBuffer byteBuffer) {
+        writeVersionAndFlags(byteBuffer);
+        IsoTypeWriter.writeUInt16(byteBuffer, recordingYear);
+    }
+
+}
diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/SampleAuxiliaryInformationOffsetsBox.java b/isoparser/src/main/java/com/coremedia/iso/boxes/SampleAuxiliaryInformationOffsetsBox.java
new file mode 100644
index 0000000..517bc03
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/SampleAuxiliaryInformationOffsetsBox.java
@@ -0,0 +1,127 @@
+/*
+ * Copyright 2009 castLabs GmbH, Berlin
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.coremedia.iso.boxes;
+
+import com.coremedia.iso.IsoTypeReader;
+import com.coremedia.iso.IsoTypeWriter;
+import com.googlecode.mp4parser.AbstractFullBox;
+
+import java.nio.ByteBuffer;
+import java.util.LinkedList;
+import java.util.List;
+
+import static com.googlecode.mp4parser.util.CastUtils.l2i;
+
+/*
+aligned(8) class SampleAuxiliaryInformationOffsetsBox
+            extends FullBox(‘saio’, version, flags)
+{
+            if (flags & 1) {
+                        unsigned int(32) aux_info_type;
+                        unsigned int(32) aux_info_type_parameter;
+            }
+            unsigned int(32) entry_count;
+            if ( version == 0 )
+            {
+                        unsigned int(32) offset[ entry_count ];
+            }
+            else
+            {
+                        unsigned int(64) offset[ entry_count ];
+            }
+}
+ */
+public class SampleAuxiliaryInformationOffsetsBox extends AbstractFullBox {
+    public static final String TYPE = "saio";
+
+    private List<Long> offsets = new LinkedList<Long>();
+    private long auxInfoType;
+    private long auxInfoTypeParameter;
+
+    public SampleAuxiliaryInformationOffsetsBox() {
+        super(TYPE);
+    }
+
+    @Override
+    protected long getContentSize() {
+        return 8 + (getVersion() == 0 ? 4 * offsets.size() : 8 * offsets.size()) + ((getFlags() & 1) == 1 ? 8 : 0);
+    }
+
+    @Override
+    protected void getContent(ByteBuffer byteBuffer) {
+        writeVersionAndFlags(byteBuffer);
+        if ((getFlags() & 1) == 1) {
+            IsoTypeWriter.writeUInt32(byteBuffer, auxInfoType);
+            IsoTypeWriter.writeUInt32(byteBuffer, auxInfoTypeParameter);
+        }
+
+        IsoTypeWriter.writeUInt32(byteBuffer, offsets.size());
+        for (Long offset : offsets) {
+            if (getVersion() == 0) {
+                IsoTypeWriter.writeUInt32(byteBuffer, offset);
+            } else {
+                IsoTypeWriter.writeUInt64(byteBuffer, offset);
+            }
+        }
+    }
+
+    @Override
+    public void _parseDetails(ByteBuffer content) {
+        parseVersionAndFlags(content);
+
+        if ((getFlags() & 1) == 1) {
+            auxInfoType = IsoTypeReader.readUInt32(content);
+            auxInfoTypeParameter = IsoTypeReader.readUInt32(content);
+        }
+
+        int entryCount = l2i(IsoTypeReader.readUInt32(content));
+        offsets.clear();
+
+        for (int i = 0; i < entryCount; i++) {
+            if (getVersion() == 0) {
+                offsets.add(IsoTypeReader.readUInt32(content));
+            } else {
+                offsets.add(IsoTypeReader.readUInt64(content));
+            }
+        }
+    }
+
+
+    public long getAuxInfoType() {
+        return auxInfoType;
+    }
+
+    public void setAuxInfoType(long auxInfoType) {
+        this.auxInfoType = auxInfoType;
+    }
+
+    public long getAuxInfoTypeParameter() {
+        return auxInfoTypeParameter;
+    }
+
+    public void setAuxInfoTypeParameter(long auxInfoTypeParameter) {
+        this.auxInfoTypeParameter = auxInfoTypeParameter;
+    }
+
+    public List<Long> getOffsets() {
+        return offsets;
+    }
+
+    public void setOffsets(List<Long> offsets) {
+        this.offsets = offsets;
+    }
+}
diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/SampleAuxiliaryInformationSizesBox.java b/isoparser/src/main/java/com/coremedia/iso/boxes/SampleAuxiliaryInformationSizesBox.java
new file mode 100644
index 0000000..4032d01
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/SampleAuxiliaryInformationSizesBox.java
@@ -0,0 +1,145 @@
+/*
+ * Copyright 2009 castLabs GmbH, Berlin
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.coremedia.iso.boxes;
+
+import com.coremedia.iso.IsoFile;
+import com.coremedia.iso.IsoTypeReader;
+import com.coremedia.iso.IsoTypeWriter;
+import com.googlecode.mp4parser.AbstractFullBox;
+
+import java.nio.ByteBuffer;
+import java.util.LinkedList;
+import java.util.List;
+
+import static com.googlecode.mp4parser.util.CastUtils.l2i;
+
+public class SampleAuxiliaryInformationSizesBox extends AbstractFullBox {
+    public static final String TYPE = "saiz";
+
+    private int defaultSampleInfoSize;
+    private List<Short> sampleInfoSizes = new LinkedList<Short>();
+    private int sampleCount;
+    private String auxInfoType;
+    private String auxInfoTypeParameter;
+
+    public SampleAuxiliaryInformationSizesBox() {
+        super(TYPE);
+    }
+
+    @Override
+    protected long getContentSize() {
+        int size = 4;
+        if ((getFlags() & 1) == 1) {
+            size += 8;
+        }
+
+        size += 5;
+        size += defaultSampleInfoSize == 0 ? sampleInfoSizes.size() : 0;
+        return size;
+    }
+
+    @Override
+    protected void getContent(ByteBuffer byteBuffer) {
+        writeVersionAndFlags(byteBuffer);
+        if ((getFlags() & 1) == 1) {
+            byteBuffer.put(IsoFile.fourCCtoBytes(auxInfoType));
+            byteBuffer.put(IsoFile.fourCCtoBytes(auxInfoTypeParameter));
+        }
+
+        IsoTypeWriter.writeUInt8(byteBuffer, defaultSampleInfoSize);
+
+        if (defaultSampleInfoSize == 0) {
+            IsoTypeWriter.writeUInt32(byteBuffer, sampleInfoSizes.size());
+            for (short sampleInfoSize : sampleInfoSizes) {
+                IsoTypeWriter.writeUInt8(byteBuffer, sampleInfoSize);
+            }
+        } else {
+            IsoTypeWriter.writeUInt32(byteBuffer, sampleCount);
+        }
+    }
+
+    @Override
+    public void _parseDetails(ByteBuffer content) {
+        parseVersionAndFlags(content);
+        if ((getFlags() & 1) == 1) {
+            auxInfoType = IsoTypeReader.read4cc(content);
+            auxInfoTypeParameter = IsoTypeReader.read4cc(content);
+        }
+
+        defaultSampleInfoSize = (short) IsoTypeReader.readUInt8(content);
+        sampleCount = l2i(IsoTypeReader.readUInt32(content));
+
+        sampleInfoSizes.clear();
+
+        if (defaultSampleInfoSize == 0) {
+            for (int i = 0; i < sampleCount; i++) {
+                sampleInfoSizes.add((short) IsoTypeReader.readUInt8(content));
+            }
+        }
+    }
+
+    public String getAuxInfoType() {
+        return auxInfoType;
+    }
+
+    public void setAuxInfoType(String auxInfoType) {
+        this.auxInfoType = auxInfoType;
+    }
+
+    public String getAuxInfoTypeParameter() {
+        return auxInfoTypeParameter;
+    }
+
+    public void setAuxInfoTypeParameter(String auxInfoTypeParameter) {
+        this.auxInfoTypeParameter = auxInfoTypeParameter;
+    }
+
+    public int getDefaultSampleInfoSize() {
+        return defaultSampleInfoSize;
+    }
+
+    public void setDefaultSampleInfoSize(int defaultSampleInfoSize) {
+        assert defaultSampleInfoSize <= 255;
+        this.defaultSampleInfoSize = defaultSampleInfoSize;
+    }
+
+    public List<Short> getSampleInfoSizes() {
+        return sampleInfoSizes;
+    }
+
+    public void setSampleInfoSizes(List<Short> sampleInfoSizes) {
+        this.sampleInfoSizes = sampleInfoSizes;
+    }
+
+    public int getSampleCount() {
+        return sampleCount;
+    }
+
+    public void setSampleCount(int sampleCount) {
+        this.sampleCount = sampleCount;
+    }
+
+    @Override
+    public String toString() {
+        return "SampleAuxiliaryInformationSizesBox{" +
+                "defaultSampleInfoSize=" + defaultSampleInfoSize +
+                ", sampleCount=" + sampleCount +
+                ", auxInfoType='" + auxInfoType + '\'' +
+                ", auxInfoTypeParameter='" + auxInfoTypeParameter + '\'' +
+                '}';
+    }
+}
diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/SampleDependencyTypeBox.java b/isoparser/src/main/java/com/coremedia/iso/boxes/SampleDependencyTypeBox.java
new file mode 100644
index 0000000..bb38d8c
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/SampleDependencyTypeBox.java
@@ -0,0 +1,136 @@
+/*
+ * Copyright 2009 castLabs GmbH, Berlin
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.coremedia.iso.boxes;
+
+import com.coremedia.iso.IsoTypeReader;
+import com.coremedia.iso.IsoTypeWriter;
+import com.googlecode.mp4parser.AbstractFullBox;
+
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * aligned(8) class SampleDependencyTypeBox
+ * extends FullBox('sdtp', version = 0, 0) {
+ * for (i=0; i < sample_count; i++){
+ * unsigned int(2) reserved = 0;
+ * unsigned int(2) sample_depends_on;
+ * unsigned int(2) sample_is_depended_on;
+ * unsigned int(2) sample_has_redundancy;
+ * }
+ * }
+ */
+public class SampleDependencyTypeBox extends AbstractFullBox {
+    public static final String TYPE = "sdtp";
+
+    private List<Entry> entries = new ArrayList<Entry>();
+
+    public static class Entry {
+
+        public Entry(int value) {
+            this.value = value;
+        }
+
+        private int value;
+
+
+        public int getReserved() {
+            return (value >> 6) & 0x03;
+        }
+
+        public void setReserved(int res) {
+            value = (res & 0x03) << 6 | value & 0x3f;
+        }
+
+        public int getSampleDependsOn() {
+            return (value >> 4) & 0x03;
+        }
+
+        public void setSampleDependsOn(int sdo) {
+            value = (sdo & 0x03) << 4 | value & 0xcf;
+        }
+
+        public int getSampleIsDependentOn() {
+            return (value >> 2) & 0x03;
+        }
+
+        public void setSampleIsDependentOn(int sido) {
+            value = (sido & 0x03) << 2 | value & 0xf3;
+        }
+
+        public int getSampleHasRedundancy() {
+            return value & 0x03;
+        }
+
+        public void setSampleHasRedundancy(int shr) {
+            value = shr & 0x03 | value & 0xfc;
+        }
+
+        @Override
+        public String toString() {
+            return "Entry{" +
+                    "reserved=" + getReserved() +
+                    ", sampleDependsOn=" + getSampleDependsOn() +
+                    ", sampleIsDependentOn=" + getSampleIsDependentOn() +
+                    ", sampleHasRedundancy=" + getSampleHasRedundancy() +
+                    '}';
+        }
+    }
+
+    public SampleDependencyTypeBox() {
+        super(TYPE);
+    }
+
+    @Override
+    protected long getContentSize() {
+        return 4 + entries.size();
+    }
+
+    @Override
+    protected void getContent(ByteBuffer byteBuffer) {
+        writeVersionAndFlags(byteBuffer);
+        for (Entry entry : entries) {
+            IsoTypeWriter.writeUInt8(byteBuffer, entry.value);
+        }
+    }
+
+    @Override
+    public void _parseDetails(ByteBuffer content) {
+        parseVersionAndFlags(content);
+        while (content.remaining() > 0) {
+            entries.add(new Entry(IsoTypeReader.readUInt8(content)));
+        }
+    }
+
+    public List<Entry> getEntries() {
+        return entries;
+    }
+
+    public void setEntries(List<Entry> entries) {
+        this.entries = entries;
+    }
+
+    @Override
+    public String toString() {
+        final StringBuilder sb = new StringBuilder();
+        sb.append("SampleDependencyTypeBox");
+        sb.append("{entries=").append(entries);
+        sb.append('}');
+        return sb.toString();
+    }
+}
diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/SampleDescriptionBox.java b/isoparser/src/main/java/com/coremedia/iso/boxes/SampleDescriptionBox.java
new file mode 100644
index 0000000..662fa99
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/SampleDescriptionBox.java
@@ -0,0 +1,81 @@
+/*  
+ * Copyright 2008 CoreMedia AG, Hamburg
+ *
+ * Licensed under the Apache License, Version 2.0 (the License); 
+ * you may not use this file except in compliance with the License. 
+ * You may obtain a copy of the License at 
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0 
+ * 
+ * Unless required by applicable law or agreed to in writing, software 
+ * distributed under the License is distributed on an AS IS BASIS, 
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+ * See the License for the specific language governing permissions and 
+ * limitations under the License. 
+ */
+
+package com.coremedia.iso.boxes;
+
+import com.coremedia.iso.IsoTypeWriter;
+import com.coremedia.iso.boxes.sampleentry.SampleEntry;
+import com.googlecode.mp4parser.FullContainerBox;
+
+import java.nio.ByteBuffer;
+
+/**
+ * The sample description table gives detailed information about the coding type used, and any initialization
+ * information needed for that coding. <br>
+ * The information stored in the sample description box after the entry-count is both track-type specific as
+ * documented here, and can also have variants within a track type (e.g. different codings may use different
+ * specific information after some common fields, even within a video track).<br>
+ * For video tracks, a VisualSampleEntry is used; for audio tracks, an AudioSampleEntry. Hint tracks use an
+ * entry format specific to their protocol, with an appropriate name. Timed Text tracks use a TextSampleEntry
+ * For hint tracks, the sample description contains appropriate declarative data for the streaming protocol being
+ * used, and the format of the hint track. The definition of the sample description is specific to the protocol.
+ * Multiple descriptions may be used within a track.<br>
+ * The 'protocol' and 'codingname' fields are registered identifiers that uniquely identify the streaming protocol or
+ * compression format decoder to be used. A given protocol or codingname may have optional or required
+ * extensions to the sample description (e.g. codec initialization parameters). All such extensions shall be within
+ * boxes; these boxes occur after the required fields. Unrecognized boxes shall be ignored.
+ * <br>
+ * Defined in ISO/IEC 14496-12
+ *
+ * @see com.coremedia.iso.boxes.sampleentry.VisualSampleEntry
+ * @see com.coremedia.iso.boxes.sampleentry.TextSampleEntry
+ * @see com.coremedia.iso.boxes.sampleentry.AudioSampleEntry
+ */
+public class SampleDescriptionBox extends FullContainerBox {
+    public static final String TYPE = "stsd";
+
+    public SampleDescriptionBox() {
+        super(TYPE);
+    }
+
+    @Override
+    protected long getContentSize() {
+        return super.getContentSize() + 4;
+    }
+
+    @Override
+    public void _parseDetails(ByteBuffer content) {
+        parseVersionAndFlags(content);
+        content.get(new byte[4]);
+        parseChildBoxes(content);
+    }
+
+    @Override
+    protected void getContent(ByteBuffer byteBuffer) {
+        writeVersionAndFlags(byteBuffer);
+        IsoTypeWriter.writeUInt32(byteBuffer, boxes.size());
+        writeChildBoxes(byteBuffer);
+    }
+
+    public SampleEntry getSampleEntry() {
+        for (Box box : boxes) {
+            if (box instanceof SampleEntry) {
+                return (SampleEntry) box;
+            }
+        }
+        return null;
+    }
+}
diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/SampleSizeBox.java b/isoparser/src/main/java/com/coremedia/iso/boxes/SampleSizeBox.java
new file mode 100644
index 0000000..3bc1df0
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/SampleSizeBox.java
@@ -0,0 +1,121 @@
+/*  
+ * Copyright 2008 CoreMedia AG, Hamburg
+ *
+ * Licensed under the Apache License, Version 2.0 (the License); 
+ * you may not use this file except in compliance with the License. 
+ * You may obtain a copy of the License at 
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0 
+ * 
+ * Unless required by applicable law or agreed to in writing, software 
+ * distributed under the License is distributed on an AS IS BASIS, 
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+ * See the License for the specific language governing permissions and 
+ * limitations under the License. 
+ */
+
+package com.coremedia.iso.boxes;
+
+
+import com.coremedia.iso.IsoTypeReader;
+import com.coremedia.iso.IsoTypeWriter;
+import com.googlecode.mp4parser.AbstractFullBox;
+
+import java.nio.ByteBuffer;
+
+import static com.googlecode.mp4parser.util.CastUtils.l2i;
+
+/**
+ * This box containes the sample count and a table giving the size in bytes of each sample.
+ * Defined in ISO/IEC 14496-12.
+ */
+public class SampleSizeBox extends AbstractFullBox {
+    private long sampleSize;
+    private long[] sampleSizes = new long[0];
+    public static final String TYPE = "stsz";
+    int sampleCount;
+
+    public SampleSizeBox() {
+        super(TYPE);
+    }
+
+    /**
+     * Returns the field sample size.
+     * If sampleSize > 0 every sample has the same size.
+     * If sampleSize == 0 the samples have different size as stated in the sampleSizes field.
+     *
+     * @return the sampleSize field
+     */
+    public long getSampleSize() {
+        return sampleSize;
+    }
+
+    public void setSampleSize(long sampleSize) {
+        this.sampleSize = sampleSize;
+    }
+
+
+    public long getSampleSizeAtIndex(int index) {
+        if (sampleSize > 0) {
+            return sampleSize;
+        } else {
+            return sampleSizes[index];
+        }
+    }
+
+    public long getSampleCount() {
+        if (sampleSize > 0) {
+            return sampleCount;
+        } else {
+            return sampleSizes.length;
+        }
+
+    }
+
+    public long[] getSampleSizes() {
+        return sampleSizes;
+    }
+
+    public void setSampleSizes(long[] sampleSizes) {
+        this.sampleSizes = sampleSizes;
+    }
+
+    protected long getContentSize() {
+        return 12 + (sampleSize == 0 ? sampleSizes.length * 4 : 0);
+    }
+
+    @Override
+    public void _parseDetails(ByteBuffer content) {
+        parseVersionAndFlags(content);
+        sampleSize = IsoTypeReader.readUInt32(content);
+        sampleCount = l2i(IsoTypeReader.readUInt32(content));
+
+        if (sampleSize == 0) {
+            sampleSizes = new long[(int) sampleCount];
+
+            for (int i = 0; i < sampleCount; i++) {
+                sampleSizes[i] = IsoTypeReader.readUInt32(content);
+            }
+        }
+    }
+
+    @Override
+    protected void getContent(ByteBuffer byteBuffer) {
+        writeVersionAndFlags(byteBuffer);
+        IsoTypeWriter.writeUInt32(byteBuffer, sampleSize);
+
+        if (sampleSize == 0) {
+            IsoTypeWriter.writeUInt32(byteBuffer, sampleSizes.length);
+            for (long sampleSize1 : sampleSizes) {
+                IsoTypeWriter.writeUInt32(byteBuffer, sampleSize1);
+            }
+        } else {
+            IsoTypeWriter.writeUInt32(byteBuffer, sampleCount);
+        }
+
+    }
+
+    public String toString() {
+        return "SampleSizeBox[sampleSize=" + getSampleSize() + ";sampleCount=" + getSampleCount() + "]";
+    }
+}
diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/SampleTableBox.java b/isoparser/src/main/java/com/coremedia/iso/boxes/SampleTableBox.java
new file mode 100644
index 0000000..33968b3
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/SampleTableBox.java
@@ -0,0 +1,124 @@
+/*  
+ * Copyright 2008 CoreMedia AG, Hamburg
+ *
+ * Licensed under the Apache License, Version 2.0 (the License); 
+ * you may not use this file except in compliance with the License. 
+ * You may obtain a copy of the License at 
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0 
+ * 
+ * Unless required by applicable law or agreed to in writing, software 
+ * distributed under the License is distributed on an AS IS BASIS, 
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+ * See the License for the specific language governing permissions and 
+ * limitations under the License. 
+ */
+
+package com.coremedia.iso.boxes;
+
+import com.googlecode.mp4parser.AbstractContainerBox;
+
+/**
+ * The sample table contains all the time and data indexing of the media samples in a track. Using the tables
+ * here, it is possible to locate samples in time, determine their type (e.g. I-frame or not), and determine their
+ * size, container, and offset into that container.  <br>
+ * If the track that contains the Sample Table Box references no data, then the Sample Table Box does not need
+ * to contain any sub-boxes (this is not a very useful media track).                                          <br>
+ * If the track that the Sample Table Box is contained in does reference data, then the following sub-boxes are
+ * required: Sample Description, Sample Size, Sample To Chunk, and Chunk Offset. Further, the Sample
+ * Description Box shall contain at least one entry. A Sample Description Box is required because it contains the
+ * data reference index field which indicates which Data Reference Box to use to retrieve the media samples.
+ * Without the Sample Description, it is not possible to determine where the media samples are stored. The Sync
+ * Sample Box is optional. If the Sync Sample Box is not present, all samples are sync samples.<br>
+ * Annex A provides a narrative description of random access using the structures defined in the Sample Table
+ * Box.
+ */
+public class SampleTableBox extends AbstractContainerBox {
+    public static final String TYPE = "stbl";
+
+    public SampleTableBox() {
+        super(TYPE);
+    }
+
+    public SampleDescriptionBox getSampleDescriptionBox() {
+        for (Box box : boxes) {
+            if (box instanceof SampleDescriptionBox) {
+                return (SampleDescriptionBox) box;
+            }
+        }
+        return null;
+    }
+
+    public SampleSizeBox getSampleSizeBox() {
+        for (Box box : boxes) {
+            if (box instanceof SampleSizeBox) {
+                return (SampleSizeBox) box;
+            }
+        }
+        return null;
+    }
+
+    public SampleToChunkBox getSampleToChunkBox() {
+        for (Box box : boxes) {
+            if (box instanceof SampleToChunkBox) {
+                return (SampleToChunkBox) box;
+            }
+        }
+        return null;
+    }
+
+    public ChunkOffsetBox getChunkOffsetBox() {
+        for (Box box : boxes) {
+            if (box instanceof ChunkOffsetBox) {
+                return (ChunkOffsetBox) box;
+            }
+        }
+        return null;
+    }
+
+    public void setChunkOffsetBox(ChunkOffsetBox b) {
+        for (int i = 0; i < boxes.size(); i++) {
+            Box box = boxes.get(i);
+            if (box instanceof ChunkOffsetBox) {
+                boxes.set(i, b);
+            }
+        }
+    }
+
+    public TimeToSampleBox getTimeToSampleBox() {
+        for (Box box : boxes) {
+            if (box instanceof TimeToSampleBox) {
+                return (TimeToSampleBox) box;
+            }
+        }
+        return null;
+    }
+
+    public SyncSampleBox getSyncSampleBox() {
+        for (Box box : boxes) {
+            if (box instanceof SyncSampleBox) {
+                return (SyncSampleBox) box;
+            }
+        }
+        return null;
+    }
+
+    public CompositionTimeToSample getCompositionTimeToSample() {
+        for (Box box : boxes) {
+            if (box instanceof CompositionTimeToSample) {
+                return (CompositionTimeToSample) box;
+            }
+        }
+        return null;
+    }
+
+    public SampleDependencyTypeBox getSampleDependencyTypeBox() {
+        for (Box box : boxes) {
+            if (box instanceof SampleDependencyTypeBox) {
+                return (SampleDependencyTypeBox) box;
+            }
+        }
+        return null;
+    }
+
+}
diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/SampleToChunkBox.java b/isoparser/src/main/java/com/coremedia/iso/boxes/SampleToChunkBox.java
new file mode 100644
index 0000000..593504d
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/SampleToChunkBox.java
@@ -0,0 +1,156 @@
+/*  
+ * Copyright 2008 CoreMedia AG, Hamburg
+ *
+ * Licensed under the Apache License, Version 2.0 (the License); 
+ * you may not use this file except in compliance with the License. 
+ * You may obtain a copy of the License at 
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0 
+ * 
+ * Unless required by applicable law or agreed to in writing, software 
+ * distributed under the License is distributed on an AS IS BASIS, 
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+ * See the License for the specific language governing permissions and 
+ * limitations under the License. 
+ */
+
+package com.coremedia.iso.boxes;
+
+import com.coremedia.iso.IsoTypeReader;
+import com.coremedia.iso.IsoTypeWriter;
+import com.googlecode.mp4parser.AbstractFullBox;
+
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+
+import static com.googlecode.mp4parser.util.CastUtils.l2i;
+
+/**
+ * Samples within the media data are grouped into chunks. Chunks can be of different sizes, and the
+ * samples within a chunk can have different sizes. This table can be used to find the chunk that
+ * contains a sample, its position, and the associated sample description. Defined in ISO/IEC 14496-12.
+ */
+public class SampleToChunkBox extends AbstractFullBox {
+    List<Entry> entries = Collections.emptyList();
+
+    public static final String TYPE = "stsc";
+
+    public SampleToChunkBox() {
+        super(TYPE);
+    }
+
+    public List<Entry> getEntries() {
+        return entries;
+    }
+
+    public void setEntries(List<Entry> entries) {
+        this.entries = entries;
+    }
+
+    protected long getContentSize() {
+        return entries.size() * 12 + 8;
+    }
+
+    @Override
+    public void _parseDetails(ByteBuffer content) {
+        parseVersionAndFlags(content);
+
+        int entryCount = l2i(IsoTypeReader.readUInt32(content));
+        entries = new ArrayList<Entry>(entryCount);
+        for (int i = 0; i < entryCount; i++) {
+            entries.add(new Entry(
+                    IsoTypeReader.readUInt32(content),
+                    IsoTypeReader.readUInt32(content),
+                    IsoTypeReader.readUInt32(content)));
+        }
+    }
+
+    @Override
+    protected void getContent(ByteBuffer byteBuffer) {
+        writeVersionAndFlags(byteBuffer);
+        IsoTypeWriter.writeUInt32(byteBuffer, entries.size());
+        for (Entry entry : entries) {
+            IsoTypeWriter.writeUInt32(byteBuffer, entry.getFirstChunk());
+            IsoTypeWriter.writeUInt32(byteBuffer, entry.getSamplesPerChunk());
+            IsoTypeWriter.writeUInt32(byteBuffer, entry.getSampleDescriptionIndex());
+        }
+    }
+
+    public String toString() {
+        return "SampleToChunkBox[entryCount=" + entries.size() + "]";
+    }
+
+    /**
+     * Decompresses the list of entries and returns the number of samples per chunk for
+     * every single chunk.
+     *
+     * @param chunkCount overall number of chunks
+     * @return number of samples per chunk
+     */
+    public long[] blowup(int chunkCount) {
+        long[] numberOfSamples = new long[chunkCount];
+        int j = 0;
+        List<SampleToChunkBox.Entry> sampleToChunkEntries = new LinkedList<Entry>(entries);
+        Collections.reverse(sampleToChunkEntries);
+        Iterator<Entry> iterator = sampleToChunkEntries.iterator();
+        SampleToChunkBox.Entry currentEntry = iterator.next();
+
+        for (int i = numberOfSamples.length; i > 1; i--) {
+            numberOfSamples[i - 1] = currentEntry.getSamplesPerChunk();
+            if (i == currentEntry.getFirstChunk()) {
+                currentEntry = iterator.next();
+            }
+        }
+        numberOfSamples[0] = currentEntry.getSamplesPerChunk();
+        return numberOfSamples;
+    }
+
+    public static class Entry {
+        long firstChunk;
+        long samplesPerChunk;
+        long sampleDescriptionIndex;
+
+        public Entry(long firstChunk, long samplesPerChunk, long sampleDescriptionIndex) {
+            this.firstChunk = firstChunk;
+            this.samplesPerChunk = samplesPerChunk;
+            this.sampleDescriptionIndex = sampleDescriptionIndex;
+        }
+
+        public long getFirstChunk() {
+            return firstChunk;
+        }
+
+        public void setFirstChunk(long firstChunk) {
+            this.firstChunk = firstChunk;
+        }
+
+        public long getSamplesPerChunk() {
+            return samplesPerChunk;
+        }
+
+        public void setSamplesPerChunk(long samplesPerChunk) {
+            this.samplesPerChunk = samplesPerChunk;
+        }
+
+        public long getSampleDescriptionIndex() {
+            return sampleDescriptionIndex;
+        }
+
+        public void setSampleDescriptionIndex(long sampleDescriptionIndex) {
+            this.sampleDescriptionIndex = sampleDescriptionIndex;
+        }
+
+        @Override
+        public String toString() {
+            return "Entry{" +
+                    "firstChunk=" + firstChunk +
+                    ", samplesPerChunk=" + samplesPerChunk +
+                    ", sampleDescriptionIndex=" + sampleDescriptionIndex +
+                    '}';
+        }
+    }
+}
diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/SchemeInformationBox.java b/isoparser/src/main/java/com/coremedia/iso/boxes/SchemeInformationBox.java
new file mode 100644
index 0000000..5e3565e
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/SchemeInformationBox.java
@@ -0,0 +1,33 @@
+/*  
+ * Copyright 2008 CoreMedia AG, Hamburg
+ *
+ * Licensed under the Apache License, Version 2.0 (the License); 
+ * you may not use this file except in compliance with the License. 
+ * You may obtain a copy of the License at 
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0 
+ * 
+ * Unless required by applicable law or agreed to in writing, software 
+ * distributed under the License is distributed on an AS IS BASIS, 
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+ * See the License for the specific language governing permissions and 
+ * limitations under the License. 
+ */
+
+package com.coremedia.iso.boxes;
+
+import com.googlecode.mp4parser.AbstractContainerBox;
+
+/**
+ * The Scheme Information Box is a container box that is only interpreted by the scheme beeing used.
+ * Any information the encryption system needs is stored here. The content of this box is a series of
+ * boxexes whose type annd format are defined by the scheme declared in the {@link com.coremedia.iso.boxes.SchemeTypeBox}.
+ */
+public class SchemeInformationBox extends AbstractContainerBox {
+    public static final String TYPE = "schi";
+
+    public SchemeInformationBox() {
+        super(TYPE);
+    }
+
+}
diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/SchemeTypeBox.java b/isoparser/src/main/java/com/coremedia/iso/boxes/SchemeTypeBox.java
new file mode 100644
index 0000000..ed517da
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/SchemeTypeBox.java
@@ -0,0 +1,101 @@
+/*  
+ * Copyright 2008 CoreMedia AG, Hamburg
+ *
+ * Licensed under the Apache License, Version 2.0 (the License); 
+ * you may not use this file except in compliance with the License. 
+ * You may obtain a copy of the License at 
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0 
+ * 
+ * Unless required by applicable law or agreed to in writing, software 
+ * distributed under the License is distributed on an AS IS BASIS, 
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+ * See the License for the specific language governing permissions and 
+ * limitations under the License. 
+ */
+
+package com.coremedia.iso.boxes;
+
+import com.coremedia.iso.IsoFile;
+import com.coremedia.iso.IsoTypeReader;
+import com.coremedia.iso.IsoTypeWriter;
+import com.coremedia.iso.Utf8;
+import com.googlecode.mp4parser.AbstractFullBox;
+
+import java.nio.ByteBuffer;
+
+/**
+ * The Scheme Type Box identifies the protection scheme. Resides in  a Protection Scheme Information Box or
+ * an SRTP Process Box.
+ *
+ * @see com.coremedia.iso.boxes.SchemeInformationBox
+ */
+public class SchemeTypeBox extends AbstractFullBox {
+    public static final String TYPE = "schm";
+    String schemeType = "    ";
+    long schemeVersion;
+    String schemeUri = null;
+
+    public SchemeTypeBox() {
+        super(TYPE);
+    }
+
+    public String getSchemeType() {
+        return schemeType;
+    }
+
+    public long getSchemeVersion() {
+        return schemeVersion;
+    }
+
+    public String getSchemeUri() {
+        return schemeUri;
+    }
+
+    public void setSchemeType(String schemeType) {
+        assert schemeType != null && schemeType.length() == 4 : "SchemeType may not be null or not 4 bytes long";
+        this.schemeType = schemeType;
+    }
+
+    public void setSchemeVersion(int schemeVersion) {
+        this.schemeVersion = schemeVersion;
+    }
+
+    public void setSchemeUri(String schemeUri) {
+        this.schemeUri = schemeUri;
+    }
+
+    protected long getContentSize() {
+        return 12 + (((getFlags() & 1) == 1) ? Utf8.utf8StringLengthInBytes(schemeUri) + 1 : 0);
+    }
+
+    @Override
+    public void _parseDetails(ByteBuffer content) {
+        parseVersionAndFlags(content);
+        schemeType = IsoTypeReader.read4cc(content);
+        schemeVersion = IsoTypeReader.readUInt32(content);
+        if ((getFlags() & 1) == 1) {
+            schemeUri = IsoTypeReader.readString(content);
+        }
+    }
+
+    @Override
+    protected void getContent(ByteBuffer byteBuffer) {
+        writeVersionAndFlags(byteBuffer);
+        byteBuffer.put(IsoFile.fourCCtoBytes(schemeType));
+        IsoTypeWriter.writeUInt32(byteBuffer, schemeVersion);
+        if ((getFlags() & 1) == 1) {
+            byteBuffer.put(Utf8.convert(schemeUri));
+        }
+    }
+
+    public String toString() {
+        StringBuilder buffer = new StringBuilder();
+        buffer.append("Schema Type Box[");
+        buffer.append("schemeUri=").append(schemeUri).append("; ");
+        buffer.append("schemeType=").append(schemeType).append("; ");
+        buffer.append("schemeVersion=").append(schemeUri).append("; ");
+        buffer.append("]");
+        return buffer.toString();
+    }
+}
diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/SoundMediaHeaderBox.java b/isoparser/src/main/java/com/coremedia/iso/boxes/SoundMediaHeaderBox.java
new file mode 100644
index 0000000..c5fb88d
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/SoundMediaHeaderBox.java
@@ -0,0 +1,58 @@
+/*  
+ * Copyright 2008 CoreMedia AG, Hamburg
+ *
+ * Licensed under the Apache License, Version 2.0 (the License); 
+ * you may not use this file except in compliance with the License. 
+ * You may obtain a copy of the License at 
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0 
+ * 
+ * Unless required by applicable law or agreed to in writing, software 
+ * distributed under the License is distributed on an AS IS BASIS, 
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+ * See the License for the specific language governing permissions and 
+ * limitations under the License. 
+ */
+
+package com.coremedia.iso.boxes;
+
+import com.coremedia.iso.IsoTypeReader;
+import com.coremedia.iso.IsoTypeWriter;
+
+import java.nio.ByteBuffer;
+
+public class SoundMediaHeaderBox extends AbstractMediaHeaderBox {
+
+    public static final String TYPE = "smhd";
+    private float balance;
+
+    public SoundMediaHeaderBox() {
+        super(TYPE);
+    }
+
+    public float getBalance() {
+        return balance;
+    }
+
+    protected long getContentSize() {
+        return 8;
+    }
+
+    @Override
+    public void _parseDetails(ByteBuffer content) {
+        parseVersionAndFlags(content);
+        balance = IsoTypeReader.readFixedPoint88(content);
+        IsoTypeReader.readUInt16(content);
+    }
+
+    @Override
+    protected void getContent(ByteBuffer byteBuffer) {
+        writeVersionAndFlags(byteBuffer);
+        IsoTypeWriter.writeFixedPont88(byteBuffer, balance);
+        IsoTypeWriter.writeUInt16(byteBuffer, 0);
+    }
+
+    public String toString() {
+        return "SoundMediaHeaderBox[balance=" + getBalance() + "]";
+    }
+}
diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/StaticChunkOffsetBox.java b/isoparser/src/main/java/com/coremedia/iso/boxes/StaticChunkOffsetBox.java
new file mode 100644
index 0000000..efcdd14
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/StaticChunkOffsetBox.java
@@ -0,0 +1,71 @@
+/*  
+ * Copyright 2008 CoreMedia AG, Hamburg
+ *
+ * Licensed under the Apache License, Version 2.0 (the License); 
+ * you may not use this file except in compliance with the License. 
+ * You may obtain a copy of the License at 
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0 
+ * 
+ * Unless required by applicable law or agreed to in writing, software 
+ * distributed under the License is distributed on an AS IS BASIS, 
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+ * See the License for the specific language governing permissions and 
+ * limitations under the License. 
+ */
+
+package com.coremedia.iso.boxes;
+
+import com.coremedia.iso.IsoTypeReader;
+import com.coremedia.iso.IsoTypeWriter;
+
+import java.nio.ByteBuffer;
+
+import static com.googlecode.mp4parser.util.CastUtils.l2i;
+
+/**
+ * The chunk offset table gives the index of each chunk into the containing file. Defined in ISO/IEC 14496-12.
+ */
+public class StaticChunkOffsetBox extends ChunkOffsetBox {
+    public static final String TYPE = "stco";
+
+    private long[] chunkOffsets = new long[0];
+
+    public StaticChunkOffsetBox() {
+        super(TYPE);
+    }
+
+    public long[] getChunkOffsets() {
+        return chunkOffsets;
+    }
+
+    protected long getContentSize() {
+        return 8 + chunkOffsets.length * 4;
+    }
+
+    public void setChunkOffsets(long[] chunkOffsets) {
+        this.chunkOffsets = chunkOffsets;
+    }
+
+    @Override
+    public void _parseDetails(ByteBuffer content) {
+        parseVersionAndFlags(content);
+        int entryCount = l2i(IsoTypeReader.readUInt32(content));
+        chunkOffsets = new long[entryCount];
+        for (int i = 0; i < entryCount; i++) {
+            chunkOffsets[i] = IsoTypeReader.readUInt32(content);
+        }
+
+    }
+
+    @Override
+    protected void getContent(ByteBuffer byteBuffer) {
+        writeVersionAndFlags(byteBuffer);
+        IsoTypeWriter.writeUInt32(byteBuffer, chunkOffsets.length);
+        for (long chunkOffset : chunkOffsets) {
+            IsoTypeWriter.writeUInt32(byteBuffer, chunkOffset);
+        }
+    }
+
+
+}
diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/SubSampleInformationBox.java b/isoparser/src/main/java/com/coremedia/iso/boxes/SubSampleInformationBox.java
new file mode 100644
index 0000000..f5806eb
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/SubSampleInformationBox.java
@@ -0,0 +1,208 @@
+package com.coremedia.iso.boxes;

+

+import com.coremedia.iso.IsoTypeReader;

+import com.coremedia.iso.IsoTypeWriter;

+import com.googlecode.mp4parser.AbstractFullBox;

+

+import java.nio.ByteBuffer;

+import java.util.ArrayList;

+import java.util.List;

+

+import static com.googlecode.mp4parser.util.CastUtils.l2i;

+

+/**

+ * aligned(8) class SubSampleInformationBox

+ * extends FullBox('subs', version, 0) {

+ * unsigned int(32) entry_count;

+ * int i,j;

+ * for (i=0; i < entry_count; i++) {

+ * unsigned int(32) sample_delta;

+ * unsigned int(16) subsample_count;

+ * if (subsample_count > 0) {

+ * for (j=0; j < subsample_count; j++) {

+ * if(version == 1)

+ * {

+ * unsigned int(32) subsample_size;

+ * }

+ * else

+ * {

+ * unsigned int(16) subsample_size;

+ * }

+ * unsigned int(8) subsample_priority;

+ * unsigned int(8) discardable;

+ * unsigned int(32) reserved = 0;

+ * }

+ * }

+ * }

+ * }

+ */

+public class SubSampleInformationBox extends AbstractFullBox {

+    public static final String TYPE = "subs";

+

+    private long entryCount;

+    private List<SampleEntry> entries = new ArrayList<SampleEntry>();

+

+    public SubSampleInformationBox() {

+        super(TYPE);

+    }

+

+    public List<SampleEntry> getEntries() {

+        return entries;

+    }

+

+    public void setEntries(List<SampleEntry> entries) {

+        this.entries = entries;

+        entryCount = entries.size();

+    }

+

+    @Override

+    protected long getContentSize() {

+        long entries = 8 + ((4 + 2) * entryCount);

+        int subsampleEntries = 0;

+        for (SampleEntry sampleEntry : this.entries) {

+            subsampleEntries += sampleEntry.getSubsampleCount() * (((getVersion() == 1) ? 4 : 2) + 1 + 1 + 4);

+        }

+        return entries + subsampleEntries;

+    }

+

+    @Override

+    public void _parseDetails(ByteBuffer content) {

+        parseVersionAndFlags(content);

+

+        entryCount = IsoTypeReader.readUInt32(content);

+

+        for (int i = 0; i < entryCount; i++) {

+            SampleEntry sampleEntry = new SampleEntry();

+            sampleEntry.setSampleDelta(IsoTypeReader.readUInt32(content));

+            int subsampleCount = IsoTypeReader.readUInt16(content);

+            for (int j = 0; j < subsampleCount; j++) {

+                SampleEntry.SubsampleEntry subsampleEntry = new SampleEntry.SubsampleEntry();

+                subsampleEntry.setSubsampleSize(getVersion() == 1 ? IsoTypeReader.readUInt32(content) : IsoTypeReader.readUInt16(content));

+                subsampleEntry.setSubsamplePriority(IsoTypeReader.readUInt8(content));

+                subsampleEntry.setDiscardable(IsoTypeReader.readUInt8(content));

+                subsampleEntry.setReserved(IsoTypeReader.readUInt32(content));

+                sampleEntry.addSubsampleEntry(subsampleEntry);

+            }

+            entries.add(sampleEntry);

+        }

+

+    }

+

+    @Override

+    protected void getContent(ByteBuffer byteBuffer) {

+        writeVersionAndFlags(byteBuffer);

+        IsoTypeWriter.writeUInt32(byteBuffer, entries.size());

+        for (SampleEntry sampleEntry : entries) {

+            IsoTypeWriter.writeUInt32(byteBuffer, sampleEntry.getSampleDelta());

+            IsoTypeWriter.writeUInt16(byteBuffer, sampleEntry.getSubsampleCount());

+            List<SampleEntry.SubsampleEntry> subsampleEntries = sampleEntry.getSubsampleEntries();

+            for (SampleEntry.SubsampleEntry subsampleEntry : subsampleEntries) {

+                if (getVersion() == 1) {

+                    IsoTypeWriter.writeUInt32(byteBuffer, subsampleEntry.getSubsampleSize());

+                } else {

+                    IsoTypeWriter.writeUInt16(byteBuffer, l2i(subsampleEntry.getSubsampleSize()));

+                }

+                IsoTypeWriter.writeUInt8(byteBuffer, subsampleEntry.getSubsamplePriority());

+                IsoTypeWriter.writeUInt8(byteBuffer, subsampleEntry.getDiscardable());

+                IsoTypeWriter.writeUInt32(byteBuffer, subsampleEntry.getReserved());

+            }

+        }

+    }

+

+    @Override

+    public String toString() {

+        return "SubSampleInformationBox{" +

+                "entryCount=" + entryCount +

+                ", entries=" + entries +

+                '}';

+    }

+

+    public static class SampleEntry {

+        private long sampleDelta;

+        private int subsampleCount;

+        private List<SubsampleEntry> subsampleEntries = new ArrayList<SubsampleEntry>();

+

+        public long getSampleDelta() {

+            return sampleDelta;

+        }

+

+        public void setSampleDelta(long sampleDelta) {

+            this.sampleDelta = sampleDelta;

+        }

+

+        public int getSubsampleCount() {

+            return subsampleCount;

+        }

+

+        public void setSubsampleCount(int subsampleCount) {

+            this.subsampleCount = subsampleCount;

+        }

+

+        public List<SubsampleEntry> getSubsampleEntries() {

+            return subsampleEntries;

+        }

+

+        public void addSubsampleEntry(SubsampleEntry subsampleEntry) {

+            subsampleEntries.add(subsampleEntry);

+            subsampleCount++;

+        }

+

+        public static class SubsampleEntry {

+            private long subsampleSize;

+            private int subsamplePriority;

+            private int discardable;

+            private long reserved;

+

+            public long getSubsampleSize() {

+                return subsampleSize;

+            }

+

+            public void setSubsampleSize(long subsampleSize) {

+                this.subsampleSize = subsampleSize;

+            }

+

+            public int getSubsamplePriority() {

+                return subsamplePriority;

+            }

+

+            public void setSubsamplePriority(int subsamplePriority) {

+                this.subsamplePriority = subsamplePriority;

+            }

+

+            public int getDiscardable() {

+                return discardable;

+            }

+

+            public void setDiscardable(int discardable) {

+                this.discardable = discardable;

+            }

+

+            public long getReserved() {

+                return reserved;

+            }

+

+            public void setReserved(long reserved) {

+                this.reserved = reserved;

+            }

+

+            @Override

+            public String toString() {

+                return "SubsampleEntry{" +

+                        "subsampleSize=" + subsampleSize +

+                        ", subsamplePriority=" + subsamplePriority +

+                        ", discardable=" + discardable +

+                        ", reserved=" + reserved +

+                        '}';

+            }

+        }

+

+        @Override

+        public String toString() {

+            return "SampleEntry{" +

+                    "sampleDelta=" + sampleDelta +

+                    ", subsampleCount=" + subsampleCount +

+                    ", subsampleEntries=" + subsampleEntries +

+                    '}';

+        }

+    }

+}

diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/SubtitleMediaHeaderBox.java b/isoparser/src/main/java/com/coremedia/iso/boxes/SubtitleMediaHeaderBox.java
new file mode 100644
index 0000000..fa25a5c
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/SubtitleMediaHeaderBox.java
@@ -0,0 +1,30 @@
+package com.coremedia.iso.boxes;
+
+import java.nio.ByteBuffer;
+
+public class SubtitleMediaHeaderBox extends AbstractMediaHeaderBox {
+
+    public static final String TYPE = "sthd";
+
+    public SubtitleMediaHeaderBox() {
+        super(TYPE);
+    }
+
+    protected long getContentSize() {
+        return 4;
+    }
+
+    @Override
+    public void _parseDetails(ByteBuffer content) {
+        parseVersionAndFlags(content);
+    }
+
+    @Override
+    protected void getContent(ByteBuffer byteBuffer) {
+        writeVersionAndFlags(byteBuffer);
+    }
+
+    public String toString() {
+        return "SubtitleMediaHeaderBox";
+    }
+}
diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/SyncSampleBox.java b/isoparser/src/main/java/com/coremedia/iso/boxes/SyncSampleBox.java
new file mode 100644
index 0000000..5fc758b
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/SyncSampleBox.java
@@ -0,0 +1,83 @@
+/*  
+ * Copyright 2008 CoreMedia AG, Hamburg
+ *
+ * Licensed under the Apache License, Version 2.0 (the License); 
+ * you may not use this file except in compliance with the License. 
+ * You may obtain a copy of the License at 
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0 
+ * 
+ * Unless required by applicable law or agreed to in writing, software 
+ * distributed under the License is distributed on an AS IS BASIS, 
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+ * See the License for the specific language governing permissions and 
+ * limitations under the License. 
+ */
+
+package com.coremedia.iso.boxes;
+
+import com.coremedia.iso.IsoTypeReader;
+import com.coremedia.iso.IsoTypeWriter;
+import com.googlecode.mp4parser.AbstractFullBox;
+
+import java.nio.ByteBuffer;
+
+import static com.googlecode.mp4parser.util.CastUtils.l2i;
+
+/**
+ * This box provides a compact marking of the random access points withinthe stream. The table is arranged in
+ * strictly decreasinf order of sample number. Defined in ISO/IEC 14496-12.
+ */
+public class SyncSampleBox extends AbstractFullBox {
+    public static final String TYPE = "stss";
+
+    private long[] sampleNumber;
+
+    public SyncSampleBox() {
+        super(TYPE);
+    }
+
+    /**
+     * Gives the numbers of the samples that are random access points in the stream.
+     *
+     * @return random access sample numbers.
+     */
+    public long[] getSampleNumber() {
+        return sampleNumber;
+    }
+
+    protected long getContentSize() {
+        return sampleNumber.length * 4 + 8;
+    }
+
+    @Override
+    public void _parseDetails(ByteBuffer content) {
+        parseVersionAndFlags(content);
+        int entryCount = l2i(IsoTypeReader.readUInt32(content));
+
+        sampleNumber = new long[entryCount];
+        for (int i = 0; i < entryCount; i++) {
+            sampleNumber[i] = IsoTypeReader.readUInt32(content);
+        }
+    }
+
+    @Override
+    protected void getContent(ByteBuffer byteBuffer) {
+        writeVersionAndFlags(byteBuffer);
+
+        IsoTypeWriter.writeUInt32(byteBuffer, sampleNumber.length);
+
+        for (long aSampleNumber : sampleNumber) {
+            IsoTypeWriter.writeUInt32(byteBuffer, aSampleNumber);
+        }
+
+    }
+
+    public String toString() {
+        return "SyncSampleBox[entryCount=" + sampleNumber.length + "]";
+    }
+
+    public void setSampleNumber(long[] sampleNumber) {
+        this.sampleNumber = sampleNumber;
+    }
+}
diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/TimeToSampleBox.java b/isoparser/src/main/java/com/coremedia/iso/boxes/TimeToSampleBox.java
new file mode 100644
index 0000000..8f4f97e
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/TimeToSampleBox.java
@@ -0,0 +1,152 @@
+/*  
+ * Copyright 2008 CoreMedia AG, Hamburg
+ *
+ * Licensed under the Apache License, Version 2.0 (the License); 
+ * you may not use this file except in compliance with the License. 
+ * You may obtain a copy of the License at 
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0 
+ * 
+ * Unless required by applicable law or agreed to in writing, software 
+ * distributed under the License is distributed on an AS IS BASIS, 
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+ * See the License for the specific language governing permissions and 
+ * limitations under the License. 
+ */
+
+package com.coremedia.iso.boxes;
+
+
+import com.coremedia.iso.IsoTypeReader;
+import com.coremedia.iso.IsoTypeWriter;
+import com.googlecode.mp4parser.AbstractFullBox;
+
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import static com.googlecode.mp4parser.util.CastUtils.l2i;
+
+/**
+ * This box contains a compact version of a table that allows indexing from decoding time to sample number.
+ * Other tables give sample sizes and pointers, from the sample number. Each entry in the table gives the
+ * number of consecutive samples with the same time delta, and the delta of those samples. By adding the
+ * deltas a complete time-to-sample map may be built.<br>
+ * The Decoding Time to Sample Box contains decode time delta's: <code>DT(n+1) = DT(n) + STTS(n)</code> where STTS(n)
+ * is the (uncompressed) table entry for sample n.<br>
+ * The sample entries are ordered by decoding time stamps; therefore the deltas are all non-negative. <br>
+ * The DT axis has a zero origin; <code>DT(i) = SUM(for j=0 to i-1 of delta(j))</code>, and the sum of all
+ * deltas gives the length of the media in the track (not mapped to the overall timescale, and not considering
+ * any edit list).    <br>
+ * The Edit List Box provides the initial CT value if it is non-empty (non-zero).
+ */
+public class TimeToSampleBox extends AbstractFullBox {
+    public static final String TYPE = "stts";
+
+    List<Entry> entries = Collections.emptyList();
+
+
+    public TimeToSampleBox() {
+        super(TYPE);
+    }
+
+    protected long getContentSize() {
+        return 8 + entries.size() * 8;
+    }
+
+    @Override
+    public void _parseDetails(ByteBuffer content) {
+        parseVersionAndFlags(content);
+        int entryCount = l2i(IsoTypeReader.readUInt32(content));
+        entries = new ArrayList<Entry>(entryCount);
+
+        for (int i = 0; i < entryCount; i++) {
+            entries.add(new Entry(IsoTypeReader.readUInt32(content), IsoTypeReader.readUInt32(content)));
+        }
+
+    }
+
+    @Override
+    protected void getContent(ByteBuffer byteBuffer) {
+        writeVersionAndFlags(byteBuffer);
+        IsoTypeWriter.writeUInt32(byteBuffer, entries.size());
+        for (Entry entry : entries) {
+            IsoTypeWriter.writeUInt32(byteBuffer, entry.getCount());
+            IsoTypeWriter.writeUInt32(byteBuffer, entry.getDelta());
+        }
+    }
+
+    public List<Entry> getEntries() {
+        return entries;
+    }
+
+    public void setEntries(List<Entry> entries) {
+        this.entries = entries;
+    }
+
+    public String toString() {
+        return "TimeToSampleBox[entryCount=" + entries.size() + "]";
+    }
+
+    public static class Entry {
+        long count;
+        long delta;
+
+        public Entry(long count, long delta) {
+            this.count = count;
+            this.delta = delta;
+        }
+
+        public long getCount() {
+            return count;
+        }
+
+        public long getDelta() {
+            return delta;
+        }
+
+        public void setCount(long count) {
+            this.count = count;
+        }
+
+        public void setDelta(long delta) {
+            this.delta = delta;
+        }
+
+        @Override
+        public String toString() {
+            return "Entry{" +
+                    "count=" + count +
+                    ", delta=" + delta +
+                    '}';
+        }
+    }
+
+    /**
+     * Decompresses the list of entries and returns the list of decoding times.
+     *
+     * @return decoding time per sample
+     */
+    public static long[] blowupTimeToSamples(List<TimeToSampleBox.Entry> entries) {
+        long numOfSamples = 0;
+        for (TimeToSampleBox.Entry entry : entries) {
+            numOfSamples += entry.getCount();
+        }
+        assert numOfSamples <= Integer.MAX_VALUE;
+        long[] decodingTime = new long[(int) numOfSamples];
+
+        int current = 0;
+
+
+        for (TimeToSampleBox.Entry entry : entries) {
+            for (int i = 0; i < entry.getCount(); i++) {
+                decodingTime[current++] = entry.getDelta();
+            }
+        }
+
+        return decodingTime;
+    }
+
+
+}
diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/TitleBox.java b/isoparser/src/main/java/com/coremedia/iso/boxes/TitleBox.java
new file mode 100644
index 0000000..46ee5ee
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/TitleBox.java
@@ -0,0 +1,89 @@
+/*  
+ * Copyright 2008 CoreMedia AG, Hamburg
+ *
+ * Licensed under the Apache License, Version 2.0 (the License); 
+ * you may not use this file except in compliance with the License. 
+ * You may obtain a copy of the License at 
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0 
+ * 
+ * Unless required by applicable law or agreed to in writing, software 
+ * distributed under the License is distributed on an AS IS BASIS, 
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+ * See the License for the specific language governing permissions and 
+ * limitations under the License. 
+ */
+
+package com.coremedia.iso.boxes;
+
+import com.coremedia.iso.IsoTypeReader;
+import com.coremedia.iso.IsoTypeWriter;
+import com.coremedia.iso.Utf8;
+import com.googlecode.mp4parser.AbstractFullBox;
+
+import java.nio.ByteBuffer;
+
+/**
+ * <code>
+ * Box Type: 'titl'<br>
+ * Container: {@link UserDataBox} ('udta')<br>
+ * Mandatory: No<br>
+ * Quantity: Zero or one<br><br>
+ * </code>
+ * <p/>
+ * Title for the media.
+ */
+public class TitleBox extends AbstractFullBox {
+    public static final String TYPE = "titl";
+
+    private String language;
+    private String title;
+
+    public TitleBox() {
+        super(TYPE);
+    }
+
+    public String getLanguage() {
+        return language;
+    }
+
+    public String getTitle() {
+        return title;
+    }
+
+    /**
+     * Sets the 3-letter ISO-639 language for this title.
+     *
+     * @param language 3-letter ISO-639 code
+     */
+    public void setLanguage(String language) {
+        this.language = language;
+    }
+
+    public void setTitle(String title) {
+        this.title = title;
+    }
+
+    protected long getContentSize() {
+        return 7 + Utf8.utf8StringLengthInBytes(title);
+    }
+
+
+    protected void getContent(ByteBuffer byteBuffer) {
+        writeVersionAndFlags(byteBuffer);
+        IsoTypeWriter.writeIso639(byteBuffer, language);
+        byteBuffer.put(Utf8.convert(title));
+        byteBuffer.put((byte) 0);
+    }
+
+    @Override
+    public void _parseDetails(ByteBuffer content) {
+        parseVersionAndFlags(content);
+        language = IsoTypeReader.readIso639(content);
+        title = IsoTypeReader.readString(content);
+    }
+
+    public String toString() {
+        return "TitleBox[language=" + getLanguage() + ";title=" + getTitle() + "]";
+    }
+}
diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/TrackBox.java b/isoparser/src/main/java/com/coremedia/iso/boxes/TrackBox.java
new file mode 100644
index 0000000..c2806b5
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/TrackBox.java
@@ -0,0 +1,71 @@
+/*  
+ * Copyright 2008 CoreMedia AG, Hamburg
+ *
+ * Licensed under the Apache License, Version 2.0 (the License); 
+ * you may not use this file except in compliance with the License. 
+ * You may obtain a copy of the License at 
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0 
+ * 
+ * Unless required by applicable law or agreed to in writing, software 
+ * distributed under the License is distributed on an AS IS BASIS, 
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+ * See the License for the specific language governing permissions and 
+ * limitations under the License. 
+ */
+
+package com.coremedia.iso.boxes;
+
+import com.googlecode.mp4parser.AbstractContainerBox;
+
+/**
+ * Tracks are used for two purposes: (a) to contain media data (media tracks) and (b) to contain packetization
+ * information for streaming protocols (hint tracks).  <br>
+ * There shall be at least one media track within an ISO file, and all the media tracks that contributed to the hint
+ * tracks shall remain in the file, even if the media data within them is not referenced by the hint tracks; after
+ * deleting all hint tracks, the entire un-hinted presentation shall remain.
+ */
+public class TrackBox extends AbstractContainerBox {
+    public static final String TYPE = "trak";
+
+    public TrackBox() {
+        super(TYPE);
+    }
+
+    public TrackHeaderBox getTrackHeaderBox() {
+        for (Box box : boxes) {
+            if (box instanceof TrackHeaderBox) {
+                return (TrackHeaderBox) box;
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Gets the SampleTableBox at mdia/minf/stbl if existing.
+     *
+     * @return the SampleTableBox or <code>null</code>
+     */
+    public SampleTableBox getSampleTableBox() {
+        MediaBox mdia = getMediaBox();
+        if (mdia != null) {
+            MediaInformationBox minf = mdia.getMediaInformationBox();
+            if (minf != null) {
+                return minf.getSampleTableBox();
+            }
+        }
+        return null;
+
+    }
+
+
+    public MediaBox getMediaBox() {
+        for (Box box : boxes) {
+            if (box instanceof MediaBox) {
+                return (MediaBox) box;
+            }
+        }
+        return null;
+    }
+
+}
diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/TrackHeaderBox.java b/isoparser/src/main/java/com/coremedia/iso/boxes/TrackHeaderBox.java
new file mode 100644
index 0000000..8816bb9
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/TrackHeaderBox.java
@@ -0,0 +1,249 @@
+/*  
+ * Copyright 2008 CoreMedia AG, Hamburg
+ *
+ * Licensed under the Apache License, Version 2.0 (the License); 
+ * you may not use this file except in compliance with the License. 
+ * You may obtain a copy of the License at 
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0 
+ * 
+ * Unless required by applicable law or agreed to in writing, software 
+ * distributed under the License is distributed on an AS IS BASIS, 
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+ * See the License for the specific language governing permissions and 
+ * limitations under the License. 
+ */
+
+package com.coremedia.iso.boxes;
+
+
+import com.coremedia.iso.IsoTypeReader;
+import com.coremedia.iso.IsoTypeWriter;
+import com.googlecode.mp4parser.AbstractFullBox;
+
+import java.nio.ByteBuffer;
+
+/**
+ * This box specifies the characteristics of a single track. Exactly one Track Header Box is contained in a track.<br>
+ * In the absence of an edit list, the presentation of a track starts at the beginning of the overall presentation. An
+ * empty edit is used to offset the start time of a track. <br>
+ * The default value of the track header flags for media tracks is 7 (track_enabled, track_in_movie,
+ * track_in_preview). If in a presentation all tracks have neither track_in_movie nor track_in_preview set, then all
+ * tracks shall be treated as if both flags were set on all tracks. Hint tracks should have the track header flags set
+ * to 0, so that they are ignored for local playback and preview.
+ */
+public class TrackHeaderBox extends AbstractFullBox {
+
+    public static final String TYPE = "tkhd";
+
+    private long creationTime;
+    private long modificationTime;
+    private long trackId;
+    private long duration;
+    private int layer;
+    private int alternateGroup;
+    private float volume;
+    private long[] matrix = new long[]{0x00010000, 0, 0, 0, 0x00010000, 0, 0, 0, 0x40000000};
+    private double width;
+    private double height;
+
+
+    public TrackHeaderBox() {
+        super(TYPE);
+
+    }
+
+    public long getCreationTime() {
+        return creationTime;
+    }
+
+    public long getModificationTime() {
+        return modificationTime;
+    }
+
+    public long getTrackId() {
+        return trackId;
+    }
+
+    public long getDuration() {
+        return duration;
+    }
+
+    public int getLayer() {
+        return layer;
+    }
+
+    public int getAlternateGroup() {
+        return alternateGroup;
+    }
+
+    public float getVolume() {
+        return volume;
+    }
+
+    public long[] getMatrix() {
+        return matrix;
+    }
+
+    public double getWidth() {
+        return width;
+    }
+
+    public double getHeight() {
+        return height;
+    }
+
+    protected long getContentSize() {
+        long contentSize = 4;
+        if (getVersion() == 1) {
+            contentSize += 32;
+        } else {
+            contentSize += 20;
+        }
+        contentSize += 60;
+        return contentSize;
+    }
+
+    @Override
+    public void _parseDetails(ByteBuffer content) {
+        parseVersionAndFlags(content);
+        if (getVersion() == 1) {
+            creationTime = IsoTypeReader.readUInt64(content);
+            modificationTime = IsoTypeReader.readUInt64(content);
+            trackId = IsoTypeReader.readUInt32(content);
+            IsoTypeReader.readUInt32(content);
+            duration = IsoTypeReader.readUInt64(content);
+        } else {
+            creationTime = IsoTypeReader.readUInt32(content);
+            modificationTime = IsoTypeReader.readUInt32(content);
+            trackId = IsoTypeReader.readUInt32(content);
+            IsoTypeReader.readUInt32(content);
+            duration = IsoTypeReader.readUInt32(content);
+        } // 196
+        IsoTypeReader.readUInt32(content);
+        IsoTypeReader.readUInt32(content);
+        layer = IsoTypeReader.readUInt16(content);    // 204
+        alternateGroup = IsoTypeReader.readUInt16(content);
+        volume = IsoTypeReader.readFixedPoint88(content);
+        IsoTypeReader.readUInt16(content);     // 212
+        matrix = new long[9];
+        for (int i = 0; i < 9; i++) {
+            matrix[i] = IsoTypeReader.readUInt32(content);
+        }
+        width = IsoTypeReader.readFixedPoint1616(content);    // 248
+        height = IsoTypeReader.readFixedPoint1616(content);
+    }
+
+    public void getContent(ByteBuffer byteBuffer) {
+        writeVersionAndFlags(byteBuffer);
+        if (getVersion() == 1) {
+            IsoTypeWriter.writeUInt64(byteBuffer, creationTime);
+            IsoTypeWriter.writeUInt64(byteBuffer, modificationTime);
+            IsoTypeWriter.writeUInt32(byteBuffer, trackId);
+            IsoTypeWriter.writeUInt32(byteBuffer, 0);
+            IsoTypeWriter.writeUInt64(byteBuffer, duration);
+        } else {
+            IsoTypeWriter.writeUInt32(byteBuffer, creationTime);
+            IsoTypeWriter.writeUInt32(byteBuffer, modificationTime);
+            IsoTypeWriter.writeUInt32(byteBuffer, trackId);
+            IsoTypeWriter.writeUInt32(byteBuffer, 0);
+            IsoTypeWriter.writeUInt32(byteBuffer, duration);
+        } // 196
+        IsoTypeWriter.writeUInt32(byteBuffer, 0);
+        IsoTypeWriter.writeUInt32(byteBuffer, 0);
+        IsoTypeWriter.writeUInt16(byteBuffer, layer);
+        IsoTypeWriter.writeUInt16(byteBuffer, alternateGroup);
+        IsoTypeWriter.writeFixedPont88(byteBuffer, volume);
+        IsoTypeWriter.writeUInt16(byteBuffer, 0);
+        for (int i = 0; i < 9; i++) {
+            IsoTypeWriter.writeUInt32(byteBuffer, matrix[i]);
+        }
+        IsoTypeWriter.writeFixedPont1616(byteBuffer, width);
+        IsoTypeWriter.writeFixedPont1616(byteBuffer, height);
+    }
+
+    public String toString() {
+        StringBuilder result = new StringBuilder();
+        result.append("TrackHeaderBox[");
+        result.append("creationTime=").append(getCreationTime());
+        result.append(";");
+        result.append("modificationTime=").append(getModificationTime());
+        result.append(";");
+        result.append("trackId=").append(getTrackId());
+        result.append(";");
+        result.append("duration=").append(getDuration());
+        result.append(";");
+        result.append("layer=").append(getLayer());
+        result.append(";");
+        result.append("alternateGroup=").append(getAlternateGroup());
+        result.append(";");
+        result.append("volume=").append(getVolume());
+        for (int i = 0; i < matrix.length; i++) {
+            result.append(";");
+            result.append("matrix").append(i).append("=").append(matrix[i]);
+        }
+        result.append(";");
+        result.append("width=").append(getWidth());
+        result.append(";");
+        result.append("height=").append(getHeight());
+        result.append("]");
+        return result.toString();
+    }
+
+    public void setCreationTime(long creationTime) {
+        this.creationTime = creationTime;
+    }
+
+    public void setModificationTime(long modificationTime) {
+        this.modificationTime = modificationTime;
+    }
+
+    public void setTrackId(long trackId) {
+        this.trackId = trackId;
+    }
+
+    public void setDuration(long duration) {
+        this.duration = duration;
+    }
+
+    public void setLayer(int layer) {
+        this.layer = layer;
+    }
+
+    public void setAlternateGroup(int alternateGroup) {
+        this.alternateGroup = alternateGroup;
+    }
+
+    public void setVolume(float volume) {
+        this.volume = volume;
+    }
+
+    public void setMatrix(long[] matrix) {
+        this.matrix = matrix;
+    }
+
+    public void setWidth(double width) {
+        this.width = width;
+    }
+
+    public void setHeight(double height) {
+        this.height = height;
+    }
+
+
+    public boolean isEnabled() {
+        return (getFlags() & 1) > 0;
+    }
+
+    public boolean isInMovie() {
+        return (getFlags() & 2) > 0;
+    }
+
+    public boolean isInPreview() {
+        return (getFlags() & 4) > 0;
+    }
+
+    public boolean isInPoster() {
+        return (getFlags() & 8) > 0;
+    }
+}
diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/TrackReferenceBox.java b/isoparser/src/main/java/com/coremedia/iso/boxes/TrackReferenceBox.java
new file mode 100644
index 0000000..1b4a7fb
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/TrackReferenceBox.java
@@ -0,0 +1,41 @@
+/*  
+ * Copyright 2008 CoreMedia AG, Hamburg
+ *
+ * Licensed under the Apache License, Version 2.0 (the License); 
+ * you may not use this file except in compliance with the License. 
+ * You may obtain a copy of the License at 
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0 
+ * 
+ * Unless required by applicable law or agreed to in writing, software 
+ * distributed under the License is distributed on an AS IS BASIS, 
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+ * See the License for the specific language governing permissions and 
+ * limitations under the License. 
+ */
+
+package com.coremedia.iso.boxes;
+
+import com.googlecode.mp4parser.AbstractContainerBox;
+
+/**
+ * <code>
+ * Box Type: 'tref'<br>
+ * Container: {@link TrackBox} ('trak')<br>
+ * Mandatory: No<br>
+ * Quantity: Zero or one<br><br>
+ * </code>
+ * This box provides a reference from the containing track to another track in the presentation. These references
+ * are typed. A 'hint' reference links from the containing hint track to the media data that it hints. A content
+ * description reference 'cdsc' links a descriptive or metadata track to the content which it describes.
+ * Exactly one Track Reference Box can be contained within the Track Box.
+ * If this box is not present, the track is not referencing any other track in any way. The reference array is sized
+ * to fill the reference type box.
+ */
+public class TrackReferenceBox extends AbstractContainerBox {
+    public static final String TYPE = "tref";
+
+    public TrackReferenceBox() {
+        super(TYPE);
+    }
+}
diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/TrackReferenceTypeBox.java b/isoparser/src/main/java/com/coremedia/iso/boxes/TrackReferenceTypeBox.java
new file mode 100644
index 0000000..297932d
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/TrackReferenceTypeBox.java
@@ -0,0 +1,76 @@
+/*  
+ * Copyright 2008 CoreMedia AG, Hamburg
+ *
+ * Licensed under the Apache License, Version 2.0 (the License); 
+ * you may not use this file except in compliance with the License. 
+ * You may obtain a copy of the License at 
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0 
+ * 
+ * Unless required by applicable law or agreed to in writing, software 
+ * distributed under the License is distributed on an AS IS BASIS, 
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+ * See the License for the specific language governing permissions and 
+ * limitations under the License. 
+ */
+
+package com.coremedia.iso.boxes;
+
+import com.coremedia.iso.IsoTypeReader;
+import com.coremedia.iso.IsoTypeWriter;
+import com.googlecode.mp4parser.AbstractBox;
+
+import java.nio.ByteBuffer;
+
+/**
+ * Contains a reference to a track. The type of the box gives the kind of reference.
+ */
+public class TrackReferenceTypeBox extends AbstractBox {
+
+    public static final String TYPE1 = "hint";
+    public static final String TYPE2 = "cdsc";
+
+    private long[] trackIds;
+
+    public TrackReferenceTypeBox(String type) {
+        super(type);
+    }
+
+    public long[] getTrackIds() {
+        return trackIds;
+    }
+
+    @Override
+    public void _parseDetails(ByteBuffer content) {
+        int count = (int) (content.remaining() / 4);
+        trackIds = new long[count];
+        for (int i = 0; i < count; i++) {
+            trackIds[i] = IsoTypeReader.readUInt32(content);
+        }
+    }
+
+    @Override
+    protected void getContent(ByteBuffer byteBuffer) {
+        for (long trackId : trackIds) {
+            IsoTypeWriter.writeUInt32(byteBuffer, trackId);
+        }
+    }
+
+
+    protected long getContentSize() {
+        return trackIds.length * 4;
+    }
+
+    public String toString() {
+        StringBuilder buffer = new StringBuilder();
+        buffer.append("TrackReferenceTypeBox[type=").append(getType());
+        for (int i = 0; i < trackIds.length; i++) {
+            buffer.append(";trackId");
+            buffer.append(i);
+            buffer.append("=");
+            buffer.append(trackIds[i]);
+        }
+        buffer.append("]");
+        return buffer.toString();
+    }
+}
diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/UnknownBox.java b/isoparser/src/main/java/com/coremedia/iso/boxes/UnknownBox.java
new file mode 100644
index 0000000..f76481c
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/UnknownBox.java
@@ -0,0 +1,59 @@
+/*  
+ * Copyright 2008 CoreMedia AG, Hamburg
+ *
+ * Licensed under the Apache License, Version 2.0 (the License); 
+ * you may not use this file except in compliance with the License. 
+ * You may obtain a copy of the License at 
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0 
+ * 
+ * Unless required by applicable law or agreed to in writing, software 
+ * distributed under the License is distributed on an AS IS BASIS, 
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+ * See the License for the specific language governing permissions and 
+ * limitations under the License. 
+ */
+
+package com.coremedia.iso.boxes;
+
+
+import com.googlecode.mp4parser.AbstractBox;
+
+import java.nio.ByteBuffer;
+
+/**
+ * A box unknown to the ISO Parser. If there is no specific Box implementation for a Box this <code>UnknownBox</code>
+ * will just hold the box's data.
+ */
+public class UnknownBox extends AbstractBox {
+    ByteBuffer data;
+
+    public UnknownBox(String type) {
+        super(type);
+    }
+
+    @Override
+    protected long getContentSize() {
+        return data.limit();
+    }
+
+    @Override
+    public void _parseDetails(ByteBuffer content) {
+        data = content;
+        content.position(content.position() + content.remaining());
+    }
+
+    @Override
+    protected void getContent(ByteBuffer byteBuffer) {
+        data.rewind();
+        byteBuffer.put(data);
+    }
+
+    public ByteBuffer getData() {
+        return data;
+    }
+
+    public void setData(ByteBuffer data) {
+        this.data = data;
+    }
+}
diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/UserBox.java b/isoparser/src/main/java/com/coremedia/iso/boxes/UserBox.java
new file mode 100644
index 0000000..db0e741
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/UserBox.java
@@ -0,0 +1,64 @@
+/*  
+ * Copyright 2008 CoreMedia AG, Hamburg
+ *
+ * Licensed under the Apache License, Version 2.0 (the License); 
+ * you may not use this file except in compliance with the License. 
+ * You may obtain a copy of the License at 
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0 
+ * 
+ * Unless required by applicable law or agreed to in writing, software 
+ * distributed under the License is distributed on an AS IS BASIS, 
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+ * See the License for the specific language governing permissions and 
+ * limitations under the License. 
+ */
+
+package com.coremedia.iso.boxes;
+
+import com.googlecode.mp4parser.AbstractBox;
+
+import java.nio.ByteBuffer;
+
+/**
+ * A user specifc box. See ISO/IEC 14496-12 for details.
+ */
+public class UserBox extends AbstractBox {
+    byte[] data;
+    public static final String TYPE = "uuid";
+
+    public UserBox(byte[] userType) {
+        super(TYPE, userType);
+    }
+
+
+    protected long getContentSize() {
+        return data.length;
+    }
+
+    public String toString() {
+        return "UserBox[type=" + (getType()) +
+                ";userType=" + new String(getUserType()) +
+                ";contentLength=" + data.length + "]";
+    }
+
+
+    public byte[] getData() {
+        return data;
+    }
+
+    public void setData(byte[] data) {
+        this.data = data;
+    }
+
+    @Override
+    public void _parseDetails(ByteBuffer content) {
+        data = new byte[content.remaining()];
+        content.get(data);
+    }
+
+    @Override
+    protected void getContent(ByteBuffer byteBuffer) {
+        byteBuffer.put(data);
+    }
+}
diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/UserDataBox.java b/isoparser/src/main/java/com/coremedia/iso/boxes/UserDataBox.java
new file mode 100644
index 0000000..65c5808
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/UserDataBox.java
@@ -0,0 +1,59 @@
+/*  
+ * Copyright 2008 CoreMedia AG, Hamburg
+ *
+ * Licensed under the Apache License, Version 2.0 (the License); 
+ * you may not use this file except in compliance with the License. 
+ * You may obtain a copy of the License at 
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0 
+ * 
+ * Unless required by applicable law or agreed to in writing, software 
+ * distributed under the License is distributed on an AS IS BASIS, 
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+ * See the License for the specific language governing permissions and 
+ * limitations under the License. 
+ */
+
+package com.coremedia.iso.boxes;
+
+import com.coremedia.iso.BoxParser;
+import com.googlecode.mp4parser.AbstractContainerBox;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.nio.channels.ReadableByteChannel;
+
+/**
+ * This box contains objects that declare user information about the containing box and its data (presentation or
+ * track).<br>
+ * The User Data Box is a container box for informative user-data. This user data is formatted as a set of boxes
+ * with more specific box types, which declare more precisely their content
+ */
+public class UserDataBox extends AbstractContainerBox {
+    public static final String TYPE = "udta";
+
+    @Override
+    protected long getContentSize() {
+        return super.getContentSize();    //To change body of overridden methods use File | Settings | File Templates.
+    }
+
+    @Override
+    public void parse(ReadableByteChannel readableByteChannel, ByteBuffer header, long contentSize, BoxParser boxParser) throws IOException {
+        super.parse(readableByteChannel, header, contentSize, boxParser);    //To change body of overridden methods use File | Settings | File Templates.
+    }
+
+    @Override
+    public void _parseDetails(ByteBuffer content) {
+        super._parseDetails(content);    //To change body of overridden methods use File | Settings | File Templates.
+    }
+
+    @Override
+    protected void getContent(ByteBuffer byteBuffer) {
+        super.getContent(byteBuffer);    //To change body of overridden methods use File | Settings | File Templates.
+    }
+
+    public UserDataBox() {
+        super(TYPE);
+    }
+
+}
diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/VideoMediaHeaderBox.java b/isoparser/src/main/java/com/coremedia/iso/boxes/VideoMediaHeaderBox.java
new file mode 100644
index 0000000..421a67d
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/VideoMediaHeaderBox.java
@@ -0,0 +1,81 @@
+/*  
+ * Copyright 2008 CoreMedia AG, Hamburg
+ *
+ * Licensed under the Apache License, Version 2.0 (the License); 
+ * you may not use this file except in compliance with the License. 
+ * You may obtain a copy of the License at 
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0 
+ * 
+ * Unless required by applicable law or agreed to in writing, software 
+ * distributed under the License is distributed on an AS IS BASIS, 
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+ * See the License for the specific language governing permissions and 
+ * limitations under the License. 
+ */
+
+package com.coremedia.iso.boxes;
+
+import com.coremedia.iso.IsoTypeReader;
+import com.coremedia.iso.IsoTypeWriter;
+
+import java.nio.ByteBuffer;
+
+/**
+ * The video media header contains general presentation information, independent of the coding, for video
+ * media. Note that the flags field has the value 1.
+ */
+public class VideoMediaHeaderBox extends AbstractMediaHeaderBox {
+    private int graphicsmode = 0;
+    private int[] opcolor = new int[]{0, 0, 0};
+    public static final String TYPE = "vmhd";
+
+    public VideoMediaHeaderBox() {
+        super(TYPE);
+        setFlags(1); // 1 is default.
+    }
+
+    public int getGraphicsmode() {
+        return graphicsmode;
+    }
+
+    public int[] getOpcolor() {
+        return opcolor;
+    }
+
+    protected long getContentSize() {
+        return 12;
+    }
+
+
+    @Override
+    public void _parseDetails(ByteBuffer content) {
+        parseVersionAndFlags(content);
+        graphicsmode = IsoTypeReader.readUInt16(content);
+        opcolor = new int[3];
+        for (int i = 0; i < 3; i++) {
+            opcolor[i] = IsoTypeReader.readUInt16(content);
+        }
+    }
+
+    @Override
+    protected void getContent(ByteBuffer byteBuffer) {
+        writeVersionAndFlags(byteBuffer);
+        IsoTypeWriter.writeUInt16(byteBuffer, graphicsmode);
+        for (int anOpcolor : opcolor) {
+            IsoTypeWriter.writeUInt16(byteBuffer, anOpcolor);
+        }
+    }
+
+    public String toString() {
+        return "VideoMediaHeaderBox[graphicsmode=" + getGraphicsmode() + ";opcolor0=" + getOpcolor()[0] + ";opcolor1=" + getOpcolor()[1] + ";opcolor2=" + getOpcolor()[2] + "]";
+    }
+
+    public void setOpcolor(int[] opcolor) {
+        this.opcolor = opcolor;
+    }
+
+    public void setGraphicsmode(int graphicsmode) {
+        this.graphicsmode = graphicsmode;
+    }
+}
diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/WriteListener.java b/isoparser/src/main/java/com/coremedia/iso/boxes/WriteListener.java
new file mode 100644
index 0000000..dc22d52
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/WriteListener.java
@@ -0,0 +1,10 @@
+package com.coremedia.iso.boxes;
+
+/**
+ * The <class>WriteListener</class> is used to get the offset of
+ * a box before writing the box. This can be used if a box written
+ * later needs an offset.
+ */
+public interface WriteListener {
+    public void beforeWrite(long offset);
+}
diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/XmlBox.java b/isoparser/src/main/java/com/coremedia/iso/boxes/XmlBox.java
new file mode 100644
index 0000000..43727e1
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/XmlBox.java
@@ -0,0 +1,51 @@
+package com.coremedia.iso.boxes;
+
+import com.coremedia.iso.IsoTypeReader;
+import com.coremedia.iso.Utf8;
+import com.googlecode.mp4parser.AbstractFullBox;
+
+import java.nio.ByteBuffer;
+
+/**
+ *
+ */
+public class XmlBox extends AbstractFullBox {
+    String xml = "";
+    public static final String TYPE = "xml ";
+
+    public XmlBox() {
+        super(TYPE);
+    }
+
+    public String getXml() {
+        return xml;
+    }
+
+    public void setXml(String xml) {
+        this.xml = xml;
+    }
+
+    @Override
+    protected long getContentSize() {
+        return 4 + Utf8.utf8StringLengthInBytes(xml);
+    }
+
+    @Override
+    public void _parseDetails(ByteBuffer content) {
+        parseVersionAndFlags(content);
+        xml = IsoTypeReader.readString(content, content.remaining());
+    }
+
+    @Override
+    protected void getContent(ByteBuffer byteBuffer) {
+        writeVersionAndFlags(byteBuffer);
+        byteBuffer.put(Utf8.convert(xml));
+    }
+
+    @Override
+    public String toString() {
+        return "XmlBox{" +
+                "xml='" + xml + '\'' +
+                '}';
+    }
+}
diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/apple/.svn/all-wcprops b/isoparser/src/main/java/com/coremedia/iso/boxes/apple/.svn/all-wcprops
new file mode 100644
index 0000000..581c9a0
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/apple/.svn/all-wcprops
@@ -0,0 +1,263 @@
+K 25
+svn:wc:ra_dav:version-url
+V 77
+/svn/!svn/ver/507/trunk/isoparser/src/main/java/com/coremedia/iso/boxes/apple
+END
+AppleTrackTitleBox.java
+K 25
+svn:wc:ra_dav:version-url
+V 101
+/svn/!svn/ver/198/trunk/isoparser/src/main/java/com/coremedia/iso/boxes/apple/AppleTrackTitleBox.java
+END
+AppleCopyrightBox.java
+K 25
+svn:wc:ra_dav:version-url
+V 100
+/svn/!svn/ver/198/trunk/isoparser/src/main/java/com/coremedia/iso/boxes/apple/AppleCopyrightBox.java
+END
+ApplePurchaseDateBox.java
+K 25
+svn:wc:ra_dav:version-url
+V 103
+/svn/!svn/ver/198/trunk/isoparser/src/main/java/com/coremedia/iso/boxes/apple/ApplePurchaseDateBox.java
+END
+AppleSortAlbumBox.java
+K 25
+svn:wc:ra_dav:version-url
+V 100
+/svn/!svn/ver/198/trunk/isoparser/src/main/java/com/coremedia/iso/boxes/apple/AppleSortAlbumBox.java
+END
+AppleTvEpisodeNumberBox.java
+K 25
+svn:wc:ra_dav:version-url
+V 106
+/svn/!svn/ver/198/trunk/isoparser/src/main/java/com/coremedia/iso/boxes/apple/AppleTvEpisodeNumberBox.java
+END
+AppleStoreAccountTypeBox.java
+K 25
+svn:wc:ra_dav:version-url
+V 107
+/svn/!svn/ver/377/trunk/isoparser/src/main/java/com/coremedia/iso/boxes/apple/AppleStoreAccountTypeBox.java
+END
+AppleStoreCountryCodeBox.java
+K 25
+svn:wc:ra_dav:version-url
+V 107
+/svn/!svn/ver/198/trunk/isoparser/src/main/java/com/coremedia/iso/boxes/apple/AppleStoreCountryCodeBox.java
+END
+AppleGenericBox.java
+K 25
+svn:wc:ra_dav:version-url
+V 98
+/svn/!svn/ver/505/trunk/isoparser/src/main/java/com/coremedia/iso/boxes/apple/AppleGenericBox.java
+END
+AppleNameBox.java
+K 25
+svn:wc:ra_dav:version-url
+V 95
+/svn/!svn/ver/507/trunk/isoparser/src/main/java/com/coremedia/iso/boxes/apple/AppleNameBox.java
+END
+AppleShowBox.java
+K 25
+svn:wc:ra_dav:version-url
+V 95
+/svn/!svn/ver/198/trunk/isoparser/src/main/java/com/coremedia/iso/boxes/apple/AppleShowBox.java
+END
+AppleStandardGenreBox.java
+K 25
+svn:wc:ra_dav:version-url
+V 104
+/svn/!svn/ver/198/trunk/isoparser/src/main/java/com/coremedia/iso/boxes/apple/AppleStandardGenreBox.java
+END
+AppleRatingBox.java
+K 25
+svn:wc:ra_dav:version-url
+V 97
+/svn/!svn/ver/198/trunk/isoparser/src/main/java/com/coremedia/iso/boxes/apple/AppleRatingBox.java
+END
+AppleSynopsisBox.java
+K 25
+svn:wc:ra_dav:version-url
+V 99
+/svn/!svn/ver/198/trunk/isoparser/src/main/java/com/coremedia/iso/boxes/apple/AppleSynopsisBox.java
+END
+AppleNetworkBox.java
+K 25
+svn:wc:ra_dav:version-url
+V 98
+/svn/!svn/ver/198/trunk/isoparser/src/main/java/com/coremedia/iso/boxes/apple/AppleNetworkBox.java
+END
+AppleRecordingYearBox.java
+K 25
+svn:wc:ra_dav:version-url
+V 104
+/svn/!svn/ver/198/trunk/isoparser/src/main/java/com/coremedia/iso/boxes/apple/AppleRecordingYearBox.java
+END
+AppleReferenceMovieBox.java
+K 25
+svn:wc:ra_dav:version-url
+V 105
+/svn/!svn/ver/505/trunk/isoparser/src/main/java/com/coremedia/iso/boxes/apple/AppleReferenceMovieBox.java
+END
+AppleTvEpisodeBox.java
+K 25
+svn:wc:ra_dav:version-url
+V 100
+/svn/!svn/ver/198/trunk/isoparser/src/main/java/com/coremedia/iso/boxes/apple/AppleTvEpisodeBox.java
+END
+AppleWaveBox.java
+K 25
+svn:wc:ra_dav:version-url
+V 95
+/svn/!svn/ver/505/trunk/isoparser/src/main/java/com/coremedia/iso/boxes/apple/AppleWaveBox.java
+END
+AbstractAppleMetaDataBox.java
+K 25
+svn:wc:ra_dav:version-url
+V 107
+/svn/!svn/ver/507/trunk/isoparser/src/main/java/com/coremedia/iso/boxes/apple/AbstractAppleMetaDataBox.java
+END
+AppleGaplessPlaybackBox.java
+K 25
+svn:wc:ra_dav:version-url
+V 106
+/svn/!svn/ver/198/trunk/isoparser/src/main/java/com/coremedia/iso/boxes/apple/AppleGaplessPlaybackBox.java
+END
+AppleTempBox.java
+K 25
+svn:wc:ra_dav:version-url
+V 95
+/svn/!svn/ver/377/trunk/isoparser/src/main/java/com/coremedia/iso/boxes/apple/AppleTempBox.java
+END
+AppleArtistBox.java
+K 25
+svn:wc:ra_dav:version-url
+V 97
+/svn/!svn/ver/198/trunk/isoparser/src/main/java/com/coremedia/iso/boxes/apple/AppleArtistBox.java
+END
+AppleDataBox.java
+K 25
+svn:wc:ra_dav:version-url
+V 95
+/svn/!svn/ver/507/trunk/isoparser/src/main/java/com/coremedia/iso/boxes/apple/AppleDataBox.java
+END
+AppleTrackNumberBox.java
+K 25
+svn:wc:ra_dav:version-url
+V 102
+/svn/!svn/ver/377/trunk/isoparser/src/main/java/com/coremedia/iso/boxes/apple/AppleTrackNumberBox.java
+END
+AppleLosslessSpecificBox.java
+K 25
+svn:wc:ra_dav:version-url
+V 107
+/svn/!svn/ver/507/trunk/isoparser/src/main/java/com/coremedia/iso/boxes/apple/AppleLosslessSpecificBox.java
+END
+AppleCompilationBox.java
+K 25
+svn:wc:ra_dav:version-url
+V 102
+/svn/!svn/ver/198/trunk/isoparser/src/main/java/com/coremedia/iso/boxes/apple/AppleCompilationBox.java
+END
+AppleCoverBox.java
+K 25
+svn:wc:ra_dav:version-url
+V 96
+/svn/!svn/ver/377/trunk/isoparser/src/main/java/com/coremedia/iso/boxes/apple/AppleCoverBox.java
+END
+AppleEncoderBox.java
+K 25
+svn:wc:ra_dav:version-url
+V 98
+/svn/!svn/ver/198/trunk/isoparser/src/main/java/com/coremedia/iso/boxes/apple/AppleEncoderBox.java
+END
+AppleMeanBox.java
+K 25
+svn:wc:ra_dav:version-url
+V 95
+/svn/!svn/ver/507/trunk/isoparser/src/main/java/com/coremedia/iso/boxes/apple/AppleMeanBox.java
+END
+AppleMediaTypeBox.java
+K 25
+svn:wc:ra_dav:version-url
+V 100
+/svn/!svn/ver/198/trunk/isoparser/src/main/java/com/coremedia/iso/boxes/apple/AppleMediaTypeBox.java
+END
+AppleDescriptionBox.java
+K 25
+svn:wc:ra_dav:version-url
+V 102
+/svn/!svn/ver/198/trunk/isoparser/src/main/java/com/coremedia/iso/boxes/apple/AppleDescriptionBox.java
+END
+AppleDataRateBox.java
+K 25
+svn:wc:ra_dav:version-url
+V 99
+/svn/!svn/ver/507/trunk/isoparser/src/main/java/com/coremedia/iso/boxes/apple/AppleDataRateBox.java
+END
+AppleTrackAuthorBox.java
+K 25
+svn:wc:ra_dav:version-url
+V 102
+/svn/!svn/ver/198/trunk/isoparser/src/main/java/com/coremedia/iso/boxes/apple/AppleTrackAuthorBox.java
+END
+AppleAlbumArtistBox.java
+K 25
+svn:wc:ra_dav:version-url
+V 102
+/svn/!svn/ver/198/trunk/isoparser/src/main/java/com/coremedia/iso/boxes/apple/AppleAlbumArtistBox.java
+END
+AppleDataReferenceBox.java
+K 25
+svn:wc:ra_dav:version-url
+V 104
+/svn/!svn/ver/507/trunk/isoparser/src/main/java/com/coremedia/iso/boxes/apple/AppleDataReferenceBox.java
+END
+AppleItemListBox.java
+K 25
+svn:wc:ra_dav:version-url
+V 99
+/svn/!svn/ver/505/trunk/isoparser/src/main/java/com/coremedia/iso/boxes/apple/AppleItemListBox.java
+END
+AppleGroupingBox.java
+K 25
+svn:wc:ra_dav:version-url
+V 99
+/svn/!svn/ver/198/trunk/isoparser/src/main/java/com/coremedia/iso/boxes/apple/AppleGroupingBox.java
+END
+AppleCustomGenreBox.java
+K 25
+svn:wc:ra_dav:version-url
+V 102
+/svn/!svn/ver/377/trunk/isoparser/src/main/java/com/coremedia/iso/boxes/apple/AppleCustomGenreBox.java
+END
+AppleIdBox.java
+K 25
+svn:wc:ra_dav:version-url
+V 93
+/svn/!svn/ver/198/trunk/isoparser/src/main/java/com/coremedia/iso/boxes/apple/AppleIdBox.java
+END
+AppleReferenceMovieDescriptorBox.java
+K 25
+svn:wc:ra_dav:version-url
+V 115
+/svn/!svn/ver/505/trunk/isoparser/src/main/java/com/coremedia/iso/boxes/apple/AppleReferenceMovieDescriptorBox.java
+END
+AppleAlbumBox.java
+K 25
+svn:wc:ra_dav:version-url
+V 96
+/svn/!svn/ver/198/trunk/isoparser/src/main/java/com/coremedia/iso/boxes/apple/AppleAlbumBox.java
+END
+AppleCommentBox.java
+K 25
+svn:wc:ra_dav:version-url
+V 98
+/svn/!svn/ver/198/trunk/isoparser/src/main/java/com/coremedia/iso/boxes/apple/AppleCommentBox.java
+END
+AppleTvSeasonBox.java
+K 25
+svn:wc:ra_dav:version-url
+V 99
+/svn/!svn/ver/198/trunk/isoparser/src/main/java/com/coremedia/iso/boxes/apple/AppleTvSeasonBox.java
+END
diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/apple/.svn/entries b/isoparser/src/main/java/com/coremedia/iso/boxes/apple/.svn/entries
new file mode 100644
index 0000000..aadbfac
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/apple/.svn/entries
@@ -0,0 +1,1490 @@
+10
+
+dir
+778
+http://mp4parser.googlecode.com/svn/trunk/isoparser/src/main/java/com/coremedia/iso/boxes/apple
+http://mp4parser.googlecode.com/svn
+
+
+
+2012-04-21T22:05:38.425329Z
+507
+Sebastian.Annies@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+7decde4b-c250-0410-a0da-51896bc88be6
+
+AppleTrackTitleBox.java
+file
+
+
+
+
+2012-09-14T17:27:52.037241Z
+d00320057c7c9b507bdd9413d190eade
+2011-08-11T14:33:30.631951Z
+198
+Sebastian.Annies@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+302
+
+AppleCopyrightBox.java
+file
+
+
+
+
+2012-09-14T17:27:52.037241Z
+d10479559734743978d76f30ffc59465
+2011-08-11T14:33:30.631951Z
+198
+Sebastian.Annies@gmail.com
+has-props
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+323
+
+ApplePurchaseDateBox.java
+file
+
+
+
+
+2012-09-14T17:27:52.037241Z
+a970bf8322f9e093a3916aec472ea947
+2011-08-11T14:33:30.631951Z
+198
+Sebastian.Annies@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+300
+
+AppleSortAlbumBox.java
+file
+
+
+
+
+2012-09-14T17:27:52.037241Z
+517e986ff5c8917167163f94bdf507dd
+2011-08-11T14:33:30.631951Z
+198
+Sebastian.Annies@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+293
+
+AppleTvEpisodeNumberBox.java
+file
+
+
+
+
+2012-09-14T17:27:52.037241Z
+203d82f75cf575c09a2fc51a9de729a1
+2011-08-11T14:33:30.631951Z
+198
+Sebastian.Annies@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+326
+
+AppleStoreAccountTypeBox.java
+file
+
+
+
+
+2012-09-14T17:27:52.037241Z
+5b6e2900853c7d47daba86a93ab9df6b
+2012-03-05T23:28:24.666173Z
+377
+Sebastian.Annies@gmail.com
+has-props
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+646
+
+AppleStoreCountryCodeBox.java
+file
+
+
+
+
+2012-09-14T17:27:52.037241Z
+0e1bb94c09e72b3d9973d376c42c5455
+2011-08-11T14:33:30.631951Z
+198
+Sebastian.Annies@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+1772
+
+AppleGenericBox.java
+file
+
+
+
+
+2012-09-14T17:27:52.037241Z
+290bdaf97d2b67e2f04fec1b5bf251fe
+2012-04-21T21:18:31.685061Z
+505
+Sebastian.Annies@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+279
+
+AppleNameBox.java
+file
+
+
+
+
+2012-09-14T17:27:52.037241Z
+8e435cf54ce66721515e4cc955be94d5
+2012-04-21T22:05:38.425329Z
+507
+Sebastian.Annies@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+1075
+
+AppleShowBox.java
+file
+
+
+
+
+2012-09-14T17:27:52.037241Z
+47cc10c763e97419f7e57eeaaf469abe
+2011-08-11T14:33:30.631951Z
+198
+Sebastian.Annies@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+284
+
+AppleStandardGenreBox.java
+file
+
+
+
+
+2012-09-14T17:27:52.037241Z
+849a14b354905fbb51d173ceeb520730
+2011-08-11T14:33:30.631951Z
+198
+Sebastian.Annies@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+301
+
+AppleRatingBox.java
+file
+
+
+
+
+2012-09-14T17:27:52.037241Z
+fc93688c8546a210349c4b42e916abec
+2011-08-11T14:33:30.631951Z
+198
+Sebastian.Annies@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+308
+
+AppleSynopsisBox.java
+file
+
+
+
+
+2012-09-14T17:27:52.037241Z
+a0c3dab5469f58afffbb7a26440b4cd3
+2011-08-11T14:33:30.631951Z
+198
+Sebastian.Annies@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+293
+
+AppleNetworkBox.java
+file
+
+
+
+
+2012-09-14T17:27:52.037241Z
+9af00d5cc53625f084891cd0985219cb
+2011-08-11T14:33:30.631951Z
+198
+Sebastian.Annies@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+291
+
+AppleRecordingYearBox.java
+file
+
+
+
+
+2012-09-14T17:27:52.037241Z
+14e939016b9c0c909240a680b92d4300
+2011-08-11T14:33:30.631951Z
+198
+Sebastian.Annies@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+302
+
+AppleReferenceMovieBox.java
+file
+
+
+
+
+2012-09-14T17:27:52.037241Z
+1c577082bb05a1d59ae899bcef5bbce1
+2012-04-21T21:18:31.685061Z
+505
+Sebastian.Annies@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+907
+
+AppleTvEpisodeBox.java
+file
+
+
+
+
+2012-09-14T17:27:52.037241Z
+a433a5413c9363a190f588ff6af717b2
+2011-08-11T14:33:30.631951Z
+198
+Sebastian.Annies@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+314
+
+AppleWaveBox.java
+file
+
+
+
+
+2012-09-14T17:27:52.037241Z
+07d6df3c463714a51bd6957fec7b15f5
+2012-04-21T21:18:31.685061Z
+505
+Sebastian.Annies@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+275
+
+AbstractAppleMetaDataBox.java
+file
+
+
+
+
+2012-09-14T17:27:52.037241Z
+3beb0cfc7e1f245f23ac59adecf6c90b
+2012-04-21T22:05:38.425329Z
+507
+Sebastian.Annies@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+5703
+
+AppleGaplessPlaybackBox.java
+file
+
+
+
+
+2012-09-14T17:27:52.037241Z
+610b85d8fe94c499ba679e47d7af59aa
+2011-08-11T14:33:30.631951Z
+198
+Sebastian.Annies@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+339
+
+AppleTempBox.java
+file
+
+
+
+
+2012-09-14T17:27:52.037241Z
+ab1b52b242ac326460a50dafcb4d586b
+2012-03-05T23:28:24.666173Z
+377
+Sebastian.Annies@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+682
+
+AppleArtistBox.java
+file
+
+
+
+
+2012-09-14T17:27:52.037241Z
+50d2d51ac35d53fa91d596d9fba893c1
+2011-08-11T14:33:30.631951Z
+198
+Sebastian.Annies@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+330
+
+AppleDataBox.java
+file
+
+
+
+
+2012-09-14T17:27:52.037241Z
+064c87d2b50c91ebaa552f3b53844de2
+2012-04-21T22:05:38.425329Z
+507
+Sebastian.Annies@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+2475
+
+AppleTrackNumberBox.java
+file
+
+
+
+
+2012-09-14T17:27:52.047241Z
+3cf21c036183461f0a26d7812cd54a11
+2012-03-05T23:28:24.666173Z
+377
+Sebastian.Annies@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+1177
+
+AppleLosslessSpecificBox.java
+file
+
+
+
+
+2012-09-14T17:27:52.047241Z
+3659a7955b976252491eaff784518492
+2012-04-21T22:05:38.425329Z
+507
+Sebastian.Annies@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+4638
+
+AppleCompilationBox.java
+file
+
+
+
+
+2012-09-14T17:27:52.047241Z
+e6bcc185918d8b2d3c449bd1218536c9
+2011-08-11T14:33:30.631951Z
+198
+Sebastian.Annies@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+324
+
+AppleCoverBox.java
+file
+
+
+
+
+2012-09-14T17:27:52.047241Z
+9d9ec44a18fdc7b3490073454ae6bf8e
+2012-03-05T23:28:24.666173Z
+377
+Sebastian.Annies@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+1005
+
+AppleEncoderBox.java
+file
+
+
+
+
+2012-09-14T17:27:52.047241Z
+aa3191200ee624f2fde12d6d29da22c3
+2011-08-11T14:33:30.631951Z
+198
+Sebastian.Annies@gmail.com
+has-props
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+324
+
+AppleMeanBox.java
+file
+
+
+
+
+2012-09-14T17:27:52.047241Z
+d64b8d0e17b59ff76c984d831a36cc85
+2012-04-21T22:05:38.425329Z
+507
+Sebastian.Annies@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+1151
+
+AppleMediaTypeBox.java
+file
+
+
+
+
+2012-09-14T17:27:52.047241Z
+ca121472ac950656cb0158cecb259db9
+2011-08-11T14:33:30.631951Z
+198
+Sebastian.Annies@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+1038
+
+AppleDescriptionBox.java
+file
+
+
+
+
+2012-09-14T17:27:52.047241Z
+21ee5c043816a5117165b95234eadc13
+2011-08-11T14:33:30.631951Z
+198
+Sebastian.Annies@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+298
+
+AppleDataRateBox.java
+file
+
+
+
+
+2012-09-14T17:27:52.047241Z
+88e0145f42678bb7a380e50bd8ab3157
+2012-04-21T22:05:38.425329Z
+507
+Sebastian.Annies@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+1514
+
+AppleTrackAuthorBox.java
+file
+
+
+
+
+2012-09-14T17:27:52.047241Z
+5a6f88b1189b0d1cd56f336ee6400d80
+2011-08-11T14:33:30.631951Z
+198
+Sebastian.Annies@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+304
+
+AppleAlbumArtistBox.java
+file
+
+
+
+
+2012-09-14T17:27:52.047241Z
+2595bb2e066cee575a8cd963e6ce648a
+2011-08-11T14:33:30.631951Z
+198
+Sebastian.Annies@gmail.com
+has-props
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+322
+
+AppleDataReferenceBox.java
+file
+
+
+
+
+2012-09-14T17:27:52.047241Z
+c47ce167549e9d5b400ed21b64450a4e
+2012-04-21T22:05:38.425329Z
+507
+Sebastian.Annies@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+2226
+
+AppleItemListBox.java
+file
+
+
+
+
+2012-09-14T17:27:52.047241Z
+2e430a7e3bc2d56e975340e9899a05ae
+2012-04-21T21:18:31.685061Z
+505
+Sebastian.Annies@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+310
+
+AppleGroupingBox.java
+file
+
+
+
+
+2012-09-14T17:27:52.047241Z
+a12a7d1cc3c693cfd8ec5c20df44aa1c
+2011-08-11T14:33:30.631951Z
+198
+Sebastian.Annies@gmail.com
+has-props
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+326
+
+AppleCustomGenreBox.java
+file
+
+
+
+
+2012-09-14T17:27:52.047241Z
+2e06c42c89625ea9943c5bca05040844
+2012-03-05T23:28:24.666173Z
+377
+Sebastian.Annies@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+685
+
+AppleIdBox.java
+file
+
+
+
+
+2012-09-14T17:27:52.047241Z
+18aecf8082534727517207e0f00df3ba
+2011-08-11T14:33:30.631951Z
+198
+Sebastian.Annies@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+280
+
+AppleReferenceMovieDescriptorBox.java
+file
+
+
+
+
+2012-09-14T17:27:52.047241Z
+f621253270c3f55828bd412050238d07
+2012-04-21T21:18:31.685061Z
+505
+Sebastian.Annies@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+925
+
+AppleAlbumBox.java
+file
+
+
+
+
+2012-09-14T17:27:52.047241Z
+4a59cf2bbab9bc17ef1a28da752902e9
+2011-08-11T14:33:30.631951Z
+198
+Sebastian.Annies@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+291
+
+AppleCommentBox.java
+file
+
+
+
+
+2012-09-14T17:27:52.047241Z
+e0d8d51f0b5f000fcea8ee721c2bf382
+2011-08-11T14:33:30.631951Z
+198
+Sebastian.Annies@gmail.com
+has-props
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+326
+
+AppleTvSeasonBox.java
+file
+
+
+
+
+2012-09-14T17:27:52.047241Z
+c991f4f5c2998dc6d20404138653705b
+2011-08-11T14:33:30.631951Z
+198
+Sebastian.Annies@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+317
+
diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/apple/.svn/prop-base/AppleAlbumArtistBox.java.svn-base b/isoparser/src/main/java/com/coremedia/iso/boxes/apple/.svn/prop-base/AppleAlbumArtistBox.java.svn-base
new file mode 100644
index 0000000..869ac71
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/apple/.svn/prop-base/AppleAlbumArtistBox.java.svn-base
@@ -0,0 +1,5 @@
+K 14
+svn:executable
+V 1
+*
+END
diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/apple/.svn/prop-base/AppleCommentBox.java.svn-base b/isoparser/src/main/java/com/coremedia/iso/boxes/apple/.svn/prop-base/AppleCommentBox.java.svn-base
new file mode 100644
index 0000000..869ac71
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/apple/.svn/prop-base/AppleCommentBox.java.svn-base
@@ -0,0 +1,5 @@
+K 14
+svn:executable
+V 1
+*
+END
diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/apple/.svn/prop-base/AppleCopyrightBox.java.svn-base b/isoparser/src/main/java/com/coremedia/iso/boxes/apple/.svn/prop-base/AppleCopyrightBox.java.svn-base
new file mode 100644
index 0000000..869ac71
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/apple/.svn/prop-base/AppleCopyrightBox.java.svn-base
@@ -0,0 +1,5 @@
+K 14
+svn:executable
+V 1
+*
+END
diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/apple/.svn/prop-base/AppleEncoderBox.java.svn-base b/isoparser/src/main/java/com/coremedia/iso/boxes/apple/.svn/prop-base/AppleEncoderBox.java.svn-base
new file mode 100644
index 0000000..869ac71
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/apple/.svn/prop-base/AppleEncoderBox.java.svn-base
@@ -0,0 +1,5 @@
+K 14
+svn:executable
+V 1
+*
+END
diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/apple/.svn/prop-base/AppleGroupingBox.java.svn-base b/isoparser/src/main/java/com/coremedia/iso/boxes/apple/.svn/prop-base/AppleGroupingBox.java.svn-base
new file mode 100644
index 0000000..869ac71
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/apple/.svn/prop-base/AppleGroupingBox.java.svn-base
@@ -0,0 +1,5 @@
+K 14
+svn:executable
+V 1
+*
+END
diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/apple/.svn/prop-base/AppleStoreAccountTypeBox.java.svn-base b/isoparser/src/main/java/com/coremedia/iso/boxes/apple/.svn/prop-base/AppleStoreAccountTypeBox.java.svn-base
new file mode 100644
index 0000000..869ac71
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/apple/.svn/prop-base/AppleStoreAccountTypeBox.java.svn-base
@@ -0,0 +1,5 @@
+K 14
+svn:executable
+V 1
+*
+END
diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/apple/.svn/text-base/AbstractAppleMetaDataBox.java.svn-base b/isoparser/src/main/java/com/coremedia/iso/boxes/apple/.svn/text-base/AbstractAppleMetaDataBox.java.svn-base
new file mode 100644
index 0000000..fdb7ac9
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/apple/.svn/text-base/AbstractAppleMetaDataBox.java.svn-base
@@ -0,0 +1,164 @@
+package com.coremedia.iso.boxes.apple;
+
+import com.coremedia.iso.IsoTypeReader;
+import com.coremedia.iso.IsoTypeWriter;
+import com.coremedia.iso.Utf8;
+import com.googlecode.mp4parser.AbstractBox;
+import com.coremedia.iso.boxes.Box;
+import com.coremedia.iso.boxes.ContainerBox;
+import com.googlecode.mp4parser.util.ByteBufferByteChannel;
+
+import java.io.IOException;
+import java.math.BigInteger;
+import java.nio.ByteBuffer;
+import java.util.Collections;
+import java.util.List;
+import java.util.logging.Logger;
+
+/**
+ *
+ */
+public abstract class AbstractAppleMetaDataBox extends AbstractBox implements ContainerBox {
+    private static Logger LOG = Logger.getLogger(AbstractAppleMetaDataBox.class.getName());
+    AppleDataBox appleDataBox = new AppleDataBox();
+
+    public List<Box> getBoxes() {
+        return Collections.singletonList((Box) appleDataBox);
+    }
+
+    public void setBoxes(List<Box> boxes) {
+        if (boxes.size() == 1 && boxes.get(0) instanceof AppleDataBox) {
+            appleDataBox = (AppleDataBox) boxes.get(0);
+        } else {
+            throw new IllegalArgumentException("This box only accepts one AppleDataBox child");
+        }
+    }
+
+    public <T extends Box> List<T> getBoxes(Class<T> clazz) {
+        return getBoxes(clazz, false);
+    }
+
+    public <T extends Box> List<T> getBoxes(Class<T> clazz, boolean recursive) {
+        //todo recursive?
+        if (clazz.isAssignableFrom(appleDataBox.getClass())) {
+            return (List<T>) Collections.singletonList(appleDataBox);
+        }
+        return null;
+    }
+
+    public AbstractAppleMetaDataBox(String type) {
+        super(type);
+    }
+
+    @Override
+    public void _parseDetails(ByteBuffer content) {
+        long dataBoxSize = IsoTypeReader.readUInt32(content);
+        String thisShouldBeData = IsoTypeReader.read4cc(content);
+        assert "data".equals(thisShouldBeData);
+        appleDataBox = new AppleDataBox();
+        try {
+            appleDataBox.parse(new ByteBufferByteChannel(content), null, content.remaining(), null);
+        } catch (IOException e) {
+            throw new RuntimeException(e);
+        }
+        appleDataBox.setParent(this);
+    }
+
+
+    protected long getContentSize() {
+        return appleDataBox.getSize();
+    }
+
+    protected void getContent(ByteBuffer byteBuffer) {
+        try {
+            appleDataBox.getBox(new ByteBufferByteChannel(byteBuffer));
+        } catch (IOException e) {
+            throw new RuntimeException("The Channel is based on a ByteBuffer and therefore it shouldn't throw any exception");
+        }
+    }
+
+    public long getNumOfBytesToFirstChild() {
+        return getSize() - appleDataBox.getSize();
+    }
+
+    @Override
+    public String toString() {
+        return this.getClass().getSimpleName() + "{" +
+                "appleDataBox=" + getValue() +
+                '}';
+    }
+
+    static long toLong(byte b) {
+        return b < 0 ? b + 256 : b;
+    }
+
+    public void setValue(String value) {
+        if (appleDataBox.getFlags() == 1) {
+            appleDataBox = new AppleDataBox();
+            appleDataBox.setVersion(0);
+            appleDataBox.setFlags(1);
+            appleDataBox.setFourBytes(new byte[4]);
+            appleDataBox.setData(Utf8.convert(value));
+        } else if (appleDataBox.getFlags() == 21) {
+            byte[] content = appleDataBox.getData();
+            appleDataBox = new AppleDataBox();
+            appleDataBox.setVersion(0);
+            appleDataBox.setFlags(21);
+            appleDataBox.setFourBytes(new byte[4]);
+
+            ByteBuffer bb = ByteBuffer.allocate(content.length);
+            if (content.length == 1) {
+                IsoTypeWriter.writeUInt8(bb, (Byte.parseByte(value) & 0xFF));
+            } else if (content.length == 2) {
+                IsoTypeWriter.writeUInt16(bb, Integer.parseInt(value));
+            } else if (content.length == 4) {
+                IsoTypeWriter.writeUInt32(bb, Long.parseLong(value));
+            } else if (content.length == 8) {
+                IsoTypeWriter.writeUInt64(bb, Long.parseLong(value));
+            } else {
+                throw new Error("The content length within the appleDataBox is neither 1, 2, 4 or 8. I can't handle that!");
+            }
+            appleDataBox.setData(bb.array());
+        } else if (appleDataBox.getFlags() == 0) {
+            appleDataBox = new AppleDataBox();
+            appleDataBox.setVersion(0);
+            appleDataBox.setFlags(0);
+            appleDataBox.setFourBytes(new byte[4]);
+            appleDataBox.setData(hexStringToByteArray(value));
+
+        } else {
+            LOG.warning("Don't know how to handle appleDataBox with flag=" + appleDataBox.getFlags());
+        }
+    }
+
+    public String getValue() {
+        if (appleDataBox.getFlags() == 1) {
+            return Utf8.convert(appleDataBox.getData());
+        } else if (appleDataBox.getFlags() == 21) {
+            byte[] content = appleDataBox.getData();
+            long l = 0;
+            int current = 1;
+            int length = content.length;
+            for (byte b : content) {
+                l += toLong(b) << (8 * (length - current++));
+            }
+            return "" + l;
+        } else if (appleDataBox.getFlags() == 0) {
+            return String.format("%x", new BigInteger(appleDataBox.getData()));
+        } else {
+            return "unknown";
+        }
+    }
+
+    public static byte[] hexStringToByteArray(String s) {
+        int len = s.length();
+        byte[] data = new byte[len / 2];
+        for (int i = 0; i < len; i += 2) {
+            data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4)
+                    + Character.digit(s.charAt(i + 1), 16));
+        }
+        return data;
+    }
+
+
+}
diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/apple/.svn/text-base/AppleAlbumArtistBox.java.svn-base b/isoparser/src/main/java/com/coremedia/iso/boxes/apple/.svn/text-base/AppleAlbumArtistBox.java.svn-base
new file mode 100644
index 0000000..5c258b4
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/apple/.svn/text-base/AppleAlbumArtistBox.java.svn-base
@@ -0,0 +1,16 @@
+package com.coremedia.iso.boxes.apple;
+
+/**
+ * itunes MetaData comment box.
+ */
+public class AppleAlbumArtistBox extends AbstractAppleMetaDataBox {
+    public static final String TYPE = "aART";
+
+
+    public AppleAlbumArtistBox() {
+        super(TYPE);
+        appleDataBox = AppleDataBox.getStringAppleDataBox();
+    }
+
+
+}
\ No newline at end of file
diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/apple/.svn/text-base/AppleAlbumBox.java.svn-base b/isoparser/src/main/java/com/coremedia/iso/boxes/apple/.svn/text-base/AppleAlbumBox.java.svn-base
new file mode 100644
index 0000000..9e3d5f7
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/apple/.svn/text-base/AppleAlbumBox.java.svn-base
@@ -0,0 +1,15 @@
+package com.coremedia.iso.boxes.apple;
+
+/**
+ *
+ */
+public final class AppleAlbumBox extends AbstractAppleMetaDataBox {
+    public static final String TYPE = "\u00a9alb";
+
+
+    public AppleAlbumBox() {
+        super(TYPE);
+        appleDataBox = AppleDataBox.getStringAppleDataBox();
+    }
+
+}
\ No newline at end of file
diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/apple/.svn/text-base/AppleArtistBox.java.svn-base b/isoparser/src/main/java/com/coremedia/iso/boxes/apple/.svn/text-base/AppleArtistBox.java.svn-base
new file mode 100644
index 0000000..627a603
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/apple/.svn/text-base/AppleArtistBox.java.svn-base
@@ -0,0 +1,16 @@
+package com.coremedia.iso.boxes.apple;

+

+/**

+ * iTunes Artist box.

+ */

+public final class AppleArtistBox extends AbstractAppleMetaDataBox {

+    public static final String TYPE = "\u00a9ART";

+

+

+    public AppleArtistBox() {

+        super(TYPE);

+        appleDataBox = AppleDataBox.getStringAppleDataBox();

+    }

+

+

+}

diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/apple/.svn/text-base/AppleCommentBox.java.svn-base b/isoparser/src/main/java/com/coremedia/iso/boxes/apple/.svn/text-base/AppleCommentBox.java.svn-base
new file mode 100644
index 0000000..b58899f
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/apple/.svn/text-base/AppleCommentBox.java.svn-base
@@ -0,0 +1,16 @@
+package com.coremedia.iso.boxes.apple;
+
+/**
+ * itunes MetaData comment box.
+ */
+public final class AppleCommentBox extends AbstractAppleMetaDataBox {
+    public static final String TYPE = "\u00a9cmt";
+
+
+    public AppleCommentBox() {
+        super(TYPE);
+        appleDataBox = AppleDataBox.getStringAppleDataBox();
+    }
+
+
+}
diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/apple/.svn/text-base/AppleCompilationBox.java.svn-base b/isoparser/src/main/java/com/coremedia/iso/boxes/apple/.svn/text-base/AppleCompilationBox.java.svn-base
new file mode 100644
index 0000000..c8c9bf4
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/apple/.svn/text-base/AppleCompilationBox.java.svn-base
@@ -0,0 +1,15 @@
+package com.coremedia.iso.boxes.apple;

+

+/**

+ * Compilation.

+ */

+public final class AppleCompilationBox extends AbstractAppleMetaDataBox {

+    public static final String TYPE = "cpil";

+

+

+    public AppleCompilationBox() {

+        super(TYPE);

+        appleDataBox = AppleDataBox.getUint8AppleDataBox();

+    }

+

+}
\ No newline at end of file
diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/apple/.svn/text-base/AppleCopyrightBox.java.svn-base b/isoparser/src/main/java/com/coremedia/iso/boxes/apple/.svn/text-base/AppleCopyrightBox.java.svn-base
new file mode 100644
index 0000000..ae44285
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/apple/.svn/text-base/AppleCopyrightBox.java.svn-base
@@ -0,0 +1,15 @@
+package com.coremedia.iso.boxes.apple;
+
+/**
+ * itunes MetaData comment box.
+ */
+public final class AppleCopyrightBox extends AbstractAppleMetaDataBox {
+    public static final String TYPE = "cprt";
+
+
+    public AppleCopyrightBox() {
+        super(TYPE);
+        appleDataBox = AppleDataBox.getStringAppleDataBox();
+    }
+
+}
\ No newline at end of file
diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/apple/.svn/text-base/AppleCoverBox.java.svn-base b/isoparser/src/main/java/com/coremedia/iso/boxes/apple/.svn/text-base/AppleCoverBox.java.svn-base
new file mode 100644
index 0000000..946dd49
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/apple/.svn/text-base/AppleCoverBox.java.svn-base
@@ -0,0 +1,44 @@
+package com.coremedia.iso.boxes.apple;
+
+import java.util.logging.Logger;
+
+/**
+ *
+ */
+public final class AppleCoverBox extends AbstractAppleMetaDataBox {
+    private static Logger LOG = Logger.getLogger(AppleCoverBox.class.getName());
+    public static final String TYPE = "covr";
+
+
+    public AppleCoverBox() {
+        super(TYPE);
+    }
+
+
+    public void setPng(byte[] pngData) {
+        appleDataBox = new AppleDataBox();
+        appleDataBox.setVersion(0);
+        appleDataBox.setFlags(0xe);
+        appleDataBox.setFourBytes(new byte[4]);
+        appleDataBox.setData(pngData);
+    }
+
+
+    public void setJpg(byte[] jpgData) {
+        appleDataBox = new AppleDataBox();
+        appleDataBox.setVersion(0);
+        appleDataBox.setFlags(0xd);
+        appleDataBox.setFourBytes(new byte[4]);
+        appleDataBox.setData(jpgData);
+    }
+
+    @Override
+    public void setValue(String value) {
+        LOG.warning("---");
+    }
+
+    @Override
+    public String getValue() {
+        return "---";
+    }
+}
\ No newline at end of file
diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/apple/.svn/text-base/AppleCustomGenreBox.java.svn-base b/isoparser/src/main/java/com/coremedia/iso/boxes/apple/.svn/text-base/AppleCustomGenreBox.java.svn-base
new file mode 100644
index 0000000..0c67f97
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/apple/.svn/text-base/AppleCustomGenreBox.java.svn-base
@@ -0,0 +1,28 @@
+package com.coremedia.iso.boxes.apple;
+
+import com.coremedia.iso.Utf8;
+
+/**
+ *
+ */
+public final class AppleCustomGenreBox extends AbstractAppleMetaDataBox {
+    public static final String TYPE = "\u00a9gen";
+
+
+    public AppleCustomGenreBox() {
+        super(TYPE);
+        appleDataBox = AppleDataBox.getStringAppleDataBox();
+    }
+
+    public void setGenre(String genre) {
+        appleDataBox = new AppleDataBox();
+        appleDataBox.setVersion(0);
+        appleDataBox.setFlags(1);
+        appleDataBox.setFourBytes(new byte[4]);
+        appleDataBox.setData(Utf8.convert(genre));
+    }
+
+    public String getGenre() {
+        return Utf8.convert(appleDataBox.getData());
+    }
+}
\ No newline at end of file
diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/apple/.svn/text-base/AppleDataBox.java.svn-base b/isoparser/src/main/java/com/coremedia/iso/boxes/apple/.svn/text-base/AppleDataBox.java.svn-base
new file mode 100644
index 0000000..ba42629
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/apple/.svn/text-base/AppleDataBox.java.svn-base
@@ -0,0 +1,92 @@
+package com.coremedia.iso.boxes.apple;
+
+import com.googlecode.mp4parser.AbstractFullBox;
+
+import java.nio.ByteBuffer;
+
+/**
+ * Most stupid box of the world. Encapsulates actual data within
+ */
+public final class AppleDataBox extends AbstractFullBox {
+    public static final String TYPE = "data";
+
+    private byte[] fourBytes = new byte[4];
+    private byte[] data;
+
+    private static AppleDataBox getEmpty() {
+        AppleDataBox appleDataBox = new AppleDataBox();
+        appleDataBox.setVersion(0);
+        appleDataBox.setFourBytes(new byte[4]);
+        return appleDataBox;
+    }
+
+    public static AppleDataBox getStringAppleDataBox() {
+        AppleDataBox appleDataBox = getEmpty();
+        appleDataBox.setFlags(1);
+        appleDataBox.setData(new byte[]{0});
+        return appleDataBox;
+    }
+
+    public static AppleDataBox getUint8AppleDataBox() {
+        AppleDataBox appleDataBox = new AppleDataBox();
+        appleDataBox.setFlags(21);
+        appleDataBox.setData(new byte[]{0});
+        return appleDataBox;
+    }
+
+    public static AppleDataBox getUint16AppleDataBox() {
+        AppleDataBox appleDataBox = new AppleDataBox();
+        appleDataBox.setFlags(21);
+        appleDataBox.setData(new byte[]{0, 0});
+        return appleDataBox;
+    }
+
+    public static AppleDataBox getUint32AppleDataBox() {
+        AppleDataBox appleDataBox = new AppleDataBox();
+        appleDataBox.setFlags(21);
+        appleDataBox.setData(new byte[]{0, 0, 0, 0});
+        return appleDataBox;
+    }
+
+    public AppleDataBox() {
+        super(TYPE);
+    }
+
+    protected long getContentSize() {
+        return data.length + 8;
+    }
+
+    public void setData(byte[] data) {
+        this.data = new byte[data.length];
+        System.arraycopy(data, 0, this.data, 0, data.length);
+    }
+
+    public void setFourBytes(byte[] fourBytes) {
+        System.arraycopy(fourBytes, 0, this.fourBytes, 0, 4);
+    }
+
+    @Override
+    public void _parseDetails(ByteBuffer content) {
+        parseVersionAndFlags(content);
+        fourBytes = new byte[4];
+        content.get(fourBytes);
+        data = new byte[content.remaining()];
+        content.get(data);
+    }
+
+
+    @Override
+    protected void getContent(ByteBuffer byteBuffer) {
+        writeVersionAndFlags(byteBuffer);
+        byteBuffer.put(fourBytes, 0, 4);
+        byteBuffer.put(data);
+    }
+
+    public byte[] getFourBytes() {
+        return fourBytes;
+    }
+
+    public byte[] getData() {
+        return data;
+    }
+}
diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/apple/.svn/text-base/AppleDataRateBox.java.svn-base b/isoparser/src/main/java/com/coremedia/iso/boxes/apple/.svn/text-base/AppleDataRateBox.java.svn-base
new file mode 100644
index 0000000..e58e550
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/apple/.svn/text-base/AppleDataRateBox.java.svn-base
@@ -0,0 +1,53 @@
+/*

+ * Copyright 2009 castLabs GmbH, Berlin

+ *

+ * Licensed under the Apache License, Version 2.0 (the License);

+ * you may not use this file except in compliance with the License.

+ * You may obtain a copy of the License at

+ *

+ *     http://www.apache.org/licenses/LICENSE-2.0

+ *

+ * Unless required by applicable law or agreed to in writing, software

+ * distributed under the License is distributed on an AS IS BASIS,

+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

+ * See the License for the specific language governing permissions and

+ * limitations under the License.

+ */

+

+package com.coremedia.iso.boxes.apple;

+

+import com.coremedia.iso.IsoTypeReader;

+import com.coremedia.iso.IsoTypeWriter;

+import com.googlecode.mp4parser.AbstractFullBox;

+

+import java.nio.ByteBuffer;

+

+public class AppleDataRateBox extends AbstractFullBox {

+    public static final String TYPE = "rmdr";

+    private long dataRate;

+

+    public AppleDataRateBox() {

+        super(TYPE);

+    }

+

+    protected long getContentSize() {

+        return 8;

+    }

+

+    @Override

+    public void _parseDetails(ByteBuffer content) {

+        parseVersionAndFlags(content);

+        dataRate = IsoTypeReader.readUInt32(content);

+    }

+

+    @Override

+    protected void getContent(ByteBuffer byteBuffer) {

+        writeVersionAndFlags(byteBuffer);

+        IsoTypeWriter.writeUInt32(byteBuffer, dataRate);

+    }

+

+

+    public long getDataRate() {

+        return dataRate;

+    }

+}

diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/apple/.svn/text-base/AppleDataReferenceBox.java.svn-base b/isoparser/src/main/java/com/coremedia/iso/boxes/apple/.svn/text-base/AppleDataReferenceBox.java.svn-base
new file mode 100644
index 0000000..7370c10
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/apple/.svn/text-base/AppleDataReferenceBox.java.svn-base
@@ -0,0 +1,71 @@
+/*

+ * Copyright 2009 castLabs GmbH, Berlin

+ *

+ * Licensed under the Apache License, Version 2.0 (the License);

+ * you may not use this file except in compliance with the License.

+ * You may obtain a copy of the License at

+ *

+ *     http://www.apache.org/licenses/LICENSE-2.0

+ *

+ * Unless required by applicable law or agreed to in writing, software

+ * distributed under the License is distributed on an AS IS BASIS,

+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

+ * See the License for the specific language governing permissions and

+ * limitations under the License.

+ */

+

+package com.coremedia.iso.boxes.apple;

+

+import com.coremedia.iso.IsoFile;

+import com.coremedia.iso.IsoTypeReader;

+import com.coremedia.iso.IsoTypeWriter;

+import com.coremedia.iso.Utf8;

+import com.googlecode.mp4parser.AbstractFullBox;

+

+import java.nio.ByteBuffer;

+

+import static com.googlecode.mp4parser.util.CastUtils.l2i;

+

+public class AppleDataReferenceBox extends AbstractFullBox {

+    public static final String TYPE = "rdrf";

+    private int dataReferenceSize;

+    private String dataReferenceType;

+    private String dataReference;

+

+    public AppleDataReferenceBox() {

+        super(TYPE);

+    }

+

+

+    protected long getContentSize() {

+        return 12 + dataReferenceSize;

+    }

+

+    @Override

+    public void _parseDetails(ByteBuffer content) {

+        parseVersionAndFlags(content);

+        dataReferenceType = IsoTypeReader.read4cc(content);

+        dataReferenceSize = l2i(IsoTypeReader.readUInt32(content));

+        dataReference = IsoTypeReader.readString(content, dataReferenceSize);

+    }

+

+    @Override

+    protected void getContent(ByteBuffer byteBuffer) {

+        writeVersionAndFlags(byteBuffer);

+        byteBuffer.put(IsoFile.fourCCtoBytes(dataReferenceType));

+        IsoTypeWriter.writeUInt32(byteBuffer, dataReferenceSize);

+        byteBuffer.put(Utf8.convert(dataReference));

+    }

+

+    public long getDataReferenceSize() {

+        return dataReferenceSize;

+    }

+

+    public String getDataReferenceType() {

+        return dataReferenceType;

+    }

+

+    public String getDataReference() {

+        return dataReference;

+    }

+}

diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/apple/.svn/text-base/AppleDescriptionBox.java.svn-base b/isoparser/src/main/java/com/coremedia/iso/boxes/apple/.svn/text-base/AppleDescriptionBox.java.svn-base
new file mode 100644
index 0000000..e20e0fc
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/apple/.svn/text-base/AppleDescriptionBox.java.svn-base
@@ -0,0 +1,15 @@
+package com.coremedia.iso.boxes.apple;
+
+/**
+ *
+ */
+public final class AppleDescriptionBox extends AbstractAppleMetaDataBox {
+    public static final String TYPE = "desc";
+
+
+    public AppleDescriptionBox() {
+        super(TYPE);
+        appleDataBox = AppleDataBox.getStringAppleDataBox();
+    }
+
+}
\ No newline at end of file
diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/apple/.svn/text-base/AppleEncoderBox.java.svn-base b/isoparser/src/main/java/com/coremedia/iso/boxes/apple/.svn/text-base/AppleEncoderBox.java.svn-base
new file mode 100644
index 0000000..5a59e81
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/apple/.svn/text-base/AppleEncoderBox.java.svn-base
@@ -0,0 +1,15 @@
+package com.coremedia.iso.boxes.apple;
+
+/**
+ * itunes MetaData comment box.
+ */
+public final class AppleEncoderBox extends AbstractAppleMetaDataBox {
+    public static final String TYPE = "\u00a9too";
+
+
+    public AppleEncoderBox() {
+        super(TYPE);
+        appleDataBox = AppleDataBox.getStringAppleDataBox();
+    }
+
+}
\ No newline at end of file
diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/apple/.svn/text-base/AppleGaplessPlaybackBox.java.svn-base b/isoparser/src/main/java/com/coremedia/iso/boxes/apple/.svn/text-base/AppleGaplessPlaybackBox.java.svn-base
new file mode 100644
index 0000000..c617a54
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/apple/.svn/text-base/AppleGaplessPlaybackBox.java.svn-base
@@ -0,0 +1,15 @@
+package com.coremedia.iso.boxes.apple;

+

+/**

+ * Gapless Playback.

+ */

+public final class AppleGaplessPlaybackBox extends AbstractAppleMetaDataBox {

+    public static final String TYPE = "pgap";

+

+

+    public AppleGaplessPlaybackBox() {

+        super(TYPE);

+        appleDataBox = AppleDataBox.getUint8AppleDataBox();

+    }

+

+}

diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/apple/.svn/text-base/AppleGenericBox.java.svn-base b/isoparser/src/main/java/com/coremedia/iso/boxes/apple/.svn/text-base/AppleGenericBox.java.svn-base
new file mode 100644
index 0000000..177a25b
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/apple/.svn/text-base/AppleGenericBox.java.svn-base
@@ -0,0 +1,15 @@
+package com.coremedia.iso.boxes.apple;
+
+import com.googlecode.mp4parser.AbstractContainerBox;
+
+/**
+ *
+ */
+public final class AppleGenericBox extends AbstractContainerBox {
+    public static final String TYPE = "----";
+
+    public AppleGenericBox() {
+        super(TYPE);
+    }
+
+}
\ No newline at end of file
diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/apple/.svn/text-base/AppleGroupingBox.java.svn-base b/isoparser/src/main/java/com/coremedia/iso/boxes/apple/.svn/text-base/AppleGroupingBox.java.svn-base
new file mode 100644
index 0000000..9884298
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/apple/.svn/text-base/AppleGroupingBox.java.svn-base
@@ -0,0 +1,15 @@
+package com.coremedia.iso.boxes.apple;
+
+/**
+ * itunes MetaData comment box.
+ */
+public final class AppleGroupingBox extends AbstractAppleMetaDataBox {
+    public static final String TYPE = "\u00a9grp";
+
+
+    public AppleGroupingBox() {
+        super(TYPE);
+        appleDataBox = AppleDataBox.getStringAppleDataBox();
+    }
+
+}
\ No newline at end of file
diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/apple/.svn/text-base/AppleIdBox.java.svn-base b/isoparser/src/main/java/com/coremedia/iso/boxes/apple/.svn/text-base/AppleIdBox.java.svn-base
new file mode 100644
index 0000000..08c697e
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/apple/.svn/text-base/AppleIdBox.java.svn-base
@@ -0,0 +1,15 @@
+package com.coremedia.iso.boxes.apple;
+
+/**
+ *
+ */
+public final class AppleIdBox extends AbstractAppleMetaDataBox {
+    public static final String TYPE = "apID";
+
+
+    public AppleIdBox() {
+        super(TYPE);
+        appleDataBox = AppleDataBox.getStringAppleDataBox();
+    }
+
+}
\ No newline at end of file
diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/apple/.svn/text-base/AppleItemListBox.java.svn-base b/isoparser/src/main/java/com/coremedia/iso/boxes/apple/.svn/text-base/AppleItemListBox.java.svn-base
new file mode 100644
index 0000000..cd26e81
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/apple/.svn/text-base/AppleItemListBox.java.svn-base
@@ -0,0 +1,15 @@
+package com.coremedia.iso.boxes.apple;
+
+import com.googlecode.mp4parser.AbstractContainerBox;
+
+/**
+ * undocumented iTunes MetaData Box.
+ */
+public class AppleItemListBox extends AbstractContainerBox {
+    public static final String TYPE = "ilst";
+
+    public AppleItemListBox() {
+        super(TYPE);
+    }
+
+}
diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/apple/.svn/text-base/AppleLosslessSpecificBox.java.svn-base b/isoparser/src/main/java/com/coremedia/iso/boxes/apple/.svn/text-base/AppleLosslessSpecificBox.java.svn-base
new file mode 100644
index 0000000..781af49
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/apple/.svn/text-base/AppleLosslessSpecificBox.java.svn-base
@@ -0,0 +1,163 @@
+package com.coremedia.iso.boxes.apple;

+

+import com.coremedia.iso.IsoTypeReader;

+import com.coremedia.iso.IsoTypeWriter;

+import com.googlecode.mp4parser.AbstractFullBox;

+

+import java.nio.ByteBuffer;

+

+/**

+ *

+ */

+public final class AppleLosslessSpecificBox extends AbstractFullBox {

+

+    public static final String TYPE = "alac";

+    /*

+   Extradata: 32bit size 32bit tag (=alac) 32bit zero?

+   32bit max sample per frame 8bit ?? (zero?) 8bit sample

+   size 8bit history mult 8bit initial history 8bit kmodifier

+   8bit channels? 16bit ?? 32bit max coded frame size 32bit

+   bitrate? 32bit samplerate

+    */

+    private long maxSamplePerFrame; // 32bi

+    private int unknown1; // 8bit

+    private int sampleSize; // 8bit

+    private int historyMult; // 8bit

+    private int initialHistory; // 8bit

+    private int kModifier; // 8bit

+    private int channels; // 8bit

+    private int unknown2; // 16bit

+    private long maxCodedFrameSize; // 32bit

+    private long bitRate; // 32bit

+    private long sampleRate; // 32bit

+

+    public long getMaxSamplePerFrame() {

+        return maxSamplePerFrame;

+    }

+

+    public void setMaxSamplePerFrame(int maxSamplePerFrame) {

+        this.maxSamplePerFrame = maxSamplePerFrame;

+    }

+

+    public int getUnknown1() {

+        return unknown1;

+    }

+

+    public void setUnknown1(int unknown1) {

+        this.unknown1 = unknown1;

+    }

+

+    public int getSampleSize() {

+        return sampleSize;

+    }

+

+    public void setSampleSize(int sampleSize) {

+        this.sampleSize = sampleSize;

+    }

+

+    public int getHistoryMult() {

+        return historyMult;

+    }

+

+    public void setHistoryMult(int historyMult) {

+        this.historyMult = historyMult;

+    }

+

+    public int getInitialHistory() {

+        return initialHistory;

+    }

+

+    public void setInitialHistory(int initialHistory) {

+        this.initialHistory = initialHistory;

+    }

+

+    public int getKModifier() {

+        return kModifier;

+    }

+

+    public void setKModifier(int kModifier) {

+        this.kModifier = kModifier;

+    }

+

+    public int getChannels() {

+        return channels;

+    }

+

+    public void setChannels(int channels) {

+        this.channels = channels;

+    }

+

+    public int getUnknown2() {

+        return unknown2;

+    }

+

+    public void setUnknown2(int unknown2) {

+        this.unknown2 = unknown2;

+    }

+

+    public long getMaxCodedFrameSize() {

+        return maxCodedFrameSize;

+    }

+

+    public void setMaxCodedFrameSize(int maxCodedFrameSize) {

+        this.maxCodedFrameSize = maxCodedFrameSize;

+    }

+

+    public long getBitRate() {

+        return bitRate;

+    }

+

+    public void setBitRate(int bitRate) {

+        this.bitRate = bitRate;

+    }

+

+    public long getSampleRate() {

+        return sampleRate;

+    }

+

+    public void setSampleRate(int sampleRate) {

+        this.sampleRate = sampleRate;

+    }

+

+

+    @Override

+    public void _parseDetails(ByteBuffer content) {

+        parseVersionAndFlags(content);

+        maxSamplePerFrame = IsoTypeReader.readUInt32(content);

+        unknown1 = IsoTypeReader.readUInt8(content);

+        sampleSize = IsoTypeReader.readUInt8(content);

+        historyMult = IsoTypeReader.readUInt8(content);

+        initialHistory = IsoTypeReader.readUInt8(content);

+        kModifier = IsoTypeReader.readUInt8(content);

+        channels = IsoTypeReader.readUInt8(content);

+        unknown2 = IsoTypeReader.readUInt16(content);

+        maxCodedFrameSize = IsoTypeReader.readUInt32(content);

+        bitRate = IsoTypeReader.readUInt32(content);

+        sampleRate = IsoTypeReader.readUInt32(content);

+    }

+

+    @Override

+    protected void getContent(ByteBuffer byteBuffer) {

+        writeVersionAndFlags(byteBuffer);

+        IsoTypeWriter.writeUInt32(byteBuffer, maxSamplePerFrame);

+        IsoTypeWriter.writeUInt8(byteBuffer, unknown1);

+        IsoTypeWriter.writeUInt8(byteBuffer, sampleSize);

+        IsoTypeWriter.writeUInt8(byteBuffer, historyMult);

+        IsoTypeWriter.writeUInt8(byteBuffer, initialHistory);

+        IsoTypeWriter.writeUInt8(byteBuffer, kModifier);

+        IsoTypeWriter.writeUInt8(byteBuffer, channels);

+        IsoTypeWriter.writeUInt16(byteBuffer, unknown2);

+        IsoTypeWriter.writeUInt32(byteBuffer, maxCodedFrameSize);

+        IsoTypeWriter.writeUInt32(byteBuffer, bitRate);

+        IsoTypeWriter.writeUInt32(byteBuffer, sampleRate);

+    }

+

+    public AppleLosslessSpecificBox() {

+        super("alac");

+    }

+

+    protected long getContentSize() {

+        return 28;

+    }

+

+}

diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/apple/.svn/text-base/AppleMeanBox.java.svn-base b/isoparser/src/main/java/com/coremedia/iso/boxes/apple/.svn/text-base/AppleMeanBox.java.svn-base
new file mode 100644
index 0000000..3a26f96
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/apple/.svn/text-base/AppleMeanBox.java.svn-base
@@ -0,0 +1,47 @@
+package com.coremedia.iso.boxes.apple;

+

+import com.coremedia.iso.IsoTypeReader;

+import com.coremedia.iso.Utf8;

+import com.googlecode.mp4parser.AbstractFullBox;

+

+import java.nio.ByteBuffer;

+

+/**

+ * Apple Meaning box. Allowed as subbox of "----" box.

+ *

+ * @see com.coremedia.iso.boxes.apple.AppleGenericBox

+ */

+public final class AppleMeanBox extends AbstractFullBox {

+    public static final String TYPE = "mean";

+    private String meaning;

+

+    public AppleMeanBox() {

+        super(TYPE);

+    }

+

+    protected long getContentSize() {

+        return 4 + Utf8.utf8StringLengthInBytes(meaning);

+    }

+

+    @Override

+    public void _parseDetails(ByteBuffer content) {

+        parseVersionAndFlags(content);

+        meaning = IsoTypeReader.readString(content, content.remaining());

+    }

+

+    @Override

+    protected void getContent(ByteBuffer byteBuffer) {

+        writeVersionAndFlags(byteBuffer);

+        byteBuffer.put(Utf8.convert(meaning));

+    }

+

+    public String getMeaning() {

+        return meaning;

+    }

+

+    public void setMeaning(String meaning) {

+        this.meaning = meaning;

+    }

+

+

+}

diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/apple/.svn/text-base/AppleMediaTypeBox.java.svn-base b/isoparser/src/main/java/com/coremedia/iso/boxes/apple/.svn/text-base/AppleMediaTypeBox.java.svn-base
new file mode 100644
index 0000000..f4ca98d
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/apple/.svn/text-base/AppleMediaTypeBox.java.svn-base
@@ -0,0 +1,39 @@
+package com.coremedia.iso.boxes.apple;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * itunes MetaData comment box.
+ */
+public class AppleMediaTypeBox extends AbstractAppleMetaDataBox {
+    private static Map<String, String> mediaTypes = new HashMap<String, String>();
+
+    static {
+        mediaTypes.put("0", "Movie (is now 9)");
+        mediaTypes.put("1", "Normal (Music)");
+        mediaTypes.put("2", "Audiobook");
+        mediaTypes.put("6", "Music Video");
+        mediaTypes.put("9", "Movie");
+        mediaTypes.put("10", "TV Show");
+        mediaTypes.put("11", "Booklet");
+        mediaTypes.put("14", "Ringtone");
+    }
+
+    public static final String TYPE = "stik";
+
+
+    public AppleMediaTypeBox() {
+        super(TYPE);
+        appleDataBox = AppleDataBox.getUint8AppleDataBox();
+    }
+
+    public String getReadableValue() {
+        if (mediaTypes.containsKey(getValue())) {
+            return mediaTypes.get(getValue());
+        } else {
+            return "unknown media type " + getValue();
+        }
+
+    }
+}
\ No newline at end of file
diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/apple/.svn/text-base/AppleNameBox.java.svn-base b/isoparser/src/main/java/com/coremedia/iso/boxes/apple/.svn/text-base/AppleNameBox.java.svn-base
new file mode 100644
index 0000000..5cad249
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/apple/.svn/text-base/AppleNameBox.java.svn-base
@@ -0,0 +1,45 @@
+package com.coremedia.iso.boxes.apple;

+

+import com.coremedia.iso.IsoTypeReader;

+import com.coremedia.iso.Utf8;

+import com.googlecode.mp4parser.AbstractFullBox;

+

+import java.nio.ByteBuffer;

+

+/**

+ * Apple Name box. Allowed as subbox of "----" box.

+ *

+ * @see AppleGenericBox

+ */

+public final class AppleNameBox extends AbstractFullBox {

+    public static final String TYPE = "name";

+    private String name;

+

+    public AppleNameBox() {

+        super(TYPE);

+    }

+

+    protected long getContentSize() {

+        return 4 + Utf8.convert(name).length;

+    }

+

+    public String getName() {

+        return name;

+    }

+

+    public void setName(String name) {

+        this.name = name;

+    }

+

+    @Override

+    public void _parseDetails(ByteBuffer content) {

+        parseVersionAndFlags(content);

+        name = IsoTypeReader.readString(content, content.remaining());

+    }

+

+    @Override

+    protected void getContent(ByteBuffer byteBuffer) {

+        writeVersionAndFlags(byteBuffer);

+        byteBuffer.put(Utf8.convert(name));

+    }

+}

diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/apple/.svn/text-base/AppleNetworkBox.java.svn-base b/isoparser/src/main/java/com/coremedia/iso/boxes/apple/.svn/text-base/AppleNetworkBox.java.svn-base
new file mode 100644
index 0000000..07691b3
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/apple/.svn/text-base/AppleNetworkBox.java.svn-base
@@ -0,0 +1,16 @@
+package com.coremedia.iso.boxes.apple;
+
+/**
+ *
+ */
+public final class AppleNetworkBox extends AbstractAppleMetaDataBox {
+    public static final String TYPE = "tvnn";
+
+
+    public AppleNetworkBox() {
+        super(TYPE);
+        appleDataBox = AppleDataBox.getStringAppleDataBox();
+    }
+
+
+}
\ No newline at end of file
diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/apple/.svn/text-base/ApplePurchaseDateBox.java.svn-base b/isoparser/src/main/java/com/coremedia/iso/boxes/apple/.svn/text-base/ApplePurchaseDateBox.java.svn-base
new file mode 100644
index 0000000..eb9807f
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/apple/.svn/text-base/ApplePurchaseDateBox.java.svn-base
@@ -0,0 +1,15 @@
+package com.coremedia.iso.boxes.apple;
+
+/**
+ *
+ */
+public final class ApplePurchaseDateBox extends AbstractAppleMetaDataBox {
+    public static final String TYPE = "purd";
+
+
+    public ApplePurchaseDateBox() {
+        super(TYPE);
+        appleDataBox = AppleDataBox.getStringAppleDataBox();
+    }
+
+}
\ No newline at end of file
diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/apple/.svn/text-base/AppleRatingBox.java.svn-base b/isoparser/src/main/java/com/coremedia/iso/boxes/apple/.svn/text-base/AppleRatingBox.java.svn-base
new file mode 100644
index 0000000..71671fc
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/apple/.svn/text-base/AppleRatingBox.java.svn-base
@@ -0,0 +1,16 @@
+package com.coremedia.iso.boxes.apple;
+
+/**
+ * iTunes Rating Box.
+ */
+public final class AppleRatingBox extends AbstractAppleMetaDataBox {
+    public static final String TYPE = "rtng";
+
+
+    public AppleRatingBox() {
+        super(TYPE);
+        appleDataBox = AppleDataBox.getUint8AppleDataBox();
+    }
+
+
+}
diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/apple/.svn/text-base/AppleRecordingYearBox.java.svn-base b/isoparser/src/main/java/com/coremedia/iso/boxes/apple/.svn/text-base/AppleRecordingYearBox.java.svn-base
new file mode 100644
index 0000000..da13300
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/apple/.svn/text-base/AppleRecordingYearBox.java.svn-base
@@ -0,0 +1,16 @@
+package com.coremedia.iso.boxes.apple;
+
+/**
+ *
+ */
+public class AppleRecordingYearBox extends AbstractAppleMetaDataBox {
+    public static final String TYPE = "\u00a9day";
+
+
+    public AppleRecordingYearBox() {
+        super(TYPE);
+        appleDataBox = AppleDataBox.getStringAppleDataBox();
+    }
+
+
+}
\ No newline at end of file
diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/apple/.svn/text-base/AppleReferenceMovieBox.java.svn-base b/isoparser/src/main/java/com/coremedia/iso/boxes/apple/.svn/text-base/AppleReferenceMovieBox.java.svn-base
new file mode 100644
index 0000000..49c539f
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/apple/.svn/text-base/AppleReferenceMovieBox.java.svn-base
@@ -0,0 +1,28 @@
+/*

+ * Copyright 2009 castLabs GmbH, Berlin

+ *

+ * Licensed under the Apache License, Version 2.0 (the License);

+ * you may not use this file except in compliance with the License.

+ * You may obtain a copy of the License at

+ *

+ *     http://www.apache.org/licenses/LICENSE-2.0

+ *

+ * Unless required by applicable law or agreed to in writing, software

+ * distributed under the License is distributed on an AS IS BASIS,

+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

+ * See the License for the specific language governing permissions and

+ * limitations under the License.

+ */

+

+package com.coremedia.iso.boxes.apple;

+

+import com.googlecode.mp4parser.AbstractContainerBox;

+

+public class AppleReferenceMovieBox extends AbstractContainerBox {

+    public static final String TYPE = "rmra";

+

+    public AppleReferenceMovieBox() {

+        super(TYPE);

+    }

+

+}

diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/apple/.svn/text-base/AppleReferenceMovieDescriptorBox.java.svn-base b/isoparser/src/main/java/com/coremedia/iso/boxes/apple/.svn/text-base/AppleReferenceMovieDescriptorBox.java.svn-base
new file mode 100644
index 0000000..488f01b
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/apple/.svn/text-base/AppleReferenceMovieDescriptorBox.java.svn-base
@@ -0,0 +1,27 @@
+/*

+ * Copyright 2009 castLabs GmbH, Berlin

+ *

+ * Licensed under the Apache License, Version 2.0 (the License);

+ * you may not use this file except in compliance with the License.

+ * You may obtain a copy of the License at

+ *

+ *     http://www.apache.org/licenses/LICENSE-2.0

+ *

+ * Unless required by applicable law or agreed to in writing, software

+ * distributed under the License is distributed on an AS IS BASIS,

+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

+ * See the License for the specific language governing permissions and

+ * limitations under the License.

+ */

+

+package com.coremedia.iso.boxes.apple;

+

+import com.googlecode.mp4parser.AbstractContainerBox;

+

+public class AppleReferenceMovieDescriptorBox extends AbstractContainerBox {

+    public static final String TYPE = "rmda";

+

+    public AppleReferenceMovieDescriptorBox() {

+        super(TYPE);

+    }

+}

diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/apple/.svn/text-base/AppleShowBox.java.svn-base b/isoparser/src/main/java/com/coremedia/iso/boxes/apple/.svn/text-base/AppleShowBox.java.svn-base
new file mode 100644
index 0000000..66b0d59
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/apple/.svn/text-base/AppleShowBox.java.svn-base
@@ -0,0 +1,15 @@
+package com.coremedia.iso.boxes.apple;
+
+/**
+ *
+ */
+public final class AppleShowBox extends AbstractAppleMetaDataBox {
+    public static final String TYPE = "tvsh";
+
+
+    public AppleShowBox() {
+        super(TYPE);
+        appleDataBox = AppleDataBox.getStringAppleDataBox();
+    }
+
+}
\ No newline at end of file
diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/apple/.svn/text-base/AppleSortAlbumBox.java.svn-base b/isoparser/src/main/java/com/coremedia/iso/boxes/apple/.svn/text-base/AppleSortAlbumBox.java.svn-base
new file mode 100644
index 0000000..cf74004
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/apple/.svn/text-base/AppleSortAlbumBox.java.svn-base
@@ -0,0 +1,14 @@
+package com.coremedia.iso.boxes.apple;
+
+/**
+ *
+ */
+public final class AppleSortAlbumBox extends AbstractAppleMetaDataBox {
+    public static final String TYPE = "soal";
+
+
+    public AppleSortAlbumBox() {
+        super(TYPE);
+        appleDataBox = AppleDataBox.getStringAppleDataBox();
+    }
+}
\ No newline at end of file
diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/apple/.svn/text-base/AppleStandardGenreBox.java.svn-base b/isoparser/src/main/java/com/coremedia/iso/boxes/apple/.svn/text-base/AppleStandardGenreBox.java.svn-base
new file mode 100644
index 0000000..21932fa
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/apple/.svn/text-base/AppleStandardGenreBox.java.svn-base
@@ -0,0 +1,14 @@
+package com.coremedia.iso.boxes.apple;
+
+/**
+ *
+ */
+public final class AppleStandardGenreBox extends AbstractAppleMetaDataBox {
+    public static final String TYPE = "gnre";
+
+
+    public AppleStandardGenreBox() {
+        super(TYPE);
+        appleDataBox = AppleDataBox.getUint16AppleDataBox();
+    }
+}
\ No newline at end of file
diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/apple/.svn/text-base/AppleStoreAccountTypeBox.java.svn-base b/isoparser/src/main/java/com/coremedia/iso/boxes/apple/.svn/text-base/AppleStoreAccountTypeBox.java.svn-base
new file mode 100644
index 0000000..36ecf4e
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/apple/.svn/text-base/AppleStoreAccountTypeBox.java.svn-base
@@ -0,0 +1,27 @@
+package com.coremedia.iso.boxes.apple;
+
+/**
+ * itunes MetaData comment box.
+ */
+public class AppleStoreAccountTypeBox extends AbstractAppleMetaDataBox {
+    public static final String TYPE = "akID";
+
+
+    public AppleStoreAccountTypeBox() {
+        super(TYPE);
+        appleDataBox = AppleDataBox.getUint8AppleDataBox();
+    }
+
+    public String getReadableValue() {
+        byte value = this.appleDataBox.getData()[0];
+        switch (value) {
+            case 0:
+                return "iTunes Account";
+            case 1:
+                return "AOL Account";
+            default:
+                return "unknown Account";
+        }
+
+    }
+}
\ No newline at end of file
diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/apple/.svn/text-base/AppleStoreCountryCodeBox.java.svn-base b/isoparser/src/main/java/com/coremedia/iso/boxes/apple/.svn/text-base/AppleStoreCountryCodeBox.java.svn-base
new file mode 100644
index 0000000..2c4756a
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/apple/.svn/text-base/AppleStoreCountryCodeBox.java.svn-base
@@ -0,0 +1,54 @@
+package com.coremedia.iso.boxes.apple;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * itunes MetaData comment box.
+ */
+public class AppleStoreCountryCodeBox extends AbstractAppleMetaDataBox {
+    private static Map<String, String> countryCodes = new HashMap<String, String>();
+
+    static {
+        countryCodes.put("143460", "Australia");
+        countryCodes.put("143445", "Austria");
+        countryCodes.put("143446", "Belgium");
+        countryCodes.put("143455", "Canada");
+        countryCodes.put("143458", "Denmark");
+        countryCodes.put("143447", "Finland");
+        countryCodes.put("143442", "France");
+        countryCodes.put("143443", "Germany");
+        countryCodes.put("143448", "Greece");
+        countryCodes.put("143449", "Ireland");
+        countryCodes.put("143450", "Italy");
+        countryCodes.put("143462", "Japan");
+        countryCodes.put("143451", "Luxembourg");
+        countryCodes.put("143452", "Netherlands");
+        countryCodes.put("143461", "New Zealand");
+        countryCodes.put("143457", "Norway");
+        countryCodes.put("143453", "Portugal");
+        countryCodes.put("143454", "Spain");
+        countryCodes.put("143456", "Sweden");
+        countryCodes.put("143459", "Switzerland");
+        countryCodes.put("143444", "United Kingdom");
+        countryCodes.put("143441", "United States");
+    }
+
+    public static final String TYPE = "sfID";
+
+
+    public AppleStoreCountryCodeBox() {
+        super(TYPE);
+        appleDataBox = AppleDataBox.getUint32AppleDataBox();
+    }
+
+
+    public String getReadableValue() {
+        if (countryCodes.containsKey(getValue())) {
+            return countryCodes.get(getValue());
+        } else {
+            return "unknown country code " + getValue();
+        }
+
+    }
+}
\ No newline at end of file
diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/apple/.svn/text-base/AppleSynopsisBox.java.svn-base b/isoparser/src/main/java/com/coremedia/iso/boxes/apple/.svn/text-base/AppleSynopsisBox.java.svn-base
new file mode 100644
index 0000000..cd5c2ab
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/apple/.svn/text-base/AppleSynopsisBox.java.svn-base
@@ -0,0 +1,16 @@
+package com.coremedia.iso.boxes.apple;
+
+/**
+ *
+ */
+public final class AppleSynopsisBox extends AbstractAppleMetaDataBox {
+    public static final String TYPE = "ldes";
+
+
+    public AppleSynopsisBox() {
+        super(TYPE);
+        appleDataBox = AppleDataBox.getStringAppleDataBox();
+    }
+
+
+}
\ No newline at end of file
diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/apple/.svn/text-base/AppleTempBox.java.svn-base b/isoparser/src/main/java/com/coremedia/iso/boxes/apple/.svn/text-base/AppleTempBox.java.svn-base
new file mode 100644
index 0000000..ef57228
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/apple/.svn/text-base/AppleTempBox.java.svn-base
@@ -0,0 +1,28 @@
+package com.coremedia.iso.boxes.apple;

+

+/**

+ * Beats per minute.

+ */

+public final class AppleTempBox extends AbstractAppleMetaDataBox {

+    public static final String TYPE = "tmpo";

+

+

+    public AppleTempBox() {

+        super(TYPE);

+        appleDataBox = AppleDataBox.getUint16AppleDataBox();

+    }

+

+

+    public int getTempo() {

+        return appleDataBox.getData()[1];

+    }

+

+    public void setTempo(int tempo) {

+        appleDataBox = new AppleDataBox();

+        appleDataBox.setVersion(0);

+        appleDataBox.setFlags(21);

+        appleDataBox.setFourBytes(new byte[4]);

+        appleDataBox.setData(new byte[]{0, (byte) (tempo & 0xFF)});

+

+    }

+}
\ No newline at end of file
diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/apple/.svn/text-base/AppleTrackAuthorBox.java.svn-base b/isoparser/src/main/java/com/coremedia/iso/boxes/apple/.svn/text-base/AppleTrackAuthorBox.java.svn-base
new file mode 100644
index 0000000..c5b3732
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/apple/.svn/text-base/AppleTrackAuthorBox.java.svn-base
@@ -0,0 +1,16 @@
+package com.coremedia.iso.boxes.apple;
+
+/**
+ *
+ */
+public final class AppleTrackAuthorBox extends AbstractAppleMetaDataBox {
+    public static final String TYPE = "\u00a9wrt";
+
+
+    public AppleTrackAuthorBox() {
+        super(TYPE);
+        appleDataBox = AppleDataBox.getStringAppleDataBox();
+    }
+
+
+}
\ No newline at end of file
diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/apple/.svn/text-base/AppleTrackNumberBox.java.svn-base b/isoparser/src/main/java/com/coremedia/iso/boxes/apple/.svn/text-base/AppleTrackNumberBox.java.svn-base
new file mode 100644
index 0000000..c073c2f
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/apple/.svn/text-base/AppleTrackNumberBox.java.svn-base
@@ -0,0 +1,48 @@
+package com.coremedia.iso.boxes.apple;
+
+/**
+ *
+ */
+public final class AppleTrackNumberBox extends AbstractAppleMetaDataBox {
+    public static final String TYPE = "trkn";
+
+
+    public AppleTrackNumberBox() {
+        super(TYPE);
+    }
+
+
+    /**
+     * @param track the actual track number
+     * @param of    number of tracks overall
+     */
+    public void setTrackNumber(byte track, byte of) {
+        appleDataBox = new AppleDataBox();
+        appleDataBox.setVersion(0);
+        appleDataBox.setFlags(0);
+        appleDataBox.setFourBytes(new byte[4]);
+        appleDataBox.setData(new byte[]{0, 0, 0, track, 0, of, 0, 0});
+    }
+
+    public byte getTrackNumber() {
+        return appleDataBox.getData()[3];
+    }
+
+    public byte getNumberOfTracks() {
+        return appleDataBox.getData()[5];
+    }
+
+    public void setNumberOfTracks(byte numberOfTracks) {
+        byte[] content = appleDataBox.getData();
+        content[5] = numberOfTracks;
+        appleDataBox.setData(content);
+    }
+
+    public void setTrackNumber(byte trackNumber) {
+        byte[] content = appleDataBox.getData();
+        content[3] = trackNumber;
+        appleDataBox.setData(content);
+    }
+
+
+}
\ No newline at end of file
diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/apple/.svn/text-base/AppleTrackTitleBox.java.svn-base b/isoparser/src/main/java/com/coremedia/iso/boxes/apple/.svn/text-base/AppleTrackTitleBox.java.svn-base
new file mode 100644
index 0000000..3dd613c
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/apple/.svn/text-base/AppleTrackTitleBox.java.svn-base
@@ -0,0 +1,15 @@
+package com.coremedia.iso.boxes.apple;
+
+/**
+ *
+ */
+public final class AppleTrackTitleBox extends AbstractAppleMetaDataBox {
+    public static final String TYPE = "\u00a9nam";
+
+
+    public AppleTrackTitleBox() {
+        super(TYPE);
+        appleDataBox = AppleDataBox.getStringAppleDataBox();
+    }
+
+}
diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/apple/.svn/text-base/AppleTvEpisodeBox.java.svn-base b/isoparser/src/main/java/com/coremedia/iso/boxes/apple/.svn/text-base/AppleTvEpisodeBox.java.svn-base
new file mode 100644
index 0000000..3b3817b
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/apple/.svn/text-base/AppleTvEpisodeBox.java.svn-base
@@ -0,0 +1,15 @@
+package com.coremedia.iso.boxes.apple;

+

+/**

+ * Tv Episode.

+ */

+public class AppleTvEpisodeBox extends AbstractAppleMetaDataBox {

+    public static final String TYPE = "tves";

+

+

+    public AppleTvEpisodeBox() {

+        super(TYPE);

+        appleDataBox = AppleDataBox.getUint32AppleDataBox();

+    }

+

+}
\ No newline at end of file
diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/apple/.svn/text-base/AppleTvEpisodeNumberBox.java.svn-base b/isoparser/src/main/java/com/coremedia/iso/boxes/apple/.svn/text-base/AppleTvEpisodeNumberBox.java.svn-base
new file mode 100644
index 0000000..33cd4e3
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/apple/.svn/text-base/AppleTvEpisodeNumberBox.java.svn-base
@@ -0,0 +1,15 @@
+package com.coremedia.iso.boxes.apple;

+

+/**

+ * Tv Episode.

+ */

+public class AppleTvEpisodeNumberBox extends AbstractAppleMetaDataBox {

+    public static final String TYPE = "tven";

+

+

+    public AppleTvEpisodeNumberBox() {

+        super(TYPE);

+        appleDataBox = AppleDataBox.getStringAppleDataBox();

+    }

+

+}
\ No newline at end of file
diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/apple/.svn/text-base/AppleTvSeasonBox.java.svn-base b/isoparser/src/main/java/com/coremedia/iso/boxes/apple/.svn/text-base/AppleTvSeasonBox.java.svn-base
new file mode 100644
index 0000000..9459ea3
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/apple/.svn/text-base/AppleTvSeasonBox.java.svn-base
@@ -0,0 +1,15 @@
+package com.coremedia.iso.boxes.apple;

+

+/**

+ * Tv Season.

+ */

+public final class AppleTvSeasonBox extends AbstractAppleMetaDataBox {

+    public static final String TYPE = "tvsn";

+

+

+    public AppleTvSeasonBox() {

+        super(TYPE);

+        appleDataBox = AppleDataBox.getUint32AppleDataBox();

+    }

+

+}
\ No newline at end of file
diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/apple/.svn/text-base/AppleWaveBox.java.svn-base b/isoparser/src/main/java/com/coremedia/iso/boxes/apple/.svn/text-base/AppleWaveBox.java.svn-base
new file mode 100644
index 0000000..65edd38
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/apple/.svn/text-base/AppleWaveBox.java.svn-base
@@ -0,0 +1,16 @@
+package com.coremedia.iso.boxes.apple;
+
+import com.googlecode.mp4parser.AbstractContainerBox;
+
+/**
+ *
+ */
+public final class AppleWaveBox extends AbstractContainerBox {
+    public static final String TYPE = "wave";
+
+    public AppleWaveBox() {
+        super(TYPE);
+    }
+
+
+}
diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/apple/AbstractAppleMetaDataBox.java b/isoparser/src/main/java/com/coremedia/iso/boxes/apple/AbstractAppleMetaDataBox.java
new file mode 100644
index 0000000..fdb7ac9
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/apple/AbstractAppleMetaDataBox.java
@@ -0,0 +1,164 @@
+package com.coremedia.iso.boxes.apple;
+
+import com.coremedia.iso.IsoTypeReader;
+import com.coremedia.iso.IsoTypeWriter;
+import com.coremedia.iso.Utf8;
+import com.googlecode.mp4parser.AbstractBox;
+import com.coremedia.iso.boxes.Box;
+import com.coremedia.iso.boxes.ContainerBox;
+import com.googlecode.mp4parser.util.ByteBufferByteChannel;
+
+import java.io.IOException;
+import java.math.BigInteger;
+import java.nio.ByteBuffer;
+import java.util.Collections;
+import java.util.List;
+import java.util.logging.Logger;
+
+/**
+ *
+ */
+public abstract class AbstractAppleMetaDataBox extends AbstractBox implements ContainerBox {
+    private static Logger LOG = Logger.getLogger(AbstractAppleMetaDataBox.class.getName());
+    AppleDataBox appleDataBox = new AppleDataBox();
+
+    public List<Box> getBoxes() {
+        return Collections.singletonList((Box) appleDataBox);
+    }
+
+    public void setBoxes(List<Box> boxes) {
+        if (boxes.size() == 1 && boxes.get(0) instanceof AppleDataBox) {
+            appleDataBox = (AppleDataBox) boxes.get(0);
+        } else {
+            throw new IllegalArgumentException("This box only accepts one AppleDataBox child");
+        }
+    }
+
+    public <T extends Box> List<T> getBoxes(Class<T> clazz) {
+        return getBoxes(clazz, false);
+    }
+
+    public <T extends Box> List<T> getBoxes(Class<T> clazz, boolean recursive) {
+        //todo recursive?
+        if (clazz.isAssignableFrom(appleDataBox.getClass())) {
+            return (List<T>) Collections.singletonList(appleDataBox);
+        }
+        return null;
+    }
+
+    public AbstractAppleMetaDataBox(String type) {
+        super(type);
+    }
+
+    @Override
+    public void _parseDetails(ByteBuffer content) {
+        long dataBoxSize = IsoTypeReader.readUInt32(content);
+        String thisShouldBeData = IsoTypeReader.read4cc(content);
+        assert "data".equals(thisShouldBeData);
+        appleDataBox = new AppleDataBox();
+        try {
+            appleDataBox.parse(new ByteBufferByteChannel(content), null, content.remaining(), null);
+        } catch (IOException e) {
+            throw new RuntimeException(e);
+        }
+        appleDataBox.setParent(this);
+    }
+
+
+    protected long getContentSize() {
+        return appleDataBox.getSize();
+    }
+
+    protected void getContent(ByteBuffer byteBuffer) {
+        try {
+            appleDataBox.getBox(new ByteBufferByteChannel(byteBuffer));
+        } catch (IOException e) {
+            throw new RuntimeException("The Channel is based on a ByteBuffer and therefore it shouldn't throw any exception");
+        }
+    }
+
+    public long getNumOfBytesToFirstChild() {
+        return getSize() - appleDataBox.getSize();
+    }
+
+    @Override
+    public String toString() {
+        return this.getClass().getSimpleName() + "{" +
+                "appleDataBox=" + getValue() +
+                '}';
+    }
+
+    static long toLong(byte b) {
+        return b < 0 ? b + 256 : b;
+    }
+
+    public void setValue(String value) {
+        if (appleDataBox.getFlags() == 1) {
+            appleDataBox = new AppleDataBox();
+            appleDataBox.setVersion(0);
+            appleDataBox.setFlags(1);
+            appleDataBox.setFourBytes(new byte[4]);
+            appleDataBox.setData(Utf8.convert(value));
+        } else if (appleDataBox.getFlags() == 21) {
+            byte[] content = appleDataBox.getData();
+            appleDataBox = new AppleDataBox();
+            appleDataBox.setVersion(0);
+            appleDataBox.setFlags(21);
+            appleDataBox.setFourBytes(new byte[4]);
+
+            ByteBuffer bb = ByteBuffer.allocate(content.length);
+            if (content.length == 1) {
+                IsoTypeWriter.writeUInt8(bb, (Byte.parseByte(value) & 0xFF));
+            } else if (content.length == 2) {
+                IsoTypeWriter.writeUInt16(bb, Integer.parseInt(value));
+            } else if (content.length == 4) {
+                IsoTypeWriter.writeUInt32(bb, Long.parseLong(value));
+            } else if (content.length == 8) {
+                IsoTypeWriter.writeUInt64(bb, Long.parseLong(value));
+            } else {
+                throw new Error("The content length within the appleDataBox is neither 1, 2, 4 or 8. I can't handle that!");
+            }
+            appleDataBox.setData(bb.array());
+        } else if (appleDataBox.getFlags() == 0) {
+            appleDataBox = new AppleDataBox();
+            appleDataBox.setVersion(0);
+            appleDataBox.setFlags(0);
+            appleDataBox.setFourBytes(new byte[4]);
+            appleDataBox.setData(hexStringToByteArray(value));
+
+        } else {
+            LOG.warning("Don't know how to handle appleDataBox with flag=" + appleDataBox.getFlags());
+        }
+    }
+
+    public String getValue() {
+        if (appleDataBox.getFlags() == 1) {
+            return Utf8.convert(appleDataBox.getData());
+        } else if (appleDataBox.getFlags() == 21) {
+            byte[] content = appleDataBox.getData();
+            long l = 0;
+            int current = 1;
+            int length = content.length;
+            for (byte b : content) {
+                l += toLong(b) << (8 * (length - current++));
+            }
+            return "" + l;
+        } else if (appleDataBox.getFlags() == 0) {
+            return String.format("%x", new BigInteger(appleDataBox.getData()));
+        } else {
+            return "unknown";
+        }
+    }
+
+    public static byte[] hexStringToByteArray(String s) {
+        int len = s.length();
+        byte[] data = new byte[len / 2];
+        for (int i = 0; i < len; i += 2) {
+            data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4)
+                    + Character.digit(s.charAt(i + 1), 16));
+        }
+        return data;
+    }
+
+
+}
diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/apple/AppleAlbumArtistBox.java b/isoparser/src/main/java/com/coremedia/iso/boxes/apple/AppleAlbumArtistBox.java
new file mode 100755
index 0000000..5c258b4
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/apple/AppleAlbumArtistBox.java
@@ -0,0 +1,16 @@
+package com.coremedia.iso.boxes.apple;
+
+/**
+ * itunes MetaData comment box.
+ */
+public class AppleAlbumArtistBox extends AbstractAppleMetaDataBox {
+    public static final String TYPE = "aART";
+
+
+    public AppleAlbumArtistBox() {
+        super(TYPE);
+        appleDataBox = AppleDataBox.getStringAppleDataBox();
+    }
+
+
+}
\ No newline at end of file
diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/apple/AppleAlbumBox.java b/isoparser/src/main/java/com/coremedia/iso/boxes/apple/AppleAlbumBox.java
new file mode 100644
index 0000000..9e3d5f7
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/apple/AppleAlbumBox.java
@@ -0,0 +1,15 @@
+package com.coremedia.iso.boxes.apple;
+
+/**
+ *
+ */
+public final class AppleAlbumBox extends AbstractAppleMetaDataBox {
+    public static final String TYPE = "\u00a9alb";
+
+
+    public AppleAlbumBox() {
+        super(TYPE);
+        appleDataBox = AppleDataBox.getStringAppleDataBox();
+    }
+
+}
\ No newline at end of file
diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/apple/AppleArtistBox.java b/isoparser/src/main/java/com/coremedia/iso/boxes/apple/AppleArtistBox.java
new file mode 100644
index 0000000..627a603
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/apple/AppleArtistBox.java
@@ -0,0 +1,16 @@
+package com.coremedia.iso.boxes.apple;

+

+/**

+ * iTunes Artist box.

+ */

+public final class AppleArtistBox extends AbstractAppleMetaDataBox {

+    public static final String TYPE = "\u00a9ART";

+

+

+    public AppleArtistBox() {

+        super(TYPE);

+        appleDataBox = AppleDataBox.getStringAppleDataBox();

+    }

+

+

+}

diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/apple/AppleCommentBox.java b/isoparser/src/main/java/com/coremedia/iso/boxes/apple/AppleCommentBox.java
new file mode 100755
index 0000000..b58899f
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/apple/AppleCommentBox.java
@@ -0,0 +1,16 @@
+package com.coremedia.iso.boxes.apple;
+
+/**
+ * itunes MetaData comment box.
+ */
+public final class AppleCommentBox extends AbstractAppleMetaDataBox {
+    public static final String TYPE = "\u00a9cmt";
+
+
+    public AppleCommentBox() {
+        super(TYPE);
+        appleDataBox = AppleDataBox.getStringAppleDataBox();
+    }
+
+
+}
diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/apple/AppleCompilationBox.java b/isoparser/src/main/java/com/coremedia/iso/boxes/apple/AppleCompilationBox.java
new file mode 100644
index 0000000..c8c9bf4
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/apple/AppleCompilationBox.java
@@ -0,0 +1,15 @@
+package com.coremedia.iso.boxes.apple;

+

+/**

+ * Compilation.

+ */

+public final class AppleCompilationBox extends AbstractAppleMetaDataBox {

+    public static final String TYPE = "cpil";

+

+

+    public AppleCompilationBox() {

+        super(TYPE);

+        appleDataBox = AppleDataBox.getUint8AppleDataBox();

+    }

+

+}
\ No newline at end of file
diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/apple/AppleCopyrightBox.java b/isoparser/src/main/java/com/coremedia/iso/boxes/apple/AppleCopyrightBox.java
new file mode 100755
index 0000000..ae44285
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/apple/AppleCopyrightBox.java
@@ -0,0 +1,15 @@
+package com.coremedia.iso.boxes.apple;
+
+/**
+ * itunes MetaData comment box.
+ */
+public final class AppleCopyrightBox extends AbstractAppleMetaDataBox {
+    public static final String TYPE = "cprt";
+
+
+    public AppleCopyrightBox() {
+        super(TYPE);
+        appleDataBox = AppleDataBox.getStringAppleDataBox();
+    }
+
+}
\ No newline at end of file
diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/apple/AppleCoverBox.java b/isoparser/src/main/java/com/coremedia/iso/boxes/apple/AppleCoverBox.java
new file mode 100644
index 0000000..946dd49
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/apple/AppleCoverBox.java
@@ -0,0 +1,44 @@
+package com.coremedia.iso.boxes.apple;
+
+import java.util.logging.Logger;
+
+/**
+ *
+ */
+public final class AppleCoverBox extends AbstractAppleMetaDataBox {
+    private static Logger LOG = Logger.getLogger(AppleCoverBox.class.getName());
+    public static final String TYPE = "covr";
+
+
+    public AppleCoverBox() {
+        super(TYPE);
+    }
+
+
+    public void setPng(byte[] pngData) {
+        appleDataBox = new AppleDataBox();
+        appleDataBox.setVersion(0);
+        appleDataBox.setFlags(0xe);
+        appleDataBox.setFourBytes(new byte[4]);
+        appleDataBox.setData(pngData);
+    }
+
+
+    public void setJpg(byte[] jpgData) {
+        appleDataBox = new AppleDataBox();
+        appleDataBox.setVersion(0);
+        appleDataBox.setFlags(0xd);
+        appleDataBox.setFourBytes(new byte[4]);
+        appleDataBox.setData(jpgData);
+    }
+
+    @Override
+    public void setValue(String value) {
+        LOG.warning("---");
+    }
+
+    @Override
+    public String getValue() {
+        return "---";
+    }
+}
\ No newline at end of file
diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/apple/AppleCustomGenreBox.java b/isoparser/src/main/java/com/coremedia/iso/boxes/apple/AppleCustomGenreBox.java
new file mode 100644
index 0000000..0c67f97
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/apple/AppleCustomGenreBox.java
@@ -0,0 +1,28 @@
+package com.coremedia.iso.boxes.apple;
+
+import com.coremedia.iso.Utf8;
+
+/**
+ *
+ */
+public final class AppleCustomGenreBox extends AbstractAppleMetaDataBox {
+    public static final String TYPE = "\u00a9gen";
+
+
+    public AppleCustomGenreBox() {
+        super(TYPE);
+        appleDataBox = AppleDataBox.getStringAppleDataBox();
+    }
+
+    public void setGenre(String genre) {
+        appleDataBox = new AppleDataBox();
+        appleDataBox.setVersion(0);
+        appleDataBox.setFlags(1);
+        appleDataBox.setFourBytes(new byte[4]);
+        appleDataBox.setData(Utf8.convert(genre));
+    }
+
+    public String getGenre() {
+        return Utf8.convert(appleDataBox.getData());
+    }
+}
\ No newline at end of file
diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/apple/AppleDataBox.java b/isoparser/src/main/java/com/coremedia/iso/boxes/apple/AppleDataBox.java
new file mode 100644
index 0000000..ba42629
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/apple/AppleDataBox.java
@@ -0,0 +1,92 @@
+package com.coremedia.iso.boxes.apple;
+
+import com.googlecode.mp4parser.AbstractFullBox;
+
+import java.nio.ByteBuffer;
+
+/**
+ * Most stupid box of the world. Encapsulates actual data within
+ */
+public final class AppleDataBox extends AbstractFullBox {
+    public static final String TYPE = "data";
+
+    private byte[] fourBytes = new byte[4];
+    private byte[] data;
+
+    private static AppleDataBox getEmpty() {
+        AppleDataBox appleDataBox = new AppleDataBox();
+        appleDataBox.setVersion(0);
+        appleDataBox.setFourBytes(new byte[4]);
+        return appleDataBox;
+    }
+
+    public static AppleDataBox getStringAppleDataBox() {
+        AppleDataBox appleDataBox = getEmpty();
+        appleDataBox.setFlags(1);
+        appleDataBox.setData(new byte[]{0});
+        return appleDataBox;
+    }
+
+    public static AppleDataBox getUint8AppleDataBox() {
+        AppleDataBox appleDataBox = new AppleDataBox();
+        appleDataBox.setFlags(21);
+        appleDataBox.setData(new byte[]{0});
+        return appleDataBox;
+    }
+
+    public static AppleDataBox getUint16AppleDataBox() {
+        AppleDataBox appleDataBox = new AppleDataBox();
+        appleDataBox.setFlags(21);
+        appleDataBox.setData(new byte[]{0, 0});
+        return appleDataBox;
+    }
+
+    public static AppleDataBox getUint32AppleDataBox() {
+        AppleDataBox appleDataBox = new AppleDataBox();
+        appleDataBox.setFlags(21);
+        appleDataBox.setData(new byte[]{0, 0, 0, 0});
+        return appleDataBox;
+    }
+
+    public AppleDataBox() {
+        super(TYPE);
+    }
+
+    protected long getContentSize() {
+        return data.length + 8;
+    }
+
+    public void setData(byte[] data) {
+        this.data = new byte[data.length];
+        System.arraycopy(data, 0, this.data, 0, data.length);
+    }
+
+    public void setFourBytes(byte[] fourBytes) {
+        System.arraycopy(fourBytes, 0, this.fourBytes, 0, 4);
+    }
+
+    @Override
+    public void _parseDetails(ByteBuffer content) {
+        parseVersionAndFlags(content);
+        fourBytes = new byte[4];
+        content.get(fourBytes);
+        data = new byte[content.remaining()];
+        content.get(data);
+    }
+
+
+    @Override
+    protected void getContent(ByteBuffer byteBuffer) {
+        writeVersionAndFlags(byteBuffer);
+        byteBuffer.put(fourBytes, 0, 4);
+        byteBuffer.put(data);
+    }
+
+    public byte[] getFourBytes() {
+        return fourBytes;
+    }
+
+    public byte[] getData() {
+        return data;
+    }
+}
diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/apple/AppleDataRateBox.java b/isoparser/src/main/java/com/coremedia/iso/boxes/apple/AppleDataRateBox.java
new file mode 100644
index 0000000..e58e550
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/apple/AppleDataRateBox.java
@@ -0,0 +1,53 @@
+/*

+ * Copyright 2009 castLabs GmbH, Berlin

+ *

+ * Licensed under the Apache License, Version 2.0 (the License);

+ * you may not use this file except in compliance with the License.

+ * You may obtain a copy of the License at

+ *

+ *     http://www.apache.org/licenses/LICENSE-2.0

+ *

+ * Unless required by applicable law or agreed to in writing, software

+ * distributed under the License is distributed on an AS IS BASIS,

+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

+ * See the License for the specific language governing permissions and

+ * limitations under the License.

+ */

+

+package com.coremedia.iso.boxes.apple;

+

+import com.coremedia.iso.IsoTypeReader;

+import com.coremedia.iso.IsoTypeWriter;

+import com.googlecode.mp4parser.AbstractFullBox;

+

+import java.nio.ByteBuffer;

+

+public class AppleDataRateBox extends AbstractFullBox {

+    public static final String TYPE = "rmdr";

+    private long dataRate;

+

+    public AppleDataRateBox() {

+        super(TYPE);

+    }

+

+    protected long getContentSize() {

+        return 8;

+    }

+

+    @Override

+    public void _parseDetails(ByteBuffer content) {

+        parseVersionAndFlags(content);

+        dataRate = IsoTypeReader.readUInt32(content);

+    }

+

+    @Override

+    protected void getContent(ByteBuffer byteBuffer) {

+        writeVersionAndFlags(byteBuffer);

+        IsoTypeWriter.writeUInt32(byteBuffer, dataRate);

+    }

+

+

+    public long getDataRate() {

+        return dataRate;

+    }

+}

diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/apple/AppleDataReferenceBox.java b/isoparser/src/main/java/com/coremedia/iso/boxes/apple/AppleDataReferenceBox.java
new file mode 100644
index 0000000..7370c10
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/apple/AppleDataReferenceBox.java
@@ -0,0 +1,71 @@
+/*

+ * Copyright 2009 castLabs GmbH, Berlin

+ *

+ * Licensed under the Apache License, Version 2.0 (the License);

+ * you may not use this file except in compliance with the License.

+ * You may obtain a copy of the License at

+ *

+ *     http://www.apache.org/licenses/LICENSE-2.0

+ *

+ * Unless required by applicable law or agreed to in writing, software

+ * distributed under the License is distributed on an AS IS BASIS,

+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

+ * See the License for the specific language governing permissions and

+ * limitations under the License.

+ */

+

+package com.coremedia.iso.boxes.apple;

+

+import com.coremedia.iso.IsoFile;

+import com.coremedia.iso.IsoTypeReader;

+import com.coremedia.iso.IsoTypeWriter;

+import com.coremedia.iso.Utf8;

+import com.googlecode.mp4parser.AbstractFullBox;

+

+import java.nio.ByteBuffer;

+

+import static com.googlecode.mp4parser.util.CastUtils.l2i;

+

+public class AppleDataReferenceBox extends AbstractFullBox {

+    public static final String TYPE = "rdrf";

+    private int dataReferenceSize;

+    private String dataReferenceType;

+    private String dataReference;

+

+    public AppleDataReferenceBox() {

+        super(TYPE);

+    }

+

+

+    protected long getContentSize() {

+        return 12 + dataReferenceSize;

+    }

+

+    @Override

+    public void _parseDetails(ByteBuffer content) {

+        parseVersionAndFlags(content);

+        dataReferenceType = IsoTypeReader.read4cc(content);

+        dataReferenceSize = l2i(IsoTypeReader.readUInt32(content));

+        dataReference = IsoTypeReader.readString(content, dataReferenceSize);

+    }

+

+    @Override

+    protected void getContent(ByteBuffer byteBuffer) {

+        writeVersionAndFlags(byteBuffer);

+        byteBuffer.put(IsoFile.fourCCtoBytes(dataReferenceType));

+        IsoTypeWriter.writeUInt32(byteBuffer, dataReferenceSize);

+        byteBuffer.put(Utf8.convert(dataReference));

+    }

+

+    public long getDataReferenceSize() {

+        return dataReferenceSize;

+    }

+

+    public String getDataReferenceType() {

+        return dataReferenceType;

+    }

+

+    public String getDataReference() {

+        return dataReference;

+    }

+}

diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/apple/AppleDescriptionBox.java b/isoparser/src/main/java/com/coremedia/iso/boxes/apple/AppleDescriptionBox.java
new file mode 100644
index 0000000..e20e0fc
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/apple/AppleDescriptionBox.java
@@ -0,0 +1,15 @@
+package com.coremedia.iso.boxes.apple;
+
+/**
+ *
+ */
+public final class AppleDescriptionBox extends AbstractAppleMetaDataBox {
+    public static final String TYPE = "desc";
+
+
+    public AppleDescriptionBox() {
+        super(TYPE);
+        appleDataBox = AppleDataBox.getStringAppleDataBox();
+    }
+
+}
\ No newline at end of file
diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/apple/AppleEncoderBox.java b/isoparser/src/main/java/com/coremedia/iso/boxes/apple/AppleEncoderBox.java
new file mode 100755
index 0000000..5a59e81
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/apple/AppleEncoderBox.java
@@ -0,0 +1,15 @@
+package com.coremedia.iso.boxes.apple;
+
+/**
+ * itunes MetaData comment box.
+ */
+public final class AppleEncoderBox extends AbstractAppleMetaDataBox {
+    public static final String TYPE = "\u00a9too";
+
+
+    public AppleEncoderBox() {
+        super(TYPE);
+        appleDataBox = AppleDataBox.getStringAppleDataBox();
+    }
+
+}
\ No newline at end of file
diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/apple/AppleGaplessPlaybackBox.java b/isoparser/src/main/java/com/coremedia/iso/boxes/apple/AppleGaplessPlaybackBox.java
new file mode 100644
index 0000000..c617a54
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/apple/AppleGaplessPlaybackBox.java
@@ -0,0 +1,15 @@
+package com.coremedia.iso.boxes.apple;

+

+/**

+ * Gapless Playback.

+ */

+public final class AppleGaplessPlaybackBox extends AbstractAppleMetaDataBox {

+    public static final String TYPE = "pgap";

+

+

+    public AppleGaplessPlaybackBox() {

+        super(TYPE);

+        appleDataBox = AppleDataBox.getUint8AppleDataBox();

+    }

+

+}

diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/apple/AppleGenericBox.java b/isoparser/src/main/java/com/coremedia/iso/boxes/apple/AppleGenericBox.java
new file mode 100644
index 0000000..177a25b
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/apple/AppleGenericBox.java
@@ -0,0 +1,15 @@
+package com.coremedia.iso.boxes.apple;
+
+import com.googlecode.mp4parser.AbstractContainerBox;
+
+/**
+ *
+ */
+public final class AppleGenericBox extends AbstractContainerBox {
+    public static final String TYPE = "----";
+
+    public AppleGenericBox() {
+        super(TYPE);
+    }
+
+}
\ No newline at end of file
diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/apple/AppleGroupingBox.java b/isoparser/src/main/java/com/coremedia/iso/boxes/apple/AppleGroupingBox.java
new file mode 100755
index 0000000..9884298
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/apple/AppleGroupingBox.java
@@ -0,0 +1,15 @@
+package com.coremedia.iso.boxes.apple;
+
+/**
+ * itunes MetaData comment box.
+ */
+public final class AppleGroupingBox extends AbstractAppleMetaDataBox {
+    public static final String TYPE = "\u00a9grp";
+
+
+    public AppleGroupingBox() {
+        super(TYPE);
+        appleDataBox = AppleDataBox.getStringAppleDataBox();
+    }
+
+}
\ No newline at end of file
diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/apple/AppleIdBox.java b/isoparser/src/main/java/com/coremedia/iso/boxes/apple/AppleIdBox.java
new file mode 100644
index 0000000..08c697e
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/apple/AppleIdBox.java
@@ -0,0 +1,15 @@
+package com.coremedia.iso.boxes.apple;
+
+/**
+ *
+ */
+public final class AppleIdBox extends AbstractAppleMetaDataBox {
+    public static final String TYPE = "apID";
+
+
+    public AppleIdBox() {
+        super(TYPE);
+        appleDataBox = AppleDataBox.getStringAppleDataBox();
+    }
+
+}
\ No newline at end of file
diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/apple/AppleItemListBox.java b/isoparser/src/main/java/com/coremedia/iso/boxes/apple/AppleItemListBox.java
new file mode 100644
index 0000000..cd26e81
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/apple/AppleItemListBox.java
@@ -0,0 +1,15 @@
+package com.coremedia.iso.boxes.apple;
+
+import com.googlecode.mp4parser.AbstractContainerBox;
+
+/**
+ * undocumented iTunes MetaData Box.
+ */
+public class AppleItemListBox extends AbstractContainerBox {
+    public static final String TYPE = "ilst";
+
+    public AppleItemListBox() {
+        super(TYPE);
+    }
+
+}
diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/apple/AppleLosslessSpecificBox.java b/isoparser/src/main/java/com/coremedia/iso/boxes/apple/AppleLosslessSpecificBox.java
new file mode 100644
index 0000000..781af49
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/apple/AppleLosslessSpecificBox.java
@@ -0,0 +1,163 @@
+package com.coremedia.iso.boxes.apple;

+

+import com.coremedia.iso.IsoTypeReader;

+import com.coremedia.iso.IsoTypeWriter;

+import com.googlecode.mp4parser.AbstractFullBox;

+

+import java.nio.ByteBuffer;

+

+/**

+ *

+ */

+public final class AppleLosslessSpecificBox extends AbstractFullBox {

+

+    public static final String TYPE = "alac";

+    /*

+   Extradata: 32bit size 32bit tag (=alac) 32bit zero?

+   32bit max sample per frame 8bit ?? (zero?) 8bit sample

+   size 8bit history mult 8bit initial history 8bit kmodifier

+   8bit channels? 16bit ?? 32bit max coded frame size 32bit

+   bitrate? 32bit samplerate

+    */

+    private long maxSamplePerFrame; // 32bi

+    private int unknown1; // 8bit

+    private int sampleSize; // 8bit

+    private int historyMult; // 8bit

+    private int initialHistory; // 8bit

+    private int kModifier; // 8bit

+    private int channels; // 8bit

+    private int unknown2; // 16bit

+    private long maxCodedFrameSize; // 32bit

+    private long bitRate; // 32bit

+    private long sampleRate; // 32bit

+

+    public long getMaxSamplePerFrame() {

+        return maxSamplePerFrame;

+    }

+

+    public void setMaxSamplePerFrame(int maxSamplePerFrame) {

+        this.maxSamplePerFrame = maxSamplePerFrame;

+    }

+

+    public int getUnknown1() {

+        return unknown1;

+    }

+

+    public void setUnknown1(int unknown1) {

+        this.unknown1 = unknown1;

+    }

+

+    public int getSampleSize() {

+        return sampleSize;

+    }

+

+    public void setSampleSize(int sampleSize) {

+        this.sampleSize = sampleSize;

+    }

+

+    public int getHistoryMult() {

+        return historyMult;

+    }

+

+    public void setHistoryMult(int historyMult) {

+        this.historyMult = historyMult;

+    }

+

+    public int getInitialHistory() {

+        return initialHistory;

+    }

+

+    public void setInitialHistory(int initialHistory) {

+        this.initialHistory = initialHistory;

+    }

+

+    public int getKModifier() {

+        return kModifier;

+    }

+

+    public void setKModifier(int kModifier) {

+        this.kModifier = kModifier;

+    }

+

+    public int getChannels() {

+        return channels;

+    }

+

+    public void setChannels(int channels) {

+        this.channels = channels;

+    }

+

+    public int getUnknown2() {

+        return unknown2;

+    }

+

+    public void setUnknown2(int unknown2) {

+        this.unknown2 = unknown2;

+    }

+

+    public long getMaxCodedFrameSize() {

+        return maxCodedFrameSize;

+    }

+

+    public void setMaxCodedFrameSize(int maxCodedFrameSize) {

+        this.maxCodedFrameSize = maxCodedFrameSize;

+    }

+

+    public long getBitRate() {

+        return bitRate;

+    }

+

+    public void setBitRate(int bitRate) {

+        this.bitRate = bitRate;

+    }

+

+    public long getSampleRate() {

+        return sampleRate;

+    }

+

+    public void setSampleRate(int sampleRate) {

+        this.sampleRate = sampleRate;

+    }

+

+

+    @Override

+    public void _parseDetails(ByteBuffer content) {

+        parseVersionAndFlags(content);

+        maxSamplePerFrame = IsoTypeReader.readUInt32(content);

+        unknown1 = IsoTypeReader.readUInt8(content);

+        sampleSize = IsoTypeReader.readUInt8(content);

+        historyMult = IsoTypeReader.readUInt8(content);

+        initialHistory = IsoTypeReader.readUInt8(content);

+        kModifier = IsoTypeReader.readUInt8(content);

+        channels = IsoTypeReader.readUInt8(content);

+        unknown2 = IsoTypeReader.readUInt16(content);

+        maxCodedFrameSize = IsoTypeReader.readUInt32(content);

+        bitRate = IsoTypeReader.readUInt32(content);

+        sampleRate = IsoTypeReader.readUInt32(content);

+    }

+

+    @Override

+    protected void getContent(ByteBuffer byteBuffer) {

+        writeVersionAndFlags(byteBuffer);

+        IsoTypeWriter.writeUInt32(byteBuffer, maxSamplePerFrame);

+        IsoTypeWriter.writeUInt8(byteBuffer, unknown1);

+        IsoTypeWriter.writeUInt8(byteBuffer, sampleSize);

+        IsoTypeWriter.writeUInt8(byteBuffer, historyMult);

+        IsoTypeWriter.writeUInt8(byteBuffer, initialHistory);

+        IsoTypeWriter.writeUInt8(byteBuffer, kModifier);

+        IsoTypeWriter.writeUInt8(byteBuffer, channels);

+        IsoTypeWriter.writeUInt16(byteBuffer, unknown2);

+        IsoTypeWriter.writeUInt32(byteBuffer, maxCodedFrameSize);

+        IsoTypeWriter.writeUInt32(byteBuffer, bitRate);

+        IsoTypeWriter.writeUInt32(byteBuffer, sampleRate);

+    }

+

+    public AppleLosslessSpecificBox() {

+        super("alac");

+    }

+

+    protected long getContentSize() {

+        return 28;

+    }

+

+}

diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/apple/AppleMeanBox.java b/isoparser/src/main/java/com/coremedia/iso/boxes/apple/AppleMeanBox.java
new file mode 100644
index 0000000..3a26f96
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/apple/AppleMeanBox.java
@@ -0,0 +1,47 @@
+package com.coremedia.iso.boxes.apple;

+

+import com.coremedia.iso.IsoTypeReader;

+import com.coremedia.iso.Utf8;

+import com.googlecode.mp4parser.AbstractFullBox;

+

+import java.nio.ByteBuffer;

+

+/**

+ * Apple Meaning box. Allowed as subbox of "----" box.

+ *

+ * @see com.coremedia.iso.boxes.apple.AppleGenericBox

+ */

+public final class AppleMeanBox extends AbstractFullBox {

+    public static final String TYPE = "mean";

+    private String meaning;

+

+    public AppleMeanBox() {

+        super(TYPE);

+    }

+

+    protected long getContentSize() {

+        return 4 + Utf8.utf8StringLengthInBytes(meaning);

+    }

+

+    @Override

+    public void _parseDetails(ByteBuffer content) {

+        parseVersionAndFlags(content);

+        meaning = IsoTypeReader.readString(content, content.remaining());

+    }

+

+    @Override

+    protected void getContent(ByteBuffer byteBuffer) {

+        writeVersionAndFlags(byteBuffer);

+        byteBuffer.put(Utf8.convert(meaning));

+    }

+

+    public String getMeaning() {

+        return meaning;

+    }

+

+    public void setMeaning(String meaning) {

+        this.meaning = meaning;

+    }

+

+

+}

diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/apple/AppleMediaTypeBox.java b/isoparser/src/main/java/com/coremedia/iso/boxes/apple/AppleMediaTypeBox.java
new file mode 100644
index 0000000..f4ca98d
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/apple/AppleMediaTypeBox.java
@@ -0,0 +1,39 @@
+package com.coremedia.iso.boxes.apple;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * itunes MetaData comment box.
+ */
+public class AppleMediaTypeBox extends AbstractAppleMetaDataBox {
+    private static Map<String, String> mediaTypes = new HashMap<String, String>();
+
+    static {
+        mediaTypes.put("0", "Movie (is now 9)");
+        mediaTypes.put("1", "Normal (Music)");
+        mediaTypes.put("2", "Audiobook");
+        mediaTypes.put("6", "Music Video");
+        mediaTypes.put("9", "Movie");
+        mediaTypes.put("10", "TV Show");
+        mediaTypes.put("11", "Booklet");
+        mediaTypes.put("14", "Ringtone");
+    }
+
+    public static final String TYPE = "stik";
+
+
+    public AppleMediaTypeBox() {
+        super(TYPE);
+        appleDataBox = AppleDataBox.getUint8AppleDataBox();
+    }
+
+    public String getReadableValue() {
+        if (mediaTypes.containsKey(getValue())) {
+            return mediaTypes.get(getValue());
+        } else {
+            return "unknown media type " + getValue();
+        }
+
+    }
+}
\ No newline at end of file
diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/apple/AppleNameBox.java b/isoparser/src/main/java/com/coremedia/iso/boxes/apple/AppleNameBox.java
new file mode 100644
index 0000000..5cad249
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/apple/AppleNameBox.java
@@ -0,0 +1,45 @@
+package com.coremedia.iso.boxes.apple;

+

+import com.coremedia.iso.IsoTypeReader;

+import com.coremedia.iso.Utf8;

+import com.googlecode.mp4parser.AbstractFullBox;

+

+import java.nio.ByteBuffer;

+

+/**

+ * Apple Name box. Allowed as subbox of "----" box.

+ *

+ * @see AppleGenericBox

+ */

+public final class AppleNameBox extends AbstractFullBox {

+    public static final String TYPE = "name";

+    private String name;

+

+    public AppleNameBox() {

+        super(TYPE);

+    }

+

+    protected long getContentSize() {

+        return 4 + Utf8.convert(name).length;

+    }

+

+    public String getName() {

+        return name;

+    }

+

+    public void setName(String name) {

+        this.name = name;

+    }

+

+    @Override

+    public void _parseDetails(ByteBuffer content) {

+        parseVersionAndFlags(content);

+        name = IsoTypeReader.readString(content, content.remaining());

+    }

+

+    @Override

+    protected void getContent(ByteBuffer byteBuffer) {

+        writeVersionAndFlags(byteBuffer);

+        byteBuffer.put(Utf8.convert(name));

+    }

+}

diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/apple/AppleNetworkBox.java b/isoparser/src/main/java/com/coremedia/iso/boxes/apple/AppleNetworkBox.java
new file mode 100644
index 0000000..07691b3
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/apple/AppleNetworkBox.java
@@ -0,0 +1,16 @@
+package com.coremedia.iso.boxes.apple;
+
+/**
+ *
+ */
+public final class AppleNetworkBox extends AbstractAppleMetaDataBox {
+    public static final String TYPE = "tvnn";
+
+
+    public AppleNetworkBox() {
+        super(TYPE);
+        appleDataBox = AppleDataBox.getStringAppleDataBox();
+    }
+
+
+}
\ No newline at end of file
diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/apple/ApplePurchaseDateBox.java b/isoparser/src/main/java/com/coremedia/iso/boxes/apple/ApplePurchaseDateBox.java
new file mode 100644
index 0000000..eb9807f
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/apple/ApplePurchaseDateBox.java
@@ -0,0 +1,15 @@
+package com.coremedia.iso.boxes.apple;
+
+/**
+ *
+ */
+public final class ApplePurchaseDateBox extends AbstractAppleMetaDataBox {
+    public static final String TYPE = "purd";
+
+
+    public ApplePurchaseDateBox() {
+        super(TYPE);
+        appleDataBox = AppleDataBox.getStringAppleDataBox();
+    }
+
+}
\ No newline at end of file
diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/apple/AppleRatingBox.java b/isoparser/src/main/java/com/coremedia/iso/boxes/apple/AppleRatingBox.java
new file mode 100644
index 0000000..71671fc
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/apple/AppleRatingBox.java
@@ -0,0 +1,16 @@
+package com.coremedia.iso.boxes.apple;
+
+/**
+ * iTunes Rating Box.
+ */
+public final class AppleRatingBox extends AbstractAppleMetaDataBox {
+    public static final String TYPE = "rtng";
+
+
+    public AppleRatingBox() {
+        super(TYPE);
+        appleDataBox = AppleDataBox.getUint8AppleDataBox();
+    }
+
+
+}
diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/apple/AppleRecordingYearBox.java b/isoparser/src/main/java/com/coremedia/iso/boxes/apple/AppleRecordingYearBox.java
new file mode 100644
index 0000000..da13300
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/apple/AppleRecordingYearBox.java
@@ -0,0 +1,16 @@
+package com.coremedia.iso.boxes.apple;
+
+/**
+ *
+ */
+public class AppleRecordingYearBox extends AbstractAppleMetaDataBox {
+    public static final String TYPE = "\u00a9day";
+
+
+    public AppleRecordingYearBox() {
+        super(TYPE);
+        appleDataBox = AppleDataBox.getStringAppleDataBox();
+    }
+
+
+}
\ No newline at end of file
diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/apple/AppleReferenceMovieBox.java b/isoparser/src/main/java/com/coremedia/iso/boxes/apple/AppleReferenceMovieBox.java
new file mode 100644
index 0000000..49c539f
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/apple/AppleReferenceMovieBox.java
@@ -0,0 +1,28 @@
+/*

+ * Copyright 2009 castLabs GmbH, Berlin

+ *

+ * Licensed under the Apache License, Version 2.0 (the License);

+ * you may not use this file except in compliance with the License.

+ * You may obtain a copy of the License at

+ *

+ *     http://www.apache.org/licenses/LICENSE-2.0

+ *

+ * Unless required by applicable law or agreed to in writing, software

+ * distributed under the License is distributed on an AS IS BASIS,

+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

+ * See the License for the specific language governing permissions and

+ * limitations under the License.

+ */

+

+package com.coremedia.iso.boxes.apple;

+

+import com.googlecode.mp4parser.AbstractContainerBox;

+

+public class AppleReferenceMovieBox extends AbstractContainerBox {

+    public static final String TYPE = "rmra";

+

+    public AppleReferenceMovieBox() {

+        super(TYPE);

+    }

+

+}

diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/apple/AppleReferenceMovieDescriptorBox.java b/isoparser/src/main/java/com/coremedia/iso/boxes/apple/AppleReferenceMovieDescriptorBox.java
new file mode 100644
index 0000000..488f01b
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/apple/AppleReferenceMovieDescriptorBox.java
@@ -0,0 +1,27 @@
+/*

+ * Copyright 2009 castLabs GmbH, Berlin

+ *

+ * Licensed under the Apache License, Version 2.0 (the License);

+ * you may not use this file except in compliance with the License.

+ * You may obtain a copy of the License at

+ *

+ *     http://www.apache.org/licenses/LICENSE-2.0

+ *

+ * Unless required by applicable law or agreed to in writing, software

+ * distributed under the License is distributed on an AS IS BASIS,

+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

+ * See the License for the specific language governing permissions and

+ * limitations under the License.

+ */

+

+package com.coremedia.iso.boxes.apple;

+

+import com.googlecode.mp4parser.AbstractContainerBox;

+

+public class AppleReferenceMovieDescriptorBox extends AbstractContainerBox {

+    public static final String TYPE = "rmda";

+

+    public AppleReferenceMovieDescriptorBox() {

+        super(TYPE);

+    }

+}

diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/apple/AppleShowBox.java b/isoparser/src/main/java/com/coremedia/iso/boxes/apple/AppleShowBox.java
new file mode 100644
index 0000000..66b0d59
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/apple/AppleShowBox.java
@@ -0,0 +1,15 @@
+package com.coremedia.iso.boxes.apple;
+
+/**
+ *
+ */
+public final class AppleShowBox extends AbstractAppleMetaDataBox {
+    public static final String TYPE = "tvsh";
+
+
+    public AppleShowBox() {
+        super(TYPE);
+        appleDataBox = AppleDataBox.getStringAppleDataBox();
+    }
+
+}
\ No newline at end of file
diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/apple/AppleSortAlbumBox.java b/isoparser/src/main/java/com/coremedia/iso/boxes/apple/AppleSortAlbumBox.java
new file mode 100644
index 0000000..cf74004
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/apple/AppleSortAlbumBox.java
@@ -0,0 +1,14 @@
+package com.coremedia.iso.boxes.apple;
+
+/**
+ *
+ */
+public final class AppleSortAlbumBox extends AbstractAppleMetaDataBox {
+    public static final String TYPE = "soal";
+
+
+    public AppleSortAlbumBox() {
+        super(TYPE);
+        appleDataBox = AppleDataBox.getStringAppleDataBox();
+    }
+}
\ No newline at end of file
diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/apple/AppleStandardGenreBox.java b/isoparser/src/main/java/com/coremedia/iso/boxes/apple/AppleStandardGenreBox.java
new file mode 100644
index 0000000..21932fa
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/apple/AppleStandardGenreBox.java
@@ -0,0 +1,14 @@
+package com.coremedia.iso.boxes.apple;
+
+/**
+ *
+ */
+public final class AppleStandardGenreBox extends AbstractAppleMetaDataBox {
+    public static final String TYPE = "gnre";
+
+
+    public AppleStandardGenreBox() {
+        super(TYPE);
+        appleDataBox = AppleDataBox.getUint16AppleDataBox();
+    }
+}
\ No newline at end of file
diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/apple/AppleStoreAccountTypeBox.java b/isoparser/src/main/java/com/coremedia/iso/boxes/apple/AppleStoreAccountTypeBox.java
new file mode 100755
index 0000000..36ecf4e
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/apple/AppleStoreAccountTypeBox.java
@@ -0,0 +1,27 @@
+package com.coremedia.iso.boxes.apple;
+
+/**
+ * itunes MetaData comment box.
+ */
+public class AppleStoreAccountTypeBox extends AbstractAppleMetaDataBox {
+    public static final String TYPE = "akID";
+
+
+    public AppleStoreAccountTypeBox() {
+        super(TYPE);
+        appleDataBox = AppleDataBox.getUint8AppleDataBox();
+    }
+
+    public String getReadableValue() {
+        byte value = this.appleDataBox.getData()[0];
+        switch (value) {
+            case 0:
+                return "iTunes Account";
+            case 1:
+                return "AOL Account";
+            default:
+                return "unknown Account";
+        }
+
+    }
+}
\ No newline at end of file
diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/apple/AppleStoreCountryCodeBox.java b/isoparser/src/main/java/com/coremedia/iso/boxes/apple/AppleStoreCountryCodeBox.java
new file mode 100644
index 0000000..2c4756a
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/apple/AppleStoreCountryCodeBox.java
@@ -0,0 +1,54 @@
+package com.coremedia.iso.boxes.apple;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * itunes MetaData comment box.
+ */
+public class AppleStoreCountryCodeBox extends AbstractAppleMetaDataBox {
+    private static Map<String, String> countryCodes = new HashMap<String, String>();
+
+    static {
+        countryCodes.put("143460", "Australia");
+        countryCodes.put("143445", "Austria");
+        countryCodes.put("143446", "Belgium");
+        countryCodes.put("143455", "Canada");
+        countryCodes.put("143458", "Denmark");
+        countryCodes.put("143447", "Finland");
+        countryCodes.put("143442", "France");
+        countryCodes.put("143443", "Germany");
+        countryCodes.put("143448", "Greece");
+        countryCodes.put("143449", "Ireland");
+        countryCodes.put("143450", "Italy");
+        countryCodes.put("143462", "Japan");
+        countryCodes.put("143451", "Luxembourg");
+        countryCodes.put("143452", "Netherlands");
+        countryCodes.put("143461", "New Zealand");
+        countryCodes.put("143457", "Norway");
+        countryCodes.put("143453", "Portugal");
+        countryCodes.put("143454", "Spain");
+        countryCodes.put("143456", "Sweden");
+        countryCodes.put("143459", "Switzerland");
+        countryCodes.put("143444", "United Kingdom");
+        countryCodes.put("143441", "United States");
+    }
+
+    public static final String TYPE = "sfID";
+
+
+    public AppleStoreCountryCodeBox() {
+        super(TYPE);
+        appleDataBox = AppleDataBox.getUint32AppleDataBox();
+    }
+
+
+    public String getReadableValue() {
+        if (countryCodes.containsKey(getValue())) {
+            return countryCodes.get(getValue());
+        } else {
+            return "unknown country code " + getValue();
+        }
+
+    }
+}
\ No newline at end of file
diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/apple/AppleSynopsisBox.java b/isoparser/src/main/java/com/coremedia/iso/boxes/apple/AppleSynopsisBox.java
new file mode 100644
index 0000000..cd5c2ab
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/apple/AppleSynopsisBox.java
@@ -0,0 +1,16 @@
+package com.coremedia.iso.boxes.apple;
+
+/**
+ *
+ */
+public final class AppleSynopsisBox extends AbstractAppleMetaDataBox {
+    public static final String TYPE = "ldes";
+
+
+    public AppleSynopsisBox() {
+        super(TYPE);
+        appleDataBox = AppleDataBox.getStringAppleDataBox();
+    }
+
+
+}
\ No newline at end of file
diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/apple/AppleTempBox.java b/isoparser/src/main/java/com/coremedia/iso/boxes/apple/AppleTempBox.java
new file mode 100644
index 0000000..ef57228
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/apple/AppleTempBox.java
@@ -0,0 +1,28 @@
+package com.coremedia.iso.boxes.apple;

+

+/**

+ * Beats per minute.

+ */

+public final class AppleTempBox extends AbstractAppleMetaDataBox {

+    public static final String TYPE = "tmpo";

+

+

+    public AppleTempBox() {

+        super(TYPE);

+        appleDataBox = AppleDataBox.getUint16AppleDataBox();

+    }

+

+

+    public int getTempo() {

+        return appleDataBox.getData()[1];

+    }

+

+    public void setTempo(int tempo) {

+        appleDataBox = new AppleDataBox();

+        appleDataBox.setVersion(0);

+        appleDataBox.setFlags(21);

+        appleDataBox.setFourBytes(new byte[4]);

+        appleDataBox.setData(new byte[]{0, (byte) (tempo & 0xFF)});

+

+    }

+}
\ No newline at end of file
diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/apple/AppleTrackAuthorBox.java b/isoparser/src/main/java/com/coremedia/iso/boxes/apple/AppleTrackAuthorBox.java
new file mode 100644
index 0000000..c5b3732
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/apple/AppleTrackAuthorBox.java
@@ -0,0 +1,16 @@
+package com.coremedia.iso.boxes.apple;
+
+/**
+ *
+ */
+public final class AppleTrackAuthorBox extends AbstractAppleMetaDataBox {
+    public static final String TYPE = "\u00a9wrt";
+
+
+    public AppleTrackAuthorBox() {
+        super(TYPE);
+        appleDataBox = AppleDataBox.getStringAppleDataBox();
+    }
+
+
+}
\ No newline at end of file
diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/apple/AppleTrackNumberBox.java b/isoparser/src/main/java/com/coremedia/iso/boxes/apple/AppleTrackNumberBox.java
new file mode 100644
index 0000000..c073c2f
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/apple/AppleTrackNumberBox.java
@@ -0,0 +1,48 @@
+package com.coremedia.iso.boxes.apple;
+
+/**
+ *
+ */
+public final class AppleTrackNumberBox extends AbstractAppleMetaDataBox {
+    public static final String TYPE = "trkn";
+
+
+    public AppleTrackNumberBox() {
+        super(TYPE);
+    }
+
+
+    /**
+     * @param track the actual track number
+     * @param of    number of tracks overall
+     */
+    public void setTrackNumber(byte track, byte of) {
+        appleDataBox = new AppleDataBox();
+        appleDataBox.setVersion(0);
+        appleDataBox.setFlags(0);
+        appleDataBox.setFourBytes(new byte[4]);
+        appleDataBox.setData(new byte[]{0, 0, 0, track, 0, of, 0, 0});
+    }
+
+    public byte getTrackNumber() {
+        return appleDataBox.getData()[3];
+    }
+
+    public byte getNumberOfTracks() {
+        return appleDataBox.getData()[5];
+    }
+
+    public void setNumberOfTracks(byte numberOfTracks) {
+        byte[] content = appleDataBox.getData();
+        content[5] = numberOfTracks;
+        appleDataBox.setData(content);
+    }
+
+    public void setTrackNumber(byte trackNumber) {
+        byte[] content = appleDataBox.getData();
+        content[3] = trackNumber;
+        appleDataBox.setData(content);
+    }
+
+
+}
\ No newline at end of file
diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/apple/AppleTrackTitleBox.java b/isoparser/src/main/java/com/coremedia/iso/boxes/apple/AppleTrackTitleBox.java
new file mode 100644
index 0000000..3dd613c
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/apple/AppleTrackTitleBox.java
@@ -0,0 +1,15 @@
+package com.coremedia.iso.boxes.apple;
+
+/**
+ *
+ */
+public final class AppleTrackTitleBox extends AbstractAppleMetaDataBox {
+    public static final String TYPE = "\u00a9nam";
+
+
+    public AppleTrackTitleBox() {
+        super(TYPE);
+        appleDataBox = AppleDataBox.getStringAppleDataBox();
+    }
+
+}
diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/apple/AppleTvEpisodeBox.java b/isoparser/src/main/java/com/coremedia/iso/boxes/apple/AppleTvEpisodeBox.java
new file mode 100644
index 0000000..3b3817b
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/apple/AppleTvEpisodeBox.java
@@ -0,0 +1,15 @@
+package com.coremedia.iso.boxes.apple;

+

+/**

+ * Tv Episode.

+ */

+public class AppleTvEpisodeBox extends AbstractAppleMetaDataBox {

+    public static final String TYPE = "tves";

+

+

+    public AppleTvEpisodeBox() {

+        super(TYPE);

+        appleDataBox = AppleDataBox.getUint32AppleDataBox();

+    }

+

+}
\ No newline at end of file
diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/apple/AppleTvEpisodeNumberBox.java b/isoparser/src/main/java/com/coremedia/iso/boxes/apple/AppleTvEpisodeNumberBox.java
new file mode 100644
index 0000000..33cd4e3
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/apple/AppleTvEpisodeNumberBox.java
@@ -0,0 +1,15 @@
+package com.coremedia.iso.boxes.apple;

+

+/**

+ * Tv Episode.

+ */

+public class AppleTvEpisodeNumberBox extends AbstractAppleMetaDataBox {

+    public static final String TYPE = "tven";

+

+

+    public AppleTvEpisodeNumberBox() {

+        super(TYPE);

+        appleDataBox = AppleDataBox.getStringAppleDataBox();

+    }

+

+}
\ No newline at end of file
diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/apple/AppleTvSeasonBox.java b/isoparser/src/main/java/com/coremedia/iso/boxes/apple/AppleTvSeasonBox.java
new file mode 100644
index 0000000..9459ea3
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/apple/AppleTvSeasonBox.java
@@ -0,0 +1,15 @@
+package com.coremedia.iso.boxes.apple;

+

+/**

+ * Tv Season.

+ */

+public final class AppleTvSeasonBox extends AbstractAppleMetaDataBox {

+    public static final String TYPE = "tvsn";

+

+

+    public AppleTvSeasonBox() {

+        super(TYPE);

+        appleDataBox = AppleDataBox.getUint32AppleDataBox();

+    }

+

+}
\ No newline at end of file
diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/apple/AppleWaveBox.java b/isoparser/src/main/java/com/coremedia/iso/boxes/apple/AppleWaveBox.java
new file mode 100644
index 0000000..65edd38
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/apple/AppleWaveBox.java
@@ -0,0 +1,16 @@
+package com.coremedia.iso.boxes.apple;
+
+import com.googlecode.mp4parser.AbstractContainerBox;
+
+/**
+ *
+ */
+public final class AppleWaveBox extends AbstractContainerBox {
+    public static final String TYPE = "wave";
+
+    public AppleWaveBox() {
+        super(TYPE);
+    }
+
+
+}
diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/dece/.svn/all-wcprops b/isoparser/src/main/java/com/coremedia/iso/boxes/dece/.svn/all-wcprops
new file mode 100644
index 0000000..fb492fe
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/dece/.svn/all-wcprops
@@ -0,0 +1,11 @@
+K 25
+svn:wc:ra_dav:version-url
+V 76
+/svn/!svn/ver/507/trunk/isoparser/src/main/java/com/coremedia/iso/boxes/dece
+END
+TrickPlayBox.java
+K 25
+svn:wc:ra_dav:version-url
+V 94
+/svn/!svn/ver/507/trunk/isoparser/src/main/java/com/coremedia/iso/boxes/dece/TrickPlayBox.java
+END
diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/dece/.svn/entries b/isoparser/src/main/java/com/coremedia/iso/boxes/dece/.svn/entries
new file mode 100644
index 0000000..f3d8baf
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/dece/.svn/entries
@@ -0,0 +1,62 @@
+10
+
+dir
+778
+http://mp4parser.googlecode.com/svn/trunk/isoparser/src/main/java/com/coremedia/iso/boxes/dece
+http://mp4parser.googlecode.com/svn
+
+
+
+2012-04-21T22:05:38.425329Z
+507
+Sebastian.Annies@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+7decde4b-c250-0410-a0da-51896bc88be6
+
+TrickPlayBox.java
+file
+
+
+
+
+2012-09-14T17:27:52.607249Z
+0afc708ec47fcdf8687d1623014b81a0
+2012-04-21T22:05:38.425329Z
+507
+Sebastian.Annies@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+2716
+
diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/dece/.svn/text-base/TrickPlayBox.java.svn-base b/isoparser/src/main/java/com/coremedia/iso/boxes/dece/.svn/text-base/TrickPlayBox.java.svn-base
new file mode 100644
index 0000000..24d5712
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/dece/.svn/text-base/TrickPlayBox.java.svn-base
@@ -0,0 +1,108 @@
+package com.coremedia.iso.boxes.dece;

+

+import com.coremedia.iso.IsoTypeReader;

+import com.coremedia.iso.IsoTypeWriter;

+import com.googlecode.mp4parser.AbstractFullBox;

+

+import java.nio.ByteBuffer;

+import java.util.ArrayList;

+import java.util.List;

+

+/**

+ * aligned(8) class TrickPlayBox

+ * extends FullBox(‘trik’, version=0, flags=0)

+ * {

+ * for (i=0; I < sample_count; i++) {

+ * unsigned int(2) pic_type;

+ * unsigned int(6) dependency_level;

+ * }

+ * }

+ */

+public class TrickPlayBox extends AbstractFullBox {

+    public static final String TYPE = "trik";

+

+    private List<Entry> entries = new ArrayList<Entry>();

+

+    public TrickPlayBox() {

+        super(TYPE);

+    }

+

+    public void setEntries(List<Entry> entries) {

+        this.entries = entries;

+    }

+

+    public List<Entry> getEntries() {

+        return entries;

+    }

+

+    public static class Entry {

+

+        public Entry() {

+        }

+

+        public Entry(int value) {

+            this.value = value;

+        }

+

+

+        private int value;

+

+        public int getPicType() {

+            return (value >> 6) & 0x03;

+        }

+

+        public void setPicType(int picType) {

+            value = value & (0xff >> 3);

+            value = (picType & 0x03) << 6 | value;

+        }

+

+        public int getDependencyLevel() {

+            return value & 0x3f;

+        }

+

+        public void setDependencyLevel(int dependencyLevel) {

+            value = (dependencyLevel & 0x3f) | value;

+        }

+

+

+        @Override

+        public String toString() {

+            final StringBuilder sb = new StringBuilder();

+            sb.append("Entry");

+            sb.append("{picType=").append(getPicType());

+            sb.append(",dependencyLevel=").append(getDependencyLevel());

+            sb.append('}');

+            return sb.toString();

+        }

+    }

+

+    @Override

+    protected long getContentSize() {

+        return 4 + entries.size();

+    }

+

+    @Override

+    public void _parseDetails(ByteBuffer content) {

+        parseVersionAndFlags(content);

+        while (content.remaining() > 0) {

+            entries.add(new Entry(IsoTypeReader.readUInt8(content)));

+        }

+    }

+

+    @Override

+    protected void getContent(ByteBuffer byteBuffer) {

+        writeVersionAndFlags(byteBuffer);

+        for (Entry entry : entries) {

+            IsoTypeWriter.writeUInt8(byteBuffer, entry.value);

+        }

+    }

+

+    @Override

+    public String toString() {

+        final StringBuilder sb = new StringBuilder();

+        sb.append("TrickPlayBox");

+        sb.append("{entries=").append(entries);

+        sb.append('}');

+        return sb.toString();

+    }

+}

diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/dece/TrickPlayBox.java b/isoparser/src/main/java/com/coremedia/iso/boxes/dece/TrickPlayBox.java
new file mode 100644
index 0000000..24d5712
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/dece/TrickPlayBox.java
@@ -0,0 +1,108 @@
+package com.coremedia.iso.boxes.dece;

+

+import com.coremedia.iso.IsoTypeReader;

+import com.coremedia.iso.IsoTypeWriter;

+import com.googlecode.mp4parser.AbstractFullBox;

+

+import java.nio.ByteBuffer;

+import java.util.ArrayList;

+import java.util.List;

+

+/**

+ * aligned(8) class TrickPlayBox

+ * extends FullBox(‘trik’, version=0, flags=0)

+ * {

+ * for (i=0; I < sample_count; i++) {

+ * unsigned int(2) pic_type;

+ * unsigned int(6) dependency_level;

+ * }

+ * }

+ */

+public class TrickPlayBox extends AbstractFullBox {

+    public static final String TYPE = "trik";

+

+    private List<Entry> entries = new ArrayList<Entry>();

+

+    public TrickPlayBox() {

+        super(TYPE);

+    }

+

+    public void setEntries(List<Entry> entries) {

+        this.entries = entries;

+    }

+

+    public List<Entry> getEntries() {

+        return entries;

+    }

+

+    public static class Entry {

+

+        public Entry() {

+        }

+

+        public Entry(int value) {

+            this.value = value;

+        }

+

+

+        private int value;

+

+        public int getPicType() {

+            return (value >> 6) & 0x03;

+        }

+

+        public void setPicType(int picType) {

+            value = value & (0xff >> 3);

+            value = (picType & 0x03) << 6 | value;

+        }

+

+        public int getDependencyLevel() {

+            return value & 0x3f;

+        }

+

+        public void setDependencyLevel(int dependencyLevel) {

+            value = (dependencyLevel & 0x3f) | value;

+        }

+

+

+        @Override

+        public String toString() {

+            final StringBuilder sb = new StringBuilder();

+            sb.append("Entry");

+            sb.append("{picType=").append(getPicType());

+            sb.append(",dependencyLevel=").append(getDependencyLevel());

+            sb.append('}');

+            return sb.toString();

+        }

+    }

+

+    @Override

+    protected long getContentSize() {

+        return 4 + entries.size();

+    }

+

+    @Override

+    public void _parseDetails(ByteBuffer content) {

+        parseVersionAndFlags(content);

+        while (content.remaining() > 0) {

+            entries.add(new Entry(IsoTypeReader.readUInt8(content)));

+        }

+    }

+

+    @Override

+    protected void getContent(ByteBuffer byteBuffer) {

+        writeVersionAndFlags(byteBuffer);

+        for (Entry entry : entries) {

+            IsoTypeWriter.writeUInt8(byteBuffer, entry.value);

+        }

+    }

+

+    @Override

+    public String toString() {

+        final StringBuilder sb = new StringBuilder();

+        sb.append("TrickPlayBox");

+        sb.append("{entries=").append(entries);

+        sb.append('}');

+        return sb.toString();

+    }

+}

diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/fragment/.svn/all-wcprops b/isoparser/src/main/java/com/coremedia/iso/boxes/fragment/.svn/all-wcprops
new file mode 100644
index 0000000..4b6b1e0
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/fragment/.svn/all-wcprops
@@ -0,0 +1,89 @@
+K 25
+svn:wc:ra_dav:version-url
+V 80
+/svn/!svn/ver/707/trunk/isoparser/src/main/java/com/coremedia/iso/boxes/fragment
+END
+MovieFragmentRandomAccessBox.java
+K 25
+svn:wc:ra_dav:version-url
+V 114
+/svn/!svn/ver/505/trunk/isoparser/src/main/java/com/coremedia/iso/boxes/fragment/MovieFragmentRandomAccessBox.java
+END
+TrackFragmentBaseMediaDecodeTimeBox.java
+K 25
+svn:wc:ra_dav:version-url
+V 121
+/svn/!svn/ver/507/trunk/isoparser/src/main/java/com/coremedia/iso/boxes/fragment/TrackFragmentBaseMediaDecodeTimeBox.java
+END
+TrackFragmentBox.java
+K 25
+svn:wc:ra_dav:version-url
+V 102
+/svn/!svn/ver/505/trunk/isoparser/src/main/java/com/coremedia/iso/boxes/fragment/TrackFragmentBox.java
+END
+TrackRunBox.java
+K 25
+svn:wc:ra_dav:version-url
+V 97
+/svn/!svn/ver/640/trunk/isoparser/src/main/java/com/coremedia/iso/boxes/fragment/TrackRunBox.java
+END
+MovieExtendsBox.java
+K 25
+svn:wc:ra_dav:version-url
+V 101
+/svn/!svn/ver/505/trunk/isoparser/src/main/java/com/coremedia/iso/boxes/fragment/MovieExtendsBox.java
+END
+TrackFragmentRandomAccessBox.java
+K 25
+svn:wc:ra_dav:version-url
+V 114
+/svn/!svn/ver/624/trunk/isoparser/src/main/java/com/coremedia/iso/boxes/fragment/TrackFragmentRandomAccessBox.java
+END
+MovieFragmentHeaderBox.java
+K 25
+svn:wc:ra_dav:version-url
+V 108
+/svn/!svn/ver/507/trunk/isoparser/src/main/java/com/coremedia/iso/boxes/fragment/MovieFragmentHeaderBox.java
+END
+MovieFragmentRandomAccessOffsetBox.java
+K 25
+svn:wc:ra_dav:version-url
+V 120
+/svn/!svn/ver/507/trunk/isoparser/src/main/java/com/coremedia/iso/boxes/fragment/MovieFragmentRandomAccessOffsetBox.java
+END
+TrackExtendsBox.java
+K 25
+svn:wc:ra_dav:version-url
+V 101
+/svn/!svn/ver/507/trunk/isoparser/src/main/java/com/coremedia/iso/boxes/fragment/TrackExtendsBox.java
+END
+TrackFragmentHeaderBox.java
+K 25
+svn:wc:ra_dav:version-url
+V 108
+/svn/!svn/ver/640/trunk/isoparser/src/main/java/com/coremedia/iso/boxes/fragment/TrackFragmentHeaderBox.java
+END
+MovieFragmentBox.java
+K 25
+svn:wc:ra_dav:version-url
+V 102
+/svn/!svn/ver/671/trunk/isoparser/src/main/java/com/coremedia/iso/boxes/fragment/MovieFragmentBox.java
+END
+MovieExtendsHeaderBox.java
+K 25
+svn:wc:ra_dav:version-url
+V 107
+/svn/!svn/ver/707/trunk/isoparser/src/main/java/com/coremedia/iso/boxes/fragment/MovieExtendsHeaderBox.java
+END
+SegmentTypeBox.java
+K 25
+svn:wc:ra_dav:version-url
+V 100
+/svn/!svn/ver/613/trunk/isoparser/src/main/java/com/coremedia/iso/boxes/fragment/SegmentTypeBox.java
+END
+SampleFlags.java
+K 25
+svn:wc:ra_dav:version-url
+V 97
+/svn/!svn/ver/534/trunk/isoparser/src/main/java/com/coremedia/iso/boxes/fragment/SampleFlags.java
+END
diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/fragment/.svn/entries b/isoparser/src/main/java/com/coremedia/iso/boxes/fragment/.svn/entries
new file mode 100644
index 0000000..6212978
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/fragment/.svn/entries
@@ -0,0 +1,504 @@
+10
+
+dir
+778
+http://mp4parser.googlecode.com/svn/trunk/isoparser/src/main/java/com/coremedia/iso/boxes/fragment
+http://mp4parser.googlecode.com/svn
+
+
+
+2012-07-10T16:32:53.757675Z
+707
+michael.stattmann@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+7decde4b-c250-0410-a0da-51896bc88be6
+
+MovieFragmentRandomAccessBox.java
+file
+
+
+
+
+2012-09-14T17:27:52.267244Z
+4eabe3aabca1078ceea9af4a4834b0f1
+2012-04-21T21:18:31.685061Z
+505
+Sebastian.Annies@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+984
+
+TrackFragmentBaseMediaDecodeTimeBox.java
+file
+
+
+
+
+2012-09-14T17:27:52.267244Z
+af8610f8a9e617ce31f65b03dcc17367
+2012-04-21T22:05:38.425329Z
+507
+Sebastian.Annies@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+2190
+
+TrackFragmentBox.java
+file
+
+
+
+
+2012-09-14T17:27:52.267244Z
+dba2633d9c107e9eddcf3e6eab22c9dd
+2012-04-21T21:18:31.685061Z
+505
+Sebastian.Annies@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+1241
+
+TrackRunBox.java
+file
+
+
+
+
+2012-09-14T17:27:52.267244Z
+c28d12fedd74251d99e0d5c1830c94d3
+2012-05-25T01:59:01.697137Z
+640
+michael.stattmann@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+11046
+
+MovieExtendsBox.java
+file
+
+
+
+
+2012-09-14T17:27:52.267244Z
+dcf05781e764bcbfbb5e15fd788fb0aa
+2012-04-21T21:18:31.685061Z
+505
+Sebastian.Annies@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+937
+
+TrackFragmentRandomAccessBox.java
+file
+
+
+
+
+2012-09-14T17:27:52.267244Z
+45b30b8d197f9815b53fcc90fb31ee95
+2012-05-21T11:57:37.647327Z
+624
+Sebastian.Annies@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+9307
+
+MovieFragmentHeaderBox.java
+file
+
+
+
+
+2012-09-14T17:27:52.267244Z
+25d305e9e55dfdcf69ae5f31c90b8337
+2012-04-21T22:05:38.425329Z
+507
+Sebastian.Annies@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+1914
+
+MovieFragmentRandomAccessOffsetBox.java
+file
+
+
+
+
+2012-09-14T17:27:52.267244Z
+6d2116a9bd56b10e667a6a51bea18b53
+2012-04-21T22:05:38.425329Z
+507
+Sebastian.Annies@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+1720
+
+TrackExtendsBox.java
+file
+
+
+
+
+2012-09-14T17:27:52.267244Z
+322aa8226e5343046573a005646fc1d2
+2012-04-21T22:05:38.425329Z
+507
+Sebastian.Annies@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+3577
+
+TrackFragmentHeaderBox.java
+file
+
+
+
+
+2012-09-14T17:27:52.267244Z
+984fc3f2f62a36cef43dc93b804accb6
+2012-05-25T01:59:01.697137Z
+640
+michael.stattmann@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+7356
+
+MovieFragmentBox.java
+file
+
+
+
+
+2012-09-14T17:27:52.267244Z
+a3c1c53469581b52f3658b1abeba4e6a
+2012-06-10T18:50:38.971172Z
+671
+michael.stattmann@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+3033
+
+MovieExtendsHeaderBox.java
+file
+
+
+
+
+2012-09-14T17:27:52.267244Z
+1b6dca9e192c4e7f9ad26a2be93a2fd8
+2012-07-10T16:32:53.757675Z
+707
+michael.stattmann@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+2083
+
+SegmentTypeBox.java
+file
+
+
+
+
+2012-09-14T17:27:52.267244Z
+0c595f0be955e83b6f9e980455f6719f
+2012-05-11T07:48:18.576721Z
+613
+Sebastian.Annies@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+4363
+
+SampleFlags.java
+file
+
+
+
+
+2012-09-14T17:27:52.267244Z
+d39b07fe798f248be8d054513f809787
+2012-04-27T14:59:11.479630Z
+534
+Sebastian.Annies@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+6723
+
diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/fragment/.svn/text-base/MovieExtendsBox.java.svn-base b/isoparser/src/main/java/com/coremedia/iso/boxes/fragment/.svn/text-base/MovieExtendsBox.java.svn-base
new file mode 100644
index 0000000..5ecd642
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/fragment/.svn/text-base/MovieExtendsBox.java.svn-base
@@ -0,0 +1,31 @@
+/*
+ * Copyright 2009 castLabs GmbH, Berlin
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.coremedia.iso.boxes.fragment;
+
+import com.googlecode.mp4parser.AbstractContainerBox;
+
+/**
+ * aligned(8) class MovieExtendsBox extends Box('mvex'){
+ * }
+ */
+public class MovieExtendsBox extends AbstractContainerBox {
+    public static final String TYPE = "mvex";
+
+    public MovieExtendsBox() {
+        super(TYPE);
+    }
+}
diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/fragment/.svn/text-base/MovieExtendsHeaderBox.java.svn-base b/isoparser/src/main/java/com/coremedia/iso/boxes/fragment/.svn/text-base/MovieExtendsHeaderBox.java.svn-base
new file mode 100644
index 0000000..8dd58f9
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/fragment/.svn/text-base/MovieExtendsHeaderBox.java.svn-base
@@ -0,0 +1,71 @@
+/*
+ * Copyright 2009 castLabs GmbH, Berlin
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.coremedia.iso.boxes.fragment;
+
+import com.coremedia.iso.IsoTypeReader;
+import com.coremedia.iso.IsoTypeWriter;
+import com.googlecode.mp4parser.AbstractFullBox;
+
+import java.nio.ByteBuffer;
+
+/**
+ * aligned(8) class MovieExtendsHeaderBox extends FullBox('mehd', version, 0) {
+ * if (version==1) {
+ * unsigned int(64) fragment_duration;
+ * } else { // version==0
+ * unsigned int(32) fragment_duration;
+ * }
+ * }
+ */
+public class MovieExtendsHeaderBox extends AbstractFullBox {
+    public static final String TYPE = "mehd";
+    private long fragmentDuration;
+
+    public MovieExtendsHeaderBox() {
+        super(TYPE);
+    }
+
+    @Override
+    protected long getContentSize() {
+        return getVersion() == 1 ? 12 : 8;
+    }
+
+    @Override
+    public void _parseDetails(ByteBuffer content) {
+        parseVersionAndFlags(content);
+        fragmentDuration = getVersion() == 1 ? IsoTypeReader.readUInt64(content) : IsoTypeReader.readUInt32(content);
+    }
+
+
+    @Override
+    protected void getContent(ByteBuffer byteBuffer) {
+        writeVersionAndFlags(byteBuffer);
+        if (getVersion() == 1) {
+            IsoTypeWriter.writeUInt64(byteBuffer, fragmentDuration);
+        } else {
+            IsoTypeWriter.writeUInt32(byteBuffer, fragmentDuration);
+        }
+    }
+
+    public long getFragmentDuration() {
+        return fragmentDuration;
+    }
+
+    public void setFragmentDuration(long fragmentDuration) {
+        this.fragmentDuration = fragmentDuration;
+    }
+}
diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/fragment/.svn/text-base/MovieFragmentBox.java.svn-base b/isoparser/src/main/java/com/coremedia/iso/boxes/fragment/.svn/text-base/MovieFragmentBox.java.svn-base
new file mode 100644
index 0000000..e92bd53
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/fragment/.svn/text-base/MovieFragmentBox.java.svn-base
@@ -0,0 +1,100 @@
+/*
+ * Copyright 2009 castLabs GmbH, Berlin
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.coremedia.iso.boxes.fragment;
+
+import com.googlecode.mp4parser.AbstractContainerBox;
+import com.coremedia.iso.boxes.Box;
+import com.coremedia.iso.boxes.SampleDependencyTypeBox;
+import com.googlecode.mp4parser.annotations.DoNotParseDetail;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * aligned(8) class MovieFragmentBox extends Box(moof){
+ * }
+ */
+
+public class MovieFragmentBox extends AbstractContainerBox {
+    public static final String TYPE = "moof";
+
+    public MovieFragmentBox() {
+        super(TYPE);
+    }
+
+
+    public List<Long> getSyncSamples(SampleDependencyTypeBox sdtp) {
+        List<Long> result = new ArrayList<Long>();
+
+        final List<SampleDependencyTypeBox.Entry> sampleEntries = sdtp.getEntries();
+        long i = 1;
+        for (SampleDependencyTypeBox.Entry sampleEntry : sampleEntries) {
+            if (sampleEntry.getSampleDependsOn() == 2) {
+                result.add(i);
+            }
+            i++;
+        }
+
+        return result;
+    }
+
+    @DoNotParseDetail
+    public long getOffset() {
+        Box b = this;
+        long offset = 0;
+        while (b.getParent() != null) {
+            for (Box box : b.getParent().getBoxes()) {
+                if (b == box) {
+                    break;
+                }
+                offset += box.getSize();
+            }
+            b = b.getParent();
+        }
+        return offset;
+    }
+
+
+    public int getTrackCount() {
+        return getBoxes(TrackFragmentBox.class, false).size();
+    }
+
+    /**
+     * Returns the track numbers associated with this <code>MovieBox</code>.
+     *
+     * @return the tracknumbers (IDs) of the tracks in their order of appearance in the file
+     */
+
+    public long[] getTrackNumbers() {
+
+        List<TrackFragmentBox> trackBoxes = this.getBoxes(TrackFragmentBox.class, false);
+        long[] trackNumbers = new long[trackBoxes.size()];
+        for (int trackCounter = 0; trackCounter < trackBoxes.size(); trackCounter++) {
+            TrackFragmentBox trackBoxe = trackBoxes.get(trackCounter);
+            trackNumbers[trackCounter] = trackBoxe.getTrackFragmentHeaderBox().getTrackId();
+        }
+        return trackNumbers;
+    }
+
+    public List<TrackFragmentHeaderBox> getTrackFragmentHeaderBoxes() {
+        return getBoxes(TrackFragmentHeaderBox.class, true);
+    }
+
+    public List<TrackRunBox> getTrackRunBoxes() {
+        return getBoxes(TrackRunBox.class, true);
+    }
+}
diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/fragment/.svn/text-base/MovieFragmentHeaderBox.java.svn-base b/isoparser/src/main/java/com/coremedia/iso/boxes/fragment/.svn/text-base/MovieFragmentHeaderBox.java.svn-base
new file mode 100644
index 0000000..e58f7a2
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/fragment/.svn/text-base/MovieFragmentHeaderBox.java.svn-base
@@ -0,0 +1,72 @@
+/*
+ * Copyright 2009 castLabs GmbH, Berlin
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.coremedia.iso.boxes.fragment;
+
+import com.coremedia.iso.IsoTypeReader;
+import com.coremedia.iso.IsoTypeWriter;
+import com.googlecode.mp4parser.AbstractFullBox;
+
+import java.nio.ByteBuffer;
+
+/**
+ * aligned(8) class MovieFragmentHeaderBox
+ * extends FullBox('mfhd', 0, 0){
+ * unsigned int(32) sequence_number;
+ * }
+ */
+
+public class MovieFragmentHeaderBox extends AbstractFullBox {
+    public static final String TYPE = "mfhd";
+    private long sequenceNumber;
+
+    public MovieFragmentHeaderBox() {
+        super(TYPE);
+    }
+
+    protected long getContentSize() {
+        return 8;
+    }
+
+    @Override
+    protected void getContent(ByteBuffer byteBuffer) {
+        writeVersionAndFlags(byteBuffer);
+        IsoTypeWriter.writeUInt32(byteBuffer, sequenceNumber);
+    }
+
+
+    @Override
+    public void _parseDetails(ByteBuffer content) {
+        parseVersionAndFlags(content);
+        sequenceNumber = IsoTypeReader.readUInt32(content);
+
+    }
+
+    public long getSequenceNumber() {
+        return sequenceNumber;
+    }
+
+    public void setSequenceNumber(long sequenceNumber) {
+        this.sequenceNumber = sequenceNumber;
+    }
+
+    @Override
+    public String toString() {
+        return "MovieFragmentHeaderBox{" +
+                "sequenceNumber=" + sequenceNumber +
+                '}';
+    }
+}
diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/fragment/.svn/text-base/MovieFragmentRandomAccessBox.java.svn-base b/isoparser/src/main/java/com/coremedia/iso/boxes/fragment/.svn/text-base/MovieFragmentRandomAccessBox.java.svn-base
new file mode 100644
index 0000000..86e2c9d
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/fragment/.svn/text-base/MovieFragmentRandomAccessBox.java.svn-base
@@ -0,0 +1,34 @@
+/*
+ * Copyright 2009 castLabs GmbH, Berlin
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.coremedia.iso.boxes.fragment;
+
+import com.googlecode.mp4parser.AbstractContainerBox;
+
+/**
+ * aligned(8) class MovieFragmentRandomAccessBox
+ * extends Box('mfra')
+ * {
+ * }
+ */
+public class MovieFragmentRandomAccessBox extends AbstractContainerBox {
+    public static final String TYPE = "mfra";
+
+    public MovieFragmentRandomAccessBox() {
+        super(TYPE);
+    }
+
+}
diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/fragment/.svn/text-base/MovieFragmentRandomAccessOffsetBox.java.svn-base b/isoparser/src/main/java/com/coremedia/iso/boxes/fragment/.svn/text-base/MovieFragmentRandomAccessOffsetBox.java.svn-base
new file mode 100644
index 0000000..edbfd66
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/fragment/.svn/text-base/MovieFragmentRandomAccessOffsetBox.java.svn-base
@@ -0,0 +1,62 @@
+/*
+ * Copyright 2009 castLabs GmbH, Berlin
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.coremedia.iso.boxes.fragment;
+
+import com.coremedia.iso.IsoTypeReader;
+import com.coremedia.iso.IsoTypeWriter;
+import com.googlecode.mp4parser.AbstractFullBox;
+
+import java.nio.ByteBuffer;
+
+/**
+ * aligned(8) class MovieFragmentRandomAccessOffsetBox
+ * extends FullBox('mfro', version, 0) {
+ * unsigned int(32) size;
+ * }
+ */
+public class MovieFragmentRandomAccessOffsetBox extends AbstractFullBox {
+    public static final String TYPE = "mfro";
+    private long mfraSize;
+
+    public MovieFragmentRandomAccessOffsetBox() {
+        super(TYPE);
+    }
+
+    protected long getContentSize() {
+        return 8;
+    }
+
+    @Override
+    public void _parseDetails(ByteBuffer content) {
+        parseVersionAndFlags(content);
+        mfraSize = IsoTypeReader.readUInt32(content);
+    }
+
+    @Override
+    protected void getContent(ByteBuffer byteBuffer) {
+        writeVersionAndFlags(byteBuffer);
+        IsoTypeWriter.writeUInt32(byteBuffer, mfraSize);
+    }
+
+    public long getMfraSize() {
+        return mfraSize;
+    }
+
+    public void setMfraSize(long mfraSize) {
+        this.mfraSize = mfraSize;
+    }
+}
diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/fragment/.svn/text-base/SampleFlags.java.svn-base b/isoparser/src/main/java/com/coremedia/iso/boxes/fragment/.svn/text-base/SampleFlags.java.svn-base
new file mode 100644
index 0000000..6caaf1e
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/fragment/.svn/text-base/SampleFlags.java.svn-base
@@ -0,0 +1,207 @@
+/*
+ * Copyright 2009 castLabs GmbH, Berlin
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.coremedia.iso.boxes.fragment;
+
+import com.googlecode.mp4parser.boxes.mp4.objectdescriptors.BitReaderBuffer;
+import com.googlecode.mp4parser.boxes.mp4.objectdescriptors.BitWriterBuffer;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+
+/**
+ * bit(6) reserved=0;
+ * unsigned int(2) sample_depends_on;
+ * unsigned int(2) sample_is_depended_on;
+ * unsigned int(2) sample_has_redundancy;
+ * bit(3) sample_padding_value;
+ * bit(1) sample_is_difference_sample;
+ * // i.e. when 1 signals a non-key or non-sync sample
+ * unsigned int(16) sample_degradation_priority;
+ */
+public class SampleFlags {
+    private int reserved;
+    private int sampleDependsOn;
+    private int sampleIsDependedOn;
+    private int sampleHasRedundancy;
+    private int samplePaddingValue;
+    private boolean sampleIsDifferenceSample;
+    private int sampleDegradationPriority;
+
+    public SampleFlags() {
+
+    }
+
+    public SampleFlags(ByteBuffer bb) {
+        BitReaderBuffer brb = new BitReaderBuffer(bb);
+        reserved = brb.readBits(6);
+        sampleDependsOn = brb.readBits(2);
+        sampleIsDependedOn = brb.readBits(2);
+        sampleHasRedundancy = brb.readBits(2);
+        samplePaddingValue = brb.readBits(3);
+        sampleIsDifferenceSample = brb.readBits(1) == 1;
+        sampleDegradationPriority = brb.readBits(16);
+    }
+
+
+    public void getContent(ByteBuffer os) {
+        BitWriterBuffer bitWriterBuffer = new BitWriterBuffer(os);
+        bitWriterBuffer.writeBits(reserved, 6);
+        bitWriterBuffer.writeBits(sampleDependsOn, 2);
+        bitWriterBuffer.writeBits(sampleIsDependedOn, 2);
+        bitWriterBuffer.writeBits(sampleHasRedundancy, 2);
+        bitWriterBuffer.writeBits(samplePaddingValue, 3);
+        bitWriterBuffer.writeBits(this.sampleIsDifferenceSample ? 1 : 0, 1);
+        bitWriterBuffer.writeBits(sampleDegradationPriority, 16);
+    }
+
+    public int getReserved() {
+        return reserved;
+    }
+
+    public void setReserved(int reserved) {
+        this.reserved = reserved;
+    }
+
+    /**
+     * @see #setSampleDependsOn(int)
+     */
+    public int getSampleDependsOn() {
+        return sampleDependsOn;
+    }
+
+    /**
+     * sample_depends_on takes one of the following four values:
+     * <pre>
+     * 0: the dependency of this sample is unknown;
+     * 1: this sample does depend on others (not an I picture);
+     * 2: this sample does not depend on others (I picture);
+     * 3: reserved
+     * </pre>
+     *
+     */
+    public void setSampleDependsOn(int sampleDependsOn) {
+        this.sampleDependsOn = sampleDependsOn;
+    }
+
+    /**
+     * @see #setSampleIsDependedOn(int)
+     */
+    public int getSampleIsDependedOn() {
+        return sampleIsDependedOn;
+    }
+
+    /**
+     * sample_is_depended_on takes one of the following four values:
+     * <pre>
+     * 0: the dependency of other samples on this sample is unknown;
+     * 1: other samples may depend on this one (not disposable);
+     * 2: no other sample depends on this one (disposable);
+     * 3: reserved
+     * </pre>
+     *
+     */
+    public void setSampleIsDependedOn(int sampleIsDependedOn) {
+        this.sampleIsDependedOn = sampleIsDependedOn;
+    }
+
+    /**
+     * @see #setSampleHasRedundancy(int)
+     */
+    public int getSampleHasRedundancy() {
+        return sampleHasRedundancy;
+    }
+
+    /**
+     * sample_has_redundancy takes one of the following four values:
+     * <pre>
+     * 0: it is unknown whether there is redundant coding in this sample;
+     * 1: there is redundant coding in this sample;
+     * 2: there is no redundant coding in this sample;
+     * 3: reserved
+     * </pre>
+     */
+    public void setSampleHasRedundancy(int sampleHasRedundancy) {
+        this.sampleHasRedundancy = sampleHasRedundancy;
+    }
+
+    public int getSamplePaddingValue() {
+        return samplePaddingValue;
+    }
+
+    public void setSamplePaddingValue(int samplePaddingValue) {
+        this.samplePaddingValue = samplePaddingValue;
+    }
+
+    public boolean isSampleIsDifferenceSample() {
+        return sampleIsDifferenceSample;
+    }
+
+
+    public void setSampleIsDifferenceSample(boolean sampleIsDifferenceSample) {
+        this.sampleIsDifferenceSample = sampleIsDifferenceSample;
+    }
+
+    public int getSampleDegradationPriority() {
+        return sampleDegradationPriority;
+    }
+
+    public void setSampleDegradationPriority(int sampleDegradationPriority) {
+        this.sampleDegradationPriority = sampleDegradationPriority;
+    }
+
+    @Override
+    public String toString() {
+        return "SampleFlags{" +
+                "reserved=" + reserved +
+                ", sampleDependsOn=" + sampleDependsOn +
+                ", sampleHasRedundancy=" + sampleHasRedundancy +
+                ", samplePaddingValue=" + samplePaddingValue +
+                ", sampleIsDifferenceSample=" + sampleIsDifferenceSample +
+                ", sampleDegradationPriority=" + sampleDegradationPriority +
+                '}';
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (o == null || getClass() != o.getClass()) return false;
+
+        SampleFlags that = (SampleFlags) o;
+
+        if (reserved != that.reserved) return false;
+        if (sampleDegradationPriority != that.sampleDegradationPriority) return false;
+        if (sampleDependsOn != that.sampleDependsOn) return false;
+        if (sampleHasRedundancy != that.sampleHasRedundancy) return false;
+        if (sampleIsDependedOn != that.sampleIsDependedOn) return false;
+        if (sampleIsDifferenceSample != that.sampleIsDifferenceSample) return false;
+        if (samplePaddingValue != that.samplePaddingValue) return false;
+
+        return true;
+    }
+
+    @Override
+    public int hashCode() {
+        int result = reserved;
+        result = 31 * result + sampleDependsOn;
+        result = 31 * result + sampleIsDependedOn;
+        result = 31 * result + sampleHasRedundancy;
+        result = 31 * result + samplePaddingValue;
+        result = 31 * result + (sampleIsDifferenceSample ? 1 : 0);
+        result = 31 * result + sampleDegradationPriority;
+        return result;
+    }
+}
diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/fragment/.svn/text-base/SegmentTypeBox.java.svn-base b/isoparser/src/main/java/com/coremedia/iso/boxes/fragment/.svn/text-base/SegmentTypeBox.java.svn-base
new file mode 100644
index 0000000..5e0d47b
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/fragment/.svn/text-base/SegmentTypeBox.java.svn-base
@@ -0,0 +1,143 @@
+/*
+ * Copyright 2008 CoreMedia AG, Hamburg
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.coremedia.iso.boxes.fragment;
+
+import com.coremedia.iso.IsoFile;
+import com.coremedia.iso.IsoTypeReader;
+import com.coremedia.iso.IsoTypeWriter;
+import com.googlecode.mp4parser.AbstractBox;
+import com.googlecode.mp4parser.annotations.DoNotParseDetail;
+
+import java.nio.ByteBuffer;
+import java.util.Collections;
+import java.util.LinkedList;
+import java.util.List;
+
+/**
+ * This box identifies the specifications to which this file complies. <br>
+ * Each brand is a printable four-character code, registered with ISO, that
+ * identifies a precise specification.
+ */
+public class SegmentTypeBox extends AbstractBox {
+    public static final String TYPE = "styp";
+
+    private String majorBrand;
+    private long minorVersion;
+    private List<String> compatibleBrands = Collections.emptyList();
+
+    public SegmentTypeBox() {
+        super(TYPE);
+    }
+
+    public SegmentTypeBox(String majorBrand, long minorVersion, List<String> compatibleBrands) {
+        super(TYPE);
+        this.majorBrand = majorBrand;
+        this.minorVersion = minorVersion;
+        this.compatibleBrands = compatibleBrands;
+    }
+
+    protected long getContentSize() {
+        return 8 + compatibleBrands.size() * 4;
+
+    }
+
+    @Override
+    public void _parseDetails(ByteBuffer content) {
+        majorBrand = IsoTypeReader.read4cc(content);
+        minorVersion = IsoTypeReader.readUInt32(content);
+        int compatibleBrandsCount = content.remaining() / 4;
+        compatibleBrands = new LinkedList<String>();
+        for (int i = 0; i < compatibleBrandsCount; i++) {
+            compatibleBrands.add(IsoTypeReader.read4cc(content));
+        }
+    }
+
+    @Override
+    protected void getContent(ByteBuffer byteBuffer) {
+        byteBuffer.put(IsoFile.fourCCtoBytes(majorBrand));
+        IsoTypeWriter.writeUInt32(byteBuffer, minorVersion);
+        for (String compatibleBrand : compatibleBrands) {
+            byteBuffer.put(IsoFile.fourCCtoBytes(compatibleBrand));
+        }
+
+    }
+
+    /**
+     * Gets the brand identifier.
+     *
+     * @return the brand identifier
+     */
+    public String getMajorBrand() {
+        return majorBrand;
+    }
+
+    /**
+     * Sets the major brand of the file used to determine an appropriate reader.
+     *
+     * @param majorBrand the new major brand
+     */
+    public void setMajorBrand(String majorBrand) {
+        this.majorBrand = majorBrand;
+    }
+
+    /**
+     * Sets the "informative integer for the minor version of the major brand".
+     *
+     * @param minorVersion the version number of the major brand
+     */
+    public void setMinorVersion(int minorVersion) {
+        this.minorVersion = minorVersion;
+    }
+
+    /**
+     * Gets an informative integer for the minor version of the major brand.
+     *
+     * @return an informative integer
+     * @see SegmentTypeBox#getMajorBrand()
+     */
+    public long getMinorVersion() {
+        return minorVersion;
+    }
+
+    /**
+     * Gets an array of 4-cc brands.
+     *
+     * @return the compatible brands
+     */
+    public List<String> getCompatibleBrands() {
+        return compatibleBrands;
+    }
+
+    public void setCompatibleBrands(List<String> compatibleBrands) {
+        this.compatibleBrands = compatibleBrands;
+    }
+
+    @DoNotParseDetail
+    public String toString() {
+        StringBuilder result = new StringBuilder();
+        result.append("SegmentTypeBox[");
+        result.append("majorBrand=").append(getMajorBrand());
+        result.append(";");
+        result.append("minorVersion=").append(getMinorVersion());
+        for (String compatibleBrand : compatibleBrands) {
+            result.append(";");
+            result.append("compatibleBrand=").append(compatibleBrand);
+        }
+        result.append("]");
+        return result.toString();
+    }
+}
diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/fragment/.svn/text-base/TrackExtendsBox.java.svn-base b/isoparser/src/main/java/com/coremedia/iso/boxes/fragment/.svn/text-base/TrackExtendsBox.java.svn-base
new file mode 100644
index 0000000..8bba7c1
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/fragment/.svn/text-base/TrackExtendsBox.java.svn-base
@@ -0,0 +1,115 @@
+/*
+ * Copyright 2009 castLabs GmbH, Berlin
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.coremedia.iso.boxes.fragment;
+
+import com.coremedia.iso.IsoTypeReader;
+import com.coremedia.iso.IsoTypeWriter;
+import com.googlecode.mp4parser.AbstractFullBox;
+
+import java.nio.ByteBuffer;
+
+/**
+ * aligned(8) class TrackExtendsBox extends FullBox('trex', 0, 0){
+ * unsigned int(32) track_ID;
+ * unsigned int(32) default_sample_description_index;
+ * unsigned int(32) default_sample_duration;
+ * unsigned int(32) default_sample_size;
+ * unsigned int(32) default_sample_flags
+ * }
+ */
+public class TrackExtendsBox extends AbstractFullBox {
+    public static final String TYPE = "trex";
+    private long trackId;
+    private long defaultSampleDescriptionIndex;
+    private long defaultSampleDuration;
+    private long defaultSampleSize;
+    private SampleFlags defaultSampleFlags;
+
+    public TrackExtendsBox() {
+        super(TYPE);
+    }
+
+    @Override
+    protected long getContentSize() {
+        return 5 * 4 + 4;
+    }
+
+    @Override
+    protected void getContent(ByteBuffer byteBuffer) {
+        writeVersionAndFlags(byteBuffer);
+        IsoTypeWriter.writeUInt32(byteBuffer, trackId);
+        IsoTypeWriter.writeUInt32(byteBuffer, defaultSampleDescriptionIndex);
+        IsoTypeWriter.writeUInt32(byteBuffer, defaultSampleDuration);
+        IsoTypeWriter.writeUInt32(byteBuffer, defaultSampleSize);
+        defaultSampleFlags.getContent(byteBuffer);
+    }
+
+    @Override
+    public void _parseDetails(ByteBuffer content) {
+        parseVersionAndFlags(content);
+        trackId = IsoTypeReader.readUInt32(content);
+        defaultSampleDescriptionIndex = IsoTypeReader.readUInt32(content);
+        defaultSampleDuration = IsoTypeReader.readUInt32(content);
+        defaultSampleSize = IsoTypeReader.readUInt32(content);
+        defaultSampleFlags = new SampleFlags(content);
+    }
+
+    public long getTrackId() {
+        return trackId;
+    }
+
+    public long getDefaultSampleDescriptionIndex() {
+        return defaultSampleDescriptionIndex;
+    }
+
+    public long getDefaultSampleDuration() {
+        return defaultSampleDuration;
+    }
+
+    public long getDefaultSampleSize() {
+        return defaultSampleSize;
+    }
+
+    public SampleFlags getDefaultSampleFlags() {
+        return defaultSampleFlags;
+    }
+
+    public String getDefaultSampleFlagsStr() {
+        return defaultSampleFlags.toString();
+    }
+
+    public void setTrackId(long trackId) {
+        this.trackId = trackId;
+    }
+
+    public void setDefaultSampleDescriptionIndex(long defaultSampleDescriptionIndex) {
+        this.defaultSampleDescriptionIndex = defaultSampleDescriptionIndex;
+    }
+
+    public void setDefaultSampleDuration(long defaultSampleDuration) {
+        this.defaultSampleDuration = defaultSampleDuration;
+    }
+
+    public void setDefaultSampleSize(long defaultSampleSize) {
+        this.defaultSampleSize = defaultSampleSize;
+    }
+
+    public void setDefaultSampleFlags(SampleFlags defaultSampleFlags) {
+        this.defaultSampleFlags = defaultSampleFlags;
+
+    }
+}
diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/fragment/.svn/text-base/TrackFragmentBaseMediaDecodeTimeBox.java.svn-base b/isoparser/src/main/java/com/coremedia/iso/boxes/fragment/.svn/text-base/TrackFragmentBaseMediaDecodeTimeBox.java.svn-base
new file mode 100644
index 0000000..06fcf62
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/fragment/.svn/text-base/TrackFragmentBaseMediaDecodeTimeBox.java.svn-base
@@ -0,0 +1,76 @@
+/*
+ * Copyright 2009 castLabs GmbH, Berlin
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.coremedia.iso.boxes.fragment;
+
+import com.coremedia.iso.IsoTypeReader;
+import com.coremedia.iso.IsoTypeWriter;
+import com.googlecode.mp4parser.AbstractFullBox;
+
+import java.nio.ByteBuffer;
+
+public class TrackFragmentBaseMediaDecodeTimeBox extends AbstractFullBox {
+    public static final String TYPE = "tfdt";
+
+    private long baseMediaDecodeTime;
+
+    public TrackFragmentBaseMediaDecodeTimeBox() {
+        super(TYPE);
+    }
+
+    @Override
+    protected long getContentSize() {
+        return getVersion() == 0 ? 8 : 12;
+    }
+
+    @Override
+    protected void getContent(ByteBuffer byteBuffer) {
+        writeVersionAndFlags(byteBuffer);
+        if (getVersion() == 1) {
+            IsoTypeWriter.writeUInt64(byteBuffer, baseMediaDecodeTime);
+        } else {
+            IsoTypeWriter.writeUInt32(byteBuffer, baseMediaDecodeTime);
+        }
+    }
+
+
+    @Override
+    public void _parseDetails(ByteBuffer content) {
+        parseVersionAndFlags(content);
+        if (getVersion() == 1) {
+            baseMediaDecodeTime = IsoTypeReader.readUInt64(content);
+        } else {
+            baseMediaDecodeTime = IsoTypeReader.readUInt32(content);
+        }
+
+    }
+
+
+    public long getBaseMediaDecodeTime() {
+        return baseMediaDecodeTime;
+    }
+
+    public void setBaseMediaDecodeTime(long baseMediaDecodeTime) {
+        this.baseMediaDecodeTime = baseMediaDecodeTime;
+    }
+
+    @Override
+    public String toString() {
+        return "TrackFragmentBaseMediaDecodeTimeBox{" +
+                "baseMediaDecodeTime=" + baseMediaDecodeTime +
+                '}';
+    }
+}
diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/fragment/.svn/text-base/TrackFragmentBox.java.svn-base b/isoparser/src/main/java/com/coremedia/iso/boxes/fragment/.svn/text-base/TrackFragmentBox.java.svn-base
new file mode 100644
index 0000000..fde7da5
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/fragment/.svn/text-base/TrackFragmentBox.java.svn-base
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2009 castLabs GmbH, Berlin
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.coremedia.iso.boxes.fragment;
+
+import com.googlecode.mp4parser.AbstractContainerBox;
+import com.coremedia.iso.boxes.Box;
+
+/**
+ * aligned(8) class TrackFragmentBox extends Box('traf'){
+ * }
+ */
+public class TrackFragmentBox extends AbstractContainerBox {
+    public static final String TYPE = "traf";
+
+    public TrackFragmentBox() {
+        super(TYPE);
+    }
+
+
+    public TrackFragmentHeaderBox getTrackFragmentHeaderBox() {
+        for (Box box : getBoxes()) {
+            if (box instanceof TrackFragmentHeaderBox) {
+                return (TrackFragmentHeaderBox) box;
+            }
+        }
+        return null;
+    }
+
+}
diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/fragment/.svn/text-base/TrackFragmentHeaderBox.java.svn-base b/isoparser/src/main/java/com/coremedia/iso/boxes/fragment/.svn/text-base/TrackFragmentHeaderBox.java.svn-base
new file mode 100644
index 0000000..fb9509b
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/fragment/.svn/text-base/TrackFragmentHeaderBox.java.svn-base
@@ -0,0 +1,224 @@
+/*
+ * Copyright 2009 castLabs GmbH, Berlin
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.coremedia.iso.boxes.fragment;
+
+import com.coremedia.iso.IsoTypeReader;
+import com.coremedia.iso.IsoTypeWriter;
+import com.googlecode.mp4parser.AbstractFullBox;
+
+import java.nio.ByteBuffer;
+
+/**
+ * aligned(8) class TrackFragmentHeaderBox
+ * extends FullBox('tfhd', 0, tf_flags){
+ * unsigned int(32) track_ID;
+ * // all the following are optional fields
+ * unsigned int(64) base_data_offset;
+ * unsigned int(32) sample_description_index;
+ * unsigned int(32) default_sample_duration;
+ * unsigned int(32) default_sample_size;
+ * unsigned int(32) default_sample_flags
+ * }
+ */
+public class TrackFragmentHeaderBox extends AbstractFullBox {
+    public static final String TYPE = "tfhd";
+
+    private long trackId;
+    private long baseDataOffset = -1;
+    private long sampleDescriptionIndex;
+    private long defaultSampleDuration = -1;
+    private long defaultSampleSize = -1;
+    private SampleFlags defaultSampleFlags;
+    private boolean durationIsEmpty;
+
+    public TrackFragmentHeaderBox() {
+        super(TYPE);
+    }
+
+    protected long getContentSize() {
+        long size = 8;
+        int flags = getFlags();
+        if ((flags & 0x1) == 1) { //baseDataOffsetPresent
+            size += 8;
+        }
+        if ((flags & 0x2) == 0x2) { //sampleDescriptionIndexPresent
+            size += 4;
+        }
+        if ((flags & 0x8) == 0x8) { //defaultSampleDurationPresent
+            size += 4;
+        }
+        if ((flags & 0x10) == 0x10) { //defaultSampleSizePresent
+            size += 4;
+        }
+        if ((flags & 0x20) == 0x20) { //defaultSampleFlagsPresent
+            size += 4;
+        }
+        return size;
+    }
+
+
+    protected void getContent(ByteBuffer byteBuffer) {
+        writeVersionAndFlags(byteBuffer);
+        IsoTypeWriter.writeUInt32(byteBuffer, trackId);
+
+        if ((getFlags() & 0x1) == 1) { //baseDataOffsetPresent
+            IsoTypeWriter.writeUInt64(byteBuffer, getBaseDataOffset());
+        }
+        if ((getFlags() & 0x2) == 0x2) { //sampleDescriptionIndexPresent
+            IsoTypeWriter.writeUInt32(byteBuffer, getSampleDescriptionIndex());
+        }
+        if ((getFlags() & 0x8) == 0x8) { //defaultSampleDurationPresent
+            IsoTypeWriter.writeUInt32(byteBuffer, getDefaultSampleDuration());
+        }
+        if ((getFlags() & 0x10) == 0x10) { //defaultSampleSizePresent
+            IsoTypeWriter.writeUInt32(byteBuffer, getDefaultSampleSize());
+        }
+        if ((getFlags() & 0x20) == 0x20) { //defaultSampleFlagsPresent
+            defaultSampleFlags.getContent(byteBuffer);
+        }
+    }
+
+    @Override
+    public void _parseDetails(ByteBuffer content) {
+        parseVersionAndFlags(content);
+        trackId = IsoTypeReader.readUInt32(content);
+        if ((getFlags() & 0x1) == 1) { //baseDataOffsetPresent
+            baseDataOffset = IsoTypeReader.readUInt64(content);
+        }
+        if ((getFlags() & 0x2) == 0x2) { //sampleDescriptionIndexPresent
+            sampleDescriptionIndex = IsoTypeReader.readUInt32(content);
+        }
+        if ((getFlags() & 0x8) == 0x8) { //defaultSampleDurationPresent
+            defaultSampleDuration = IsoTypeReader.readUInt32(content);
+        }
+        if ((getFlags() & 0x10) == 0x10) { //defaultSampleSizePresent
+            defaultSampleSize = IsoTypeReader.readUInt32(content);
+        }
+        if ((getFlags() & 0x20) == 0x20) { //defaultSampleFlagsPresent
+            defaultSampleFlags = new SampleFlags(content);
+        }
+        if ((getFlags() & 0x10000) == 0x10000) { //durationIsEmpty
+            durationIsEmpty = true;
+        }
+    }
+
+    public boolean hasBaseDataOffset() {
+        return (getFlags() & 0x1) != 0;
+    }
+
+    public boolean hasSampleDescriptionIndex() {
+        return (getFlags() & 0x2) != 0;
+    }
+
+    public boolean hasDefaultSampleDuration() {
+        return (getFlags() & 0x8) != 0;
+    }
+
+    public boolean hasDefaultSampleSize() {
+        return (getFlags() & 0x10) != 0;
+    }
+
+    public boolean hasDefaultSampleFlags() {
+        return (getFlags() & 0x20) != 0;
+    }
+
+    public long getTrackId() {
+        return trackId;
+    }
+
+    public long getBaseDataOffset() {
+        return baseDataOffset;
+    }
+
+    public long getSampleDescriptionIndex() {
+        return sampleDescriptionIndex;
+    }
+
+    public long getDefaultSampleDuration() {
+        return defaultSampleDuration;
+    }
+
+    public long getDefaultSampleSize() {
+        return defaultSampleSize;
+    }
+
+    public SampleFlags getDefaultSampleFlags() {
+        return defaultSampleFlags;
+    }
+
+    public boolean isDurationIsEmpty() {
+        return durationIsEmpty;
+    }
+
+    public void setTrackId(long trackId) {
+        this.trackId = trackId;
+    }
+
+    public void setBaseDataOffset(long baseDataOffset) {
+        if (baseDataOffset == -1) {
+            setFlags(getFlags() & (Integer.MAX_VALUE ^ 0x1));
+        } else {
+            setFlags(getFlags() | 0x1); // activate the field
+        }
+        this.baseDataOffset = baseDataOffset;
+    }
+
+    public void setSampleDescriptionIndex(long sampleDescriptionIndex) {
+        if (sampleDescriptionIndex == -1) {
+            setFlags(getFlags() & (Integer.MAX_VALUE ^ 0x2));
+        } else {
+            setFlags(getFlags() | 0x2); // activate the field
+        }
+        this.sampleDescriptionIndex = sampleDescriptionIndex;
+    }
+
+    public void setDefaultSampleDuration(long defaultSampleDuration) {
+        setFlags(getFlags() | 0x8); // activate the field
+        this.defaultSampleDuration = defaultSampleDuration;
+    }
+
+    public void setDefaultSampleSize(long defaultSampleSize) {
+        setFlags(getFlags() | 0x10); // activate the field
+        this.defaultSampleSize = defaultSampleSize;
+    }
+
+    public void setDefaultSampleFlags(SampleFlags defaultSampleFlags) {
+        setFlags(getFlags() | 0x20); // activate the field
+        this.defaultSampleFlags = defaultSampleFlags;
+    }
+
+    public void setDurationIsEmpty(boolean durationIsEmpty) {
+        setFlags(getFlags() | 0x10000); // activate the field
+        this.durationIsEmpty = durationIsEmpty;
+    }
+
+    @Override
+    public String toString() {
+        final StringBuilder sb = new StringBuilder();
+        sb.append("TrackFragmentHeaderBox");
+        sb.append("{trackId=").append(trackId);
+        sb.append(", baseDataOffset=").append(baseDataOffset);
+        sb.append(", sampleDescriptionIndex=").append(sampleDescriptionIndex);
+        sb.append(", defaultSampleDuration=").append(defaultSampleDuration);
+        sb.append(", defaultSampleSize=").append(defaultSampleSize);
+        sb.append(", defaultSampleFlags=").append(defaultSampleFlags);
+        sb.append(", durationIsEmpty=").append(durationIsEmpty);
+        sb.append('}');
+        return sb.toString();
+    }
+
+}
diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/fragment/.svn/text-base/TrackFragmentRandomAccessBox.java.svn-base b/isoparser/src/main/java/com/coremedia/iso/boxes/fragment/.svn/text-base/TrackFragmentRandomAccessBox.java.svn-base
new file mode 100644
index 0000000..94d24ae
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/fragment/.svn/text-base/TrackFragmentRandomAccessBox.java.svn-base
@@ -0,0 +1,294 @@
+/*
+ * Copyright 2009 castLabs GmbH, Berlin
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.coremedia.iso.boxes.fragment;
+
+import com.coremedia.iso.IsoTypeReader;
+import com.coremedia.iso.IsoTypeReaderVariable;
+import com.coremedia.iso.IsoTypeWriter;
+import com.coremedia.iso.IsoTypeWriterVariable;
+import com.googlecode.mp4parser.AbstractFullBox;
+
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * aligned(8) class TrackFragmentRandomAccessBox
+ * extends FullBox('tfra', version, 0) {
+ * unsigned int(32) track_ID;
+ * const unsigned int(26) reserved = 0;
+ * unsigned int(2) length_size_of_traf_num;
+ * unsigned int(2) length_size_of_trun_num;
+ * unsigned int(2) length_size_of_sample_num;
+ * unsigned int(32) number_of_entry;
+ * for(i=1; i <= number_of_entry; i++){
+ * if(version==1){
+ * unsigned int(64) time;
+ * unsigned int(64) moof_offset;
+ * }else{
+ * unsigned int(32) time;
+ * unsigned int(32) moof_offset;
+ * }
+ * unsigned int((length_size_of_traf_num+1) * 8) traf_number;
+ * unsigned int((length_size_of_trun_num+1) * 8) trun_number;
+ * unsigned int((length_size_of_sample_num+1) * 8) sample_number;
+ * }
+ * }
+ */
+public class TrackFragmentRandomAccessBox extends AbstractFullBox {
+    public static final String TYPE = "tfra";
+
+    private long trackId;
+    private int reserved;
+    private int lengthSizeOfTrafNum = 2;
+    private int lengthSizeOfTrunNum = 2;
+    private int lengthSizeOfSampleNum = 2;
+    private List<Entry> entries = Collections.emptyList();
+
+    public TrackFragmentRandomAccessBox() {
+        super(TYPE);
+    }
+
+
+    protected long getContentSize() {
+        long contentSize = 4;
+        contentSize += 4 + 4 /*26 + 2 + 2 + 2 */ + 4;
+        if (getVersion() == 1) {
+            contentSize += (8 + 8) * entries.size();
+        } else {
+            contentSize += (4 + 4) * entries.size();
+        }
+        contentSize += lengthSizeOfTrafNum * entries.size();
+        contentSize += lengthSizeOfTrunNum * entries.size();
+        contentSize += lengthSizeOfSampleNum * entries.size();
+        return contentSize;
+    }
+
+
+    @Override
+    public void _parseDetails(ByteBuffer content) {
+        parseVersionAndFlags(content);
+        trackId = IsoTypeReader.readUInt32(content);
+        long temp = IsoTypeReader.readUInt32(content);
+        reserved = (int) (temp >> 6);
+        lengthSizeOfTrafNum = ((int) (temp & 0x3F) >> 4) + 1;
+        lengthSizeOfTrunNum = ((int) (temp & 0xC) >> 2) + 1;
+        lengthSizeOfSampleNum = ((int) (temp & 0x3)) + 1;
+        long numberOfEntries = IsoTypeReader.readUInt32(content);
+
+        entries = new ArrayList<Entry>();
+
+        for (int i = 0; i < numberOfEntries; i++) {
+            Entry entry = new Entry();
+            if (getVersion() == 1) {
+                entry.time = IsoTypeReader.readUInt64(content);
+                entry.moofOffset = IsoTypeReader.readUInt64(content);
+            } else {
+                entry.time = IsoTypeReader.readUInt32(content);
+                entry.moofOffset = IsoTypeReader.readUInt32(content);
+            }
+            entry.trafNumber = IsoTypeReaderVariable.read(content, lengthSizeOfTrafNum);
+            entry.trunNumber = IsoTypeReaderVariable.read(content, lengthSizeOfTrunNum);
+            entry.sampleNumber = IsoTypeReaderVariable.read(content, lengthSizeOfSampleNum);
+
+            entries.add(entry);
+        }
+
+    }
+
+
+    @Override
+    protected void getContent(ByteBuffer byteBuffer) {
+        writeVersionAndFlags(byteBuffer);
+        IsoTypeWriter.writeUInt32(byteBuffer, trackId);
+        long temp;
+        temp = reserved << 6;
+        temp = temp | (((lengthSizeOfTrafNum - 1) & 0x3) << 4);
+        temp = temp | (((lengthSizeOfTrunNum - 1) & 0x3) << 2);
+        temp = temp | ((lengthSizeOfSampleNum - 1) & 0x3);
+        IsoTypeWriter.writeUInt32(byteBuffer, temp);
+        IsoTypeWriter.writeUInt32(byteBuffer, entries.size());
+
+        for (Entry entry : entries) {
+            if (getVersion() == 1) {
+                IsoTypeWriter.writeUInt64(byteBuffer, entry.time);
+                IsoTypeWriter.writeUInt64(byteBuffer, entry.moofOffset);
+            } else {
+                IsoTypeWriter.writeUInt32(byteBuffer, entry.time);
+                IsoTypeWriter.writeUInt32(byteBuffer, entry.moofOffset);
+            }
+            IsoTypeWriterVariable.write(entry.trafNumber, byteBuffer, lengthSizeOfTrafNum);
+            IsoTypeWriterVariable.write(entry.trunNumber, byteBuffer, lengthSizeOfTrunNum);
+            IsoTypeWriterVariable.write(entry.sampleNumber, byteBuffer, lengthSizeOfSampleNum);
+
+        }
+    }
+
+
+    public void setTrackId(long trackId) {
+        this.trackId = trackId;
+    }
+
+    public void setLengthSizeOfTrafNum(int lengthSizeOfTrafNum) {
+        this.lengthSizeOfTrafNum = lengthSizeOfTrafNum;
+    }
+
+    public void setLengthSizeOfTrunNum(int lengthSizeOfTrunNum) {
+        this.lengthSizeOfTrunNum = lengthSizeOfTrunNum;
+    }
+
+    public void setLengthSizeOfSampleNum(int lengthSizeOfSampleNum) {
+        this.lengthSizeOfSampleNum = lengthSizeOfSampleNum;
+    }
+
+    public long getTrackId() {
+        return trackId;
+    }
+
+    public int getReserved() {
+        return reserved;
+    }
+
+    public int getLengthSizeOfTrafNum() {
+        return lengthSizeOfTrafNum;
+    }
+
+    public int getLengthSizeOfTrunNum() {
+        return lengthSizeOfTrunNum;
+    }
+
+    public int getLengthSizeOfSampleNum() {
+        return lengthSizeOfSampleNum;
+    }
+
+    public long getNumberOfEntries() {
+        return entries.size();
+    }
+
+    public List<Entry> getEntries() {
+        return Collections.unmodifiableList(entries);
+    }
+
+    public void setEntries(List<Entry> entries) {
+        this.entries = entries;
+    }
+
+    public static class Entry {
+        private long time;
+        private long moofOffset;
+        private long trafNumber;
+        private long trunNumber;
+        private long sampleNumber;
+
+        public Entry() {
+        }
+
+        public Entry(long time, long moofOffset, long trafNumber, long trunNumber, long sampleNumber) {
+            this.moofOffset = moofOffset;
+            this.sampleNumber = sampleNumber;
+            this.time = time;
+            this.trafNumber = trafNumber;
+            this.trunNumber = trunNumber;
+        }
+
+        public long getTime() {
+            return time;
+        }
+
+        public long getMoofOffset() {
+            return moofOffset;
+        }
+
+        public long getTrafNumber() {
+            return trafNumber;
+        }
+
+        public long getTrunNumber() {
+            return trunNumber;
+        }
+
+        public long getSampleNumber() {
+            return sampleNumber;
+        }
+
+        public void setTime(long time) {
+            this.time = time;
+        }
+
+        public void setMoofOffset(long moofOffset) {
+            this.moofOffset = moofOffset;
+        }
+
+        public void setTrafNumber(long trafNumber) {
+            this.trafNumber = trafNumber;
+        }
+
+        public void setTrunNumber(long trunNumber) {
+            this.trunNumber = trunNumber;
+        }
+
+        public void setSampleNumber(long sampleNumber) {
+            this.sampleNumber = sampleNumber;
+        }
+
+        @Override
+        public String toString() {
+            return "Entry{" +
+                    "time=" + time +
+                    ", moofOffset=" + moofOffset +
+                    ", trafNumber=" + trafNumber +
+                    ", trunNumber=" + trunNumber +
+                    ", sampleNumber=" + sampleNumber +
+                    '}';
+        }
+
+        @Override
+        public boolean equals(Object o) {
+            if (this == o) return true;
+            if (o == null || getClass() != o.getClass()) return false;
+
+            Entry entry = (Entry) o;
+
+            if (moofOffset != entry.moofOffset) return false;
+            if (sampleNumber != entry.sampleNumber) return false;
+            if (time != entry.time) return false;
+            if (trafNumber != entry.trafNumber) return false;
+            if (trunNumber != entry.trunNumber) return false;
+
+            return true;
+        }
+
+        @Override
+        public int hashCode() {
+            int result = (int) (time ^ (time >>> 32));
+            result = 31 * result + (int) (moofOffset ^ (moofOffset >>> 32));
+            result = 31 * result + (int) (trafNumber ^ (trafNumber >>> 32));
+            result = 31 * result + (int) (trunNumber ^ (trunNumber >>> 32));
+            result = 31 * result + (int) (sampleNumber ^ (sampleNumber >>> 32));
+            return result;
+        }
+    }
+
+    @Override
+    public String toString() {
+        return "TrackFragmentRandomAccessBox{" +
+                "trackId=" + trackId +
+                ", entries=" + entries +
+                '}';
+    }
+}
diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/fragment/.svn/text-base/TrackRunBox.java.svn-base b/isoparser/src/main/java/com/coremedia/iso/boxes/fragment/.svn/text-base/TrackRunBox.java.svn-base
new file mode 100644
index 0000000..fc4faac
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/fragment/.svn/text-base/TrackRunBox.java.svn-base
@@ -0,0 +1,355 @@
+/*
+ * Copyright 2009 castLabs GmbH, Berlin
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.coremedia.iso.boxes.fragment;
+
+import com.coremedia.iso.IsoTypeReader;
+import com.coremedia.iso.IsoTypeWriter;
+import com.coremedia.iso.boxes.MovieBox;
+import com.googlecode.mp4parser.AbstractFullBox;
+
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
+import java.util.List;
+
+import static com.googlecode.mp4parser.util.CastUtils.l2i;
+
+/**
+ * aligned(8) class TrackRunBox
+ * extends FullBox('trun', 0, tr_flags) {
+ * unsigned int(32) sample_count;
+ * // the following are optional fields
+ * signed int(32) data_offset;
+ * unsigned int(32) first_sample_flags;
+ * // all fields in the following array are optional
+ * {
+ * unsigned int(32) sample_duration;
+ * unsigned int(32) sample_size;
+ * unsigned int(32) sample_flags
+ * unsigned int(32) sample_composition_time_offset;
+ * }[ sample_count ]
+ * }
+ */
+
+public class TrackRunBox extends AbstractFullBox {
+    public static final String TYPE = "trun";
+    private int dataOffset;
+    private SampleFlags firstSampleFlags;
+    private List<Entry> entries = new ArrayList<Entry>();
+
+
+    public List<Entry> getEntries() {
+        return entries;
+    }
+
+    public static class Entry {
+        private long sampleDuration;
+        private long sampleSize;
+        private SampleFlags sampleFlags;
+        private int sampleCompositionTimeOffset;
+
+        public Entry() {
+        }
+
+        public Entry(long sampleDuration, long sampleSize, SampleFlags sampleFlags, int sampleCompositionTimeOffset) {
+            this.sampleDuration = sampleDuration;
+            this.sampleSize = sampleSize;
+            this.sampleFlags = sampleFlags;
+            this.sampleCompositionTimeOffset = sampleCompositionTimeOffset;
+        }
+
+        public long getSampleDuration() {
+            return sampleDuration;
+        }
+
+        public long getSampleSize() {
+            return sampleSize;
+        }
+
+        public SampleFlags getSampleFlags() {
+            return sampleFlags;
+        }
+
+        public int getSampleCompositionTimeOffset() {
+            return sampleCompositionTimeOffset;
+        }
+
+        public void setSampleDuration(long sampleDuration) {
+            this.sampleDuration = sampleDuration;
+        }
+
+        public void setSampleSize(long sampleSize) {
+            this.sampleSize = sampleSize;
+        }
+
+        public void setSampleFlags(SampleFlags sampleFlags) {
+            this.sampleFlags = sampleFlags;
+        }
+
+        public void setSampleCompositionTimeOffset(int sampleCompositionTimeOffset) {
+            this.sampleCompositionTimeOffset = sampleCompositionTimeOffset;
+        }
+
+        @Override
+        public String toString() {
+            return "Entry{" +
+                    "sampleDuration=" + sampleDuration +
+                    ", sampleSize=" + sampleSize +
+                    ", sampleFlags=" + sampleFlags +
+                    ", sampleCompositionTimeOffset=" + sampleCompositionTimeOffset +
+                    '}';
+        }
+    }
+
+    public void setDataOffset(int dataOffset) {
+        if (dataOffset == -1) {
+            setFlags(getFlags() & (0xFFFFFF ^ 1));
+        } else {
+            setFlags(getFlags() | 0x1); // turn on dataoffset
+        }
+        this.dataOffset = dataOffset;
+    }
+
+    public long[] getSampleCompositionTimeOffsets() {
+        if (isSampleCompositionTimeOffsetPresent()) {
+            long[] result = new long[entries.size()];
+
+            for (int i = 0; i < result.length; i++) {
+                result[i] = entries.get(i).getSampleCompositionTimeOffset();
+            }
+            return result;
+        }
+        return null;
+    }
+
+    public TrackExtendsBox getTrackExtendsBox() {
+        final TrackFragmentHeaderBox tfhd = ((TrackFragmentBox) getParent()).getTrackFragmentHeaderBox();
+        final List<MovieBox> movieBoxes = tfhd.getIsoFile().getBoxes(MovieBox.class);
+        if (movieBoxes.size() == 0) {
+            return null;
+        }
+
+        final List<TrackExtendsBox> trexBoxes = movieBoxes.get(0).getBoxes(TrackExtendsBox.class, true);
+        TrackExtendsBox trex = null;
+        for (TrackExtendsBox aTrex : trexBoxes) {
+            if (aTrex.getTrackId() == tfhd.getTrackId()) {
+                trex = aTrex;
+            }
+        }
+        return trex;
+    }
+
+    public TrackRunBox() {
+        super(TYPE);
+    }
+
+    protected long getContentSize() {
+        long size = 8;
+        int flags = getFlags();
+
+        if ((flags & 0x1) == 0x1) { //dataOffsetPresent
+            size += 4;
+        }
+        if ((flags & 0x4) == 0x4) { //firstSampleFlagsPresent
+            size += 4;
+        }
+
+        long entrySize = 0;
+        if ((flags & 0x100) == 0x100) { //sampleDurationPresent
+            entrySize += 4;
+        }
+        if ((flags & 0x200) == 0x200) { //sampleSizePresent
+            entrySize += 4;
+        }
+        if ((flags & 0x400) == 0x400) { //sampleFlagsPresent
+            entrySize += 4;
+        }
+        if ((flags & 0x800) == 0x800) { //sampleCompositionTimeOffsetPresent
+            entrySize += 4;
+        }
+        size += entrySize * entries.size();
+        return size;
+    }
+
+    protected void getContent(ByteBuffer byteBuffer) {
+        writeVersionAndFlags(byteBuffer);
+        IsoTypeWriter.writeUInt32(byteBuffer, entries.size());
+        int flags = getFlags();
+
+        if ((flags & 0x1) == 1) { //dataOffsetPresent
+            IsoTypeWriter.writeUInt32(byteBuffer, dataOffset);
+        }
+        if ((flags & 0x4) == 0x4) { //firstSampleFlagsPresent
+            firstSampleFlags.getContent(byteBuffer);
+        }
+
+        for (Entry entry : entries) {
+            if ((flags & 0x100) == 0x100) { //sampleDurationPresent
+                IsoTypeWriter.writeUInt32(byteBuffer, entry.sampleDuration);
+            }
+            if ((flags & 0x200) == 0x200) { //sampleSizePresent
+                IsoTypeWriter.writeUInt32(byteBuffer, entry.sampleSize);
+            }
+            if ((flags & 0x400) == 0x400) { //sampleFlagsPresent
+                entry.sampleFlags.getContent(byteBuffer);
+            }
+            if ((flags & 0x800) == 0x800) { //sampleCompositionTimeOffsetPresent
+                byteBuffer.putInt(entry.sampleCompositionTimeOffset);
+            }
+        }
+    }
+
+    @Override
+    public void _parseDetails(ByteBuffer content) {
+        parseVersionAndFlags(content);
+        long sampleCount = IsoTypeReader.readUInt32(content);
+
+        if ((getFlags() & 0x1) == 1) { //dataOffsetPresent
+            dataOffset = l2i(IsoTypeReader.readUInt32(content));
+        } else {
+            dataOffset = -1;
+        }
+        if ((getFlags() & 0x4) == 0x4) { //firstSampleFlagsPresent
+            firstSampleFlags = new SampleFlags(content);
+        }
+
+        for (int i = 0; i < sampleCount; i++) {
+            Entry entry = new Entry();
+            if ((getFlags() & 0x100) == 0x100) { //sampleDurationPresent
+                entry.sampleDuration = IsoTypeReader.readUInt32(content);
+            }
+            if ((getFlags() & 0x200) == 0x200) { //sampleSizePresent
+                entry.sampleSize = IsoTypeReader.readUInt32(content);
+            }
+            if ((getFlags() & 0x400) == 0x400) { //sampleFlagsPresent
+                entry.sampleFlags = new SampleFlags(content);
+            }
+            if ((getFlags() & 0x800) == 0x800) { //sampleCompositionTimeOffsetPresent
+                entry.sampleCompositionTimeOffset = content.getInt();
+            }
+            entries.add(entry);
+        }
+
+    }
+
+    public long getSampleCount() {
+        return entries.size();
+    }
+
+    public boolean isDataOffsetPresent() {
+        return (getFlags() & 0x1) == 1;
+    }
+
+    public boolean isFirstSampleFlagsPresent() {
+        return (getFlags() & 0x4) == 0x4;
+    }
+
+
+    public boolean isSampleSizePresent() {
+        return (getFlags() & 0x200) == 0x200;
+    }
+
+    public boolean isSampleDurationPresent() {
+        return (getFlags() & 0x100) == 0x100;
+    }
+
+    public boolean isSampleFlagsPresent() {
+        return (getFlags() & 0x400) == 0x400;
+    }
+
+    public boolean isSampleCompositionTimeOffsetPresent() {
+        return (getFlags() & 0x800) == 0x800;
+    }
+
+    public void setDataOffsetPresent(boolean v) {
+        if (v) {
+            setFlags(getFlags() | 0x01);
+        } else {
+            setFlags(getFlags() & (0xFFFFFF ^ 0x1));
+        }
+    }
+
+    public void setSampleSizePresent(boolean v) {
+        if (v) {
+            setFlags(getFlags() | 0x200);
+        } else {
+            setFlags(getFlags() & (0xFFFFFF ^ 0x200));
+        }
+    }
+
+    public void setSampleDurationPresent(boolean v) {
+
+        if (v) {
+            setFlags(getFlags() | 0x100);
+        } else {
+            setFlags(getFlags() & (0xFFFFFF ^ 0x100));
+        }
+    }
+
+    public void setSampleFlagsPresent(boolean v) {
+        if (v) {
+            setFlags(getFlags() | 0x400);
+        } else {
+            setFlags(getFlags() & (0xFFFFFF ^ 0x400));
+        }
+    }
+
+    public void setSampleCompositionTimeOffsetPresent(boolean v) {
+        if (v) {
+            setFlags(getFlags() | 0x800);
+        } else {
+            setFlags(getFlags() & (0xFFFFFF ^ 0x800));
+        }
+
+    }
+
+    public int getDataOffset() {
+        return dataOffset;
+    }
+
+    public SampleFlags getFirstSampleFlags() {
+        return firstSampleFlags;
+    }
+
+    public void setFirstSampleFlags(SampleFlags firstSampleFlags) {
+        if (firstSampleFlags == null) {
+            setFlags(getFlags() & (0xFFFFFF ^ 0x4));
+        } else {
+            setFlags(getFlags() | 0x4);
+        }
+        this.firstSampleFlags = firstSampleFlags;
+    }
+
+    @Override
+    public String toString() {
+        final StringBuilder sb = new StringBuilder();
+        sb.append("TrackRunBox");
+        sb.append("{sampleCount=").append(entries.size());
+        sb.append(", dataOffset=").append(dataOffset);
+        sb.append(", dataOffsetPresent=").append(isDataOffsetPresent());
+        sb.append(", sampleSizePresent=").append(isSampleSizePresent());
+        sb.append(", sampleDurationPresent=").append(isSampleDurationPresent());
+        sb.append(", sampleFlagsPresentPresent=").append(isSampleFlagsPresent());
+        sb.append(", sampleCompositionTimeOffsetPresent=").append(isSampleCompositionTimeOffsetPresent());
+        sb.append(", firstSampleFlags=").append(firstSampleFlags);
+        sb.append('}');
+        return sb.toString();
+    }
+
+    public void setEntries(List<Entry> entries) {
+        this.entries = entries;
+    }
+}
diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/fragment/MovieExtendsBox.java b/isoparser/src/main/java/com/coremedia/iso/boxes/fragment/MovieExtendsBox.java
new file mode 100644
index 0000000..5ecd642
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/fragment/MovieExtendsBox.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright 2009 castLabs GmbH, Berlin
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.coremedia.iso.boxes.fragment;
+
+import com.googlecode.mp4parser.AbstractContainerBox;
+
+/**
+ * aligned(8) class MovieExtendsBox extends Box('mvex'){
+ * }
+ */
+public class MovieExtendsBox extends AbstractContainerBox {
+    public static final String TYPE = "mvex";
+
+    public MovieExtendsBox() {
+        super(TYPE);
+    }
+}
diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/fragment/MovieExtendsHeaderBox.java b/isoparser/src/main/java/com/coremedia/iso/boxes/fragment/MovieExtendsHeaderBox.java
new file mode 100644
index 0000000..8dd58f9
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/fragment/MovieExtendsHeaderBox.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright 2009 castLabs GmbH, Berlin
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.coremedia.iso.boxes.fragment;
+
+import com.coremedia.iso.IsoTypeReader;
+import com.coremedia.iso.IsoTypeWriter;
+import com.googlecode.mp4parser.AbstractFullBox;
+
+import java.nio.ByteBuffer;
+
+/**
+ * aligned(8) class MovieExtendsHeaderBox extends FullBox('mehd', version, 0) {
+ * if (version==1) {
+ * unsigned int(64) fragment_duration;
+ * } else { // version==0
+ * unsigned int(32) fragment_duration;
+ * }
+ * }
+ */
+public class MovieExtendsHeaderBox extends AbstractFullBox {
+    public static final String TYPE = "mehd";
+    private long fragmentDuration;
+
+    public MovieExtendsHeaderBox() {
+        super(TYPE);
+    }
+
+    @Override
+    protected long getContentSize() {
+        return getVersion() == 1 ? 12 : 8;
+    }
+
+    @Override
+    public void _parseDetails(ByteBuffer content) {
+        parseVersionAndFlags(content);
+        fragmentDuration = getVersion() == 1 ? IsoTypeReader.readUInt64(content) : IsoTypeReader.readUInt32(content);
+    }
+
+
+    @Override
+    protected void getContent(ByteBuffer byteBuffer) {
+        writeVersionAndFlags(byteBuffer);
+        if (getVersion() == 1) {
+            IsoTypeWriter.writeUInt64(byteBuffer, fragmentDuration);
+        } else {
+            IsoTypeWriter.writeUInt32(byteBuffer, fragmentDuration);
+        }
+    }
+
+    public long getFragmentDuration() {
+        return fragmentDuration;
+    }
+
+    public void setFragmentDuration(long fragmentDuration) {
+        this.fragmentDuration = fragmentDuration;
+    }
+}
diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/fragment/MovieFragmentBox.java b/isoparser/src/main/java/com/coremedia/iso/boxes/fragment/MovieFragmentBox.java
new file mode 100644
index 0000000..e92bd53
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/fragment/MovieFragmentBox.java
@@ -0,0 +1,100 @@
+/*
+ * Copyright 2009 castLabs GmbH, Berlin
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.coremedia.iso.boxes.fragment;
+
+import com.googlecode.mp4parser.AbstractContainerBox;
+import com.coremedia.iso.boxes.Box;
+import com.coremedia.iso.boxes.SampleDependencyTypeBox;
+import com.googlecode.mp4parser.annotations.DoNotParseDetail;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * aligned(8) class MovieFragmentBox extends Box(moof){
+ * }
+ */
+
+public class MovieFragmentBox extends AbstractContainerBox {
+    public static final String TYPE = "moof";
+
+    public MovieFragmentBox() {
+        super(TYPE);
+    }
+
+
+    public List<Long> getSyncSamples(SampleDependencyTypeBox sdtp) {
+        List<Long> result = new ArrayList<Long>();
+
+        final List<SampleDependencyTypeBox.Entry> sampleEntries = sdtp.getEntries();
+        long i = 1;
+        for (SampleDependencyTypeBox.Entry sampleEntry : sampleEntries) {
+            if (sampleEntry.getSampleDependsOn() == 2) {
+                result.add(i);
+            }
+            i++;
+        }
+
+        return result;
+    }
+
+    @DoNotParseDetail
+    public long getOffset() {
+        Box b = this;
+        long offset = 0;
+        while (b.getParent() != null) {
+            for (Box box : b.getParent().getBoxes()) {
+                if (b == box) {
+                    break;
+                }
+                offset += box.getSize();
+            }
+            b = b.getParent();
+        }
+        return offset;
+    }
+
+
+    public int getTrackCount() {
+        return getBoxes(TrackFragmentBox.class, false).size();
+    }
+
+    /**
+     * Returns the track numbers associated with this <code>MovieBox</code>.
+     *
+     * @return the tracknumbers (IDs) of the tracks in their order of appearance in the file
+     */
+
+    public long[] getTrackNumbers() {
+
+        List<TrackFragmentBox> trackBoxes = this.getBoxes(TrackFragmentBox.class, false);
+        long[] trackNumbers = new long[trackBoxes.size()];
+        for (int trackCounter = 0; trackCounter < trackBoxes.size(); trackCounter++) {
+            TrackFragmentBox trackBoxe = trackBoxes.get(trackCounter);
+            trackNumbers[trackCounter] = trackBoxe.getTrackFragmentHeaderBox().getTrackId();
+        }
+        return trackNumbers;
+    }
+
+    public List<TrackFragmentHeaderBox> getTrackFragmentHeaderBoxes() {
+        return getBoxes(TrackFragmentHeaderBox.class, true);
+    }
+
+    public List<TrackRunBox> getTrackRunBoxes() {
+        return getBoxes(TrackRunBox.class, true);
+    }
+}
diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/fragment/MovieFragmentHeaderBox.java b/isoparser/src/main/java/com/coremedia/iso/boxes/fragment/MovieFragmentHeaderBox.java
new file mode 100644
index 0000000..e58f7a2
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/fragment/MovieFragmentHeaderBox.java
@@ -0,0 +1,72 @@
+/*
+ * Copyright 2009 castLabs GmbH, Berlin
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.coremedia.iso.boxes.fragment;
+
+import com.coremedia.iso.IsoTypeReader;
+import com.coremedia.iso.IsoTypeWriter;
+import com.googlecode.mp4parser.AbstractFullBox;
+
+import java.nio.ByteBuffer;
+
+/**
+ * aligned(8) class MovieFragmentHeaderBox
+ * extends FullBox('mfhd', 0, 0){
+ * unsigned int(32) sequence_number;
+ * }
+ */
+
+public class MovieFragmentHeaderBox extends AbstractFullBox {
+    public static final String TYPE = "mfhd";
+    private long sequenceNumber;
+
+    public MovieFragmentHeaderBox() {
+        super(TYPE);
+    }
+
+    protected long getContentSize() {
+        return 8;
+    }
+
+    @Override
+    protected void getContent(ByteBuffer byteBuffer) {
+        writeVersionAndFlags(byteBuffer);
+        IsoTypeWriter.writeUInt32(byteBuffer, sequenceNumber);
+    }
+
+
+    @Override
+    public void _parseDetails(ByteBuffer content) {
+        parseVersionAndFlags(content);
+        sequenceNumber = IsoTypeReader.readUInt32(content);
+
+    }
+
+    public long getSequenceNumber() {
+        return sequenceNumber;
+    }
+
+    public void setSequenceNumber(long sequenceNumber) {
+        this.sequenceNumber = sequenceNumber;
+    }
+
+    @Override
+    public String toString() {
+        return "MovieFragmentHeaderBox{" +
+                "sequenceNumber=" + sequenceNumber +
+                '}';
+    }
+}
diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/fragment/MovieFragmentRandomAccessBox.java b/isoparser/src/main/java/com/coremedia/iso/boxes/fragment/MovieFragmentRandomAccessBox.java
new file mode 100644
index 0000000..86e2c9d
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/fragment/MovieFragmentRandomAccessBox.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright 2009 castLabs GmbH, Berlin
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.coremedia.iso.boxes.fragment;
+
+import com.googlecode.mp4parser.AbstractContainerBox;
+
+/**
+ * aligned(8) class MovieFragmentRandomAccessBox
+ * extends Box('mfra')
+ * {
+ * }
+ */
+public class MovieFragmentRandomAccessBox extends AbstractContainerBox {
+    public static final String TYPE = "mfra";
+
+    public MovieFragmentRandomAccessBox() {
+        super(TYPE);
+    }
+
+}
diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/fragment/MovieFragmentRandomAccessOffsetBox.java b/isoparser/src/main/java/com/coremedia/iso/boxes/fragment/MovieFragmentRandomAccessOffsetBox.java
new file mode 100644
index 0000000..edbfd66
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/fragment/MovieFragmentRandomAccessOffsetBox.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright 2009 castLabs GmbH, Berlin
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.coremedia.iso.boxes.fragment;
+
+import com.coremedia.iso.IsoTypeReader;
+import com.coremedia.iso.IsoTypeWriter;
+import com.googlecode.mp4parser.AbstractFullBox;
+
+import java.nio.ByteBuffer;
+
+/**
+ * aligned(8) class MovieFragmentRandomAccessOffsetBox
+ * extends FullBox('mfro', version, 0) {
+ * unsigned int(32) size;
+ * }
+ */
+public class MovieFragmentRandomAccessOffsetBox extends AbstractFullBox {
+    public static final String TYPE = "mfro";
+    private long mfraSize;
+
+    public MovieFragmentRandomAccessOffsetBox() {
+        super(TYPE);
+    }
+
+    protected long getContentSize() {
+        return 8;
+    }
+
+    @Override
+    public void _parseDetails(ByteBuffer content) {
+        parseVersionAndFlags(content);
+        mfraSize = IsoTypeReader.readUInt32(content);
+    }
+
+    @Override
+    protected void getContent(ByteBuffer byteBuffer) {
+        writeVersionAndFlags(byteBuffer);
+        IsoTypeWriter.writeUInt32(byteBuffer, mfraSize);
+    }
+
+    public long getMfraSize() {
+        return mfraSize;
+    }
+
+    public void setMfraSize(long mfraSize) {
+        this.mfraSize = mfraSize;
+    }
+}
diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/fragment/SampleFlags.java b/isoparser/src/main/java/com/coremedia/iso/boxes/fragment/SampleFlags.java
new file mode 100644
index 0000000..6caaf1e
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/fragment/SampleFlags.java
@@ -0,0 +1,207 @@
+/*
+ * Copyright 2009 castLabs GmbH, Berlin
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.coremedia.iso.boxes.fragment;
+
+import com.googlecode.mp4parser.boxes.mp4.objectdescriptors.BitReaderBuffer;
+import com.googlecode.mp4parser.boxes.mp4.objectdescriptors.BitWriterBuffer;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+
+/**
+ * bit(6) reserved=0;
+ * unsigned int(2) sample_depends_on;
+ * unsigned int(2) sample_is_depended_on;
+ * unsigned int(2) sample_has_redundancy;
+ * bit(3) sample_padding_value;
+ * bit(1) sample_is_difference_sample;
+ * // i.e. when 1 signals a non-key or non-sync sample
+ * unsigned int(16) sample_degradation_priority;
+ */
+public class SampleFlags {
+    private int reserved;
+    private int sampleDependsOn;
+    private int sampleIsDependedOn;
+    private int sampleHasRedundancy;
+    private int samplePaddingValue;
+    private boolean sampleIsDifferenceSample;
+    private int sampleDegradationPriority;
+
+    public SampleFlags() {
+
+    }
+
+    public SampleFlags(ByteBuffer bb) {
+        BitReaderBuffer brb = new BitReaderBuffer(bb);
+        reserved = brb.readBits(6);
+        sampleDependsOn = brb.readBits(2);
+        sampleIsDependedOn = brb.readBits(2);
+        sampleHasRedundancy = brb.readBits(2);
+        samplePaddingValue = brb.readBits(3);
+        sampleIsDifferenceSample = brb.readBits(1) == 1;
+        sampleDegradationPriority = brb.readBits(16);
+    }
+
+
+    public void getContent(ByteBuffer os) {
+        BitWriterBuffer bitWriterBuffer = new BitWriterBuffer(os);
+        bitWriterBuffer.writeBits(reserved, 6);
+        bitWriterBuffer.writeBits(sampleDependsOn, 2);
+        bitWriterBuffer.writeBits(sampleIsDependedOn, 2);
+        bitWriterBuffer.writeBits(sampleHasRedundancy, 2);
+        bitWriterBuffer.writeBits(samplePaddingValue, 3);
+        bitWriterBuffer.writeBits(this.sampleIsDifferenceSample ? 1 : 0, 1);
+        bitWriterBuffer.writeBits(sampleDegradationPriority, 16);
+    }
+
+    public int getReserved() {
+        return reserved;
+    }
+
+    public void setReserved(int reserved) {
+        this.reserved = reserved;
+    }
+
+    /**
+     * @see #setSampleDependsOn(int)
+     */
+    public int getSampleDependsOn() {
+        return sampleDependsOn;
+    }
+
+    /**
+     * sample_depends_on takes one of the following four values:
+     * <pre>
+     * 0: the dependency of this sample is unknown;
+     * 1: this sample does depend on others (not an I picture);
+     * 2: this sample does not depend on others (I picture);
+     * 3: reserved
+     * </pre>
+     *
+     */
+    public void setSampleDependsOn(int sampleDependsOn) {
+        this.sampleDependsOn = sampleDependsOn;
+    }
+
+    /**
+     * @see #setSampleIsDependedOn(int)
+     */
+    public int getSampleIsDependedOn() {
+        return sampleIsDependedOn;
+    }
+
+    /**
+     * sample_is_depended_on takes one of the following four values:
+     * <pre>
+     * 0: the dependency of other samples on this sample is unknown;
+     * 1: other samples may depend on this one (not disposable);
+     * 2: no other sample depends on this one (disposable);
+     * 3: reserved
+     * </pre>
+     *
+     */
+    public void setSampleIsDependedOn(int sampleIsDependedOn) {
+        this.sampleIsDependedOn = sampleIsDependedOn;
+    }
+
+    /**
+     * @see #setSampleHasRedundancy(int)
+     */
+    public int getSampleHasRedundancy() {
+        return sampleHasRedundancy;
+    }
+
+    /**
+     * sample_has_redundancy takes one of the following four values:
+     * <pre>
+     * 0: it is unknown whether there is redundant coding in this sample;
+     * 1: there is redundant coding in this sample;
+     * 2: there is no redundant coding in this sample;
+     * 3: reserved
+     * </pre>
+     */
+    public void setSampleHasRedundancy(int sampleHasRedundancy) {
+        this.sampleHasRedundancy = sampleHasRedundancy;
+    }
+
+    public int getSamplePaddingValue() {
+        return samplePaddingValue;
+    }
+
+    public void setSamplePaddingValue(int samplePaddingValue) {
+        this.samplePaddingValue = samplePaddingValue;
+    }
+
+    public boolean isSampleIsDifferenceSample() {
+        return sampleIsDifferenceSample;
+    }
+
+
+    public void setSampleIsDifferenceSample(boolean sampleIsDifferenceSample) {
+        this.sampleIsDifferenceSample = sampleIsDifferenceSample;
+    }
+
+    public int getSampleDegradationPriority() {
+        return sampleDegradationPriority;
+    }
+
+    public void setSampleDegradationPriority(int sampleDegradationPriority) {
+        this.sampleDegradationPriority = sampleDegradationPriority;
+    }
+
+    @Override
+    public String toString() {
+        return "SampleFlags{" +
+                "reserved=" + reserved +
+                ", sampleDependsOn=" + sampleDependsOn +
+                ", sampleHasRedundancy=" + sampleHasRedundancy +
+                ", samplePaddingValue=" + samplePaddingValue +
+                ", sampleIsDifferenceSample=" + sampleIsDifferenceSample +
+                ", sampleDegradationPriority=" + sampleDegradationPriority +
+                '}';
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (o == null || getClass() != o.getClass()) return false;
+
+        SampleFlags that = (SampleFlags) o;
+
+        if (reserved != that.reserved) return false;
+        if (sampleDegradationPriority != that.sampleDegradationPriority) return false;
+        if (sampleDependsOn != that.sampleDependsOn) return false;
+        if (sampleHasRedundancy != that.sampleHasRedundancy) return false;
+        if (sampleIsDependedOn != that.sampleIsDependedOn) return false;
+        if (sampleIsDifferenceSample != that.sampleIsDifferenceSample) return false;
+        if (samplePaddingValue != that.samplePaddingValue) return false;
+
+        return true;
+    }
+
+    @Override
+    public int hashCode() {
+        int result = reserved;
+        result = 31 * result + sampleDependsOn;
+        result = 31 * result + sampleIsDependedOn;
+        result = 31 * result + sampleHasRedundancy;
+        result = 31 * result + samplePaddingValue;
+        result = 31 * result + (sampleIsDifferenceSample ? 1 : 0);
+        result = 31 * result + sampleDegradationPriority;
+        return result;
+    }
+}
diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/fragment/SegmentTypeBox.java b/isoparser/src/main/java/com/coremedia/iso/boxes/fragment/SegmentTypeBox.java
new file mode 100644
index 0000000..5e0d47b
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/fragment/SegmentTypeBox.java
@@ -0,0 +1,143 @@
+/*
+ * Copyright 2008 CoreMedia AG, Hamburg
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.coremedia.iso.boxes.fragment;
+
+import com.coremedia.iso.IsoFile;
+import com.coremedia.iso.IsoTypeReader;
+import com.coremedia.iso.IsoTypeWriter;
+import com.googlecode.mp4parser.AbstractBox;
+import com.googlecode.mp4parser.annotations.DoNotParseDetail;
+
+import java.nio.ByteBuffer;
+import java.util.Collections;
+import java.util.LinkedList;
+import java.util.List;
+
+/**
+ * This box identifies the specifications to which this file complies. <br>
+ * Each brand is a printable four-character code, registered with ISO, that
+ * identifies a precise specification.
+ */
+public class SegmentTypeBox extends AbstractBox {
+    public static final String TYPE = "styp";
+
+    private String majorBrand;
+    private long minorVersion;
+    private List<String> compatibleBrands = Collections.emptyList();
+
+    public SegmentTypeBox() {
+        super(TYPE);
+    }
+
+    public SegmentTypeBox(String majorBrand, long minorVersion, List<String> compatibleBrands) {
+        super(TYPE);
+        this.majorBrand = majorBrand;
+        this.minorVersion = minorVersion;
+        this.compatibleBrands = compatibleBrands;
+    }
+
+    protected long getContentSize() {
+        return 8 + compatibleBrands.size() * 4;
+
+    }
+
+    @Override
+    public void _parseDetails(ByteBuffer content) {
+        majorBrand = IsoTypeReader.read4cc(content);
+        minorVersion = IsoTypeReader.readUInt32(content);
+        int compatibleBrandsCount = content.remaining() / 4;
+        compatibleBrands = new LinkedList<String>();
+        for (int i = 0; i < compatibleBrandsCount; i++) {
+            compatibleBrands.add(IsoTypeReader.read4cc(content));
+        }
+    }
+
+    @Override
+    protected void getContent(ByteBuffer byteBuffer) {
+        byteBuffer.put(IsoFile.fourCCtoBytes(majorBrand));
+        IsoTypeWriter.writeUInt32(byteBuffer, minorVersion);
+        for (String compatibleBrand : compatibleBrands) {
+            byteBuffer.put(IsoFile.fourCCtoBytes(compatibleBrand));
+        }
+
+    }
+
+    /**
+     * Gets the brand identifier.
+     *
+     * @return the brand identifier
+     */
+    public String getMajorBrand() {
+        return majorBrand;
+    }
+
+    /**
+     * Sets the major brand of the file used to determine an appropriate reader.
+     *
+     * @param majorBrand the new major brand
+     */
+    public void setMajorBrand(String majorBrand) {
+        this.majorBrand = majorBrand;
+    }
+
+    /**
+     * Sets the "informative integer for the minor version of the major brand".
+     *
+     * @param minorVersion the version number of the major brand
+     */
+    public void setMinorVersion(int minorVersion) {
+        this.minorVersion = minorVersion;
+    }
+
+    /**
+     * Gets an informative integer for the minor version of the major brand.
+     *
+     * @return an informative integer
+     * @see SegmentTypeBox#getMajorBrand()
+     */
+    public long getMinorVersion() {
+        return minorVersion;
+    }
+
+    /**
+     * Gets an array of 4-cc brands.
+     *
+     * @return the compatible brands
+     */
+    public List<String> getCompatibleBrands() {
+        return compatibleBrands;
+    }
+
+    public void setCompatibleBrands(List<String> compatibleBrands) {
+        this.compatibleBrands = compatibleBrands;
+    }
+
+    @DoNotParseDetail
+    public String toString() {
+        StringBuilder result = new StringBuilder();
+        result.append("SegmentTypeBox[");
+        result.append("majorBrand=").append(getMajorBrand());
+        result.append(";");
+        result.append("minorVersion=").append(getMinorVersion());
+        for (String compatibleBrand : compatibleBrands) {
+            result.append(";");
+            result.append("compatibleBrand=").append(compatibleBrand);
+        }
+        result.append("]");
+        return result.toString();
+    }
+}
diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/fragment/TrackExtendsBox.java b/isoparser/src/main/java/com/coremedia/iso/boxes/fragment/TrackExtendsBox.java
new file mode 100644
index 0000000..8bba7c1
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/fragment/TrackExtendsBox.java
@@ -0,0 +1,115 @@
+/*
+ * Copyright 2009 castLabs GmbH, Berlin
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.coremedia.iso.boxes.fragment;
+
+import com.coremedia.iso.IsoTypeReader;
+import com.coremedia.iso.IsoTypeWriter;
+import com.googlecode.mp4parser.AbstractFullBox;
+
+import java.nio.ByteBuffer;
+
+/**
+ * aligned(8) class TrackExtendsBox extends FullBox('trex', 0, 0){
+ * unsigned int(32) track_ID;
+ * unsigned int(32) default_sample_description_index;
+ * unsigned int(32) default_sample_duration;
+ * unsigned int(32) default_sample_size;
+ * unsigned int(32) default_sample_flags
+ * }
+ */
+public class TrackExtendsBox extends AbstractFullBox {
+    public static final String TYPE = "trex";
+    private long trackId;
+    private long defaultSampleDescriptionIndex;
+    private long defaultSampleDuration;
+    private long defaultSampleSize;
+    private SampleFlags defaultSampleFlags;
+
+    public TrackExtendsBox() {
+        super(TYPE);
+    }
+
+    @Override
+    protected long getContentSize() {
+        return 5 * 4 + 4;
+    }
+
+    @Override
+    protected void getContent(ByteBuffer byteBuffer) {
+        writeVersionAndFlags(byteBuffer);
+        IsoTypeWriter.writeUInt32(byteBuffer, trackId);
+        IsoTypeWriter.writeUInt32(byteBuffer, defaultSampleDescriptionIndex);
+        IsoTypeWriter.writeUInt32(byteBuffer, defaultSampleDuration);
+        IsoTypeWriter.writeUInt32(byteBuffer, defaultSampleSize);
+        defaultSampleFlags.getContent(byteBuffer);
+    }
+
+    @Override
+    public void _parseDetails(ByteBuffer content) {
+        parseVersionAndFlags(content);
+        trackId = IsoTypeReader.readUInt32(content);
+        defaultSampleDescriptionIndex = IsoTypeReader.readUInt32(content);
+        defaultSampleDuration = IsoTypeReader.readUInt32(content);
+        defaultSampleSize = IsoTypeReader.readUInt32(content);
+        defaultSampleFlags = new SampleFlags(content);
+    }
+
+    public long getTrackId() {
+        return trackId;
+    }
+
+    public long getDefaultSampleDescriptionIndex() {
+        return defaultSampleDescriptionIndex;
+    }
+
+    public long getDefaultSampleDuration() {
+        return defaultSampleDuration;
+    }
+
+    public long getDefaultSampleSize() {
+        return defaultSampleSize;
+    }
+
+    public SampleFlags getDefaultSampleFlags() {
+        return defaultSampleFlags;
+    }
+
+    public String getDefaultSampleFlagsStr() {
+        return defaultSampleFlags.toString();
+    }
+
+    public void setTrackId(long trackId) {
+        this.trackId = trackId;
+    }
+
+    public void setDefaultSampleDescriptionIndex(long defaultSampleDescriptionIndex) {
+        this.defaultSampleDescriptionIndex = defaultSampleDescriptionIndex;
+    }
+
+    public void setDefaultSampleDuration(long defaultSampleDuration) {
+        this.defaultSampleDuration = defaultSampleDuration;
+    }
+
+    public void setDefaultSampleSize(long defaultSampleSize) {
+        this.defaultSampleSize = defaultSampleSize;
+    }
+
+    public void setDefaultSampleFlags(SampleFlags defaultSampleFlags) {
+        this.defaultSampleFlags = defaultSampleFlags;
+
+    }
+}
diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/fragment/TrackFragmentBaseMediaDecodeTimeBox.java b/isoparser/src/main/java/com/coremedia/iso/boxes/fragment/TrackFragmentBaseMediaDecodeTimeBox.java
new file mode 100644
index 0000000..06fcf62
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/fragment/TrackFragmentBaseMediaDecodeTimeBox.java
@@ -0,0 +1,76 @@
+/*
+ * Copyright 2009 castLabs GmbH, Berlin
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.coremedia.iso.boxes.fragment;
+
+import com.coremedia.iso.IsoTypeReader;
+import com.coremedia.iso.IsoTypeWriter;
+import com.googlecode.mp4parser.AbstractFullBox;
+
+import java.nio.ByteBuffer;
+
+public class TrackFragmentBaseMediaDecodeTimeBox extends AbstractFullBox {
+    public static final String TYPE = "tfdt";
+
+    private long baseMediaDecodeTime;
+
+    public TrackFragmentBaseMediaDecodeTimeBox() {
+        super(TYPE);
+    }
+
+    @Override
+    protected long getContentSize() {
+        return getVersion() == 0 ? 8 : 12;
+    }
+
+    @Override
+    protected void getContent(ByteBuffer byteBuffer) {
+        writeVersionAndFlags(byteBuffer);
+        if (getVersion() == 1) {
+            IsoTypeWriter.writeUInt64(byteBuffer, baseMediaDecodeTime);
+        } else {
+            IsoTypeWriter.writeUInt32(byteBuffer, baseMediaDecodeTime);
+        }
+    }
+
+
+    @Override
+    public void _parseDetails(ByteBuffer content) {
+        parseVersionAndFlags(content);
+        if (getVersion() == 1) {
+            baseMediaDecodeTime = IsoTypeReader.readUInt64(content);
+        } else {
+            baseMediaDecodeTime = IsoTypeReader.readUInt32(content);
+        }
+
+    }
+
+
+    public long getBaseMediaDecodeTime() {
+        return baseMediaDecodeTime;
+    }
+
+    public void setBaseMediaDecodeTime(long baseMediaDecodeTime) {
+        this.baseMediaDecodeTime = baseMediaDecodeTime;
+    }
+
+    @Override
+    public String toString() {
+        return "TrackFragmentBaseMediaDecodeTimeBox{" +
+                "baseMediaDecodeTime=" + baseMediaDecodeTime +
+                '}';
+    }
+}
diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/fragment/TrackFragmentBox.java b/isoparser/src/main/java/com/coremedia/iso/boxes/fragment/TrackFragmentBox.java
new file mode 100644
index 0000000..fde7da5
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/fragment/TrackFragmentBox.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2009 castLabs GmbH, Berlin
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.coremedia.iso.boxes.fragment;
+
+import com.googlecode.mp4parser.AbstractContainerBox;
+import com.coremedia.iso.boxes.Box;
+
+/**
+ * aligned(8) class TrackFragmentBox extends Box('traf'){
+ * }
+ */
+public class TrackFragmentBox extends AbstractContainerBox {
+    public static final String TYPE = "traf";
+
+    public TrackFragmentBox() {
+        super(TYPE);
+    }
+
+
+    public TrackFragmentHeaderBox getTrackFragmentHeaderBox() {
+        for (Box box : getBoxes()) {
+            if (box instanceof TrackFragmentHeaderBox) {
+                return (TrackFragmentHeaderBox) box;
+            }
+        }
+        return null;
+    }
+
+}
diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/fragment/TrackFragmentHeaderBox.java b/isoparser/src/main/java/com/coremedia/iso/boxes/fragment/TrackFragmentHeaderBox.java
new file mode 100644
index 0000000..fb9509b
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/fragment/TrackFragmentHeaderBox.java
@@ -0,0 +1,224 @@
+/*
+ * Copyright 2009 castLabs GmbH, Berlin
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.coremedia.iso.boxes.fragment;
+
+import com.coremedia.iso.IsoTypeReader;
+import com.coremedia.iso.IsoTypeWriter;
+import com.googlecode.mp4parser.AbstractFullBox;
+
+import java.nio.ByteBuffer;
+
+/**
+ * aligned(8) class TrackFragmentHeaderBox
+ * extends FullBox('tfhd', 0, tf_flags){
+ * unsigned int(32) track_ID;
+ * // all the following are optional fields
+ * unsigned int(64) base_data_offset;
+ * unsigned int(32) sample_description_index;
+ * unsigned int(32) default_sample_duration;
+ * unsigned int(32) default_sample_size;
+ * unsigned int(32) default_sample_flags
+ * }
+ */
+public class TrackFragmentHeaderBox extends AbstractFullBox {
+    public static final String TYPE = "tfhd";
+
+    private long trackId;
+    private long baseDataOffset = -1;
+    private long sampleDescriptionIndex;
+    private long defaultSampleDuration = -1;
+    private long defaultSampleSize = -1;
+    private SampleFlags defaultSampleFlags;
+    private boolean durationIsEmpty;
+
+    public TrackFragmentHeaderBox() {
+        super(TYPE);
+    }
+
+    protected long getContentSize() {
+        long size = 8;
+        int flags = getFlags();
+        if ((flags & 0x1) == 1) { //baseDataOffsetPresent
+            size += 8;
+        }
+        if ((flags & 0x2) == 0x2) { //sampleDescriptionIndexPresent
+            size += 4;
+        }
+        if ((flags & 0x8) == 0x8) { //defaultSampleDurationPresent
+            size += 4;
+        }
+        if ((flags & 0x10) == 0x10) { //defaultSampleSizePresent
+            size += 4;
+        }
+        if ((flags & 0x20) == 0x20) { //defaultSampleFlagsPresent
+            size += 4;
+        }
+        return size;
+    }
+
+
+    protected void getContent(ByteBuffer byteBuffer) {
+        writeVersionAndFlags(byteBuffer);
+        IsoTypeWriter.writeUInt32(byteBuffer, trackId);
+
+        if ((getFlags() & 0x1) == 1) { //baseDataOffsetPresent
+            IsoTypeWriter.writeUInt64(byteBuffer, getBaseDataOffset());
+        }
+        if ((getFlags() & 0x2) == 0x2) { //sampleDescriptionIndexPresent
+            IsoTypeWriter.writeUInt32(byteBuffer, getSampleDescriptionIndex());
+        }
+        if ((getFlags() & 0x8) == 0x8) { //defaultSampleDurationPresent
+            IsoTypeWriter.writeUInt32(byteBuffer, getDefaultSampleDuration());
+        }
+        if ((getFlags() & 0x10) == 0x10) { //defaultSampleSizePresent
+            IsoTypeWriter.writeUInt32(byteBuffer, getDefaultSampleSize());
+        }
+        if ((getFlags() & 0x20) == 0x20) { //defaultSampleFlagsPresent
+            defaultSampleFlags.getContent(byteBuffer);
+        }
+    }
+
+    @Override
+    public void _parseDetails(ByteBuffer content) {
+        parseVersionAndFlags(content);
+        trackId = IsoTypeReader.readUInt32(content);
+        if ((getFlags() & 0x1) == 1) { //baseDataOffsetPresent
+            baseDataOffset = IsoTypeReader.readUInt64(content);
+        }
+        if ((getFlags() & 0x2) == 0x2) { //sampleDescriptionIndexPresent
+            sampleDescriptionIndex = IsoTypeReader.readUInt32(content);
+        }
+        if ((getFlags() & 0x8) == 0x8) { //defaultSampleDurationPresent
+            defaultSampleDuration = IsoTypeReader.readUInt32(content);
+        }
+        if ((getFlags() & 0x10) == 0x10) { //defaultSampleSizePresent
+            defaultSampleSize = IsoTypeReader.readUInt32(content);
+        }
+        if ((getFlags() & 0x20) == 0x20) { //defaultSampleFlagsPresent
+            defaultSampleFlags = new SampleFlags(content);
+        }
+        if ((getFlags() & 0x10000) == 0x10000) { //durationIsEmpty
+            durationIsEmpty = true;
+        }
+    }
+
+    public boolean hasBaseDataOffset() {
+        return (getFlags() & 0x1) != 0;
+    }
+
+    public boolean hasSampleDescriptionIndex() {
+        return (getFlags() & 0x2) != 0;
+    }
+
+    public boolean hasDefaultSampleDuration() {
+        return (getFlags() & 0x8) != 0;
+    }
+
+    public boolean hasDefaultSampleSize() {
+        return (getFlags() & 0x10) != 0;
+    }
+
+    public boolean hasDefaultSampleFlags() {
+        return (getFlags() & 0x20) != 0;
+    }
+
+    public long getTrackId() {
+        return trackId;
+    }
+
+    public long getBaseDataOffset() {
+        return baseDataOffset;
+    }
+
+    public long getSampleDescriptionIndex() {
+        return sampleDescriptionIndex;
+    }
+
+    public long getDefaultSampleDuration() {
+        return defaultSampleDuration;
+    }
+
+    public long getDefaultSampleSize() {
+        return defaultSampleSize;
+    }
+
+    public SampleFlags getDefaultSampleFlags() {
+        return defaultSampleFlags;
+    }
+
+    public boolean isDurationIsEmpty() {
+        return durationIsEmpty;
+    }
+
+    public void setTrackId(long trackId) {
+        this.trackId = trackId;
+    }
+
+    public void setBaseDataOffset(long baseDataOffset) {
+        if (baseDataOffset == -1) {
+            setFlags(getFlags() & (Integer.MAX_VALUE ^ 0x1));
+        } else {
+            setFlags(getFlags() | 0x1); // activate the field
+        }
+        this.baseDataOffset = baseDataOffset;
+    }
+
+    public void setSampleDescriptionIndex(long sampleDescriptionIndex) {
+        if (sampleDescriptionIndex == -1) {
+            setFlags(getFlags() & (Integer.MAX_VALUE ^ 0x2));
+        } else {
+            setFlags(getFlags() | 0x2); // activate the field
+        }
+        this.sampleDescriptionIndex = sampleDescriptionIndex;
+    }
+
+    public void setDefaultSampleDuration(long defaultSampleDuration) {
+        setFlags(getFlags() | 0x8); // activate the field
+        this.defaultSampleDuration = defaultSampleDuration;
+    }
+
+    public void setDefaultSampleSize(long defaultSampleSize) {
+        setFlags(getFlags() | 0x10); // activate the field
+        this.defaultSampleSize = defaultSampleSize;
+    }
+
+    public void setDefaultSampleFlags(SampleFlags defaultSampleFlags) {
+        setFlags(getFlags() | 0x20); // activate the field
+        this.defaultSampleFlags = defaultSampleFlags;
+    }
+
+    public void setDurationIsEmpty(boolean durationIsEmpty) {
+        setFlags(getFlags() | 0x10000); // activate the field
+        this.durationIsEmpty = durationIsEmpty;
+    }
+
+    @Override
+    public String toString() {
+        final StringBuilder sb = new StringBuilder();
+        sb.append("TrackFragmentHeaderBox");
+        sb.append("{trackId=").append(trackId);
+        sb.append(", baseDataOffset=").append(baseDataOffset);
+        sb.append(", sampleDescriptionIndex=").append(sampleDescriptionIndex);
+        sb.append(", defaultSampleDuration=").append(defaultSampleDuration);
+        sb.append(", defaultSampleSize=").append(defaultSampleSize);
+        sb.append(", defaultSampleFlags=").append(defaultSampleFlags);
+        sb.append(", durationIsEmpty=").append(durationIsEmpty);
+        sb.append('}');
+        return sb.toString();
+    }
+
+}
diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/fragment/TrackFragmentRandomAccessBox.java b/isoparser/src/main/java/com/coremedia/iso/boxes/fragment/TrackFragmentRandomAccessBox.java
new file mode 100644
index 0000000..94d24ae
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/fragment/TrackFragmentRandomAccessBox.java
@@ -0,0 +1,294 @@
+/*
+ * Copyright 2009 castLabs GmbH, Berlin
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.coremedia.iso.boxes.fragment;
+
+import com.coremedia.iso.IsoTypeReader;
+import com.coremedia.iso.IsoTypeReaderVariable;
+import com.coremedia.iso.IsoTypeWriter;
+import com.coremedia.iso.IsoTypeWriterVariable;
+import com.googlecode.mp4parser.AbstractFullBox;
+
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * aligned(8) class TrackFragmentRandomAccessBox
+ * extends FullBox('tfra', version, 0) {
+ * unsigned int(32) track_ID;
+ * const unsigned int(26) reserved = 0;
+ * unsigned int(2) length_size_of_traf_num;
+ * unsigned int(2) length_size_of_trun_num;
+ * unsigned int(2) length_size_of_sample_num;
+ * unsigned int(32) number_of_entry;
+ * for(i=1; i <= number_of_entry; i++){
+ * if(version==1){
+ * unsigned int(64) time;
+ * unsigned int(64) moof_offset;
+ * }else{
+ * unsigned int(32) time;
+ * unsigned int(32) moof_offset;
+ * }
+ * unsigned int((length_size_of_traf_num+1) * 8) traf_number;
+ * unsigned int((length_size_of_trun_num+1) * 8) trun_number;
+ * unsigned int((length_size_of_sample_num+1) * 8) sample_number;
+ * }
+ * }
+ */
+public class TrackFragmentRandomAccessBox extends AbstractFullBox {
+    public static final String TYPE = "tfra";
+
+    private long trackId;
+    private int reserved;
+    private int lengthSizeOfTrafNum = 2;
+    private int lengthSizeOfTrunNum = 2;
+    private int lengthSizeOfSampleNum = 2;
+    private List<Entry> entries = Collections.emptyList();
+
+    public TrackFragmentRandomAccessBox() {
+        super(TYPE);
+    }
+
+
+    protected long getContentSize() {
+        long contentSize = 4;
+        contentSize += 4 + 4 /*26 + 2 + 2 + 2 */ + 4;
+        if (getVersion() == 1) {
+            contentSize += (8 + 8) * entries.size();
+        } else {
+            contentSize += (4 + 4) * entries.size();
+        }
+        contentSize += lengthSizeOfTrafNum * entries.size();
+        contentSize += lengthSizeOfTrunNum * entries.size();
+        contentSize += lengthSizeOfSampleNum * entries.size();
+        return contentSize;
+    }
+
+
+    @Override
+    public void _parseDetails(ByteBuffer content) {
+        parseVersionAndFlags(content);
+        trackId = IsoTypeReader.readUInt32(content);
+        long temp = IsoTypeReader.readUInt32(content);
+        reserved = (int) (temp >> 6);
+        lengthSizeOfTrafNum = ((int) (temp & 0x3F) >> 4) + 1;
+        lengthSizeOfTrunNum = ((int) (temp & 0xC) >> 2) + 1;
+        lengthSizeOfSampleNum = ((int) (temp & 0x3)) + 1;
+        long numberOfEntries = IsoTypeReader.readUInt32(content);
+
+        entries = new ArrayList<Entry>();
+
+        for (int i = 0; i < numberOfEntries; i++) {
+            Entry entry = new Entry();
+            if (getVersion() == 1) {
+                entry.time = IsoTypeReader.readUInt64(content);
+                entry.moofOffset = IsoTypeReader.readUInt64(content);
+            } else {
+                entry.time = IsoTypeReader.readUInt32(content);
+                entry.moofOffset = IsoTypeReader.readUInt32(content);
+            }
+            entry.trafNumber = IsoTypeReaderVariable.read(content, lengthSizeOfTrafNum);
+            entry.trunNumber = IsoTypeReaderVariable.read(content, lengthSizeOfTrunNum);
+            entry.sampleNumber = IsoTypeReaderVariable.read(content, lengthSizeOfSampleNum);
+
+            entries.add(entry);
+        }
+
+    }
+
+
+    @Override
+    protected void getContent(ByteBuffer byteBuffer) {
+        writeVersionAndFlags(byteBuffer);
+        IsoTypeWriter.writeUInt32(byteBuffer, trackId);
+        long temp;
+        temp = reserved << 6;
+        temp = temp | (((lengthSizeOfTrafNum - 1) & 0x3) << 4);
+        temp = temp | (((lengthSizeOfTrunNum - 1) & 0x3) << 2);
+        temp = temp | ((lengthSizeOfSampleNum - 1) & 0x3);
+        IsoTypeWriter.writeUInt32(byteBuffer, temp);
+        IsoTypeWriter.writeUInt32(byteBuffer, entries.size());
+
+        for (Entry entry : entries) {
+            if (getVersion() == 1) {
+                IsoTypeWriter.writeUInt64(byteBuffer, entry.time);
+                IsoTypeWriter.writeUInt64(byteBuffer, entry.moofOffset);
+            } else {
+                IsoTypeWriter.writeUInt32(byteBuffer, entry.time);
+                IsoTypeWriter.writeUInt32(byteBuffer, entry.moofOffset);
+            }
+            IsoTypeWriterVariable.write(entry.trafNumber, byteBuffer, lengthSizeOfTrafNum);
+            IsoTypeWriterVariable.write(entry.trunNumber, byteBuffer, lengthSizeOfTrunNum);
+            IsoTypeWriterVariable.write(entry.sampleNumber, byteBuffer, lengthSizeOfSampleNum);
+
+        }
+    }
+
+
+    public void setTrackId(long trackId) {
+        this.trackId = trackId;
+    }
+
+    public void setLengthSizeOfTrafNum(int lengthSizeOfTrafNum) {
+        this.lengthSizeOfTrafNum = lengthSizeOfTrafNum;
+    }
+
+    public void setLengthSizeOfTrunNum(int lengthSizeOfTrunNum) {
+        this.lengthSizeOfTrunNum = lengthSizeOfTrunNum;
+    }
+
+    public void setLengthSizeOfSampleNum(int lengthSizeOfSampleNum) {
+        this.lengthSizeOfSampleNum = lengthSizeOfSampleNum;
+    }
+
+    public long getTrackId() {
+        return trackId;
+    }
+
+    public int getReserved() {
+        return reserved;
+    }
+
+    public int getLengthSizeOfTrafNum() {
+        return lengthSizeOfTrafNum;
+    }
+
+    public int getLengthSizeOfTrunNum() {
+        return lengthSizeOfTrunNum;
+    }
+
+    public int getLengthSizeOfSampleNum() {
+        return lengthSizeOfSampleNum;
+    }
+
+    public long getNumberOfEntries() {
+        return entries.size();
+    }
+
+    public List<Entry> getEntries() {
+        return Collections.unmodifiableList(entries);
+    }
+
+    public void setEntries(List<Entry> entries) {
+        this.entries = entries;
+    }
+
+    public static class Entry {
+        private long time;
+        private long moofOffset;
+        private long trafNumber;
+        private long trunNumber;
+        private long sampleNumber;
+
+        public Entry() {
+        }
+
+        public Entry(long time, long moofOffset, long trafNumber, long trunNumber, long sampleNumber) {
+            this.moofOffset = moofOffset;
+            this.sampleNumber = sampleNumber;
+            this.time = time;
+            this.trafNumber = trafNumber;
+            this.trunNumber = trunNumber;
+        }
+
+        public long getTime() {
+            return time;
+        }
+
+        public long getMoofOffset() {
+            return moofOffset;
+        }
+
+        public long getTrafNumber() {
+            return trafNumber;
+        }
+
+        public long getTrunNumber() {
+            return trunNumber;
+        }
+
+        public long getSampleNumber() {
+            return sampleNumber;
+        }
+
+        public void setTime(long time) {
+            this.time = time;
+        }
+
+        public void setMoofOffset(long moofOffset) {
+            this.moofOffset = moofOffset;
+        }
+
+        public void setTrafNumber(long trafNumber) {
+            this.trafNumber = trafNumber;
+        }
+
+        public void setTrunNumber(long trunNumber) {
+            this.trunNumber = trunNumber;
+        }
+
+        public void setSampleNumber(long sampleNumber) {
+            this.sampleNumber = sampleNumber;
+        }
+
+        @Override
+        public String toString() {
+            return "Entry{" +
+                    "time=" + time +
+                    ", moofOffset=" + moofOffset +
+                    ", trafNumber=" + trafNumber +
+                    ", trunNumber=" + trunNumber +
+                    ", sampleNumber=" + sampleNumber +
+                    '}';
+        }
+
+        @Override
+        public boolean equals(Object o) {
+            if (this == o) return true;
+            if (o == null || getClass() != o.getClass()) return false;
+
+            Entry entry = (Entry) o;
+
+            if (moofOffset != entry.moofOffset) return false;
+            if (sampleNumber != entry.sampleNumber) return false;
+            if (time != entry.time) return false;
+            if (trafNumber != entry.trafNumber) return false;
+            if (trunNumber != entry.trunNumber) return false;
+
+            return true;
+        }
+
+        @Override
+        public int hashCode() {
+            int result = (int) (time ^ (time >>> 32));
+            result = 31 * result + (int) (moofOffset ^ (moofOffset >>> 32));
+            result = 31 * result + (int) (trafNumber ^ (trafNumber >>> 32));
+            result = 31 * result + (int) (trunNumber ^ (trunNumber >>> 32));
+            result = 31 * result + (int) (sampleNumber ^ (sampleNumber >>> 32));
+            return result;
+        }
+    }
+
+    @Override
+    public String toString() {
+        return "TrackFragmentRandomAccessBox{" +
+                "trackId=" + trackId +
+                ", entries=" + entries +
+                '}';
+    }
+}
diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/fragment/TrackRunBox.java b/isoparser/src/main/java/com/coremedia/iso/boxes/fragment/TrackRunBox.java
new file mode 100644
index 0000000..fc4faac
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/fragment/TrackRunBox.java
@@ -0,0 +1,355 @@
+/*
+ * Copyright 2009 castLabs GmbH, Berlin
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.coremedia.iso.boxes.fragment;
+
+import com.coremedia.iso.IsoTypeReader;
+import com.coremedia.iso.IsoTypeWriter;
+import com.coremedia.iso.boxes.MovieBox;
+import com.googlecode.mp4parser.AbstractFullBox;
+
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
+import java.util.List;
+
+import static com.googlecode.mp4parser.util.CastUtils.l2i;
+
+/**
+ * aligned(8) class TrackRunBox
+ * extends FullBox('trun', 0, tr_flags) {
+ * unsigned int(32) sample_count;
+ * // the following are optional fields
+ * signed int(32) data_offset;
+ * unsigned int(32) first_sample_flags;
+ * // all fields in the following array are optional
+ * {
+ * unsigned int(32) sample_duration;
+ * unsigned int(32) sample_size;
+ * unsigned int(32) sample_flags
+ * unsigned int(32) sample_composition_time_offset;
+ * }[ sample_count ]
+ * }
+ */
+
+public class TrackRunBox extends AbstractFullBox {
+    public static final String TYPE = "trun";
+    private int dataOffset;
+    private SampleFlags firstSampleFlags;
+    private List<Entry> entries = new ArrayList<Entry>();
+
+
+    public List<Entry> getEntries() {
+        return entries;
+    }
+
+    public static class Entry {
+        private long sampleDuration;
+        private long sampleSize;
+        private SampleFlags sampleFlags;
+        private int sampleCompositionTimeOffset;
+
+        public Entry() {
+        }
+
+        public Entry(long sampleDuration, long sampleSize, SampleFlags sampleFlags, int sampleCompositionTimeOffset) {
+            this.sampleDuration = sampleDuration;
+            this.sampleSize = sampleSize;
+            this.sampleFlags = sampleFlags;
+            this.sampleCompositionTimeOffset = sampleCompositionTimeOffset;
+        }
+
+        public long getSampleDuration() {
+            return sampleDuration;
+        }
+
+        public long getSampleSize() {
+            return sampleSize;
+        }
+
+        public SampleFlags getSampleFlags() {
+            return sampleFlags;
+        }
+
+        public int getSampleCompositionTimeOffset() {
+            return sampleCompositionTimeOffset;
+        }
+
+        public void setSampleDuration(long sampleDuration) {
+            this.sampleDuration = sampleDuration;
+        }
+
+        public void setSampleSize(long sampleSize) {
+            this.sampleSize = sampleSize;
+        }
+
+        public void setSampleFlags(SampleFlags sampleFlags) {
+            this.sampleFlags = sampleFlags;
+        }
+
+        public void setSampleCompositionTimeOffset(int sampleCompositionTimeOffset) {
+            this.sampleCompositionTimeOffset = sampleCompositionTimeOffset;
+        }
+
+        @Override
+        public String toString() {
+            return "Entry{" +
+                    "sampleDuration=" + sampleDuration +
+                    ", sampleSize=" + sampleSize +
+                    ", sampleFlags=" + sampleFlags +
+                    ", sampleCompositionTimeOffset=" + sampleCompositionTimeOffset +
+                    '}';
+        }
+    }
+
+    public void setDataOffset(int dataOffset) {
+        if (dataOffset == -1) {
+            setFlags(getFlags() & (0xFFFFFF ^ 1));
+        } else {
+            setFlags(getFlags() | 0x1); // turn on dataoffset
+        }
+        this.dataOffset = dataOffset;
+    }
+
+    public long[] getSampleCompositionTimeOffsets() {
+        if (isSampleCompositionTimeOffsetPresent()) {
+            long[] result = new long[entries.size()];
+
+            for (int i = 0; i < result.length; i++) {
+                result[i] = entries.get(i).getSampleCompositionTimeOffset();
+            }
+            return result;
+        }
+        return null;
+    }
+
+    public TrackExtendsBox getTrackExtendsBox() {
+        final TrackFragmentHeaderBox tfhd = ((TrackFragmentBox) getParent()).getTrackFragmentHeaderBox();
+        final List<MovieBox> movieBoxes = tfhd.getIsoFile().getBoxes(MovieBox.class);
+        if (movieBoxes.size() == 0) {
+            return null;
+        }
+
+        final List<TrackExtendsBox> trexBoxes = movieBoxes.get(0).getBoxes(TrackExtendsBox.class, true);
+        TrackExtendsBox trex = null;
+        for (TrackExtendsBox aTrex : trexBoxes) {
+            if (aTrex.getTrackId() == tfhd.getTrackId()) {
+                trex = aTrex;
+            }
+        }
+        return trex;
+    }
+
+    public TrackRunBox() {
+        super(TYPE);
+    }
+
+    protected long getContentSize() {
+        long size = 8;
+        int flags = getFlags();
+
+        if ((flags & 0x1) == 0x1) { //dataOffsetPresent
+            size += 4;
+        }
+        if ((flags & 0x4) == 0x4) { //firstSampleFlagsPresent
+            size += 4;
+        }
+
+        long entrySize = 0;
+        if ((flags & 0x100) == 0x100) { //sampleDurationPresent
+            entrySize += 4;
+        }
+        if ((flags & 0x200) == 0x200) { //sampleSizePresent
+            entrySize += 4;
+        }
+        if ((flags & 0x400) == 0x400) { //sampleFlagsPresent
+            entrySize += 4;
+        }
+        if ((flags & 0x800) == 0x800) { //sampleCompositionTimeOffsetPresent
+            entrySize += 4;
+        }
+        size += entrySize * entries.size();
+        return size;
+    }
+
+    protected void getContent(ByteBuffer byteBuffer) {
+        writeVersionAndFlags(byteBuffer);
+        IsoTypeWriter.writeUInt32(byteBuffer, entries.size());
+        int flags = getFlags();
+
+        if ((flags & 0x1) == 1) { //dataOffsetPresent
+            IsoTypeWriter.writeUInt32(byteBuffer, dataOffset);
+        }
+        if ((flags & 0x4) == 0x4) { //firstSampleFlagsPresent
+            firstSampleFlags.getContent(byteBuffer);
+        }
+
+        for (Entry entry : entries) {
+            if ((flags & 0x100) == 0x100) { //sampleDurationPresent
+                IsoTypeWriter.writeUInt32(byteBuffer, entry.sampleDuration);
+            }
+            if ((flags & 0x200) == 0x200) { //sampleSizePresent
+                IsoTypeWriter.writeUInt32(byteBuffer, entry.sampleSize);
+            }
+            if ((flags & 0x400) == 0x400) { //sampleFlagsPresent
+                entry.sampleFlags.getContent(byteBuffer);
+            }
+            if ((flags & 0x800) == 0x800) { //sampleCompositionTimeOffsetPresent
+                byteBuffer.putInt(entry.sampleCompositionTimeOffset);
+            }
+        }
+    }
+
+    @Override
+    public void _parseDetails(ByteBuffer content) {
+        parseVersionAndFlags(content);
+        long sampleCount = IsoTypeReader.readUInt32(content);
+
+        if ((getFlags() & 0x1) == 1) { //dataOffsetPresent
+            dataOffset = l2i(IsoTypeReader.readUInt32(content));
+        } else {
+            dataOffset = -1;
+        }
+        if ((getFlags() & 0x4) == 0x4) { //firstSampleFlagsPresent
+            firstSampleFlags = new SampleFlags(content);
+        }
+
+        for (int i = 0; i < sampleCount; i++) {
+            Entry entry = new Entry();
+            if ((getFlags() & 0x100) == 0x100) { //sampleDurationPresent
+                entry.sampleDuration = IsoTypeReader.readUInt32(content);
+            }
+            if ((getFlags() & 0x200) == 0x200) { //sampleSizePresent
+                entry.sampleSize = IsoTypeReader.readUInt32(content);
+            }
+            if ((getFlags() & 0x400) == 0x400) { //sampleFlagsPresent
+                entry.sampleFlags = new SampleFlags(content);
+            }
+            if ((getFlags() & 0x800) == 0x800) { //sampleCompositionTimeOffsetPresent
+                entry.sampleCompositionTimeOffset = content.getInt();
+            }
+            entries.add(entry);
+        }
+
+    }
+
+    public long getSampleCount() {
+        return entries.size();
+    }
+
+    public boolean isDataOffsetPresent() {
+        return (getFlags() & 0x1) == 1;
+    }
+
+    public boolean isFirstSampleFlagsPresent() {
+        return (getFlags() & 0x4) == 0x4;
+    }
+
+
+    public boolean isSampleSizePresent() {
+        return (getFlags() & 0x200) == 0x200;
+    }
+
+    public boolean isSampleDurationPresent() {
+        return (getFlags() & 0x100) == 0x100;
+    }
+
+    public boolean isSampleFlagsPresent() {
+        return (getFlags() & 0x400) == 0x400;
+    }
+
+    public boolean isSampleCompositionTimeOffsetPresent() {
+        return (getFlags() & 0x800) == 0x800;
+    }
+
+    public void setDataOffsetPresent(boolean v) {
+        if (v) {
+            setFlags(getFlags() | 0x01);
+        } else {
+            setFlags(getFlags() & (0xFFFFFF ^ 0x1));
+        }
+    }
+
+    public void setSampleSizePresent(boolean v) {
+        if (v) {
+            setFlags(getFlags() | 0x200);
+        } else {
+            setFlags(getFlags() & (0xFFFFFF ^ 0x200));
+        }
+    }
+
+    public void setSampleDurationPresent(boolean v) {
+
+        if (v) {
+            setFlags(getFlags() | 0x100);
+        } else {
+            setFlags(getFlags() & (0xFFFFFF ^ 0x100));
+        }
+    }
+
+    public void setSampleFlagsPresent(boolean v) {
+        if (v) {
+            setFlags(getFlags() | 0x400);
+        } else {
+            setFlags(getFlags() & (0xFFFFFF ^ 0x400));
+        }
+    }
+
+    public void setSampleCompositionTimeOffsetPresent(boolean v) {
+        if (v) {
+            setFlags(getFlags() | 0x800);
+        } else {
+            setFlags(getFlags() & (0xFFFFFF ^ 0x800));
+        }
+
+    }
+
+    public int getDataOffset() {
+        return dataOffset;
+    }
+
+    public SampleFlags getFirstSampleFlags() {
+        return firstSampleFlags;
+    }
+
+    public void setFirstSampleFlags(SampleFlags firstSampleFlags) {
+        if (firstSampleFlags == null) {
+            setFlags(getFlags() & (0xFFFFFF ^ 0x4));
+        } else {
+            setFlags(getFlags() | 0x4);
+        }
+        this.firstSampleFlags = firstSampleFlags;
+    }
+
+    @Override
+    public String toString() {
+        final StringBuilder sb = new StringBuilder();
+        sb.append("TrackRunBox");
+        sb.append("{sampleCount=").append(entries.size());
+        sb.append(", dataOffset=").append(dataOffset);
+        sb.append(", dataOffsetPresent=").append(isDataOffsetPresent());
+        sb.append(", sampleSizePresent=").append(isSampleSizePresent());
+        sb.append(", sampleDurationPresent=").append(isSampleDurationPresent());
+        sb.append(", sampleFlagsPresentPresent=").append(isSampleFlagsPresent());
+        sb.append(", sampleCompositionTimeOffsetPresent=").append(isSampleCompositionTimeOffsetPresent());
+        sb.append(", firstSampleFlags=").append(firstSampleFlags);
+        sb.append('}');
+        return sb.toString();
+    }
+
+    public void setEntries(List<Entry> entries) {
+        this.entries = entries;
+    }
+}
diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/h264/.svn/all-wcprops b/isoparser/src/main/java/com/coremedia/iso/boxes/h264/.svn/all-wcprops
new file mode 100644
index 0000000..15d84c0
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/h264/.svn/all-wcprops
@@ -0,0 +1,11 @@
+K 25
+svn:wc:ra_dav:version-url
+V 76
+/svn/!svn/ver/777/trunk/isoparser/src/main/java/com/coremedia/iso/boxes/h264
+END
+AvcConfigurationBox.java
+K 25
+svn:wc:ra_dav:version-url
+V 101
+/svn/!svn/ver/777/trunk/isoparser/src/main/java/com/coremedia/iso/boxes/h264/AvcConfigurationBox.java
+END
diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/h264/.svn/entries b/isoparser/src/main/java/com/coremedia/iso/boxes/h264/.svn/entries
new file mode 100644
index 0000000..ccf8f72
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/h264/.svn/entries
@@ -0,0 +1,62 @@
+10
+
+dir
+778
+http://mp4parser.googlecode.com/svn/trunk/isoparser/src/main/java/com/coremedia/iso/boxes/h264
+http://mp4parser.googlecode.com/svn
+
+
+
+2012-09-10T14:56:10.036617Z
+777
+sebastian.annies@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+7decde4b-c250-0410-a0da-51896bc88be6
+
+AvcConfigurationBox.java
+file
+
+
+
+
+2012-09-14T17:27:52.727250Z
+676ca6ae057828e6b82a8e4fa58caa3e
+2012-09-10T14:56:10.036617Z
+777
+sebastian.annies@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+15420
+
diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/h264/.svn/text-base/AvcConfigurationBox.java.svn-base b/isoparser/src/main/java/com/coremedia/iso/boxes/h264/.svn/text-base/AvcConfigurationBox.java.svn-base
new file mode 100644
index 0000000..52f3695
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/h264/.svn/text-base/AvcConfigurationBox.java.svn-base
@@ -0,0 +1,378 @@
+/*  
+ * Copyright 2008 CoreMedia AG, Hamburg
+ *
+ * Licensed under the Apache License, Version 2.0 (the License); 
+ * you may not use this file except in compliance with the License. 
+ * You may obtain a copy of the License at 
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0 
+ * 
+ * Unless required by applicable law or agreed to in writing, software 
+ * distributed under the License is distributed on an AS IS BASIS, 
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+ * See the License for the specific language governing permissions and 
+ * limitations under the License. 
+ */
+
+package com.coremedia.iso.boxes.h264;
+
+import com.coremedia.iso.Hex;
+import com.coremedia.iso.IsoTypeReader;
+import com.coremedia.iso.IsoTypeWriter;
+import com.googlecode.mp4parser.AbstractBox;
+import com.googlecode.mp4parser.boxes.mp4.objectdescriptors.BitReaderBuffer;
+import com.googlecode.mp4parser.boxes.mp4.objectdescriptors.BitWriterBuffer;
+import com.googlecode.mp4parser.h264.model.PictureParameterSet;
+import com.googlecode.mp4parser.h264.model.SeqParameterSet;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * Defined in ISO/IEC 14496-15:2004.
+ */
+public final class AvcConfigurationBox extends AbstractBox {
+    public static final String TYPE = "avcC";
+
+    public AVCDecoderConfigurationRecord avcDecoderConfigurationRecord = new AVCDecoderConfigurationRecord();
+
+
+    public AvcConfigurationBox() {
+        super(TYPE);
+    }
+
+    public int getConfigurationVersion() {
+        return avcDecoderConfigurationRecord.configurationVersion;
+    }
+
+    public int getAvcProfileIndication() {
+        return avcDecoderConfigurationRecord.avcProfileIndication;
+    }
+
+    public int getProfileCompatibility() {
+        return avcDecoderConfigurationRecord.profileCompatibility;
+    }
+
+    public int getAvcLevelIndication() {
+        return avcDecoderConfigurationRecord.avcLevelIndication;
+    }
+
+    public int getLengthSizeMinusOne() {
+        return avcDecoderConfigurationRecord.lengthSizeMinusOne;
+    }
+
+    public List<byte[]> getSequenceParameterSets() {
+        return Collections.unmodifiableList(avcDecoderConfigurationRecord.sequenceParameterSets);
+    }
+
+    public List<byte[]> getPictureParameterSets() {
+        return Collections.unmodifiableList(avcDecoderConfigurationRecord.pictureParameterSets);
+    }
+
+    public void setConfigurationVersion(int configurationVersion) {
+        this.avcDecoderConfigurationRecord.configurationVersion = configurationVersion;
+    }
+
+    public void setAvcProfileIndication(int avcProfileIndication) {
+        this.avcDecoderConfigurationRecord.avcProfileIndication = avcProfileIndication;
+    }
+
+    public void setProfileCompatibility(int profileCompatibility) {
+        this.avcDecoderConfigurationRecord.profileCompatibility = profileCompatibility;
+    }
+
+    public void setAvcLevelIndication(int avcLevelIndication) {
+        this.avcDecoderConfigurationRecord.avcLevelIndication = avcLevelIndication;
+    }
+
+    public void setLengthSizeMinusOne(int lengthSizeMinusOne) {
+        this.avcDecoderConfigurationRecord.lengthSizeMinusOne = lengthSizeMinusOne;
+    }
+
+    public void setSequenceParameterSets(List<byte[]> sequenceParameterSets) {
+        this.avcDecoderConfigurationRecord.sequenceParameterSets = sequenceParameterSets;
+    }
+
+    public void setPictureParameterSets(List<byte[]> pictureParameterSets) {
+        this.avcDecoderConfigurationRecord.pictureParameterSets = pictureParameterSets;
+    }
+
+    public int getChromaFormat() {
+        return avcDecoderConfigurationRecord.chromaFormat;
+    }
+
+    public void setChromaFormat(int chromaFormat) {
+        this.avcDecoderConfigurationRecord.chromaFormat = chromaFormat;
+    }
+
+    public int getBitDepthLumaMinus8() {
+        return avcDecoderConfigurationRecord.bitDepthLumaMinus8;
+    }
+
+    public void setBitDepthLumaMinus8(int bitDepthLumaMinus8) {
+        this.avcDecoderConfigurationRecord.bitDepthLumaMinus8 = bitDepthLumaMinus8;
+    }
+
+    public int getBitDepthChromaMinus8() {
+        return avcDecoderConfigurationRecord.bitDepthChromaMinus8;
+    }
+
+    public void setBitDepthChromaMinus8(int bitDepthChromaMinus8) {
+        this.avcDecoderConfigurationRecord.bitDepthChromaMinus8 = bitDepthChromaMinus8;
+    }
+
+    public List<byte[]> getSequenceParameterSetExts() {
+        return avcDecoderConfigurationRecord.sequenceParameterSetExts;
+    }
+
+    public void setSequenceParameterSetExts(List<byte[]> sequenceParameterSetExts) {
+        this.avcDecoderConfigurationRecord.sequenceParameterSetExts = sequenceParameterSetExts;
+    }
+
+    public boolean hasExts() {
+        return avcDecoderConfigurationRecord.hasExts;
+    }
+
+    public void setHasExts(boolean hasExts) {
+        this.avcDecoderConfigurationRecord.hasExts = hasExts;
+    }
+
+    @Override
+    public void _parseDetails(ByteBuffer content) {
+        avcDecoderConfigurationRecord = new AVCDecoderConfigurationRecord(content);
+    }
+
+
+    @Override
+    public long getContentSize() {
+        return avcDecoderConfigurationRecord.getContentSize();
+    }
+
+
+    @Override
+    public void getContent(ByteBuffer byteBuffer) {
+        avcDecoderConfigurationRecord.getContent(byteBuffer);
+    }
+
+    // just to display sps in isoviewer no practical use
+    public String[] getSPS() {
+        return avcDecoderConfigurationRecord.getSPS();
+    }
+
+    public String[] getPPS() {
+        return avcDecoderConfigurationRecord.getPPS();
+    }
+
+    public List<String> getSequenceParameterSetsAsStrings() {
+        return avcDecoderConfigurationRecord.getSequenceParameterSetsAsStrings();
+    }
+
+    public List<String> getSequenceParameterSetExtsAsStrings() {
+        return avcDecoderConfigurationRecord.getSequenceParameterSetExtsAsStrings();
+    }
+
+    public List<String> getPictureParameterSetsAsStrings() {
+        return avcDecoderConfigurationRecord.getPictureParameterSetsAsStrings();
+    }
+
+    public AVCDecoderConfigurationRecord getavcDecoderConfigurationRecord() {
+        return avcDecoderConfigurationRecord;
+    }
+
+
+    public static class AVCDecoderConfigurationRecord {
+        public int configurationVersion;
+        public int avcProfileIndication;
+        public int profileCompatibility;
+        public int avcLevelIndication;
+        public int lengthSizeMinusOne;
+        public List<byte[]> sequenceParameterSets = new ArrayList<byte[]>();
+        public List<byte[]> pictureParameterSets = new ArrayList<byte[]>();
+
+        public boolean hasExts = true;
+        public int chromaFormat = 1;
+        public int bitDepthLumaMinus8 = 0;
+        public int bitDepthChromaMinus8 = 0;
+        public List<byte[]> sequenceParameterSetExts = new ArrayList<byte[]>();
+
+        /**
+         * Just for non-spec-conform encoders
+         */
+        public int lengthSizeMinusOnePaddingBits = 60;
+        public int numberOfSequenceParameterSetsPaddingBits = 7;
+        public int chromaFormatPaddingBits = 31;
+        public int bitDepthLumaMinus8PaddingBits = 31;
+        public int bitDepthChromaMinus8PaddingBits = 31;
+
+        public AVCDecoderConfigurationRecord() {
+        }
+
+        public AVCDecoderConfigurationRecord(ByteBuffer content) {
+            configurationVersion = IsoTypeReader.readUInt8(content);
+            avcProfileIndication = IsoTypeReader.readUInt8(content);
+            profileCompatibility = IsoTypeReader.readUInt8(content);
+            avcLevelIndication = IsoTypeReader.readUInt8(content);
+            BitReaderBuffer brb = new BitReaderBuffer(content);
+            lengthSizeMinusOnePaddingBits = brb.readBits(6);
+            lengthSizeMinusOne = brb.readBits(2);
+            numberOfSequenceParameterSetsPaddingBits = brb.readBits(3);
+            int numberOfSeuqenceParameterSets = brb.readBits(5);
+            for (int i = 0; i < numberOfSeuqenceParameterSets; i++) {
+                int sequenceParameterSetLength = IsoTypeReader.readUInt16(content);
+
+                byte[] sequenceParameterSetNALUnit = new byte[sequenceParameterSetLength];
+                content.get(sequenceParameterSetNALUnit);
+                sequenceParameterSets.add(sequenceParameterSetNALUnit);
+            }
+            long numberOfPictureParameterSets = IsoTypeReader.readUInt8(content);
+            for (int i = 0; i < numberOfPictureParameterSets; i++) {
+                int pictureParameterSetLength = IsoTypeReader.readUInt16(content);
+                byte[] pictureParameterSetNALUnit = new byte[pictureParameterSetLength];
+                content.get(pictureParameterSetNALUnit);
+                pictureParameterSets.add(pictureParameterSetNALUnit);
+            }
+            if (content.remaining() < 4) {
+                hasExts = false;
+            }
+            if (hasExts && (avcProfileIndication == 100 || avcProfileIndication == 110 || avcProfileIndication == 122 || avcProfileIndication == 144)) {
+                // actually only some bits are interesting so masking with & x would be good but not all Mp4 creating tools set the reserved bits to 1.
+                // So we need to store all bits
+                brb = new BitReaderBuffer(content);
+                chromaFormatPaddingBits = brb.readBits(6);
+                chromaFormat = brb.readBits(2);
+                bitDepthLumaMinus8PaddingBits = brb.readBits(5);
+                bitDepthLumaMinus8 = brb.readBits(3);
+                bitDepthChromaMinus8PaddingBits = brb.readBits(5);
+                bitDepthChromaMinus8 = brb.readBits(3);
+                long numOfSequenceParameterSetExt = IsoTypeReader.readUInt8(content);
+                for (int i = 0; i < numOfSequenceParameterSetExt; i++) {
+                    int sequenceParameterSetExtLength = IsoTypeReader.readUInt16(content);
+                    byte[] sequenceParameterSetExtNALUnit = new byte[sequenceParameterSetExtLength];
+                    content.get(sequenceParameterSetExtNALUnit);
+                    sequenceParameterSetExts.add(sequenceParameterSetExtNALUnit);
+                }
+            } else {
+                chromaFormat = -1;
+                bitDepthLumaMinus8 = -1;
+                bitDepthChromaMinus8 = -1;
+            }
+        }
+
+        public void getContent(ByteBuffer byteBuffer) {
+            IsoTypeWriter.writeUInt8(byteBuffer, configurationVersion);
+            IsoTypeWriter.writeUInt8(byteBuffer, avcProfileIndication);
+            IsoTypeWriter.writeUInt8(byteBuffer, profileCompatibility);
+            IsoTypeWriter.writeUInt8(byteBuffer, avcLevelIndication);
+            BitWriterBuffer bwb = new BitWriterBuffer(byteBuffer);
+            bwb.writeBits(lengthSizeMinusOnePaddingBits, 6);
+            bwb.writeBits(lengthSizeMinusOne, 2);
+            bwb.writeBits(numberOfSequenceParameterSetsPaddingBits, 3);
+            bwb.writeBits(pictureParameterSets.size(), 5);
+            for (byte[] sequenceParameterSetNALUnit : sequenceParameterSets) {
+                IsoTypeWriter.writeUInt16(byteBuffer, sequenceParameterSetNALUnit.length);
+                byteBuffer.put(sequenceParameterSetNALUnit);
+            }
+            IsoTypeWriter.writeUInt8(byteBuffer, pictureParameterSets.size());
+            for (byte[] pictureParameterSetNALUnit : pictureParameterSets) {
+                IsoTypeWriter.writeUInt16(byteBuffer, pictureParameterSetNALUnit.length);
+                byteBuffer.put(pictureParameterSetNALUnit);
+            }
+            if (hasExts && (avcProfileIndication == 100 || avcProfileIndication == 110 || avcProfileIndication == 122 || avcProfileIndication == 144)) {
+
+                bwb = new BitWriterBuffer(byteBuffer);
+                bwb.writeBits(chromaFormatPaddingBits, 6);
+                bwb.writeBits(chromaFormat, 2);
+                bwb.writeBits(bitDepthLumaMinus8PaddingBits, 5);
+                bwb.writeBits(bitDepthLumaMinus8, 3);
+                bwb.writeBits(bitDepthChromaMinus8PaddingBits, 5);
+                bwb.writeBits(bitDepthChromaMinus8, 3);
+                for (byte[] sequenceParameterSetExtNALUnit : sequenceParameterSetExts) {
+                    IsoTypeWriter.writeUInt16(byteBuffer, sequenceParameterSetExtNALUnit.length);
+                    byteBuffer.put(sequenceParameterSetExtNALUnit);
+                }
+            }
+        }
+
+        public long getContentSize() {
+            long size = 5;
+            size += 1; // sequenceParamsetLength
+            for (byte[] sequenceParameterSetNALUnit : sequenceParameterSets) {
+                size += 2; //lengthSizeMinusOne field
+                size += sequenceParameterSetNALUnit.length;
+            }
+            size += 1; // pictureParamsetLength
+            for (byte[] pictureParameterSetNALUnit : pictureParameterSets) {
+                size += 2; //lengthSizeMinusOne field
+                size += pictureParameterSetNALUnit.length;
+            }
+            if (hasExts && (avcProfileIndication == 100 || avcProfileIndication == 110 || avcProfileIndication == 122 || avcProfileIndication == 144)) {
+                size += 4;
+                for (byte[] sequenceParameterSetExtNALUnit : sequenceParameterSetExts) {
+                    size += 2;
+                    size += sequenceParameterSetExtNALUnit.length;
+                }
+            }
+
+            return size;
+        }
+
+        public String[] getPPS() {
+            ArrayList<String> l = new ArrayList<String>();
+            for (byte[] pictureParameterSet : pictureParameterSets) {
+                String details = "not parsable";
+                try {
+                    details = PictureParameterSet.read(pictureParameterSet).toString();
+                } catch (IOException e) {
+                    throw new RuntimeException(e);
+                }
+
+                l.add(details);
+            }
+            return l.toArray(new String[l.size()]);
+        }
+
+        public String[] getSPS() {
+            ArrayList<String> l = new ArrayList<String>();
+            for (byte[] sequenceParameterSet : sequenceParameterSets) {
+                String detail = "not parsable";
+                try {
+                    detail = SeqParameterSet.read(new ByteArrayInputStream(sequenceParameterSet)).toString();
+                } catch (IOException e) {
+
+                }
+                l.add(detail);
+            }
+            return l.toArray(new String[l.size()]);
+        }
+
+        public List<String> getSequenceParameterSetsAsStrings() {
+            List <String> result = new ArrayList<String>(sequenceParameterSets.size());
+            for (byte[] parameterSet : sequenceParameterSets) {
+                result.add(Hex.encodeHex(parameterSet));
+            }
+            return result;
+        }
+
+        public List<String> getSequenceParameterSetExtsAsStrings() {
+            List <String> result = new ArrayList<String>(sequenceParameterSetExts.size());
+            for (byte[] parameterSet : sequenceParameterSetExts) {
+                result.add(Hex.encodeHex(parameterSet));
+            }
+            return result;
+        }
+
+        public List<String> getPictureParameterSetsAsStrings() {
+            List <String> result = new ArrayList<String>(pictureParameterSets.size());
+            for (byte[] parameterSet : pictureParameterSets) {
+                result.add(Hex.encodeHex(parameterSet));
+            }
+            return result;
+        }
+
+    }
+}
+
diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/h264/AvcConfigurationBox.java b/isoparser/src/main/java/com/coremedia/iso/boxes/h264/AvcConfigurationBox.java
new file mode 100644
index 0000000..52f3695
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/h264/AvcConfigurationBox.java
@@ -0,0 +1,378 @@
+/*  
+ * Copyright 2008 CoreMedia AG, Hamburg
+ *
+ * Licensed under the Apache License, Version 2.0 (the License); 
+ * you may not use this file except in compliance with the License. 
+ * You may obtain a copy of the License at 
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0 
+ * 
+ * Unless required by applicable law or agreed to in writing, software 
+ * distributed under the License is distributed on an AS IS BASIS, 
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+ * See the License for the specific language governing permissions and 
+ * limitations under the License. 
+ */
+
+package com.coremedia.iso.boxes.h264;
+
+import com.coremedia.iso.Hex;
+import com.coremedia.iso.IsoTypeReader;
+import com.coremedia.iso.IsoTypeWriter;
+import com.googlecode.mp4parser.AbstractBox;
+import com.googlecode.mp4parser.boxes.mp4.objectdescriptors.BitReaderBuffer;
+import com.googlecode.mp4parser.boxes.mp4.objectdescriptors.BitWriterBuffer;
+import com.googlecode.mp4parser.h264.model.PictureParameterSet;
+import com.googlecode.mp4parser.h264.model.SeqParameterSet;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * Defined in ISO/IEC 14496-15:2004.
+ */
+public final class AvcConfigurationBox extends AbstractBox {
+    public static final String TYPE = "avcC";
+
+    public AVCDecoderConfigurationRecord avcDecoderConfigurationRecord = new AVCDecoderConfigurationRecord();
+
+
+    public AvcConfigurationBox() {
+        super(TYPE);
+    }
+
+    public int getConfigurationVersion() {
+        return avcDecoderConfigurationRecord.configurationVersion;
+    }
+
+    public int getAvcProfileIndication() {
+        return avcDecoderConfigurationRecord.avcProfileIndication;
+    }
+
+    public int getProfileCompatibility() {
+        return avcDecoderConfigurationRecord.profileCompatibility;
+    }
+
+    public int getAvcLevelIndication() {
+        return avcDecoderConfigurationRecord.avcLevelIndication;
+    }
+
+    public int getLengthSizeMinusOne() {
+        return avcDecoderConfigurationRecord.lengthSizeMinusOne;
+    }
+
+    public List<byte[]> getSequenceParameterSets() {
+        return Collections.unmodifiableList(avcDecoderConfigurationRecord.sequenceParameterSets);
+    }
+
+    public List<byte[]> getPictureParameterSets() {
+        return Collections.unmodifiableList(avcDecoderConfigurationRecord.pictureParameterSets);
+    }
+
+    public void setConfigurationVersion(int configurationVersion) {
+        this.avcDecoderConfigurationRecord.configurationVersion = configurationVersion;
+    }
+
+    public void setAvcProfileIndication(int avcProfileIndication) {
+        this.avcDecoderConfigurationRecord.avcProfileIndication = avcProfileIndication;
+    }
+
+    public void setProfileCompatibility(int profileCompatibility) {
+        this.avcDecoderConfigurationRecord.profileCompatibility = profileCompatibility;
+    }
+
+    public void setAvcLevelIndication(int avcLevelIndication) {
+        this.avcDecoderConfigurationRecord.avcLevelIndication = avcLevelIndication;
+    }
+
+    public void setLengthSizeMinusOne(int lengthSizeMinusOne) {
+        this.avcDecoderConfigurationRecord.lengthSizeMinusOne = lengthSizeMinusOne;
+    }
+
+    public void setSequenceParameterSets(List<byte[]> sequenceParameterSets) {
+        this.avcDecoderConfigurationRecord.sequenceParameterSets = sequenceParameterSets;
+    }
+
+    public void setPictureParameterSets(List<byte[]> pictureParameterSets) {
+        this.avcDecoderConfigurationRecord.pictureParameterSets = pictureParameterSets;
+    }
+
+    public int getChromaFormat() {
+        return avcDecoderConfigurationRecord.chromaFormat;
+    }
+
+    public void setChromaFormat(int chromaFormat) {
+        this.avcDecoderConfigurationRecord.chromaFormat = chromaFormat;
+    }
+
+    public int getBitDepthLumaMinus8() {
+        return avcDecoderConfigurationRecord.bitDepthLumaMinus8;
+    }
+
+    public void setBitDepthLumaMinus8(int bitDepthLumaMinus8) {
+        this.avcDecoderConfigurationRecord.bitDepthLumaMinus8 = bitDepthLumaMinus8;
+    }
+
+    public int getBitDepthChromaMinus8() {
+        return avcDecoderConfigurationRecord.bitDepthChromaMinus8;
+    }
+
+    public void setBitDepthChromaMinus8(int bitDepthChromaMinus8) {
+        this.avcDecoderConfigurationRecord.bitDepthChromaMinus8 = bitDepthChromaMinus8;
+    }
+
+    public List<byte[]> getSequenceParameterSetExts() {
+        return avcDecoderConfigurationRecord.sequenceParameterSetExts;
+    }
+
+    public void setSequenceParameterSetExts(List<byte[]> sequenceParameterSetExts) {
+        this.avcDecoderConfigurationRecord.sequenceParameterSetExts = sequenceParameterSetExts;
+    }
+
+    public boolean hasExts() {
+        return avcDecoderConfigurationRecord.hasExts;
+    }
+
+    public void setHasExts(boolean hasExts) {
+        this.avcDecoderConfigurationRecord.hasExts = hasExts;
+    }
+
+    @Override
+    public void _parseDetails(ByteBuffer content) {
+        avcDecoderConfigurationRecord = new AVCDecoderConfigurationRecord(content);
+    }
+
+
+    @Override
+    public long getContentSize() {
+        return avcDecoderConfigurationRecord.getContentSize();
+    }
+
+
+    @Override
+    public void getContent(ByteBuffer byteBuffer) {
+        avcDecoderConfigurationRecord.getContent(byteBuffer);
+    }
+
+    // just to display sps in isoviewer no practical use
+    public String[] getSPS() {
+        return avcDecoderConfigurationRecord.getSPS();
+    }
+
+    public String[] getPPS() {
+        return avcDecoderConfigurationRecord.getPPS();
+    }
+
+    public List<String> getSequenceParameterSetsAsStrings() {
+        return avcDecoderConfigurationRecord.getSequenceParameterSetsAsStrings();
+    }
+
+    public List<String> getSequenceParameterSetExtsAsStrings() {
+        return avcDecoderConfigurationRecord.getSequenceParameterSetExtsAsStrings();
+    }
+
+    public List<String> getPictureParameterSetsAsStrings() {
+        return avcDecoderConfigurationRecord.getPictureParameterSetsAsStrings();
+    }
+
+    public AVCDecoderConfigurationRecord getavcDecoderConfigurationRecord() {
+        return avcDecoderConfigurationRecord;
+    }
+
+
+    public static class AVCDecoderConfigurationRecord {
+        public int configurationVersion;
+        public int avcProfileIndication;
+        public int profileCompatibility;
+        public int avcLevelIndication;
+        public int lengthSizeMinusOne;
+        public List<byte[]> sequenceParameterSets = new ArrayList<byte[]>();
+        public List<byte[]> pictureParameterSets = new ArrayList<byte[]>();
+
+        public boolean hasExts = true;
+        public int chromaFormat = 1;
+        public int bitDepthLumaMinus8 = 0;
+        public int bitDepthChromaMinus8 = 0;
+        public List<byte[]> sequenceParameterSetExts = new ArrayList<byte[]>();
+
+        /**
+         * Just for non-spec-conform encoders
+         */
+        public int lengthSizeMinusOnePaddingBits = 60;
+        public int numberOfSequenceParameterSetsPaddingBits = 7;
+        public int chromaFormatPaddingBits = 31;
+        public int bitDepthLumaMinus8PaddingBits = 31;
+        public int bitDepthChromaMinus8PaddingBits = 31;
+
+        public AVCDecoderConfigurationRecord() {
+        }
+
+        public AVCDecoderConfigurationRecord(ByteBuffer content) {
+            configurationVersion = IsoTypeReader.readUInt8(content);
+            avcProfileIndication = IsoTypeReader.readUInt8(content);
+            profileCompatibility = IsoTypeReader.readUInt8(content);
+            avcLevelIndication = IsoTypeReader.readUInt8(content);
+            BitReaderBuffer brb = new BitReaderBuffer(content);
+            lengthSizeMinusOnePaddingBits = brb.readBits(6);
+            lengthSizeMinusOne = brb.readBits(2);
+            numberOfSequenceParameterSetsPaddingBits = brb.readBits(3);
+            int numberOfSeuqenceParameterSets = brb.readBits(5);
+            for (int i = 0; i < numberOfSeuqenceParameterSets; i++) {
+                int sequenceParameterSetLength = IsoTypeReader.readUInt16(content);
+
+                byte[] sequenceParameterSetNALUnit = new byte[sequenceParameterSetLength];
+                content.get(sequenceParameterSetNALUnit);
+                sequenceParameterSets.add(sequenceParameterSetNALUnit);
+            }
+            long numberOfPictureParameterSets = IsoTypeReader.readUInt8(content);
+            for (int i = 0; i < numberOfPictureParameterSets; i++) {
+                int pictureParameterSetLength = IsoTypeReader.readUInt16(content);
+                byte[] pictureParameterSetNALUnit = new byte[pictureParameterSetLength];
+                content.get(pictureParameterSetNALUnit);
+                pictureParameterSets.add(pictureParameterSetNALUnit);
+            }
+            if (content.remaining() < 4) {
+                hasExts = false;
+            }
+            if (hasExts && (avcProfileIndication == 100 || avcProfileIndication == 110 || avcProfileIndication == 122 || avcProfileIndication == 144)) {
+                // actually only some bits are interesting so masking with & x would be good but not all Mp4 creating tools set the reserved bits to 1.
+                // So we need to store all bits
+                brb = new BitReaderBuffer(content);
+                chromaFormatPaddingBits = brb.readBits(6);
+                chromaFormat = brb.readBits(2);
+                bitDepthLumaMinus8PaddingBits = brb.readBits(5);
+                bitDepthLumaMinus8 = brb.readBits(3);
+                bitDepthChromaMinus8PaddingBits = brb.readBits(5);
+                bitDepthChromaMinus8 = brb.readBits(3);
+                long numOfSequenceParameterSetExt = IsoTypeReader.readUInt8(content);
+                for (int i = 0; i < numOfSequenceParameterSetExt; i++) {
+                    int sequenceParameterSetExtLength = IsoTypeReader.readUInt16(content);
+                    byte[] sequenceParameterSetExtNALUnit = new byte[sequenceParameterSetExtLength];
+                    content.get(sequenceParameterSetExtNALUnit);
+                    sequenceParameterSetExts.add(sequenceParameterSetExtNALUnit);
+                }
+            } else {
+                chromaFormat = -1;
+                bitDepthLumaMinus8 = -1;
+                bitDepthChromaMinus8 = -1;
+            }
+        }
+
+        public void getContent(ByteBuffer byteBuffer) {
+            IsoTypeWriter.writeUInt8(byteBuffer, configurationVersion);
+            IsoTypeWriter.writeUInt8(byteBuffer, avcProfileIndication);
+            IsoTypeWriter.writeUInt8(byteBuffer, profileCompatibility);
+            IsoTypeWriter.writeUInt8(byteBuffer, avcLevelIndication);
+            BitWriterBuffer bwb = new BitWriterBuffer(byteBuffer);
+            bwb.writeBits(lengthSizeMinusOnePaddingBits, 6);
+            bwb.writeBits(lengthSizeMinusOne, 2);
+            bwb.writeBits(numberOfSequenceParameterSetsPaddingBits, 3);
+            bwb.writeBits(pictureParameterSets.size(), 5);
+            for (byte[] sequenceParameterSetNALUnit : sequenceParameterSets) {
+                IsoTypeWriter.writeUInt16(byteBuffer, sequenceParameterSetNALUnit.length);
+                byteBuffer.put(sequenceParameterSetNALUnit);
+            }
+            IsoTypeWriter.writeUInt8(byteBuffer, pictureParameterSets.size());
+            for (byte[] pictureParameterSetNALUnit : pictureParameterSets) {
+                IsoTypeWriter.writeUInt16(byteBuffer, pictureParameterSetNALUnit.length);
+                byteBuffer.put(pictureParameterSetNALUnit);
+            }
+            if (hasExts && (avcProfileIndication == 100 || avcProfileIndication == 110 || avcProfileIndication == 122 || avcProfileIndication == 144)) {
+
+                bwb = new BitWriterBuffer(byteBuffer);
+                bwb.writeBits(chromaFormatPaddingBits, 6);
+                bwb.writeBits(chromaFormat, 2);
+                bwb.writeBits(bitDepthLumaMinus8PaddingBits, 5);
+                bwb.writeBits(bitDepthLumaMinus8, 3);
+                bwb.writeBits(bitDepthChromaMinus8PaddingBits, 5);
+                bwb.writeBits(bitDepthChromaMinus8, 3);
+                for (byte[] sequenceParameterSetExtNALUnit : sequenceParameterSetExts) {
+                    IsoTypeWriter.writeUInt16(byteBuffer, sequenceParameterSetExtNALUnit.length);
+                    byteBuffer.put(sequenceParameterSetExtNALUnit);
+                }
+            }
+        }
+
+        public long getContentSize() {
+            long size = 5;
+            size += 1; // sequenceParamsetLength
+            for (byte[] sequenceParameterSetNALUnit : sequenceParameterSets) {
+                size += 2; //lengthSizeMinusOne field
+                size += sequenceParameterSetNALUnit.length;
+            }
+            size += 1; // pictureParamsetLength
+            for (byte[] pictureParameterSetNALUnit : pictureParameterSets) {
+                size += 2; //lengthSizeMinusOne field
+                size += pictureParameterSetNALUnit.length;
+            }
+            if (hasExts && (avcProfileIndication == 100 || avcProfileIndication == 110 || avcProfileIndication == 122 || avcProfileIndication == 144)) {
+                size += 4;
+                for (byte[] sequenceParameterSetExtNALUnit : sequenceParameterSetExts) {
+                    size += 2;
+                    size += sequenceParameterSetExtNALUnit.length;
+                }
+            }
+
+            return size;
+        }
+
+        public String[] getPPS() {
+            ArrayList<String> l = new ArrayList<String>();
+            for (byte[] pictureParameterSet : pictureParameterSets) {
+                String details = "not parsable";
+                try {
+                    details = PictureParameterSet.read(pictureParameterSet).toString();
+                } catch (IOException e) {
+                    throw new RuntimeException(e);
+                }
+
+                l.add(details);
+            }
+            return l.toArray(new String[l.size()]);
+        }
+
+        public String[] getSPS() {
+            ArrayList<String> l = new ArrayList<String>();
+            for (byte[] sequenceParameterSet : sequenceParameterSets) {
+                String detail = "not parsable";
+                try {
+                    detail = SeqParameterSet.read(new ByteArrayInputStream(sequenceParameterSet)).toString();
+                } catch (IOException e) {
+
+                }
+                l.add(detail);
+            }
+            return l.toArray(new String[l.size()]);
+        }
+
+        public List<String> getSequenceParameterSetsAsStrings() {
+            List <String> result = new ArrayList<String>(sequenceParameterSets.size());
+            for (byte[] parameterSet : sequenceParameterSets) {
+                result.add(Hex.encodeHex(parameterSet));
+            }
+            return result;
+        }
+
+        public List<String> getSequenceParameterSetExtsAsStrings() {
+            List <String> result = new ArrayList<String>(sequenceParameterSetExts.size());
+            for (byte[] parameterSet : sequenceParameterSetExts) {
+                result.add(Hex.encodeHex(parameterSet));
+            }
+            return result;
+        }
+
+        public List<String> getPictureParameterSetsAsStrings() {
+            List <String> result = new ArrayList<String>(pictureParameterSets.size());
+            for (byte[] parameterSet : pictureParameterSets) {
+                result.add(Hex.encodeHex(parameterSet));
+            }
+            return result;
+        }
+
+    }
+}
+
diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/mdat/.svn/all-wcprops b/isoparser/src/main/java/com/coremedia/iso/boxes/mdat/.svn/all-wcprops
new file mode 100644
index 0000000..238325a
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/mdat/.svn/all-wcprops
@@ -0,0 +1,23 @@
+K 25
+svn:wc:ra_dav:version-url
+V 76
+/svn/!svn/ver/772/trunk/isoparser/src/main/java/com/coremedia/iso/boxes/mdat
+END
+MediaDataBox.java
+K 25
+svn:wc:ra_dav:version-url
+V 94
+/svn/!svn/ver/772/trunk/isoparser/src/main/java/com/coremedia/iso/boxes/mdat/MediaDataBox.java
+END
+DummyMap.java
+K 25
+svn:wc:ra_dav:version-url
+V 90
+/svn/!svn/ver/377/trunk/isoparser/src/main/java/com/coremedia/iso/boxes/mdat/DummyMap.java
+END
+SampleList.java
+K 25
+svn:wc:ra_dav:version-url
+V 92
+/svn/!svn/ver/671/trunk/isoparser/src/main/java/com/coremedia/iso/boxes/mdat/SampleList.java
+END
diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/mdat/.svn/entries b/isoparser/src/main/java/com/coremedia/iso/boxes/mdat/.svn/entries
new file mode 100644
index 0000000..7dc6a8e
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/mdat/.svn/entries
@@ -0,0 +1,130 @@
+10
+
+dir
+778
+http://mp4parser.googlecode.com/svn/trunk/isoparser/src/main/java/com/coremedia/iso/boxes/mdat
+http://mp4parser.googlecode.com/svn
+
+
+
+2012-09-01T02:22:41.253285Z
+772
+michael.stattmann@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+7decde4b-c250-0410-a0da-51896bc88be6
+
+MediaDataBox.java
+file
+
+
+
+
+2012-09-14T17:27:52.567248Z
+9805155611e85fdee88d368ada02bbdb
+2012-09-01T02:22:41.253285Z
+772
+michael.stattmann@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+7442
+
+DummyMap.java
+file
+
+
+
+
+2012-09-14T17:27:52.567248Z
+911189888371eb0f2ae03f4e019d33c5
+2012-03-05T23:28:24.666173Z
+377
+Sebastian.Annies@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+1722
+
+SampleList.java
+file
+
+
+
+
+2012-09-14T17:27:52.567248Z
+1986183baf9f90328a4a7131cf21897d
+2012-06-10T18:50:38.971172Z
+671
+michael.stattmann@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+9770
+
diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/mdat/.svn/text-base/DummyMap.java.svn-base b/isoparser/src/main/java/com/coremedia/iso/boxes/mdat/.svn/text-base/DummyMap.java.svn-base
new file mode 100644
index 0000000..ab96023
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/mdat/.svn/text-base/DummyMap.java.svn-base
@@ -0,0 +1,84 @@
+package com.coremedia.iso.boxes.mdat;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * A SortedSet that contains just one value.
+ */
+public class DummyMap<K, V> implements Map<K, V> {
+    HashSet<K> keys = new HashSet<K>();
+    V value;
+
+    public DummyMap(V value) {
+        this.value = value;
+    }
+
+    public Comparator<? super K> comparator() {
+        return null;  // I don't have any
+    }
+
+    public void addKeys(K[] keys) {
+        Collections.addAll(this.keys, keys);
+
+    }
+
+    public int size() {
+        return keys.size();
+    }
+
+    public boolean isEmpty() {
+        return keys.isEmpty();
+    }
+
+    public boolean containsKey(Object key) {
+        return keys.contains(key);
+    }
+
+    public boolean containsValue(Object value) {
+        return this.value == value;
+    }
+
+    public V get(Object key) {
+        return keys.contains(key) ? value : null;
+    }
+
+    public V put(K key, V value) {
+        assert this.value == value;
+        keys.add(key);
+        return this.value;
+    }
+
+    public V remove(Object key) {
+        V v = get(key);
+        keys.remove(key);
+        return v;
+    }
+
+    public void putAll(Map<? extends K, ? extends V> m) {
+        for (K k : m.keySet()) {
+            assert m.get(k) == value;
+            this.keys.add(k);
+        }
+    }
+
+    public void clear() {
+        keys.clear();
+    }
+
+    public Set<K> keySet() {
+        return keys;
+    }
+
+    public Collection<V> values() {
+        throw new UnsupportedOperationException();
+    }
+
+    public Set<Entry<K, V>> entrySet() {
+        throw new UnsupportedOperationException();
+    }
+}
diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/mdat/.svn/text-base/MediaDataBox.java.svn-base b/isoparser/src/main/java/com/coremedia/iso/boxes/mdat/.svn/text-base/MediaDataBox.java.svn-base
new file mode 100644
index 0000000..5075a15
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/mdat/.svn/text-base/MediaDataBox.java.svn-base
@@ -0,0 +1,189 @@
+/*  
+ * Copyright 2008 CoreMedia AG, Hamburg
+ *
+ * Licensed under the Apache License, Version 2.0 (the License); 
+ * you may not use this file except in compliance with the License. 
+ * You may obtain a copy of the License at 
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0 
+ * 
+ * Unless required by applicable law or agreed to in writing, software 
+ * distributed under the License is distributed on an AS IS BASIS, 
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+ * See the License for the specific language governing permissions and 
+ * limitations under the License. 
+ */
+
+package com.coremedia.iso.boxes.mdat;
+
+import com.coremedia.iso.BoxParser;
+import com.coremedia.iso.ChannelHelper;
+import com.coremedia.iso.boxes.Box;
+import com.coremedia.iso.boxes.ContainerBox;
+import com.googlecode.mp4parser.AbstractBox;
+
+import java.io.IOException;
+import java.lang.ref.Reference;
+import java.lang.ref.SoftReference;
+import java.nio.ByteBuffer;
+import java.nio.channels.FileChannel;
+import java.nio.channels.ReadableByteChannel;
+import java.nio.channels.WritableByteChannel;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.logging.Logger;
+
+import static com.googlecode.mp4parser.util.CastUtils.l2i;
+
+/**
+ * This box contains the media data. In video tracks, this box would contain video frames. A presentation may
+ * contain zero or more Media Data Boxes. The actual media data follows the type field; its structure is described
+ * by the metadata (see {@link com.coremedia.iso.boxes.SampleTableBox}).<br>
+ * In large presentations, it may be desirable to have more data in this box than a 32-bit size would permit. In this
+ * case, the large variant of the size field is used.<br>
+ * There may be any number of these boxes in the file (including zero, if all the media data is in other files). The
+ * metadata refers to media data by its absolute offset within the file (see {@link com.coremedia.iso.boxes.StaticChunkOffsetBox});
+ * so Media Data Box headers and free space may easily be skipped, and files without any box structure may
+ * also be referenced and used.
+ */
+public final class MediaDataBox implements Box {
+    private static Logger LOG = Logger.getLogger(MediaDataBox.class.getName());
+
+    public static final String TYPE = "mdat";
+    public static final int BUFFER_SIZE = 10 * 1024 * 1024;
+    ContainerBox parent;
+
+    ByteBuffer header;
+
+    // These fields are for the special case of a FileChannel as input.
+    private FileChannel fileChannel;
+    private long startPosition;
+    private long contentSize;
+
+
+    private Map<Long, Reference<ByteBuffer>> cache = new HashMap<Long, Reference<ByteBuffer>>();
+
+
+    /**
+     * If the whole content is just in one mapped buffer keep a strong reference to it so it is
+     * not evicted from the cache.
+     */
+    private ByteBuffer content;
+
+    public ContainerBox getParent() {
+        return parent;
+    }
+
+    public void setParent(ContainerBox parent) {
+        this.parent = parent;
+    }
+
+    public String getType() {
+        return TYPE;
+    }
+
+    private static void transfer(FileChannel from, long position, long count, WritableByteChannel to) throws IOException {
+        long maxCount = (64 * 1024 * 1024) - (32 * 1024);
+        // Transfer data in chunks a bit less than 64MB
+        // People state that this is a kind of magic number on Windows.
+        // I don't care. The size seems reasonable.
+        long offset = 0;
+        while (offset < count) {
+            offset += from.transferTo(position + offset, Math.min(maxCount, count - offset), to);
+        }
+    }
+
+    public void getBox(WritableByteChannel writableByteChannel) throws IOException {
+        if (fileChannel != null) {
+            assert checkStillOk();
+            transfer(fileChannel, startPosition - header.limit(), contentSize + header.limit(), writableByteChannel);
+        } else {
+            header.rewind();
+            writableByteChannel.write(header);
+            writableByteChannel.write(content);
+        }
+    }
+
+    /**
+     * If someone use the same file as source and sink it could the case that
+     * inserting a few bytes before the mdat results in overwrting data we still
+     * need to write this mdat here. This method just makes sure that we haven't already
+     * overwritten the mdat contents.
+     *
+     * @return true if ok
+     */
+    private boolean checkStillOk() {
+        try {
+            fileChannel.position(startPosition - header.limit());
+            ByteBuffer h2 = ByteBuffer.allocate(header.limit());
+            fileChannel.read(h2);
+            header.rewind();
+            h2.rewind();
+            assert h2.equals(header) : "It seems that the content I want to read has already been overwritten.";
+            return true;
+        } catch (IOException e) {
+            e.printStackTrace();
+            return false;
+        }
+
+    }
+
+
+    public long getSize() {
+        long size = header.limit();
+        size += contentSize;
+        return size;
+    }
+
+    public void parse(ReadableByteChannel readableByteChannel, ByteBuffer header, long contentSize, BoxParser boxParser) throws IOException {
+        this.header = header;
+        this.contentSize = contentSize;
+
+        if (readableByteChannel instanceof FileChannel && (contentSize > AbstractBox.MEM_MAP_THRESHOLD)) {
+            this.fileChannel = ((FileChannel) readableByteChannel);
+            this.startPosition = ((FileChannel) readableByteChannel).position();
+            ((FileChannel) readableByteChannel).position(((FileChannel) readableByteChannel).position() + contentSize);
+        } else {
+            content = ChannelHelper.readFully(readableByteChannel, l2i(contentSize));
+            cache.put(0l, new SoftReference<ByteBuffer>(content));
+        }
+    }
+
+    public synchronized ByteBuffer getContent(long offset, int length) {
+
+        for (Long chacheEntryOffset : cache.keySet()) {
+            if (chacheEntryOffset <= offset && offset <= chacheEntryOffset + BUFFER_SIZE) {
+                ByteBuffer cacheEntry = cache.get(chacheEntryOffset).get();
+                if ((cacheEntry != null) && ((chacheEntryOffset + cacheEntry.limit()) >= (offset + length))) {
+                    // CACHE HIT
+                    cacheEntry.position((int) (offset - chacheEntryOffset));
+                    ByteBuffer cachedSample = cacheEntry.slice();
+                    cachedSample.limit(length);
+                    return cachedSample;
+                }
+            }
+        }
+        // CACHE MISS
+        ByteBuffer cacheEntry;
+        try {
+            // Just mapping 10MB at a time. Seems reasonable.
+            cacheEntry = fileChannel.map(FileChannel.MapMode.READ_ONLY, startPosition + offset, Math.min(BUFFER_SIZE, contentSize - offset));
+        } catch (IOException e1) {
+            LOG.fine("Even mapping just 10MB of the source file into the memory failed. " + e1);
+            throw new RuntimeException(
+                    "Delayed reading of mdat content failed. Make sure not to close " +
+                            "the FileChannel that has been used to create the IsoFile!", e1);
+        }
+        cache.put(offset, new SoftReference<ByteBuffer>(cacheEntry));
+        cacheEntry.position(0);
+        ByteBuffer cachedSample = cacheEntry.slice();
+        cachedSample.limit(length);
+        return cachedSample;
+    }
+
+
+    public ByteBuffer getHeader() {
+        return header;
+    }
+
+}
diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/mdat/.svn/text-base/SampleList.java.svn-base b/isoparser/src/main/java/com/coremedia/iso/boxes/mdat/.svn/text-base/SampleList.java.svn-base
new file mode 100644
index 0000000..a7f7b59
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/mdat/.svn/text-base/SampleList.java.svn-base
@@ -0,0 +1,227 @@
+package com.coremedia.iso.boxes.mdat;
+
+import com.coremedia.iso.IsoFile;
+import com.coremedia.iso.boxes.*;
+import com.coremedia.iso.boxes.fragment.*;
+
+import java.nio.ByteBuffer;
+import java.util.*;
+
+import static com.googlecode.mp4parser.util.CastUtils.l2i;
+
+/**
+ * Creates a list of <code>ByteBuffer</code>s that represent the samples of a given track.
+ */
+public class SampleList extends AbstractList<ByteBuffer> {
+
+
+    long[] offsets;
+    long[] sizes;
+
+    IsoFile isoFile;
+    HashMap<MediaDataBox, Long> mdatStartCache = new HashMap<MediaDataBox, Long>();
+    HashMap<MediaDataBox, Long> mdatEndCache = new HashMap<MediaDataBox, Long>();
+    MediaDataBox[] mdats;
+
+    /**
+     * Gets a sorted random access optimized list of all sample offsets.
+     * Basically it is a map from sample number to sample offset.
+     *
+     * @return the sorted list of sample offsets
+     */
+    public long[] getOffsetKeys() {
+        return offsets;
+    }
+
+
+    public SampleList(TrackBox trackBox) {
+        initIsoFile(trackBox.getIsoFile()); // where are we?
+
+        // first we get all sample from the 'normal' MP4 part.
+        // if there are none - no problem.
+        SampleSizeBox sampleSizeBox = trackBox.getSampleTableBox().getSampleSizeBox();
+        ChunkOffsetBox chunkOffsetBox = trackBox.getSampleTableBox().getChunkOffsetBox();
+        SampleToChunkBox sampleToChunkBox = trackBox.getSampleTableBox().getSampleToChunkBox();
+
+
+        final long[] chunkOffsets = chunkOffsetBox != null ? chunkOffsetBox.getChunkOffsets() : new long[0];
+        if (sampleToChunkBox != null && sampleToChunkBox.getEntries().size() > 0 &&
+                chunkOffsets.length > 0 && sampleSizeBox != null && sampleSizeBox.getSampleCount() > 0) {
+            long[] numberOfSamplesInChunk = sampleToChunkBox.blowup(chunkOffsets.length);
+
+            int sampleIndex = 0;
+
+            if (sampleSizeBox.getSampleSize() > 0) {
+                sizes = new long[l2i(sampleSizeBox.getSampleCount())];
+                Arrays.fill(sizes, sampleSizeBox.getSampleSize());
+            } else {
+                sizes = sampleSizeBox.getSampleSizes();
+            }
+            offsets = new long[sizes.length];
+
+                for (int i = 0; i < numberOfSamplesInChunk.length; i++) {
+                    long thisChunksNumberOfSamples = numberOfSamplesInChunk[i];
+                long sampleOffset = chunkOffsets[i];
+                    for (int j = 0; j < thisChunksNumberOfSamples; j++) {
+                    long sampleSize = sizes[sampleIndex];
+                    offsets[sampleIndex] = sampleOffset;
+                        sampleOffset += sampleSize;
+                        sampleIndex++;
+                    }
+                }
+
+            }
+
+        // Next we add all samples from the fragments
+        // in most cases - I've never seen it different it's either normal or fragmented.        
+        List<MovieExtendsBox> movieExtendsBoxes = trackBox.getParent().getBoxes(MovieExtendsBox.class);
+
+        if (movieExtendsBoxes.size() > 0) {
+            Map<Long, Long> offsets2Sizes = new HashMap<Long, Long>();
+            List<TrackExtendsBox> trackExtendsBoxes = movieExtendsBoxes.get(0).getBoxes(TrackExtendsBox.class);
+            for (TrackExtendsBox trackExtendsBox : trackExtendsBoxes) {
+                if (trackExtendsBox.getTrackId() == trackBox.getTrackHeaderBox().getTrackId()) {
+                    for (MovieFragmentBox movieFragmentBox : trackBox.getIsoFile().getBoxes(MovieFragmentBox.class)) {
+                        offsets2Sizes.putAll(getOffsets(movieFragmentBox, trackBox.getTrackHeaderBox().getTrackId(), trackExtendsBox));
+                    }
+                }
+            }
+            
+            if (sizes == null || offsets == null) {
+                sizes = new long[0];
+                offsets = new long[0];
+            }
+            
+            splitToArrays(offsets2Sizes);
+        }
+        
+        // We have now a map from all sample offsets to their sizes
+    }
+
+    private void splitToArrays(Map<Long, Long> offsets2Sizes) {
+        List<Long> keys = new ArrayList<Long>(offsets2Sizes.keySet());
+        Collections.sort(keys);
+
+        long[] nuSizes = new long[sizes.length + keys.size()];
+        System.arraycopy(sizes, 0, nuSizes, 0, sizes.length);
+        long[] nuOffsets = new long[offsets.length + keys.size()];
+        System.arraycopy(offsets, 0, nuOffsets, 0, offsets.length);
+        for (int i = 0; i < keys.size(); i++) {
+            nuOffsets[i + offsets.length] = keys.get(i);
+            nuSizes[i + sizes.length] = offsets2Sizes.get(keys.get(i));
+        }
+        sizes = nuSizes;
+        offsets = nuOffsets;
+    }
+    
+    public SampleList(TrackFragmentBox traf) {
+        sizes = new long[0];
+        offsets = new long[0];
+        Map<Long, Long> offsets2Sizes = new HashMap<Long, Long>();
+        initIsoFile(traf.getIsoFile());
+
+        final List<MovieFragmentBox> movieFragmentBoxList = isoFile.getBoxes(MovieFragmentBox.class);
+
+        final long trackId = traf.getTrackFragmentHeaderBox().getTrackId();
+        for (MovieFragmentBox moof : movieFragmentBoxList) {
+            final List<TrackFragmentHeaderBox> trackFragmentHeaderBoxes = moof.getTrackFragmentHeaderBoxes();
+            for (TrackFragmentHeaderBox tfhd : trackFragmentHeaderBoxes) {
+                if (tfhd.getTrackId() == trackId) {
+                    offsets2Sizes.putAll(getOffsets(moof, trackId, null));
+                }
+            }
+        }
+        splitToArrays(offsets2Sizes);
+    }
+
+    private void initIsoFile(IsoFile isoFile) {
+        this.isoFile = isoFile;
+        // find all mdats first to be able to use them later with explicitly looking them up
+        long currentOffset = 0;
+        LinkedList<MediaDataBox> mdats = new LinkedList<MediaDataBox>();
+        for (Box b : this.isoFile.getBoxes()) {
+            long currentSize = b.getSize();
+            if ("mdat".equals(b.getType())) {
+                if (b instanceof MediaDataBox) {
+                    long contentOffset = currentOffset + ((MediaDataBox) b).getHeader().limit();
+                    mdatStartCache.put((MediaDataBox) b, contentOffset);
+                    mdatEndCache.put((MediaDataBox) b, contentOffset + currentSize);
+                    mdats.add((MediaDataBox) b);
+                } else {
+                    throw new RuntimeException("Sample need to be in mdats and mdats need to be instanceof MediaDataBox");
+                }
+            }
+            currentOffset += currentSize;
+        }
+        this.mdats = mdats.toArray(new MediaDataBox[mdats.size()]);
+    }
+
+
+    @Override
+    public int size() {
+        return sizes.length;
+    }
+
+
+    @Override
+    public ByteBuffer get(int index) {
+        // it is a two stage lookup: from index to offset to size
+        long offset = offsets[index];
+        int sampleSize = l2i(sizes[index]);
+
+        for (MediaDataBox mediaDataBox : mdats) {
+            long start = mdatStartCache.get(mediaDataBox);
+            long end = mdatEndCache.get(mediaDataBox);
+            if ((start <= offset) && (offset + sampleSize <= end)) {
+                return mediaDataBox.getContent(offset - start, sampleSize);
+            }
+        }
+
+        throw new RuntimeException("The sample with offset " + offset + " and size " + sampleSize + " is NOT located within an mdat");
+    }
+
+    Map<Long, Long> getOffsets(MovieFragmentBox moof, long trackId, TrackExtendsBox trex) {
+        Map<Long, Long> offsets2Sizes = new HashMap<Long, Long>();
+        List<TrackFragmentBox> traf = moof.getBoxes(TrackFragmentBox.class);
+        for (TrackFragmentBox trackFragmentBox : traf) {
+            if (trackFragmentBox.getTrackFragmentHeaderBox().getTrackId() == trackId) {
+                long baseDataOffset;
+                if (trackFragmentBox.getTrackFragmentHeaderBox().hasBaseDataOffset()) {
+                    baseDataOffset = trackFragmentBox.getTrackFragmentHeaderBox().getBaseDataOffset();
+                } else {
+                    baseDataOffset = moof.getOffset();
+                }
+
+                for (TrackRunBox trun : trackFragmentBox.getBoxes(TrackRunBox.class)) {
+                    long sampleBaseOffset = baseDataOffset + trun.getDataOffset();
+                    final TrackFragmentHeaderBox tfhd = ((TrackFragmentBox) trun.getParent()).getTrackFragmentHeaderBox();
+
+                    long offset = 0;
+                    for (TrackRunBox.Entry entry : trun.getEntries()) {
+                        final long sampleSize;
+                        if (trun.isSampleSizePresent()) {
+                            sampleSize = entry.getSampleSize();
+                            offsets2Sizes.put(offset + sampleBaseOffset, sampleSize);
+                            offset += sampleSize;
+                        } else {
+                            if (tfhd.hasDefaultSampleSize()) {
+                                sampleSize = tfhd.getDefaultSampleSize();
+                                offsets2Sizes.put(offset + sampleBaseOffset, sampleSize);
+                                offset += sampleSize;
+                            } else {
+                                if (trex == null) {
+                                    throw new RuntimeException("File doesn't contain trex box but track fragments aren't fully self contained. Cannot determine sample size.");
+                                }
+                                sampleSize = trex.getDefaultSampleSize();
+                                offsets2Sizes.put(offset + sampleBaseOffset, sampleSize);
+                                offset += sampleSize;
+                            }
+                        }
+                    }
+                }
+            }
+        }
+        return offsets2Sizes;
+    }
+
+}
\ No newline at end of file
diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/mdat/DummyMap.java b/isoparser/src/main/java/com/coremedia/iso/boxes/mdat/DummyMap.java
new file mode 100644
index 0000000..ab96023
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/mdat/DummyMap.java
@@ -0,0 +1,84 @@
+package com.coremedia.iso.boxes.mdat;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * A SortedSet that contains just one value.
+ */
+public class DummyMap<K, V> implements Map<K, V> {
+    HashSet<K> keys = new HashSet<K>();
+    V value;
+
+    public DummyMap(V value) {
+        this.value = value;
+    }
+
+    public Comparator<? super K> comparator() {
+        return null;  // I don't have any
+    }
+
+    public void addKeys(K[] keys) {
+        Collections.addAll(this.keys, keys);
+
+    }
+
+    public int size() {
+        return keys.size();
+    }
+
+    public boolean isEmpty() {
+        return keys.isEmpty();
+    }
+
+    public boolean containsKey(Object key) {
+        return keys.contains(key);
+    }
+
+    public boolean containsValue(Object value) {
+        return this.value == value;
+    }
+
+    public V get(Object key) {
+        return keys.contains(key) ? value : null;
+    }
+
+    public V put(K key, V value) {
+        assert this.value == value;
+        keys.add(key);
+        return this.value;
+    }
+
+    public V remove(Object key) {
+        V v = get(key);
+        keys.remove(key);
+        return v;
+    }
+
+    public void putAll(Map<? extends K, ? extends V> m) {
+        for (K k : m.keySet()) {
+            assert m.get(k) == value;
+            this.keys.add(k);
+        }
+    }
+
+    public void clear() {
+        keys.clear();
+    }
+
+    public Set<K> keySet() {
+        return keys;
+    }
+
+    public Collection<V> values() {
+        throw new UnsupportedOperationException();
+    }
+
+    public Set<Entry<K, V>> entrySet() {
+        throw new UnsupportedOperationException();
+    }
+}
diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/mdat/MediaDataBox.java b/isoparser/src/main/java/com/coremedia/iso/boxes/mdat/MediaDataBox.java
new file mode 100644
index 0000000..5075a15
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/mdat/MediaDataBox.java
@@ -0,0 +1,189 @@
+/*  
+ * Copyright 2008 CoreMedia AG, Hamburg
+ *
+ * Licensed under the Apache License, Version 2.0 (the License); 
+ * you may not use this file except in compliance with the License. 
+ * You may obtain a copy of the License at 
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0 
+ * 
+ * Unless required by applicable law or agreed to in writing, software 
+ * distributed under the License is distributed on an AS IS BASIS, 
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+ * See the License for the specific language governing permissions and 
+ * limitations under the License. 
+ */
+
+package com.coremedia.iso.boxes.mdat;
+
+import com.coremedia.iso.BoxParser;
+import com.coremedia.iso.ChannelHelper;
+import com.coremedia.iso.boxes.Box;
+import com.coremedia.iso.boxes.ContainerBox;
+import com.googlecode.mp4parser.AbstractBox;
+
+import java.io.IOException;
+import java.lang.ref.Reference;
+import java.lang.ref.SoftReference;
+import java.nio.ByteBuffer;
+import java.nio.channels.FileChannel;
+import java.nio.channels.ReadableByteChannel;
+import java.nio.channels.WritableByteChannel;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.logging.Logger;
+
+import static com.googlecode.mp4parser.util.CastUtils.l2i;
+
+/**
+ * This box contains the media data. In video tracks, this box would contain video frames. A presentation may
+ * contain zero or more Media Data Boxes. The actual media data follows the type field; its structure is described
+ * by the metadata (see {@link com.coremedia.iso.boxes.SampleTableBox}).<br>
+ * In large presentations, it may be desirable to have more data in this box than a 32-bit size would permit. In this
+ * case, the large variant of the size field is used.<br>
+ * There may be any number of these boxes in the file (including zero, if all the media data is in other files). The
+ * metadata refers to media data by its absolute offset within the file (see {@link com.coremedia.iso.boxes.StaticChunkOffsetBox});
+ * so Media Data Box headers and free space may easily be skipped, and files without any box structure may
+ * also be referenced and used.
+ */
+public final class MediaDataBox implements Box {
+    private static Logger LOG = Logger.getLogger(MediaDataBox.class.getName());
+
+    public static final String TYPE = "mdat";
+    public static final int BUFFER_SIZE = 10 * 1024 * 1024;
+    ContainerBox parent;
+
+    ByteBuffer header;
+
+    // These fields are for the special case of a FileChannel as input.
+    private FileChannel fileChannel;
+    private long startPosition;
+    private long contentSize;
+
+
+    private Map<Long, Reference<ByteBuffer>> cache = new HashMap<Long, Reference<ByteBuffer>>();
+
+
+    /**
+     * If the whole content is just in one mapped buffer keep a strong reference to it so it is
+     * not evicted from the cache.
+     */
+    private ByteBuffer content;
+
+    public ContainerBox getParent() {
+        return parent;
+    }
+
+    public void setParent(ContainerBox parent) {
+        this.parent = parent;
+    }
+
+    public String getType() {
+        return TYPE;
+    }
+
+    private static void transfer(FileChannel from, long position, long count, WritableByteChannel to) throws IOException {
+        long maxCount = (64 * 1024 * 1024) - (32 * 1024);
+        // Transfer data in chunks a bit less than 64MB
+        // People state that this is a kind of magic number on Windows.
+        // I don't care. The size seems reasonable.
+        long offset = 0;
+        while (offset < count) {
+            offset += from.transferTo(position + offset, Math.min(maxCount, count - offset), to);
+        }
+    }
+
+    public void getBox(WritableByteChannel writableByteChannel) throws IOException {
+        if (fileChannel != null) {
+            assert checkStillOk();
+            transfer(fileChannel, startPosition - header.limit(), contentSize + header.limit(), writableByteChannel);
+        } else {
+            header.rewind();
+            writableByteChannel.write(header);
+            writableByteChannel.write(content);
+        }
+    }
+
+    /**
+     * If someone use the same file as source and sink it could the case that
+     * inserting a few bytes before the mdat results in overwrting data we still
+     * need to write this mdat here. This method just makes sure that we haven't already
+     * overwritten the mdat contents.
+     *
+     * @return true if ok
+     */
+    private boolean checkStillOk() {
+        try {
+            fileChannel.position(startPosition - header.limit());
+            ByteBuffer h2 = ByteBuffer.allocate(header.limit());
+            fileChannel.read(h2);
+            header.rewind();
+            h2.rewind();
+            assert h2.equals(header) : "It seems that the content I want to read has already been overwritten.";
+            return true;
+        } catch (IOException e) {
+            e.printStackTrace();
+            return false;
+        }
+
+    }
+
+
+    public long getSize() {
+        long size = header.limit();
+        size += contentSize;
+        return size;
+    }
+
+    public void parse(ReadableByteChannel readableByteChannel, ByteBuffer header, long contentSize, BoxParser boxParser) throws IOException {
+        this.header = header;
+        this.contentSize = contentSize;
+
+        if (readableByteChannel instanceof FileChannel && (contentSize > AbstractBox.MEM_MAP_THRESHOLD)) {
+            this.fileChannel = ((FileChannel) readableByteChannel);
+            this.startPosition = ((FileChannel) readableByteChannel).position();
+            ((FileChannel) readableByteChannel).position(((FileChannel) readableByteChannel).position() + contentSize);
+        } else {
+            content = ChannelHelper.readFully(readableByteChannel, l2i(contentSize));
+            cache.put(0l, new SoftReference<ByteBuffer>(content));
+        }
+    }
+
+    public synchronized ByteBuffer getContent(long offset, int length) {
+
+        for (Long chacheEntryOffset : cache.keySet()) {
+            if (chacheEntryOffset <= offset && offset <= chacheEntryOffset + BUFFER_SIZE) {
+                ByteBuffer cacheEntry = cache.get(chacheEntryOffset).get();
+                if ((cacheEntry != null) && ((chacheEntryOffset + cacheEntry.limit()) >= (offset + length))) {
+                    // CACHE HIT
+                    cacheEntry.position((int) (offset - chacheEntryOffset));
+                    ByteBuffer cachedSample = cacheEntry.slice();
+                    cachedSample.limit(length);
+                    return cachedSample;
+                }
+            }
+        }
+        // CACHE MISS
+        ByteBuffer cacheEntry;
+        try {
+            // Just mapping 10MB at a time. Seems reasonable.
+            cacheEntry = fileChannel.map(FileChannel.MapMode.READ_ONLY, startPosition + offset, Math.min(BUFFER_SIZE, contentSize - offset));
+        } catch (IOException e1) {
+            LOG.fine("Even mapping just 10MB of the source file into the memory failed. " + e1);
+            throw new RuntimeException(
+                    "Delayed reading of mdat content failed. Make sure not to close " +
+                            "the FileChannel that has been used to create the IsoFile!", e1);
+        }
+        cache.put(offset, new SoftReference<ByteBuffer>(cacheEntry));
+        cacheEntry.position(0);
+        ByteBuffer cachedSample = cacheEntry.slice();
+        cachedSample.limit(length);
+        return cachedSample;
+    }
+
+
+    public ByteBuffer getHeader() {
+        return header;
+    }
+
+}
diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/mdat/SampleList.java b/isoparser/src/main/java/com/coremedia/iso/boxes/mdat/SampleList.java
new file mode 100644
index 0000000..a7f7b59
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/mdat/SampleList.java
@@ -0,0 +1,227 @@
+package com.coremedia.iso.boxes.mdat;
+
+import com.coremedia.iso.IsoFile;
+import com.coremedia.iso.boxes.*;
+import com.coremedia.iso.boxes.fragment.*;
+
+import java.nio.ByteBuffer;
+import java.util.*;
+
+import static com.googlecode.mp4parser.util.CastUtils.l2i;
+
+/**
+ * Creates a list of <code>ByteBuffer</code>s that represent the samples of a given track.
+ */
+public class SampleList extends AbstractList<ByteBuffer> {
+
+
+    long[] offsets;
+    long[] sizes;
+
+    IsoFile isoFile;
+    HashMap<MediaDataBox, Long> mdatStartCache = new HashMap<MediaDataBox, Long>();
+    HashMap<MediaDataBox, Long> mdatEndCache = new HashMap<MediaDataBox, Long>();
+    MediaDataBox[] mdats;
+
+    /**
+     * Gets a sorted random access optimized list of all sample offsets.
+     * Basically it is a map from sample number to sample offset.
+     *
+     * @return the sorted list of sample offsets
+     */
+    public long[] getOffsetKeys() {
+        return offsets;
+    }
+
+
+    public SampleList(TrackBox trackBox) {
+        initIsoFile(trackBox.getIsoFile()); // where are we?
+
+        // first we get all sample from the 'normal' MP4 part.
+        // if there are none - no problem.
+        SampleSizeBox sampleSizeBox = trackBox.getSampleTableBox().getSampleSizeBox();
+        ChunkOffsetBox chunkOffsetBox = trackBox.getSampleTableBox().getChunkOffsetBox();
+        SampleToChunkBox sampleToChunkBox = trackBox.getSampleTableBox().getSampleToChunkBox();
+
+
+        final long[] chunkOffsets = chunkOffsetBox != null ? chunkOffsetBox.getChunkOffsets() : new long[0];
+        if (sampleToChunkBox != null && sampleToChunkBox.getEntries().size() > 0 &&
+                chunkOffsets.length > 0 && sampleSizeBox != null && sampleSizeBox.getSampleCount() > 0) {
+            long[] numberOfSamplesInChunk = sampleToChunkBox.blowup(chunkOffsets.length);
+
+            int sampleIndex = 0;
+
+            if (sampleSizeBox.getSampleSize() > 0) {
+                sizes = new long[l2i(sampleSizeBox.getSampleCount())];
+                Arrays.fill(sizes, sampleSizeBox.getSampleSize());
+            } else {
+                sizes = sampleSizeBox.getSampleSizes();
+            }
+            offsets = new long[sizes.length];
+
+                for (int i = 0; i < numberOfSamplesInChunk.length; i++) {
+                    long thisChunksNumberOfSamples = numberOfSamplesInChunk[i];
+                long sampleOffset = chunkOffsets[i];
+                    for (int j = 0; j < thisChunksNumberOfSamples; j++) {
+                    long sampleSize = sizes[sampleIndex];
+                    offsets[sampleIndex] = sampleOffset;
+                        sampleOffset += sampleSize;
+                        sampleIndex++;
+                    }
+                }
+
+            }
+
+        // Next we add all samples from the fragments
+        // in most cases - I've never seen it different it's either normal or fragmented.        
+        List<MovieExtendsBox> movieExtendsBoxes = trackBox.getParent().getBoxes(MovieExtendsBox.class);
+
+        if (movieExtendsBoxes.size() > 0) {
+            Map<Long, Long> offsets2Sizes = new HashMap<Long, Long>();
+            List<TrackExtendsBox> trackExtendsBoxes = movieExtendsBoxes.get(0).getBoxes(TrackExtendsBox.class);
+            for (TrackExtendsBox trackExtendsBox : trackExtendsBoxes) {
+                if (trackExtendsBox.getTrackId() == trackBox.getTrackHeaderBox().getTrackId()) {
+                    for (MovieFragmentBox movieFragmentBox : trackBox.getIsoFile().getBoxes(MovieFragmentBox.class)) {
+                        offsets2Sizes.putAll(getOffsets(movieFragmentBox, trackBox.getTrackHeaderBox().getTrackId(), trackExtendsBox));
+                    }
+                }
+            }
+            
+            if (sizes == null || offsets == null) {
+                sizes = new long[0];
+                offsets = new long[0];
+            }
+            
+            splitToArrays(offsets2Sizes);
+        }
+        
+        // We have now a map from all sample offsets to their sizes
+    }
+
+    private void splitToArrays(Map<Long, Long> offsets2Sizes) {
+        List<Long> keys = new ArrayList<Long>(offsets2Sizes.keySet());
+        Collections.sort(keys);
+
+        long[] nuSizes = new long[sizes.length + keys.size()];
+        System.arraycopy(sizes, 0, nuSizes, 0, sizes.length);
+        long[] nuOffsets = new long[offsets.length + keys.size()];
+        System.arraycopy(offsets, 0, nuOffsets, 0, offsets.length);
+        for (int i = 0; i < keys.size(); i++) {
+            nuOffsets[i + offsets.length] = keys.get(i);
+            nuSizes[i + sizes.length] = offsets2Sizes.get(keys.get(i));
+        }
+        sizes = nuSizes;
+        offsets = nuOffsets;
+    }
+    
+    public SampleList(TrackFragmentBox traf) {
+        sizes = new long[0];
+        offsets = new long[0];
+        Map<Long, Long> offsets2Sizes = new HashMap<Long, Long>();
+        initIsoFile(traf.getIsoFile());
+
+        final List<MovieFragmentBox> movieFragmentBoxList = isoFile.getBoxes(MovieFragmentBox.class);
+
+        final long trackId = traf.getTrackFragmentHeaderBox().getTrackId();
+        for (MovieFragmentBox moof : movieFragmentBoxList) {
+            final List<TrackFragmentHeaderBox> trackFragmentHeaderBoxes = moof.getTrackFragmentHeaderBoxes();
+            for (TrackFragmentHeaderBox tfhd : trackFragmentHeaderBoxes) {
+                if (tfhd.getTrackId() == trackId) {
+                    offsets2Sizes.putAll(getOffsets(moof, trackId, null));
+                }
+            }
+        }
+        splitToArrays(offsets2Sizes);
+    }
+
+    private void initIsoFile(IsoFile isoFile) {
+        this.isoFile = isoFile;
+        // find all mdats first to be able to use them later with explicitly looking them up
+        long currentOffset = 0;
+        LinkedList<MediaDataBox> mdats = new LinkedList<MediaDataBox>();
+        for (Box b : this.isoFile.getBoxes()) {
+            long currentSize = b.getSize();
+            if ("mdat".equals(b.getType())) {
+                if (b instanceof MediaDataBox) {
+                    long contentOffset = currentOffset + ((MediaDataBox) b).getHeader().limit();
+                    mdatStartCache.put((MediaDataBox) b, contentOffset);
+                    mdatEndCache.put((MediaDataBox) b, contentOffset + currentSize);
+                    mdats.add((MediaDataBox) b);
+                } else {
+                    throw new RuntimeException("Sample need to be in mdats and mdats need to be instanceof MediaDataBox");
+                }
+            }
+            currentOffset += currentSize;
+        }
+        this.mdats = mdats.toArray(new MediaDataBox[mdats.size()]);
+    }
+
+
+    @Override
+    public int size() {
+        return sizes.length;
+    }
+
+
+    @Override
+    public ByteBuffer get(int index) {
+        // it is a two stage lookup: from index to offset to size
+        long offset = offsets[index];
+        int sampleSize = l2i(sizes[index]);
+
+        for (MediaDataBox mediaDataBox : mdats) {
+            long start = mdatStartCache.get(mediaDataBox);
+            long end = mdatEndCache.get(mediaDataBox);
+            if ((start <= offset) && (offset + sampleSize <= end)) {
+                return mediaDataBox.getContent(offset - start, sampleSize);
+            }
+        }
+
+        throw new RuntimeException("The sample with offset " + offset + " and size " + sampleSize + " is NOT located within an mdat");
+    }
+
+    Map<Long, Long> getOffsets(MovieFragmentBox moof, long trackId, TrackExtendsBox trex) {
+        Map<Long, Long> offsets2Sizes = new HashMap<Long, Long>();
+        List<TrackFragmentBox> traf = moof.getBoxes(TrackFragmentBox.class);
+        for (TrackFragmentBox trackFragmentBox : traf) {
+            if (trackFragmentBox.getTrackFragmentHeaderBox().getTrackId() == trackId) {
+                long baseDataOffset;
+                if (trackFragmentBox.getTrackFragmentHeaderBox().hasBaseDataOffset()) {
+                    baseDataOffset = trackFragmentBox.getTrackFragmentHeaderBox().getBaseDataOffset();
+                } else {
+                    baseDataOffset = moof.getOffset();
+                }
+
+                for (TrackRunBox trun : trackFragmentBox.getBoxes(TrackRunBox.class)) {
+                    long sampleBaseOffset = baseDataOffset + trun.getDataOffset();
+                    final TrackFragmentHeaderBox tfhd = ((TrackFragmentBox) trun.getParent()).getTrackFragmentHeaderBox();
+
+                    long offset = 0;
+                    for (TrackRunBox.Entry entry : trun.getEntries()) {
+                        final long sampleSize;
+                        if (trun.isSampleSizePresent()) {
+                            sampleSize = entry.getSampleSize();
+                            offsets2Sizes.put(offset + sampleBaseOffset, sampleSize);
+                            offset += sampleSize;
+                        } else {
+                            if (tfhd.hasDefaultSampleSize()) {
+                                sampleSize = tfhd.getDefaultSampleSize();
+                                offsets2Sizes.put(offset + sampleBaseOffset, sampleSize);
+                                offset += sampleSize;
+                            } else {
+                                if (trex == null) {
+                                    throw new RuntimeException("File doesn't contain trex box but track fragments aren't fully self contained. Cannot determine sample size.");
+                                }
+                                sampleSize = trex.getDefaultSampleSize();
+                                offsets2Sizes.put(offset + sampleBaseOffset, sampleSize);
+                                offset += sampleSize;
+                            }
+                        }
+                    }
+                }
+            }
+        }
+        return offsets2Sizes;
+    }
+
+}
\ No newline at end of file
diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/odf-boxes.zip b/isoparser/src/main/java/com/coremedia/iso/boxes/odf-boxes.zip
new file mode 100644
index 0000000..04e0e5e
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/odf-boxes.zip
Binary files differ
diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/rtp-boxes.zip b/isoparser/src/main/java/com/coremedia/iso/boxes/rtp-boxes.zip
new file mode 100644
index 0000000..be1a167
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/rtp-boxes.zip
Binary files differ
diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/sampleentry/.svn/all-wcprops b/isoparser/src/main/java/com/coremedia/iso/boxes/sampleentry/.svn/all-wcprops
new file mode 100644
index 0000000..8a5b647
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/sampleentry/.svn/all-wcprops
@@ -0,0 +1,53 @@
+K 25
+svn:wc:ra_dav:version-url
+V 83
+/svn/!svn/ver/757/trunk/isoparser/src/main/java/com/coremedia/iso/boxes/sampleentry
+END
+SubtitleSampleEntry.java
+K 25
+svn:wc:ra_dav:version-url
+V 108
+/svn/!svn/ver/507/trunk/isoparser/src/main/java/com/coremedia/iso/boxes/sampleentry/SubtitleSampleEntry.java
+END
+Ovc1VisualSampleEntryImpl.java
+K 25
+svn:wc:ra_dav:version-url
+V 114
+/svn/!svn/ver/507/trunk/isoparser/src/main/java/com/coremedia/iso/boxes/sampleentry/Ovc1VisualSampleEntryImpl.java
+END
+SampleEntry.java
+K 25
+svn:wc:ra_dav:version-url
+V 100
+/svn/!svn/ver/745/trunk/isoparser/src/main/java/com/coremedia/iso/boxes/sampleentry/SampleEntry.java
+END
+AudioSampleEntry.java
+K 25
+svn:wc:ra_dav:version-url
+V 105
+/svn/!svn/ver/757/trunk/isoparser/src/main/java/com/coremedia/iso/boxes/sampleentry/AudioSampleEntry.java
+END
+VisualSampleEntry.java
+K 25
+svn:wc:ra_dav:version-url
+V 106
+/svn/!svn/ver/745/trunk/isoparser/src/main/java/com/coremedia/iso/boxes/sampleentry/VisualSampleEntry.java
+END
+TextSampleEntry.java
+K 25
+svn:wc:ra_dav:version-url
+V 104
+/svn/!svn/ver/507/trunk/isoparser/src/main/java/com/coremedia/iso/boxes/sampleentry/TextSampleEntry.java
+END
+MpegSampleEntry.java
+K 25
+svn:wc:ra_dav:version-url
+V 104
+/svn/!svn/ver/507/trunk/isoparser/src/main/java/com/coremedia/iso/boxes/sampleentry/MpegSampleEntry.java
+END
+AmrSpecificBox.java
+K 25
+svn:wc:ra_dav:version-url
+V 103
+/svn/!svn/ver/507/trunk/isoparser/src/main/java/com/coremedia/iso/boxes/sampleentry/AmrSpecificBox.java
+END
diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/sampleentry/.svn/entries b/isoparser/src/main/java/com/coremedia/iso/boxes/sampleentry/.svn/entries
new file mode 100644
index 0000000..3891d06
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/sampleentry/.svn/entries
@@ -0,0 +1,300 @@
+10
+
+dir
+778
+http://mp4parser.googlecode.com/svn/trunk/isoparser/src/main/java/com/coremedia/iso/boxes/sampleentry
+http://mp4parser.googlecode.com/svn
+
+
+
+2012-08-17T05:55:12.215481Z
+757
+michael.stattmann@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+7decde4b-c250-0410-a0da-51896bc88be6
+
+SubtitleSampleEntry.java
+file
+
+
+
+
+2012-09-14T17:27:52.647249Z
+a1d02883384ec405c3d62e1a4d157b5e
+2012-04-21T22:05:38.425329Z
+507
+Sebastian.Annies@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+2055
+
+Ovc1VisualSampleEntryImpl.java
+file
+
+
+
+
+2012-09-14T17:27:52.647249Z
+c92067b340193f4ffa776fd1e449dcf5
+2012-04-21T22:05:38.425329Z
+507
+Sebastian.Annies@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+1018
+
+SampleEntry.java
+file
+
+
+
+
+2012-09-14T17:27:52.647249Z
+8d726941a0af28eaa7b3cc9abcf4bd55
+2012-08-14T19:18:50.777750Z
+745
+Sebastian.Annies@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+5020
+
+AudioSampleEntry.java
+file
+
+
+
+
+2012-09-14T17:27:52.647249Z
+3ee1365e9bd772c4e77c3011765ae58a
+2012-08-17T05:55:12.215481Z
+757
+michael.stattmann@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+8585
+
+VisualSampleEntry.java
+file
+
+
+
+
+2012-09-14T17:27:52.647249Z
+5616cce8d163f57f4e105fd3dbf34e61
+2012-08-14T19:18:50.777750Z
+745
+Sebastian.Annies@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+6899
+
+TextSampleEntry.java
+file
+
+
+
+
+2012-09-14T17:27:52.647249Z
+96794e77ef63fbcc1cb861b25ddbb784
+2012-04-21T22:05:38.425329Z
+507
+Sebastian.Annies@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+9126
+
+MpegSampleEntry.java
+file
+
+
+
+
+2012-09-14T17:27:52.647249Z
+97170f2c4511a4f03915f73d5690cb4d
+2012-04-21T22:05:38.425329Z
+507
+Sebastian.Annies@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+1079
+
+AmrSpecificBox.java
+file
+
+
+
+
+2012-09-14T17:27:52.647249Z
+c306ac7445479a0a2642022bb8428d8f
+2012-04-21T22:05:38.425329Z
+507
+Sebastian.Annies@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+2974
+
diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/sampleentry/.svn/text-base/AmrSpecificBox.java.svn-base b/isoparser/src/main/java/com/coremedia/iso/boxes/sampleentry/.svn/text-base/AmrSpecificBox.java.svn-base
new file mode 100644
index 0000000..f69de7b
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/sampleentry/.svn/text-base/AmrSpecificBox.java.svn-base
@@ -0,0 +1,101 @@
+/*  
+ * Copyright 2008 CoreMedia AG, Hamburg
+ *
+ * Licensed under the Apache License, Version 2.0 (the License); 
+ * you may not use this file except in compliance with the License. 
+ * You may obtain a copy of the License at 
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0 
+ * 
+ * Unless required by applicable law or agreed to in writing, software 
+ * distributed under the License is distributed on an AS IS BASIS, 
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+ * See the License for the specific language governing permissions and 
+ * limitations under the License. 
+ */
+
+package com.coremedia.iso.boxes.sampleentry;
+
+
+import com.coremedia.iso.IsoFile;
+import com.coremedia.iso.IsoTypeReader;
+import com.coremedia.iso.IsoTypeWriter;
+import com.googlecode.mp4parser.AbstractBox;
+
+import java.nio.ByteBuffer;
+
+/**
+ * AMR audio format specific subbox of an audio sample entry.
+ *
+ * @see com.coremedia.iso.boxes.sampleentry.AudioSampleEntry
+ */
+public class AmrSpecificBox extends AbstractBox {
+    public static final String TYPE = "damr";
+
+    private String vendor;
+    private int decoderVersion;
+    private int modeSet;
+    private int modeChangePeriod;
+    private int framesPerSample;
+
+    public AmrSpecificBox() {
+        super(TYPE);
+    }
+
+    public String getVendor() {
+        return vendor;
+    }
+
+    public int getDecoderVersion() {
+        return decoderVersion;
+    }
+
+    public int getModeSet() {
+        return modeSet;
+    }
+
+    public int getModeChangePeriod() {
+        return modeChangePeriod;
+    }
+
+    public int getFramesPerSample() {
+        return framesPerSample;
+    }
+
+    protected long getContentSize() {
+        return 9;
+    }
+
+    @Override
+    public void _parseDetails(ByteBuffer content) {
+        byte[] v = new byte[4];
+        content.get(v);
+        vendor = IsoFile.bytesToFourCC(v);
+
+        decoderVersion = IsoTypeReader.readUInt8(content);
+        modeSet = IsoTypeReader.readUInt16(content);
+        modeChangePeriod = IsoTypeReader.readUInt8(content);
+        framesPerSample = IsoTypeReader.readUInt8(content);
+
+    }
+
+
+    public void getContent(ByteBuffer byteBuffer) {
+        byteBuffer.put(IsoFile.fourCCtoBytes(vendor));
+        IsoTypeWriter.writeUInt8(byteBuffer, decoderVersion);
+        IsoTypeWriter.writeUInt16(byteBuffer, modeSet);
+        IsoTypeWriter.writeUInt8(byteBuffer, modeChangePeriod);
+        IsoTypeWriter.writeUInt8(byteBuffer, framesPerSample);
+    }
+
+    public String toString() {
+        StringBuilder buffer = new StringBuilder();
+        buffer.append("AmrSpecificBox[vendor=").append(getVendor());
+        buffer.append(";decoderVersion=").append(getDecoderVersion());
+        buffer.append(";modeSet=").append(getModeSet());
+        buffer.append(";modeChangePeriod=").append(getModeChangePeriod());
+        buffer.append(";framesPerSample=").append(getFramesPerSample());
+        buffer.append("]");
+        return buffer.toString();
+    }
+}
diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/sampleentry/.svn/text-base/AudioSampleEntry.java.svn-base b/isoparser/src/main/java/com/coremedia/iso/boxes/sampleentry/.svn/text-base/AudioSampleEntry.java.svn-base
new file mode 100644
index 0000000..69aeb79
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/sampleentry/.svn/text-base/AudioSampleEntry.java.svn-base
@@ -0,0 +1,278 @@
+/*  
+ * Copyright 2008 CoreMedia AG, Hamburg
+ *
+ * Licensed under the Apache License, Version 2.0 (the License); 
+ * you may not use this file except in compliance with the License. 
+ * You may obtain a copy of the License at 
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0 
+ * 
+ * Unless required by applicable law or agreed to in writing, software 
+ * distributed under the License is distributed on an AS IS BASIS, 
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+ * See the License for the specific language governing permissions and 
+ * limitations under the License. 
+ */
+
+package com.coremedia.iso.boxes.sampleentry;
+
+import com.coremedia.iso.BoxParser;
+import com.coremedia.iso.IsoTypeReader;
+import com.coremedia.iso.IsoTypeWriter;
+import com.coremedia.iso.boxes.Box;
+import com.coremedia.iso.boxes.ContainerBox;
+
+import java.nio.ByteBuffer;
+
+/**
+ * Contains basic information about the audio samples in this track. Format-specific information
+ * is appened as boxes after the data described in ISO/IEC 14496-12 chapter 8.16.2.
+ */
+public class AudioSampleEntry extends SampleEntry implements ContainerBox {
+
+    public static final String TYPE1 = "samr";
+    public static final String TYPE2 = "sawb";
+    public static final String TYPE3 = "mp4a";
+    public static final String TYPE4 = "drms";
+    public static final String TYPE5 = "alac";
+    public static final String TYPE7 = "owma";
+    public static final String TYPE8 = "ac-3"; /* ETSI TS 102 366 1.2.1 Annex F */
+    public static final String TYPE9 = "ec-3"; /* ETSI TS 102 366 1.2.1 Annex F */
+    public static final String TYPE10 = "mlpa";
+    public static final String TYPE11 = "dtsl";
+    public static final String TYPE12 = "dtsh";
+    public static final String TYPE13 = "dtse";
+
+    /**
+     * Identifier for an encrypted audio track.
+     *
+     * @see com.coremedia.iso.boxes.ProtectionSchemeInformationBox
+     */
+    public static final String TYPE_ENCRYPTED = "enca";
+
+    private int channelCount;
+    private int sampleSize;
+    private long sampleRate;
+    private int soundVersion;
+    private int compressionId;
+    private int packetSize;
+    private long samplesPerPacket;
+    private long bytesPerPacket;
+    private long bytesPerFrame;
+    private long bytesPerSample;
+
+    private int reserved1;
+    private long reserved2;
+    private byte[] soundVersion2Data;
+    private BoxParser boxParser;
+
+    public AudioSampleEntry(String type) {
+        super(type);
+    }
+
+    public int getChannelCount() {
+        return channelCount;
+    }
+
+    public int getSampleSize() {
+        return sampleSize;
+    }
+
+    public long getSampleRate() {
+        return sampleRate;
+    }
+
+    public int getSoundVersion() {
+        return soundVersion;
+    }
+
+    public int getCompressionId() {
+        return compressionId;
+    }
+
+    public int getPacketSize() {
+        return packetSize;
+    }
+
+    public long getSamplesPerPacket() {
+        return samplesPerPacket;
+    }
+
+    public long getBytesPerPacket() {
+        return bytesPerPacket;
+    }
+
+    public long getBytesPerFrame() {
+        return bytesPerFrame;
+    }
+
+    public long getBytesPerSample() {
+        return bytesPerSample;
+    }
+
+    public byte[] getSoundVersion2Data() {
+        return soundVersion2Data;
+    }
+
+    public int getReserved1() {
+        return reserved1;
+    }
+
+    public long getReserved2() {
+        return reserved2;
+    }
+
+    public void setChannelCount(int channelCount) {
+        this.channelCount = channelCount;
+    }
+
+    public void setSampleSize(int sampleSize) {
+        this.sampleSize = sampleSize;
+    }
+
+    public void setSampleRate(long sampleRate) {
+        this.sampleRate = sampleRate;
+    }
+
+    public void setSoundVersion(int soundVersion) {
+        this.soundVersion = soundVersion;
+    }
+
+    public void setCompressionId(int compressionId) {
+        this.compressionId = compressionId;
+    }
+
+    public void setPacketSize(int packetSize) {
+        this.packetSize = packetSize;
+    }
+
+    public void setSamplesPerPacket(long samplesPerPacket) {
+        this.samplesPerPacket = samplesPerPacket;
+    }
+
+    public void setBytesPerPacket(long bytesPerPacket) {
+        this.bytesPerPacket = bytesPerPacket;
+    }
+
+    public void setBytesPerFrame(long bytesPerFrame) {
+        this.bytesPerFrame = bytesPerFrame;
+    }
+
+    public void setBytesPerSample(long bytesPerSample) {
+        this.bytesPerSample = bytesPerSample;
+    }
+
+    public void setReserved1(int reserved1) {
+        this.reserved1 = reserved1;
+    }
+
+    public void setReserved2(long reserved2) {
+        this.reserved2 = reserved2;
+    }
+
+    public void setSoundVersion2Data(byte[] soundVersion2Data) {
+        this.soundVersion2Data = soundVersion2Data;
+    }
+
+    public void setBoxParser(BoxParser boxParser) {
+        this.boxParser = boxParser;
+    }
+
+    @Override
+    public void _parseDetails(ByteBuffer content) {
+        _parseReservedAndDataReferenceIndex(content);    //parses the six reserved bytes and dataReferenceIndex
+        // 8 bytes already parsed
+        //reserved bits - used by qt
+        soundVersion = IsoTypeReader.readUInt16(content);
+
+        //reserved
+        reserved1 = IsoTypeReader.readUInt16(content);
+        reserved2 = IsoTypeReader.readUInt32(content);
+
+        channelCount = IsoTypeReader.readUInt16(content);
+        sampleSize = IsoTypeReader.readUInt16(content);
+        //reserved bits - used by qt
+        compressionId = IsoTypeReader.readUInt16(content);
+        //reserved bits - used by qt
+        packetSize = IsoTypeReader.readUInt16(content);
+        //sampleRate = in.readFixedPoint1616();
+        sampleRate = IsoTypeReader.readUInt32(content);
+        if (!type.equals("mlpa")) {
+            sampleRate = sampleRate >>> 16;
+        }
+
+        //more qt stuff - see http://mp4v2.googlecode.com/svn-history/r388/trunk/src/atom_sound.cpp
+        if (soundVersion > 0) {
+            samplesPerPacket = IsoTypeReader.readUInt32(content);
+            bytesPerPacket = IsoTypeReader.readUInt32(content);
+            bytesPerFrame = IsoTypeReader.readUInt32(content);
+            bytesPerSample = IsoTypeReader.readUInt32(content);
+        }
+        if (soundVersion == 2) {
+
+            soundVersion2Data = new byte[20];
+            content.get(20);
+        }
+        _parseChildBoxes(content);
+
+    }
+
+
+    @Override
+    protected long getContentSize() {
+        long contentSize = 28;
+        contentSize += soundVersion > 0 ? 16 : 0;
+        contentSize += soundVersion == 2 ? 20 : 0;
+        for (Box boxe : boxes) {
+            contentSize += boxe.getSize();
+        }
+        return contentSize;
+    }
+
+    @Override
+    public String toString() {
+        return "AudioSampleEntry{" +
+                "bytesPerSample=" + bytesPerSample +
+                ", bytesPerFrame=" + bytesPerFrame +
+                ", bytesPerPacket=" + bytesPerPacket +
+                ", samplesPerPacket=" + samplesPerPacket +
+                ", packetSize=" + packetSize +
+                ", compressionId=" + compressionId +
+                ", soundVersion=" + soundVersion +
+                ", sampleRate=" + sampleRate +
+                ", sampleSize=" + sampleSize +
+                ", channelCount=" + channelCount +
+                ", boxes=" + getBoxes() +
+                '}';
+    }
+
+    @Override
+    protected void getContent(ByteBuffer byteBuffer) {
+        _writeReservedAndDataReferenceIndex(byteBuffer);
+        IsoTypeWriter.writeUInt16(byteBuffer, soundVersion);
+        IsoTypeWriter.writeUInt16(byteBuffer, reserved1);
+        IsoTypeWriter.writeUInt32(byteBuffer, reserved2);
+        IsoTypeWriter.writeUInt16(byteBuffer, channelCount);
+        IsoTypeWriter.writeUInt16(byteBuffer, sampleSize);
+        IsoTypeWriter.writeUInt16(byteBuffer, compressionId);
+        IsoTypeWriter.writeUInt16(byteBuffer, packetSize);
+        //isos.writeFixedPont1616(getSampleRate());
+        if (type.equals("mlpa")) {
+            IsoTypeWriter.writeUInt32(byteBuffer, getSampleRate());
+        } else {
+            IsoTypeWriter.writeUInt32(byteBuffer, getSampleRate() << 16);
+        }
+
+        if (soundVersion > 0) {
+            IsoTypeWriter.writeUInt32(byteBuffer, samplesPerPacket);
+            IsoTypeWriter.writeUInt32(byteBuffer, bytesPerPacket);
+            IsoTypeWriter.writeUInt32(byteBuffer, bytesPerFrame);
+            IsoTypeWriter.writeUInt32(byteBuffer, bytesPerSample);
+        }
+
+        if (soundVersion == 2) {
+            byteBuffer.put(soundVersion2Data);
+        }
+        _writeChildBoxes(byteBuffer);
+    }
+}
diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/sampleentry/.svn/text-base/MpegSampleEntry.java.svn-base b/isoparser/src/main/java/com/coremedia/iso/boxes/sampleentry/.svn/text-base/MpegSampleEntry.java.svn-base
new file mode 100644
index 0000000..e4a33dc
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/sampleentry/.svn/text-base/MpegSampleEntry.java.svn-base
@@ -0,0 +1,43 @@
+package com.coremedia.iso.boxes.sampleentry;

+

+import com.coremedia.iso.BoxParser;

+import com.coremedia.iso.boxes.Box;

+import com.coremedia.iso.boxes.ContainerBox;

+

+import java.nio.ByteBuffer;

+import java.util.Arrays;

+

+public class MpegSampleEntry extends SampleEntry implements ContainerBox {

+

+    private BoxParser boxParser;

+

+    public MpegSampleEntry(String type) {

+        super(type);

+    }

+

+    @Override

+    public void _parseDetails(ByteBuffer content) {

+        _parseReservedAndDataReferenceIndex(content);

+        _parseChildBoxes(content);

+

+    }

+

+    @Override

+    protected long getContentSize() {

+        long contentSize = 8;

+        for (Box boxe : boxes) {

+            contentSize += boxe.getSize();

+        }

+        return contentSize;

+    }

+

+    public String toString() {

+        return "MpegSampleEntry" + Arrays.asList(getBoxes());

+    }

+

+    @Override

+    protected void getContent(ByteBuffer byteBuffer) {

+        _writeReservedAndDataReferenceIndex(byteBuffer);

+        _writeChildBoxes(byteBuffer);

+    }

+}

diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/sampleentry/.svn/text-base/Ovc1VisualSampleEntryImpl.java.svn-base b/isoparser/src/main/java/com/coremedia/iso/boxes/sampleentry/.svn/text-base/Ovc1VisualSampleEntryImpl.java.svn-base
new file mode 100644
index 0000000..56b8adb
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/sampleentry/.svn/text-base/Ovc1VisualSampleEntryImpl.java.svn-base
@@ -0,0 +1,45 @@
+package com.coremedia.iso.boxes.sampleentry;
+
+import com.coremedia.iso.IsoTypeWriter;
+import com.coremedia.iso.boxes.Box;
+
+import java.nio.ByteBuffer;
+
+
+public class Ovc1VisualSampleEntryImpl extends SampleEntry {
+    private byte[] vc1Content;
+    public static final String TYPE = "ovc1";
+
+
+    @Override
+    protected long getContentSize() {
+        long size = 8;
+
+        for (Box box : boxes) {
+            size += box.getSize();
+        }
+        size += vc1Content.length;
+        return size;
+    }
+
+    @Override
+    public void _parseDetails(ByteBuffer content) {
+        _parseReservedAndDataReferenceIndex(content);
+        vc1Content = new byte[content.remaining()];
+        content.get(vc1Content);
+
+    }
+
+    @Override
+    protected void getContent(ByteBuffer byteBuffer) {
+        byteBuffer.put(new byte[6]);
+        IsoTypeWriter.writeUInt16(byteBuffer, getDataReferenceIndex());
+        byteBuffer.put(vc1Content);
+    }
+
+
+    protected Ovc1VisualSampleEntryImpl() {
+        super(TYPE);
+    }
+
+}
diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/sampleentry/.svn/text-base/SampleEntry.java.svn-base b/isoparser/src/main/java/com/coremedia/iso/boxes/sampleentry/.svn/text-base/SampleEntry.java.svn-base
new file mode 100644
index 0000000..a1a5486
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/sampleentry/.svn/text-base/SampleEntry.java.svn-base
@@ -0,0 +1,159 @@
+/*  
+ * Copyright 2008 CoreMedia AG, Hamburg
+ *
+ * Licensed under the Apache License, Version 2.0 (the License); 
+ * you may not use this file except in compliance with the License. 
+ * You may obtain a copy of the License at 
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0 
+ * 
+ * Unless required by applicable law or agreed to in writing, software 
+ * distributed under the License is distributed on an AS IS BASIS, 
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+ * See the License for the specific language governing permissions and 
+ * limitations under the License. 
+ */
+
+package com.coremedia.iso.boxes.sampleentry;
+
+import com.coremedia.iso.BoxParser;
+import com.coremedia.iso.IsoTypeReader;
+import com.coremedia.iso.IsoTypeWriter;
+import com.googlecode.mp4parser.AbstractBox;
+import com.coremedia.iso.boxes.Box;
+import com.coremedia.iso.boxes.ContainerBox;
+import com.googlecode.mp4parser.util.ByteBufferByteChannel;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.nio.channels.Channels;
+import java.nio.channels.ReadableByteChannel;
+import java.nio.channels.WritableByteChannel;
+import java.util.ArrayList;
+import java.util.LinkedList;
+import java.util.List;
+
+/**
+ * Abstract base class for all sample entries.
+ *
+ * @see com.coremedia.iso.boxes.sampleentry.AudioSampleEntry
+ * @see com.coremedia.iso.boxes.sampleentry.VisualSampleEntry
+ * @see com.coremedia.iso.boxes.sampleentry.TextSampleEntry
+ */
+public abstract class SampleEntry extends AbstractBox implements ContainerBox {
+
+
+    private int dataReferenceIndex = 1;
+    protected List<Box> boxes = new LinkedList<Box>();
+    private BoxParser boxParser;
+
+
+    protected SampleEntry(String type) {
+        super(type);
+    }
+
+    public void setType(String type) {
+        this.type = type;
+    }
+
+    public int getDataReferenceIndex() {
+        return dataReferenceIndex;
+    }
+
+    public void setDataReferenceIndex(int dataReferenceIndex) {
+        this.dataReferenceIndex = dataReferenceIndex;
+    }
+
+    public void setBoxes(List<Box> boxes) {
+        this.boxes = new LinkedList<Box>(boxes);
+    }
+
+    public void addBox(Box b) {
+        b.setParent(this);
+        boxes.add(b);
+    }
+
+    public boolean removeBox(Box b) {
+        b.setParent(this);
+        return boxes.remove(b);
+    }
+
+    public List<Box> getBoxes() {
+        return boxes;
+    }
+
+    @SuppressWarnings("unchecked")
+    public <T extends Box> List<T> getBoxes(Class<T> clazz, boolean recursive) {
+        List<T> boxesToBeReturned = new ArrayList<T>(2);
+        for (Box boxe : boxes) { //clazz.isInstance(boxe) / clazz == boxe.getClass()?
+            if (clazz == boxe.getClass()) {
+                boxesToBeReturned.add((T) boxe);
+            }
+
+            if (recursive && boxe instanceof ContainerBox) {
+                boxesToBeReturned.addAll(((ContainerBox) boxe).getBoxes(clazz, recursive));
+            }
+        }
+        // Optimize here! Spare object creation work on arrays directly! System.arrayCopy
+        return boxesToBeReturned;
+        //return (T[]) boxesToBeReturned.toArray();
+    }
+
+    @SuppressWarnings("unchecked")
+    public <T extends Box> List<T> getBoxes(Class<T> clazz) {
+        return getBoxes(clazz, false);
+    }
+
+    @Override
+    public void parse(ReadableByteChannel readableByteChannel, ByteBuffer header, long contentSize, BoxParser boxParser) throws IOException {
+        super.parse(readableByteChannel, header, contentSize, boxParser);
+        this.boxParser = boxParser;
+    }
+
+
+    public void _parseReservedAndDataReferenceIndex(ByteBuffer content) {
+        content.get(new byte[6]); // ignore 6 reserved bytes;
+        dataReferenceIndex = IsoTypeReader.readUInt16(content);
+    }
+
+    public void _parseChildBoxes(ByteBuffer content) {
+        while (content.remaining() > 8) {
+            try {
+                boxes.add(boxParser.parseBox(new ByteBufferByteChannel(content), this));
+            } catch (IOException e) {
+                throw new RuntimeException(e);
+            }
+
+        }
+        setDeadBytes(content.slice());
+    }
+
+    public void _writeReservedAndDataReferenceIndex(ByteBuffer bb) {
+        bb.put(new byte[6]);
+        IsoTypeWriter.writeUInt16(bb, dataReferenceIndex);
+    }
+
+    public void _writeChildBoxes(ByteBuffer bb) {
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        WritableByteChannel wbc = Channels.newChannel(baos);
+        try {
+            for (Box box : boxes) {
+                box.getBox(wbc);
+            }
+            wbc.close();
+        } catch (IOException e) {
+            throw new RuntimeException("Cannot happen. Everything should be in memory and therefore no exceptions.");
+        }
+        bb.put(baos.toByteArray());
+    }
+
+    public long getNumOfBytesToFirstChild() {
+        long sizeOfChildren = 0;
+        for (Box box : boxes) {
+            sizeOfChildren += box.getSize();
+        }
+        return getSize() - sizeOfChildren;
+    }
+
+}
diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/sampleentry/.svn/text-base/SubtitleSampleEntry.java.svn-base b/isoparser/src/main/java/com/coremedia/iso/boxes/sampleentry/.svn/text-base/SubtitleSampleEntry.java.svn-base
new file mode 100644
index 0000000..21d0cc4
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/sampleentry/.svn/text-base/SubtitleSampleEntry.java.svn-base
@@ -0,0 +1,76 @@
+package com.coremedia.iso.boxes.sampleentry;
+
+import com.coremedia.iso.IsoTypeReader;
+import com.coremedia.iso.IsoTypeWriter;
+
+import java.nio.ByteBuffer;
+
+/**
+ * Created by IntelliJ IDEA.
+ * User: magnus
+ * Date: 2012-03-08
+ * Time: 11:36
+ * To change this template use File | Settings | File Templates.
+ */
+public class SubtitleSampleEntry extends SampleEntry {
+
+    public static final String TYPE1 = "stpp";
+
+    public static final String TYPE_ENCRYPTED = ""; // This is not known!
+
+    private String namespace;
+    private String schemaLocation;
+    private String imageMimeType;
+
+    public SubtitleSampleEntry(String type) {
+        super(type);
+    }
+
+    @Override
+    protected long getContentSize() {
+        long contentSize = 8 + namespace.length() + schemaLocation.length() + imageMimeType.length() + 3;
+        return contentSize;
+    }
+
+    @Override
+    public void _parseDetails(ByteBuffer content) {
+        _parseReservedAndDataReferenceIndex(content);
+        namespace = IsoTypeReader.readString(content);
+        schemaLocation = IsoTypeReader.readString(content);
+        imageMimeType = IsoTypeReader.readString(content);
+        _parseChildBoxes(content);
+    }
+
+    @Override
+    protected void getContent(ByteBuffer byteBuffer) {
+        _writeReservedAndDataReferenceIndex(byteBuffer);
+        IsoTypeWriter.writeUtf8String(byteBuffer, namespace);
+        IsoTypeWriter.writeUtf8String(byteBuffer, schemaLocation);
+        IsoTypeWriter.writeUtf8String(byteBuffer, imageMimeType);
+    }
+
+    public String getNamespace() {
+        return namespace;
+    }
+
+    public void setNamespace(String namespace) {
+        this.namespace = namespace;
+    }
+
+    public String getSchemaLocation() {
+        return schemaLocation;
+    }
+
+    public void setSchemaLocation(String schemaLocation) {
+        this.schemaLocation = schemaLocation;
+    }
+
+    public String getImageMimeType() {
+        return imageMimeType;
+    }
+
+    public void setImageMimeType(String imageMimeType) {
+        this.imageMimeType = imageMimeType;
+    }
+}
+
diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/sampleentry/.svn/text-base/TextSampleEntry.java.svn-base b/isoparser/src/main/java/com/coremedia/iso/boxes/sampleentry/.svn/text-base/TextSampleEntry.java.svn-base
new file mode 100644
index 0000000..3a0b83a
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/sampleentry/.svn/text-base/TextSampleEntry.java.svn-base
@@ -0,0 +1,305 @@
+/*  
+ * Copyright 2008 CoreMedia AG, Hamburg
+ *
+ * Licensed under the Apache License, Version 2.0 (the License); 
+ * you may not use this file except in compliance with the License. 
+ * You may obtain a copy of the License at 
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0 
+ * 
+ * Unless required by applicable law or agreed to in writing, software 
+ * distributed under the License is distributed on an AS IS BASIS, 
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+ * See the License for the specific language governing permissions and 
+ * limitations under the License. 
+ */
+
+package com.coremedia.iso.boxes.sampleentry;
+
+import com.coremedia.iso.IsoTypeReader;
+import com.coremedia.iso.IsoTypeWriter;
+import com.coremedia.iso.boxes.Box;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+
+/**
+ * Entry type for timed text samples defined in the timed text specification (ISO/IEC 14496-17).
+ */
+public class TextSampleEntry extends SampleEntry {
+
+    public static final String TYPE1 = "tx3g";
+
+    public static final String TYPE_ENCRYPTED = "enct";
+
+/*  class TextSampleEntry() extends SampleEntry ('tx3g') {
+    unsigned int(32)  displayFlags;
+    signed int(8)     horizontal-justification;
+    signed int(8)     vertical-justification;
+    unsigned int(8)   background-color-rgba[4];
+    BoxRecord         default-text-box;
+    StyleRecord       default-style;
+    FontTableBox      font-table;
+  }
+  */
+
+    private long displayFlags; // 32 bits
+    private int horizontalJustification; // 8 bit
+    private int verticalJustification;  // 8 bit
+    private int[] backgroundColorRgba = new int[4]; // 4 bytes
+    private BoxRecord boxRecord = new BoxRecord();
+    private StyleRecord styleRecord = new StyleRecord();
+
+    public TextSampleEntry(String type) {
+        super(type);
+    }
+
+    @Override
+    public void _parseDetails(ByteBuffer content) {
+        _parseReservedAndDataReferenceIndex(content);
+        displayFlags = IsoTypeReader.readUInt32(content);
+        horizontalJustification = IsoTypeReader.readUInt8(content);
+        verticalJustification = IsoTypeReader.readUInt8(content);
+        backgroundColorRgba = new int[4];
+        backgroundColorRgba[0] = IsoTypeReader.readUInt8(content);
+        backgroundColorRgba[1] = IsoTypeReader.readUInt8(content);
+        backgroundColorRgba[2] = IsoTypeReader.readUInt8(content);
+        backgroundColorRgba[3] = IsoTypeReader.readUInt8(content);
+        boxRecord = new BoxRecord();
+        boxRecord.parse(content);
+
+        styleRecord = new StyleRecord();
+        styleRecord.parse(content);
+        _parseChildBoxes(content);
+    }
+
+
+    protected long getContentSize() {
+        long contentSize = 18;
+        contentSize += boxRecord.getSize();
+        contentSize += styleRecord.getSize();
+        for (Box boxe : boxes) {
+            contentSize += boxe.getSize();
+        }
+        return contentSize;
+    }
+
+    public String toString() {
+        return "TextSampleEntry";
+    }
+
+    @Override
+    protected void getContent(ByteBuffer byteBuffer) {
+        _writeReservedAndDataReferenceIndex(byteBuffer);
+        IsoTypeWriter.writeUInt32(byteBuffer, displayFlags);
+        IsoTypeWriter.writeUInt8(byteBuffer, horizontalJustification);
+        IsoTypeWriter.writeUInt8(byteBuffer, verticalJustification);
+        IsoTypeWriter.writeUInt8(byteBuffer, backgroundColorRgba[0]);
+        IsoTypeWriter.writeUInt8(byteBuffer, backgroundColorRgba[1]);
+        IsoTypeWriter.writeUInt8(byteBuffer, backgroundColorRgba[2]);
+        IsoTypeWriter.writeUInt8(byteBuffer, backgroundColorRgba[3]);
+        boxRecord.getContent(byteBuffer);
+        styleRecord.getContent(byteBuffer);
+
+        _writeChildBoxes(byteBuffer);
+    }
+
+    public BoxRecord getBoxRecord() {
+        return boxRecord;
+    }
+
+    public void setBoxRecord(BoxRecord boxRecord) {
+        this.boxRecord = boxRecord;
+    }
+
+    public StyleRecord getStyleRecord() {
+        return styleRecord;
+    }
+
+    public void setStyleRecord(StyleRecord styleRecord) {
+        this.styleRecord = styleRecord;
+    }
+
+    public boolean isScrollIn() {
+        return (displayFlags & 0x00000020) == 0x00000020;
+    }
+
+    public void setScrollIn(boolean scrollIn) {
+        if (scrollIn) {
+            displayFlags |= 0x00000020;
+        } else {
+            displayFlags &= ~0x00000020;
+        }
+    }
+
+    public boolean isScrollOut() {
+        return (displayFlags & 0x00000040) == 0x00000040;
+    }
+
+    public void setScrollOut(boolean scrollOutIn) {
+        if (scrollOutIn) {
+            displayFlags |= 0x00000040;
+        } else {
+            displayFlags &= ~0x00000040;
+        }
+    }
+
+    public boolean isScrollDirection() {
+        return (displayFlags & 0x00000180) == 0x00000180;
+    }
+
+    public void setScrollDirection(boolean scrollOutIn) {
+        if (scrollOutIn) {
+            displayFlags |= 0x00000180;
+        } else {
+            displayFlags &= ~0x00000180;
+        }
+    }
+
+    public boolean isContinuousKaraoke() {
+        return (displayFlags & 0x00000800) == 0x00000800;
+    }
+
+    public void setContinuousKaraoke(boolean continuousKaraoke) {
+        if (continuousKaraoke) {
+            displayFlags |= 0x00000800;
+        } else {
+            displayFlags &= ~0x00000800;
+        }
+    }
+
+    public boolean isWriteTextVertically() {
+        return (displayFlags & 0x00020000) == 0x00020000;
+    }
+
+    public void setWriteTextVertically(boolean writeTextVertically) {
+        if (writeTextVertically) {
+            displayFlags |= 0x00020000;
+        } else {
+            displayFlags &= ~0x00020000;
+        }
+    }
+
+
+    public boolean isFillTextRegion() {
+        return (displayFlags & 0x00040000) == 0x00040000;
+    }
+
+    public void setFillTextRegion(boolean fillTextRegion) {
+        if (fillTextRegion) {
+            displayFlags |= 0x00040000;
+        } else {
+            displayFlags &= ~0x00040000;
+        }
+    }
+
+
+    public int getHorizontalJustification() {
+        return horizontalJustification;
+    }
+
+    public void setHorizontalJustification(int horizontalJustification) {
+        this.horizontalJustification = horizontalJustification;
+    }
+
+    public int getVerticalJustification() {
+        return verticalJustification;
+    }
+
+    public void setVerticalJustification(int verticalJustification) {
+        this.verticalJustification = verticalJustification;
+    }
+
+    public int[] getBackgroundColorRgba() {
+        return backgroundColorRgba;
+    }
+
+    public void setBackgroundColorRgba(int[] backgroundColorRgba) {
+        this.backgroundColorRgba = backgroundColorRgba;
+    }
+
+    public static class BoxRecord {
+        int top;
+        int left;
+        int bottom;
+        int right;
+
+        public void parse(ByteBuffer in) {
+            top = IsoTypeReader.readUInt16(in);
+            left = IsoTypeReader.readUInt16(in);
+            bottom = IsoTypeReader.readUInt16(in);
+            right = IsoTypeReader.readUInt16(in);
+        }
+
+        public void getContent(ByteBuffer bb)  {
+            IsoTypeWriter.writeUInt16(bb, top);
+            IsoTypeWriter.writeUInt16(bb, left);
+            IsoTypeWriter.writeUInt16(bb, bottom);
+            IsoTypeWriter.writeUInt16(bb, right);
+        }
+
+        public int getSize() {
+            return 8;
+        }
+    }
+
+    /*
+    class FontRecord {
+	unsigned int(16) 	font-ID;
+	unsigned int(8)	font-name-length;
+	unsigned int(8)	font[font-name-length];
+}
+     */
+
+
+    /*
+   aligned(8) class StyleRecord {
+   unsigned int(16) 	startChar;
+   unsigned int(16)	endChar;
+   unsigned int(16)	font-ID;
+   unsigned int(8)	face-style-flags;
+   unsigned int(8)	font-size;
+   unsigned int(8)	text-color-rgba[4];
+}
+    */
+    public static class StyleRecord {
+        int startChar;
+        int endChar;
+        int fontId;
+        int faceStyleFlags;
+        int fontSize;
+        int[] textColor = new int[]{0xff, 0xff, 0xff, 0xff};
+
+        public void parse(ByteBuffer in) {
+            startChar = IsoTypeReader.readUInt16(in);
+            endChar = IsoTypeReader.readUInt16(in);
+            fontId = IsoTypeReader.readUInt16(in);
+            faceStyleFlags = IsoTypeReader.readUInt8(in);
+            fontSize = IsoTypeReader.readUInt8(in);
+            textColor = new int[4];
+            textColor[0] = IsoTypeReader.readUInt8(in);
+            textColor[1] = IsoTypeReader.readUInt8(in);
+            textColor[2] = IsoTypeReader.readUInt8(in);
+            textColor[3] = IsoTypeReader.readUInt8(in);
+        }
+
+
+        public void getContent(ByteBuffer bb) {
+            IsoTypeWriter.writeUInt16(bb, startChar);
+            IsoTypeWriter.writeUInt16(bb, endChar);
+            IsoTypeWriter.writeUInt16(bb, fontId);
+            IsoTypeWriter.writeUInt8(bb, faceStyleFlags);
+            IsoTypeWriter.writeUInt8(bb, fontSize);
+            IsoTypeWriter.writeUInt8(bb, textColor[0]);
+            IsoTypeWriter.writeUInt8(bb, textColor[1]);
+            IsoTypeWriter.writeUInt8(bb, textColor[2]);
+            IsoTypeWriter.writeUInt8(bb, textColor[3]);
+        }
+
+        public int getSize() {
+            return 12;
+        }
+    }
+
+
+}
diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/sampleentry/.svn/text-base/VisualSampleEntry.java.svn-base b/isoparser/src/main/java/com/coremedia/iso/boxes/sampleentry/.svn/text-base/VisualSampleEntry.java.svn-base
new file mode 100644
index 0000000..407e79f
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/sampleentry/.svn/text-base/VisualSampleEntry.java.svn-base
@@ -0,0 +1,213 @@
+/*  
+ * Copyright 2008 CoreMedia AG, Hamburg
+ *
+ * Licensed under the Apache License, Version 2.0 (the License); 
+ * you may not use this file except in compliance with the License. 
+ * You may obtain a copy of the License at 
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0 
+ * 
+ * Unless required by applicable law or agreed to in writing, software 
+ * distributed under the License is distributed on an AS IS BASIS, 
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+ * See the License for the specific language governing permissions and 
+ * limitations under the License. 
+ */
+
+package com.coremedia.iso.boxes.sampleentry;
+
+import com.coremedia.iso.IsoTypeReader;
+import com.coremedia.iso.IsoTypeWriter;
+import com.coremedia.iso.Utf8;
+import com.coremedia.iso.boxes.Box;
+import com.coremedia.iso.boxes.ContainerBox;
+
+import java.nio.ByteBuffer;
+
+/**
+ * Contains information common to all visual tracks.
+ * <code>
+ * <pre>
+ * class VisualSampleEntry(codingname) extends SampleEntry (codingname){
+ * unsigned int(16) pre_defined = 0;
+ * const unsigned int(16) reserved = 0;
+ * unsigned int(32)[3] pre_defined = 0;
+ * unsigned int(16) width;
+ * unsigned int(16) height;
+ * template unsigned int(32) horizresolution = 0x00480000; // 72 dpi
+ * template unsigned int(32) vertresolution = 0x00480000; // 72 dpi
+ * const unsigned int(32) reserved = 0;
+ * template unsigned int(16) frame_count = 1;
+ * string[32] compressorname;
+ * template unsigned int(16) depth = 0x0018;
+ * int(16) pre_defined = -1;
+ * }<br>
+ * </pre>
+ * </code>
+ * <p/>
+ * Format-specific informationis appened as boxes after the data described in ISO/IEC 14496-12 chapter 8.16.2.
+ */
+public class VisualSampleEntry extends SampleEntry implements ContainerBox {
+    public static final String TYPE1 = "mp4v";
+    public static final String TYPE2 = "s263";
+    public static final String TYPE3 = "avc1";
+
+
+    /**
+     * Identifier for an encrypted video track.
+     *
+     * @see com.coremedia.iso.boxes.ProtectionSchemeInformationBox
+     */
+    public static final String TYPE_ENCRYPTED = "encv";
+
+
+    private int width;
+    private int height;
+    private double horizresolution = 72;
+    private double vertresolution = 72;
+    private int frameCount = 1;
+    private String compressorname;
+    private int depth = 24;
+
+    private long[] predefined = new long[3];
+
+    public VisualSampleEntry(String type) {
+        super(type);
+    }
+
+    public int getWidth() {
+        return width;
+    }
+
+    public int getHeight() {
+        return height;
+    }
+
+    public double getHorizresolution() {
+        return horizresolution;
+    }
+
+    public double getVertresolution() {
+        return vertresolution;
+    }
+
+    public int getFrameCount() {
+        return frameCount;
+    }
+
+    public String getCompressorname() {
+        return compressorname;
+    }
+
+    public int getDepth() {
+        return depth;
+    }
+
+    public void setCompressorname(String compressorname) {
+        this.compressorname = compressorname;
+    }
+
+    public void setWidth(int width) {
+        this.width = width;
+    }
+
+    public void setHeight(int height) {
+        this.height = height;
+    }
+
+    public void setHorizresolution(double horizresolution) {
+        this.horizresolution = horizresolution;
+    }
+
+    public void setVertresolution(double vertresolution) {
+        this.vertresolution = vertresolution;
+    }
+
+    public void setFrameCount(int frameCount) {
+        this.frameCount = frameCount;
+    }
+
+    public void setDepth(int depth) {
+        this.depth = depth;
+    }
+
+    @Override
+    public void _parseDetails(ByteBuffer content) {
+        _parseReservedAndDataReferenceIndex(content);
+        long tmp = IsoTypeReader.readUInt16(content);
+        assert 0 == tmp : "reserved byte not 0";
+        tmp = IsoTypeReader.readUInt16(content);
+        assert 0 == tmp : "reserved byte not 0";
+        predefined[0] = IsoTypeReader.readUInt32(content);     // should be zero
+        predefined[1] = IsoTypeReader.readUInt32(content);     // should be zero
+        predefined[2] = IsoTypeReader.readUInt32(content);     // should be zero
+        width = IsoTypeReader.readUInt16(content);
+        height = IsoTypeReader.readUInt16(content);
+        horizresolution = IsoTypeReader.readFixedPoint1616(content);
+        vertresolution = IsoTypeReader.readFixedPoint1616(content);
+        tmp = IsoTypeReader.readUInt32(content);
+        assert 0 == tmp : "reserved byte not 0";
+        frameCount = IsoTypeReader.readUInt16(content);
+        int compressornameDisplayAbleData = IsoTypeReader.readUInt8(content);
+        if (compressornameDisplayAbleData > 31) {
+            System.out.println("invalid compressor name displayable data: " + compressornameDisplayAbleData);
+            compressornameDisplayAbleData = 31;
+        }
+        byte[] bytes = new byte[compressornameDisplayAbleData];
+        content.get(bytes);
+        compressorname = Utf8.convert(bytes);
+        if (compressornameDisplayAbleData < 31) {
+            byte[] zeros = new byte[31 - compressornameDisplayAbleData];
+            content.get(zeros);
+            //assert Arrays.equals(zeros, new byte[zeros.length]) : "The compressor name length was not filled up with zeros";
+        }
+        depth = IsoTypeReader.readUInt16(content);
+        tmp = IsoTypeReader.readUInt16(content);
+        assert 0xFFFF == tmp;
+
+        _parseChildBoxes(content);
+
+    }
+
+
+    protected long getContentSize() {
+        long contentSize = 78;
+        for (Box boxe : boxes) {
+            contentSize += boxe.getSize();
+        }
+        return contentSize;
+    }
+
+    @Override
+    protected void getContent(ByteBuffer byteBuffer) {
+        _writeReservedAndDataReferenceIndex(byteBuffer);
+        IsoTypeWriter.writeUInt16(byteBuffer, 0);
+        IsoTypeWriter.writeUInt16(byteBuffer, 0);
+        IsoTypeWriter.writeUInt32(byteBuffer, predefined[0]);
+        IsoTypeWriter.writeUInt32(byteBuffer, predefined[1]);
+        IsoTypeWriter.writeUInt32(byteBuffer, predefined[2]);
+
+        IsoTypeWriter.writeUInt16(byteBuffer, getWidth());
+        IsoTypeWriter.writeUInt16(byteBuffer, getHeight());
+
+        IsoTypeWriter.writeFixedPont1616(byteBuffer, getHorizresolution());
+        IsoTypeWriter.writeFixedPont1616(byteBuffer, getVertresolution());
+
+
+        IsoTypeWriter.writeUInt32(byteBuffer, 0);
+        IsoTypeWriter.writeUInt16(byteBuffer, getFrameCount());
+        IsoTypeWriter.writeUInt8(byteBuffer, Utf8.utf8StringLengthInBytes(getCompressorname()));
+        byteBuffer.put(Utf8.convert(getCompressorname()));
+        int a = Utf8.utf8StringLengthInBytes(getCompressorname());
+        while (a < 31) {
+            a++;
+            byteBuffer.put((byte) 0);
+        }
+        IsoTypeWriter.writeUInt16(byteBuffer, getDepth());
+        IsoTypeWriter.writeUInt16(byteBuffer, 0xFFFF);
+
+        _writeChildBoxes(byteBuffer);
+
+    }
+
+}
diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/sampleentry/AmrSpecificBox.java b/isoparser/src/main/java/com/coremedia/iso/boxes/sampleentry/AmrSpecificBox.java
new file mode 100644
index 0000000..f69de7b
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/sampleentry/AmrSpecificBox.java
@@ -0,0 +1,101 @@
+/*  
+ * Copyright 2008 CoreMedia AG, Hamburg
+ *
+ * Licensed under the Apache License, Version 2.0 (the License); 
+ * you may not use this file except in compliance with the License. 
+ * You may obtain a copy of the License at 
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0 
+ * 
+ * Unless required by applicable law or agreed to in writing, software 
+ * distributed under the License is distributed on an AS IS BASIS, 
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+ * See the License for the specific language governing permissions and 
+ * limitations under the License. 
+ */
+
+package com.coremedia.iso.boxes.sampleentry;
+
+
+import com.coremedia.iso.IsoFile;
+import com.coremedia.iso.IsoTypeReader;
+import com.coremedia.iso.IsoTypeWriter;
+import com.googlecode.mp4parser.AbstractBox;
+
+import java.nio.ByteBuffer;
+
+/**
+ * AMR audio format specific subbox of an audio sample entry.
+ *
+ * @see com.coremedia.iso.boxes.sampleentry.AudioSampleEntry
+ */
+public class AmrSpecificBox extends AbstractBox {
+    public static final String TYPE = "damr";
+
+    private String vendor;
+    private int decoderVersion;
+    private int modeSet;
+    private int modeChangePeriod;
+    private int framesPerSample;
+
+    public AmrSpecificBox() {
+        super(TYPE);
+    }
+
+    public String getVendor() {
+        return vendor;
+    }
+
+    public int getDecoderVersion() {
+        return decoderVersion;
+    }
+
+    public int getModeSet() {
+        return modeSet;
+    }
+
+    public int getModeChangePeriod() {
+        return modeChangePeriod;
+    }
+
+    public int getFramesPerSample() {
+        return framesPerSample;
+    }
+
+    protected long getContentSize() {
+        return 9;
+    }
+
+    @Override
+    public void _parseDetails(ByteBuffer content) {
+        byte[] v = new byte[4];
+        content.get(v);
+        vendor = IsoFile.bytesToFourCC(v);
+
+        decoderVersion = IsoTypeReader.readUInt8(content);
+        modeSet = IsoTypeReader.readUInt16(content);
+        modeChangePeriod = IsoTypeReader.readUInt8(content);
+        framesPerSample = IsoTypeReader.readUInt8(content);
+
+    }
+
+
+    public void getContent(ByteBuffer byteBuffer) {
+        byteBuffer.put(IsoFile.fourCCtoBytes(vendor));
+        IsoTypeWriter.writeUInt8(byteBuffer, decoderVersion);
+        IsoTypeWriter.writeUInt16(byteBuffer, modeSet);
+        IsoTypeWriter.writeUInt8(byteBuffer, modeChangePeriod);
+        IsoTypeWriter.writeUInt8(byteBuffer, framesPerSample);
+    }
+
+    public String toString() {
+        StringBuilder buffer = new StringBuilder();
+        buffer.append("AmrSpecificBox[vendor=").append(getVendor());
+        buffer.append(";decoderVersion=").append(getDecoderVersion());
+        buffer.append(";modeSet=").append(getModeSet());
+        buffer.append(";modeChangePeriod=").append(getModeChangePeriod());
+        buffer.append(";framesPerSample=").append(getFramesPerSample());
+        buffer.append("]");
+        return buffer.toString();
+    }
+}
diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/sampleentry/AudioSampleEntry.java b/isoparser/src/main/java/com/coremedia/iso/boxes/sampleentry/AudioSampleEntry.java
new file mode 100644
index 0000000..69aeb79
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/sampleentry/AudioSampleEntry.java
@@ -0,0 +1,278 @@
+/*  
+ * Copyright 2008 CoreMedia AG, Hamburg
+ *
+ * Licensed under the Apache License, Version 2.0 (the License); 
+ * you may not use this file except in compliance with the License. 
+ * You may obtain a copy of the License at 
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0 
+ * 
+ * Unless required by applicable law or agreed to in writing, software 
+ * distributed under the License is distributed on an AS IS BASIS, 
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+ * See the License for the specific language governing permissions and 
+ * limitations under the License. 
+ */
+
+package com.coremedia.iso.boxes.sampleentry;
+
+import com.coremedia.iso.BoxParser;
+import com.coremedia.iso.IsoTypeReader;
+import com.coremedia.iso.IsoTypeWriter;
+import com.coremedia.iso.boxes.Box;
+import com.coremedia.iso.boxes.ContainerBox;
+
+import java.nio.ByteBuffer;
+
+/**
+ * Contains basic information about the audio samples in this track. Format-specific information
+ * is appened as boxes after the data described in ISO/IEC 14496-12 chapter 8.16.2.
+ */
+public class AudioSampleEntry extends SampleEntry implements ContainerBox {
+
+    public static final String TYPE1 = "samr";
+    public static final String TYPE2 = "sawb";
+    public static final String TYPE3 = "mp4a";
+    public static final String TYPE4 = "drms";
+    public static final String TYPE5 = "alac";
+    public static final String TYPE7 = "owma";
+    public static final String TYPE8 = "ac-3"; /* ETSI TS 102 366 1.2.1 Annex F */
+    public static final String TYPE9 = "ec-3"; /* ETSI TS 102 366 1.2.1 Annex F */
+    public static final String TYPE10 = "mlpa";
+    public static final String TYPE11 = "dtsl";
+    public static final String TYPE12 = "dtsh";
+    public static final String TYPE13 = "dtse";
+
+    /**
+     * Identifier for an encrypted audio track.
+     *
+     * @see com.coremedia.iso.boxes.ProtectionSchemeInformationBox
+     */
+    public static final String TYPE_ENCRYPTED = "enca";
+
+    private int channelCount;
+    private int sampleSize;
+    private long sampleRate;
+    private int soundVersion;
+    private int compressionId;
+    private int packetSize;
+    private long samplesPerPacket;
+    private long bytesPerPacket;
+    private long bytesPerFrame;
+    private long bytesPerSample;
+
+    private int reserved1;
+    private long reserved2;
+    private byte[] soundVersion2Data;
+    private BoxParser boxParser;
+
+    public AudioSampleEntry(String type) {
+        super(type);
+    }
+
+    public int getChannelCount() {
+        return channelCount;
+    }
+
+    public int getSampleSize() {
+        return sampleSize;
+    }
+
+    public long getSampleRate() {
+        return sampleRate;
+    }
+
+    public int getSoundVersion() {
+        return soundVersion;
+    }
+
+    public int getCompressionId() {
+        return compressionId;
+    }
+
+    public int getPacketSize() {
+        return packetSize;
+    }
+
+    public long getSamplesPerPacket() {
+        return samplesPerPacket;
+    }
+
+    public long getBytesPerPacket() {
+        return bytesPerPacket;
+    }
+
+    public long getBytesPerFrame() {
+        return bytesPerFrame;
+    }
+
+    public long getBytesPerSample() {
+        return bytesPerSample;
+    }
+
+    public byte[] getSoundVersion2Data() {
+        return soundVersion2Data;
+    }
+
+    public int getReserved1() {
+        return reserved1;
+    }
+
+    public long getReserved2() {
+        return reserved2;
+    }
+
+    public void setChannelCount(int channelCount) {
+        this.channelCount = channelCount;
+    }
+
+    public void setSampleSize(int sampleSize) {
+        this.sampleSize = sampleSize;
+    }
+
+    public void setSampleRate(long sampleRate) {
+        this.sampleRate = sampleRate;
+    }
+
+    public void setSoundVersion(int soundVersion) {
+        this.soundVersion = soundVersion;
+    }
+
+    public void setCompressionId(int compressionId) {
+        this.compressionId = compressionId;
+    }
+
+    public void setPacketSize(int packetSize) {
+        this.packetSize = packetSize;
+    }
+
+    public void setSamplesPerPacket(long samplesPerPacket) {
+        this.samplesPerPacket = samplesPerPacket;
+    }
+
+    public void setBytesPerPacket(long bytesPerPacket) {
+        this.bytesPerPacket = bytesPerPacket;
+    }
+
+    public void setBytesPerFrame(long bytesPerFrame) {
+        this.bytesPerFrame = bytesPerFrame;
+    }
+
+    public void setBytesPerSample(long bytesPerSample) {
+        this.bytesPerSample = bytesPerSample;
+    }
+
+    public void setReserved1(int reserved1) {
+        this.reserved1 = reserved1;
+    }
+
+    public void setReserved2(long reserved2) {
+        this.reserved2 = reserved2;
+    }
+
+    public void setSoundVersion2Data(byte[] soundVersion2Data) {
+        this.soundVersion2Data = soundVersion2Data;
+    }
+
+    public void setBoxParser(BoxParser boxParser) {
+        this.boxParser = boxParser;
+    }
+
+    @Override
+    public void _parseDetails(ByteBuffer content) {
+        _parseReservedAndDataReferenceIndex(content);    //parses the six reserved bytes and dataReferenceIndex
+        // 8 bytes already parsed
+        //reserved bits - used by qt
+        soundVersion = IsoTypeReader.readUInt16(content);
+
+        //reserved
+        reserved1 = IsoTypeReader.readUInt16(content);
+        reserved2 = IsoTypeReader.readUInt32(content);
+
+        channelCount = IsoTypeReader.readUInt16(content);
+        sampleSize = IsoTypeReader.readUInt16(content);
+        //reserved bits - used by qt
+        compressionId = IsoTypeReader.readUInt16(content);
+        //reserved bits - used by qt
+        packetSize = IsoTypeReader.readUInt16(content);
+        //sampleRate = in.readFixedPoint1616();
+        sampleRate = IsoTypeReader.readUInt32(content);
+        if (!type.equals("mlpa")) {
+            sampleRate = sampleRate >>> 16;
+        }
+
+        //more qt stuff - see http://mp4v2.googlecode.com/svn-history/r388/trunk/src/atom_sound.cpp
+        if (soundVersion > 0) {
+            samplesPerPacket = IsoTypeReader.readUInt32(content);
+            bytesPerPacket = IsoTypeReader.readUInt32(content);
+            bytesPerFrame = IsoTypeReader.readUInt32(content);
+            bytesPerSample = IsoTypeReader.readUInt32(content);
+        }
+        if (soundVersion == 2) {
+
+            soundVersion2Data = new byte[20];
+            content.get(20);
+        }
+        _parseChildBoxes(content);
+
+    }
+
+
+    @Override
+    protected long getContentSize() {
+        long contentSize = 28;
+        contentSize += soundVersion > 0 ? 16 : 0;
+        contentSize += soundVersion == 2 ? 20 : 0;
+        for (Box boxe : boxes) {
+            contentSize += boxe.getSize();
+        }
+        return contentSize;
+    }
+
+    @Override
+    public String toString() {
+        return "AudioSampleEntry{" +
+                "bytesPerSample=" + bytesPerSample +
+                ", bytesPerFrame=" + bytesPerFrame +
+                ", bytesPerPacket=" + bytesPerPacket +
+                ", samplesPerPacket=" + samplesPerPacket +
+                ", packetSize=" + packetSize +
+                ", compressionId=" + compressionId +
+                ", soundVersion=" + soundVersion +
+                ", sampleRate=" + sampleRate +
+                ", sampleSize=" + sampleSize +
+                ", channelCount=" + channelCount +
+                ", boxes=" + getBoxes() +
+                '}';
+    }
+
+    @Override
+    protected void getContent(ByteBuffer byteBuffer) {
+        _writeReservedAndDataReferenceIndex(byteBuffer);
+        IsoTypeWriter.writeUInt16(byteBuffer, soundVersion);
+        IsoTypeWriter.writeUInt16(byteBuffer, reserved1);
+        IsoTypeWriter.writeUInt32(byteBuffer, reserved2);
+        IsoTypeWriter.writeUInt16(byteBuffer, channelCount);
+        IsoTypeWriter.writeUInt16(byteBuffer, sampleSize);
+        IsoTypeWriter.writeUInt16(byteBuffer, compressionId);
+        IsoTypeWriter.writeUInt16(byteBuffer, packetSize);
+        //isos.writeFixedPont1616(getSampleRate());
+        if (type.equals("mlpa")) {
+            IsoTypeWriter.writeUInt32(byteBuffer, getSampleRate());
+        } else {
+            IsoTypeWriter.writeUInt32(byteBuffer, getSampleRate() << 16);
+        }
+
+        if (soundVersion > 0) {
+            IsoTypeWriter.writeUInt32(byteBuffer, samplesPerPacket);
+            IsoTypeWriter.writeUInt32(byteBuffer, bytesPerPacket);
+            IsoTypeWriter.writeUInt32(byteBuffer, bytesPerFrame);
+            IsoTypeWriter.writeUInt32(byteBuffer, bytesPerSample);
+        }
+
+        if (soundVersion == 2) {
+            byteBuffer.put(soundVersion2Data);
+        }
+        _writeChildBoxes(byteBuffer);
+    }
+}
diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/sampleentry/MpegSampleEntry.java b/isoparser/src/main/java/com/coremedia/iso/boxes/sampleentry/MpegSampleEntry.java
new file mode 100644
index 0000000..e4a33dc
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/sampleentry/MpegSampleEntry.java
@@ -0,0 +1,43 @@
+package com.coremedia.iso.boxes.sampleentry;

+

+import com.coremedia.iso.BoxParser;

+import com.coremedia.iso.boxes.Box;

+import com.coremedia.iso.boxes.ContainerBox;

+

+import java.nio.ByteBuffer;

+import java.util.Arrays;

+

+public class MpegSampleEntry extends SampleEntry implements ContainerBox {

+

+    private BoxParser boxParser;

+

+    public MpegSampleEntry(String type) {

+        super(type);

+    }

+

+    @Override

+    public void _parseDetails(ByteBuffer content) {

+        _parseReservedAndDataReferenceIndex(content);

+        _parseChildBoxes(content);

+

+    }

+

+    @Override

+    protected long getContentSize() {

+        long contentSize = 8;

+        for (Box boxe : boxes) {

+            contentSize += boxe.getSize();

+        }

+        return contentSize;

+    }

+

+    public String toString() {

+        return "MpegSampleEntry" + Arrays.asList(getBoxes());

+    }

+

+    @Override

+    protected void getContent(ByteBuffer byteBuffer) {

+        _writeReservedAndDataReferenceIndex(byteBuffer);

+        _writeChildBoxes(byteBuffer);

+    }

+}

diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/sampleentry/Ovc1VisualSampleEntryImpl.java b/isoparser/src/main/java/com/coremedia/iso/boxes/sampleentry/Ovc1VisualSampleEntryImpl.java
new file mode 100644
index 0000000..56b8adb
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/sampleentry/Ovc1VisualSampleEntryImpl.java
@@ -0,0 +1,45 @@
+package com.coremedia.iso.boxes.sampleentry;
+
+import com.coremedia.iso.IsoTypeWriter;
+import com.coremedia.iso.boxes.Box;
+
+import java.nio.ByteBuffer;
+
+
+public class Ovc1VisualSampleEntryImpl extends SampleEntry {
+    private byte[] vc1Content;
+    public static final String TYPE = "ovc1";
+
+
+    @Override
+    protected long getContentSize() {
+        long size = 8;
+
+        for (Box box : boxes) {
+            size += box.getSize();
+        }
+        size += vc1Content.length;
+        return size;
+    }
+
+    @Override
+    public void _parseDetails(ByteBuffer content) {
+        _parseReservedAndDataReferenceIndex(content);
+        vc1Content = new byte[content.remaining()];
+        content.get(vc1Content);
+
+    }
+
+    @Override
+    protected void getContent(ByteBuffer byteBuffer) {
+        byteBuffer.put(new byte[6]);
+        IsoTypeWriter.writeUInt16(byteBuffer, getDataReferenceIndex());
+        byteBuffer.put(vc1Content);
+    }
+
+
+    protected Ovc1VisualSampleEntryImpl() {
+        super(TYPE);
+    }
+
+}
diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/sampleentry/SampleEntry.java b/isoparser/src/main/java/com/coremedia/iso/boxes/sampleentry/SampleEntry.java
new file mode 100644
index 0000000..a1a5486
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/sampleentry/SampleEntry.java
@@ -0,0 +1,159 @@
+/*  
+ * Copyright 2008 CoreMedia AG, Hamburg
+ *
+ * Licensed under the Apache License, Version 2.0 (the License); 
+ * you may not use this file except in compliance with the License. 
+ * You may obtain a copy of the License at 
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0 
+ * 
+ * Unless required by applicable law or agreed to in writing, software 
+ * distributed under the License is distributed on an AS IS BASIS, 
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+ * See the License for the specific language governing permissions and 
+ * limitations under the License. 
+ */
+
+package com.coremedia.iso.boxes.sampleentry;
+
+import com.coremedia.iso.BoxParser;
+import com.coremedia.iso.IsoTypeReader;
+import com.coremedia.iso.IsoTypeWriter;
+import com.googlecode.mp4parser.AbstractBox;
+import com.coremedia.iso.boxes.Box;
+import com.coremedia.iso.boxes.ContainerBox;
+import com.googlecode.mp4parser.util.ByteBufferByteChannel;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.nio.channels.Channels;
+import java.nio.channels.ReadableByteChannel;
+import java.nio.channels.WritableByteChannel;
+import java.util.ArrayList;
+import java.util.LinkedList;
+import java.util.List;
+
+/**
+ * Abstract base class for all sample entries.
+ *
+ * @see com.coremedia.iso.boxes.sampleentry.AudioSampleEntry
+ * @see com.coremedia.iso.boxes.sampleentry.VisualSampleEntry
+ * @see com.coremedia.iso.boxes.sampleentry.TextSampleEntry
+ */
+public abstract class SampleEntry extends AbstractBox implements ContainerBox {
+
+
+    private int dataReferenceIndex = 1;
+    protected List<Box> boxes = new LinkedList<Box>();
+    private BoxParser boxParser;
+
+
+    protected SampleEntry(String type) {
+        super(type);
+    }
+
+    public void setType(String type) {
+        this.type = type;
+    }
+
+    public int getDataReferenceIndex() {
+        return dataReferenceIndex;
+    }
+
+    public void setDataReferenceIndex(int dataReferenceIndex) {
+        this.dataReferenceIndex = dataReferenceIndex;
+    }
+
+    public void setBoxes(List<Box> boxes) {
+        this.boxes = new LinkedList<Box>(boxes);
+    }
+
+    public void addBox(Box b) {
+        b.setParent(this);
+        boxes.add(b);
+    }
+
+    public boolean removeBox(Box b) {
+        b.setParent(this);
+        return boxes.remove(b);
+    }
+
+    public List<Box> getBoxes() {
+        return boxes;
+    }
+
+    @SuppressWarnings("unchecked")
+    public <T extends Box> List<T> getBoxes(Class<T> clazz, boolean recursive) {
+        List<T> boxesToBeReturned = new ArrayList<T>(2);
+        for (Box boxe : boxes) { //clazz.isInstance(boxe) / clazz == boxe.getClass()?
+            if (clazz == boxe.getClass()) {
+                boxesToBeReturned.add((T) boxe);
+            }
+
+            if (recursive && boxe instanceof ContainerBox) {
+                boxesToBeReturned.addAll(((ContainerBox) boxe).getBoxes(clazz, recursive));
+            }
+        }
+        // Optimize here! Spare object creation work on arrays directly! System.arrayCopy
+        return boxesToBeReturned;
+        //return (T[]) boxesToBeReturned.toArray();
+    }
+
+    @SuppressWarnings("unchecked")
+    public <T extends Box> List<T> getBoxes(Class<T> clazz) {
+        return getBoxes(clazz, false);
+    }
+
+    @Override
+    public void parse(ReadableByteChannel readableByteChannel, ByteBuffer header, long contentSize, BoxParser boxParser) throws IOException {
+        super.parse(readableByteChannel, header, contentSize, boxParser);
+        this.boxParser = boxParser;
+    }
+
+
+    public void _parseReservedAndDataReferenceIndex(ByteBuffer content) {
+        content.get(new byte[6]); // ignore 6 reserved bytes;
+        dataReferenceIndex = IsoTypeReader.readUInt16(content);
+    }
+
+    public void _parseChildBoxes(ByteBuffer content) {
+        while (content.remaining() > 8) {
+            try {
+                boxes.add(boxParser.parseBox(new ByteBufferByteChannel(content), this));
+            } catch (IOException e) {
+                throw new RuntimeException(e);
+            }
+
+        }
+        setDeadBytes(content.slice());
+    }
+
+    public void _writeReservedAndDataReferenceIndex(ByteBuffer bb) {
+        bb.put(new byte[6]);
+        IsoTypeWriter.writeUInt16(bb, dataReferenceIndex);
+    }
+
+    public void _writeChildBoxes(ByteBuffer bb) {
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        WritableByteChannel wbc = Channels.newChannel(baos);
+        try {
+            for (Box box : boxes) {
+                box.getBox(wbc);
+            }
+            wbc.close();
+        } catch (IOException e) {
+            throw new RuntimeException("Cannot happen. Everything should be in memory and therefore no exceptions.");
+        }
+        bb.put(baos.toByteArray());
+    }
+
+    public long getNumOfBytesToFirstChild() {
+        long sizeOfChildren = 0;
+        for (Box box : boxes) {
+            sizeOfChildren += box.getSize();
+        }
+        return getSize() - sizeOfChildren;
+    }
+
+}
diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/sampleentry/SubtitleSampleEntry.java b/isoparser/src/main/java/com/coremedia/iso/boxes/sampleentry/SubtitleSampleEntry.java
new file mode 100644
index 0000000..21d0cc4
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/sampleentry/SubtitleSampleEntry.java
@@ -0,0 +1,76 @@
+package com.coremedia.iso.boxes.sampleentry;
+
+import com.coremedia.iso.IsoTypeReader;
+import com.coremedia.iso.IsoTypeWriter;
+
+import java.nio.ByteBuffer;
+
+/**
+ * Created by IntelliJ IDEA.
+ * User: magnus
+ * Date: 2012-03-08
+ * Time: 11:36
+ * To change this template use File | Settings | File Templates.
+ */
+public class SubtitleSampleEntry extends SampleEntry {
+
+    public static final String TYPE1 = "stpp";
+
+    public static final String TYPE_ENCRYPTED = ""; // This is not known!
+
+    private String namespace;
+    private String schemaLocation;
+    private String imageMimeType;
+
+    public SubtitleSampleEntry(String type) {
+        super(type);
+    }
+
+    @Override
+    protected long getContentSize() {
+        long contentSize = 8 + namespace.length() + schemaLocation.length() + imageMimeType.length() + 3;
+        return contentSize;
+    }
+
+    @Override
+    public void _parseDetails(ByteBuffer content) {
+        _parseReservedAndDataReferenceIndex(content);
+        namespace = IsoTypeReader.readString(content);
+        schemaLocation = IsoTypeReader.readString(content);
+        imageMimeType = IsoTypeReader.readString(content);
+        _parseChildBoxes(content);
+    }
+
+    @Override
+    protected void getContent(ByteBuffer byteBuffer) {
+        _writeReservedAndDataReferenceIndex(byteBuffer);
+        IsoTypeWriter.writeUtf8String(byteBuffer, namespace);
+        IsoTypeWriter.writeUtf8String(byteBuffer, schemaLocation);
+        IsoTypeWriter.writeUtf8String(byteBuffer, imageMimeType);
+    }
+
+    public String getNamespace() {
+        return namespace;
+    }
+
+    public void setNamespace(String namespace) {
+        this.namespace = namespace;
+    }
+
+    public String getSchemaLocation() {
+        return schemaLocation;
+    }
+
+    public void setSchemaLocation(String schemaLocation) {
+        this.schemaLocation = schemaLocation;
+    }
+
+    public String getImageMimeType() {
+        return imageMimeType;
+    }
+
+    public void setImageMimeType(String imageMimeType) {
+        this.imageMimeType = imageMimeType;
+    }
+}
+
diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/sampleentry/TextSampleEntry.java b/isoparser/src/main/java/com/coremedia/iso/boxes/sampleentry/TextSampleEntry.java
new file mode 100644
index 0000000..3a0b83a
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/sampleentry/TextSampleEntry.java
@@ -0,0 +1,305 @@
+/*  
+ * Copyright 2008 CoreMedia AG, Hamburg
+ *
+ * Licensed under the Apache License, Version 2.0 (the License); 
+ * you may not use this file except in compliance with the License. 
+ * You may obtain a copy of the License at 
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0 
+ * 
+ * Unless required by applicable law or agreed to in writing, software 
+ * distributed under the License is distributed on an AS IS BASIS, 
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+ * See the License for the specific language governing permissions and 
+ * limitations under the License. 
+ */
+
+package com.coremedia.iso.boxes.sampleentry;
+
+import com.coremedia.iso.IsoTypeReader;
+import com.coremedia.iso.IsoTypeWriter;
+import com.coremedia.iso.boxes.Box;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+
+/**
+ * Entry type for timed text samples defined in the timed text specification (ISO/IEC 14496-17).
+ */
+public class TextSampleEntry extends SampleEntry {
+
+    public static final String TYPE1 = "tx3g";
+
+    public static final String TYPE_ENCRYPTED = "enct";
+
+/*  class TextSampleEntry() extends SampleEntry ('tx3g') {
+    unsigned int(32)  displayFlags;
+    signed int(8)     horizontal-justification;
+    signed int(8)     vertical-justification;
+    unsigned int(8)   background-color-rgba[4];
+    BoxRecord         default-text-box;
+    StyleRecord       default-style;
+    FontTableBox      font-table;
+  }
+  */
+
+    private long displayFlags; // 32 bits
+    private int horizontalJustification; // 8 bit
+    private int verticalJustification;  // 8 bit
+    private int[] backgroundColorRgba = new int[4]; // 4 bytes
+    private BoxRecord boxRecord = new BoxRecord();
+    private StyleRecord styleRecord = new StyleRecord();
+
+    public TextSampleEntry(String type) {
+        super(type);
+    }
+
+    @Override
+    public void _parseDetails(ByteBuffer content) {
+        _parseReservedAndDataReferenceIndex(content);
+        displayFlags = IsoTypeReader.readUInt32(content);
+        horizontalJustification = IsoTypeReader.readUInt8(content);
+        verticalJustification = IsoTypeReader.readUInt8(content);
+        backgroundColorRgba = new int[4];
+        backgroundColorRgba[0] = IsoTypeReader.readUInt8(content);
+        backgroundColorRgba[1] = IsoTypeReader.readUInt8(content);
+        backgroundColorRgba[2] = IsoTypeReader.readUInt8(content);
+        backgroundColorRgba[3] = IsoTypeReader.readUInt8(content);
+        boxRecord = new BoxRecord();
+        boxRecord.parse(content);
+
+        styleRecord = new StyleRecord();
+        styleRecord.parse(content);
+        _parseChildBoxes(content);
+    }
+
+
+    protected long getContentSize() {
+        long contentSize = 18;
+        contentSize += boxRecord.getSize();
+        contentSize += styleRecord.getSize();
+        for (Box boxe : boxes) {
+            contentSize += boxe.getSize();
+        }
+        return contentSize;
+    }
+
+    public String toString() {
+        return "TextSampleEntry";
+    }
+
+    @Override
+    protected void getContent(ByteBuffer byteBuffer) {
+        _writeReservedAndDataReferenceIndex(byteBuffer);
+        IsoTypeWriter.writeUInt32(byteBuffer, displayFlags);
+        IsoTypeWriter.writeUInt8(byteBuffer, horizontalJustification);
+        IsoTypeWriter.writeUInt8(byteBuffer, verticalJustification);
+        IsoTypeWriter.writeUInt8(byteBuffer, backgroundColorRgba[0]);
+        IsoTypeWriter.writeUInt8(byteBuffer, backgroundColorRgba[1]);
+        IsoTypeWriter.writeUInt8(byteBuffer, backgroundColorRgba[2]);
+        IsoTypeWriter.writeUInt8(byteBuffer, backgroundColorRgba[3]);
+        boxRecord.getContent(byteBuffer);
+        styleRecord.getContent(byteBuffer);
+
+        _writeChildBoxes(byteBuffer);
+    }
+
+    public BoxRecord getBoxRecord() {
+        return boxRecord;
+    }
+
+    public void setBoxRecord(BoxRecord boxRecord) {
+        this.boxRecord = boxRecord;
+    }
+
+    public StyleRecord getStyleRecord() {
+        return styleRecord;
+    }
+
+    public void setStyleRecord(StyleRecord styleRecord) {
+        this.styleRecord = styleRecord;
+    }
+
+    public boolean isScrollIn() {
+        return (displayFlags & 0x00000020) == 0x00000020;
+    }
+
+    public void setScrollIn(boolean scrollIn) {
+        if (scrollIn) {
+            displayFlags |= 0x00000020;
+        } else {
+            displayFlags &= ~0x00000020;
+        }
+    }
+
+    public boolean isScrollOut() {
+        return (displayFlags & 0x00000040) == 0x00000040;
+    }
+
+    public void setScrollOut(boolean scrollOutIn) {
+        if (scrollOutIn) {
+            displayFlags |= 0x00000040;
+        } else {
+            displayFlags &= ~0x00000040;
+        }
+    }
+
+    public boolean isScrollDirection() {
+        return (displayFlags & 0x00000180) == 0x00000180;
+    }
+
+    public void setScrollDirection(boolean scrollOutIn) {
+        if (scrollOutIn) {
+            displayFlags |= 0x00000180;
+        } else {
+            displayFlags &= ~0x00000180;
+        }
+    }
+
+    public boolean isContinuousKaraoke() {
+        return (displayFlags & 0x00000800) == 0x00000800;
+    }
+
+    public void setContinuousKaraoke(boolean continuousKaraoke) {
+        if (continuousKaraoke) {
+            displayFlags |= 0x00000800;
+        } else {
+            displayFlags &= ~0x00000800;
+        }
+    }
+
+    public boolean isWriteTextVertically() {
+        return (displayFlags & 0x00020000) == 0x00020000;
+    }
+
+    public void setWriteTextVertically(boolean writeTextVertically) {
+        if (writeTextVertically) {
+            displayFlags |= 0x00020000;
+        } else {
+            displayFlags &= ~0x00020000;
+        }
+    }
+
+
+    public boolean isFillTextRegion() {
+        return (displayFlags & 0x00040000) == 0x00040000;
+    }
+
+    public void setFillTextRegion(boolean fillTextRegion) {
+        if (fillTextRegion) {
+            displayFlags |= 0x00040000;
+        } else {
+            displayFlags &= ~0x00040000;
+        }
+    }
+
+
+    public int getHorizontalJustification() {
+        return horizontalJustification;
+    }
+
+    public void setHorizontalJustification(int horizontalJustification) {
+        this.horizontalJustification = horizontalJustification;
+    }
+
+    public int getVerticalJustification() {
+        return verticalJustification;
+    }
+
+    public void setVerticalJustification(int verticalJustification) {
+        this.verticalJustification = verticalJustification;
+    }
+
+    public int[] getBackgroundColorRgba() {
+        return backgroundColorRgba;
+    }
+
+    public void setBackgroundColorRgba(int[] backgroundColorRgba) {
+        this.backgroundColorRgba = backgroundColorRgba;
+    }
+
+    public static class BoxRecord {
+        int top;
+        int left;
+        int bottom;
+        int right;
+
+        public void parse(ByteBuffer in) {
+            top = IsoTypeReader.readUInt16(in);
+            left = IsoTypeReader.readUInt16(in);
+            bottom = IsoTypeReader.readUInt16(in);
+            right = IsoTypeReader.readUInt16(in);
+        }
+
+        public void getContent(ByteBuffer bb)  {
+            IsoTypeWriter.writeUInt16(bb, top);
+            IsoTypeWriter.writeUInt16(bb, left);
+            IsoTypeWriter.writeUInt16(bb, bottom);
+            IsoTypeWriter.writeUInt16(bb, right);
+        }
+
+        public int getSize() {
+            return 8;
+        }
+    }
+
+    /*
+    class FontRecord {
+	unsigned int(16) 	font-ID;
+	unsigned int(8)	font-name-length;
+	unsigned int(8)	font[font-name-length];
+}
+     */
+
+
+    /*
+   aligned(8) class StyleRecord {
+   unsigned int(16) 	startChar;
+   unsigned int(16)	endChar;
+   unsigned int(16)	font-ID;
+   unsigned int(8)	face-style-flags;
+   unsigned int(8)	font-size;
+   unsigned int(8)	text-color-rgba[4];
+}
+    */
+    public static class StyleRecord {
+        int startChar;
+        int endChar;
+        int fontId;
+        int faceStyleFlags;
+        int fontSize;
+        int[] textColor = new int[]{0xff, 0xff, 0xff, 0xff};
+
+        public void parse(ByteBuffer in) {
+            startChar = IsoTypeReader.readUInt16(in);
+            endChar = IsoTypeReader.readUInt16(in);
+            fontId = IsoTypeReader.readUInt16(in);
+            faceStyleFlags = IsoTypeReader.readUInt8(in);
+            fontSize = IsoTypeReader.readUInt8(in);
+            textColor = new int[4];
+            textColor[0] = IsoTypeReader.readUInt8(in);
+            textColor[1] = IsoTypeReader.readUInt8(in);
+            textColor[2] = IsoTypeReader.readUInt8(in);
+            textColor[3] = IsoTypeReader.readUInt8(in);
+        }
+
+
+        public void getContent(ByteBuffer bb) {
+            IsoTypeWriter.writeUInt16(bb, startChar);
+            IsoTypeWriter.writeUInt16(bb, endChar);
+            IsoTypeWriter.writeUInt16(bb, fontId);
+            IsoTypeWriter.writeUInt8(bb, faceStyleFlags);
+            IsoTypeWriter.writeUInt8(bb, fontSize);
+            IsoTypeWriter.writeUInt8(bb, textColor[0]);
+            IsoTypeWriter.writeUInt8(bb, textColor[1]);
+            IsoTypeWriter.writeUInt8(bb, textColor[2]);
+            IsoTypeWriter.writeUInt8(bb, textColor[3]);
+        }
+
+        public int getSize() {
+            return 12;
+        }
+    }
+
+
+}
diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/sampleentry/VisualSampleEntry.java b/isoparser/src/main/java/com/coremedia/iso/boxes/sampleentry/VisualSampleEntry.java
new file mode 100644
index 0000000..407e79f
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/sampleentry/VisualSampleEntry.java
@@ -0,0 +1,213 @@
+/*  
+ * Copyright 2008 CoreMedia AG, Hamburg
+ *
+ * Licensed under the Apache License, Version 2.0 (the License); 
+ * you may not use this file except in compliance with the License. 
+ * You may obtain a copy of the License at 
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0 
+ * 
+ * Unless required by applicable law or agreed to in writing, software 
+ * distributed under the License is distributed on an AS IS BASIS, 
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+ * See the License for the specific language governing permissions and 
+ * limitations under the License. 
+ */
+
+package com.coremedia.iso.boxes.sampleentry;
+
+import com.coremedia.iso.IsoTypeReader;
+import com.coremedia.iso.IsoTypeWriter;
+import com.coremedia.iso.Utf8;
+import com.coremedia.iso.boxes.Box;
+import com.coremedia.iso.boxes.ContainerBox;
+
+import java.nio.ByteBuffer;
+
+/**
+ * Contains information common to all visual tracks.
+ * <code>
+ * <pre>
+ * class VisualSampleEntry(codingname) extends SampleEntry (codingname){
+ * unsigned int(16) pre_defined = 0;
+ * const unsigned int(16) reserved = 0;
+ * unsigned int(32)[3] pre_defined = 0;
+ * unsigned int(16) width;
+ * unsigned int(16) height;
+ * template unsigned int(32) horizresolution = 0x00480000; // 72 dpi
+ * template unsigned int(32) vertresolution = 0x00480000; // 72 dpi
+ * const unsigned int(32) reserved = 0;
+ * template unsigned int(16) frame_count = 1;
+ * string[32] compressorname;
+ * template unsigned int(16) depth = 0x0018;
+ * int(16) pre_defined = -1;
+ * }<br>
+ * </pre>
+ * </code>
+ * <p/>
+ * Format-specific informationis appened as boxes after the data described in ISO/IEC 14496-12 chapter 8.16.2.
+ */
+public class VisualSampleEntry extends SampleEntry implements ContainerBox {
+    public static final String TYPE1 = "mp4v";
+    public static final String TYPE2 = "s263";
+    public static final String TYPE3 = "avc1";
+
+
+    /**
+     * Identifier for an encrypted video track.
+     *
+     * @see com.coremedia.iso.boxes.ProtectionSchemeInformationBox
+     */
+    public static final String TYPE_ENCRYPTED = "encv";
+
+
+    private int width;
+    private int height;
+    private double horizresolution = 72;
+    private double vertresolution = 72;
+    private int frameCount = 1;
+    private String compressorname;
+    private int depth = 24;
+
+    private long[] predefined = new long[3];
+
+    public VisualSampleEntry(String type) {
+        super(type);
+    }
+
+    public int getWidth() {
+        return width;
+    }
+
+    public int getHeight() {
+        return height;
+    }
+
+    public double getHorizresolution() {
+        return horizresolution;
+    }
+
+    public double getVertresolution() {
+        return vertresolution;
+    }
+
+    public int getFrameCount() {
+        return frameCount;
+    }
+
+    public String getCompressorname() {
+        return compressorname;
+    }
+
+    public int getDepth() {
+        return depth;
+    }
+
+    public void setCompressorname(String compressorname) {
+        this.compressorname = compressorname;
+    }
+
+    public void setWidth(int width) {
+        this.width = width;
+    }
+
+    public void setHeight(int height) {
+        this.height = height;
+    }
+
+    public void setHorizresolution(double horizresolution) {
+        this.horizresolution = horizresolution;
+    }
+
+    public void setVertresolution(double vertresolution) {
+        this.vertresolution = vertresolution;
+    }
+
+    public void setFrameCount(int frameCount) {
+        this.frameCount = frameCount;
+    }
+
+    public void setDepth(int depth) {
+        this.depth = depth;
+    }
+
+    @Override
+    public void _parseDetails(ByteBuffer content) {
+        _parseReservedAndDataReferenceIndex(content);
+        long tmp = IsoTypeReader.readUInt16(content);
+        assert 0 == tmp : "reserved byte not 0";
+        tmp = IsoTypeReader.readUInt16(content);
+        assert 0 == tmp : "reserved byte not 0";
+        predefined[0] = IsoTypeReader.readUInt32(content);     // should be zero
+        predefined[1] = IsoTypeReader.readUInt32(content);     // should be zero
+        predefined[2] = IsoTypeReader.readUInt32(content);     // should be zero
+        width = IsoTypeReader.readUInt16(content);
+        height = IsoTypeReader.readUInt16(content);
+        horizresolution = IsoTypeReader.readFixedPoint1616(content);
+        vertresolution = IsoTypeReader.readFixedPoint1616(content);
+        tmp = IsoTypeReader.readUInt32(content);
+        assert 0 == tmp : "reserved byte not 0";
+        frameCount = IsoTypeReader.readUInt16(content);
+        int compressornameDisplayAbleData = IsoTypeReader.readUInt8(content);
+        if (compressornameDisplayAbleData > 31) {
+            System.out.println("invalid compressor name displayable data: " + compressornameDisplayAbleData);
+            compressornameDisplayAbleData = 31;
+        }
+        byte[] bytes = new byte[compressornameDisplayAbleData];
+        content.get(bytes);
+        compressorname = Utf8.convert(bytes);
+        if (compressornameDisplayAbleData < 31) {
+            byte[] zeros = new byte[31 - compressornameDisplayAbleData];
+            content.get(zeros);
+            //assert Arrays.equals(zeros, new byte[zeros.length]) : "The compressor name length was not filled up with zeros";
+        }
+        depth = IsoTypeReader.readUInt16(content);
+        tmp = IsoTypeReader.readUInt16(content);
+        assert 0xFFFF == tmp;
+
+        _parseChildBoxes(content);
+
+    }
+
+
+    protected long getContentSize() {
+        long contentSize = 78;
+        for (Box boxe : boxes) {
+            contentSize += boxe.getSize();
+        }
+        return contentSize;
+    }
+
+    @Override
+    protected void getContent(ByteBuffer byteBuffer) {
+        _writeReservedAndDataReferenceIndex(byteBuffer);
+        IsoTypeWriter.writeUInt16(byteBuffer, 0);
+        IsoTypeWriter.writeUInt16(byteBuffer, 0);
+        IsoTypeWriter.writeUInt32(byteBuffer, predefined[0]);
+        IsoTypeWriter.writeUInt32(byteBuffer, predefined[1]);
+        IsoTypeWriter.writeUInt32(byteBuffer, predefined[2]);
+
+        IsoTypeWriter.writeUInt16(byteBuffer, getWidth());
+        IsoTypeWriter.writeUInt16(byteBuffer, getHeight());
+
+        IsoTypeWriter.writeFixedPont1616(byteBuffer, getHorizresolution());
+        IsoTypeWriter.writeFixedPont1616(byteBuffer, getVertresolution());
+
+
+        IsoTypeWriter.writeUInt32(byteBuffer, 0);
+        IsoTypeWriter.writeUInt16(byteBuffer, getFrameCount());
+        IsoTypeWriter.writeUInt8(byteBuffer, Utf8.utf8StringLengthInBytes(getCompressorname()));
+        byteBuffer.put(Utf8.convert(getCompressorname()));
+        int a = Utf8.utf8StringLengthInBytes(getCompressorname());
+        while (a < 31) {
+            a++;
+            byteBuffer.put((byte) 0);
+        }
+        IsoTypeWriter.writeUInt16(byteBuffer, getDepth());
+        IsoTypeWriter.writeUInt16(byteBuffer, 0xFFFF);
+
+        _writeChildBoxes(byteBuffer);
+
+    }
+
+}
diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/threegpp26244/.svn/all-wcprops b/isoparser/src/main/java/com/coremedia/iso/boxes/threegpp26244/.svn/all-wcprops
new file mode 100644
index 0000000..da12da8
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/threegpp26244/.svn/all-wcprops
@@ -0,0 +1,11 @@
+K 25
+svn:wc:ra_dav:version-url
+V 85
+/svn/!svn/ver/507/trunk/isoparser/src/main/java/com/coremedia/iso/boxes/threegpp26244
+END
+LocationInformationBox.java
+K 25
+svn:wc:ra_dav:version-url
+V 113
+/svn/!svn/ver/507/trunk/isoparser/src/main/java/com/coremedia/iso/boxes/threegpp26244/LocationInformationBox.java
+END
diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/threegpp26244/.svn/entries b/isoparser/src/main/java/com/coremedia/iso/boxes/threegpp26244/.svn/entries
new file mode 100644
index 0000000..b3a35ea
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/threegpp26244/.svn/entries
@@ -0,0 +1,62 @@
+10
+
+dir
+778
+http://mp4parser.googlecode.com/svn/trunk/isoparser/src/main/java/com/coremedia/iso/boxes/threegpp26244
+http://mp4parser.googlecode.com/svn
+
+
+
+2012-04-21T22:05:38.425329Z
+507
+Sebastian.Annies@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+7decde4b-c250-0410-a0da-51896bc88be6
+
+LocationInformationBox.java
+file
+
+
+
+
+2012-09-14T17:27:52.867252Z
+e71dfcd8b93af51a55331fb161d8cb88
+2012-04-21T22:05:38.425329Z
+507
+Sebastian.Annies@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+3428
+
diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/threegpp26244/.svn/text-base/LocationInformationBox.java.svn-base b/isoparser/src/main/java/com/coremedia/iso/boxes/threegpp26244/.svn/text-base/LocationInformationBox.java.svn-base
new file mode 100644
index 0000000..089d97b
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/threegpp26244/.svn/text-base/LocationInformationBox.java.svn-base
@@ -0,0 +1,126 @@
+package com.coremedia.iso.boxes.threegpp26244;
+
+import com.coremedia.iso.IsoTypeReader;
+import com.coremedia.iso.IsoTypeWriter;
+import com.coremedia.iso.Utf8;
+import com.googlecode.mp4parser.AbstractFullBox;
+
+import java.nio.ByteBuffer;
+
+/**
+ * Location Information Box as specified in TS 26.244.
+ */
+public class LocationInformationBox extends AbstractFullBox {
+    public static final String TYPE = "loci";
+
+    private String language;
+    private String name = "";
+    private int role;
+    private double longitude;
+    private double latitude;
+    private double altitude;
+    private String astronomicalBody = "";
+    private String additionalNotes = "";
+
+    public LocationInformationBox() {
+        super(TYPE);
+    }
+
+    public String getLanguage() {
+        return language;
+    }
+
+    public void setLanguage(String language) {
+        this.language = language;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    public int getRole() {
+        return role;
+    }
+
+    public void setRole(int role) {
+        this.role = role;
+    }
+
+    public double getLongitude() {
+        return longitude;
+    }
+
+    public void setLongitude(double longitude) {
+        this.longitude = longitude;
+    }
+
+    public double getLatitude() {
+        return latitude;
+    }
+
+    public void setLatitude(double latitude) {
+        this.latitude = latitude;
+    }
+
+    public double getAltitude() {
+        return altitude;
+    }
+
+    public void setAltitude(double altitude) {
+        this.altitude = altitude;
+    }
+
+    public String getAstronomicalBody() {
+        return astronomicalBody;
+    }
+
+    public void setAstronomicalBody(String astronomicalBody) {
+        this.astronomicalBody = astronomicalBody;
+    }
+
+    public String getAdditionalNotes() {
+        return additionalNotes;
+    }
+
+    public void setAdditionalNotes(String additionalNotes) {
+        this.additionalNotes = additionalNotes;
+    }
+
+    protected long getContentSize() {
+        return 22 + Utf8.convert(name).length + Utf8.convert(astronomicalBody).length + Utf8.convert(additionalNotes).length;
+    }
+
+    @Override
+    public void _parseDetails(ByteBuffer content) {
+        parseVersionAndFlags(content);
+        language = IsoTypeReader.readIso639(content);
+        name = IsoTypeReader.readString(content);
+        role = IsoTypeReader.readUInt8(content);
+        longitude = IsoTypeReader.readFixedPoint1616(content);
+        latitude = IsoTypeReader.readFixedPoint1616(content);
+        altitude = IsoTypeReader.readFixedPoint1616(content);
+        astronomicalBody = IsoTypeReader.readString(content);
+        additionalNotes = IsoTypeReader.readString(content);
+    }
+
+
+    @Override
+    protected void getContent(ByteBuffer byteBuffer) {
+        writeVersionAndFlags(byteBuffer);
+        IsoTypeWriter.writeIso639(byteBuffer, language);
+        byteBuffer.put(Utf8.convert(name));
+        byteBuffer.put((byte) 0);
+        IsoTypeWriter.writeUInt8(byteBuffer, role);
+        IsoTypeWriter.writeFixedPont1616(byteBuffer, longitude);
+        IsoTypeWriter.writeFixedPont1616(byteBuffer, latitude);
+        IsoTypeWriter.writeFixedPont1616(byteBuffer, altitude);
+        byteBuffer.put(Utf8.convert(astronomicalBody));
+        byteBuffer.put((byte) 0);
+        byteBuffer.put(Utf8.convert(additionalNotes));
+        byteBuffer.put((byte) 0);
+    }
+}
diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/threegpp26244/LocationInformationBox.java b/isoparser/src/main/java/com/coremedia/iso/boxes/threegpp26244/LocationInformationBox.java
new file mode 100644
index 0000000..089d97b
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/threegpp26244/LocationInformationBox.java
@@ -0,0 +1,126 @@
+package com.coremedia.iso.boxes.threegpp26244;
+
+import com.coremedia.iso.IsoTypeReader;
+import com.coremedia.iso.IsoTypeWriter;
+import com.coremedia.iso.Utf8;
+import com.googlecode.mp4parser.AbstractFullBox;
+
+import java.nio.ByteBuffer;
+
+/**
+ * Location Information Box as specified in TS 26.244.
+ */
+public class LocationInformationBox extends AbstractFullBox {
+    public static final String TYPE = "loci";
+
+    private String language;
+    private String name = "";
+    private int role;
+    private double longitude;
+    private double latitude;
+    private double altitude;
+    private String astronomicalBody = "";
+    private String additionalNotes = "";
+
+    public LocationInformationBox() {
+        super(TYPE);
+    }
+
+    public String getLanguage() {
+        return language;
+    }
+
+    public void setLanguage(String language) {
+        this.language = language;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    public int getRole() {
+        return role;
+    }
+
+    public void setRole(int role) {
+        this.role = role;
+    }
+
+    public double getLongitude() {
+        return longitude;
+    }
+
+    public void setLongitude(double longitude) {
+        this.longitude = longitude;
+    }
+
+    public double getLatitude() {
+        return latitude;
+    }
+
+    public void setLatitude(double latitude) {
+        this.latitude = latitude;
+    }
+
+    public double getAltitude() {
+        return altitude;
+    }
+
+    public void setAltitude(double altitude) {
+        this.altitude = altitude;
+    }
+
+    public String getAstronomicalBody() {
+        return astronomicalBody;
+    }
+
+    public void setAstronomicalBody(String astronomicalBody) {
+        this.astronomicalBody = astronomicalBody;
+    }
+
+    public String getAdditionalNotes() {
+        return additionalNotes;
+    }
+
+    public void setAdditionalNotes(String additionalNotes) {
+        this.additionalNotes = additionalNotes;
+    }
+
+    protected long getContentSize() {
+        return 22 + Utf8.convert(name).length + Utf8.convert(astronomicalBody).length + Utf8.convert(additionalNotes).length;
+    }
+
+    @Override
+    public void _parseDetails(ByteBuffer content) {
+        parseVersionAndFlags(content);
+        language = IsoTypeReader.readIso639(content);
+        name = IsoTypeReader.readString(content);
+        role = IsoTypeReader.readUInt8(content);
+        longitude = IsoTypeReader.readFixedPoint1616(content);
+        latitude = IsoTypeReader.readFixedPoint1616(content);
+        altitude = IsoTypeReader.readFixedPoint1616(content);
+        astronomicalBody = IsoTypeReader.readString(content);
+        additionalNotes = IsoTypeReader.readString(content);
+    }
+
+
+    @Override
+    protected void getContent(ByteBuffer byteBuffer) {
+        writeVersionAndFlags(byteBuffer);
+        IsoTypeWriter.writeIso639(byteBuffer, language);
+        byteBuffer.put(Utf8.convert(name));
+        byteBuffer.put((byte) 0);
+        IsoTypeWriter.writeUInt8(byteBuffer, role);
+        IsoTypeWriter.writeFixedPont1616(byteBuffer, longitude);
+        IsoTypeWriter.writeFixedPont1616(byteBuffer, latitude);
+        IsoTypeWriter.writeFixedPont1616(byteBuffer, altitude);
+        byteBuffer.put(Utf8.convert(astronomicalBody));
+        byteBuffer.put((byte) 0);
+        byteBuffer.put(Utf8.convert(additionalNotes));
+        byteBuffer.put((byte) 0);
+    }
+}
diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/vodafone/.svn/all-wcprops b/isoparser/src/main/java/com/coremedia/iso/boxes/vodafone/.svn/all-wcprops
new file mode 100644
index 0000000..b46dee4
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/vodafone/.svn/all-wcprops
@@ -0,0 +1,29 @@
+K 25
+svn:wc:ra_dav:version-url
+V 80
+/svn/!svn/ver/507/trunk/isoparser/src/main/java/com/coremedia/iso/boxes/vodafone
+END
+AlbumArtistBox.java
+K 25
+svn:wc:ra_dav:version-url
+V 100
+/svn/!svn/ver/507/trunk/isoparser/src/main/java/com/coremedia/iso/boxes/vodafone/AlbumArtistBox.java
+END
+CoverUriBox.java
+K 25
+svn:wc:ra_dav:version-url
+V 97
+/svn/!svn/ver/507/trunk/isoparser/src/main/java/com/coremedia/iso/boxes/vodafone/CoverUriBox.java
+END
+ContentDistributorIdBox.java
+K 25
+svn:wc:ra_dav:version-url
+V 109
+/svn/!svn/ver/507/trunk/isoparser/src/main/java/com/coremedia/iso/boxes/vodafone/ContentDistributorIdBox.java
+END
+LyricsUriBox.java
+K 25
+svn:wc:ra_dav:version-url
+V 98
+/svn/!svn/ver/507/trunk/isoparser/src/main/java/com/coremedia/iso/boxes/vodafone/LyricsUriBox.java
+END
diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/vodafone/.svn/entries b/isoparser/src/main/java/com/coremedia/iso/boxes/vodafone/.svn/entries
new file mode 100644
index 0000000..15f0da6
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/vodafone/.svn/entries
@@ -0,0 +1,164 @@
+10
+
+dir
+778
+http://mp4parser.googlecode.com/svn/trunk/isoparser/src/main/java/com/coremedia/iso/boxes/vodafone
+http://mp4parser.googlecode.com/svn
+
+
+
+2012-04-21T22:05:38.425329Z
+507
+Sebastian.Annies@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+7decde4b-c250-0410-a0da-51896bc88be6
+
+AlbumArtistBox.java
+file
+
+
+
+
+2012-09-14T17:27:52.067241Z
+973d28c2a51998190028321bb407ac03
+2012-04-21T22:05:38.425329Z
+507
+Sebastian.Annies@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+2322
+
+CoverUriBox.java
+file
+
+
+
+
+2012-09-14T17:27:52.067241Z
+142d0171f6ace065d723ff0f1ca68101
+2012-04-21T22:05:38.425329Z
+507
+Sebastian.Annies@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+1753
+
+ContentDistributorIdBox.java
+file
+
+
+
+
+2012-09-14T17:27:52.067241Z
+5e3e0bf310b779bd3c23bf4a100f1dc8
+2012-04-21T22:05:38.425329Z
+507
+Sebastian.Annies@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+2091
+
+LyricsUriBox.java
+file
+
+
+
+
+2012-09-14T17:27:52.067241Z
+7aebcd173c05102c97a5bb61874f260d
+2012-04-21T22:05:38.425329Z
+507
+Sebastian.Annies@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+1873
+
diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/vodafone/.svn/text-base/AlbumArtistBox.java.svn-base b/isoparser/src/main/java/com/coremedia/iso/boxes/vodafone/.svn/text-base/AlbumArtistBox.java.svn-base
new file mode 100644
index 0000000..aba12a4
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/vodafone/.svn/text-base/AlbumArtistBox.java.svn-base
@@ -0,0 +1,78 @@
+/*  
+ * Copyright 2008 CoreMedia AG, Hamburg
+ *
+ * Licensed under the Apache License, Version 2.0 (the License); 
+ * you may not use this file except in compliance with the License. 
+ * You may obtain a copy of the License at 
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0 
+ * 
+ * Unless required by applicable law or agreed to in writing, software 
+ * distributed under the License is distributed on an AS IS BASIS, 
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+ * See the License for the specific language governing permissions and 
+ * limitations under the License. 
+ */
+
+package com.coremedia.iso.boxes.vodafone;
+
+
+import com.coremedia.iso.IsoTypeReader;
+import com.coremedia.iso.IsoTypeWriter;
+import com.coremedia.iso.Utf8;
+import com.googlecode.mp4parser.AbstractFullBox;
+
+import java.nio.ByteBuffer;
+
+/**
+ * Special box used by Vodafone in their DCF containing information about the artist. Mainly used for OMA DCF files
+ * containing music. Resides in the {@link com.coremedia.iso.boxes.UserDataBox}.
+ */
+public class AlbumArtistBox extends AbstractFullBox {
+    public static final String TYPE = "albr";
+
+    private String language;
+    private String albumArtist;
+
+    public AlbumArtistBox() {
+        super(TYPE);
+    }
+
+    public String getLanguage() {
+        return language;
+    }
+
+    public String getAlbumArtist() {
+        return albumArtist;
+    }
+
+    public void setLanguage(String language) {
+        this.language = language;
+    }
+
+    public void setAlbumArtist(String albumArtist) {
+        this.albumArtist = albumArtist;
+    }
+
+    protected long getContentSize() {
+        return 6 + Utf8.utf8StringLengthInBytes(albumArtist) + 1;
+    }
+
+    @Override
+    public void _parseDetails(ByteBuffer content) {
+        parseVersionAndFlags(content);
+        language = IsoTypeReader.readIso639(content);
+        albumArtist = IsoTypeReader.readString(content);
+    }
+
+    protected void getContent(ByteBuffer byteBuffer) {
+        writeVersionAndFlags(byteBuffer);
+        IsoTypeWriter.writeIso639(byteBuffer, language);
+        byteBuffer.put(Utf8.convert(albumArtist));
+        byteBuffer.put((byte) 0);
+    }
+
+    public String toString() {
+        return "AlbumArtistBox[language=" + getLanguage() + ";albumArtist=" + getAlbumArtist() + "]";
+    }
+}
diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/vodafone/.svn/text-base/ContentDistributorIdBox.java.svn-base b/isoparser/src/main/java/com/coremedia/iso/boxes/vodafone/.svn/text-base/ContentDistributorIdBox.java.svn-base
new file mode 100644
index 0000000..dc36f45
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/vodafone/.svn/text-base/ContentDistributorIdBox.java.svn-base
@@ -0,0 +1,70 @@
+/*  
+ * Copyright 2008 CoreMedia AG, Hamburg
+ *
+ * Licensed under the Apache License, Version 2.0 (the License); 
+ * you may not use this file except in compliance with the License. 
+ * You may obtain a copy of the License at 
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0 
+ * 
+ * Unless required by applicable law or agreed to in writing, software 
+ * distributed under the License is distributed on an AS IS BASIS, 
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+ * See the License for the specific language governing permissions and 
+ * limitations under the License. 
+ */
+
+package com.coremedia.iso.boxes.vodafone;
+
+import com.coremedia.iso.IsoTypeReader;
+import com.coremedia.iso.IsoTypeWriter;
+import com.coremedia.iso.Utf8;
+import com.googlecode.mp4parser.AbstractFullBox;
+
+import java.nio.ByteBuffer;
+
+/**
+ * Vodafone specific box. Usage unclear.
+ */
+public class ContentDistributorIdBox extends AbstractFullBox {
+    public static final String TYPE = "cdis";
+
+    private String language;
+    private String contentDistributorId;
+
+    public ContentDistributorIdBox() {
+        super(TYPE);
+    }
+
+    public String getLanguage() {
+        return language;
+    }
+
+    public String getContentDistributorId() {
+        return contentDistributorId;
+    }
+
+    protected long getContentSize() {
+        return 2 + Utf8.utf8StringLengthInBytes(contentDistributorId) + 5;
+    }
+
+    @Override
+    public void _parseDetails(ByteBuffer content) {
+        parseVersionAndFlags(content);
+        language = IsoTypeReader.readIso639(content);
+        contentDistributorId = IsoTypeReader.readString(content);
+    }
+
+    @Override
+    protected void getContent(ByteBuffer byteBuffer) {
+        writeVersionAndFlags(byteBuffer);
+        IsoTypeWriter.writeIso639(byteBuffer, language);
+        byteBuffer.put(Utf8.convert(contentDistributorId));
+        byteBuffer.put((byte) 0);
+
+    }
+
+    public String toString() {
+        return "ContentDistributorIdBox[language=" + getLanguage() + ";contentDistributorId=" + getContentDistributorId() + "]";
+    }
+}
diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/vodafone/.svn/text-base/CoverUriBox.java.svn-base b/isoparser/src/main/java/com/coremedia/iso/boxes/vodafone/.svn/text-base/CoverUriBox.java.svn-base
new file mode 100644
index 0000000..0e78b25
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/vodafone/.svn/text-base/CoverUriBox.java.svn-base
@@ -0,0 +1,66 @@
+/*  
+ * Copyright 2008 CoreMedia AG, Hamburg
+ *
+ * Licensed under the Apache License, Version 2.0 (the License); 
+ * you may not use this file except in compliance with the License. 
+ * You may obtain a copy of the License at 
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0 
+ * 
+ * Unless required by applicable law or agreed to in writing, software 
+ * distributed under the License is distributed on an AS IS BASIS, 
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+ * See the License for the specific language governing permissions and 
+ * limitations under the License. 
+ */
+
+package com.coremedia.iso.boxes.vodafone;
+
+import com.coremedia.iso.IsoTypeReader;
+import com.coremedia.iso.Utf8;
+import com.googlecode.mp4parser.AbstractFullBox;
+
+import java.nio.ByteBuffer;
+
+/**
+ * A vodafone specific box.
+ */
+public class CoverUriBox extends AbstractFullBox {
+    public static final String TYPE = "cvru";
+
+    private String coverUri;
+
+    public CoverUriBox() {
+        super(TYPE);
+    }
+
+    public String getCoverUri() {
+        return coverUri;
+    }
+
+    public void setCoverUri(String coverUri) {
+        this.coverUri = coverUri;
+    }
+
+    protected long getContentSize() {
+        return Utf8.utf8StringLengthInBytes(coverUri) + 5;
+    }
+
+    @Override
+    public void _parseDetails(ByteBuffer content) {
+        parseVersionAndFlags(content);
+        coverUri = IsoTypeReader.readString(content);
+    }
+
+    @Override
+    protected void getContent(ByteBuffer byteBuffer) {
+        writeVersionAndFlags(byteBuffer);
+        byteBuffer.put(Utf8.convert(coverUri));
+        byteBuffer.put((byte) 0);
+    }
+
+
+    public String toString() {
+        return "CoverUriBox[coverUri=" + getCoverUri() + "]";
+    }
+}
diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/vodafone/.svn/text-base/LyricsUriBox.java.svn-base b/isoparser/src/main/java/com/coremedia/iso/boxes/vodafone/.svn/text-base/LyricsUriBox.java.svn-base
new file mode 100644
index 0000000..fbfc243
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/vodafone/.svn/text-base/LyricsUriBox.java.svn-base
@@ -0,0 +1,66 @@
+/*  
+ * Copyright 2008 CoreMedia AG, Hamburg
+ *
+ * Licensed under the Apache License, Version 2.0 (the License); 
+ * you may not use this file except in compliance with the License. 
+ * You may obtain a copy of the License at 
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0 
+ * 
+ * Unless required by applicable law or agreed to in writing, software 
+ * distributed under the License is distributed on an AS IS BASIS, 
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+ * See the License for the specific language governing permissions and 
+ * limitations under the License. 
+ */
+
+package com.coremedia.iso.boxes.vodafone;
+
+import com.coremedia.iso.IsoTypeReader;
+import com.coremedia.iso.Utf8;
+import com.googlecode.mp4parser.AbstractFullBox;
+
+import java.nio.ByteBuffer;
+
+/**
+ * A box in the {@link com.coremedia.iso.boxes.UserDataBox} containing information about the lyric location.
+ * Invented by Vodafone.
+ */
+public class LyricsUriBox extends AbstractFullBox {
+    public static final String TYPE = "lrcu";
+
+    private String lyricsUri;
+
+    public LyricsUriBox() {
+        super(TYPE);
+    }
+
+    public String getLyricsUri() {
+        return lyricsUri;
+    }
+
+    public void setLyricsUri(String lyricsUri) {
+        this.lyricsUri = lyricsUri;
+    }
+
+    protected long getContentSize() {
+        return Utf8.utf8StringLengthInBytes(lyricsUri) + 5;
+    }
+
+    @Override
+    public void _parseDetails(ByteBuffer content) {
+        parseVersionAndFlags(content);
+        lyricsUri = IsoTypeReader.readString(content);
+    }
+
+    @Override
+    protected void getContent(ByteBuffer byteBuffer) {
+        writeVersionAndFlags(byteBuffer);
+        byteBuffer.put(Utf8.convert(lyricsUri));
+        byteBuffer.put((byte) 0);
+    }
+
+    public String toString() {
+        return "LyricsUriBox[lyricsUri=" + getLyricsUri() + "]";
+    }
+}
diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/vodafone/AlbumArtistBox.java b/isoparser/src/main/java/com/coremedia/iso/boxes/vodafone/AlbumArtistBox.java
new file mode 100644
index 0000000..aba12a4
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/vodafone/AlbumArtistBox.java
@@ -0,0 +1,78 @@
+/*  
+ * Copyright 2008 CoreMedia AG, Hamburg
+ *
+ * Licensed under the Apache License, Version 2.0 (the License); 
+ * you may not use this file except in compliance with the License. 
+ * You may obtain a copy of the License at 
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0 
+ * 
+ * Unless required by applicable law or agreed to in writing, software 
+ * distributed under the License is distributed on an AS IS BASIS, 
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+ * See the License for the specific language governing permissions and 
+ * limitations under the License. 
+ */
+
+package com.coremedia.iso.boxes.vodafone;
+
+
+import com.coremedia.iso.IsoTypeReader;
+import com.coremedia.iso.IsoTypeWriter;
+import com.coremedia.iso.Utf8;
+import com.googlecode.mp4parser.AbstractFullBox;
+
+import java.nio.ByteBuffer;
+
+/**
+ * Special box used by Vodafone in their DCF containing information about the artist. Mainly used for OMA DCF files
+ * containing music. Resides in the {@link com.coremedia.iso.boxes.UserDataBox}.
+ */
+public class AlbumArtistBox extends AbstractFullBox {
+    public static final String TYPE = "albr";
+
+    private String language;
+    private String albumArtist;
+
+    public AlbumArtistBox() {
+        super(TYPE);
+    }
+
+    public String getLanguage() {
+        return language;
+    }
+
+    public String getAlbumArtist() {
+        return albumArtist;
+    }
+
+    public void setLanguage(String language) {
+        this.language = language;
+    }
+
+    public void setAlbumArtist(String albumArtist) {
+        this.albumArtist = albumArtist;
+    }
+
+    protected long getContentSize() {
+        return 6 + Utf8.utf8StringLengthInBytes(albumArtist) + 1;
+    }
+
+    @Override
+    public void _parseDetails(ByteBuffer content) {
+        parseVersionAndFlags(content);
+        language = IsoTypeReader.readIso639(content);
+        albumArtist = IsoTypeReader.readString(content);
+    }
+
+    protected void getContent(ByteBuffer byteBuffer) {
+        writeVersionAndFlags(byteBuffer);
+        IsoTypeWriter.writeIso639(byteBuffer, language);
+        byteBuffer.put(Utf8.convert(albumArtist));
+        byteBuffer.put((byte) 0);
+    }
+
+    public String toString() {
+        return "AlbumArtistBox[language=" + getLanguage() + ";albumArtist=" + getAlbumArtist() + "]";
+    }
+}
diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/vodafone/ContentDistributorIdBox.java b/isoparser/src/main/java/com/coremedia/iso/boxes/vodafone/ContentDistributorIdBox.java
new file mode 100644
index 0000000..dc36f45
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/vodafone/ContentDistributorIdBox.java
@@ -0,0 +1,70 @@
+/*  
+ * Copyright 2008 CoreMedia AG, Hamburg
+ *
+ * Licensed under the Apache License, Version 2.0 (the License); 
+ * you may not use this file except in compliance with the License. 
+ * You may obtain a copy of the License at 
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0 
+ * 
+ * Unless required by applicable law or agreed to in writing, software 
+ * distributed under the License is distributed on an AS IS BASIS, 
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+ * See the License for the specific language governing permissions and 
+ * limitations under the License. 
+ */
+
+package com.coremedia.iso.boxes.vodafone;
+
+import com.coremedia.iso.IsoTypeReader;
+import com.coremedia.iso.IsoTypeWriter;
+import com.coremedia.iso.Utf8;
+import com.googlecode.mp4parser.AbstractFullBox;
+
+import java.nio.ByteBuffer;
+
+/**
+ * Vodafone specific box. Usage unclear.
+ */
+public class ContentDistributorIdBox extends AbstractFullBox {
+    public static final String TYPE = "cdis";
+
+    private String language;
+    private String contentDistributorId;
+
+    public ContentDistributorIdBox() {
+        super(TYPE);
+    }
+
+    public String getLanguage() {
+        return language;
+    }
+
+    public String getContentDistributorId() {
+        return contentDistributorId;
+    }
+
+    protected long getContentSize() {
+        return 2 + Utf8.utf8StringLengthInBytes(contentDistributorId) + 5;
+    }
+
+    @Override
+    public void _parseDetails(ByteBuffer content) {
+        parseVersionAndFlags(content);
+        language = IsoTypeReader.readIso639(content);
+        contentDistributorId = IsoTypeReader.readString(content);
+    }
+
+    @Override
+    protected void getContent(ByteBuffer byteBuffer) {
+        writeVersionAndFlags(byteBuffer);
+        IsoTypeWriter.writeIso639(byteBuffer, language);
+        byteBuffer.put(Utf8.convert(contentDistributorId));
+        byteBuffer.put((byte) 0);
+
+    }
+
+    public String toString() {
+        return "ContentDistributorIdBox[language=" + getLanguage() + ";contentDistributorId=" + getContentDistributorId() + "]";
+    }
+}
diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/vodafone/CoverUriBox.java b/isoparser/src/main/java/com/coremedia/iso/boxes/vodafone/CoverUriBox.java
new file mode 100644
index 0000000..0e78b25
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/vodafone/CoverUriBox.java
@@ -0,0 +1,66 @@
+/*  
+ * Copyright 2008 CoreMedia AG, Hamburg
+ *
+ * Licensed under the Apache License, Version 2.0 (the License); 
+ * you may not use this file except in compliance with the License. 
+ * You may obtain a copy of the License at 
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0 
+ * 
+ * Unless required by applicable law or agreed to in writing, software 
+ * distributed under the License is distributed on an AS IS BASIS, 
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+ * See the License for the specific language governing permissions and 
+ * limitations under the License. 
+ */
+
+package com.coremedia.iso.boxes.vodafone;
+
+import com.coremedia.iso.IsoTypeReader;
+import com.coremedia.iso.Utf8;
+import com.googlecode.mp4parser.AbstractFullBox;
+
+import java.nio.ByteBuffer;
+
+/**
+ * A vodafone specific box.
+ */
+public class CoverUriBox extends AbstractFullBox {
+    public static final String TYPE = "cvru";
+
+    private String coverUri;
+
+    public CoverUriBox() {
+        super(TYPE);
+    }
+
+    public String getCoverUri() {
+        return coverUri;
+    }
+
+    public void setCoverUri(String coverUri) {
+        this.coverUri = coverUri;
+    }
+
+    protected long getContentSize() {
+        return Utf8.utf8StringLengthInBytes(coverUri) + 5;
+    }
+
+    @Override
+    public void _parseDetails(ByteBuffer content) {
+        parseVersionAndFlags(content);
+        coverUri = IsoTypeReader.readString(content);
+    }
+
+    @Override
+    protected void getContent(ByteBuffer byteBuffer) {
+        writeVersionAndFlags(byteBuffer);
+        byteBuffer.put(Utf8.convert(coverUri));
+        byteBuffer.put((byte) 0);
+    }
+
+
+    public String toString() {
+        return "CoverUriBox[coverUri=" + getCoverUri() + "]";
+    }
+}
diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/vodafone/LyricsUriBox.java b/isoparser/src/main/java/com/coremedia/iso/boxes/vodafone/LyricsUriBox.java
new file mode 100644
index 0000000..fbfc243
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/boxes/vodafone/LyricsUriBox.java
@@ -0,0 +1,66 @@
+/*  
+ * Copyright 2008 CoreMedia AG, Hamburg
+ *
+ * Licensed under the Apache License, Version 2.0 (the License); 
+ * you may not use this file except in compliance with the License. 
+ * You may obtain a copy of the License at 
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0 
+ * 
+ * Unless required by applicable law or agreed to in writing, software 
+ * distributed under the License is distributed on an AS IS BASIS, 
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+ * See the License for the specific language governing permissions and 
+ * limitations under the License. 
+ */
+
+package com.coremedia.iso.boxes.vodafone;
+
+import com.coremedia.iso.IsoTypeReader;
+import com.coremedia.iso.Utf8;
+import com.googlecode.mp4parser.AbstractFullBox;
+
+import java.nio.ByteBuffer;
+
+/**
+ * A box in the {@link com.coremedia.iso.boxes.UserDataBox} containing information about the lyric location.
+ * Invented by Vodafone.
+ */
+public class LyricsUriBox extends AbstractFullBox {
+    public static final String TYPE = "lrcu";
+
+    private String lyricsUri;
+
+    public LyricsUriBox() {
+        super(TYPE);
+    }
+
+    public String getLyricsUri() {
+        return lyricsUri;
+    }
+
+    public void setLyricsUri(String lyricsUri) {
+        this.lyricsUri = lyricsUri;
+    }
+
+    protected long getContentSize() {
+        return Utf8.utf8StringLengthInBytes(lyricsUri) + 5;
+    }
+
+    @Override
+    public void _parseDetails(ByteBuffer content) {
+        parseVersionAndFlags(content);
+        lyricsUri = IsoTypeReader.readString(content);
+    }
+
+    @Override
+    protected void getContent(ByteBuffer byteBuffer) {
+        writeVersionAndFlags(byteBuffer);
+        byteBuffer.put(Utf8.convert(lyricsUri));
+        byteBuffer.put((byte) 0);
+    }
+
+    public String toString() {
+        return "LyricsUriBox[lyricsUri=" + getLyricsUri() + "]";
+    }
+}
diff --git a/isoparser/src/main/java/com/coremedia/iso/mdta/.svn/all-wcprops b/isoparser/src/main/java/com/coremedia/iso/mdta/.svn/all-wcprops
new file mode 100644
index 0000000..2f92d3c
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/mdta/.svn/all-wcprops
@@ -0,0 +1,5 @@
+K 25
+svn:wc:ra_dav:version-url
+V 70
+/svn/!svn/ver/178/trunk/isoparser/src/main/java/com/coremedia/iso/mdta
+END
diff --git a/isoparser/src/main/java/com/coremedia/iso/mdta/.svn/entries b/isoparser/src/main/java/com/coremedia/iso/mdta/.svn/entries
new file mode 100644
index 0000000..081f87d
--- /dev/null
+++ b/isoparser/src/main/java/com/coremedia/iso/mdta/.svn/entries
@@ -0,0 +1,28 @@
+10
+
+dir
+778
+http://mp4parser.googlecode.com/svn/trunk/isoparser/src/main/java/com/coremedia/iso/mdta
+http://mp4parser.googlecode.com/svn
+
+
+
+2011-07-11T20:39:14.277970Z
+178
+Sebastian.Annies@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+7decde4b-c250-0410-a0da-51896bc88be6
+
diff --git a/isoparser/src/main/java/com/googlecode/.svn/all-wcprops b/isoparser/src/main/java/com/googlecode/.svn/all-wcprops
new file mode 100644
index 0000000..ca84640
--- /dev/null
+++ b/isoparser/src/main/java/com/googlecode/.svn/all-wcprops
@@ -0,0 +1,5 @@
+K 25
+svn:wc:ra_dav:version-url
+V 62
+/svn/!svn/ver/776/trunk/isoparser/src/main/java/com/googlecode
+END
diff --git a/isoparser/src/main/java/com/googlecode/.svn/entries b/isoparser/src/main/java/com/googlecode/.svn/entries
new file mode 100644
index 0000000..c776f07
--- /dev/null
+++ b/isoparser/src/main/java/com/googlecode/.svn/entries
@@ -0,0 +1,31 @@
+10
+
+dir
+778
+http://mp4parser.googlecode.com/svn/trunk/isoparser/src/main/java/com/googlecode
+http://mp4parser.googlecode.com/svn
+
+
+
+2012-09-10T14:34:23.574807Z
+776
+sebastian.annies@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+7decde4b-c250-0410-a0da-51896bc88be6
+
+mp4parser
+dir
+
diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/.svn/all-wcprops b/isoparser/src/main/java/com/googlecode/mp4parser/.svn/all-wcprops
new file mode 100644
index 0000000..31dd55d
--- /dev/null
+++ b/isoparser/src/main/java/com/googlecode/mp4parser/.svn/all-wcprops
@@ -0,0 +1,41 @@
+K 25
+svn:wc:ra_dav:version-url
+V 72
+/svn/!svn/ver/776/trunk/isoparser/src/main/java/com/googlecode/mp4parser
+END
+AbstractContainerBox.java
+K 25
+svn:wc:ra_dav:version-url
+V 98
+/svn/!svn/ver/616/trunk/isoparser/src/main/java/com/googlecode/mp4parser/AbstractContainerBox.java
+END
+AbstractFullBox.java
+K 25
+svn:wc:ra_dav:version-url
+V 93
+/svn/!svn/ver/525/trunk/isoparser/src/main/java/com/googlecode/mp4parser/AbstractFullBox.java
+END
+Version.java
+K 25
+svn:wc:ra_dav:version-url
+V 85
+/svn/!svn/ver/599/trunk/isoparser/src/main/java/com/googlecode/mp4parser/Version.java
+END
+AbstractBox.java
+K 25
+svn:wc:ra_dav:version-url
+V 89
+/svn/!svn/ver/772/trunk/isoparser/src/main/java/com/googlecode/mp4parser/AbstractBox.java
+END
+RequiresParseDetailAspect.java
+K 25
+svn:wc:ra_dav:version-url
+V 103
+/svn/!svn/ver/705/trunk/isoparser/src/main/java/com/googlecode/mp4parser/RequiresParseDetailAspect.java
+END
+FullContainerBox.java
+K 25
+svn:wc:ra_dav:version-url
+V 94
+/svn/!svn/ver/616/trunk/isoparser/src/main/java/com/googlecode/mp4parser/FullContainerBox.java
+END
diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/.svn/entries b/isoparser/src/main/java/com/googlecode/mp4parser/.svn/entries
new file mode 100644
index 0000000..159e3a7
--- /dev/null
+++ b/isoparser/src/main/java/com/googlecode/mp4parser/.svn/entries
@@ -0,0 +1,250 @@
+10
+
+dir
+778
+http://mp4parser.googlecode.com/svn/trunk/isoparser/src/main/java/com/googlecode/mp4parser
+http://mp4parser.googlecode.com/svn
+
+
+
+2012-09-10T14:34:23.574807Z
+776
+sebastian.annies@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+7decde4b-c250-0410-a0da-51896bc88be6
+
+AbstractContainerBox.java
+file
+
+
+
+
+2012-09-14T17:27:51.677236Z
+023ce1033e326946fb1e551942a711fe
+2012-05-17T09:04:15.805545Z
+616
+Sebastian.Annies@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+5225
+
+AbstractFullBox.java
+file
+
+
+
+
+2012-09-14T17:27:51.677236Z
+9a0208c01832235bc5b32054aaea4cb5
+2012-04-25T19:24:04.485529Z
+525
+Sebastian.Annies@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+1937
+
+authoring
+dir
+
+boxes
+dir
+
+h264
+dir
+
+Version.java
+file
+
+
+
+
+2012-09-14T17:27:51.677236Z
+6123f036beaaa10451566670349e4454
+2012-05-10T08:19:36.847188Z
+599
+Sebastian.Annies@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+718
+
+srt
+dir
+
+AbstractBox.java
+file
+
+
+
+
+2012-09-14T17:27:51.677236Z
+35f21f761802c8d830736d617b7dd93a
+2012-09-01T02:22:41.253285Z
+772
+michael.stattmann@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+9423
+
+annotations
+dir
+
+util
+dir
+
+RequiresParseDetailAspect.java
+file
+
+
+
+
+2012-09-14T17:27:51.677236Z
+f5277a7d1c211e4312c9ff308ad3b5f9
+2012-07-06T09:18:45.003720Z
+705
+Sebastian.Annies@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+2591
+
+FullContainerBox.java
+file
+
+
+
+
+2012-09-14T17:27:51.677236Z
+96f90fe7c15db4a397da4f38d047702f
+2012-05-17T09:04:15.805545Z
+616
+Sebastian.Annies@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+5054
+
diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/.svn/text-base/AbstractBox.java.svn-base b/isoparser/src/main/java/com/googlecode/mp4parser/.svn/text-base/AbstractBox.java.svn-base
new file mode 100644
index 0000000..f75bc1d
--- /dev/null
+++ b/isoparser/src/main/java/com/googlecode/mp4parser/.svn/text-base/AbstractBox.java.svn-base
@@ -0,0 +1,275 @@
+/*  
+ * Copyright 2012 Sebastian Annies, Hamburg
+ *
+ * Licensed under the Apache License, Version 2.0 (the License); 
+ * you may not use this file except in compliance with the License. 
+ * You may obtain a copy of the License at 
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0 
+ * 
+ * Unless required by applicable law or agreed to in writing, software 
+ * distributed under the License is distributed on an AS IS BASIS, 
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+ * See the License for the specific language governing permissions and 
+ * limitations under the License. 
+ */
+
+package com.googlecode.mp4parser;
+
+import com.coremedia.iso.BoxParser;
+import com.coremedia.iso.ChannelHelper;
+import com.coremedia.iso.Hex;
+import com.coremedia.iso.IsoFile;
+import com.coremedia.iso.IsoTypeWriter;
+import com.coremedia.iso.boxes.Box;
+import com.coremedia.iso.boxes.ContainerBox;
+import com.coremedia.iso.boxes.UserBox;
+import com.googlecode.mp4parser.annotations.DoNotParseDetail;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.nio.channels.FileChannel;
+import java.nio.channels.ReadableByteChannel;
+import java.nio.channels.WritableByteChannel;
+import java.util.logging.Logger;
+
+import static com.googlecode.mp4parser.util.CastUtils.l2i;
+
+/**
+ * A basic on-demand parsing box. Requires the implementation of three methods to become a fully working box:
+ * <ol>
+ * <li>{@link #_parseDetails(java.nio.ByteBuffer)}</li>
+ * <li>{@link #getContent(java.nio.ByteBuffer)}</li>
+ * <li>{@link #getContentSize()}</li>
+ * </ol>
+ * additionally this new box has to be put into the <code>isoparser-default.properties</code> file so that
+ * it is accessible by the <code>PropertyBoxParserImpl</code>
+ */
+public abstract class AbstractBox implements Box {
+    public static int MEM_MAP_THRESHOLD = 100 * 1024;
+    private static Logger LOG = Logger.getLogger(AbstractBox.class.getName());
+
+    protected String type;
+    private byte[] userType;
+    private ContainerBox parent;
+
+    private ByteBuffer content;
+    private ByteBuffer deadBytes = null;
+
+
+    protected AbstractBox(String type) {
+        this.type = type;
+    }
+
+    protected AbstractBox(String type, byte[] userType) {
+        this.type = type;
+        this.userType = userType;
+    }
+
+    /**
+     * Get the box's content size without its header. This must be the exact number of bytes
+     * that <code>getContent(ByteBuffer)</code> writes.
+     *
+     * @return Gets the box's content size in bytes
+     * @see #getContent(java.nio.ByteBuffer)
+     */
+    protected abstract long getContentSize();
+
+    /**
+     * Write the box's content into the given <code>ByteBuffer</code>. This must include flags
+     * and version in case of a full box. <code>byteBuffer</code> has been initialized with
+     * <code>getSize()</code> bytes.
+     *
+     * @param byteBuffer the sink for the box's content
+     */
+    protected abstract void getContent(ByteBuffer byteBuffer);
+
+    /**
+     * Parse the box's fields and child boxes if any.
+     *
+     * @param content the box's raw content beginning after the 4-cc field.
+     */
+    protected abstract void _parseDetails(ByteBuffer content);
+
+    /**
+     * Read the box's content from a byte channel without parsing it. Parsing is done on-demand.
+     *
+     * @param readableByteChannel the (part of the) iso file to parse
+     * @param contentSize         expected contentSize of the box
+     * @param boxParser           creates inner boxes
+     * @throws IOException in case of an I/O error.
+     */
+    @DoNotParseDetail
+    public void parse(ReadableByteChannel readableByteChannel, ByteBuffer header, long contentSize, BoxParser boxParser) throws IOException {
+        if (readableByteChannel instanceof FileChannel && contentSize > MEM_MAP_THRESHOLD) {
+            // todo: if I map this here delayed I could use transferFrom/transferTo in the getBox method
+            // todo: potentially this could speed up writing.
+            //
+            // It's quite expensive to map a file into the memory. Just do it when the box is larger than a MB.
+            content = ((FileChannel) readableByteChannel).map(FileChannel.MapMode.READ_ONLY, ((FileChannel) readableByteChannel).position(), contentSize);
+            ((FileChannel) readableByteChannel).position(((FileChannel) readableByteChannel).position() + contentSize);
+        } else {
+            assert contentSize < Integer.MAX_VALUE;
+            content = ChannelHelper.readFully(readableByteChannel, contentSize);
+        }
+    }
+
+    public void getBox(WritableByteChannel os) throws IOException {
+        ByteBuffer bb = ByteBuffer.allocate(l2i(getSize()));
+        getHeader(bb);
+        if (content == null) {
+            getContent(bb);
+            if (deadBytes != null) {
+                deadBytes.rewind();
+                while (deadBytes.remaining() > 0) {
+                    bb.put(deadBytes);
+                }
+            }
+        } else {
+            content.rewind();
+            bb.put(content);
+        }
+        bb.rewind();
+        os.write(bb);
+    }
+
+
+    /**
+     * Parses the raw content of the box. It surrounds the actual parsing
+     * which is done
+     */
+    synchronized final void parseDetails() {
+        if (content != null) {
+            ByteBuffer content = this.content;
+            this.content = null;
+            content.rewind();
+            _parseDetails(content);
+            if (content.remaining() > 0) {
+                deadBytes = content.slice();
+            }
+            assert verify(content);
+        }
+    }
+
+    /**
+     * Sets the 'dead' bytes. These bytes are left if the content of the box
+     * has been parsed but not all bytes have been used up.
+     *
+     * @param newDeadBytes the unused bytes with no meaning but required for bytewise reconstruction
+     */
+    protected void setDeadBytes(ByteBuffer newDeadBytes) {
+        deadBytes = newDeadBytes;
+    }
+
+
+    /**
+     * Gets the full size of the box including header and content.
+     *
+     * @return the box's size
+     */
+    public long getSize() {
+        long size = (content == null ? getContentSize() : content.limit());
+        size += (8 + // size|type
+                (size >= ((1L << 32) - 8) ? 8 : 0) + // 32bit - 8 byte size and type
+                (UserBox.TYPE.equals(getType()) ? 16 : 0));
+        size += (deadBytes == null ? 0 : deadBytes.limit());
+        return size;
+    }
+
+    @DoNotParseDetail
+    public String getType() {
+        return type;
+    }
+
+    @DoNotParseDetail
+    public byte[] getUserType() {
+        return userType;
+    }
+
+    @DoNotParseDetail
+    public ContainerBox getParent() {
+        return parent;
+    }
+
+    @DoNotParseDetail
+    public void setParent(ContainerBox parent) {
+        this.parent = parent;
+    }
+
+    @DoNotParseDetail
+    public IsoFile getIsoFile() {
+        return parent.getIsoFile();
+    }
+
+    /**
+     * Check if details are parsed.
+     *
+     * @return <code>true</code> whenever the content <code>ByteBuffer</code> is not <code>null</code>
+     */
+    public boolean isParsed() {
+        return content == null;
+    }
+
+
+    /**
+     * Verifies that a box can be reconstructed byte-exact after parsing.
+     *
+     * @param content the raw content of the box
+     * @return <code>true</code> if raw content exactly matches the reconstructed content
+     */
+    private boolean verify(ByteBuffer content) {
+        ByteBuffer bb = ByteBuffer.allocate(l2i(getContentSize() + (deadBytes != null ? deadBytes.limit() : 0)));
+        getContent(bb);
+        if (deadBytes != null) {
+            deadBytes.rewind();
+            while (deadBytes.remaining() > 0) {
+                bb.put(deadBytes);
+            }
+        }
+        content.rewind();
+        bb.rewind();
+
+
+        if (content.remaining() != bb.remaining()) {
+            LOG.severe(this.getType() + ": remaining differs " + content.remaining() + " vs. " + bb.remaining());
+            return false;
+        }
+        int p = content.position();
+        for (int i = content.limit() - 1, j = bb.limit() - 1; i >= p; i--, j--) {
+            byte v1 = content.get(i);
+            byte v2 = bb.get(j);
+            if (v1 != v2) {
+                LOG.severe(String.format("%s: buffers differ at %d: %2X/%2X", this.getType(), i, v1, v2));
+                byte[] b1 = new byte[content.remaining()];
+                byte[] b2 = new byte[bb.remaining()];
+                content.get(b1);
+                bb.get(b2);
+                System.err.println("original      : " + Hex.encodeHex(b1, 4));
+                System.err.println("reconstructed : " + Hex.encodeHex(b2, 4));
+                return false;
+            }
+        }
+        return true;
+
+    }
+
+    private boolean isSmallBox() {
+        return (content == null ? (getContentSize() + (deadBytes != null ? deadBytes.limit() : 0) + 8) : content.limit()) < 1L << 32;
+    }
+
+    private void getHeader(ByteBuffer byteBuffer) {
+        if (isSmallBox()) {
+            IsoTypeWriter.writeUInt32(byteBuffer, this.getSize());
+            byteBuffer.put(IsoFile.fourCCtoBytes(getType()));
+        } else {
+            IsoTypeWriter.writeUInt32(byteBuffer, 1);
+            byteBuffer.put(IsoFile.fourCCtoBytes(getType()));
+            IsoTypeWriter.writeUInt64(byteBuffer, getSize());
+        }
+        if (UserBox.TYPE.equals(getType())) {
+            byteBuffer.put(getUserType());
+        }
+
+
+    }
+}
diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/.svn/text-base/AbstractContainerBox.java.svn-base b/isoparser/src/main/java/com/googlecode/mp4parser/.svn/text-base/AbstractContainerBox.java.svn-base
new file mode 100644
index 0000000..93369f3
--- /dev/null
+++ b/isoparser/src/main/java/com/googlecode/mp4parser/.svn/text-base/AbstractContainerBox.java.svn-base
@@ -0,0 +1,171 @@
+/*  
+ * Copyright 2008 CoreMedia AG, Hamburg
+ *
+ * Licensed under the Apache License, Version 2.0 (the License); 
+ * you may not use this file except in compliance with the License. 
+ * You may obtain a copy of the License at 
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0 
+ * 
+ * Unless required by applicable law or agreed to in writing, software 
+ * distributed under the License is distributed on an AS IS BASIS, 
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+ * See the License for the specific language governing permissions and 
+ * limitations under the License. 
+ */
+
+package com.googlecode.mp4parser;
+
+import com.coremedia.iso.BoxParser;
+import com.coremedia.iso.boxes.Box;
+import com.coremedia.iso.boxes.ContainerBox;
+import com.googlecode.mp4parser.util.ByteBufferByteChannel;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.nio.channels.ReadableByteChannel;
+import java.nio.channels.WritableByteChannel;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.logging.Logger;
+
+
+/**
+ * Abstract base class suitable for most boxes acting purely as container for other boxes.
+ */
+public abstract class AbstractContainerBox extends AbstractBox implements ContainerBox {
+    private static Logger LOG = Logger.getLogger(AbstractContainerBox.class.getName());
+
+    protected List<Box> boxes = new LinkedList<Box>();
+    protected BoxParser boxParser;
+
+    @Override
+    protected long getContentSize() {
+        long contentSize = 0;
+        for (Box boxe : boxes) {
+            contentSize += boxe.getSize();
+        }
+        return contentSize;
+    }
+
+    public AbstractContainerBox(String type) {
+        super(type);
+    }
+
+    public List<Box> getBoxes() {
+        return Collections.unmodifiableList(boxes);
+    }
+
+    public void setBoxes(List<Box> boxes) {
+        this.boxes = new LinkedList<Box>(boxes);
+    }
+
+    @SuppressWarnings("unchecked")
+    public <T extends Box> List<T> getBoxes(Class<T> clazz) {
+        return getBoxes(clazz, false);
+    }
+
+    @SuppressWarnings("unchecked")
+    public <T extends Box> List<T> getBoxes(Class<T> clazz, boolean recursive) {
+        List<T> boxesToBeReturned = new ArrayList<T>(2);
+        for (Box boxe : boxes) {
+            //clazz.isInstance(boxe) / clazz == boxe.getClass()?
+            // I hereby finally decide to use isInstance
+
+            if (clazz.isInstance(boxe)) {
+                boxesToBeReturned.add((T) boxe);
+            }
+
+            if (recursive && boxe instanceof ContainerBox) {
+                boxesToBeReturned.addAll(((ContainerBox) boxe).getBoxes(clazz, recursive));
+            }
+        }
+        return boxesToBeReturned;
+    }
+
+    /**
+     * Add <code>b</code> to the container and sets the parent correctly.
+     *
+     * @param b will be added to the container
+     */
+    public void addBox(Box b) {
+        b.setParent(this);
+        boxes.add(b);
+    }
+
+    public void removeBox(Box b) {
+        b.setParent(this);
+        boxes.remove(b);
+    }
+
+    @Override
+    public void parse(ReadableByteChannel readableByteChannel, ByteBuffer header, long contentSize, BoxParser boxParser) throws IOException {
+        super.parse(readableByteChannel, header, contentSize, boxParser);
+        this.boxParser = boxParser;
+    }
+
+    @Override
+    public void _parseDetails(ByteBuffer content) {
+        parseChildBoxes(content);
+    }
+
+
+    public String toString() {
+        StringBuilder buffer = new StringBuilder();
+
+        buffer.append(this.getClass().getSimpleName()).append("[");
+        for (int i = 0; i < boxes.size(); i++) {
+            if (i > 0) {
+                buffer.append(";");
+            }
+            buffer.append(boxes.get(i).toString());
+        }
+        buffer.append("]");
+        return buffer.toString();
+    }
+
+    /**
+     * The number of bytes from box start (first length byte) to the
+     * first length byte of the first child box
+     *
+     * @return offset to first child box
+     */
+    public long getNumOfBytesToFirstChild() {
+        return 8;
+    }
+
+    @Override
+    protected void getContent(ByteBuffer byteBuffer) {
+        writeChildBoxes(byteBuffer);
+    }
+
+    protected final void parseChildBoxes(ByteBuffer content) {
+        try {
+            while (content.remaining() >= 8) { //  8 is the minimal size for a sane box
+                boxes.add(boxParser.parseBox(new ByteBufferByteChannel(content), this));
+            }
+
+            if (content.remaining() != 0) {
+                setDeadBytes(content.slice());
+                LOG.warning("Something's wrong with the sizes. There are dead bytes in a container box.");
+            }
+        } catch (IOException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    protected final void writeChildBoxes(ByteBuffer bb) {
+        WritableByteChannel wbc = new ByteBufferByteChannel(bb);
+        for (Box box : boxes) {
+            try {
+                box.getBox(wbc);
+            } catch (IOException e) {
+                // My WritableByteChannel won't throw any excpetion
+                throw new RuntimeException("Cannot happen to me", e);
+            }
+        }
+    }
+
+}
diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/.svn/text-base/AbstractFullBox.java.svn-base b/isoparser/src/main/java/com/googlecode/mp4parser/.svn/text-base/AbstractFullBox.java.svn-base
new file mode 100644
index 0000000..bec8975
--- /dev/null
+++ b/isoparser/src/main/java/com/googlecode/mp4parser/.svn/text-base/AbstractFullBox.java.svn-base
@@ -0,0 +1,74 @@
+/*  
+ * Copyright 2008 CoreMedia AG, Hamburg
+ *
+ * Licensed under the Apache License, Version 2.0 (the License); 
+ * you may not use this file except in compliance with the License. 
+ * You may obtain a copy of the License at 
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0 
+ * 
+ * Unless required by applicable law or agreed to in writing, software 
+ * distributed under the License is distributed on an AS IS BASIS, 
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+ * See the License for the specific language governing permissions and 
+ * limitations under the License. 
+ */
+
+package com.googlecode.mp4parser;
+
+
+import com.coremedia.iso.IsoTypeReader;
+import com.coremedia.iso.IsoTypeWriter;
+import com.coremedia.iso.boxes.FullBox;
+
+import java.nio.ByteBuffer;
+
+/**
+ * Base class for all ISO Full boxes.
+ */
+public abstract class AbstractFullBox extends AbstractBox implements FullBox {
+    private int version;
+    private int flags;
+
+    protected AbstractFullBox(String type) {
+        super(type);
+    }
+
+    protected AbstractFullBox(String type, byte[] userType) {
+        super(type, userType);
+    }
+
+    public int getVersion() {
+        return version;
+    }
+
+    public void setVersion(int version) {
+        this.version = version;
+    }
+
+    public int getFlags() {
+        return flags;
+    }
+
+    public void setFlags(int flags) {
+        this.flags = flags;
+    }
+
+
+    /**
+     * Parses the version/flags header and returns the remaining box size.
+     *
+     * @param content
+     * @return number of bytes read
+     */
+    protected final long parseVersionAndFlags(ByteBuffer content) {
+        version = IsoTypeReader.readUInt8(content);
+        flags = IsoTypeReader.readUInt24(content);
+        return 4;
+    }
+
+    protected final void writeVersionAndFlags(ByteBuffer bb) {
+        IsoTypeWriter.writeUInt8(bb, version);
+        IsoTypeWriter.writeUInt24(bb, flags);
+    }
+}
diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/.svn/text-base/FullContainerBox.java.svn-base b/isoparser/src/main/java/com/googlecode/mp4parser/.svn/text-base/FullContainerBox.java.svn-base
new file mode 100644
index 0000000..d16e47d
--- /dev/null
+++ b/isoparser/src/main/java/com/googlecode/mp4parser/.svn/text-base/FullContainerBox.java.svn-base
@@ -0,0 +1,159 @@
+/*  
+ * Copyright 2008 CoreMedia AG, Hamburg
+ *
+ * Licensed under the Apache License, Version 2.0 (the License); 
+ * you may not use this file except in compliance with the License. 
+ * You may obtain a copy of the License at 
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0 
+ * 
+ * Unless required by applicable law or agreed to in writing, software 
+ * distributed under the License is distributed on an AS IS BASIS, 
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+ * See the License for the specific language governing permissions and 
+ * limitations under the License. 
+ */
+
+package com.googlecode.mp4parser;
+
+import com.coremedia.iso.BoxParser;
+import com.coremedia.iso.boxes.Box;
+import com.coremedia.iso.boxes.ContainerBox;
+import com.googlecode.mp4parser.util.ByteBufferByteChannel;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.nio.channels.ReadableByteChannel;
+import java.nio.channels.WritableByteChannel;
+import java.util.ArrayList;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.logging.Logger;
+
+/**
+ * Abstract base class for a full iso box only containing ither boxes.
+ */
+public abstract class FullContainerBox extends AbstractFullBox implements ContainerBox {
+    protected List<Box> boxes = new LinkedList<Box>();
+    private static Logger LOG = Logger.getLogger(FullContainerBox.class.getName());
+    BoxParser boxParser;
+
+    public void setBoxes(List<Box> boxes) {
+        this.boxes = new LinkedList<Box>(boxes);
+    }
+
+    @SuppressWarnings("unchecked")
+    public <T extends Box> List<T> getBoxes(Class<T> clazz) {
+        return getBoxes(clazz, false);
+    }
+
+    @SuppressWarnings("unchecked")
+    public <T extends Box> List<T> getBoxes(Class<T> clazz, boolean recursive) {
+        List<T> boxesToBeReturned = new ArrayList<T>(2);
+        for (Box boxe : boxes) { //clazz.isInstance(boxe) / clazz == boxe.getClass()?
+            if (clazz == boxe.getClass()) {
+                boxesToBeReturned.add((T) boxe);
+            }
+
+            if (recursive && boxe instanceof ContainerBox) {
+                boxesToBeReturned.addAll((((ContainerBox) boxe).getBoxes(clazz, recursive)));
+            }
+        }
+        // Optimize here! Spare object creation work on arrays directly! System.arrayCopy
+        return boxesToBeReturned;
+        //return (T[]) boxesToBeReturned.toArray();
+    }
+
+    protected long getContentSize() {
+        long contentSize = 4; // flags and version
+        for (Box boxe : boxes) {
+            contentSize += boxe.getSize();
+        }
+        return contentSize;
+    }
+
+    public void addBox(Box b) {
+        b.setParent(this);
+        boxes.add(b);
+    }
+
+    public void removeBox(Box b) {
+        b.setParent(null);
+        boxes.remove(b);
+    }
+
+    public FullContainerBox(String type) {
+        super(type);
+    }
+
+    public List<Box> getBoxes() {
+        return boxes;
+    }
+
+    @Override
+    public void parse(ReadableByteChannel readableByteChannel, ByteBuffer header, long contentSize, BoxParser boxParser) throws IOException {
+        super.parse(readableByteChannel, header, contentSize, boxParser);
+        this.boxParser = boxParser;
+    }
+
+    @Override
+    public void _parseDetails(ByteBuffer content) {
+        parseVersionAndFlags(content);
+        parseChildBoxes(content);
+    }
+
+    protected final void parseChildBoxes(ByteBuffer content) {
+        try {
+            while (content.remaining() >= 8) { //  8 is the minimal size for a sane box
+                boxes.add(boxParser.parseBox(new ByteBufferByteChannel(content), this));
+            }
+
+            if (content.remaining() != 0) {
+                setDeadBytes(content.slice());
+                LOG.severe("Some sizes are wrong");
+            }
+        } catch (IOException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    public String toString() {
+        StringBuilder buffer = new StringBuilder();
+        buffer.append(this.getClass().getSimpleName()).append("[");
+        for (int i = 0; i < boxes.size(); i++) {
+            if (i > 0) {
+                buffer.append(";");
+            }
+            buffer.append(boxes.get(i).toString());
+        }
+        buffer.append("]");
+        return buffer.toString();
+    }
+
+
+    protected void getContent(ByteBuffer byteBuffer) {
+        writeVersionAndFlags(byteBuffer);
+        writeChildBoxes(byteBuffer);
+    }
+
+    protected final void writeChildBoxes(ByteBuffer bb) {
+        WritableByteChannel wbc = new ByteBufferByteChannel(bb);
+        for (Box box : boxes) {
+            try {
+                box.getBox(wbc);
+            } catch (IOException e) {
+                // cannot happen since my WritableByteChannel won't throw any excpetion
+                throw new RuntimeException("Cannot happen.", e);
+            }
+
+        }
+    }
+
+    public long getNumOfBytesToFirstChild() {
+        long sizeOfChildren = 0;
+        for (Box box : boxes) {
+            sizeOfChildren += box.getSize();
+        }
+        return getSize() - sizeOfChildren;
+    }
+}
diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/.svn/text-base/RequiresParseDetailAspect.java.svn-base b/isoparser/src/main/java/com/googlecode/mp4parser/.svn/text-base/RequiresParseDetailAspect.java.svn-base
new file mode 100644
index 0000000..5009230
--- /dev/null
+++ b/isoparser/src/main/java/com/googlecode/mp4parser/.svn/text-base/RequiresParseDetailAspect.java.svn-base
@@ -0,0 +1,62 @@
+/*
+ * Copyright 2012 Sebastian Annies, Hamburg
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.googlecode.mp4parser;
+
+import org.aspectj.lang.JoinPoint;
+import org.aspectj.lang.annotation.Aspect;
+import org.aspectj.lang.annotation.Before;
+
+@Aspect
+/**
+ * An aspect to trigger the actual parsing of boxes' content when it is actually needed. This aspect
+ * calls {@link com.googlecode.mp4parser.AbstractBox#parseDetails()} before actually executing
+ * the method.
+ */
+public class RequiresParseDetailAspect {
+
+
+    @Before("this(com.googlecode.mp4parser.AbstractBox) && ((execution(public * * (..)) && !( " +
+            "execution(* parseDetails()) || " +
+            "execution(* getNumOfBytesToFirstChild()) || " +
+            "execution(* getType()) || " +
+            "execution(* isParsed()) || " +
+            "execution(* getHeader(*)) || " +
+            "execution(* parse()) || " +
+            "execution(* getBox(*)) || " +
+            "execution(* getSize()) || " +
+            "execution(* parseDetails()) || " +
+            "execution(* _parseDetails(*)) || " +
+            "execution(* parse(*,*,*,*)) || " +
+            "execution(* getIsoFile()) || " +
+            "execution(* getParent()) || " +
+            "execution(* setParent(*)) || " +
+            "execution(* getUserType()) || " +
+            "execution(* setUserType(*))) && " +
+            "!@annotation(com.googlecode.mp4parser.annotations.DoNotParseDetail)) || @annotation(com.googlecode.mp4parser.annotations.ParseDetail))")
+    public void before(JoinPoint joinPoint) {
+        if (joinPoint.getTarget() instanceof AbstractBox) {
+            if (!((AbstractBox) joinPoint.getTarget()).isParsed()) {
+                //System.err.println(String.format("parsed detail %s", joinPoint.getTarget().getClass().getSimpleName()));
+                ((AbstractBox) joinPoint.getTarget()).parseDetails();
+            }
+        } else {
+            throw new RuntimeException("Only methods in subclasses of " + AbstractBox.class.getName() + " can  be annotated with ParseDetail");
+        }
+
+    }
+
+
+}
\ No newline at end of file
diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/.svn/text-base/Version.java.svn-base b/isoparser/src/main/java/com/googlecode/mp4parser/.svn/text-base/Version.java.svn-base
new file mode 100644
index 0000000..f93816f
--- /dev/null
+++ b/isoparser/src/main/java/com/googlecode/mp4parser/.svn/text-base/Version.java.svn-base
@@ -0,0 +1,27 @@
+package com.googlecode.mp4parser;
+
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.LineNumberReader;
+import java.util.logging.Logger;
+
+/**
+ * The classic version object.
+ */
+public class Version {
+    private static final Logger LOG = Logger.getLogger(Version.class.getName());
+    public static final String VERSION;
+
+    static {
+        LineNumberReader lnr = new LineNumberReader(new InputStreamReader(Version.class.getResourceAsStream("/version.txt")));
+        String version;
+        try {
+            version = lnr.readLine();
+        } catch (IOException e) {
+            LOG.warning(e.getMessage());
+            version = "unknown";
+        }
+        VERSION = version;
+
+    }
+}
diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/AbstractBox.java b/isoparser/src/main/java/com/googlecode/mp4parser/AbstractBox.java
new file mode 100644
index 0000000..f75bc1d
--- /dev/null
+++ b/isoparser/src/main/java/com/googlecode/mp4parser/AbstractBox.java
@@ -0,0 +1,275 @@
+/*  
+ * Copyright 2012 Sebastian Annies, Hamburg
+ *
+ * Licensed under the Apache License, Version 2.0 (the License); 
+ * you may not use this file except in compliance with the License. 
+ * You may obtain a copy of the License at 
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0 
+ * 
+ * Unless required by applicable law or agreed to in writing, software 
+ * distributed under the License is distributed on an AS IS BASIS, 
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+ * See the License for the specific language governing permissions and 
+ * limitations under the License. 
+ */
+
+package com.googlecode.mp4parser;
+
+import com.coremedia.iso.BoxParser;
+import com.coremedia.iso.ChannelHelper;
+import com.coremedia.iso.Hex;
+import com.coremedia.iso.IsoFile;
+import com.coremedia.iso.IsoTypeWriter;
+import com.coremedia.iso.boxes.Box;
+import com.coremedia.iso.boxes.ContainerBox;
+import com.coremedia.iso.boxes.UserBox;
+import com.googlecode.mp4parser.annotations.DoNotParseDetail;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.nio.channels.FileChannel;
+import java.nio.channels.ReadableByteChannel;
+import java.nio.channels.WritableByteChannel;
+import java.util.logging.Logger;
+
+import static com.googlecode.mp4parser.util.CastUtils.l2i;
+
+/**
+ * A basic on-demand parsing box. Requires the implementation of three methods to become a fully working box:
+ * <ol>
+ * <li>{@link #_parseDetails(java.nio.ByteBuffer)}</li>
+ * <li>{@link #getContent(java.nio.ByteBuffer)}</li>
+ * <li>{@link #getContentSize()}</li>
+ * </ol>
+ * additionally this new box has to be put into the <code>isoparser-default.properties</code> file so that
+ * it is accessible by the <code>PropertyBoxParserImpl</code>
+ */
+public abstract class AbstractBox implements Box {
+    public static int MEM_MAP_THRESHOLD = 100 * 1024;
+    private static Logger LOG = Logger.getLogger(AbstractBox.class.getName());
+
+    protected String type;
+    private byte[] userType;
+    private ContainerBox parent;
+
+    private ByteBuffer content;
+    private ByteBuffer deadBytes = null;
+
+
+    protected AbstractBox(String type) {
+        this.type = type;
+    }
+
+    protected AbstractBox(String type, byte[] userType) {
+        this.type = type;
+        this.userType = userType;
+    }
+
+    /**
+     * Get the box's content size without its header. This must be the exact number of bytes
+     * that <code>getContent(ByteBuffer)</code> writes.
+     *
+     * @return Gets the box's content size in bytes
+     * @see #getContent(java.nio.ByteBuffer)
+     */
+    protected abstract long getContentSize();
+
+    /**
+     * Write the box's content into the given <code>ByteBuffer</code>. This must include flags
+     * and version in case of a full box. <code>byteBuffer</code> has been initialized with
+     * <code>getSize()</code> bytes.
+     *
+     * @param byteBuffer the sink for the box's content
+     */
+    protected abstract void getContent(ByteBuffer byteBuffer);
+
+    /**
+     * Parse the box's fields and child boxes if any.
+     *
+     * @param content the box's raw content beginning after the 4-cc field.
+     */
+    protected abstract void _parseDetails(ByteBuffer content);
+
+    /**
+     * Read the box's content from a byte channel without parsing it. Parsing is done on-demand.
+     *
+     * @param readableByteChannel the (part of the) iso file to parse
+     * @param contentSize         expected contentSize of the box
+     * @param boxParser           creates inner boxes
+     * @throws IOException in case of an I/O error.
+     */
+    @DoNotParseDetail
+    public void parse(ReadableByteChannel readableByteChannel, ByteBuffer header, long contentSize, BoxParser boxParser) throws IOException {
+        if (readableByteChannel instanceof FileChannel && contentSize > MEM_MAP_THRESHOLD) {
+            // todo: if I map this here delayed I could use transferFrom/transferTo in the getBox method
+            // todo: potentially this could speed up writing.
+            //
+            // It's quite expensive to map a file into the memory. Just do it when the box is larger than a MB.
+            content = ((FileChannel) readableByteChannel).map(FileChannel.MapMode.READ_ONLY, ((FileChannel) readableByteChannel).position(), contentSize);
+            ((FileChannel) readableByteChannel).position(((FileChannel) readableByteChannel).position() + contentSize);
+        } else {
+            assert contentSize < Integer.MAX_VALUE;
+            content = ChannelHelper.readFully(readableByteChannel, contentSize);
+        }
+    }
+
+    public void getBox(WritableByteChannel os) throws IOException {
+        ByteBuffer bb = ByteBuffer.allocate(l2i(getSize()));
+        getHeader(bb);
+        if (content == null) {
+            getContent(bb);
+            if (deadBytes != null) {
+                deadBytes.rewind();
+                while (deadBytes.remaining() > 0) {
+                    bb.put(deadBytes);
+                }
+            }
+        } else {
+            content.rewind();
+            bb.put(content);
+        }
+        bb.rewind();
+        os.write(bb);
+    }
+
+
+    /**
+     * Parses the raw content of the box. It surrounds the actual parsing
+     * which is done
+     */
+    synchronized final void parseDetails() {
+        if (content != null) {
+            ByteBuffer content = this.content;
+            this.content = null;
+            content.rewind();
+            _parseDetails(content);
+            if (content.remaining() > 0) {
+                deadBytes = content.slice();
+            }
+            assert verify(content);
+        }
+    }
+
+    /**
+     * Sets the 'dead' bytes. These bytes are left if the content of the box
+     * has been parsed but not all bytes have been used up.
+     *
+     * @param newDeadBytes the unused bytes with no meaning but required for bytewise reconstruction
+     */
+    protected void setDeadBytes(ByteBuffer newDeadBytes) {
+        deadBytes = newDeadBytes;
+    }
+
+
+    /**
+     * Gets the full size of the box including header and content.
+     *
+     * @return the box's size
+     */
+    public long getSize() {
+        long size = (content == null ? getContentSize() : content.limit());
+        size += (8 + // size|type
+                (size >= ((1L << 32) - 8) ? 8 : 0) + // 32bit - 8 byte size and type
+                (UserBox.TYPE.equals(getType()) ? 16 : 0));
+        size += (deadBytes == null ? 0 : deadBytes.limit());
+        return size;
+    }
+
+    @DoNotParseDetail
+    public String getType() {
+        return type;
+    }
+
+    @DoNotParseDetail
+    public byte[] getUserType() {
+        return userType;
+    }
+
+    @DoNotParseDetail
+    public ContainerBox getParent() {
+        return parent;
+    }
+
+    @DoNotParseDetail
+    public void setParent(ContainerBox parent) {
+        this.parent = parent;
+    }
+
+    @DoNotParseDetail
+    public IsoFile getIsoFile() {
+        return parent.getIsoFile();
+    }
+
+    /**
+     * Check if details are parsed.
+     *
+     * @return <code>true</code> whenever the content <code>ByteBuffer</code> is not <code>null</code>
+     */
+    public boolean isParsed() {
+        return content == null;
+    }
+
+
+    /**
+     * Verifies that a box can be reconstructed byte-exact after parsing.
+     *
+     * @param content the raw content of the box
+     * @return <code>true</code> if raw content exactly matches the reconstructed content
+     */
+    private boolean verify(ByteBuffer content) {
+        ByteBuffer bb = ByteBuffer.allocate(l2i(getContentSize() + (deadBytes != null ? deadBytes.limit() : 0)));
+        getContent(bb);
+        if (deadBytes != null) {
+            deadBytes.rewind();
+            while (deadBytes.remaining() > 0) {
+                bb.put(deadBytes);
+            }
+        }
+        content.rewind();
+        bb.rewind();
+
+
+        if (content.remaining() != bb.remaining()) {
+            LOG.severe(this.getType() + ": remaining differs " + content.remaining() + " vs. " + bb.remaining());
+            return false;
+        }
+        int p = content.position();
+        for (int i = content.limit() - 1, j = bb.limit() - 1; i >= p; i--, j--) {
+            byte v1 = content.get(i);
+            byte v2 = bb.get(j);
+            if (v1 != v2) {
+                LOG.severe(String.format("%s: buffers differ at %d: %2X/%2X", this.getType(), i, v1, v2));
+                byte[] b1 = new byte[content.remaining()];
+                byte[] b2 = new byte[bb.remaining()];
+                content.get(b1);
+                bb.get(b2);
+                System.err.println("original      : " + Hex.encodeHex(b1, 4));
+                System.err.println("reconstructed : " + Hex.encodeHex(b2, 4));
+                return false;
+            }
+        }
+        return true;
+
+    }
+
+    private boolean isSmallBox() {
+        return (content == null ? (getContentSize() + (deadBytes != null ? deadBytes.limit() : 0) + 8) : content.limit()) < 1L << 32;
+    }
+
+    private void getHeader(ByteBuffer byteBuffer) {
+        if (isSmallBox()) {
+            IsoTypeWriter.writeUInt32(byteBuffer, this.getSize());
+            byteBuffer.put(IsoFile.fourCCtoBytes(getType()));
+        } else {
+            IsoTypeWriter.writeUInt32(byteBuffer, 1);
+            byteBuffer.put(IsoFile.fourCCtoBytes(getType()));
+            IsoTypeWriter.writeUInt64(byteBuffer, getSize());
+        }
+        if (UserBox.TYPE.equals(getType())) {
+            byteBuffer.put(getUserType());
+        }
+
+
+    }
+}
diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/AbstractContainerBox.java b/isoparser/src/main/java/com/googlecode/mp4parser/AbstractContainerBox.java
new file mode 100644
index 0000000..93369f3
--- /dev/null
+++ b/isoparser/src/main/java/com/googlecode/mp4parser/AbstractContainerBox.java
@@ -0,0 +1,171 @@
+/*  
+ * Copyright 2008 CoreMedia AG, Hamburg
+ *
+ * Licensed under the Apache License, Version 2.0 (the License); 
+ * you may not use this file except in compliance with the License. 
+ * You may obtain a copy of the License at 
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0 
+ * 
+ * Unless required by applicable law or agreed to in writing, software 
+ * distributed under the License is distributed on an AS IS BASIS, 
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+ * See the License for the specific language governing permissions and 
+ * limitations under the License. 
+ */
+
+package com.googlecode.mp4parser;
+
+import com.coremedia.iso.BoxParser;
+import com.coremedia.iso.boxes.Box;
+import com.coremedia.iso.boxes.ContainerBox;
+import com.googlecode.mp4parser.util.ByteBufferByteChannel;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.nio.channels.ReadableByteChannel;
+import java.nio.channels.WritableByteChannel;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.logging.Logger;
+
+
+/**
+ * Abstract base class suitable for most boxes acting purely as container for other boxes.
+ */
+public abstract class AbstractContainerBox extends AbstractBox implements ContainerBox {
+    private static Logger LOG = Logger.getLogger(AbstractContainerBox.class.getName());
+
+    protected List<Box> boxes = new LinkedList<Box>();
+    protected BoxParser boxParser;
+
+    @Override
+    protected long getContentSize() {
+        long contentSize = 0;
+        for (Box boxe : boxes) {
+            contentSize += boxe.getSize();
+        }
+        return contentSize;
+    }
+
+    public AbstractContainerBox(String type) {
+        super(type);
+    }
+
+    public List<Box> getBoxes() {
+        return Collections.unmodifiableList(boxes);
+    }
+
+    public void setBoxes(List<Box> boxes) {
+        this.boxes = new LinkedList<Box>(boxes);
+    }
+
+    @SuppressWarnings("unchecked")
+    public <T extends Box> List<T> getBoxes(Class<T> clazz) {
+        return getBoxes(clazz, false);
+    }
+
+    @SuppressWarnings("unchecked")
+    public <T extends Box> List<T> getBoxes(Class<T> clazz, boolean recursive) {
+        List<T> boxesToBeReturned = new ArrayList<T>(2);
+        for (Box boxe : boxes) {
+            //clazz.isInstance(boxe) / clazz == boxe.getClass()?
+            // I hereby finally decide to use isInstance
+
+            if (clazz.isInstance(boxe)) {
+                boxesToBeReturned.add((T) boxe);
+            }
+
+            if (recursive && boxe instanceof ContainerBox) {
+                boxesToBeReturned.addAll(((ContainerBox) boxe).getBoxes(clazz, recursive));
+            }
+        }
+        return boxesToBeReturned;
+    }
+
+    /**
+     * Add <code>b</code> to the container and sets the parent correctly.
+     *
+     * @param b will be added to the container
+     */
+    public void addBox(Box b) {
+        b.setParent(this);
+        boxes.add(b);
+    }
+
+    public void removeBox(Box b) {
+        b.setParent(this);
+        boxes.remove(b);
+    }
+
+    @Override
+    public void parse(ReadableByteChannel readableByteChannel, ByteBuffer header, long contentSize, BoxParser boxParser) throws IOException {
+        super.parse(readableByteChannel, header, contentSize, boxParser);
+        this.boxParser = boxParser;
+    }
+
+    @Override
+    public void _parseDetails(ByteBuffer content) {
+        parseChildBoxes(content);
+    }
+
+
+    public String toString() {
+        StringBuilder buffer = new StringBuilder();
+
+        buffer.append(this.getClass().getSimpleName()).append("[");
+        for (int i = 0; i < boxes.size(); i++) {
+            if (i > 0) {
+                buffer.append(";");
+            }
+            buffer.append(boxes.get(i).toString());
+        }
+        buffer.append("]");
+        return buffer.toString();
+    }
+
+    /**
+     * The number of bytes from box start (first length byte) to the
+     * first length byte of the first child box
+     *
+     * @return offset to first child box
+     */
+    public long getNumOfBytesToFirstChild() {
+        return 8;
+    }
+
+    @Override
+    protected void getContent(ByteBuffer byteBuffer) {
+        writeChildBoxes(byteBuffer);
+    }
+
+    protected final void parseChildBoxes(ByteBuffer content) {
+        try {
+            while (content.remaining() >= 8) { //  8 is the minimal size for a sane box
+                boxes.add(boxParser.parseBox(new ByteBufferByteChannel(content), this));
+            }
+
+            if (content.remaining() != 0) {
+                setDeadBytes(content.slice());
+                LOG.warning("Something's wrong with the sizes. There are dead bytes in a container box.");
+            }
+        } catch (IOException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    protected final void writeChildBoxes(ByteBuffer bb) {
+        WritableByteChannel wbc = new ByteBufferByteChannel(bb);
+        for (Box box : boxes) {
+            try {
+                box.getBox(wbc);
+            } catch (IOException e) {
+                // My WritableByteChannel won't throw any excpetion
+                throw new RuntimeException("Cannot happen to me", e);
+            }
+        }
+    }
+
+}
diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/AbstractFullBox.java b/isoparser/src/main/java/com/googlecode/mp4parser/AbstractFullBox.java
new file mode 100644
index 0000000..bec8975
--- /dev/null
+++ b/isoparser/src/main/java/com/googlecode/mp4parser/AbstractFullBox.java
@@ -0,0 +1,74 @@
+/*  
+ * Copyright 2008 CoreMedia AG, Hamburg
+ *
+ * Licensed under the Apache License, Version 2.0 (the License); 
+ * you may not use this file except in compliance with the License. 
+ * You may obtain a copy of the License at 
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0 
+ * 
+ * Unless required by applicable law or agreed to in writing, software 
+ * distributed under the License is distributed on an AS IS BASIS, 
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+ * See the License for the specific language governing permissions and 
+ * limitations under the License. 
+ */
+
+package com.googlecode.mp4parser;
+
+
+import com.coremedia.iso.IsoTypeReader;
+import com.coremedia.iso.IsoTypeWriter;
+import com.coremedia.iso.boxes.FullBox;
+
+import java.nio.ByteBuffer;
+
+/**
+ * Base class for all ISO Full boxes.
+ */
+public abstract class AbstractFullBox extends AbstractBox implements FullBox {
+    private int version;
+    private int flags;
+
+    protected AbstractFullBox(String type) {
+        super(type);
+    }
+
+    protected AbstractFullBox(String type, byte[] userType) {
+        super(type, userType);
+    }
+
+    public int getVersion() {
+        return version;
+    }
+
+    public void setVersion(int version) {
+        this.version = version;
+    }
+
+    public int getFlags() {
+        return flags;
+    }
+
+    public void setFlags(int flags) {
+        this.flags = flags;
+    }
+
+
+    /**
+     * Parses the version/flags header and returns the remaining box size.
+     *
+     * @param content
+     * @return number of bytes read
+     */
+    protected final long parseVersionAndFlags(ByteBuffer content) {
+        version = IsoTypeReader.readUInt8(content);
+        flags = IsoTypeReader.readUInt24(content);
+        return 4;
+    }
+
+    protected final void writeVersionAndFlags(ByteBuffer bb) {
+        IsoTypeWriter.writeUInt8(bb, version);
+        IsoTypeWriter.writeUInt24(bb, flags);
+    }
+}
diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/FullContainerBox.java b/isoparser/src/main/java/com/googlecode/mp4parser/FullContainerBox.java
new file mode 100644
index 0000000..d16e47d
--- /dev/null
+++ b/isoparser/src/main/java/com/googlecode/mp4parser/FullContainerBox.java
@@ -0,0 +1,159 @@
+/*  
+ * Copyright 2008 CoreMedia AG, Hamburg
+ *
+ * Licensed under the Apache License, Version 2.0 (the License); 
+ * you may not use this file except in compliance with the License. 
+ * You may obtain a copy of the License at 
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0 
+ * 
+ * Unless required by applicable law or agreed to in writing, software 
+ * distributed under the License is distributed on an AS IS BASIS, 
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+ * See the License for the specific language governing permissions and 
+ * limitations under the License. 
+ */
+
+package com.googlecode.mp4parser;
+
+import com.coremedia.iso.BoxParser;
+import com.coremedia.iso.boxes.Box;
+import com.coremedia.iso.boxes.ContainerBox;
+import com.googlecode.mp4parser.util.ByteBufferByteChannel;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.nio.channels.ReadableByteChannel;
+import java.nio.channels.WritableByteChannel;
+import java.util.ArrayList;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.logging.Logger;
+
+/**
+ * Abstract base class for a full iso box only containing ither boxes.
+ */
+public abstract class FullContainerBox extends AbstractFullBox implements ContainerBox {
+    protected List<Box> boxes = new LinkedList<Box>();
+    private static Logger LOG = Logger.getLogger(FullContainerBox.class.getName());
+    BoxParser boxParser;
+
+    public void setBoxes(List<Box> boxes) {
+        this.boxes = new LinkedList<Box>(boxes);
+    }
+
+    @SuppressWarnings("unchecked")
+    public <T extends Box> List<T> getBoxes(Class<T> clazz) {
+        return getBoxes(clazz, false);
+    }
+
+    @SuppressWarnings("unchecked")
+    public <T extends Box> List<T> getBoxes(Class<T> clazz, boolean recursive) {
+        List<T> boxesToBeReturned = new ArrayList<T>(2);
+        for (Box boxe : boxes) { //clazz.isInstance(boxe) / clazz == boxe.getClass()?
+            if (clazz == boxe.getClass()) {
+                boxesToBeReturned.add((T) boxe);
+            }
+
+            if (recursive && boxe instanceof ContainerBox) {
+                boxesToBeReturned.addAll((((ContainerBox) boxe).getBoxes(clazz, recursive)));
+            }
+        }
+        // Optimize here! Spare object creation work on arrays directly! System.arrayCopy
+        return boxesToBeReturned;
+        //return (T[]) boxesToBeReturned.toArray();
+    }
+
+    protected long getContentSize() {
+        long contentSize = 4; // flags and version
+        for (Box boxe : boxes) {
+            contentSize += boxe.getSize();
+        }
+        return contentSize;
+    }
+
+    public void addBox(Box b) {
+        b.setParent(this);
+        boxes.add(b);
+    }
+
+    public void removeBox(Box b) {
+        b.setParent(null);
+        boxes.remove(b);
+    }
+
+    public FullContainerBox(String type) {
+        super(type);
+    }
+
+    public List<Box> getBoxes() {
+        return boxes;
+    }
+
+    @Override
+    public void parse(ReadableByteChannel readableByteChannel, ByteBuffer header, long contentSize, BoxParser boxParser) throws IOException {
+        super.parse(readableByteChannel, header, contentSize, boxParser);
+        this.boxParser = boxParser;
+    }
+
+    @Override
+    public void _parseDetails(ByteBuffer content) {
+        parseVersionAndFlags(content);
+        parseChildBoxes(content);
+    }
+
+    protected final void parseChildBoxes(ByteBuffer content) {
+        try {
+            while (content.remaining() >= 8) { //  8 is the minimal size for a sane box
+                boxes.add(boxParser.parseBox(new ByteBufferByteChannel(content), this));
+            }
+
+            if (content.remaining() != 0) {
+                setDeadBytes(content.slice());
+                LOG.severe("Some sizes are wrong");
+            }
+        } catch (IOException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    public String toString() {
+        StringBuilder buffer = new StringBuilder();
+        buffer.append(this.getClass().getSimpleName()).append("[");
+        for (int i = 0; i < boxes.size(); i++) {
+            if (i > 0) {
+                buffer.append(";");
+            }
+            buffer.append(boxes.get(i).toString());
+        }
+        buffer.append("]");
+        return buffer.toString();
+    }
+
+
+    protected void getContent(ByteBuffer byteBuffer) {
+        writeVersionAndFlags(byteBuffer);
+        writeChildBoxes(byteBuffer);
+    }
+
+    protected final void writeChildBoxes(ByteBuffer bb) {
+        WritableByteChannel wbc = new ByteBufferByteChannel(bb);
+        for (Box box : boxes) {
+            try {
+                box.getBox(wbc);
+            } catch (IOException e) {
+                // cannot happen since my WritableByteChannel won't throw any excpetion
+                throw new RuntimeException("Cannot happen.", e);
+            }
+
+        }
+    }
+
+    public long getNumOfBytesToFirstChild() {
+        long sizeOfChildren = 0;
+        for (Box box : boxes) {
+            sizeOfChildren += box.getSize();
+        }
+        return getSize() - sizeOfChildren;
+    }
+}
diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/Version.java b/isoparser/src/main/java/com/googlecode/mp4parser/Version.java
new file mode 100644
index 0000000..f93816f
--- /dev/null
+++ b/isoparser/src/main/java/com/googlecode/mp4parser/Version.java
@@ -0,0 +1,27 @@
+package com.googlecode.mp4parser;
+
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.LineNumberReader;
+import java.util.logging.Logger;
+
+/**
+ * The classic version object.
+ */
+public class Version {
+    private static final Logger LOG = Logger.getLogger(Version.class.getName());
+    public static final String VERSION;
+
+    static {
+        LineNumberReader lnr = new LineNumberReader(new InputStreamReader(Version.class.getResourceAsStream("/version.txt")));
+        String version;
+        try {
+            version = lnr.readLine();
+        } catch (IOException e) {
+            LOG.warning(e.getMessage());
+            version = "unknown";
+        }
+        VERSION = version;
+
+    }
+}
diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/annotations/.svn/all-wcprops b/isoparser/src/main/java/com/googlecode/mp4parser/annotations/.svn/all-wcprops
new file mode 100644
index 0000000..a072f85
--- /dev/null
+++ b/isoparser/src/main/java/com/googlecode/mp4parser/annotations/.svn/all-wcprops
@@ -0,0 +1,17 @@
+K 25
+svn:wc:ra_dav:version-url
+V 84
+/svn/!svn/ver/510/trunk/isoparser/src/main/java/com/googlecode/mp4parser/annotations
+END
+DoNotParseDetail.java
+K 25
+svn:wc:ra_dav:version-url
+V 106
+/svn/!svn/ver/510/trunk/isoparser/src/main/java/com/googlecode/mp4parser/annotations/DoNotParseDetail.java
+END
+ParseDetail.java
+K 25
+svn:wc:ra_dav:version-url
+V 101
+/svn/!svn/ver/505/trunk/isoparser/src/main/java/com/googlecode/mp4parser/annotations/ParseDetail.java
+END
diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/annotations/.svn/entries b/isoparser/src/main/java/com/googlecode/mp4parser/annotations/.svn/entries
new file mode 100644
index 0000000..c1fdd1c
--- /dev/null
+++ b/isoparser/src/main/java/com/googlecode/mp4parser/annotations/.svn/entries
@@ -0,0 +1,96 @@
+10
+
+dir
+778
+http://mp4parser.googlecode.com/svn/trunk/isoparser/src/main/java/com/googlecode/mp4parser/annotations
+http://mp4parser.googlecode.com/svn
+
+
+
+2012-04-22T09:16:09.151890Z
+510
+Sebastian.Annies@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+7decde4b-c250-0410-a0da-51896bc88be6
+
+DoNotParseDetail.java
+file
+
+
+
+
+2012-09-14T17:27:51.617235Z
+fc2fddc66ebab5d81ec1c3a226b350b2
+2012-04-22T09:16:09.151890Z
+510
+Sebastian.Annies@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+1277
+
+ParseDetail.java
+file
+
+
+
+
+2012-09-14T17:27:51.617235Z
+14c265468fb110b7dc7f59ba02b532a0
+2012-04-21T21:18:31.685061Z
+505
+Sebastian.Annies@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+1037
+
diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/annotations/.svn/text-base/DoNotParseDetail.java.svn-base b/isoparser/src/main/java/com/googlecode/mp4parser/annotations/.svn/text-base/DoNotParseDetail.java.svn-base
new file mode 100644
index 0000000..c08460f
--- /dev/null
+++ b/isoparser/src/main/java/com/googlecode/mp4parser/annotations/.svn/text-base/DoNotParseDetail.java.svn-base
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2012 Sebastian Annies, Hamburg
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.googlecode.mp4parser.annotations;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Inherited;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ *
+ */
+
+@Target({ElementType.METHOD, ElementType.TYPE})
+@Retention(RetentionPolicy.RUNTIME)
+@Inherited
+@Documented
+/**
+ * Mark a method with this annotation to prevent triggering the call of
+ * <code>AbstractBox#parseDetails()</code> before actually executing the
+ * method.
+ * @see com.googlecode.mp4parser.RequiresParseDetailAspect
+ */
+public @interface DoNotParseDetail {
+}
+
+
diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/annotations/.svn/text-base/ParseDetail.java.svn-base b/isoparser/src/main/java/com/googlecode/mp4parser/annotations/.svn/text-base/ParseDetail.java.svn-base
new file mode 100644
index 0000000..7b66d53
--- /dev/null
+++ b/isoparser/src/main/java/com/googlecode/mp4parser/annotations/.svn/text-base/ParseDetail.java.svn-base
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2012 Sebastian Annies, Hamburg
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.googlecode.mp4parser.annotations;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Inherited;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+
+@Target({ElementType.METHOD, ElementType.TYPE})
+@Retention(RetentionPolicy.RUNTIME)
+@Inherited
+@Documented
+public @interface ParseDetail {
+}
+
+
diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/annotations/DoNotParseDetail.java b/isoparser/src/main/java/com/googlecode/mp4parser/annotations/DoNotParseDetail.java
new file mode 100644
index 0000000..c08460f
--- /dev/null
+++ b/isoparser/src/main/java/com/googlecode/mp4parser/annotations/DoNotParseDetail.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2012 Sebastian Annies, Hamburg
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.googlecode.mp4parser.annotations;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Inherited;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ *
+ */
+
+@Target({ElementType.METHOD, ElementType.TYPE})
+@Retention(RetentionPolicy.RUNTIME)
+@Inherited
+@Documented
+/**
+ * Mark a method with this annotation to prevent triggering the call of
+ * <code>AbstractBox#parseDetails()</code> before actually executing the
+ * method.
+ * @see com.googlecode.mp4parser.RequiresParseDetailAspect
+ */
+public @interface DoNotParseDetail {
+}
+
+
diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/annotations/ParseDetail.java b/isoparser/src/main/java/com/googlecode/mp4parser/annotations/ParseDetail.java
new file mode 100644
index 0000000..7b66d53
--- /dev/null
+++ b/isoparser/src/main/java/com/googlecode/mp4parser/annotations/ParseDetail.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2012 Sebastian Annies, Hamburg
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.googlecode.mp4parser.annotations;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Inherited;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+
+@Target({ElementType.METHOD, ElementType.TYPE})
+@Retention(RetentionPolicy.RUNTIME)
+@Inherited
+@Documented
+public @interface ParseDetail {
+}
+
+
diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/authoring/.svn/all-wcprops b/isoparser/src/main/java/com/googlecode/mp4parser/authoring/.svn/all-wcprops
new file mode 100644
index 0000000..89054c9
--- /dev/null
+++ b/isoparser/src/main/java/com/googlecode/mp4parser/authoring/.svn/all-wcprops
@@ -0,0 +1,41 @@
+K 25
+svn:wc:ra_dav:version-url
+V 82
+/svn/!svn/ver/776/trunk/isoparser/src/main/java/com/googlecode/mp4parser/authoring
+END
+Movie.java
+K 25
+svn:wc:ra_dav:version-url
+V 93
+/svn/!svn/ver/514/trunk/isoparser/src/main/java/com/googlecode/mp4parser/authoring/Movie.java
+END
+Track.java
+K 25
+svn:wc:ra_dav:version-url
+V 93
+/svn/!svn/ver/686/trunk/isoparser/src/main/java/com/googlecode/mp4parser/authoring/Track.java
+END
+TrackMetaData.java
+K 25
+svn:wc:ra_dav:version-url
+V 101
+/svn/!svn/ver/745/trunk/isoparser/src/main/java/com/googlecode/mp4parser/authoring/TrackMetaData.java
+END
+Mp4TrackImpl.java
+K 25
+svn:wc:ra_dav:version-url
+V 100
+/svn/!svn/ver/765/trunk/isoparser/src/main/java/com/googlecode/mp4parser/authoring/Mp4TrackImpl.java
+END
+AbstractTrack.java
+K 25
+svn:wc:ra_dav:version-url
+V 101
+/svn/!svn/ver/418/trunk/isoparser/src/main/java/com/googlecode/mp4parser/authoring/AbstractTrack.java
+END
+DateHelper.java
+K 25
+svn:wc:ra_dav:version-url
+V 98
+/svn/!svn/ver/418/trunk/isoparser/src/main/java/com/googlecode/mp4parser/authoring/DateHelper.java
+END
diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/authoring/.svn/entries b/isoparser/src/main/java/com/googlecode/mp4parser/authoring/.svn/entries
new file mode 100644
index 0000000..7d2b29e
--- /dev/null
+++ b/isoparser/src/main/java/com/googlecode/mp4parser/authoring/.svn/entries
@@ -0,0 +1,244 @@
+10
+
+dir
+778
+http://mp4parser.googlecode.com/svn/trunk/isoparser/src/main/java/com/googlecode/mp4parser/authoring
+http://mp4parser.googlecode.com/svn
+
+
+
+2012-09-10T14:34:23.574807Z
+776
+sebastian.annies@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+7decde4b-c250-0410-a0da-51896bc88be6
+
+Movie.java
+file
+
+
+
+
+2012-09-14T17:27:50.517219Z
+e3a56133cfdfacb92ed0a54177e847b4
+2012-04-22T10:09:06.632613Z
+514
+Sebastian.Annies@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+2558
+
+container
+dir
+
+Track.java
+file
+
+
+
+
+2012-09-14T17:27:50.517219Z
+9537fa79b71fe26727e56e84e94bbdb8
+2012-06-24T19:52:05.961412Z
+686
+Sebastian.Annies@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+1607
+
+TrackMetaData.java
+file
+
+
+
+
+2012-09-14T17:27:50.527219Z
+cbb770cca0ee421026eec0a2f40d2376
+2012-08-14T19:18:50.777750Z
+745
+Sebastian.Annies@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+2948
+
+builder
+dir
+
+adaptivestreaming
+dir
+
+tracks
+dir
+
+Mp4TrackImpl.java
+file
+
+
+
+
+2012-09-14T17:27:50.527219Z
+c57930172e9d0da9e881d8dc8ecf2924
+2012-08-29T08:26:56.932482Z
+765
+michael.stattmann@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+10958
+
+AbstractTrack.java
+file
+
+
+
+
+2012-09-14T17:27:50.527219Z
+973f4f354fb6f575dd1a0c8a68d54653
+2012-03-11T20:54:45.638478Z
+418
+Sebastian.Annies@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+1481
+
+DateHelper.java
+file
+
+
+
+
+2012-09-14T17:27:50.527219Z
+765e3f37d7bb369f569aa91e326a90b8
+2012-03-11T20:54:45.638478Z
+418
+Sebastian.Annies@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+1349
+
diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/authoring/.svn/text-base/AbstractTrack.java.svn-base b/isoparser/src/main/java/com/googlecode/mp4parser/authoring/.svn/text-base/AbstractTrack.java.svn-base
new file mode 100644
index 0000000..fb0e224
--- /dev/null
+++ b/isoparser/src/main/java/com/googlecode/mp4parser/authoring/.svn/text-base/AbstractTrack.java.svn-base
@@ -0,0 +1,60 @@
+/*
+ * Copyright 2012 Sebastian Annies, Hamburg
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.googlecode.mp4parser.authoring;
+
+/**
+ *
+ */
+public abstract class AbstractTrack implements Track {
+    private boolean enabled = true;
+    private boolean inMovie = true;
+    private boolean inPreview = true;
+    private boolean inPoster = true;
+
+    public boolean isEnabled() {
+        return enabled;
+    }
+
+    public boolean isInMovie() {
+        return inMovie;
+    }
+
+    public boolean isInPreview() {
+        return inPreview;
+    }
+
+    public boolean isInPoster() {
+        return inPoster;
+    }
+
+    public void setEnabled(boolean enabled) {
+        this.enabled = enabled;
+    }
+
+    public void setInMovie(boolean inMovie) {
+        this.inMovie = inMovie;
+    }
+
+    public void setInPreview(boolean inPreview) {
+        this.inPreview = inPreview;
+    }
+
+    public void setInPoster(boolean inPoster) {
+        this.inPoster = inPoster;
+    }
+
+}
diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/authoring/.svn/text-base/DateHelper.java.svn-base b/isoparser/src/main/java/com/googlecode/mp4parser/authoring/.svn/text-base/DateHelper.java.svn-base
new file mode 100644
index 0000000..0252859
--- /dev/null
+++ b/isoparser/src/main/java/com/googlecode/mp4parser/authoring/.svn/text-base/DateHelper.java.svn-base
@@ -0,0 +1,44 @@
+/*
+ * Copyright 2012 Sebastian Annies, Hamburg
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.googlecode.mp4parser.authoring;
+
+import java.util.Date;
+
+/**
+ * Converts ISO Dates (seconds since 1/1/1904) to Date and vice versa.
+ */
+public class DateHelper {
+    /**
+     * Converts a long value with seconds since 1/1/1904 to Date.
+     *
+     * @param secondsSince seconds since 1/1/1904
+     * @return date the corresponding <code>Date</code>
+     */
+    static public Date convert(long secondsSince) {
+        return new Date((secondsSince - 2082844800L) * 1000L);
+    }
+
+
+    /**
+     * Converts a date as long to a mac date as long
+     *
+     * @param date date to convert
+     * @return date in mac format
+     */
+    static public long convert(Date date) {
+        return (date.getTime() / 1000L) + 2082844800L;
+    }
+}
diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/authoring/.svn/text-base/Movie.java.svn-base b/isoparser/src/main/java/com/googlecode/mp4parser/authoring/.svn/text-base/Movie.java.svn-base
new file mode 100644
index 0000000..0658682
--- /dev/null
+++ b/isoparser/src/main/java/com/googlecode/mp4parser/authoring/.svn/text-base/Movie.java.svn-base
@@ -0,0 +1,91 @@
+/*
+ * Copyright 2012 Sebastian Annies, Hamburg
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.googlecode.mp4parser.authoring;
+
+import java.util.LinkedList;
+import java.util.List;
+
+/**
+ *
+ */
+public class Movie {
+    List<Track> tracks = new LinkedList<Track>();
+
+    public List<Track> getTracks() {
+        return tracks;
+    }
+
+    public void setTracks(List<Track> tracks) {
+        this.tracks = tracks;
+    }
+
+    public void addTrack(Track nuTrack) {
+        // do some checking
+        // perhaps the movie needs to get longer!
+        if (getTrackByTrackId(nuTrack.getTrackMetaData().getTrackId()) != null) {
+            // We already have a track with that trackId. Create a new one
+            nuTrack.getTrackMetaData().setTrackId(getNextTrackId());
+        }
+        tracks.add(nuTrack);
+    }
+
+
+    @Override
+    public String toString() {
+        String s = "Movie{ ";
+        for (Track track : tracks) {
+            s += "track_" + track.getTrackMetaData().getTrackId() + " (" + track.getHandler() + ") ";
+        }
+
+        s += '}';
+        return s;
+    }
+
+    public long getNextTrackId() {
+        long nextTrackId = 0;
+        for (Track track : tracks) {
+            nextTrackId = nextTrackId < track.getTrackMetaData().getTrackId() ? track.getTrackMetaData().getTrackId() : nextTrackId;
+        }
+        return ++nextTrackId;
+    }
+
+
+    public Track getTrackByTrackId(long trackId) {
+        for (Track track : tracks) {
+            if (track.getTrackMetaData().getTrackId() == trackId) {
+                return track;
+            }
+        }
+        return null;
+    }
+
+
+    public long getTimescale() {
+        long timescale = this.getTracks().iterator().next().getTrackMetaData().getTimescale();
+        for (Track track : this.getTracks()) {
+            timescale = gcd(track.getTrackMetaData().getTimescale(), timescale);
+        }
+        return timescale;
+    }
+
+    public static long gcd(long a, long b) {
+        if (b == 0) {
+            return a;
+        }
+        return gcd(b, a % b);
+    }
+
+}
diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/authoring/.svn/text-base/Mp4TrackImpl.java.svn-base b/isoparser/src/main/java/com/googlecode/mp4parser/authoring/.svn/text-base/Mp4TrackImpl.java.svn-base
new file mode 100644
index 0000000..3bff1a5
--- /dev/null
+++ b/isoparser/src/main/java/com/googlecode/mp4parser/authoring/.svn/text-base/Mp4TrackImpl.java.svn-base
@@ -0,0 +1,219 @@
+/*
+ * Copyright 2012 Sebastian Annies, Hamburg
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.googlecode.mp4parser.authoring;
+
+import com.coremedia.iso.boxes.*;
+import com.coremedia.iso.boxes.fragment.*;
+import com.coremedia.iso.boxes.mdat.SampleList;
+
+import java.nio.ByteBuffer;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+
+import static com.googlecode.mp4parser.util.CastUtils.l2i;
+
+/**
+ * Represents a single track of an MP4 file.
+ */
+public class Mp4TrackImpl extends AbstractTrack {
+    private List<ByteBuffer> samples;
+    private SampleDescriptionBox sampleDescriptionBox;
+    private List<TimeToSampleBox.Entry> decodingTimeEntries;
+    private List<CompositionTimeToSample.Entry> compositionTimeEntries;
+    private long[] syncSamples = new long[0];
+    private List<SampleDependencyTypeBox.Entry> sampleDependencies;
+    private TrackMetaData trackMetaData = new TrackMetaData();
+    private String handler;
+    private AbstractMediaHeaderBox mihd;
+
+    public Mp4TrackImpl(TrackBox trackBox) {
+        final long trackId = trackBox.getTrackHeaderBox().getTrackId();
+        samples = new SampleList(trackBox);
+        SampleTableBox stbl = trackBox.getMediaBox().getMediaInformationBox().getSampleTableBox();
+        handler = trackBox.getMediaBox().getHandlerBox().getHandlerType();
+
+        mihd = trackBox.getMediaBox().getMediaInformationBox().getMediaHeaderBox();
+        decodingTimeEntries = new LinkedList<TimeToSampleBox.Entry>();
+        compositionTimeEntries = new LinkedList<CompositionTimeToSample.Entry>();
+        sampleDependencies = new LinkedList<SampleDependencyTypeBox.Entry>();
+
+        decodingTimeEntries.addAll(stbl.getTimeToSampleBox().getEntries());
+        if (stbl.getCompositionTimeToSample() != null) {
+            compositionTimeEntries.addAll(stbl.getCompositionTimeToSample().getEntries());
+        }
+        if (stbl.getSampleDependencyTypeBox() != null) {
+            sampleDependencies.addAll(stbl.getSampleDependencyTypeBox().getEntries());
+        }
+        if (stbl.getSyncSampleBox() != null) {
+            syncSamples = stbl.getSyncSampleBox().getSampleNumber();
+        }
+
+
+        sampleDescriptionBox = stbl.getSampleDescriptionBox();
+        final List<MovieExtendsBox> movieExtendsBoxes = trackBox.getParent().getBoxes(MovieExtendsBox.class);
+        if (movieExtendsBoxes.size() > 0) {
+            for (MovieExtendsBox mvex : movieExtendsBoxes) {
+                final List<TrackExtendsBox> trackExtendsBoxes = mvex.getBoxes(TrackExtendsBox.class);
+                for (TrackExtendsBox trex : trackExtendsBoxes) {
+                    if (trex.getTrackId() == trackId) {
+                        List<Long> syncSampleList = new LinkedList<Long>();
+
+                        long sampleNumber = 1;
+                        for (MovieFragmentBox movieFragmentBox : trackBox.getIsoFile().getBoxes(MovieFragmentBox.class)) {
+                            List<TrackFragmentBox> trafs = movieFragmentBox.getBoxes(TrackFragmentBox.class);
+                            for (TrackFragmentBox traf : trafs) {
+                                if (traf.getTrackFragmentHeaderBox().getTrackId() == trackId) {
+                                    List<TrackRunBox> truns = traf.getBoxes(TrackRunBox.class);
+                                    for (TrackRunBox trun : truns) {
+                                        final TrackFragmentHeaderBox tfhd = ((TrackFragmentBox) trun.getParent()).getTrackFragmentHeaderBox();
+                                        boolean first = true;
+                                        for (TrackRunBox.Entry entry : trun.getEntries()) {
+                                            if (trun.isSampleDurationPresent()) {
+                                                if (decodingTimeEntries.size() == 0 ||
+                                                        decodingTimeEntries.get(decodingTimeEntries.size() - 1).getDelta() != entry.getSampleDuration()) {
+                                                    decodingTimeEntries.add(new TimeToSampleBox.Entry(1, entry.getSampleDuration()));
+                                                } else {
+                                                    TimeToSampleBox.Entry e = decodingTimeEntries.get(decodingTimeEntries.size() - 1);
+                                                    e.setCount(e.getCount() + 1);
+                                                }
+                                            } else {
+                                                if (tfhd.hasDefaultSampleDuration()) {
+                                                    decodingTimeEntries.add(new TimeToSampleBox.Entry(1, tfhd.getDefaultSampleDuration()));
+                                                } else {
+                                                    decodingTimeEntries.add(new TimeToSampleBox.Entry(1, trex.getDefaultSampleDuration()));
+                                                }
+                                            }
+
+                                            if (trun.isSampleCompositionTimeOffsetPresent()) {
+                                                if (compositionTimeEntries.size() == 0 ||
+                                                        compositionTimeEntries.get(compositionTimeEntries.size() - 1).getOffset() != entry.getSampleCompositionTimeOffset()) {
+                                                    compositionTimeEntries.add(new CompositionTimeToSample.Entry(1, l2i(entry.getSampleCompositionTimeOffset())));
+                                                } else {
+                                                    CompositionTimeToSample.Entry e = compositionTimeEntries.get(compositionTimeEntries.size() - 1);
+                                                    e.setCount(e.getCount() + 1);
+                                                }
+                                            }
+                                            final SampleFlags sampleFlags;
+                                            if (trun.isSampleFlagsPresent()) {
+                                                sampleFlags = entry.getSampleFlags();
+                                            } else {
+                                                if (first && trun.isFirstSampleFlagsPresent()) {
+                                                    sampleFlags = trun.getFirstSampleFlags();
+                                                } else {
+                                                    if (tfhd.hasDefaultSampleFlags()) {
+                                                        sampleFlags = tfhd.getDefaultSampleFlags();
+                                                    } else {
+                                                        sampleFlags = trex.getDefaultSampleFlags();
+                                                    }
+                                                }
+                                            }
+                                            if (sampleFlags != null && !sampleFlags.isSampleIsDifferenceSample()) {
+                                                //iframe
+                                                syncSampleList.add(sampleNumber);
+                                            }
+                                            sampleNumber++;
+                                            first = false;
+                                        }
+                                    }
+                                }
+                            }
+                        }
+                        // Warning: Crappy code
+                        long[] oldSS = syncSamples;
+                        syncSamples = new long[syncSamples.length + syncSampleList.size()];
+                        System.arraycopy(oldSS, 0, syncSamples, 0, oldSS.length);
+                        final Iterator<Long> iterator = syncSampleList.iterator();
+                        int i = oldSS.length;
+                        while (iterator.hasNext()) {
+                            Long syncSampleNumber = iterator.next();
+                            syncSamples[i++] = syncSampleNumber;
+                        }
+                    }
+                }
+            }
+        }
+        MediaHeaderBox mdhd = trackBox.getMediaBox().getMediaHeaderBox();
+        TrackHeaderBox tkhd = trackBox.getTrackHeaderBox();
+
+        setEnabled(tkhd.isEnabled());
+        setInMovie(tkhd.isInMovie());
+        setInPoster(tkhd.isInPoster());
+        setInPreview(tkhd.isInPreview());
+
+        trackMetaData.setTrackId(tkhd.getTrackId());
+        trackMetaData.setCreationTime(DateHelper.convert(mdhd.getCreationTime()));
+        trackMetaData.setLanguage(mdhd.getLanguage());
+/*        System.err.println(mdhd.getModificationTime());
+        System.err.println(DateHelper.convert(mdhd.getModificationTime()));
+        System.err.println(DateHelper.convert(DateHelper.convert(mdhd.getModificationTime())));
+        System.err.println(DateHelper.convert(DateHelper.convert(DateHelper.convert(mdhd.getModificationTime()))));*/
+
+        trackMetaData.setModificationTime(DateHelper.convert(mdhd.getModificationTime()));
+        trackMetaData.setTimescale(mdhd.getTimescale());
+        trackMetaData.setHeight(tkhd.getHeight());
+        trackMetaData.setWidth(tkhd.getWidth());
+        trackMetaData.setLayer(tkhd.getLayer());
+    }
+
+    public List<ByteBuffer> getSamples() {
+        return samples;
+    }
+
+
+    public SampleDescriptionBox getSampleDescriptionBox() {
+        return sampleDescriptionBox;
+    }
+
+    public List<TimeToSampleBox.Entry> getDecodingTimeEntries() {
+        return decodingTimeEntries;
+    }
+
+    public List<CompositionTimeToSample.Entry> getCompositionTimeEntries() {
+        return compositionTimeEntries;
+    }
+
+    public long[] getSyncSamples() {
+        return syncSamples;
+    }
+
+    public List<SampleDependencyTypeBox.Entry> getSampleDependencies() {
+        return sampleDependencies;
+    }
+
+    public TrackMetaData getTrackMetaData() {
+        return trackMetaData;
+    }
+
+    public String getHandler() {
+        return handler;
+    }
+
+    public AbstractMediaHeaderBox getMediaHeaderBox() {
+        return mihd;
+    }
+
+    public SubSampleInformationBox getSubsampleInformationBox() {
+        return null;
+    }
+
+    @Override
+    public String toString() {
+        return "Mp4TrackImpl{" +
+                "handler='" + handler + '\'' +
+                '}';
+    }
+}
diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/authoring/.svn/text-base/Track.java.svn-base b/isoparser/src/main/java/com/googlecode/mp4parser/authoring/.svn/text-base/Track.java.svn-base
new file mode 100644
index 0000000..1f4b363
--- /dev/null
+++ b/isoparser/src/main/java/com/googlecode/mp4parser/authoring/.svn/text-base/Track.java.svn-base
@@ -0,0 +1,60 @@
+/*
+ * Copyright 2012 Sebastian Annies, Hamburg
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.googlecode.mp4parser.authoring;
+
+import com.coremedia.iso.boxes.*;
+
+import java.nio.ByteBuffer;
+import java.util.List;
+
+/**
+ * Represents a Track. A track is a timed sequence of related samples.
+ * <p/>
+ * <b>NOTE: </b><br/
+ * For media data, a track corresponds to a sequence of images or sampled audio; for hint tracks, a track
+ * corresponds to a streaming channel.
+ */
+public interface Track {
+
+    SampleDescriptionBox getSampleDescriptionBox();
+
+    List<TimeToSampleBox.Entry> getDecodingTimeEntries();
+
+    List<CompositionTimeToSample.Entry> getCompositionTimeEntries();
+
+    long[] getSyncSamples();
+
+    List<SampleDependencyTypeBox.Entry> getSampleDependencies();
+
+    TrackMetaData getTrackMetaData();
+
+    String getHandler();
+
+    boolean isEnabled();
+
+    boolean isInMovie();
+
+    boolean isInPreview();
+
+    boolean isInPoster();
+
+    List<ByteBuffer> getSamples();
+
+    public Box getMediaHeaderBox();
+
+    public SubSampleInformationBox getSubsampleInformationBox();
+
+}
diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/authoring/.svn/text-base/TrackMetaData.java.svn-base b/isoparser/src/main/java/com/googlecode/mp4parser/authoring/.svn/text-base/TrackMetaData.java.svn-base
new file mode 100644
index 0000000..c262309
--- /dev/null
+++ b/isoparser/src/main/java/com/googlecode/mp4parser/authoring/.svn/text-base/TrackMetaData.java.svn-base
@@ -0,0 +1,130 @@
+/*
+ * Copyright 2012 Sebastian Annies, Hamburg
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.googlecode.mp4parser.authoring;
+
+import java.util.Date;
+
+/**
+ *
+ */
+public class TrackMetaData implements Cloneable {
+    private String language;
+    private long timescale;
+    private Date modificationTime = new Date();
+    private Date creationTime = new Date();
+    private double width;
+    private double height;
+    private float volume;
+    private long trackId = 1; // zero is not allowed
+    private int group = 0;
+
+
+    /**
+     * specifies the front-to-back ordering of video tracks; tracks with lower
+     * numbers are closer to the viewer. 0 is the normal value, and -1 would be
+     * in front of track 0, and so on.
+     */
+    int layer;
+
+    public String getLanguage() {
+        return language;
+    }
+
+    public void setLanguage(String language) {
+        this.language = language;
+    }
+
+    public long getTimescale() {
+        return timescale;
+    }
+
+    public void setTimescale(long timescale) {
+        this.timescale = timescale;
+    }
+
+    public Date getModificationTime() {
+        return modificationTime;
+    }
+
+    public void setModificationTime(Date modificationTime) {
+        this.modificationTime = modificationTime;
+    }
+
+    public Date getCreationTime() {
+        return creationTime;
+    }
+
+    public void setCreationTime(Date creationTime) {
+        this.creationTime = creationTime;
+    }
+
+    public double getWidth() {
+        return width;
+    }
+
+    public void setWidth(double width) {
+        this.width = width;
+    }
+
+    public double getHeight() {
+        return height;
+    }
+
+    public void setHeight(double height) {
+        this.height = height;
+    }
+
+    public long getTrackId() {
+        return trackId;
+    }
+
+    public void setTrackId(long trackId) {
+        this.trackId = trackId;
+    }
+
+    public int getLayer() {
+        return layer;
+    }
+
+    public void setLayer(int layer) {
+        this.layer = layer;
+    }
+
+    public float getVolume() {
+        return volume;
+    }
+
+    public void setVolume(float volume) {
+        this.volume = volume;
+    }
+
+    public int getGroup() {
+        return group;
+    }
+
+    public void setGroup(int group) {
+        this.group = group;
+    }
+
+    public Object clone() {
+        try {
+            return super.clone();
+        } catch (CloneNotSupportedException e) {
+            return null;
+        }
+    }
+
+}
diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/authoring/AbstractTrack.java b/isoparser/src/main/java/com/googlecode/mp4parser/authoring/AbstractTrack.java
new file mode 100644
index 0000000..fb0e224
--- /dev/null
+++ b/isoparser/src/main/java/com/googlecode/mp4parser/authoring/AbstractTrack.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright 2012 Sebastian Annies, Hamburg
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.googlecode.mp4parser.authoring;
+
+/**
+ *
+ */
+public abstract class AbstractTrack implements Track {
+    private boolean enabled = true;
+    private boolean inMovie = true;
+    private boolean inPreview = true;
+    private boolean inPoster = true;
+
+    public boolean isEnabled() {
+        return enabled;
+    }
+
+    public boolean isInMovie() {
+        return inMovie;
+    }
+
+    public boolean isInPreview() {
+        return inPreview;
+    }
+
+    public boolean isInPoster() {
+        return inPoster;
+    }
+
+    public void setEnabled(boolean enabled) {
+        this.enabled = enabled;
+    }
+
+    public void setInMovie(boolean inMovie) {
+        this.inMovie = inMovie;
+    }
+
+    public void setInPreview(boolean inPreview) {
+        this.inPreview = inPreview;
+    }
+
+    public void setInPoster(boolean inPoster) {
+        this.inPoster = inPoster;
+    }
+
+}
diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/authoring/DateHelper.java b/isoparser/src/main/java/com/googlecode/mp4parser/authoring/DateHelper.java
new file mode 100644
index 0000000..0252859
--- /dev/null
+++ b/isoparser/src/main/java/com/googlecode/mp4parser/authoring/DateHelper.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright 2012 Sebastian Annies, Hamburg
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.googlecode.mp4parser.authoring;
+
+import java.util.Date;
+
+/**
+ * Converts ISO Dates (seconds since 1/1/1904) to Date and vice versa.
+ */
+public class DateHelper {
+    /**
+     * Converts a long value with seconds since 1/1/1904 to Date.
+     *
+     * @param secondsSince seconds since 1/1/1904
+     * @return date the corresponding <code>Date</code>
+     */
+    static public Date convert(long secondsSince) {
+        return new Date((secondsSince - 2082844800L) * 1000L);
+    }
+
+
+    /**
+     * Converts a date as long to a mac date as long
+     *
+     * @param date date to convert
+     * @return date in mac format
+     */
+    static public long convert(Date date) {
+        return (date.getTime() / 1000L) + 2082844800L;
+    }
+}
diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/authoring/Movie.java b/isoparser/src/main/java/com/googlecode/mp4parser/authoring/Movie.java
new file mode 100644
index 0000000..0658682
--- /dev/null
+++ b/isoparser/src/main/java/com/googlecode/mp4parser/authoring/Movie.java
@@ -0,0 +1,91 @@
+/*
+ * Copyright 2012 Sebastian Annies, Hamburg
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.googlecode.mp4parser.authoring;
+
+import java.util.LinkedList;
+import java.util.List;
+
+/**
+ *
+ */
+public class Movie {
+    List<Track> tracks = new LinkedList<Track>();
+
+    public List<Track> getTracks() {
+        return tracks;
+    }
+
+    public void setTracks(List<Track> tracks) {
+        this.tracks = tracks;
+    }
+
+    public void addTrack(Track nuTrack) {
+        // do some checking
+        // perhaps the movie needs to get longer!
+        if (getTrackByTrackId(nuTrack.getTrackMetaData().getTrackId()) != null) {
+            // We already have a track with that trackId. Create a new one
+            nuTrack.getTrackMetaData().setTrackId(getNextTrackId());
+        }
+        tracks.add(nuTrack);
+    }
+
+
+    @Override
+    public String toString() {
+        String s = "Movie{ ";
+        for (Track track : tracks) {
+            s += "track_" + track.getTrackMetaData().getTrackId() + " (" + track.getHandler() + ") ";
+        }
+
+        s += '}';
+        return s;
+    }
+
+    public long getNextTrackId() {
+        long nextTrackId = 0;
+        for (Track track : tracks) {
+            nextTrackId = nextTrackId < track.getTrackMetaData().getTrackId() ? track.getTrackMetaData().getTrackId() : nextTrackId;
+        }
+        return ++nextTrackId;
+    }
+
+
+    public Track getTrackByTrackId(long trackId) {
+        for (Track track : tracks) {
+            if (track.getTrackMetaData().getTrackId() == trackId) {
+                return track;
+            }
+        }
+        return null;
+    }
+
+
+    public long getTimescale() {
+        long timescale = this.getTracks().iterator().next().getTrackMetaData().getTimescale();
+        for (Track track : this.getTracks()) {
+            timescale = gcd(track.getTrackMetaData().getTimescale(), timescale);
+        }
+        return timescale;
+    }
+
+    public static long gcd(long a, long b) {
+        if (b == 0) {
+            return a;
+        }
+        return gcd(b, a % b);
+    }
+
+}
diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/authoring/Mp4TrackImpl.java b/isoparser/src/main/java/com/googlecode/mp4parser/authoring/Mp4TrackImpl.java
new file mode 100644
index 0000000..3bff1a5
--- /dev/null
+++ b/isoparser/src/main/java/com/googlecode/mp4parser/authoring/Mp4TrackImpl.java
@@ -0,0 +1,219 @@
+/*
+ * Copyright 2012 Sebastian Annies, Hamburg
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.googlecode.mp4parser.authoring;
+
+import com.coremedia.iso.boxes.*;
+import com.coremedia.iso.boxes.fragment.*;
+import com.coremedia.iso.boxes.mdat.SampleList;
+
+import java.nio.ByteBuffer;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+
+import static com.googlecode.mp4parser.util.CastUtils.l2i;
+
+/**
+ * Represents a single track of an MP4 file.
+ */
+public class Mp4TrackImpl extends AbstractTrack {
+    private List<ByteBuffer> samples;
+    private SampleDescriptionBox sampleDescriptionBox;
+    private List<TimeToSampleBox.Entry> decodingTimeEntries;
+    private List<CompositionTimeToSample.Entry> compositionTimeEntries;
+    private long[] syncSamples = new long[0];
+    private List<SampleDependencyTypeBox.Entry> sampleDependencies;
+    private TrackMetaData trackMetaData = new TrackMetaData();
+    private String handler;
+    private AbstractMediaHeaderBox mihd;
+
+    public Mp4TrackImpl(TrackBox trackBox) {
+        final long trackId = trackBox.getTrackHeaderBox().getTrackId();
+        samples = new SampleList(trackBox);
+        SampleTableBox stbl = trackBox.getMediaBox().getMediaInformationBox().getSampleTableBox();
+        handler = trackBox.getMediaBox().getHandlerBox().getHandlerType();
+
+        mihd = trackBox.getMediaBox().getMediaInformationBox().getMediaHeaderBox();
+        decodingTimeEntries = new LinkedList<TimeToSampleBox.Entry>();
+        compositionTimeEntries = new LinkedList<CompositionTimeToSample.Entry>();
+        sampleDependencies = new LinkedList<SampleDependencyTypeBox.Entry>();
+
+        decodingTimeEntries.addAll(stbl.getTimeToSampleBox().getEntries());
+        if (stbl.getCompositionTimeToSample() != null) {
+            compositionTimeEntries.addAll(stbl.getCompositionTimeToSample().getEntries());
+        }
+        if (stbl.getSampleDependencyTypeBox() != null) {
+            sampleDependencies.addAll(stbl.getSampleDependencyTypeBox().getEntries());
+        }
+        if (stbl.getSyncSampleBox() != null) {
+            syncSamples = stbl.getSyncSampleBox().getSampleNumber();
+        }
+
+
+        sampleDescriptionBox = stbl.getSampleDescriptionBox();
+        final List<MovieExtendsBox> movieExtendsBoxes = trackBox.getParent().getBoxes(MovieExtendsBox.class);
+        if (movieExtendsBoxes.size() > 0) {
+            for (MovieExtendsBox mvex : movieExtendsBoxes) {
+                final List<TrackExtendsBox> trackExtendsBoxes = mvex.getBoxes(TrackExtendsBox.class);
+                for (TrackExtendsBox trex : trackExtendsBoxes) {
+                    if (trex.getTrackId() == trackId) {
+                        List<Long> syncSampleList = new LinkedList<Long>();
+
+                        long sampleNumber = 1;
+                        for (MovieFragmentBox movieFragmentBox : trackBox.getIsoFile().getBoxes(MovieFragmentBox.class)) {
+                            List<TrackFragmentBox> trafs = movieFragmentBox.getBoxes(TrackFragmentBox.class);
+                            for (TrackFragmentBox traf : trafs) {
+                                if (traf.getTrackFragmentHeaderBox().getTrackId() == trackId) {
+                                    List<TrackRunBox> truns = traf.getBoxes(TrackRunBox.class);
+                                    for (TrackRunBox trun : truns) {
+                                        final TrackFragmentHeaderBox tfhd = ((TrackFragmentBox) trun.getParent()).getTrackFragmentHeaderBox();
+                                        boolean first = true;
+                                        for (TrackRunBox.Entry entry : trun.getEntries()) {
+                                            if (trun.isSampleDurationPresent()) {
+                                                if (decodingTimeEntries.size() == 0 ||
+                                                        decodingTimeEntries.get(decodingTimeEntries.size() - 1).getDelta() != entry.getSampleDuration()) {
+                                                    decodingTimeEntries.add(new TimeToSampleBox.Entry(1, entry.getSampleDuration()));
+                                                } else {
+                                                    TimeToSampleBox.Entry e = decodingTimeEntries.get(decodingTimeEntries.size() - 1);
+                                                    e.setCount(e.getCount() + 1);
+                                                }
+                                            } else {
+                                                if (tfhd.hasDefaultSampleDuration()) {
+                                                    decodingTimeEntries.add(new TimeToSampleBox.Entry(1, tfhd.getDefaultSampleDuration()));
+                                                } else {
+                                                    decodingTimeEntries.add(new TimeToSampleBox.Entry(1, trex.getDefaultSampleDuration()));
+                                                }
+                                            }
+
+                                            if (trun.isSampleCompositionTimeOffsetPresent()) {
+                                                if (compositionTimeEntries.size() == 0 ||
+                                                        compositionTimeEntries.get(compositionTimeEntries.size() - 1).getOffset() != entry.getSampleCompositionTimeOffset()) {
+                                                    compositionTimeEntries.add(new CompositionTimeToSample.Entry(1, l2i(entry.getSampleCompositionTimeOffset())));
+                                                } else {
+                                                    CompositionTimeToSample.Entry e = compositionTimeEntries.get(compositionTimeEntries.size() - 1);
+                                                    e.setCount(e.getCount() + 1);
+                                                }
+                                            }
+                                            final SampleFlags sampleFlags;
+                                            if (trun.isSampleFlagsPresent()) {
+                                                sampleFlags = entry.getSampleFlags();
+                                            } else {
+                                                if (first && trun.isFirstSampleFlagsPresent()) {
+                                                    sampleFlags = trun.getFirstSampleFlags();
+                                                } else {
+                                                    if (tfhd.hasDefaultSampleFlags()) {
+                                                        sampleFlags = tfhd.getDefaultSampleFlags();
+                                                    } else {
+                                                        sampleFlags = trex.getDefaultSampleFlags();
+                                                    }
+                                                }
+                                            }
+                                            if (sampleFlags != null && !sampleFlags.isSampleIsDifferenceSample()) {
+                                                //iframe
+                                                syncSampleList.add(sampleNumber);
+                                            }
+                                            sampleNumber++;
+                                            first = false;
+                                        }
+                                    }
+                                }
+                            }
+                        }
+                        // Warning: Crappy code
+                        long[] oldSS = syncSamples;
+                        syncSamples = new long[syncSamples.length + syncSampleList.size()];
+                        System.arraycopy(oldSS, 0, syncSamples, 0, oldSS.length);
+                        final Iterator<Long> iterator = syncSampleList.iterator();
+                        int i = oldSS.length;
+                        while (iterator.hasNext()) {
+                            Long syncSampleNumber = iterator.next();
+                            syncSamples[i++] = syncSampleNumber;
+                        }
+                    }
+                }
+            }
+        }
+        MediaHeaderBox mdhd = trackBox.getMediaBox().getMediaHeaderBox();
+        TrackHeaderBox tkhd = trackBox.getTrackHeaderBox();
+
+        setEnabled(tkhd.isEnabled());
+        setInMovie(tkhd.isInMovie());
+        setInPoster(tkhd.isInPoster());
+        setInPreview(tkhd.isInPreview());
+
+        trackMetaData.setTrackId(tkhd.getTrackId());
+        trackMetaData.setCreationTime(DateHelper.convert(mdhd.getCreationTime()));
+        trackMetaData.setLanguage(mdhd.getLanguage());
+/*        System.err.println(mdhd.getModificationTime());
+        System.err.println(DateHelper.convert(mdhd.getModificationTime()));
+        System.err.println(DateHelper.convert(DateHelper.convert(mdhd.getModificationTime())));
+        System.err.println(DateHelper.convert(DateHelper.convert(DateHelper.convert(mdhd.getModificationTime()))));*/
+
+        trackMetaData.setModificationTime(DateHelper.convert(mdhd.getModificationTime()));
+        trackMetaData.setTimescale(mdhd.getTimescale());
+        trackMetaData.setHeight(tkhd.getHeight());
+        trackMetaData.setWidth(tkhd.getWidth());
+        trackMetaData.setLayer(tkhd.getLayer());
+    }
+
+    public List<ByteBuffer> getSamples() {
+        return samples;
+    }
+
+
+    public SampleDescriptionBox getSampleDescriptionBox() {
+        return sampleDescriptionBox;
+    }
+
+    public List<TimeToSampleBox.Entry> getDecodingTimeEntries() {
+        return decodingTimeEntries;
+    }
+
+    public List<CompositionTimeToSample.Entry> getCompositionTimeEntries() {
+        return compositionTimeEntries;
+    }
+
+    public long[] getSyncSamples() {
+        return syncSamples;
+    }
+
+    public List<SampleDependencyTypeBox.Entry> getSampleDependencies() {
+        return sampleDependencies;
+    }
+
+    public TrackMetaData getTrackMetaData() {
+        return trackMetaData;
+    }
+
+    public String getHandler() {
+        return handler;
+    }
+
+    public AbstractMediaHeaderBox getMediaHeaderBox() {
+        return mihd;
+    }
+
+    public SubSampleInformationBox getSubsampleInformationBox() {
+        return null;
+    }
+
+    @Override
+    public String toString() {
+        return "Mp4TrackImpl{" +
+                "handler='" + handler + '\'' +
+                '}';
+    }
+}
diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/authoring/Track.java b/isoparser/src/main/java/com/googlecode/mp4parser/authoring/Track.java
new file mode 100644
index 0000000..1f4b363
--- /dev/null
+++ b/isoparser/src/main/java/com/googlecode/mp4parser/authoring/Track.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright 2012 Sebastian Annies, Hamburg
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.googlecode.mp4parser.authoring;
+
+import com.coremedia.iso.boxes.*;
+
+import java.nio.ByteBuffer;
+import java.util.List;
+
+/**
+ * Represents a Track. A track is a timed sequence of related samples.
+ * <p/>
+ * <b>NOTE: </b><br/
+ * For media data, a track corresponds to a sequence of images or sampled audio; for hint tracks, a track
+ * corresponds to a streaming channel.
+ */
+public interface Track {
+
+    SampleDescriptionBox getSampleDescriptionBox();
+
+    List<TimeToSampleBox.Entry> getDecodingTimeEntries();
+
+    List<CompositionTimeToSample.Entry> getCompositionTimeEntries();
+
+    long[] getSyncSamples();
+
+    List<SampleDependencyTypeBox.Entry> getSampleDependencies();
+
+    TrackMetaData getTrackMetaData();
+
+    String getHandler();
+
+    boolean isEnabled();
+
+    boolean isInMovie();
+
+    boolean isInPreview();
+
+    boolean isInPoster();
+
+    List<ByteBuffer> getSamples();
+
+    public Box getMediaHeaderBox();
+
+    public SubSampleInformationBox getSubsampleInformationBox();
+
+}
diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/authoring/TrackMetaData.java b/isoparser/src/main/java/com/googlecode/mp4parser/authoring/TrackMetaData.java
new file mode 100644
index 0000000..c262309
--- /dev/null
+++ b/isoparser/src/main/java/com/googlecode/mp4parser/authoring/TrackMetaData.java
@@ -0,0 +1,130 @@
+/*
+ * Copyright 2012 Sebastian Annies, Hamburg
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.googlecode.mp4parser.authoring;
+
+import java.util.Date;
+
+/**
+ *
+ */
+public class TrackMetaData implements Cloneable {
+    private String language;
+    private long timescale;
+    private Date modificationTime = new Date();
+    private Date creationTime = new Date();
+    private double width;
+    private double height;
+    private float volume;
+    private long trackId = 1; // zero is not allowed
+    private int group = 0;
+
+
+    /**
+     * specifies the front-to-back ordering of video tracks; tracks with lower
+     * numbers are closer to the viewer. 0 is the normal value, and -1 would be
+     * in front of track 0, and so on.
+     */
+    int layer;
+
+    public String getLanguage() {
+        return language;
+    }
+
+    public void setLanguage(String language) {
+        this.language = language;
+    }
+
+    public long getTimescale() {
+        return timescale;
+    }
+
+    public void setTimescale(long timescale) {
+        this.timescale = timescale;
+    }
+
+    public Date getModificationTime() {
+        return modificationTime;
+    }
+
+    public void setModificationTime(Date modificationTime) {
+        this.modificationTime = modificationTime;
+    }
+
+    public Date getCreationTime() {
+        return creationTime;
+    }
+
+    public void setCreationTime(Date creationTime) {
+        this.creationTime = creationTime;
+    }
+
+    public double getWidth() {
+        return width;
+    }
+
+    public void setWidth(double width) {
+        this.width = width;
+    }
+
+    public double getHeight() {
+        return height;
+    }
+
+    public void setHeight(double height) {
+        this.height = height;
+    }
+
+    public long getTrackId() {
+        return trackId;
+    }
+
+    public void setTrackId(long trackId) {
+        this.trackId = trackId;
+    }
+
+    public int getLayer() {
+        return layer;
+    }
+
+    public void setLayer(int layer) {
+        this.layer = layer;
+    }
+
+    public float getVolume() {
+        return volume;
+    }
+
+    public void setVolume(float volume) {
+        this.volume = volume;
+    }
+
+    public int getGroup() {
+        return group;
+    }
+
+    public void setGroup(int group) {
+        this.group = group;
+    }
+
+    public Object clone() {
+        try {
+            return super.clone();
+        } catch (CloneNotSupportedException e) {
+            return null;
+        }
+    }
+
+}
diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/authoring/adaptivestreaming/.svn/all-wcprops b/isoparser/src/main/java/com/googlecode/mp4parser/authoring/adaptivestreaming/.svn/all-wcprops
new file mode 100644
index 0000000..7d70c40
--- /dev/null
+++ b/isoparser/src/main/java/com/googlecode/mp4parser/authoring/adaptivestreaming/.svn/all-wcprops
@@ -0,0 +1,47 @@
+K 25
+svn:wc:ra_dav:version-url
+V 100
+/svn/!svn/ver/773/trunk/isoparser/src/main/java/com/googlecode/mp4parser/authoring/adaptivestreaming
+END
+VideoQuality.java
+K 25
+svn:wc:ra_dav:version-url
+V 118
+/svn/!svn/ver/760/trunk/isoparser/src/main/java/com/googlecode/mp4parser/authoring/adaptivestreaming/VideoQuality.java
+END
+FlatPackageWriterImpl.java
+K 25
+svn:wc:ra_dav:version-url
+V 127
+/svn/!svn/ver/760/trunk/isoparser/src/main/java/com/googlecode/mp4parser/authoring/adaptivestreaming/FlatPackageWriterImpl.java
+END
+ManifestWriter.java
+K 25
+svn:wc:ra_dav:version-url
+V 120
+/svn/!svn/ver/755/trunk/isoparser/src/main/java/com/googlecode/mp4parser/authoring/adaptivestreaming/ManifestWriter.java
+END
+AbstractManifestWriter.java
+K 25
+svn:wc:ra_dav:version-url
+V 128
+/svn/!svn/ver/757/trunk/isoparser/src/main/java/com/googlecode/mp4parser/authoring/adaptivestreaming/AbstractManifestWriter.java
+END
+PackageWriter.java
+K 25
+svn:wc:ra_dav:version-url
+V 119
+/svn/!svn/ver/755/trunk/isoparser/src/main/java/com/googlecode/mp4parser/authoring/adaptivestreaming/PackageWriter.java
+END
+AudioQuality.java
+K 25
+svn:wc:ra_dav:version-url
+V 118
+/svn/!svn/ver/760/trunk/isoparser/src/main/java/com/googlecode/mp4parser/authoring/adaptivestreaming/AudioQuality.java
+END
+FlatManifestWriterImpl.java
+K 25
+svn:wc:ra_dav:version-url
+V 128
+/svn/!svn/ver/773/trunk/isoparser/src/main/java/com/googlecode/mp4parser/authoring/adaptivestreaming/FlatManifestWriterImpl.java
+END
diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/authoring/adaptivestreaming/.svn/entries b/isoparser/src/main/java/com/googlecode/mp4parser/authoring/adaptivestreaming/.svn/entries
new file mode 100644
index 0000000..619b17c
--- /dev/null
+++ b/isoparser/src/main/java/com/googlecode/mp4parser/authoring/adaptivestreaming/.svn/entries
@@ -0,0 +1,266 @@
+10
+
+dir
+778
+http://mp4parser.googlecode.com/svn/trunk/isoparser/src/main/java/com/googlecode/mp4parser/authoring/adaptivestreaming
+http://mp4parser.googlecode.com/svn
+
+
+
+2012-09-01T21:55:19.768646Z
+773
+michael.stattmann@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+7decde4b-c250-0410-a0da-51896bc88be6
+
+VideoQuality.java
+file
+
+
+
+
+2012-09-14T17:27:50.317216Z
+356fcadf80f684d83b5f30afd5cb26e4
+2012-08-17T15:20:10.783404Z
+760
+Sebastian.Annies@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+807
+
+FlatPackageWriterImpl.java
+file
+
+
+
+
+2012-09-14T17:27:50.317216Z
+f38a8b91e1b8abd48e1ae26b23b060fa
+2012-08-17T15:20:10.783404Z
+760
+Sebastian.Annies@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+8285
+
+ManifestWriter.java
+file
+
+
+
+
+2012-09-14T17:27:50.317216Z
+4fc006c7919c1ab4ed498340dfa133b3
+2012-08-17T01:13:17.213046Z
+755
+michael.stattmann@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+992
+
+AbstractManifestWriter.java
+file
+
+
+
+
+2012-09-14T17:27:50.317216Z
+1ce766c781ae825fb0620a61eb2b2e1c
+2012-08-17T05:55:12.215481Z
+757
+michael.stattmann@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+5030
+
+PackageWriter.java
+file
+
+
+
+
+2012-09-14T17:27:50.317216Z
+ffdb02efc14eeadf6c1ba9c5e500e76c
+2012-08-17T01:13:17.213046Z
+755
+michael.stattmann@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+878
+
+AudioQuality.java
+file
+
+
+
+
+2012-09-14T17:27:50.317216Z
+c2b5ada192ff228aac261452067773fd
+2012-08-17T15:20:10.783404Z
+760
+Sebastian.Annies@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+887
+
+FlatManifestWriterImpl.java
+file
+
+
+
+
+2012-09-14T17:27:50.317216Z
+d45a45107db5f4c43765d95708382310
+2012-09-01T21:55:19.768646Z
+773
+michael.stattmann@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+30095
+
diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/authoring/adaptivestreaming/.svn/text-base/AbstractManifestWriter.java.svn-base b/isoparser/src/main/java/com/googlecode/mp4parser/authoring/adaptivestreaming/.svn/text-base/AbstractManifestWriter.java.svn-base
new file mode 100644
index 0000000..6ee4ffa
--- /dev/null
+++ b/isoparser/src/main/java/com/googlecode/mp4parser/authoring/adaptivestreaming/.svn/text-base/AbstractManifestWriter.java.svn-base
@@ -0,0 +1,126 @@
+package com.googlecode.mp4parser.authoring.adaptivestreaming;

+

+import com.coremedia.iso.boxes.OriginalFormatBox;

+import com.coremedia.iso.boxes.TimeToSampleBox;

+import com.coremedia.iso.boxes.sampleentry.SampleEntry;

+import com.googlecode.mp4parser.authoring.Movie;

+import com.googlecode.mp4parser.authoring.Track;

+import com.googlecode.mp4parser.authoring.builder.FragmentIntersectionFinder;

+

+import java.io.IOException;

+import java.nio.ByteBuffer;

+import java.util.Arrays;

+import java.util.logging.Logger;

+

+import static com.googlecode.mp4parser.util.CastUtils.l2i;

+

+/**

+ * Created with IntelliJ IDEA.

+ * User: mstattma

+ * Date: 17.08.12

+ * Time: 02:51

+ * To change this template use File | Settings | File Templates.

+ */

+public abstract class AbstractManifestWriter implements ManifestWriter {

+    private static final Logger LOG = Logger.getLogger(AbstractManifestWriter.class.getName());

+

+    private FragmentIntersectionFinder intersectionFinder;

+    protected long[] audioFragmentsDurations;

+    protected long[] videoFragmentsDurations;

+

+    protected AbstractManifestWriter(FragmentIntersectionFinder intersectionFinder) {

+        this.intersectionFinder = intersectionFinder;

+    }

+

+    /**

+     * Calculates the length of each fragment in the given <code>track</code> (as part of <code>movie</code>).

+     *

+     * @param track target of calculation

+     * @param movie the <code>track</code> must be part of this <code>movie</code>

+     * @return the duration of each fragment in track timescale

+     */

+    public long[] calculateFragmentDurations(Track track, Movie movie) {

+        long[] startSamples = intersectionFinder.sampleNumbers(track, movie);

+        long[] durations = new long[startSamples.length];

+        int currentFragment = 0;

+        int currentSample = 1; // sync samples start with 1 !

+

+        for (TimeToSampleBox.Entry entry : track.getDecodingTimeEntries()) {

+            for (int max = currentSample + l2i(entry.getCount()); currentSample < max; currentSample++) {

+                // in this loop we go through the entry.getCount() samples starting from current sample.

+                // the next entry.getCount() samples have the same decoding time.

+                if (currentFragment != startSamples.length - 1 && currentSample == startSamples[currentFragment + 1]) {

+                    // we are not in the last fragment && the current sample is the start sample of the next fragment

+                    currentFragment++;

+                }

+                durations[currentFragment] += entry.getDelta();

+

+

+            }

+        }

+        return durations;

+

+    }

+

+    public long getBitrate(Track track) {

+        long bitrate = 0;

+        for (ByteBuffer sample : track.getSamples()) {

+            bitrate += sample.limit();

+        }

+        bitrate *= 8; // from bytes to bits

+        bitrate /= ((double) getDuration(track)) / track.getTrackMetaData().getTimescale(); // per second

+        return bitrate;

+    }

+

+    protected static long getDuration(Track track) {

+        long duration = 0;

+        for (TimeToSampleBox.Entry entry : track.getDecodingTimeEntries()) {

+            duration += entry.getCount() * entry.getDelta();

+        }

+        return duration;

+    }

+

+    protected long[] checkFragmentsAlign(long[] referenceTimes, long[] checkTimes) throws IOException {

+

+        if (referenceTimes == null || referenceTimes.length == 0) {

+            return checkTimes;

+        }

+        long[] referenceTimesMinusLast = new long[referenceTimes.length - 1];

+        System.arraycopy(referenceTimes, 0, referenceTimesMinusLast, 0, referenceTimes.length - 1);

+        long[] checkTimesMinusLast = new long[checkTimes.length - 1];

+        System.arraycopy(checkTimes, 0, checkTimesMinusLast, 0, checkTimes.length - 1);

+

+        if (!Arrays.equals(checkTimesMinusLast, referenceTimesMinusLast)) {

+            String log = "";

+            log += (referenceTimes.length);

+            log += ("Reference     :  [");

+            for (long l : referenceTimes) {

+                log += (String.format("%10d,", l));

+            }

+            log += ("]");

+            LOG.warning(log);

+            log = "";

+

+            log += (checkTimes.length);

+            log += ("Current       :  [");

+            for (long l : checkTimes) {

+                log += (String.format("%10d,", l));

+            }

+            log += ("]");

+            LOG.warning(log);

+            throw new IOException("Track does not have the same fragment borders as its predecessor.");

+

+        } else {

+            return checkTimes;

+        }

+    }

+

+    protected String getFormat(SampleEntry se) {

+        String type = se.getType();

+        if (type.equals("encv") || type.equals("enca") || type.equals("encv")) {

+            OriginalFormatBox frma = se.getBoxes(OriginalFormatBox.class, true).get(0);

+            type = frma.getDataFormat();

+        }

+        return type;

+    }

+}

diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/authoring/adaptivestreaming/.svn/text-base/AudioQuality.java.svn-base b/isoparser/src/main/java/com/googlecode/mp4parser/authoring/adaptivestreaming/.svn/text-base/AudioQuality.java.svn-base
new file mode 100644
index 0000000..39e115f
--- /dev/null
+++ b/isoparser/src/main/java/com/googlecode/mp4parser/authoring/adaptivestreaming/.svn/text-base/AudioQuality.java.svn-base
@@ -0,0 +1,29 @@
+/*
+ * Copyright 2012 Sebastian Annies, Hamburg
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.googlecode.mp4parser.authoring.adaptivestreaming;
+
+
+public class AudioQuality {
+    String fourCC;
+    long bitrate;
+    int audioTag;
+    long samplingRate;
+    int channels;
+    int bitPerSample;
+    int packetSize;
+    String language;
+    String codecPrivateData;
+}
diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/authoring/adaptivestreaming/.svn/text-base/FlatManifestWriterImpl.java.svn-base b/isoparser/src/main/java/com/googlecode/mp4parser/authoring/adaptivestreaming/.svn/text-base/FlatManifestWriterImpl.java.svn-base
new file mode 100644
index 0000000..5cc9be9
--- /dev/null
+++ b/isoparser/src/main/java/com/googlecode/mp4parser/authoring/adaptivestreaming/.svn/text-base/FlatManifestWriterImpl.java.svn-base
@@ -0,0 +1,643 @@
+/*
+ * Copyright 2012 Sebastian Annies, Hamburg
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.googlecode.mp4parser.authoring.adaptivestreaming;
+
+import com.coremedia.iso.Hex;
+import com.coremedia.iso.boxes.SampleDescriptionBox;
+import com.coremedia.iso.boxes.SoundMediaHeaderBox;
+import com.coremedia.iso.boxes.VideoMediaHeaderBox;
+import com.coremedia.iso.boxes.h264.AvcConfigurationBox;
+import com.coremedia.iso.boxes.sampleentry.AudioSampleEntry;
+import com.coremedia.iso.boxes.sampleentry.VisualSampleEntry;
+import com.googlecode.mp4parser.Version;
+import com.googlecode.mp4parser.authoring.Movie;
+import com.googlecode.mp4parser.authoring.Track;
+import com.googlecode.mp4parser.authoring.builder.FragmentIntersectionFinder;
+import com.googlecode.mp4parser.boxes.DTSSpecificBox;
+import com.googlecode.mp4parser.boxes.EC3SpecificBox;
+import com.googlecode.mp4parser.boxes.mp4.ESDescriptorBox;
+import com.googlecode.mp4parser.boxes.mp4.objectdescriptors.AudioSpecificConfig;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.transform.*;
+import javax.xml.transform.dom.DOMSource;
+import javax.xml.transform.stream.StreamResult;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.StringWriter;
+import java.nio.ByteBuffer;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.logging.Logger;
+
+public class FlatManifestWriterImpl extends AbstractManifestWriter {
+    private static final Logger LOG = Logger.getLogger(FlatManifestWriterImpl.class.getName());
+
+    protected FlatManifestWriterImpl(FragmentIntersectionFinder intersectionFinder) {
+        super(intersectionFinder);
+    }
+
+    /**
+     * Overwrite this method in subclasses to add your specialities.
+     *
+     * @param manifest the original manifest
+     * @return your customized version of the manifest
+     */
+    protected Document customizeManifest(Document manifest) {
+        return manifest;
+    }
+
+    public String getManifest(Movie movie) throws IOException {
+
+        LinkedList<VideoQuality> videoQualities = new LinkedList<VideoQuality>();
+        long videoTimescale = -1;
+
+        LinkedList<AudioQuality> audioQualities = new LinkedList<AudioQuality>();
+        long audioTimescale = -1;
+
+        for (Track track : movie.getTracks()) {
+            if (track.getMediaHeaderBox() instanceof VideoMediaHeaderBox) {
+                videoFragmentsDurations = checkFragmentsAlign(videoFragmentsDurations, calculateFragmentDurations(track, movie));
+                SampleDescriptionBox stsd = track.getSampleDescriptionBox();
+                videoQualities.add(getVideoQuality(track, (VisualSampleEntry) stsd.getSampleEntry()));
+                if (videoTimescale == -1) {
+                    videoTimescale = track.getTrackMetaData().getTimescale();
+                } else {
+                    assert videoTimescale == track.getTrackMetaData().getTimescale();
+                }
+            }
+            if (track.getMediaHeaderBox() instanceof SoundMediaHeaderBox) {
+                audioFragmentsDurations = checkFragmentsAlign(audioFragmentsDurations, calculateFragmentDurations(track, movie));
+                SampleDescriptionBox stsd = track.getSampleDescriptionBox();
+                audioQualities.add(getAudioQuality(track, (AudioSampleEntry) stsd.getSampleEntry()));
+                if (audioTimescale == -1) {
+                    audioTimescale = track.getTrackMetaData().getTimescale();
+                } else {
+                    assert audioTimescale == track.getTrackMetaData().getTimescale();
+                }
+
+            }
+        }
+        DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
+        DocumentBuilder documentBuilder;
+        try {
+            documentBuilder = documentBuilderFactory.newDocumentBuilder();
+        } catch (ParserConfigurationException e) {
+            throw new IOException(e);
+        }
+        Document document = documentBuilder.newDocument();
+
+
+        Element smoothStreamingMedia = document.createElement("SmoothStreamingMedia");
+        document.appendChild(smoothStreamingMedia);
+        smoothStreamingMedia.setAttribute("MajorVersion", "2");
+        smoothStreamingMedia.setAttribute("MinorVersion", "1");
+// silverlight ignores the timescale attr        smoothStreamingMedia.addAttribute(new Attribute("TimeScale", Long.toString(movieTimeScale)));
+        smoothStreamingMedia.setAttribute("Duration", "0");
+
+        smoothStreamingMedia.appendChild(document.createComment(Version.VERSION));
+        Element videoStreamIndex = document.createElement("StreamIndex");
+        videoStreamIndex.setAttribute("Type", "video");
+        videoStreamIndex.setAttribute("TimeScale", Long.toString(videoTimescale)); // silverlight ignores the timescale attr
+        videoStreamIndex.setAttribute("Chunks", Integer.toString(videoFragmentsDurations.length));
+        videoStreamIndex.setAttribute("Url", "video/{bitrate}/{start time}");
+        videoStreamIndex.setAttribute("QualityLevels", Integer.toString(videoQualities.size()));
+        smoothStreamingMedia.appendChild(videoStreamIndex);
+
+        for (int i = 0; i < videoQualities.size(); i++) {
+            VideoQuality vq = videoQualities.get(i);
+            Element qualityLevel = document.createElement("QualityLevel");
+            qualityLevel.setAttribute("Index", Integer.toString(i));
+            qualityLevel.setAttribute("Bitrate", Long.toString(vq.bitrate));
+            qualityLevel.setAttribute("FourCC", vq.fourCC);
+            qualityLevel.setAttribute("MaxWidth", Long.toString(vq.width));
+            qualityLevel.setAttribute("MaxHeight", Long.toString(vq.height));
+            qualityLevel.setAttribute("CodecPrivateData", vq.codecPrivateData);
+            qualityLevel.setAttribute("NALUnitLengthField", Integer.toString(vq.nalLength));
+            videoStreamIndex.appendChild(qualityLevel);
+        }
+
+        for (int i = 0; i < videoFragmentsDurations.length; i++) {
+            Element c = document.createElement("c");
+            c.setAttribute("n", Integer.toString(i));
+            c.setAttribute("d", Long.toString(videoFragmentsDurations[i]));
+            videoStreamIndex.appendChild(c);
+        }
+
+        if (audioFragmentsDurations != null) {
+            Element audioStreamIndex = document.createElement("StreamIndex");
+            audioStreamIndex.setAttribute("Type", "audio");
+            audioStreamIndex.setAttribute("TimeScale", Long.toString(audioTimescale)); // silverlight ignores the timescale attr
+            audioStreamIndex.setAttribute("Chunks", Integer.toString(audioFragmentsDurations.length));
+            audioStreamIndex.setAttribute("Url", "audio/{bitrate}/{start time}");
+            audioStreamIndex.setAttribute("QualityLevels", Integer.toString(audioQualities.size()));
+            smoothStreamingMedia.appendChild(audioStreamIndex);
+
+            for (int i = 0; i < audioQualities.size(); i++) {
+                AudioQuality aq = audioQualities.get(i);
+                Element qualityLevel = document.createElement("QualityLevel");
+                qualityLevel.setAttribute("Index", Integer.toString(i));
+                qualityLevel.setAttribute("FourCC", aq.fourCC);
+                qualityLevel.setAttribute("Bitrate", Long.toString(aq.bitrate));
+                qualityLevel.setAttribute("AudioTag", Integer.toString(aq.audioTag));
+                qualityLevel.setAttribute("SamplingRate", Long.toString(aq.samplingRate));
+                qualityLevel.setAttribute("Channels", Integer.toString(aq.channels));
+                qualityLevel.setAttribute("BitsPerSample", Integer.toString(aq.bitPerSample));
+                qualityLevel.setAttribute("PacketSize", Integer.toString(aq.packetSize));
+                qualityLevel.setAttribute("CodecPrivateData", aq.codecPrivateData);
+                audioStreamIndex.appendChild(qualityLevel);
+            }
+            for (int i = 0; i < audioFragmentsDurations.length; i++) {
+                Element c = document.createElement("c");
+                c.setAttribute("n", Integer.toString(i));
+                c.setAttribute("d", Long.toString(audioFragmentsDurations[i]));
+                audioStreamIndex.appendChild(c);
+            }
+        }
+
+        document.setXmlStandalone(true);
+        Source source = new DOMSource(document);
+        StringWriter stringWriter = new StringWriter();
+        Result result = new StreamResult(stringWriter);
+        TransformerFactory factory = TransformerFactory.newInstance();
+        Transformer transformer;
+        try {
+            transformer = factory.newTransformer();
+            transformer.setOutputProperty(OutputKeys.INDENT, "yes");
+            transformer.transform(source, result);
+        } catch (TransformerConfigurationException e) {
+            throw new IOException(e);
+        } catch (TransformerException e) {
+            throw new IOException(e);
+        }
+        return stringWriter.getBuffer().toString();
+
+
+    }
+
+    private AudioQuality getAudioQuality(Track track, AudioSampleEntry ase) {
+        if (getFormat(ase).equals("mp4a")) {
+            return getAacAudioQuality(track, ase);
+        } else if (getFormat(ase).equals("ec-3")) {
+            return getEc3AudioQuality(track, ase);
+        } else if (getFormat(ase).startsWith("dts")) {
+            return getDtsAudioQuality(track, ase);
+        } else {
+            throw new InternalError("I don't know what to do with audio of type " + getFormat(ase));
+        }
+
+    }
+
+    private AudioQuality getAacAudioQuality(Track track, AudioSampleEntry ase) {
+        AudioQuality l = new AudioQuality();
+        final ESDescriptorBox esDescriptorBox = ase.getBoxes(ESDescriptorBox.class).get(0);
+        final AudioSpecificConfig audioSpecificConfig = esDescriptorBox.getEsDescriptor().getDecoderConfigDescriptor().getAudioSpecificInfo();
+        if (audioSpecificConfig.getSbrPresentFlag() == 1) {
+            l.fourCC = "AACH";
+        } else if (audioSpecificConfig.getPsPresentFlag() == 1) {
+            l.fourCC = "AACP"; //I'm not sure if that's what MS considers as AAC+ - because actually AAC+ and AAC-HE should be the same...
+        } else {
+            l.fourCC = "AACL";
+        }
+        l.bitrate = getBitrate(track);
+        l.audioTag = 255;
+        l.samplingRate = ase.getSampleRate();
+        l.channels = ase.getChannelCount();
+        l.bitPerSample = ase.getSampleSize();
+        l.packetSize = 4;
+        l.codecPrivateData = getAudioCodecPrivateData(audioSpecificConfig);
+        //Index="0" Bitrate="103000" AudioTag="255" SamplingRate="44100" Channels="2" BitsPerSample="16" packetSize="4" CodecPrivateData=""
+        return l;
+    }
+
+    private AudioQuality getEc3AudioQuality(Track track, AudioSampleEntry ase) {
+        final EC3SpecificBox ec3SpecificBox = ase.getBoxes(EC3SpecificBox.class).get(0);
+        if (ec3SpecificBox == null) {
+            throw new RuntimeException("EC-3 track misses EC3SpecificBox!");
+        }
+
+        short nfchans = 0; //full bandwidth channels
+        short lfechans = 0;
+        byte dWChannelMaskFirstByte = 0;
+        byte dWChannelMaskSecondByte = 0;
+        for (EC3SpecificBox.Entry entry : ec3SpecificBox.getEntries()) {
+            /*
+            Table 4.3: Audio coding mode
+            acmod Audio coding mode Nfchans Channel array ordering
+            000 1 + 1 2 Ch1, Ch2
+            001 1/0 1 C
+            010 2/0 2 L, R
+            011 3/0 3 L, C, R
+            100 2/1 3 L, R, S
+            101 3/1 4 L, C, R, S
+            110 2/2 4 L, R, SL, SR
+            111 3/2 5 L, C, R, SL, SR
+
+            Table F.2: Chan_loc field bit assignments
+            Bit Location
+            0 Lc/Rc pair
+            1 Lrs/Rrs pair
+            2 Cs
+            3 Ts
+            4 Lsd/Rsd pair
+            5 Lw/Rw pair
+            6 Lvh/Rvh pair
+            7 Cvh
+            8 LFE2
+            */
+            switch (entry.acmod) {
+                case 0: //1+1; Ch1, Ch2
+                    nfchans += 2;
+                    throw new RuntimeException("Smooth Streaming doesn't support DDP 1+1 mode");
+                case 1: //1/0; C
+                    nfchans += 1;
+                    if (entry.num_dep_sub > 0) {
+                        DependentSubstreamMask dependentSubstreamMask = new DependentSubstreamMask(dWChannelMaskFirstByte, dWChannelMaskSecondByte, entry).process();
+                        dWChannelMaskFirstByte |= dependentSubstreamMask.getdWChannelMaskFirstByte();
+                        dWChannelMaskSecondByte |= dependentSubstreamMask.getdWChannelMaskSecondByte();
+                    } else {
+                        dWChannelMaskFirstByte |= 0x20;
+                    }
+                    break;
+                case 2: //2/0; L, R
+                    nfchans += 2;
+                    if (entry.num_dep_sub > 0) {
+                        DependentSubstreamMask dependentSubstreamMask = new DependentSubstreamMask(dWChannelMaskFirstByte, dWChannelMaskSecondByte, entry).process();
+                        dWChannelMaskFirstByte |= dependentSubstreamMask.getdWChannelMaskFirstByte();
+                        dWChannelMaskSecondByte |= dependentSubstreamMask.getdWChannelMaskSecondByte();
+                    } else {
+                        dWChannelMaskFirstByte |= 0xC0;
+                    }
+                    break;
+                case 3: //3/0; L, C, R
+                    nfchans += 3;
+                    if (entry.num_dep_sub > 0) {
+                        DependentSubstreamMask dependentSubstreamMask = new DependentSubstreamMask(dWChannelMaskFirstByte, dWChannelMaskSecondByte, entry).process();
+                        dWChannelMaskFirstByte |= dependentSubstreamMask.getdWChannelMaskFirstByte();
+                        dWChannelMaskSecondByte |= dependentSubstreamMask.getdWChannelMaskSecondByte();
+                    } else {
+                        dWChannelMaskFirstByte |= 0xE0;
+                    }
+                    break;
+                case 4: //2/1; L, R, S
+                    nfchans += 3;
+                    if (entry.num_dep_sub > 0) {
+                        DependentSubstreamMask dependentSubstreamMask = new DependentSubstreamMask(dWChannelMaskFirstByte, dWChannelMaskSecondByte, entry).process();
+                        dWChannelMaskFirstByte |= dependentSubstreamMask.getdWChannelMaskFirstByte();
+                        dWChannelMaskSecondByte |= dependentSubstreamMask.getdWChannelMaskSecondByte();
+                    } else {
+                        dWChannelMaskFirstByte |= 0xC0;
+                        dWChannelMaskSecondByte |= 0x80;
+                    }
+                    break;
+                case 5: //3/1; L, C, R, S
+                    nfchans += 4;
+                    if (entry.num_dep_sub > 0) {
+                        DependentSubstreamMask dependentSubstreamMask = new DependentSubstreamMask(dWChannelMaskFirstByte, dWChannelMaskSecondByte, entry).process();
+                        dWChannelMaskFirstByte |= dependentSubstreamMask.getdWChannelMaskFirstByte();
+                        dWChannelMaskSecondByte |= dependentSubstreamMask.getdWChannelMaskSecondByte();
+                    } else {
+                        dWChannelMaskFirstByte |= 0xE0;
+                        dWChannelMaskSecondByte |= 0x80;
+                    }
+                    break;
+                case 6: //2/2; L, R, SL, SR
+                    nfchans += 4;
+                    if (entry.num_dep_sub > 0) {
+                        DependentSubstreamMask dependentSubstreamMask = new DependentSubstreamMask(dWChannelMaskFirstByte, dWChannelMaskSecondByte, entry).process();
+                        dWChannelMaskFirstByte |= dependentSubstreamMask.getdWChannelMaskFirstByte();
+                        dWChannelMaskSecondByte |= dependentSubstreamMask.getdWChannelMaskSecondByte();
+                    } else {
+                        dWChannelMaskFirstByte |= 0xCC;
+                    }
+                    break;
+                case 7: //3/2; L, C, R, SL, SR
+                    nfchans += 5;
+                    if (entry.num_dep_sub > 0) {
+                        DependentSubstreamMask dependentSubstreamMask = new DependentSubstreamMask(dWChannelMaskFirstByte, dWChannelMaskSecondByte, entry).process();
+                        dWChannelMaskFirstByte |= dependentSubstreamMask.getdWChannelMaskFirstByte();
+                        dWChannelMaskSecondByte |= dependentSubstreamMask.getdWChannelMaskSecondByte();
+                    } else {
+                        dWChannelMaskFirstByte |= 0xEC;
+                    }
+                    break;
+            }
+            if (entry.lfeon == 1) {
+                lfechans ++;
+                dWChannelMaskFirstByte |= 0x10;
+            }
+        }
+
+        final ByteBuffer waveformatex = ByteBuffer.allocate(22);
+        waveformatex.put(new byte[]{0x00, 0x06}); //1536 wSamplesPerBlock - little endian
+        waveformatex.put(dWChannelMaskFirstByte);
+        waveformatex.put(dWChannelMaskSecondByte);
+        waveformatex.put(new byte[]{0x00, 0x00}); //pad dwChannelMask to 32bit
+        waveformatex.put(new byte[]{(byte)0xAF, (byte)0x87, (byte)0xFB, (byte)0xA7, 0x02, 0x2D, (byte)0xFB, 0x42, (byte)0xA4, (byte)0xD4, 0x05, (byte)0xCD, (byte)0x93, (byte)0x84, 0x3B, (byte)0xDD}); //SubFormat - Dolby Digital Plus GUID
+
+        final ByteBuffer dec3Content = ByteBuffer.allocate((int) ec3SpecificBox.getContentSize());
+        ec3SpecificBox.getContent(dec3Content);
+
+        AudioQuality l = new AudioQuality();
+        l.fourCC = "EC-3";
+        l.bitrate = getBitrate(track);
+        l.audioTag = 65534;
+        l.samplingRate = ase.getSampleRate();
+        l.channels = nfchans + lfechans;
+        l.bitPerSample = 16;
+        l.packetSize = track.getSamples().get(0).limit(); //assuming all are same size
+        l.codecPrivateData = Hex.encodeHex(waveformatex.array()) + Hex.encodeHex(dec3Content.array()); //append EC3SpecificBox (big endian) at the end of waveformatex
+        return l;
+    }
+
+    private AudioQuality getDtsAudioQuality(Track track, AudioSampleEntry ase) {
+        final DTSSpecificBox dtsSpecificBox = ase.getBoxes(DTSSpecificBox.class).get(0);
+        if (dtsSpecificBox == null) {
+            throw new RuntimeException("DTS track misses DTSSpecificBox!");
+        }
+
+        final ByteBuffer waveformatex = ByteBuffer.allocate(22);
+        final int frameDuration = dtsSpecificBox.getFrameDuration();
+        short samplesPerBlock = 0;
+        switch (frameDuration) {
+            case 0:
+                samplesPerBlock = 512;
+                break;
+            case 1:
+                samplesPerBlock = 1024;
+                break;
+            case 2:
+                samplesPerBlock = 2048;
+                break;
+            case 3:
+                samplesPerBlock = 4096;
+                break;
+        }
+        waveformatex.put((byte) (samplesPerBlock & 0xff));
+        waveformatex.put((byte) (samplesPerBlock >>> 8));
+        final int dwChannelMask = getNumChannelsAndMask(dtsSpecificBox)[1];
+        waveformatex.put((byte) (dwChannelMask & 0xff));
+        waveformatex.put((byte) (dwChannelMask >>> 8));
+        waveformatex.put((byte) (dwChannelMask >>> 16));
+        waveformatex.put((byte) (dwChannelMask >>> 24));
+        waveformatex.put(new byte[]{(byte)0xAE, (byte)0xE4, (byte)0xBF, (byte)0x5E, (byte)0x61, (byte)0x5E, (byte)0x41, (byte)0x87, (byte)0x92, (byte)0xFC, (byte)0xA4, (byte)0x81, (byte)0x26, (byte)0x99, (byte)0x02, (byte)0x11}); //DTS-HD GUID
+
+        final ByteBuffer dtsCodecPrivateData = ByteBuffer.allocate(8);
+        dtsCodecPrivateData.put((byte) dtsSpecificBox.getStreamConstruction());
+
+        final int channelLayout = dtsSpecificBox.getChannelLayout();
+        dtsCodecPrivateData.put((byte) (channelLayout & 0xff));
+        dtsCodecPrivateData.put((byte) (channelLayout >>> 8));
+        dtsCodecPrivateData.put((byte) (channelLayout >>> 16));
+        dtsCodecPrivateData.put((byte) (channelLayout >>> 24));
+
+        byte dtsFlags = (byte) (dtsSpecificBox.getMultiAssetFlag() << 1);
+        dtsFlags |= dtsSpecificBox.getLBRDurationMod();
+        dtsCodecPrivateData.put(dtsFlags);
+        dtsCodecPrivateData.put(new byte[]{0x00, 0x00}); //reserved
+
+        AudioQuality l = new AudioQuality();
+        l.fourCC = getFormat(ase);
+        l.bitrate = dtsSpecificBox.getAvgBitRate();
+        l.audioTag = 65534;
+        l.samplingRate = dtsSpecificBox.getDTSSamplingFrequency();
+        l.channels = getNumChannelsAndMask(dtsSpecificBox)[0];
+        l.bitPerSample = 16;
+        l.packetSize = track.getSamples().get(0).limit(); //assuming all are same size
+        l.codecPrivateData = Hex.encodeHex(waveformatex.array()) + Hex.encodeHex(dtsCodecPrivateData.array());
+        return l;
+
+    }
+
+    /* dwChannelMask
+    L SPEAKER_FRONT_LEFT 0x00000001
+    R SPEAKER_FRONT_RIGHT 0x00000002
+    C SPEAKER_FRONT_CENTER 0x00000004
+    LFE1 SPEAKER_LOW_FREQUENCY 0x00000008
+    Ls or Lsr* SPEAKER_BACK_LEFT 0x00000010
+    Rs or Rsr* SPEAKER_BACK_RIGHT 0x00000020
+    Lc SPEAKER_FRONT_LEFT_OF_CENTER 0x00000040
+    Rc SPEAKER_FRONT_RIGHT_OF_CENTER 0x00000080
+    Cs SPEAKER_BACK_CENTER 0x00000100
+    Lss SPEAKER_SIDE_LEFT 0x00000200
+    Rss SPEAKER_SIDE_RIGHT 0x00000400
+    Oh SPEAKER_TOP_CENTER 0x00000800
+    Lh SPEAKER_TOP_FRONT_LEFT 0x00001000
+    Ch SPEAKER_TOP_FRONT_CENTER 0x00002000
+    Rh SPEAKER_TOP_FRONT_RIGHT 0x00004000
+    Lhr SPEAKER_TOP_BACK_LEFT 0x00008000
+    Chf SPEAKER_TOP_BACK_CENTER 0x00010000
+    Rhr SPEAKER_TOP_BACK_RIGHT 0x00020000
+    SPEAKER_RESERVED 0x80000000
+
+    * if Lss, Rss exist, then this position is equivalent to Lsr, Rsr respectively
+     */
+    private int[] getNumChannelsAndMask(DTSSpecificBox dtsSpecificBox) {
+        final int channelLayout = dtsSpecificBox.getChannelLayout();
+        int numChannels = 0;
+        int dwChannelMask = 0;
+        if ((channelLayout & 0x0001) == 0x0001) {
+            //0001h Center in front of listener 1
+            numChannels += 1;
+            dwChannelMask |= 0x00000004; //SPEAKER_FRONT_CENTER
+        }
+        if ((channelLayout & 0x0002) == 0x0002) {
+            //0002h Left/Right in front 2
+            numChannels += 2;
+            dwChannelMask |= 0x00000001; //SPEAKER_FRONT_LEFT
+            dwChannelMask |= 0x00000002; //SPEAKER_FRONT_RIGHT
+        }
+        if ((channelLayout & 0x0004) == 0x0004) {
+            //0004h Left/Right surround on side in rear 2
+            numChannels += 2;
+            //* if Lss, Rss exist, then this position is equivalent to Lsr, Rsr respectively
+            dwChannelMask |= 0x00000010; //SPEAKER_BACK_LEFT
+            dwChannelMask |= 0x00000020; //SPEAKER_BACK_RIGHT
+        }
+        if ((channelLayout & 0x0008) == 0x0008) {
+            //0008h Low frequency effects subwoofer 1
+            numChannels += 1;
+            dwChannelMask |= 0x00000008; //SPEAKER_LOW_FREQUENCY
+        }
+        if ((channelLayout & 0x0010) == 0x0010) {
+            //0010h Center surround in rear 1
+            numChannels += 1;
+            dwChannelMask |= 0x00000100; //SPEAKER_BACK_CENTER
+        }
+        if ((channelLayout & 0x0020) == 0x0020) {
+            //0020h Left/Right height in front 2
+            numChannels += 2;
+            dwChannelMask |= 0x00001000; //SPEAKER_TOP_FRONT_LEFT
+            dwChannelMask |= 0x00004000; //SPEAKER_TOP_FRONT_RIGHT
+        }
+        if ((channelLayout & 0x0040) == 0x0040) {
+            //0040h Left/Right surround in rear 2
+            numChannels += 2;
+            dwChannelMask |= 0x00000010; //SPEAKER_BACK_LEFT
+            dwChannelMask |= 0x00000020; //SPEAKER_BACK_RIGHT
+        }
+        if ((channelLayout & 0x0080) == 0x0080) {
+            //0080h Center Height in front 1
+            numChannels += 1;
+            dwChannelMask |= 0x00002000; //SPEAKER_TOP_FRONT_CENTER
+        }
+        if ((channelLayout & 0x0100) == 0x0100) {
+            //0100h Over the listener’s head 1
+            numChannels += 1;
+            dwChannelMask |= 0x00000800; //SPEAKER_TOP_CENTER
+        }
+        if ((channelLayout & 0x0200) == 0x0200) {
+            //0200h Between left/right and center in front 2
+            numChannels += 2;
+            dwChannelMask |= 0x00000040; //SPEAKER_FRONT_LEFT_OF_CENTER
+            dwChannelMask |= 0x00000080; //SPEAKER_FRONT_RIGHT_OF_CENTER
+        }
+        if ((channelLayout & 0x0400) == 0x0400) {
+            //0400h Left/Right on side in front 2
+            numChannels += 2;
+            dwChannelMask |= 0x00000200; //SPEAKER_SIDE_LEFT
+            dwChannelMask |= 0x00000400; //SPEAKER_SIDE_RIGHT
+        }
+        if ((channelLayout & 0x0800) == 0x0800) {
+            //0800h Left/Right surround on side 2
+            numChannels += 2;
+            //* if Lss, Rss exist, then this position is equivalent to Lsr, Rsr respectively
+            dwChannelMask |= 0x00000010; //SPEAKER_BACK_LEFT
+            dwChannelMask |= 0x00000020; //SPEAKER_BACK_RIGHT
+        }
+        if ((channelLayout & 0x1000) == 0x1000) {
+            //1000h Second low frequency effects subwoofer 1
+            numChannels += 1;
+            dwChannelMask |= 0x00000008; //SPEAKER_LOW_FREQUENCY
+        }
+        if ((channelLayout & 0x2000) == 0x2000) {
+            //2000h Left/Right height on side 2
+            numChannels += 2;
+            dwChannelMask |= 0x00000010; //SPEAKER_BACK_LEFT
+            dwChannelMask |= 0x00000020; //SPEAKER_BACK_RIGHT
+        }
+        if ((channelLayout & 0x4000) == 0x4000) {
+            //4000h Center height in rear 1
+            numChannels += 1;
+            dwChannelMask |= 0x00010000; //SPEAKER_TOP_BACK_CENTER
+        }
+        if ((channelLayout & 0x8000) == 0x8000) {
+            //8000h Left/Right height in rear 2
+            numChannels += 2;
+            dwChannelMask |= 0x00008000; //SPEAKER_TOP_BACK_LEFT
+            dwChannelMask |= 0x00020000; //SPEAKER_TOP_BACK_RIGHT
+        }
+        if ((channelLayout & 0x10000) == 0x10000) {
+            //10000h Center below in front
+            numChannels += 1;
+        }
+        if ((channelLayout & 0x20000) == 0x20000) {
+            //20000h Left/Right below in front
+            numChannels += 2;
+        }
+        return new int[]{numChannels, dwChannelMask};
+    }
+
+    private String getAudioCodecPrivateData(AudioSpecificConfig audioSpecificConfig) {
+        byte[] configByteArray = audioSpecificConfig.getConfigBytes();
+        return Hex.encodeHex(configByteArray);
+    }
+
+    private VideoQuality getVideoQuality(Track track, VisualSampleEntry vse) {
+        VideoQuality l;
+        if ("avc1".equals(getFormat(vse))) {
+            AvcConfigurationBox avcConfigurationBox = vse.getBoxes(AvcConfigurationBox.class).get(0);
+            l = new VideoQuality();
+            l.bitrate = getBitrate(track);
+            l.codecPrivateData = Hex.encodeHex(getAvcCodecPrivateData(avcConfigurationBox));
+            l.fourCC = "AVC1";
+            l.width = vse.getWidth();
+            l.height = vse.getHeight();
+            l.nalLength = avcConfigurationBox.getLengthSizeMinusOne() + 1;
+        } else {
+            throw new InternalError("I don't know how to handle video of type " + getFormat(vse));
+        }
+        return l;
+    }
+
+    private byte[] getAvcCodecPrivateData(AvcConfigurationBox avcConfigurationBox) {
+        List<byte[]> sps = avcConfigurationBox.getSequenceParameterSets();
+        List<byte[]> pps = avcConfigurationBox.getPictureParameterSets();
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        try {
+            baos.write(new byte[]{0, 0, 0, 1});
+
+            for (byte[] sp : sps) {
+                baos.write(sp);
+            }
+            baos.write(new byte[]{0, 0, 0, 1});
+            for (byte[] pp : pps) {
+                baos.write(pp);
+            }
+        } catch (IOException ex) {
+            throw new RuntimeException("ByteArrayOutputStream do not throw IOException ?!?!?");
+        }
+        return baos.toByteArray();
+    }
+
+    private class DependentSubstreamMask {
+        private byte dWChannelMaskFirstByte;
+        private byte dWChannelMaskSecondByte;
+        private EC3SpecificBox.Entry entry;
+
+        public DependentSubstreamMask(byte dWChannelMaskFirstByte, byte dWChannelMaskSecondByte, EC3SpecificBox.Entry entry) {
+            this.dWChannelMaskFirstByte = dWChannelMaskFirstByte;
+            this.dWChannelMaskSecondByte = dWChannelMaskSecondByte;
+            this.entry = entry;
+        }
+
+        public byte getdWChannelMaskFirstByte() {
+            return dWChannelMaskFirstByte;
+        }
+
+        public byte getdWChannelMaskSecondByte() {
+            return dWChannelMaskSecondByte;
+        }
+
+        public DependentSubstreamMask process() {
+            switch (entry.chan_loc) {
+                case 0:
+                    dWChannelMaskFirstByte |= 0x3;
+                    break;
+                case 1:
+                    dWChannelMaskFirstByte |= 0xC;
+                    break;
+                case 2:
+                    dWChannelMaskSecondByte |= 0x80;
+                    break;
+                case 3:
+                    dWChannelMaskSecondByte |= 0x8;
+                    break;
+                case 6:
+                    dWChannelMaskSecondByte |= 0x5;
+                    break;
+                case 7:
+                    dWChannelMaskSecondByte |= 0x2;
+                    break;
+            }
+            return this;
+        }
+    }
+}
diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/authoring/adaptivestreaming/.svn/text-base/FlatPackageWriterImpl.java.svn-base b/isoparser/src/main/java/com/googlecode/mp4parser/authoring/adaptivestreaming/.svn/text-base/FlatPackageWriterImpl.java.svn-base
new file mode 100644
index 0000000..3e3847c
--- /dev/null
+++ b/isoparser/src/main/java/com/googlecode/mp4parser/authoring/adaptivestreaming/.svn/text-base/FlatPackageWriterImpl.java.svn-base
@@ -0,0 +1,197 @@
+/*
+ * Copyright 2012 Sebastian Annies, Hamburg
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.googlecode.mp4parser.authoring.adaptivestreaming;
+
+import com.coremedia.iso.IsoFile;
+import com.coremedia.iso.boxes.Box;
+import com.coremedia.iso.boxes.SoundMediaHeaderBox;
+import com.coremedia.iso.boxes.VideoMediaHeaderBox;
+import com.coremedia.iso.boxes.fragment.MovieFragmentBox;
+import com.googlecode.mp4parser.authoring.Movie;
+import com.googlecode.mp4parser.authoring.Track;
+import com.googlecode.mp4parser.authoring.builder.*;
+import com.googlecode.mp4parser.authoring.tracks.ChangeTimeScaleTrack;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.nio.channels.FileChannel;
+import java.util.Iterator;
+import java.util.logging.Logger;
+
+public class FlatPackageWriterImpl implements PackageWriter {
+    private static Logger LOG = Logger.getLogger(FlatPackageWriterImpl.class.getName());
+    long timeScale = 10000000;
+
+    private File outputDirectory;
+    private boolean debugOutput;
+    private FragmentedMp4Builder ismvBuilder;
+    ManifestWriter manifestWriter;
+
+    public FlatPackageWriterImpl() {
+        ismvBuilder = new FragmentedMp4Builder();
+        FragmentIntersectionFinder intersectionFinder = new SyncSampleIntersectFinderImpl();
+        ismvBuilder.setIntersectionFinder(intersectionFinder);
+        manifestWriter = new FlatManifestWriterImpl(intersectionFinder);
+    }
+
+    /**
+     * Creates a factory for a smooth streaming package. A smooth streaming package is
+     * a collection of files that can be served by a webserver as a smooth streaming
+     * stream.
+     * @param minFragmentDuration the smallest allowable duration of a fragment (0 == no restriction).
+     */
+    public FlatPackageWriterImpl(int minFragmentDuration) {
+        ismvBuilder = new FragmentedMp4Builder();
+        FragmentIntersectionFinder intersectionFinder = new SyncSampleIntersectFinderImpl(minFragmentDuration);
+        ismvBuilder.setIntersectionFinder(intersectionFinder);
+        manifestWriter = new FlatManifestWriterImpl(intersectionFinder);
+    }
+
+    public void setOutputDirectory(File outputDirectory) {
+        assert outputDirectory.isDirectory();
+        this.outputDirectory = outputDirectory;
+
+    }
+
+    public void setDebugOutput(boolean debugOutput) {
+        this.debugOutput = debugOutput;
+    }
+
+    public void setIsmvBuilder(FragmentedMp4Builder ismvBuilder) {
+        this.ismvBuilder = ismvBuilder;
+        this.manifestWriter = new FlatManifestWriterImpl(ismvBuilder.getFragmentIntersectionFinder());
+    }
+
+    public void setManifestWriter(ManifestWriter manifestWriter) {
+        this.manifestWriter = manifestWriter;
+    }
+
+    /**
+     * Writes the movie given as <code>qualities</code> flattened into the
+     * <code>outputDirectory</code>.
+     *
+     * @param source the source movie with all qualities
+     * @throws IOException
+     */
+    public void write(Movie source) throws IOException {
+
+        if (debugOutput) {
+            outputDirectory.mkdirs();
+            DefaultMp4Builder defaultMp4Builder = new DefaultMp4Builder();
+            IsoFile muxed = defaultMp4Builder.build(source);
+            File muxedFile = new File(outputDirectory, "debug_1_muxed.mp4");
+            FileOutputStream muxedFileOutputStream = new FileOutputStream(muxedFile);
+            muxed.getBox(muxedFileOutputStream.getChannel());
+            muxedFileOutputStream.close();
+        }
+        Movie cleanedSource = removeUnknownTracks(source);
+        Movie movieWithAdjustedTimescale = correctTimescale(cleanedSource);
+
+        if (debugOutput) {
+            DefaultMp4Builder defaultMp4Builder = new DefaultMp4Builder();
+            IsoFile muxed = defaultMp4Builder.build(movieWithAdjustedTimescale);
+            File muxedFile = new File(outputDirectory, "debug_2_timescale.mp4");
+            FileOutputStream muxedFileOutputStream = new FileOutputStream(muxedFile);
+            muxed.getBox(muxedFileOutputStream.getChannel());
+            muxedFileOutputStream.close();
+        }
+        IsoFile isoFile = ismvBuilder.build(movieWithAdjustedTimescale);
+        if (debugOutput) {
+            File allQualities = new File(outputDirectory, "debug_3_fragmented.mp4");
+            FileOutputStream allQualis = new FileOutputStream(allQualities);
+            isoFile.getBox(allQualis.getChannel());
+            allQualis.close();
+        }
+
+
+        for (Track track : movieWithAdjustedTimescale.getTracks()) {
+            String bitrate = Long.toString(manifestWriter.getBitrate(track));
+            long trackId = track.getTrackMetaData().getTrackId();
+            Iterator<Box> boxIt = isoFile.getBoxes().iterator();
+            File mediaOutDir;
+            if (track.getMediaHeaderBox() instanceof SoundMediaHeaderBox) {
+                mediaOutDir = new File(outputDirectory, "audio");
+
+            } else if (track.getMediaHeaderBox() instanceof VideoMediaHeaderBox) {
+                mediaOutDir = new File(outputDirectory, "video");
+            } else {
+                System.err.println("Skipping Track with handler " + track.getHandler() + " and " + track.getMediaHeaderBox().getClass().getSimpleName());
+                continue;
+            }
+            File bitRateOutputDir = new File(mediaOutDir, bitrate);
+            bitRateOutputDir.mkdirs();
+            LOG.finer("Created : " + bitRateOutputDir.getCanonicalPath());
+
+            long[] fragmentTimes = manifestWriter.calculateFragmentDurations(track, movieWithAdjustedTimescale);
+            long startTime = 0;
+            int currentFragment = 0;
+            while (boxIt.hasNext()) {
+                Box b = boxIt.next();
+                if (b instanceof MovieFragmentBox) {
+                    assert ((MovieFragmentBox) b).getTrackCount() == 1;
+                    if (((MovieFragmentBox) b).getTrackNumbers()[0] == trackId) {
+                        FileOutputStream fos = new FileOutputStream(new File(bitRateOutputDir, Long.toString(startTime)));
+                        startTime += fragmentTimes[currentFragment++];
+                        FileChannel fc = fos.getChannel();
+                        Box mdat = boxIt.next();
+                        assert mdat.getType().equals("mdat");
+                        b.getBox(fc); // moof
+                        mdat.getBox(fc); // mdat
+                        fc.truncate(fc.position());
+                        fc.close();
+                    }
+                }
+
+            }
+        }
+        FileWriter fw = new FileWriter(new File(outputDirectory, "Manifest"));
+        fw.write(manifestWriter.getManifest(movieWithAdjustedTimescale));
+        fw.close();
+
+    }
+
+    private Movie removeUnknownTracks(Movie source) {
+        Movie nuMovie = new Movie();
+        for (Track track : source.getTracks()) {
+            if ("vide".equals(track.getHandler()) || "soun".equals(track.getHandler())) {
+                nuMovie.addTrack(track);
+            } else {
+                LOG.fine("Removed track " + track);
+            }
+        }
+        return nuMovie;
+    }
+
+
+    /**
+     * Returns a new <code>Movie</code> in that all tracks have the timescale 10000000. CTS & DTS are modified
+     * in a way that even with more than one framerate the fragments exactly begin at the same time.
+     *
+     * @param movie
+     * @return a movie with timescales suitable for smooth streaming manifests
+     */
+    public Movie correctTimescale(Movie movie) {
+        Movie nuMovie = new Movie();
+        for (Track track : movie.getTracks()) {
+            nuMovie.addTrack(new ChangeTimeScaleTrack(track, timeScale, ismvBuilder.getFragmentIntersectionFinder().sampleNumbers(track, movie)));
+        }
+        return nuMovie;
+
+    }
+
+}
diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/authoring/adaptivestreaming/.svn/text-base/ManifestWriter.java.svn-base b/isoparser/src/main/java/com/googlecode/mp4parser/authoring/adaptivestreaming/.svn/text-base/ManifestWriter.java.svn-base
new file mode 100644
index 0000000..2b2ba7d
--- /dev/null
+++ b/isoparser/src/main/java/com/googlecode/mp4parser/authoring/adaptivestreaming/.svn/text-base/ManifestWriter.java.svn-base
@@ -0,0 +1,31 @@
+/*
+ * Copyright 2012 Sebastian Annies, Hamburg
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.googlecode.mp4parser.authoring.adaptivestreaming;
+
+
+import com.googlecode.mp4parser.authoring.Movie;
+import com.googlecode.mp4parser.authoring.Track;
+
+import java.io.IOException;
+
+public interface ManifestWriter {
+    String getManifest(Movie inputs) throws IOException;
+
+    long getBitrate(Track track);
+
+    long[] calculateFragmentDurations(Track track, Movie movie);
+
+}
diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/authoring/adaptivestreaming/.svn/text-base/PackageWriter.java.svn-base b/isoparser/src/main/java/com/googlecode/mp4parser/authoring/adaptivestreaming/.svn/text-base/PackageWriter.java.svn-base
new file mode 100644
index 0000000..0d97fc5
--- /dev/null
+++ b/isoparser/src/main/java/com/googlecode/mp4parser/authoring/adaptivestreaming/.svn/text-base/PackageWriter.java.svn-base
@@ -0,0 +1,27 @@
+/*
+ * Copyright 2012 Sebastian Annies, Hamburg
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.googlecode.mp4parser.authoring.adaptivestreaming;
+
+import com.googlecode.mp4parser.authoring.Movie;
+
+import java.io.IOException;
+
+/**
+ * Writes the whole package.
+ */
+public interface PackageWriter {
+    public void write(Movie qualities) throws IOException;
+}
diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/authoring/adaptivestreaming/.svn/text-base/VideoQuality.java.svn-base b/isoparser/src/main/java/com/googlecode/mp4parser/authoring/adaptivestreaming/.svn/text-base/VideoQuality.java.svn-base
new file mode 100644
index 0000000..4a70e47
--- /dev/null
+++ b/isoparser/src/main/java/com/googlecode/mp4parser/authoring/adaptivestreaming/.svn/text-base/VideoQuality.java.svn-base
@@ -0,0 +1,25 @@
+/*
+ * Copyright 2012 Sebastian Annies, Hamburg
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.googlecode.mp4parser.authoring.adaptivestreaming;
+
+class VideoQuality {
+    long bitrate;
+    String fourCC;
+    int width;
+    int height;
+    String codecPrivateData;
+    int nalLength;
+}
diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/authoring/adaptivestreaming/AbstractManifestWriter.java b/isoparser/src/main/java/com/googlecode/mp4parser/authoring/adaptivestreaming/AbstractManifestWriter.java
new file mode 100644
index 0000000..6ee4ffa
--- /dev/null
+++ b/isoparser/src/main/java/com/googlecode/mp4parser/authoring/adaptivestreaming/AbstractManifestWriter.java
@@ -0,0 +1,126 @@
+package com.googlecode.mp4parser.authoring.adaptivestreaming;

+

+import com.coremedia.iso.boxes.OriginalFormatBox;

+import com.coremedia.iso.boxes.TimeToSampleBox;

+import com.coremedia.iso.boxes.sampleentry.SampleEntry;

+import com.googlecode.mp4parser.authoring.Movie;

+import com.googlecode.mp4parser.authoring.Track;

+import com.googlecode.mp4parser.authoring.builder.FragmentIntersectionFinder;

+

+import java.io.IOException;

+import java.nio.ByteBuffer;

+import java.util.Arrays;

+import java.util.logging.Logger;

+

+import static com.googlecode.mp4parser.util.CastUtils.l2i;

+

+/**

+ * Created with IntelliJ IDEA.

+ * User: mstattma

+ * Date: 17.08.12

+ * Time: 02:51

+ * To change this template use File | Settings | File Templates.

+ */

+public abstract class AbstractManifestWriter implements ManifestWriter {

+    private static final Logger LOG = Logger.getLogger(AbstractManifestWriter.class.getName());

+

+    private FragmentIntersectionFinder intersectionFinder;

+    protected long[] audioFragmentsDurations;

+    protected long[] videoFragmentsDurations;

+

+    protected AbstractManifestWriter(FragmentIntersectionFinder intersectionFinder) {

+        this.intersectionFinder = intersectionFinder;

+    }

+

+    /**

+     * Calculates the length of each fragment in the given <code>track</code> (as part of <code>movie</code>).

+     *

+     * @param track target of calculation

+     * @param movie the <code>track</code> must be part of this <code>movie</code>

+     * @return the duration of each fragment in track timescale

+     */

+    public long[] calculateFragmentDurations(Track track, Movie movie) {

+        long[] startSamples = intersectionFinder.sampleNumbers(track, movie);

+        long[] durations = new long[startSamples.length];

+        int currentFragment = 0;

+        int currentSample = 1; // sync samples start with 1 !

+

+        for (TimeToSampleBox.Entry entry : track.getDecodingTimeEntries()) {

+            for (int max = currentSample + l2i(entry.getCount()); currentSample < max; currentSample++) {

+                // in this loop we go through the entry.getCount() samples starting from current sample.

+                // the next entry.getCount() samples have the same decoding time.

+                if (currentFragment != startSamples.length - 1 && currentSample == startSamples[currentFragment + 1]) {

+                    // we are not in the last fragment && the current sample is the start sample of the next fragment

+                    currentFragment++;

+                }

+                durations[currentFragment] += entry.getDelta();

+

+

+            }

+        }

+        return durations;

+

+    }

+

+    public long getBitrate(Track track) {

+        long bitrate = 0;

+        for (ByteBuffer sample : track.getSamples()) {

+            bitrate += sample.limit();

+        }

+        bitrate *= 8; // from bytes to bits

+        bitrate /= ((double) getDuration(track)) / track.getTrackMetaData().getTimescale(); // per second

+        return bitrate;

+    }

+

+    protected static long getDuration(Track track) {

+        long duration = 0;

+        for (TimeToSampleBox.Entry entry : track.getDecodingTimeEntries()) {

+            duration += entry.getCount() * entry.getDelta();

+        }

+        return duration;

+    }

+

+    protected long[] checkFragmentsAlign(long[] referenceTimes, long[] checkTimes) throws IOException {

+

+        if (referenceTimes == null || referenceTimes.length == 0) {

+            return checkTimes;

+        }

+        long[] referenceTimesMinusLast = new long[referenceTimes.length - 1];

+        System.arraycopy(referenceTimes, 0, referenceTimesMinusLast, 0, referenceTimes.length - 1);

+        long[] checkTimesMinusLast = new long[checkTimes.length - 1];

+        System.arraycopy(checkTimes, 0, checkTimesMinusLast, 0, checkTimes.length - 1);

+

+        if (!Arrays.equals(checkTimesMinusLast, referenceTimesMinusLast)) {

+            String log = "";

+            log += (referenceTimes.length);

+            log += ("Reference     :  [");

+            for (long l : referenceTimes) {

+                log += (String.format("%10d,", l));

+            }

+            log += ("]");

+            LOG.warning(log);

+            log = "";

+

+            log += (checkTimes.length);

+            log += ("Current       :  [");

+            for (long l : checkTimes) {

+                log += (String.format("%10d,", l));

+            }

+            log += ("]");

+            LOG.warning(log);

+            throw new IOException("Track does not have the same fragment borders as its predecessor.");

+

+        } else {

+            return checkTimes;

+        }

+    }

+

+    protected String getFormat(SampleEntry se) {

+        String type = se.getType();

+        if (type.equals("encv") || type.equals("enca") || type.equals("encv")) {

+            OriginalFormatBox frma = se.getBoxes(OriginalFormatBox.class, true).get(0);

+            type = frma.getDataFormat();

+        }

+        return type;

+    }

+}

diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/authoring/adaptivestreaming/AudioQuality.java b/isoparser/src/main/java/com/googlecode/mp4parser/authoring/adaptivestreaming/AudioQuality.java
new file mode 100644
index 0000000..39e115f
--- /dev/null
+++ b/isoparser/src/main/java/com/googlecode/mp4parser/authoring/adaptivestreaming/AudioQuality.java
@@ -0,0 +1,29 @@
+/*
+ * Copyright 2012 Sebastian Annies, Hamburg
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.googlecode.mp4parser.authoring.adaptivestreaming;
+
+
+public class AudioQuality {
+    String fourCC;
+    long bitrate;
+    int audioTag;
+    long samplingRate;
+    int channels;
+    int bitPerSample;
+    int packetSize;
+    String language;
+    String codecPrivateData;
+}
diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/authoring/adaptivestreaming/FlatManifestWriterImpl.java b/isoparser/src/main/java/com/googlecode/mp4parser/authoring/adaptivestreaming/FlatManifestWriterImpl.java
new file mode 100644
index 0000000..5cc9be9
--- /dev/null
+++ b/isoparser/src/main/java/com/googlecode/mp4parser/authoring/adaptivestreaming/FlatManifestWriterImpl.java
@@ -0,0 +1,643 @@
+/*
+ * Copyright 2012 Sebastian Annies, Hamburg
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.googlecode.mp4parser.authoring.adaptivestreaming;
+
+import com.coremedia.iso.Hex;
+import com.coremedia.iso.boxes.SampleDescriptionBox;
+import com.coremedia.iso.boxes.SoundMediaHeaderBox;
+import com.coremedia.iso.boxes.VideoMediaHeaderBox;
+import com.coremedia.iso.boxes.h264.AvcConfigurationBox;
+import com.coremedia.iso.boxes.sampleentry.AudioSampleEntry;
+import com.coremedia.iso.boxes.sampleentry.VisualSampleEntry;
+import com.googlecode.mp4parser.Version;
+import com.googlecode.mp4parser.authoring.Movie;
+import com.googlecode.mp4parser.authoring.Track;
+import com.googlecode.mp4parser.authoring.builder.FragmentIntersectionFinder;
+import com.googlecode.mp4parser.boxes.DTSSpecificBox;
+import com.googlecode.mp4parser.boxes.EC3SpecificBox;
+import com.googlecode.mp4parser.boxes.mp4.ESDescriptorBox;
+import com.googlecode.mp4parser.boxes.mp4.objectdescriptors.AudioSpecificConfig;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.transform.*;
+import javax.xml.transform.dom.DOMSource;
+import javax.xml.transform.stream.StreamResult;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.StringWriter;
+import java.nio.ByteBuffer;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.logging.Logger;
+
+public class FlatManifestWriterImpl extends AbstractManifestWriter {
+    private static final Logger LOG = Logger.getLogger(FlatManifestWriterImpl.class.getName());
+
+    protected FlatManifestWriterImpl(FragmentIntersectionFinder intersectionFinder) {
+        super(intersectionFinder);
+    }
+
+    /**
+     * Overwrite this method in subclasses to add your specialities.
+     *
+     * @param manifest the original manifest
+     * @return your customized version of the manifest
+     */
+    protected Document customizeManifest(Document manifest) {
+        return manifest;
+    }
+
+    public String getManifest(Movie movie) throws IOException {
+
+        LinkedList<VideoQuality> videoQualities = new LinkedList<VideoQuality>();
+        long videoTimescale = -1;
+
+        LinkedList<AudioQuality> audioQualities = new LinkedList<AudioQuality>();
+        long audioTimescale = -1;
+
+        for (Track track : movie.getTracks()) {
+            if (track.getMediaHeaderBox() instanceof VideoMediaHeaderBox) {
+                videoFragmentsDurations = checkFragmentsAlign(videoFragmentsDurations, calculateFragmentDurations(track, movie));
+                SampleDescriptionBox stsd = track.getSampleDescriptionBox();
+                videoQualities.add(getVideoQuality(track, (VisualSampleEntry) stsd.getSampleEntry()));
+                if (videoTimescale == -1) {
+                    videoTimescale = track.getTrackMetaData().getTimescale();
+                } else {
+                    assert videoTimescale == track.getTrackMetaData().getTimescale();
+                }
+            }
+            if (track.getMediaHeaderBox() instanceof SoundMediaHeaderBox) {
+                audioFragmentsDurations = checkFragmentsAlign(audioFragmentsDurations, calculateFragmentDurations(track, movie));
+                SampleDescriptionBox stsd = track.getSampleDescriptionBox();
+                audioQualities.add(getAudioQuality(track, (AudioSampleEntry) stsd.getSampleEntry()));
+                if (audioTimescale == -1) {
+                    audioTimescale = track.getTrackMetaData().getTimescale();
+                } else {
+                    assert audioTimescale == track.getTrackMetaData().getTimescale();
+                }
+
+            }
+        }
+        DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
+        DocumentBuilder documentBuilder;
+        try {
+            documentBuilder = documentBuilderFactory.newDocumentBuilder();
+        } catch (ParserConfigurationException e) {
+            throw new IOException(e);
+        }
+        Document document = documentBuilder.newDocument();
+
+
+        Element smoothStreamingMedia = document.createElement("SmoothStreamingMedia");
+        document.appendChild(smoothStreamingMedia);
+        smoothStreamingMedia.setAttribute("MajorVersion", "2");
+        smoothStreamingMedia.setAttribute("MinorVersion", "1");
+// silverlight ignores the timescale attr        smoothStreamingMedia.addAttribute(new Attribute("TimeScale", Long.toString(movieTimeScale)));
+        smoothStreamingMedia.setAttribute("Duration", "0");
+
+        smoothStreamingMedia.appendChild(document.createComment(Version.VERSION));
+        Element videoStreamIndex = document.createElement("StreamIndex");
+        videoStreamIndex.setAttribute("Type", "video");
+        videoStreamIndex.setAttribute("TimeScale", Long.toString(videoTimescale)); // silverlight ignores the timescale attr
+        videoStreamIndex.setAttribute("Chunks", Integer.toString(videoFragmentsDurations.length));
+        videoStreamIndex.setAttribute("Url", "video/{bitrate}/{start time}");
+        videoStreamIndex.setAttribute("QualityLevels", Integer.toString(videoQualities.size()));
+        smoothStreamingMedia.appendChild(videoStreamIndex);
+
+        for (int i = 0; i < videoQualities.size(); i++) {
+            VideoQuality vq = videoQualities.get(i);
+            Element qualityLevel = document.createElement("QualityLevel");
+            qualityLevel.setAttribute("Index", Integer.toString(i));
+            qualityLevel.setAttribute("Bitrate", Long.toString(vq.bitrate));
+            qualityLevel.setAttribute("FourCC", vq.fourCC);
+            qualityLevel.setAttribute("MaxWidth", Long.toString(vq.width));
+            qualityLevel.setAttribute("MaxHeight", Long.toString(vq.height));
+            qualityLevel.setAttribute("CodecPrivateData", vq.codecPrivateData);
+            qualityLevel.setAttribute("NALUnitLengthField", Integer.toString(vq.nalLength));
+            videoStreamIndex.appendChild(qualityLevel);
+        }
+
+        for (int i = 0; i < videoFragmentsDurations.length; i++) {
+            Element c = document.createElement("c");
+            c.setAttribute("n", Integer.toString(i));
+            c.setAttribute("d", Long.toString(videoFragmentsDurations[i]));
+            videoStreamIndex.appendChild(c);
+        }
+
+        if (audioFragmentsDurations != null) {
+            Element audioStreamIndex = document.createElement("StreamIndex");
+            audioStreamIndex.setAttribute("Type", "audio");
+            audioStreamIndex.setAttribute("TimeScale", Long.toString(audioTimescale)); // silverlight ignores the timescale attr
+            audioStreamIndex.setAttribute("Chunks", Integer.toString(audioFragmentsDurations.length));
+            audioStreamIndex.setAttribute("Url", "audio/{bitrate}/{start time}");
+            audioStreamIndex.setAttribute("QualityLevels", Integer.toString(audioQualities.size()));
+            smoothStreamingMedia.appendChild(audioStreamIndex);
+
+            for (int i = 0; i < audioQualities.size(); i++) {
+                AudioQuality aq = audioQualities.get(i);
+                Element qualityLevel = document.createElement("QualityLevel");
+                qualityLevel.setAttribute("Index", Integer.toString(i));
+                qualityLevel.setAttribute("FourCC", aq.fourCC);
+                qualityLevel.setAttribute("Bitrate", Long.toString(aq.bitrate));
+                qualityLevel.setAttribute("AudioTag", Integer.toString(aq.audioTag));
+                qualityLevel.setAttribute("SamplingRate", Long.toString(aq.samplingRate));
+                qualityLevel.setAttribute("Channels", Integer.toString(aq.channels));
+                qualityLevel.setAttribute("BitsPerSample", Integer.toString(aq.bitPerSample));
+                qualityLevel.setAttribute("PacketSize", Integer.toString(aq.packetSize));
+                qualityLevel.setAttribute("CodecPrivateData", aq.codecPrivateData);
+                audioStreamIndex.appendChild(qualityLevel);
+            }
+            for (int i = 0; i < audioFragmentsDurations.length; i++) {
+                Element c = document.createElement("c");
+                c.setAttribute("n", Integer.toString(i));
+                c.setAttribute("d", Long.toString(audioFragmentsDurations[i]));
+                audioStreamIndex.appendChild(c);
+            }
+        }
+
+        document.setXmlStandalone(true);
+        Source source = new DOMSource(document);
+        StringWriter stringWriter = new StringWriter();
+        Result result = new StreamResult(stringWriter);
+        TransformerFactory factory = TransformerFactory.newInstance();
+        Transformer transformer;
+        try {
+            transformer = factory.newTransformer();
+            transformer.setOutputProperty(OutputKeys.INDENT, "yes");
+            transformer.transform(source, result);
+        } catch (TransformerConfigurationException e) {
+            throw new IOException(e);
+        } catch (TransformerException e) {
+            throw new IOException(e);
+        }
+        return stringWriter.getBuffer().toString();
+
+
+    }
+
+    private AudioQuality getAudioQuality(Track track, AudioSampleEntry ase) {
+        if (getFormat(ase).equals("mp4a")) {
+            return getAacAudioQuality(track, ase);
+        } else if (getFormat(ase).equals("ec-3")) {
+            return getEc3AudioQuality(track, ase);
+        } else if (getFormat(ase).startsWith("dts")) {
+            return getDtsAudioQuality(track, ase);
+        } else {
+            throw new InternalError("I don't know what to do with audio of type " + getFormat(ase));
+        }
+
+    }
+
+    private AudioQuality getAacAudioQuality(Track track, AudioSampleEntry ase) {
+        AudioQuality l = new AudioQuality();
+        final ESDescriptorBox esDescriptorBox = ase.getBoxes(ESDescriptorBox.class).get(0);
+        final AudioSpecificConfig audioSpecificConfig = esDescriptorBox.getEsDescriptor().getDecoderConfigDescriptor().getAudioSpecificInfo();
+        if (audioSpecificConfig.getSbrPresentFlag() == 1) {
+            l.fourCC = "AACH";
+        } else if (audioSpecificConfig.getPsPresentFlag() == 1) {
+            l.fourCC = "AACP"; //I'm not sure if that's what MS considers as AAC+ - because actually AAC+ and AAC-HE should be the same...
+        } else {
+            l.fourCC = "AACL";
+        }
+        l.bitrate = getBitrate(track);
+        l.audioTag = 255;
+        l.samplingRate = ase.getSampleRate();
+        l.channels = ase.getChannelCount();
+        l.bitPerSample = ase.getSampleSize();
+        l.packetSize = 4;
+        l.codecPrivateData = getAudioCodecPrivateData(audioSpecificConfig);
+        //Index="0" Bitrate="103000" AudioTag="255" SamplingRate="44100" Channels="2" BitsPerSample="16" packetSize="4" CodecPrivateData=""
+        return l;
+    }
+
+    private AudioQuality getEc3AudioQuality(Track track, AudioSampleEntry ase) {
+        final EC3SpecificBox ec3SpecificBox = ase.getBoxes(EC3SpecificBox.class).get(0);
+        if (ec3SpecificBox == null) {
+            throw new RuntimeException("EC-3 track misses EC3SpecificBox!");
+        }
+
+        short nfchans = 0; //full bandwidth channels
+        short lfechans = 0;
+        byte dWChannelMaskFirstByte = 0;
+        byte dWChannelMaskSecondByte = 0;
+        for (EC3SpecificBox.Entry entry : ec3SpecificBox.getEntries()) {
+            /*
+            Table 4.3: Audio coding mode
+            acmod Audio coding mode Nfchans Channel array ordering
+            000 1 + 1 2 Ch1, Ch2
+            001 1/0 1 C
+            010 2/0 2 L, R
+            011 3/0 3 L, C, R
+            100 2/1 3 L, R, S
+            101 3/1 4 L, C, R, S
+            110 2/2 4 L, R, SL, SR
+            111 3/2 5 L, C, R, SL, SR
+
+            Table F.2: Chan_loc field bit assignments
+            Bit Location
+            0 Lc/Rc pair
+            1 Lrs/Rrs pair
+            2 Cs
+            3 Ts
+            4 Lsd/Rsd pair
+            5 Lw/Rw pair
+            6 Lvh/Rvh pair
+            7 Cvh
+            8 LFE2
+            */
+            switch (entry.acmod) {
+                case 0: //1+1; Ch1, Ch2
+                    nfchans += 2;
+                    throw new RuntimeException("Smooth Streaming doesn't support DDP 1+1 mode");
+                case 1: //1/0; C
+                    nfchans += 1;
+                    if (entry.num_dep_sub > 0) {
+                        DependentSubstreamMask dependentSubstreamMask = new DependentSubstreamMask(dWChannelMaskFirstByte, dWChannelMaskSecondByte, entry).process();
+                        dWChannelMaskFirstByte |= dependentSubstreamMask.getdWChannelMaskFirstByte();
+                        dWChannelMaskSecondByte |= dependentSubstreamMask.getdWChannelMaskSecondByte();
+                    } else {
+                        dWChannelMaskFirstByte |= 0x20;
+                    }
+                    break;
+                case 2: //2/0; L, R
+                    nfchans += 2;
+                    if (entry.num_dep_sub > 0) {
+                        DependentSubstreamMask dependentSubstreamMask = new DependentSubstreamMask(dWChannelMaskFirstByte, dWChannelMaskSecondByte, entry).process();
+                        dWChannelMaskFirstByte |= dependentSubstreamMask.getdWChannelMaskFirstByte();
+                        dWChannelMaskSecondByte |= dependentSubstreamMask.getdWChannelMaskSecondByte();
+                    } else {
+                        dWChannelMaskFirstByte |= 0xC0;
+                    }
+                    break;
+                case 3: //3/0; L, C, R
+                    nfchans += 3;
+                    if (entry.num_dep_sub > 0) {
+                        DependentSubstreamMask dependentSubstreamMask = new DependentSubstreamMask(dWChannelMaskFirstByte, dWChannelMaskSecondByte, entry).process();
+                        dWChannelMaskFirstByte |= dependentSubstreamMask.getdWChannelMaskFirstByte();
+                        dWChannelMaskSecondByte |= dependentSubstreamMask.getdWChannelMaskSecondByte();
+                    } else {
+                        dWChannelMaskFirstByte |= 0xE0;
+                    }
+                    break;
+                case 4: //2/1; L, R, S
+                    nfchans += 3;
+                    if (entry.num_dep_sub > 0) {
+                        DependentSubstreamMask dependentSubstreamMask = new DependentSubstreamMask(dWChannelMaskFirstByte, dWChannelMaskSecondByte, entry).process();
+                        dWChannelMaskFirstByte |= dependentSubstreamMask.getdWChannelMaskFirstByte();
+                        dWChannelMaskSecondByte |= dependentSubstreamMask.getdWChannelMaskSecondByte();
+                    } else {
+                        dWChannelMaskFirstByte |= 0xC0;
+                        dWChannelMaskSecondByte |= 0x80;
+                    }
+                    break;
+                case 5: //3/1; L, C, R, S
+                    nfchans += 4;
+                    if (entry.num_dep_sub > 0) {
+                        DependentSubstreamMask dependentSubstreamMask = new DependentSubstreamMask(dWChannelMaskFirstByte, dWChannelMaskSecondByte, entry).process();
+                        dWChannelMaskFirstByte |= dependentSubstreamMask.getdWChannelMaskFirstByte();
+                        dWChannelMaskSecondByte |= dependentSubstreamMask.getdWChannelMaskSecondByte();
+                    } else {
+                        dWChannelMaskFirstByte |= 0xE0;
+                        dWChannelMaskSecondByte |= 0x80;
+                    }
+                    break;
+                case 6: //2/2; L, R, SL, SR
+                    nfchans += 4;
+                    if (entry.num_dep_sub > 0) {
+                        DependentSubstreamMask dependentSubstreamMask = new DependentSubstreamMask(dWChannelMaskFirstByte, dWChannelMaskSecondByte, entry).process();
+                        dWChannelMaskFirstByte |= dependentSubstreamMask.getdWChannelMaskFirstByte();
+                        dWChannelMaskSecondByte |= dependentSubstreamMask.getdWChannelMaskSecondByte();
+                    } else {
+                        dWChannelMaskFirstByte |= 0xCC;
+                    }
+                    break;
+                case 7: //3/2; L, C, R, SL, SR
+                    nfchans += 5;
+                    if (entry.num_dep_sub > 0) {
+                        DependentSubstreamMask dependentSubstreamMask = new DependentSubstreamMask(dWChannelMaskFirstByte, dWChannelMaskSecondByte, entry).process();
+                        dWChannelMaskFirstByte |= dependentSubstreamMask.getdWChannelMaskFirstByte();
+                        dWChannelMaskSecondByte |= dependentSubstreamMask.getdWChannelMaskSecondByte();
+                    } else {
+                        dWChannelMaskFirstByte |= 0xEC;
+                    }
+                    break;
+            }
+            if (entry.lfeon == 1) {
+                lfechans ++;
+                dWChannelMaskFirstByte |= 0x10;
+            }
+        }
+
+        final ByteBuffer waveformatex = ByteBuffer.allocate(22);
+        waveformatex.put(new byte[]{0x00, 0x06}); //1536 wSamplesPerBlock - little endian
+        waveformatex.put(dWChannelMaskFirstByte);
+        waveformatex.put(dWChannelMaskSecondByte);
+        waveformatex.put(new byte[]{0x00, 0x00}); //pad dwChannelMask to 32bit
+        waveformatex.put(new byte[]{(byte)0xAF, (byte)0x87, (byte)0xFB, (byte)0xA7, 0x02, 0x2D, (byte)0xFB, 0x42, (byte)0xA4, (byte)0xD4, 0x05, (byte)0xCD, (byte)0x93, (byte)0x84, 0x3B, (byte)0xDD}); //SubFormat - Dolby Digital Plus GUID
+
+        final ByteBuffer dec3Content = ByteBuffer.allocate((int) ec3SpecificBox.getContentSize());
+        ec3SpecificBox.getContent(dec3Content);
+
+        AudioQuality l = new AudioQuality();
+        l.fourCC = "EC-3";
+        l.bitrate = getBitrate(track);
+        l.audioTag = 65534;
+        l.samplingRate = ase.getSampleRate();
+        l.channels = nfchans + lfechans;
+        l.bitPerSample = 16;
+        l.packetSize = track.getSamples().get(0).limit(); //assuming all are same size
+        l.codecPrivateData = Hex.encodeHex(waveformatex.array()) + Hex.encodeHex(dec3Content.array()); //append EC3SpecificBox (big endian) at the end of waveformatex
+        return l;
+    }
+
+    private AudioQuality getDtsAudioQuality(Track track, AudioSampleEntry ase) {
+        final DTSSpecificBox dtsSpecificBox = ase.getBoxes(DTSSpecificBox.class).get(0);
+        if (dtsSpecificBox == null) {
+            throw new RuntimeException("DTS track misses DTSSpecificBox!");
+        }
+
+        final ByteBuffer waveformatex = ByteBuffer.allocate(22);
+        final int frameDuration = dtsSpecificBox.getFrameDuration();
+        short samplesPerBlock = 0;
+        switch (frameDuration) {
+            case 0:
+                samplesPerBlock = 512;
+                break;
+            case 1:
+                samplesPerBlock = 1024;
+                break;
+            case 2:
+                samplesPerBlock = 2048;
+                break;
+            case 3:
+                samplesPerBlock = 4096;
+                break;
+        }
+        waveformatex.put((byte) (samplesPerBlock & 0xff));
+        waveformatex.put((byte) (samplesPerBlock >>> 8));
+        final int dwChannelMask = getNumChannelsAndMask(dtsSpecificBox)[1];
+        waveformatex.put((byte) (dwChannelMask & 0xff));
+        waveformatex.put((byte) (dwChannelMask >>> 8));
+        waveformatex.put((byte) (dwChannelMask >>> 16));
+        waveformatex.put((byte) (dwChannelMask >>> 24));
+        waveformatex.put(new byte[]{(byte)0xAE, (byte)0xE4, (byte)0xBF, (byte)0x5E, (byte)0x61, (byte)0x5E, (byte)0x41, (byte)0x87, (byte)0x92, (byte)0xFC, (byte)0xA4, (byte)0x81, (byte)0x26, (byte)0x99, (byte)0x02, (byte)0x11}); //DTS-HD GUID
+
+        final ByteBuffer dtsCodecPrivateData = ByteBuffer.allocate(8);
+        dtsCodecPrivateData.put((byte) dtsSpecificBox.getStreamConstruction());
+
+        final int channelLayout = dtsSpecificBox.getChannelLayout();
+        dtsCodecPrivateData.put((byte) (channelLayout & 0xff));
+        dtsCodecPrivateData.put((byte) (channelLayout >>> 8));
+        dtsCodecPrivateData.put((byte) (channelLayout >>> 16));
+        dtsCodecPrivateData.put((byte) (channelLayout >>> 24));
+
+        byte dtsFlags = (byte) (dtsSpecificBox.getMultiAssetFlag() << 1);
+        dtsFlags |= dtsSpecificBox.getLBRDurationMod();
+        dtsCodecPrivateData.put(dtsFlags);
+        dtsCodecPrivateData.put(new byte[]{0x00, 0x00}); //reserved
+
+        AudioQuality l = new AudioQuality();
+        l.fourCC = getFormat(ase);
+        l.bitrate = dtsSpecificBox.getAvgBitRate();
+        l.audioTag = 65534;
+        l.samplingRate = dtsSpecificBox.getDTSSamplingFrequency();
+        l.channels = getNumChannelsAndMask(dtsSpecificBox)[0];
+        l.bitPerSample = 16;
+        l.packetSize = track.getSamples().get(0).limit(); //assuming all are same size
+        l.codecPrivateData = Hex.encodeHex(waveformatex.array()) + Hex.encodeHex(dtsCodecPrivateData.array());
+        return l;
+
+    }
+
+    /* dwChannelMask
+    L SPEAKER_FRONT_LEFT 0x00000001
+    R SPEAKER_FRONT_RIGHT 0x00000002
+    C SPEAKER_FRONT_CENTER 0x00000004
+    LFE1 SPEAKER_LOW_FREQUENCY 0x00000008
+    Ls or Lsr* SPEAKER_BACK_LEFT 0x00000010
+    Rs or Rsr* SPEAKER_BACK_RIGHT 0x00000020
+    Lc SPEAKER_FRONT_LEFT_OF_CENTER 0x00000040
+    Rc SPEAKER_FRONT_RIGHT_OF_CENTER 0x00000080
+    Cs SPEAKER_BACK_CENTER 0x00000100
+    Lss SPEAKER_SIDE_LEFT 0x00000200
+    Rss SPEAKER_SIDE_RIGHT 0x00000400
+    Oh SPEAKER_TOP_CENTER 0x00000800
+    Lh SPEAKER_TOP_FRONT_LEFT 0x00001000
+    Ch SPEAKER_TOP_FRONT_CENTER 0x00002000
+    Rh SPEAKER_TOP_FRONT_RIGHT 0x00004000
+    Lhr SPEAKER_TOP_BACK_LEFT 0x00008000
+    Chf SPEAKER_TOP_BACK_CENTER 0x00010000
+    Rhr SPEAKER_TOP_BACK_RIGHT 0x00020000
+    SPEAKER_RESERVED 0x80000000
+
+    * if Lss, Rss exist, then this position is equivalent to Lsr, Rsr respectively
+     */
+    private int[] getNumChannelsAndMask(DTSSpecificBox dtsSpecificBox) {
+        final int channelLayout = dtsSpecificBox.getChannelLayout();
+        int numChannels = 0;
+        int dwChannelMask = 0;
+        if ((channelLayout & 0x0001) == 0x0001) {
+            //0001h Center in front of listener 1
+            numChannels += 1;
+            dwChannelMask |= 0x00000004; //SPEAKER_FRONT_CENTER
+        }
+        if ((channelLayout & 0x0002) == 0x0002) {
+            //0002h Left/Right in front 2
+            numChannels += 2;
+            dwChannelMask |= 0x00000001; //SPEAKER_FRONT_LEFT
+            dwChannelMask |= 0x00000002; //SPEAKER_FRONT_RIGHT
+        }
+        if ((channelLayout & 0x0004) == 0x0004) {
+            //0004h Left/Right surround on side in rear 2
+            numChannels += 2;
+            //* if Lss, Rss exist, then this position is equivalent to Lsr, Rsr respectively
+            dwChannelMask |= 0x00000010; //SPEAKER_BACK_LEFT
+            dwChannelMask |= 0x00000020; //SPEAKER_BACK_RIGHT
+        }
+        if ((channelLayout & 0x0008) == 0x0008) {
+            //0008h Low frequency effects subwoofer 1
+            numChannels += 1;
+            dwChannelMask |= 0x00000008; //SPEAKER_LOW_FREQUENCY
+        }
+        if ((channelLayout & 0x0010) == 0x0010) {
+            //0010h Center surround in rear 1
+            numChannels += 1;
+            dwChannelMask |= 0x00000100; //SPEAKER_BACK_CENTER
+        }
+        if ((channelLayout & 0x0020) == 0x0020) {
+            //0020h Left/Right height in front 2
+            numChannels += 2;
+            dwChannelMask |= 0x00001000; //SPEAKER_TOP_FRONT_LEFT
+            dwChannelMask |= 0x00004000; //SPEAKER_TOP_FRONT_RIGHT
+        }
+        if ((channelLayout & 0x0040) == 0x0040) {
+            //0040h Left/Right surround in rear 2
+            numChannels += 2;
+            dwChannelMask |= 0x00000010; //SPEAKER_BACK_LEFT
+            dwChannelMask |= 0x00000020; //SPEAKER_BACK_RIGHT
+        }
+        if ((channelLayout & 0x0080) == 0x0080) {
+            //0080h Center Height in front 1
+            numChannels += 1;
+            dwChannelMask |= 0x00002000; //SPEAKER_TOP_FRONT_CENTER
+        }
+        if ((channelLayout & 0x0100) == 0x0100) {
+            //0100h Over the listener’s head 1
+            numChannels += 1;
+            dwChannelMask |= 0x00000800; //SPEAKER_TOP_CENTER
+        }
+        if ((channelLayout & 0x0200) == 0x0200) {
+            //0200h Between left/right and center in front 2
+            numChannels += 2;
+            dwChannelMask |= 0x00000040; //SPEAKER_FRONT_LEFT_OF_CENTER
+            dwChannelMask |= 0x00000080; //SPEAKER_FRONT_RIGHT_OF_CENTER
+        }
+        if ((channelLayout & 0x0400) == 0x0400) {
+            //0400h Left/Right on side in front 2
+            numChannels += 2;
+            dwChannelMask |= 0x00000200; //SPEAKER_SIDE_LEFT
+            dwChannelMask |= 0x00000400; //SPEAKER_SIDE_RIGHT
+        }
+        if ((channelLayout & 0x0800) == 0x0800) {
+            //0800h Left/Right surround on side 2
+            numChannels += 2;
+            //* if Lss, Rss exist, then this position is equivalent to Lsr, Rsr respectively
+            dwChannelMask |= 0x00000010; //SPEAKER_BACK_LEFT
+            dwChannelMask |= 0x00000020; //SPEAKER_BACK_RIGHT
+        }
+        if ((channelLayout & 0x1000) == 0x1000) {
+            //1000h Second low frequency effects subwoofer 1
+            numChannels += 1;
+            dwChannelMask |= 0x00000008; //SPEAKER_LOW_FREQUENCY
+        }
+        if ((channelLayout & 0x2000) == 0x2000) {
+            //2000h Left/Right height on side 2
+            numChannels += 2;
+            dwChannelMask |= 0x00000010; //SPEAKER_BACK_LEFT
+            dwChannelMask |= 0x00000020; //SPEAKER_BACK_RIGHT
+        }
+        if ((channelLayout & 0x4000) == 0x4000) {
+            //4000h Center height in rear 1
+            numChannels += 1;
+            dwChannelMask |= 0x00010000; //SPEAKER_TOP_BACK_CENTER
+        }
+        if ((channelLayout & 0x8000) == 0x8000) {
+            //8000h Left/Right height in rear 2
+            numChannels += 2;
+            dwChannelMask |= 0x00008000; //SPEAKER_TOP_BACK_LEFT
+            dwChannelMask |= 0x00020000; //SPEAKER_TOP_BACK_RIGHT
+        }
+        if ((channelLayout & 0x10000) == 0x10000) {
+            //10000h Center below in front
+            numChannels += 1;
+        }
+        if ((channelLayout & 0x20000) == 0x20000) {
+            //20000h Left/Right below in front
+            numChannels += 2;
+        }
+        return new int[]{numChannels, dwChannelMask};
+    }
+
+    private String getAudioCodecPrivateData(AudioSpecificConfig audioSpecificConfig) {
+        byte[] configByteArray = audioSpecificConfig.getConfigBytes();
+        return Hex.encodeHex(configByteArray);
+    }
+
+    private VideoQuality getVideoQuality(Track track, VisualSampleEntry vse) {
+        VideoQuality l;
+        if ("avc1".equals(getFormat(vse))) {
+            AvcConfigurationBox avcConfigurationBox = vse.getBoxes(AvcConfigurationBox.class).get(0);
+            l = new VideoQuality();
+            l.bitrate = getBitrate(track);
+            l.codecPrivateData = Hex.encodeHex(getAvcCodecPrivateData(avcConfigurationBox));
+            l.fourCC = "AVC1";
+            l.width = vse.getWidth();
+            l.height = vse.getHeight();
+            l.nalLength = avcConfigurationBox.getLengthSizeMinusOne() + 1;
+        } else {
+            throw new InternalError("I don't know how to handle video of type " + getFormat(vse));
+        }
+        return l;
+    }
+
+    private byte[] getAvcCodecPrivateData(AvcConfigurationBox avcConfigurationBox) {
+        List<byte[]> sps = avcConfigurationBox.getSequenceParameterSets();
+        List<byte[]> pps = avcConfigurationBox.getPictureParameterSets();
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        try {
+            baos.write(new byte[]{0, 0, 0, 1});
+
+            for (byte[] sp : sps) {
+                baos.write(sp);
+            }
+            baos.write(new byte[]{0, 0, 0, 1});
+            for (byte[] pp : pps) {
+                baos.write(pp);
+            }
+        } catch (IOException ex) {
+            throw new RuntimeException("ByteArrayOutputStream do not throw IOException ?!?!?");
+        }
+        return baos.toByteArray();
+    }
+
+    private class DependentSubstreamMask {
+        private byte dWChannelMaskFirstByte;
+        private byte dWChannelMaskSecondByte;
+        private EC3SpecificBox.Entry entry;
+
+        public DependentSubstreamMask(byte dWChannelMaskFirstByte, byte dWChannelMaskSecondByte, EC3SpecificBox.Entry entry) {
+            this.dWChannelMaskFirstByte = dWChannelMaskFirstByte;
+            this.dWChannelMaskSecondByte = dWChannelMaskSecondByte;
+            this.entry = entry;
+        }
+
+        public byte getdWChannelMaskFirstByte() {
+            return dWChannelMaskFirstByte;
+        }
+
+        public byte getdWChannelMaskSecondByte() {
+            return dWChannelMaskSecondByte;
+        }
+
+        public DependentSubstreamMask process() {
+            switch (entry.chan_loc) {
+                case 0:
+                    dWChannelMaskFirstByte |= 0x3;
+                    break;
+                case 1:
+                    dWChannelMaskFirstByte |= 0xC;
+                    break;
+                case 2:
+                    dWChannelMaskSecondByte |= 0x80;
+                    break;
+                case 3:
+                    dWChannelMaskSecondByte |= 0x8;
+                    break;
+                case 6:
+                    dWChannelMaskSecondByte |= 0x5;
+                    break;
+                case 7:
+                    dWChannelMaskSecondByte |= 0x2;
+                    break;
+            }
+            return this;
+        }
+    }
+}
diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/authoring/adaptivestreaming/FlatPackageWriterImpl.java b/isoparser/src/main/java/com/googlecode/mp4parser/authoring/adaptivestreaming/FlatPackageWriterImpl.java
new file mode 100644
index 0000000..3e3847c
--- /dev/null
+++ b/isoparser/src/main/java/com/googlecode/mp4parser/authoring/adaptivestreaming/FlatPackageWriterImpl.java
@@ -0,0 +1,197 @@
+/*
+ * Copyright 2012 Sebastian Annies, Hamburg
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.googlecode.mp4parser.authoring.adaptivestreaming;
+
+import com.coremedia.iso.IsoFile;
+import com.coremedia.iso.boxes.Box;
+import com.coremedia.iso.boxes.SoundMediaHeaderBox;
+import com.coremedia.iso.boxes.VideoMediaHeaderBox;
+import com.coremedia.iso.boxes.fragment.MovieFragmentBox;
+import com.googlecode.mp4parser.authoring.Movie;
+import com.googlecode.mp4parser.authoring.Track;
+import com.googlecode.mp4parser.authoring.builder.*;
+import com.googlecode.mp4parser.authoring.tracks.ChangeTimeScaleTrack;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.nio.channels.FileChannel;
+import java.util.Iterator;
+import java.util.logging.Logger;
+
+public class FlatPackageWriterImpl implements PackageWriter {
+    private static Logger LOG = Logger.getLogger(FlatPackageWriterImpl.class.getName());
+    long timeScale = 10000000;
+
+    private File outputDirectory;
+    private boolean debugOutput;
+    private FragmentedMp4Builder ismvBuilder;
+    ManifestWriter manifestWriter;
+
+    public FlatPackageWriterImpl() {
+        ismvBuilder = new FragmentedMp4Builder();
+        FragmentIntersectionFinder intersectionFinder = new SyncSampleIntersectFinderImpl();
+        ismvBuilder.setIntersectionFinder(intersectionFinder);
+        manifestWriter = new FlatManifestWriterImpl(intersectionFinder);
+    }
+
+    /**
+     * Creates a factory for a smooth streaming package. A smooth streaming package is
+     * a collection of files that can be served by a webserver as a smooth streaming
+     * stream.
+     * @param minFragmentDuration the smallest allowable duration of a fragment (0 == no restriction).
+     */
+    public FlatPackageWriterImpl(int minFragmentDuration) {
+        ismvBuilder = new FragmentedMp4Builder();
+        FragmentIntersectionFinder intersectionFinder = new SyncSampleIntersectFinderImpl(minFragmentDuration);
+        ismvBuilder.setIntersectionFinder(intersectionFinder);
+        manifestWriter = new FlatManifestWriterImpl(intersectionFinder);
+    }
+
+    public void setOutputDirectory(File outputDirectory) {
+        assert outputDirectory.isDirectory();
+        this.outputDirectory = outputDirectory;
+
+    }
+
+    public void setDebugOutput(boolean debugOutput) {
+        this.debugOutput = debugOutput;
+    }
+
+    public void setIsmvBuilder(FragmentedMp4Builder ismvBuilder) {
+        this.ismvBuilder = ismvBuilder;
+        this.manifestWriter = new FlatManifestWriterImpl(ismvBuilder.getFragmentIntersectionFinder());
+    }
+
+    public void setManifestWriter(ManifestWriter manifestWriter) {
+        this.manifestWriter = manifestWriter;
+    }
+
+    /**
+     * Writes the movie given as <code>qualities</code> flattened into the
+     * <code>outputDirectory</code>.
+     *
+     * @param source the source movie with all qualities
+     * @throws IOException
+     */
+    public void write(Movie source) throws IOException {
+
+        if (debugOutput) {
+            outputDirectory.mkdirs();
+            DefaultMp4Builder defaultMp4Builder = new DefaultMp4Builder();
+            IsoFile muxed = defaultMp4Builder.build(source);
+            File muxedFile = new File(outputDirectory, "debug_1_muxed.mp4");
+            FileOutputStream muxedFileOutputStream = new FileOutputStream(muxedFile);
+            muxed.getBox(muxedFileOutputStream.getChannel());
+            muxedFileOutputStream.close();
+        }
+        Movie cleanedSource = removeUnknownTracks(source);
+        Movie movieWithAdjustedTimescale = correctTimescale(cleanedSource);
+
+        if (debugOutput) {
+            DefaultMp4Builder defaultMp4Builder = new DefaultMp4Builder();
+            IsoFile muxed = defaultMp4Builder.build(movieWithAdjustedTimescale);
+            File muxedFile = new File(outputDirectory, "debug_2_timescale.mp4");
+            FileOutputStream muxedFileOutputStream = new FileOutputStream(muxedFile);
+            muxed.getBox(muxedFileOutputStream.getChannel());
+            muxedFileOutputStream.close();
+        }
+        IsoFile isoFile = ismvBuilder.build(movieWithAdjustedTimescale);
+        if (debugOutput) {
+            File allQualities = new File(outputDirectory, "debug_3_fragmented.mp4");
+            FileOutputStream allQualis = new FileOutputStream(allQualities);
+            isoFile.getBox(allQualis.getChannel());
+            allQualis.close();
+        }
+
+
+        for (Track track : movieWithAdjustedTimescale.getTracks()) {
+            String bitrate = Long.toString(manifestWriter.getBitrate(track));
+            long trackId = track.getTrackMetaData().getTrackId();
+            Iterator<Box> boxIt = isoFile.getBoxes().iterator();
+            File mediaOutDir;
+            if (track.getMediaHeaderBox() instanceof SoundMediaHeaderBox) {
+                mediaOutDir = new File(outputDirectory, "audio");
+
+            } else if (track.getMediaHeaderBox() instanceof VideoMediaHeaderBox) {
+                mediaOutDir = new File(outputDirectory, "video");
+            } else {
+                System.err.println("Skipping Track with handler " + track.getHandler() + " and " + track.getMediaHeaderBox().getClass().getSimpleName());
+                continue;
+            }
+            File bitRateOutputDir = new File(mediaOutDir, bitrate);
+            bitRateOutputDir.mkdirs();
+            LOG.finer("Created : " + bitRateOutputDir.getCanonicalPath());
+
+            long[] fragmentTimes = manifestWriter.calculateFragmentDurations(track, movieWithAdjustedTimescale);
+            long startTime = 0;
+            int currentFragment = 0;
+            while (boxIt.hasNext()) {
+                Box b = boxIt.next();
+                if (b instanceof MovieFragmentBox) {
+                    assert ((MovieFragmentBox) b).getTrackCount() == 1;
+                    if (((MovieFragmentBox) b).getTrackNumbers()[0] == trackId) {
+                        FileOutputStream fos = new FileOutputStream(new File(bitRateOutputDir, Long.toString(startTime)));
+                        startTime += fragmentTimes[currentFragment++];
+                        FileChannel fc = fos.getChannel();
+                        Box mdat = boxIt.next();
+                        assert mdat.getType().equals("mdat");
+                        b.getBox(fc); // moof
+                        mdat.getBox(fc); // mdat
+                        fc.truncate(fc.position());
+                        fc.close();
+                    }
+                }
+
+            }
+        }
+        FileWriter fw = new FileWriter(new File(outputDirectory, "Manifest"));
+        fw.write(manifestWriter.getManifest(movieWithAdjustedTimescale));
+        fw.close();
+
+    }
+
+    private Movie removeUnknownTracks(Movie source) {
+        Movie nuMovie = new Movie();
+        for (Track track : source.getTracks()) {
+            if ("vide".equals(track.getHandler()) || "soun".equals(track.getHandler())) {
+                nuMovie.addTrack(track);
+            } else {
+                LOG.fine("Removed track " + track);
+            }
+        }
+        return nuMovie;
+    }
+
+
+    /**
+     * Returns a new <code>Movie</code> in that all tracks have the timescale 10000000. CTS & DTS are modified
+     * in a way that even with more than one framerate the fragments exactly begin at the same time.
+     *
+     * @param movie
+     * @return a movie with timescales suitable for smooth streaming manifests
+     */
+    public Movie correctTimescale(Movie movie) {
+        Movie nuMovie = new Movie();
+        for (Track track : movie.getTracks()) {
+            nuMovie.addTrack(new ChangeTimeScaleTrack(track, timeScale, ismvBuilder.getFragmentIntersectionFinder().sampleNumbers(track, movie)));
+        }
+        return nuMovie;
+
+    }
+
+}
diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/authoring/adaptivestreaming/ManifestWriter.java b/isoparser/src/main/java/com/googlecode/mp4parser/authoring/adaptivestreaming/ManifestWriter.java
new file mode 100644
index 0000000..2b2ba7d
--- /dev/null
+++ b/isoparser/src/main/java/com/googlecode/mp4parser/authoring/adaptivestreaming/ManifestWriter.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright 2012 Sebastian Annies, Hamburg
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.googlecode.mp4parser.authoring.adaptivestreaming;
+
+
+import com.googlecode.mp4parser.authoring.Movie;
+import com.googlecode.mp4parser.authoring.Track;
+
+import java.io.IOException;
+
+public interface ManifestWriter {
+    String getManifest(Movie inputs) throws IOException;
+
+    long getBitrate(Track track);
+
+    long[] calculateFragmentDurations(Track track, Movie movie);
+
+}
diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/authoring/adaptivestreaming/PackageWriter.java b/isoparser/src/main/java/com/googlecode/mp4parser/authoring/adaptivestreaming/PackageWriter.java
new file mode 100644
index 0000000..0d97fc5
--- /dev/null
+++ b/isoparser/src/main/java/com/googlecode/mp4parser/authoring/adaptivestreaming/PackageWriter.java
@@ -0,0 +1,27 @@
+/*
+ * Copyright 2012 Sebastian Annies, Hamburg
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.googlecode.mp4parser.authoring.adaptivestreaming;
+
+import com.googlecode.mp4parser.authoring.Movie;
+
+import java.io.IOException;
+
+/**
+ * Writes the whole package.
+ */
+public interface PackageWriter {
+    public void write(Movie qualities) throws IOException;
+}
diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/authoring/adaptivestreaming/VideoQuality.java b/isoparser/src/main/java/com/googlecode/mp4parser/authoring/adaptivestreaming/VideoQuality.java
new file mode 100644
index 0000000..4a70e47
--- /dev/null
+++ b/isoparser/src/main/java/com/googlecode/mp4parser/authoring/adaptivestreaming/VideoQuality.java
@@ -0,0 +1,25 @@
+/*
+ * Copyright 2012 Sebastian Annies, Hamburg
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.googlecode.mp4parser.authoring.adaptivestreaming;
+
+class VideoQuality {
+    long bitrate;
+    String fourCC;
+    int width;
+    int height;
+    String codecPrivateData;
+    int nalLength;
+}
diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/authoring/builder/.svn/all-wcprops b/isoparser/src/main/java/com/googlecode/mp4parser/authoring/builder/.svn/all-wcprops
new file mode 100644
index 0000000..9204edf
--- /dev/null
+++ b/isoparser/src/main/java/com/googlecode/mp4parser/authoring/builder/.svn/all-wcprops
@@ -0,0 +1,47 @@
+K 25
+svn:wc:ra_dav:version-url
+V 90
+/svn/!svn/ver/776/trunk/isoparser/src/main/java/com/googlecode/mp4parser/authoring/builder
+END
+FragmentIntersectionFinder.java
+K 25
+svn:wc:ra_dav:version-url
+V 122
+/svn/!svn/ver/455/trunk/isoparser/src/main/java/com/googlecode/mp4parser/authoring/builder/FragmentIntersectionFinder.java
+END
+TwoSecondIntersectionFinder.java
+K 25
+svn:wc:ra_dav:version-url
+V 123
+/svn/!svn/ver/658/trunk/isoparser/src/main/java/com/googlecode/mp4parser/authoring/builder/TwoSecondIntersectionFinder.java
+END
+FragmentedMp4Builder.java
+K 25
+svn:wc:ra_dav:version-url
+V 116
+/svn/!svn/ver/707/trunk/isoparser/src/main/java/com/googlecode/mp4parser/authoring/builder/FragmentedMp4Builder.java
+END
+Mp4Builder.java
+K 25
+svn:wc:ra_dav:version-url
+V 106
+/svn/!svn/ver/672/trunk/isoparser/src/main/java/com/googlecode/mp4parser/authoring/builder/Mp4Builder.java
+END
+SyncSampleIntersectFinderImpl.java
+K 25
+svn:wc:ra_dav:version-url
+V 125
+/svn/!svn/ver/774/trunk/isoparser/src/main/java/com/googlecode/mp4parser/authoring/builder/SyncSampleIntersectFinderImpl.java
+END
+DefaultMp4Builder.java
+K 25
+svn:wc:ra_dav:version-url
+V 113
+/svn/!svn/ver/776/trunk/isoparser/src/main/java/com/googlecode/mp4parser/authoring/builder/DefaultMp4Builder.java
+END
+ByteBufferHelper.java
+K 25
+svn:wc:ra_dav:version-url
+V 112
+/svn/!svn/ver/530/trunk/isoparser/src/main/java/com/googlecode/mp4parser/authoring/builder/ByteBufferHelper.java
+END
diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/authoring/builder/.svn/entries b/isoparser/src/main/java/com/googlecode/mp4parser/authoring/builder/.svn/entries
new file mode 100644
index 0000000..2c6e266
--- /dev/null
+++ b/isoparser/src/main/java/com/googlecode/mp4parser/authoring/builder/.svn/entries
@@ -0,0 +1,266 @@
+10
+
+dir
+778
+http://mp4parser.googlecode.com/svn/trunk/isoparser/src/main/java/com/googlecode/mp4parser/authoring/builder
+http://mp4parser.googlecode.com/svn
+
+
+
+2012-09-10T14:34:23.574807Z
+776
+sebastian.annies@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+7decde4b-c250-0410-a0da-51896bc88be6
+
+FragmentIntersectionFinder.java
+file
+
+
+
+
+2012-09-14T17:27:50.237215Z
+979df582987d3797c42ae315b3d2555a
+2012-04-10T10:20:46.357991Z
+455
+Sebastian.Annies@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+1160
+
+TwoSecondIntersectionFinder.java
+file
+
+
+
+
+2012-09-14T17:27:50.237215Z
+47aa683919ce24da51b82236e8f27426
+2012-06-06T10:36:10.590512Z
+658
+Sebastian.Annies@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+2817
+
+FragmentedMp4Builder.java
+file
+
+
+
+
+2012-09-14T17:27:50.237215Z
+f81cbeb22aee5ab0405ad38e67b9e4e1
+2012-07-10T16:32:53.757675Z
+707
+michael.stattmann@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+31005
+
+Mp4Builder.java
+file
+
+
+
+
+2012-09-14T17:27:50.237215Z
+ea548a5ace2a4480472b90d9f820bceb
+2012-06-11T22:10:18.183835Z
+672
+michael.stattmann@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+1156
+
+SyncSampleIntersectFinderImpl.java
+file
+
+
+
+
+2012-09-14T17:27:50.237215Z
+d49823bb95a5920f2df6899195c28a72
+2012-09-06T12:33:39.419429Z
+774
+michael.stattmann@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+14915
+
+DefaultMp4Builder.java
+file
+
+
+
+
+2012-09-14T17:27:50.237215Z
+15d93ea29e24e257604301ad5e73d623
+2012-09-10T14:34:23.574807Z
+776
+sebastian.annies@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+22096
+
+ByteBufferHelper.java
+file
+
+
+
+
+2012-09-14T17:27:50.237215Z
+a103511eeddf1e0d1962704ae23ba4a5
+2012-04-27T09:17:25.544414Z
+530
+hoemmagnus@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+2344
+
diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/authoring/builder/.svn/text-base/ByteBufferHelper.java.svn-base b/isoparser/src/main/java/com/googlecode/mp4parser/authoring/builder/.svn/text-base/ByteBufferHelper.java.svn-base
new file mode 100644
index 0000000..ad21b11
--- /dev/null
+++ b/isoparser/src/main/java/com/googlecode/mp4parser/authoring/builder/.svn/text-base/ByteBufferHelper.java.svn-base
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2012 Sebastian Annies, Hamburg
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.googlecode.mp4parser.authoring.builder;
+
+import java.nio.ByteBuffer;
+import java.nio.MappedByteBuffer;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Used to merge adjacent byte buffers.
+ */
+public class ByteBufferHelper {
+    public static List<ByteBuffer> mergeAdjacentBuffers(List<ByteBuffer> samples) {
+        ArrayList<ByteBuffer> nuSamples = new ArrayList<ByteBuffer>(samples.size());
+        for (ByteBuffer buffer : samples) {
+            int lastIndex = nuSamples.size() - 1;
+            if (lastIndex >= 0 && buffer.hasArray() && nuSamples.get(lastIndex).hasArray() && buffer.array() == nuSamples.get(lastIndex).array() &&
+                    nuSamples.get(lastIndex).arrayOffset() + nuSamples.get(lastIndex).limit() == buffer.arrayOffset()) {
+                ByteBuffer oldBuffer = nuSamples.remove(lastIndex);
+                ByteBuffer nu = ByteBuffer.wrap(buffer.array(), oldBuffer.arrayOffset(), oldBuffer.limit() + buffer.limit()).slice();
+                // We need to slice here since wrap([], offset, length) just sets position and not the arrayOffset.
+                nuSamples.add(nu);
+            } else if (lastIndex >= 0 &&
+                    buffer instanceof MappedByteBuffer && nuSamples.get(lastIndex) instanceof MappedByteBuffer &&
+                    nuSamples.get(lastIndex).limit() == nuSamples.get(lastIndex).capacity() - buffer.capacity()) {
+                // This can go wrong - but will it?
+                ByteBuffer oldBuffer = nuSamples.get(lastIndex);
+                oldBuffer.limit(buffer.limit() + oldBuffer.limit());
+            } else {
+                buffer.rewind();
+                nuSamples.add(buffer);
+            }
+        }
+        return nuSamples;
+    }
+}
diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/authoring/builder/.svn/text-base/DefaultMp4Builder.java.svn-base b/isoparser/src/main/java/com/googlecode/mp4parser/authoring/builder/.svn/text-base/DefaultMp4Builder.java.svn-base
new file mode 100644
index 0000000..9bd1ca6
--- /dev/null
+++ b/isoparser/src/main/java/com/googlecode/mp4parser/authoring/builder/.svn/text-base/DefaultMp4Builder.java.svn-base
@@ -0,0 +1,576 @@
+/*
+ * Copyright 2012 Sebastian Annies, Hamburg
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.googlecode.mp4parser.authoring.builder;
+
+import com.coremedia.iso.BoxParser;
+import com.coremedia.iso.IsoFile;
+import com.coremedia.iso.IsoTypeWriter;
+import com.coremedia.iso.boxes.Box;
+import com.coremedia.iso.boxes.CompositionTimeToSample;
+import com.coremedia.iso.boxes.ContainerBox;
+import com.coremedia.iso.boxes.DataEntryUrlBox;
+import com.coremedia.iso.boxes.DataInformationBox;
+import com.coremedia.iso.boxes.DataReferenceBox;
+import com.coremedia.iso.boxes.FileTypeBox;
+import com.coremedia.iso.boxes.HandlerBox;
+import com.coremedia.iso.boxes.MediaBox;
+import com.coremedia.iso.boxes.MediaHeaderBox;
+import com.coremedia.iso.boxes.MediaInformationBox;
+import com.coremedia.iso.boxes.MovieBox;
+import com.coremedia.iso.boxes.MovieHeaderBox;
+import com.coremedia.iso.boxes.SampleDependencyTypeBox;
+import com.coremedia.iso.boxes.SampleSizeBox;
+import com.coremedia.iso.boxes.SampleTableBox;
+import com.coremedia.iso.boxes.SampleToChunkBox;
+import com.coremedia.iso.boxes.StaticChunkOffsetBox;
+import com.coremedia.iso.boxes.SyncSampleBox;
+import com.coremedia.iso.boxes.TimeToSampleBox;
+import com.coremedia.iso.boxes.TrackBox;
+import com.coremedia.iso.boxes.TrackHeaderBox;
+import com.googlecode.mp4parser.authoring.DateHelper;
+import com.googlecode.mp4parser.authoring.Movie;
+import com.googlecode.mp4parser.authoring.Track;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.nio.MappedByteBuffer;
+import java.nio.channels.GatheringByteChannel;
+import java.nio.channels.ReadableByteChannel;
+import java.nio.channels.WritableByteChannel;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import static com.googlecode.mp4parser.util.CastUtils.l2i;
+
+/**
+ * Creates a plain MP4 file from a video. Plain as plain can be.
+ */
+public class DefaultMp4Builder implements Mp4Builder {
+
+    public int STEPSIZE = 64;
+    Set<StaticChunkOffsetBox> chunkOffsetBoxes = new HashSet<StaticChunkOffsetBox>();
+    private static Logger LOG = Logger.getLogger(DefaultMp4Builder.class.getName());
+
+    HashMap<Track, List<ByteBuffer>> track2Sample = new HashMap<Track, List<ByteBuffer>>();
+    HashMap<Track, long[]> track2SampleSizes = new HashMap<Track, long[]>();
+    private FragmentIntersectionFinder intersectionFinder = new TwoSecondIntersectionFinder();
+
+    public void setIntersectionFinder(FragmentIntersectionFinder intersectionFinder) {
+        this.intersectionFinder = intersectionFinder;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public IsoFile build(Movie movie) {
+        LOG.fine("Creating movie " + movie);
+        for (Track track : movie.getTracks()) {
+            // getting the samples may be a time consuming activity
+            List<ByteBuffer> samples = track.getSamples();
+            putSamples(track, samples);
+            long[] sizes = new long[samples.size()];
+            for (int i = 0; i < sizes.length; i++) {
+                sizes[i] = samples.get(i).limit();
+            }
+            putSampleSizes(track, sizes);
+        }
+
+        IsoFile isoFile = new IsoFile();
+        // ouch that is ugly but I don't know how to do it else
+        List<String> minorBrands = new LinkedList<String>();
+        minorBrands.add("isom");
+        minorBrands.add("iso2");
+        minorBrands.add("avc1");
+
+        isoFile.addBox(new FileTypeBox("isom", 0, minorBrands));
+        isoFile.addBox(createMovieBox(movie));
+        InterleaveChunkMdat mdat = new InterleaveChunkMdat(movie);
+        isoFile.addBox(mdat);
+
+        /*
+        dataOffset is where the first sample starts. In this special mdat the samples always start
+        at offset 16 so that we can use the same offset for large boxes and small boxes
+         */
+        long dataOffset = mdat.getDataOffset();
+        for (StaticChunkOffsetBox chunkOffsetBox : chunkOffsetBoxes) {
+            long[] offsets = chunkOffsetBox.getChunkOffsets();
+            for (int i = 0; i < offsets.length; i++) {
+                offsets[i] += dataOffset;
+            }
+        }
+
+
+        return isoFile;
+    }
+
+    public FragmentIntersectionFinder getFragmentIntersectionFinder() {
+        throw new UnsupportedOperationException("No fragment intersection finder in default MP4 builder!");
+    }
+
+    protected long[] putSampleSizes(Track track, long[] sizes) {
+        return track2SampleSizes.put(track, sizes);
+    }
+
+    protected List<ByteBuffer> putSamples(Track track, List<ByteBuffer> samples) {
+        return track2Sample.put(track, samples);
+    }
+
+    private MovieBox createMovieBox(Movie movie) {
+        MovieBox movieBox = new MovieBox();
+        MovieHeaderBox mvhd = new MovieHeaderBox();
+
+        mvhd.setCreationTime(DateHelper.convert(new Date()));
+        mvhd.setModificationTime(DateHelper.convert(new Date()));
+
+        long movieTimeScale = getTimescale(movie);
+        long duration = 0;
+
+        for (Track track : movie.getTracks()) {
+            long tracksDuration = getDuration(track) * movieTimeScale / track.getTrackMetaData().getTimescale();
+            if (tracksDuration > duration) {
+                duration = tracksDuration;
+            }
+
+
+        }
+
+        mvhd.setDuration(duration);
+        mvhd.setTimescale(movieTimeScale);
+        // find the next available trackId
+        long nextTrackId = 0;
+        for (Track track : movie.getTracks()) {
+            nextTrackId = nextTrackId < track.getTrackMetaData().getTrackId() ? track.getTrackMetaData().getTrackId() : nextTrackId;
+        }
+        mvhd.setNextTrackId(++nextTrackId);
+        if (mvhd.getCreationTime() >= 1l << 32 ||
+                mvhd.getModificationTime() >= 1l << 32 ||
+                mvhd.getDuration() >= 1l << 32) {
+            mvhd.setVersion(1);
+        }
+
+        movieBox.addBox(mvhd);
+        for (Track track : movie.getTracks()) {
+            movieBox.addBox(createTrackBox(track, movie));
+        }
+        // metadata here
+        Box udta = createUdta(movie);
+        if (udta != null) {
+            movieBox.addBox(udta);
+        }
+        return movieBox;
+
+    }
+
+    /**
+     * Override to create a user data box that may contain metadata.
+     *
+     * @return a 'udta' box or <code>null</code> if none provided
+     */
+    protected Box createUdta(Movie movie) {
+        return null;
+    }
+
+    private TrackBox createTrackBox(Track track, Movie movie) {
+
+        LOG.info("Creating Mp4TrackImpl " + track);
+        TrackBox trackBox = new TrackBox();
+        TrackHeaderBox tkhd = new TrackHeaderBox();
+        int flags = 0;
+        if (track.isEnabled()) {
+            flags += 1;
+        }
+
+        if (track.isInMovie()) {
+            flags += 2;
+        }
+
+        if (track.isInPreview()) {
+            flags += 4;
+        }
+
+        if (track.isInPoster()) {
+            flags += 8;
+        }
+        tkhd.setFlags(flags);
+
+        tkhd.setAlternateGroup(track.getTrackMetaData().getGroup());
+        tkhd.setCreationTime(DateHelper.convert(track.getTrackMetaData().getCreationTime()));
+        // We need to take edit list box into account in trackheader duration
+        // but as long as I don't support edit list boxes it is sufficient to
+        // just translate media duration to movie timescale
+        tkhd.setDuration(getDuration(track) * getTimescale(movie) / track.getTrackMetaData().getTimescale());
+        tkhd.setHeight(track.getTrackMetaData().getHeight());
+        tkhd.setWidth(track.getTrackMetaData().getWidth());
+        tkhd.setLayer(track.getTrackMetaData().getLayer());
+        tkhd.setModificationTime(DateHelper.convert(new Date()));
+        tkhd.setTrackId(track.getTrackMetaData().getTrackId());
+        tkhd.setVolume(track.getTrackMetaData().getVolume());
+        if (tkhd.getCreationTime() >= 1l << 32 ||
+                tkhd.getModificationTime() >= 1l << 32 ||
+                tkhd.getDuration() >= 1l << 32) {
+            tkhd.setVersion(1);
+        }
+
+        trackBox.addBox(tkhd);
+
+/*
+        EditBox edit = new EditBox();
+        EditListBox editListBox = new EditListBox();
+        editListBox.setEntries(Collections.singletonList(
+                new EditListBox.Entry(editListBox, (long) (track.getTrackMetaData().getStartTime() * getTimescale(movie)), -1, 1)));
+        edit.addBox(editListBox);
+        trackBox.addBox(edit);
+*/
+
+        MediaBox mdia = new MediaBox();
+        trackBox.addBox(mdia);
+        MediaHeaderBox mdhd = new MediaHeaderBox();
+        mdhd.setCreationTime(DateHelper.convert(track.getTrackMetaData().getCreationTime()));
+        mdhd.setDuration(getDuration(track));
+        mdhd.setTimescale(track.getTrackMetaData().getTimescale());
+        mdhd.setLanguage(track.getTrackMetaData().getLanguage());
+        mdia.addBox(mdhd);
+        HandlerBox hdlr = new HandlerBox();
+        mdia.addBox(hdlr);
+
+        hdlr.setHandlerType(track.getHandler());
+
+        MediaInformationBox minf = new MediaInformationBox();
+        minf.addBox(track.getMediaHeaderBox());
+
+        // dinf: all these three boxes tell us is that the actual
+        // data is in the current file and not somewhere external
+        DataInformationBox dinf = new DataInformationBox();
+        DataReferenceBox dref = new DataReferenceBox();
+        dinf.addBox(dref);
+        DataEntryUrlBox url = new DataEntryUrlBox();
+        url.setFlags(1);
+        dref.addBox(url);
+        minf.addBox(dinf);
+        //
+
+        SampleTableBox stbl = new SampleTableBox();
+
+        stbl.addBox(track.getSampleDescriptionBox());
+
+        List<TimeToSampleBox.Entry> decodingTimeToSampleEntries = track.getDecodingTimeEntries();
+        if (decodingTimeToSampleEntries != null && !track.getDecodingTimeEntries().isEmpty()) {
+            TimeToSampleBox stts = new TimeToSampleBox();
+            stts.setEntries(track.getDecodingTimeEntries());
+            stbl.addBox(stts);
+        }
+
+        List<CompositionTimeToSample.Entry> compositionTimeToSampleEntries = track.getCompositionTimeEntries();
+        if (compositionTimeToSampleEntries != null && !compositionTimeToSampleEntries.isEmpty()) {
+            CompositionTimeToSample ctts = new CompositionTimeToSample();
+            ctts.setEntries(compositionTimeToSampleEntries);
+            stbl.addBox(ctts);
+        }
+
+        long[] syncSamples = track.getSyncSamples();
+        if (syncSamples != null && syncSamples.length > 0) {
+            SyncSampleBox stss = new SyncSampleBox();
+            stss.setSampleNumber(syncSamples);
+            stbl.addBox(stss);
+        }
+
+        if (track.getSampleDependencies() != null && !track.getSampleDependencies().isEmpty()) {
+            SampleDependencyTypeBox sdtp = new SampleDependencyTypeBox();
+            sdtp.setEntries(track.getSampleDependencies());
+            stbl.addBox(sdtp);
+        }
+        HashMap<Track, int[]> track2ChunkSizes = new HashMap<Track, int[]>();
+        for (Track current : movie.getTracks()) {
+            track2ChunkSizes.put(current, getChunkSizes(current, movie));
+        }
+        int[] tracksChunkSizes = track2ChunkSizes.get(track);
+
+        SampleToChunkBox stsc = new SampleToChunkBox();
+        stsc.setEntries(new LinkedList<SampleToChunkBox.Entry>());
+        long lastChunkSize = Integer.MIN_VALUE; // to be sure the first chunks hasn't got the same size
+        for (int i = 0; i < tracksChunkSizes.length; i++) {
+            // The sample description index references the sample description box
+            // that describes the samples of this chunk. My Tracks cannot have more
+            // than one sample description box. Therefore 1 is always right
+            // the first chunk has the number '1'
+            if (lastChunkSize != tracksChunkSizes[i]) {
+                stsc.getEntries().add(new SampleToChunkBox.Entry(i + 1, tracksChunkSizes[i], 1));
+                lastChunkSize = tracksChunkSizes[i];
+            }
+        }
+        stbl.addBox(stsc);
+
+        SampleSizeBox stsz = new SampleSizeBox();
+        stsz.setSampleSizes(track2SampleSizes.get(track));
+
+        stbl.addBox(stsz);
+        // The ChunkOffsetBox we create here is just a stub
+        // since we haven't created the whole structure we can't tell where the
+        // first chunk starts (mdat box). So I just let the chunk offset
+        // start at zero and I will add the mdat offset later.
+        StaticChunkOffsetBox stco = new StaticChunkOffsetBox();
+        this.chunkOffsetBoxes.add(stco);
+        long offset = 0;
+        long[] chunkOffset = new long[tracksChunkSizes.length];
+        // all tracks have the same number of chunks
+        if (LOG.isLoggable(Level.FINE)) {
+            LOG.fine("Calculating chunk offsets for track_" + track.getTrackMetaData().getTrackId());
+        }
+
+
+        for (int i = 0; i < tracksChunkSizes.length; i++) {
+            // The filelayout will be:
+            // chunk_1_track_1,... ,chunk_1_track_n, chunk_2_track_1,... ,chunk_2_track_n, ... , chunk_m_track_1,... ,chunk_m_track_n
+            // calculating the offsets
+            if (LOG.isLoggable(Level.FINER)) {
+                LOG.finer("Calculating chunk offsets for track_" + track.getTrackMetaData().getTrackId() + " chunk " + i);
+            }
+            for (Track current : movie.getTracks()) {
+                if (LOG.isLoggable(Level.FINEST)) {
+                    LOG.finest("Adding offsets of track_" + current.getTrackMetaData().getTrackId());
+                }
+                int[] chunkSizes = track2ChunkSizes.get(current);
+                long firstSampleOfChunk = 0;
+                for (int j = 0; j < i; j++) {
+                    firstSampleOfChunk += chunkSizes[j];
+                }
+                if (current == track) {
+                    chunkOffset[i] = offset;
+                }
+                for (int j = l2i(firstSampleOfChunk); j < firstSampleOfChunk + chunkSizes[i]; j++) {
+                    offset += track2SampleSizes.get(current)[j];
+                }
+            }
+        }
+        stco.setChunkOffsets(chunkOffset);
+        stbl.addBox(stco);
+        minf.addBox(stbl);
+        mdia.addBox(minf);
+
+        return trackBox;
+    }
+
+    private class InterleaveChunkMdat implements Box {
+        List<Track> tracks;
+        List<ByteBuffer> samples = new ArrayList<ByteBuffer>();
+        ContainerBox parent;
+
+        long contentSize = 0;
+
+        public ContainerBox getParent() {
+            return parent;
+        }
+
+        public void setParent(ContainerBox parent) {
+            this.parent = parent;
+        }
+
+        public void parse(ReadableByteChannel readableByteChannel, ByteBuffer header, long contentSize, BoxParser boxParser) throws IOException {
+        }
+
+        private InterleaveChunkMdat(Movie movie) {
+
+            tracks = movie.getTracks();
+            Map<Track, int[]> chunks = new HashMap<Track, int[]>();
+            for (Track track : movie.getTracks()) {
+                chunks.put(track, getChunkSizes(track, movie));
+            }
+
+            for (int i = 0; i < chunks.values().iterator().next().length; i++) {
+                for (Track track : tracks) {
+
+                    int[] chunkSizes = chunks.get(track);
+                    long firstSampleOfChunk = 0;
+                    for (int j = 0; j < i; j++) {
+                        firstSampleOfChunk += chunkSizes[j];
+                    }
+
+                    for (int j = l2i(firstSampleOfChunk); j < firstSampleOfChunk + chunkSizes[i]; j++) {
+
+                        ByteBuffer s = DefaultMp4Builder.this.track2Sample.get(track).get(j);
+                        contentSize += s.limit();
+                        samples.add((ByteBuffer) s.rewind());
+                    }
+
+                }
+
+            }
+
+        }
+
+        public long getDataOffset() {
+            Box b = this;
+            long offset = 16;
+            while (b.getParent() != null) {
+                for (Box box : b.getParent().getBoxes()) {
+                    if (b == box) {
+                        break;
+                    }
+                    offset += box.getSize();
+                }
+                b = b.getParent();
+            }
+            return offset;
+        }
+
+
+        public String getType() {
+            return "mdat";
+        }
+
+        public long getSize() {
+            return 16 + contentSize;
+        }
+
+        private boolean isSmallBox(long contentSize) {
+            return (contentSize + 8) < 4294967296L;
+        }
+
+
+        public void getBox(WritableByteChannel writableByteChannel) throws IOException {
+            ByteBuffer bb = ByteBuffer.allocate(16);
+            long size = getSize();
+            if (isSmallBox(size)) {
+                IsoTypeWriter.writeUInt32(bb, size);
+            } else {
+                IsoTypeWriter.writeUInt32(bb, 1);
+            }
+            bb.put(IsoFile.fourCCtoBytes("mdat"));
+            if (isSmallBox(size)) {
+                bb.put(new byte[8]);
+            } else {
+                IsoTypeWriter.writeUInt64(bb, size);
+            }
+            bb.rewind();
+            writableByteChannel.write(bb);
+            if (writableByteChannel instanceof GatheringByteChannel) {
+                List<ByteBuffer> nuSamples = unifyAdjacentBuffers(samples);
+
+
+                for (int i = 0; i < Math.ceil((double) nuSamples.size() / STEPSIZE); i++) {
+                    List<ByteBuffer> sublist = nuSamples.subList(
+                            i * STEPSIZE, // start
+                            (i + 1) * STEPSIZE < nuSamples.size() ? (i + 1) * STEPSIZE : nuSamples.size()); // end
+                    ByteBuffer sampleArray[] = sublist.toArray(new ByteBuffer[sublist.size()]);
+                    do {
+                        ((GatheringByteChannel) writableByteChannel).write(sampleArray);
+                    } while (sampleArray[sampleArray.length - 1].remaining() > 0);
+                }
+                //System.err.println(bytesWritten);
+            } else {
+                for (ByteBuffer sample : samples) {
+                    sample.rewind();
+                    writableByteChannel.write(sample);
+                }
+            }
+        }
+
+    }
+
+    /**
+     * Gets the chunk sizes for the given track.
+     *
+     * @param track
+     * @param movie
+     * @return
+     */
+    int[] getChunkSizes(Track track, Movie movie) {
+
+        long[] referenceChunkStarts = intersectionFinder.sampleNumbers(track, movie);
+        int[] chunkSizes = new int[referenceChunkStarts.length];
+
+
+        for (int i = 0; i < referenceChunkStarts.length; i++) {
+            long start = referenceChunkStarts[i] - 1;
+            long end;
+            if (referenceChunkStarts.length == i + 1) {
+                end = track.getSamples().size();
+            } else {
+                end = referenceChunkStarts[i + 1] - 1;
+            }
+
+            chunkSizes[i] = l2i(end - start);
+            // The Stretch makes sure that there are as much audio and video chunks!
+        }
+        assert DefaultMp4Builder.this.track2Sample.get(track).size() == sum(chunkSizes) : "The number of samples and the sum of all chunk lengths must be equal";
+        return chunkSizes;
+
+
+    }
+
+
+    private static long sum(int[] ls) {
+        long rc = 0;
+        for (long l : ls) {
+            rc += l;
+        }
+        return rc;
+    }
+
+    protected static long getDuration(Track track) {
+        long duration = 0;
+        for (TimeToSampleBox.Entry entry : track.getDecodingTimeEntries()) {
+            duration += entry.getCount() * entry.getDelta();
+        }
+        return duration;
+    }
+
+    public long getTimescale(Movie movie) {
+        long timescale = movie.getTracks().iterator().next().getTrackMetaData().getTimescale();
+        for (Track track : movie.getTracks()) {
+            timescale = gcd(track.getTrackMetaData().getTimescale(), timescale);
+        }
+        return timescale;
+    }
+
+    public static long gcd(long a, long b) {
+        if (b == 0) {
+            return a;
+        }
+        return gcd(b, a % b);
+    }
+
+    public List<ByteBuffer> unifyAdjacentBuffers(List<ByteBuffer> samples) {
+        ArrayList<ByteBuffer> nuSamples = new ArrayList<ByteBuffer>(samples.size());
+        for (ByteBuffer buffer : samples) {
+            int lastIndex = nuSamples.size() - 1;
+            if (lastIndex >= 0 && buffer.hasArray() && nuSamples.get(lastIndex).hasArray() && buffer.array() == nuSamples.get(lastIndex).array() &&
+                    nuSamples.get(lastIndex).arrayOffset() + nuSamples.get(lastIndex).limit() == buffer.arrayOffset()) {
+                ByteBuffer oldBuffer = nuSamples.remove(lastIndex);
+                ByteBuffer nu = ByteBuffer.wrap(buffer.array(), oldBuffer.arrayOffset(), oldBuffer.limit() + buffer.limit()).slice();
+                // We need to slice here since wrap([], offset, length) just sets position and not the arrayOffset.
+                nuSamples.add(nu);
+            } else if (lastIndex >= 0 &&
+                    buffer instanceof MappedByteBuffer && nuSamples.get(lastIndex) instanceof MappedByteBuffer &&
+                    nuSamples.get(lastIndex).limit() == nuSamples.get(lastIndex).capacity() - buffer.capacity()) {
+                // This can go wrong - but will it?
+                ByteBuffer oldBuffer = nuSamples.get(lastIndex);
+                oldBuffer.limit(buffer.limit() + oldBuffer.limit());
+            } else {
+                nuSamples.add(buffer);
+            }
+        }
+        return nuSamples;
+    }
+}
diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/authoring/builder/.svn/text-base/FragmentIntersectionFinder.java.svn-base b/isoparser/src/main/java/com/googlecode/mp4parser/authoring/builder/.svn/text-base/FragmentIntersectionFinder.java.svn-base
new file mode 100644
index 0000000..1224bbf
--- /dev/null
+++ b/isoparser/src/main/java/com/googlecode/mp4parser/authoring/builder/.svn/text-base/FragmentIntersectionFinder.java.svn-base
@@ -0,0 +1,34 @@
+/*
+ * Copyright 2012 Sebastian Annies, Hamburg
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.googlecode.mp4parser.authoring.builder;
+
+import com.googlecode.mp4parser.authoring.Movie;
+import com.googlecode.mp4parser.authoring.Track;
+
+/**
+ *
+ */
+public interface FragmentIntersectionFinder {
+    /**
+     * Gets the ordinal number of the samples which will be the first sample
+     * in each fragment.
+     *
+     * @param track concerned track
+     * @param movie the context of the track
+     * @return an array containing the ordinal of each fragment's first sample
+     */
+    public long[] sampleNumbers(Track track, Movie movie);
+}
diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/authoring/builder/.svn/text-base/FragmentedMp4Builder.java.svn-base b/isoparser/src/main/java/com/googlecode/mp4parser/authoring/builder/.svn/text-base/FragmentedMp4Builder.java.svn-base
new file mode 100644
index 0000000..c65ff1c
--- /dev/null
+++ b/isoparser/src/main/java/com/googlecode/mp4parser/authoring/builder/.svn/text-base/FragmentedMp4Builder.java.svn-base
@@ -0,0 +1,742 @@
+/*
+ * Copyright 2012 Sebastian Annies, Hamburg
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.googlecode.mp4parser.authoring.builder;
+
+import com.coremedia.iso.BoxParser;
+import com.coremedia.iso.IsoFile;
+import com.coremedia.iso.IsoTypeWriter;
+import com.coremedia.iso.boxes.*;
+import com.coremedia.iso.boxes.fragment.*;
+import com.googlecode.mp4parser.authoring.DateHelper;
+import com.googlecode.mp4parser.authoring.Movie;
+import com.googlecode.mp4parser.authoring.Track;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.nio.channels.GatheringByteChannel;
+import java.nio.channels.ReadableByteChannel;
+import java.nio.channels.WritableByteChannel;
+import java.util.*;
+import java.util.logging.Logger;
+
+import static com.googlecode.mp4parser.util.CastUtils.l2i;
+
+/**
+ * Creates a fragmented MP4 file.
+ */
+public class FragmentedMp4Builder implements Mp4Builder {
+    private static final Logger LOG = Logger.getLogger(FragmentedMp4Builder.class.getName());
+
+    protected FragmentIntersectionFinder intersectionFinder;
+
+    public FragmentedMp4Builder() {
+        this.intersectionFinder = new SyncSampleIntersectFinderImpl();
+    }
+
+    public List<String> getAllowedHandlers() {
+        return Arrays.asList("soun", "vide");
+    }
+
+    public Box createFtyp(Movie movie) {
+        List<String> minorBrands = new LinkedList<String>();
+        minorBrands.add("isom");
+        minorBrands.add("iso2");
+        minorBrands.add("avc1");
+        return new FileTypeBox("isom", 0, minorBrands);
+    }
+
+    /**
+     * Some formats require sorting of the fragments. E.g. Ultraviolet CFF files are required
+     * to contain the fragments size sort:
+     * <ul>
+     * <li>video[1].getBytes().length < audio[1].getBytes().length < subs[1].getBytes().length</li>
+     * <li> audio[2].getBytes().length < video[2].getBytes().length < subs[2].getBytes().length</li>
+     * </ul>
+     *
+     * make this fragment:
+     *
+     * <ol>
+     *     <li>video[1]</li>
+     *     <li>audio[1]</li>
+     *     <li>subs[1]</li>
+     *     <li>audio[2]</li>
+     *     <li>video[2]</li>
+     *     <li>subs[2]</li>
+     * </ol>
+     *
+     * @param tracks the list of tracks to returned sorted
+     * @param cycle current fragment (sorting may vary between the fragments)
+     * @param intersectionMap a map from tracks to their fragments' first samples.
+     * @return the list of tracks in order of appearance in the fragment
+     */
+    protected List<Track> sortTracksInSequence(List<Track> tracks, final int cycle, final Map<Track, long[]> intersectionMap) {
+        tracks = new LinkedList<Track>(tracks);
+        Collections.sort(tracks, new Comparator<Track>() {
+            public int compare(Track o1, Track o2) {
+                long[] startSamples1 = intersectionMap.get(o1);
+                long startSample1 = startSamples1[cycle];
+                // one based sample numbers - the first sample is 1
+                long endSample1 = cycle + 1 < startSamples1.length ? startSamples1[cycle + 1] : o1.getSamples().size() + 1;
+                long[] startSamples2 = intersectionMap.get(o2);
+                long startSample2 = startSamples2[cycle];
+                // one based sample numbers - the first sample is 1
+                long endSample2 = cycle + 1 < startSamples2.length ? startSamples2[cycle + 1] : o2.getSamples().size() + 1;
+                List<ByteBuffer> samples1 = o1.getSamples().subList(l2i(startSample1) - 1, l2i(endSample1) - 1);
+                List<ByteBuffer> samples2 = o2.getSamples().subList(l2i(startSample2) - 1, l2i(endSample2) - 1);
+                int size1 = 0;
+                for (ByteBuffer byteBuffer : samples1) {
+                    size1 += byteBuffer.limit();
+                }
+                int size2 = 0;
+                for (ByteBuffer byteBuffer : samples2) {
+                    size2 += byteBuffer.limit();
+                }
+                return size1 - size2;
+            }
+        });
+        return tracks;
+    }
+
+    protected List<Box> createMoofMdat(final Movie movie) {
+        List<Box> boxes = new LinkedList<Box>();
+        HashMap<Track, long[]> intersectionMap = new HashMap<Track, long[]>();
+        int maxNumberOfFragments = 0;
+        for (Track track : movie.getTracks()) {
+            long[] intersects = intersectionFinder.sampleNumbers(track, movie);
+            intersectionMap.put(track, intersects);
+            maxNumberOfFragments = Math.max(maxNumberOfFragments, intersects.length);
+        }
+
+
+        int sequence = 1;
+        // this loop has two indices:
+
+        for (int cycle = 0; cycle < maxNumberOfFragments; cycle++) {
+
+            final List<Track> sortedTracks = sortTracksInSequence(movie.getTracks(), cycle, intersectionMap);
+
+            for (Track track : sortedTracks) {
+                if (getAllowedHandlers().isEmpty() || getAllowedHandlers().contains(track.getHandler())) {
+                    long[] startSamples = intersectionMap.get(track);
+                    //some tracks may have less fragments -> skip them
+                    if (cycle < startSamples.length) {
+
+                        long startSample = startSamples[cycle];
+                        // one based sample numbers - the first sample is 1
+                        long endSample = cycle + 1 < startSamples.length ? startSamples[cycle + 1] : track.getSamples().size() + 1;
+
+                        // if startSample == endSample the cycle is empty!
+                        if (startSample != endSample) {
+                            boxes.add(createMoof(startSample, endSample, track, sequence));
+                            boxes.add(createMdat(startSample, endSample, track, sequence++));
+                        }
+                    }
+                }
+            }
+        }
+        return boxes;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public IsoFile build(Movie movie) {
+        LOG.fine("Creating movie " + movie);
+        IsoFile isoFile = new IsoFile();
+
+
+        isoFile.addBox(createFtyp(movie));
+        isoFile.addBox(createMoov(movie));
+
+        for (Box box : createMoofMdat(movie)) {
+            isoFile.addBox(box);
+        }
+        isoFile.addBox(createMfra(movie, isoFile));
+
+        return isoFile;
+    }
+
+    protected Box createMdat(final long startSample, final long endSample, final Track track, final int i) {
+
+        class Mdat implements Box {
+            ContainerBox parent;
+
+            public ContainerBox getParent() {
+                return parent;
+            }
+
+            public void setParent(ContainerBox parent) {
+                this.parent = parent;
+            }
+
+            public long getSize() {
+                long size = 8; // I don't expect 2gig fragments
+                for (ByteBuffer sample : getSamples(startSample, endSample, track, i)) {
+                    size += sample.limit();
+                }
+                return size;
+            }
+
+            public String getType() {
+                return "mdat";
+            }
+
+            public void getBox(WritableByteChannel writableByteChannel) throws IOException {
+                List<ByteBuffer> bbs = getSamples(startSample, endSample, track, i);
+                final List<ByteBuffer> samples = ByteBufferHelper.mergeAdjacentBuffers(bbs);
+                ByteBuffer header = ByteBuffer.allocate(8);
+                IsoTypeWriter.writeUInt32(header, l2i(getSize()));
+                header.put(IsoFile.fourCCtoBytes(getType()));
+                header.rewind();
+                writableByteChannel.write(header);
+                if (writableByteChannel instanceof GatheringByteChannel) {
+
+                    int STEPSIZE = 1024;
+                    // This is required to prevent android from crashing
+                    // it seems that {@link GatheringByteChannel#write(java.nio.ByteBuffer[])}
+                    // just handles up to 1024 buffers
+                    for (int i = 0; i < Math.ceil((double) samples.size() / STEPSIZE); i++) {
+                        List<ByteBuffer> sublist = samples.subList(
+                                i * STEPSIZE, // start
+                                (i + 1) * STEPSIZE < samples.size() ? (i + 1) * STEPSIZE : samples.size()); // end
+                        ByteBuffer sampleArray[] = sublist.toArray(new ByteBuffer[sublist.size()]);
+                        do {
+                            ((GatheringByteChannel) writableByteChannel).write(sampleArray);
+                        } while (sampleArray[sampleArray.length - 1].remaining() > 0);
+                    }
+                    //System.err.println(bytesWritten);
+                } else {
+                    for (ByteBuffer sample : samples) {
+                        sample.rewind();
+                        writableByteChannel.write(sample);
+                    }
+                }
+
+            }
+
+            public void parse(ReadableByteChannel readableByteChannel, ByteBuffer header, long contentSize, BoxParser boxParser) throws IOException {
+
+            }
+        }
+
+        return new Mdat();
+    }
+
+    protected Box createTfhd(long startSample, long endSample, Track track, int sequenceNumber) {
+        TrackFragmentHeaderBox tfhd = new TrackFragmentHeaderBox();
+        SampleFlags sf = new SampleFlags();
+
+        tfhd.setDefaultSampleFlags(sf);
+        tfhd.setBaseDataOffset(-1);
+        tfhd.setTrackId(track.getTrackMetaData().getTrackId());
+        return tfhd;
+    }
+
+    protected Box createMfhd(long startSample, long endSample, Track track, int sequenceNumber) {
+        MovieFragmentHeaderBox mfhd = new MovieFragmentHeaderBox();
+        mfhd.setSequenceNumber(sequenceNumber);
+        return mfhd;
+    }
+
+    protected Box createTraf(long startSample, long endSample, Track track, int sequenceNumber) {
+        TrackFragmentBox traf = new TrackFragmentBox();
+        traf.addBox(createTfhd(startSample, endSample, track, sequenceNumber));
+        for (Box trun : createTruns(startSample, endSample, track, sequenceNumber)) {
+            traf.addBox(trun);
+        }
+
+        return traf;
+    }
+
+
+    /**
+     * Gets the all samples starting with <code>startSample</code> (one based -> one is the first) and
+     * ending with <code>endSample</code> (exclusive).
+     *
+     * @param startSample    low endpoint (inclusive) of the sample sequence
+     * @param endSample      high endpoint (exclusive) of the sample sequence
+     * @param track          source of the samples
+     * @param sequenceNumber the fragment index of the requested list of samples
+     * @return a <code>List&lt;ByteBuffer></code> of raw samples
+     */
+    protected List<ByteBuffer> getSamples(long startSample, long endSample, Track track, int sequenceNumber) {
+        // since startSample and endSample are one-based substract 1 before addressing list elements
+        return track.getSamples().subList(l2i(startSample) - 1, l2i(endSample) - 1);
+    }
+
+    /**
+     * Gets the sizes of a sequence of samples-
+     *
+     * @param startSample    low endpoint (inclusive) of the sample sequence
+     * @param endSample      high endpoint (exclusive) of the sample sequence
+     * @param track          source of the samples
+     * @param sequenceNumber the fragment index of the requested list of samples
+     * @return
+     */
+    protected long[] getSampleSizes(long startSample, long endSample, Track track, int sequenceNumber) {
+        List<ByteBuffer> samples = getSamples(startSample, endSample, track, sequenceNumber);
+
+        long[] sampleSizes = new long[samples.size()];
+        for (int i = 0; i < sampleSizes.length; i++) {
+            sampleSizes[i] = samples.get(i).limit();
+        }
+        return sampleSizes;
+    }
+
+    /**
+     * Creates one or more track run boxes for a given sequence.
+     *
+     * @param startSample    low endpoint (inclusive) of the sample sequence
+     * @param endSample      high endpoint (exclusive) of the sample sequence
+     * @param track          source of the samples
+     * @param sequenceNumber the fragment index of the requested list of samples
+     * @return the list of TrackRun boxes.
+     */
+    protected List<? extends Box> createTruns(long startSample, long endSample, Track track, int sequenceNumber) {
+        TrackRunBox trun = new TrackRunBox();
+        long[] sampleSizes = getSampleSizes(startSample, endSample, track, sequenceNumber);
+
+        trun.setSampleDurationPresent(true);
+        trun.setSampleSizePresent(true);
+        List<TrackRunBox.Entry> entries = new ArrayList<TrackRunBox.Entry>(l2i(endSample - startSample));
+
+
+        Queue<TimeToSampleBox.Entry> timeQueue = new LinkedList<TimeToSampleBox.Entry>(track.getDecodingTimeEntries());
+        long left = startSample - 1;
+        long curEntryLeft = timeQueue.peek().getCount();
+        while (left > curEntryLeft) {
+            left -= curEntryLeft;
+            timeQueue.remove();
+            curEntryLeft = timeQueue.peek().getCount();
+        }
+        curEntryLeft -= left;
+
+
+        Queue<CompositionTimeToSample.Entry> compositionTimeQueue =
+                track.getCompositionTimeEntries() != null && track.getCompositionTimeEntries().size() > 0 ?
+                        new LinkedList<CompositionTimeToSample.Entry>(track.getCompositionTimeEntries()) : null;
+        long compositionTimeEntriesLeft = compositionTimeQueue != null ? compositionTimeQueue.peek().getCount() : -1;
+
+
+        trun.setSampleCompositionTimeOffsetPresent(compositionTimeEntriesLeft > 0);
+
+        // fast forward composition stuff
+        for (long i = 1; i < startSample; i++) {
+            if (compositionTimeQueue != null) {
+                //trun.setSampleCompositionTimeOffsetPresent(true);
+                if (--compositionTimeEntriesLeft == 0 && compositionTimeQueue.size() > 1) {
+                    compositionTimeQueue.remove();
+                    compositionTimeEntriesLeft = compositionTimeQueue.element().getCount();
+                }
+            }
+        }
+
+        boolean sampleFlagsRequired = (track.getSampleDependencies() != null && !track.getSampleDependencies().isEmpty() ||
+                track.getSyncSamples() != null && track.getSyncSamples().length != 0);
+
+        trun.setSampleFlagsPresent(sampleFlagsRequired);
+
+        for (int i = 0; i < sampleSizes.length; i++) {
+            TrackRunBox.Entry entry = new TrackRunBox.Entry();
+            entry.setSampleSize(sampleSizes[i]);
+            if (sampleFlagsRequired) {
+                //if (false) {
+                SampleFlags sflags = new SampleFlags();
+
+                if (track.getSampleDependencies() != null && !track.getSampleDependencies().isEmpty()) {
+                    SampleDependencyTypeBox.Entry e = track.getSampleDependencies().get(i);
+                    sflags.setSampleDependsOn(e.getSampleDependsOn());
+                    sflags.setSampleIsDependedOn(e.getSampleIsDependentOn());
+                    sflags.setSampleHasRedundancy(e.getSampleHasRedundancy());
+                }
+                if (track.getSyncSamples() != null && track.getSyncSamples().length > 0) {
+                    // we have to mark non-sync samples!
+                    if (Arrays.binarySearch(track.getSyncSamples(), startSample + i) >= 0) {
+                        sflags.setSampleIsDifferenceSample(false);
+                        sflags.setSampleDependsOn(2);
+                    } else {
+                        sflags.setSampleIsDifferenceSample(true);
+                        sflags.setSampleDependsOn(1);
+                    }
+                }
+                // i don't have sample degradation
+                entry.setSampleFlags(sflags);
+
+            }
+
+            entry.setSampleDuration(timeQueue.peek().getDelta());
+            if (--curEntryLeft == 0 && timeQueue.size() > 1) {
+                timeQueue.remove();
+                curEntryLeft = timeQueue.peek().getCount();
+            }
+
+            if (compositionTimeQueue != null) {
+                entry.setSampleCompositionTimeOffset(compositionTimeQueue.peek().getOffset());
+                if (--compositionTimeEntriesLeft == 0 && compositionTimeQueue.size() > 1) {
+                    compositionTimeQueue.remove();
+                    compositionTimeEntriesLeft = compositionTimeQueue.element().getCount();
+                }
+            }
+            entries.add(entry);
+        }
+
+        trun.setEntries(entries);
+
+        return Collections.singletonList(trun);
+    }
+
+    /**
+     * Creates a 'moof' box for a given sequence of samples.
+     *
+     * @param startSample    low endpoint (inclusive) of the sample sequence
+     * @param endSample      high endpoint (exclusive) of the sample sequence
+     * @param track          source of the samples
+     * @param sequenceNumber the fragment index of the requested list of samples
+     * @return the list of TrackRun boxes.
+     */
+    protected Box createMoof(long startSample, long endSample, Track track, int sequenceNumber) {
+        MovieFragmentBox moof = new MovieFragmentBox();
+        moof.addBox(createMfhd(startSample, endSample, track, sequenceNumber));
+        moof.addBox(createTraf(startSample, endSample, track, sequenceNumber));
+
+        TrackRunBox firstTrun = moof.getTrackRunBoxes().get(0);
+        firstTrun.setDataOffset(1); // dummy to make size correct
+        firstTrun.setDataOffset((int) (8 + moof.getSize())); // mdat header + moof size
+
+        return moof;
+    }
+
+    /**
+     * Creates a single 'mvhd' movie header box for a given movie.
+     *
+     * @param movie the concerned movie
+     * @return an 'mvhd' box
+     */
+    protected Box createMvhd(Movie movie) {
+        MovieHeaderBox mvhd = new MovieHeaderBox();
+        mvhd.setVersion(1);
+        mvhd.setCreationTime(DateHelper.convert(new Date()));
+        mvhd.setModificationTime(DateHelper.convert(new Date()));
+        long movieTimeScale = movie.getTimescale();
+        long duration = 0;
+
+        for (Track track : movie.getTracks()) {
+            long tracksDuration = getDuration(track) * movieTimeScale / track.getTrackMetaData().getTimescale();
+            if (tracksDuration > duration) {
+                duration = tracksDuration;
+            }
+
+
+        }
+
+        mvhd.setDuration(duration);
+        mvhd.setTimescale(movieTimeScale);
+        // find the next available trackId
+        long nextTrackId = 0;
+        for (Track track : movie.getTracks()) {
+            nextTrackId = nextTrackId < track.getTrackMetaData().getTrackId() ? track.getTrackMetaData().getTrackId() : nextTrackId;
+        }
+        mvhd.setNextTrackId(++nextTrackId);
+        return mvhd;
+    }
+
+    /**
+     * Creates a fully populated 'moov' box with all child boxes. Child boxes are:
+     * <ul>
+     * <li>{@link #createMvhd(com.googlecode.mp4parser.authoring.Movie) mvhd}</li>
+     * <li>{@link #createMvex(com.googlecode.mp4parser.authoring.Movie)  mvex}</li>
+     * <li>a {@link #createTrak(com.googlecode.mp4parser.authoring.Track, com.googlecode.mp4parser.authoring.Movie)  trak} for every track</li>
+     * </ul>
+     *
+     * @param movie the concerned movie
+     * @return fully populated 'moov'
+     */
+    protected Box createMoov(Movie movie) {
+        MovieBox movieBox = new MovieBox();
+
+        movieBox.addBox(createMvhd(movie));
+        movieBox.addBox(createMvex(movie));
+
+        for (Track track : movie.getTracks()) {
+            movieBox.addBox(createTrak(track, movie));
+        }
+        // metadata here
+        return movieBox;
+
+    }
+
+    /**
+     * Creates a 'tfra' - track fragment random access box for the given track with the isoFile.
+     * The tfra contains a map of random access points with time as key and offset within the isofile
+     * as value.
+     *
+     * @param track   the concerned track
+     * @param isoFile the track is contained in
+     * @return a track fragment random access box.
+     */
+    protected Box createTfra(Track track, IsoFile isoFile) {
+        TrackFragmentRandomAccessBox tfra = new TrackFragmentRandomAccessBox();
+        tfra.setVersion(1); // use long offsets and times
+        List<TrackFragmentRandomAccessBox.Entry> offset2timeEntries = new LinkedList<TrackFragmentRandomAccessBox.Entry>();
+        List<Box> boxes = isoFile.getBoxes();
+        long offset = 0;
+        long duration = 0;
+        for (Box box : boxes) {
+            if (box instanceof MovieFragmentBox) {
+                List<TrackFragmentBox> trafs = ((MovieFragmentBox) box).getBoxes(TrackFragmentBox.class);
+                for (int i = 0; i < trafs.size(); i++) {
+                    TrackFragmentBox traf = trafs.get(i);
+                    if (traf.getTrackFragmentHeaderBox().getTrackId() == track.getTrackMetaData().getTrackId()) {
+                        // here we are at the offset required for the current entry.
+                        List<TrackRunBox> truns = traf.getBoxes(TrackRunBox.class);
+                        for (int j = 0; j < truns.size(); j++) {
+                            List<TrackFragmentRandomAccessBox.Entry> offset2timeEntriesThisTrun = new LinkedList<TrackFragmentRandomAccessBox.Entry>();
+                            TrackRunBox trun = truns.get(j);
+                            for (int k = 0; k < trun.getEntries().size(); k++) {
+                                TrackRunBox.Entry trunEntry = trun.getEntries().get(k);
+                                SampleFlags sf = null;
+                                if (k == 0 && trun.isFirstSampleFlagsPresent()) {
+                                    sf = trun.getFirstSampleFlags();
+                                } else if (trun.isSampleFlagsPresent()) {
+                                    sf = trunEntry.getSampleFlags();
+                                } else {
+                                    List<MovieExtendsBox> mvexs = isoFile.getMovieBox().getBoxes(MovieExtendsBox.class);
+                                    for (MovieExtendsBox mvex : mvexs) {
+                                        List<TrackExtendsBox> trexs = mvex.getBoxes(TrackExtendsBox.class);
+                                        for (TrackExtendsBox trex : trexs) {
+                                            if (trex.getTrackId() == track.getTrackMetaData().getTrackId()) {
+                                                sf = trex.getDefaultSampleFlags();
+                                            }
+                                        }
+                                    }
+
+                                }
+                                if (sf == null) {
+                                    throw new RuntimeException("Could not find any SampleFlags to indicate random access or not");
+                                }
+                                if (sf.getSampleDependsOn() == 2) {
+                                    offset2timeEntriesThisTrun.add(new TrackFragmentRandomAccessBox.Entry(
+                                            duration,
+                                            offset,
+                                            i + 1, j + 1, k + 1));
+                                }
+                                duration += trunEntry.getSampleDuration();
+                            }
+                            if (offset2timeEntriesThisTrun.size() == trun.getEntries().size() && trun.getEntries().size() > 0) {
+                                // Oooops every sample seems to be random access sample
+                                // is this an audio track? I don't care.
+                                // I just use the first for trun sample for tfra random access
+                                offset2timeEntries.add(offset2timeEntriesThisTrun.get(0));
+                            } else {
+                                offset2timeEntries.addAll(offset2timeEntriesThisTrun);
+                            }
+                        }
+                    }
+                }
+            }
+
+
+            offset += box.getSize();
+        }
+        tfra.setEntries(offset2timeEntries);
+        tfra.setTrackId(track.getTrackMetaData().getTrackId());
+        return tfra;
+    }
+
+    /**
+     * Creates a 'mfra' - movie fragment random access box for the given movie in the given
+     * isofile. Uses {@link #createTfra(com.googlecode.mp4parser.authoring.Track, com.coremedia.iso.IsoFile)}
+     * to generate the child boxes.
+     *
+     * @param movie   concerned movie
+     * @param isoFile concerned isofile
+     * @return a complete 'mfra' box
+     */
+    protected Box createMfra(Movie movie, IsoFile isoFile) {
+        MovieFragmentRandomAccessBox mfra = new MovieFragmentRandomAccessBox();
+        for (Track track : movie.getTracks()) {
+            mfra.addBox(createTfra(track, isoFile));
+        }
+
+        MovieFragmentRandomAccessOffsetBox mfro = new MovieFragmentRandomAccessOffsetBox();
+        mfra.addBox(mfro);
+        mfro.setMfraSize(mfra.getSize());
+        return mfra;
+    }
+
+    protected Box createTrex(Movie movie, Track track) {
+        TrackExtendsBox trex = new TrackExtendsBox();
+        trex.setTrackId(track.getTrackMetaData().getTrackId());
+        trex.setDefaultSampleDescriptionIndex(1);
+        trex.setDefaultSampleDuration(0);
+        trex.setDefaultSampleSize(0);
+        SampleFlags sf = new SampleFlags();
+        if ("soun".equals(track.getHandler())) {
+            // as far as I know there is no audio encoding
+            // where the sample are not self contained.
+            sf.setSampleDependsOn(2);
+            sf.setSampleIsDependedOn(2);
+        }
+        trex.setDefaultSampleFlags(sf);
+        return trex;
+    }
+
+    /**
+     * Creates a 'mvex' - movie extends box and populates it with 'trex' boxes
+     * by calling {@link #createTrex(com.googlecode.mp4parser.authoring.Movie, com.googlecode.mp4parser.authoring.Track)}
+     * for each track to generate them
+     *
+     * @param movie the source movie
+     * @return a complete 'mvex'
+     */
+    protected Box createMvex(Movie movie) {
+        MovieExtendsBox mvex = new MovieExtendsBox();
+        final MovieExtendsHeaderBox mved = new MovieExtendsHeaderBox();
+        for (Track track : movie.getTracks()) {
+            final long trackDuration = getTrackDuration(movie, track);
+            if (mved.getFragmentDuration() < trackDuration) {
+                mved.setFragmentDuration(trackDuration);
+            }
+        }
+        mvex.addBox(mved);
+
+        for (Track track : movie.getTracks()) {
+            mvex.addBox(createTrex(movie, track));
+        }
+        return mvex;
+    }
+
+    protected Box createTkhd(Movie movie, Track track) {
+        TrackHeaderBox tkhd = new TrackHeaderBox();
+        tkhd.setVersion(1);
+        int flags = 0;
+        if (track.isEnabled()) {
+            flags += 1;
+        }
+
+        if (track.isInMovie()) {
+            flags += 2;
+        }
+
+        if (track.isInPreview()) {
+            flags += 4;
+        }
+
+        if (track.isInPoster()) {
+            flags += 8;
+        }
+        tkhd.setFlags(flags);
+
+        tkhd.setAlternateGroup(track.getTrackMetaData().getGroup());
+        tkhd.setCreationTime(DateHelper.convert(track.getTrackMetaData().getCreationTime()));
+        // We need to take edit list box into account in trackheader duration
+        // but as long as I don't support edit list boxes it is sufficient to
+        // just translate media duration to movie timescale
+        tkhd.setDuration(getTrackDuration(movie, track));
+        tkhd.setHeight(track.getTrackMetaData().getHeight());
+        tkhd.setWidth(track.getTrackMetaData().getWidth());
+        tkhd.setLayer(track.getTrackMetaData().getLayer());
+        tkhd.setModificationTime(DateHelper.convert(new Date()));
+        tkhd.setTrackId(track.getTrackMetaData().getTrackId());
+        tkhd.setVolume(track.getTrackMetaData().getVolume());
+        return tkhd;
+    }
+
+    private long getTrackDuration(Movie movie, Track track) {
+        return getDuration(track) * movie.getTimescale() / track.getTrackMetaData().getTimescale();
+    }
+
+    protected Box createMdhd(Movie movie, Track track) {
+        MediaHeaderBox mdhd = new MediaHeaderBox();
+        mdhd.setCreationTime(DateHelper.convert(track.getTrackMetaData().getCreationTime()));
+        mdhd.setDuration(getDuration(track));
+        mdhd.setTimescale(track.getTrackMetaData().getTimescale());
+        mdhd.setLanguage(track.getTrackMetaData().getLanguage());
+        return mdhd;
+    }
+
+    protected Box createStbl(Movie movie, Track track) {
+        SampleTableBox stbl = new SampleTableBox();
+
+        stbl.addBox(track.getSampleDescriptionBox());
+        stbl.addBox(new TimeToSampleBox());
+        //stbl.addBox(new SampleToChunkBox());
+        stbl.addBox(new StaticChunkOffsetBox());
+        return stbl;
+    }
+
+    protected Box createMinf(Track track, Movie movie) {
+        MediaInformationBox minf = new MediaInformationBox();
+        minf.addBox(track.getMediaHeaderBox());
+        minf.addBox(createDinf(movie, track));
+        minf.addBox(createStbl(movie, track));
+        return minf;
+    }
+
+    protected Box createMdiaHdlr(Track track, Movie movie) {
+        HandlerBox hdlr = new HandlerBox();
+        hdlr.setHandlerType(track.getHandler());
+        return hdlr;
+    }
+
+    protected Box createMdia(Track track, Movie movie) {
+        MediaBox mdia = new MediaBox();
+        mdia.addBox(createMdhd(movie, track));
+
+
+        mdia.addBox(createMdiaHdlr(track, movie));
+
+
+        mdia.addBox(createMinf(track, movie));
+        return mdia;
+    }
+
+    protected Box createTrak(Track track, Movie movie) {
+        LOG.fine("Creating Track " + track);
+        TrackBox trackBox = new TrackBox();
+        trackBox.addBox(createTkhd(movie, track));
+        trackBox.addBox(createMdia(track, movie));
+        return trackBox;
+    }
+
+    protected DataInformationBox createDinf(Movie movie, Track track) {
+        DataInformationBox dinf = new DataInformationBox();
+        DataReferenceBox dref = new DataReferenceBox();
+        dinf.addBox(dref);
+        DataEntryUrlBox url = new DataEntryUrlBox();
+        url.setFlags(1);
+        dref.addBox(url);
+        return dinf;
+    }
+
+    public FragmentIntersectionFinder getFragmentIntersectionFinder() {
+        return intersectionFinder;
+    }
+
+    public void setIntersectionFinder(FragmentIntersectionFinder intersectionFinder) {
+        this.intersectionFinder = intersectionFinder;
+    }
+
+    protected long getDuration(Track track) {
+        long duration = 0;
+        for (TimeToSampleBox.Entry entry : track.getDecodingTimeEntries()) {
+            duration += entry.getCount() * entry.getDelta();
+        }
+        return duration;
+    }
+
+
+}
diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/authoring/builder/.svn/text-base/Mp4Builder.java.svn-base b/isoparser/src/main/java/com/googlecode/mp4parser/authoring/builder/.svn/text-base/Mp4Builder.java.svn-base
new file mode 100644
index 0000000..725745e
--- /dev/null
+++ b/isoparser/src/main/java/com/googlecode/mp4parser/authoring/builder/.svn/text-base/Mp4Builder.java.svn-base
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2012 Sebastian Annies, Hamburg
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.googlecode.mp4parser.authoring.builder;
+
+import com.coremedia.iso.IsoFile;
+import com.googlecode.mp4parser.authoring.Movie;
+
+/**
+ * Transforms a <code>Movie</code> object to an IsoFile. Implementations can
+ * determine the specific format: Fragmented MP4, MP4, MP4 with Apple Metadata,
+ * MP4 with 3GPP Metadata, MOV.
+ */
+public interface Mp4Builder {
+    /**
+     * Builds the actual IsoFile from the Movie.
+     *
+     * @param movie data source
+     * @return the freshly built IsoFile
+     */
+    public IsoFile build(Movie movie);
+
+}
diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/authoring/builder/.svn/text-base/SyncSampleIntersectFinderImpl.java.svn-base b/isoparser/src/main/java/com/googlecode/mp4parser/authoring/builder/.svn/text-base/SyncSampleIntersectFinderImpl.java.svn-base
new file mode 100644
index 0000000..2766c5e
--- /dev/null
+++ b/isoparser/src/main/java/com/googlecode/mp4parser/authoring/builder/.svn/text-base/SyncSampleIntersectFinderImpl.java.svn-base
@@ -0,0 +1,334 @@
+/*
+ * Copyright 2012 Sebastian Annies, Hamburg
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.googlecode.mp4parser.authoring.builder;
+
+import com.coremedia.iso.boxes.TimeToSampleBox;
+import com.coremedia.iso.boxes.sampleentry.AudioSampleEntry;
+import com.googlecode.mp4parser.authoring.Movie;
+import com.googlecode.mp4parser.authoring.Track;
+
+import java.util.*;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.logging.Logger;
+
+import static com.googlecode.mp4parser.util.Math.lcm;
+
+/**
+ * This <code>FragmentIntersectionFinder</code> cuts the input movie video tracks in
+ * fragments of the same length exactly before the sync samples. Audio tracks are cut
+ * into pieces of similar length.
+ */
+public class SyncSampleIntersectFinderImpl implements FragmentIntersectionFinder {
+
+    private static Logger LOG = Logger.getLogger(SyncSampleIntersectFinderImpl.class.getName());
+    private static Map<CacheTuple, long[]> getTimesCache = new ConcurrentHashMap<CacheTuple, long[]>();
+    private static Map<CacheTuple, long[]> getSampleNumbersCache = new ConcurrentHashMap<CacheTuple, long[]>();
+
+    private final int minFragmentDurationSeconds;
+
+    public SyncSampleIntersectFinderImpl() {
+        minFragmentDurationSeconds = 0;
+    }
+
+    /**
+     * Creates a <code>SyncSampleIntersectFinderImpl</code> that will not create any fragment
+     * smaller than the given <code>minFragmentDurationSeconds</code>
+     *
+     * @param minFragmentDurationSeconds the smallest allowable duration of a fragment.
+     */
+    public SyncSampleIntersectFinderImpl(int minFragmentDurationSeconds) {
+        this.minFragmentDurationSeconds = minFragmentDurationSeconds;
+    }
+
+    /**
+     * Gets an array of sample numbers that are meant to be the first sample of each
+     * chunk or fragment.
+     *
+     * @param track concerned track
+     * @param movie the context of the track
+     * @return an array containing the ordinal of each fragment's first sample
+     */
+    public long[] sampleNumbers(Track track, Movie movie) {
+        final CacheTuple key = new CacheTuple(track, movie);
+        final long[] result = getSampleNumbersCache.get(key);
+        if (result != null) {
+            return result;
+        }
+
+        if ("vide".equals(track.getHandler())) {
+            if (track.getSyncSamples() != null && track.getSyncSamples().length > 0) {
+                List<long[]> times = getSyncSamplesTimestamps(movie, track);
+                final long[] commonIndices = getCommonIndices(track.getSyncSamples(), getTimes(track, movie), track.getTrackMetaData().getTimescale(), times.toArray(new long[times.size()][]));
+                getSampleNumbersCache.put(key, commonIndices);
+                return commonIndices;
+            } else {
+                throw new RuntimeException("Video Tracks need sync samples. Only tracks other than video may have no sync samples.");
+            }
+        } else if ("soun".equals(track.getHandler())) {
+            Track referenceTrack = null;
+            for (Track candidate : movie.getTracks()) {
+                if (candidate.getSyncSamples() != null && "vide".equals(candidate.getHandler()) && candidate.getSyncSamples().length > 0) {
+                    referenceTrack = candidate;
+                }
+            }
+            if (referenceTrack != null) {
+
+                // Gets the reference track's fra
+                long[] refSyncSamples = sampleNumbers(referenceTrack, movie);
+
+                int refSampleCount = referenceTrack.getSamples().size();
+
+                long[] syncSamples = new long[refSyncSamples.length];
+                long minSampleRate = 192000;
+                for (Track testTrack : movie.getTracks()) {
+                    if ("soun".equals(testTrack.getHandler())) {
+                        AudioSampleEntry ase = (AudioSampleEntry) testTrack.getSampleDescriptionBox().getSampleEntry();
+                        if (ase.getSampleRate() < minSampleRate) {
+                            minSampleRate = ase.getSampleRate();
+                            long sc = testTrack.getSamples().size();
+                            double stretch = (double) sc / refSampleCount;
+                            TimeToSampleBox.Entry sttsEntry = testTrack.getDecodingTimeEntries().get(0);
+                            long samplesPerFrame = sttsEntry.getDelta(); // Assuming all audio tracks have the same number of samples per frame, which they do for all known types
+
+                            for (int i = 0; i < syncSamples.length; i++) {
+                                long start = (long) Math.ceil(stretch * (refSyncSamples[i] - 1) * samplesPerFrame);
+                                syncSamples[i] = start;
+                                // The Stretch makes sure that there are as much audio and video chunks!
+                            }
+                            break;
+                        }
+                    }
+                }
+                AudioSampleEntry ase = (AudioSampleEntry) track.getSampleDescriptionBox().getSampleEntry();
+                TimeToSampleBox.Entry sttsEntry = track.getDecodingTimeEntries().get(0);
+                long samplesPerFrame = sttsEntry.getDelta(); // Assuming all audio tracks have the same number of samples per frame, which they do for all known types
+                double factor = (double) ase.getSampleRate() / (double) minSampleRate;
+                if (factor != Math.rint(factor)) { // Not an integer
+                    throw new RuntimeException("Sample rates must be a multiple of the lowest sample rate to create a correct file!");
+                }
+                for (int i = 0; i < syncSamples.length; i++) {
+                    syncSamples[i] = (long) (1 + syncSamples[i] * factor / (double) samplesPerFrame);
+                }
+                getSampleNumbersCache.put(key, syncSamples);
+                return syncSamples;
+            }
+            throw new RuntimeException("There was absolutely no Track with sync samples. I can't work with that!");
+        } else {
+            // Ok, my track has no sync samples - let's find one with sync samples.
+            for (Track candidate : movie.getTracks()) {
+                if (candidate.getSyncSamples() != null && candidate.getSyncSamples().length > 0) {
+                    long[] refSyncSamples = sampleNumbers(candidate, movie);
+                    int refSampleCount = candidate.getSamples().size();
+
+                    long[] syncSamples = new long[refSyncSamples.length];
+                    long sc = track.getSamples().size();
+                    double stretch = (double) sc / refSampleCount;
+
+                    for (int i = 0; i < syncSamples.length; i++) {
+                        long start = (long) Math.ceil(stretch * (refSyncSamples[i] - 1)) + 1;
+                        syncSamples[i] = start;
+                        // The Stretch makes sure that there are as much audio and video chunks!
+                    }
+                    getSampleNumbersCache.put(key, syncSamples);
+                    return syncSamples;
+                }
+            }
+            throw new RuntimeException("There was absolutely no Track with sync samples. I can't work with that!");
+        }
+
+
+    }
+
+    /**
+     * Calculates the timestamp of all tracks' sync samples.
+     *
+     * @param movie
+     * @param track
+     * @return
+     */
+    public static List<long[]> getSyncSamplesTimestamps(Movie movie, Track track) {
+        List<long[]> times = new LinkedList<long[]>();
+        for (Track currentTrack : movie.getTracks()) {
+            if (currentTrack.getHandler().equals(track.getHandler())) {
+                long[] currentTrackSyncSamples = currentTrack.getSyncSamples();
+                if (currentTrackSyncSamples != null && currentTrackSyncSamples.length > 0) {
+                    final long[] currentTrackTimes = getTimes(currentTrack, movie);
+                    times.add(currentTrackTimes);
+                }
+            }
+        }
+        return times;
+    }
+
+    public long[] getCommonIndices(long[] syncSamples, long[] syncSampleTimes, long timeScale, long[]... otherTracksTimes) {
+        List<Long> nuSyncSamples = new LinkedList<Long>();
+        List<Long> nuSyncSampleTimes = new LinkedList<Long>();
+
+
+        for (int i = 0; i < syncSampleTimes.length; i++) {
+            boolean foundInEveryRef = true;
+            for (long[] times : otherTracksTimes) {
+                foundInEveryRef &= (Arrays.binarySearch(times, syncSampleTimes[i]) >= 0);
+            }
+
+            if (foundInEveryRef) {
+                // use sample only if found in every other track.
+                nuSyncSamples.add(syncSamples[i]);
+                nuSyncSampleTimes.add(syncSampleTimes[i]);
+            }
+        }
+        // We have two arrays now:
+        // nuSyncSamples: Contains all common sync samples
+        // nuSyncSampleTimes: Contains the times of all sync samples
+
+        // Start: Warn user if samples are not matching!
+        if (nuSyncSamples.size() < (syncSamples.length * 0.25)) {
+            String log = "";
+            log += String.format("%5d - Common:  [", nuSyncSamples.size());
+            for (long l : nuSyncSamples) {
+                log += (String.format("%10d,", l));
+            }
+            log += ("]");
+            LOG.warning(log);
+            log = "";
+
+            log += String.format("%5d - In    :  [", syncSamples.length);
+            for (long l : syncSamples) {
+                log += (String.format("%10d,", l));
+            }
+            log += ("]");
+            LOG.warning(log);
+            LOG.warning("There are less than 25% of common sync samples in the given track.");
+            throw new RuntimeException("There are less than 25% of common sync samples in the given track.");
+        } else if (nuSyncSamples.size() < (syncSamples.length * 0.5)) {
+            LOG.fine("There are less than 50% of common sync samples in the given track. This is implausible but I'm ok to continue.");
+        } else if (nuSyncSamples.size() < syncSamples.length) {
+            LOG.finest("Common SyncSample positions vs. this tracks SyncSample positions: " + nuSyncSamples.size() + " vs. " + syncSamples.length);
+        }
+        // End: Warn user if samples are not matching!
+
+
+
+
+        List<Long> finalSampleList = new LinkedList<Long>();
+
+        if (minFragmentDurationSeconds > 0) {
+            // if minFragmentDurationSeconds is greater 0
+            // we need to throw away certain samples.
+            long lastSyncSampleTime = -1;
+            Iterator<Long> nuSyncSamplesIterator = nuSyncSamples.iterator();
+            Iterator<Long> nuSyncSampleTimesIterator = nuSyncSampleTimes.iterator();
+            while (nuSyncSamplesIterator.hasNext() && nuSyncSampleTimesIterator.hasNext()) {
+                long curSyncSample = nuSyncSamplesIterator.next();
+                long curSyncSampleTime = nuSyncSampleTimesIterator.next();
+                if (lastSyncSampleTime == -1 || (curSyncSampleTime - lastSyncSampleTime) / timeScale >= minFragmentDurationSeconds) {
+                    finalSampleList.add(curSyncSample);
+                    lastSyncSampleTime = curSyncSampleTime;
+                }
+            }
+        } else {
+            // the list of all samples is the final list of samples
+            // since minFragmentDurationSeconds ist not used.
+            finalSampleList = nuSyncSamples;
+        }
+
+
+        // transform the list to an array
+        long[] finalSampleArray = new long[finalSampleList.size()];
+        for (int i = 0; i < finalSampleArray.length; i++) {
+            finalSampleArray[i] = finalSampleList.get(i);
+        }
+        return finalSampleArray;
+
+    }
+
+
+    private static long[] getTimes(Track track, Movie m) {
+        final CacheTuple key = new CacheTuple(track, m);
+        final long[] result = getTimesCache.get(key);
+        if (result != null) {
+            return result;
+        }
+
+        long[] syncSamples = track.getSyncSamples();
+        long[] syncSampleTimes = new long[syncSamples.length];
+        Queue<TimeToSampleBox.Entry> timeQueue = new LinkedList<TimeToSampleBox.Entry>(track.getDecodingTimeEntries());
+
+        int currentSample = 1;  // first syncsample is 1
+        long currentDuration = 0;
+        long currentDelta = 0;
+        int currentSyncSampleIndex = 0;
+        long left = 0;
+
+        final long scalingFactor = calculateTracktimesScalingFactor(m, track);
+
+        while (currentSample <= syncSamples[syncSamples.length - 1]) {
+            if (currentSample++ == syncSamples[currentSyncSampleIndex]) {
+                syncSampleTimes[currentSyncSampleIndex++] = currentDuration * scalingFactor;
+            }
+            if (left-- == 0) {
+                TimeToSampleBox.Entry entry = timeQueue.poll();
+                left = entry.getCount() - 1;
+                currentDelta = entry.getDelta();
+            }
+            currentDuration += currentDelta;
+        }
+        getTimesCache.put(key, syncSampleTimes);
+        return syncSampleTimes;
+    }
+
+    private static long calculateTracktimesScalingFactor(Movie m, Track track) {
+        long timeScale = 1;
+        for (Track track1 : m.getTracks()) {
+            if (track1.getHandler().equals(track.getHandler())) {
+                if (track1.getTrackMetaData().getTimescale() != track.getTrackMetaData().getTimescale()) {
+                    timeScale = lcm(timeScale, track1.getTrackMetaData().getTimescale());
+                }
+            }
+        }
+        return timeScale;
+    }
+
+    public static class CacheTuple {
+        Track track;
+        Movie movie;
+
+        public CacheTuple(Track track, Movie movie) {
+            this.track = track;
+            this.movie = movie;
+        }
+
+        @Override
+        public boolean equals(Object o) {
+            if (this == o) return true;
+            if (o == null || getClass() != o.getClass()) return false;
+
+            CacheTuple that = (CacheTuple) o;
+
+            if (movie != null ? !movie.equals(that.movie) : that.movie != null) return false;
+            if (track != null ? !track.equals(that.track) : that.track != null) return false;
+
+            return true;
+        }
+
+        @Override
+        public int hashCode() {
+            int result = track != null ? track.hashCode() : 0;
+            result = 31 * result + (movie != null ? movie.hashCode() : 0);
+            return result;
+        }
+    }
+}
diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/authoring/builder/.svn/text-base/TwoSecondIntersectionFinder.java.svn-base b/isoparser/src/main/java/com/googlecode/mp4parser/authoring/builder/.svn/text-base/TwoSecondIntersectionFinder.java.svn-base
new file mode 100644
index 0000000..88aa4ab
--- /dev/null
+++ b/isoparser/src/main/java/com/googlecode/mp4parser/authoring/builder/.svn/text-base/TwoSecondIntersectionFinder.java.svn-base
@@ -0,0 +1,86 @@
+/*
+ * Copyright 2012 Sebastian Annies, Hamburg
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.googlecode.mp4parser.authoring.builder;
+
+import com.coremedia.iso.boxes.TimeToSampleBox;
+import com.googlecode.mp4parser.authoring.Movie;
+import com.googlecode.mp4parser.authoring.Track;
+
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * This <code>FragmentIntersectionFinder</code> cuts the input movie in 2 second
+ * snippets.
+ */
+public class TwoSecondIntersectionFinder implements FragmentIntersectionFinder {
+
+    protected long getDuration(Track track) {
+        long duration = 0;
+        for (TimeToSampleBox.Entry entry : track.getDecodingTimeEntries()) {
+            duration += entry.getCount() * entry.getDelta();
+        }
+        return duration;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public long[] sampleNumbers(Track track, Movie movie) {
+        List<TimeToSampleBox.Entry> entries = track.getDecodingTimeEntries();
+
+        double trackLength = 0;
+        for (Track thisTrack : movie.getTracks()) {
+            double thisTracksLength = getDuration(thisTrack) / thisTrack.getTrackMetaData().getTimescale();
+            if (trackLength < thisTracksLength) {
+                trackLength = thisTracksLength;
+            }
+        }
+
+        int fragmentCount = (int)Math.ceil(trackLength / 2) - 1;
+        if (fragmentCount < 1) {
+            fragmentCount = 1;
+        }
+
+        long fragments[] = new long[fragmentCount];
+        Arrays.fill(fragments, -1);
+        fragments[0] = 1;
+
+        long time = 0;
+        int samples = 0;
+        for (TimeToSampleBox.Entry entry : entries) {
+            for (int i = 0; i < entry.getCount(); i++) {
+                int currentFragment = (int) (time / track.getTrackMetaData().getTimescale() / 2) + 1;
+                if (currentFragment >= fragments.length) {
+                    break;
+                }
+                fragments[currentFragment] = samples++ + 1;
+                time += entry.getDelta();
+            }
+        }
+        long last = samples + 1;
+        // fill all -1 ones.
+        for (int i = fragments.length - 1; i >= 0; i--) {
+            if (fragments[i] == -1) {
+                fragments[i] = last ;
+            }
+            last = fragments[i];
+        }
+        return fragments;
+
+    }
+
+}
diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/authoring/builder/ByteBufferHelper.java b/isoparser/src/main/java/com/googlecode/mp4parser/authoring/builder/ByteBufferHelper.java
new file mode 100644
index 0000000..ad21b11
--- /dev/null
+++ b/isoparser/src/main/java/com/googlecode/mp4parser/authoring/builder/ByteBufferHelper.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2012 Sebastian Annies, Hamburg
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.googlecode.mp4parser.authoring.builder;
+
+import java.nio.ByteBuffer;
+import java.nio.MappedByteBuffer;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Used to merge adjacent byte buffers.
+ */
+public class ByteBufferHelper {
+    public static List<ByteBuffer> mergeAdjacentBuffers(List<ByteBuffer> samples) {
+        ArrayList<ByteBuffer> nuSamples = new ArrayList<ByteBuffer>(samples.size());
+        for (ByteBuffer buffer : samples) {
+            int lastIndex = nuSamples.size() - 1;
+            if (lastIndex >= 0 && buffer.hasArray() && nuSamples.get(lastIndex).hasArray() && buffer.array() == nuSamples.get(lastIndex).array() &&
+                    nuSamples.get(lastIndex).arrayOffset() + nuSamples.get(lastIndex).limit() == buffer.arrayOffset()) {
+                ByteBuffer oldBuffer = nuSamples.remove(lastIndex);
+                ByteBuffer nu = ByteBuffer.wrap(buffer.array(), oldBuffer.arrayOffset(), oldBuffer.limit() + buffer.limit()).slice();
+                // We need to slice here since wrap([], offset, length) just sets position and not the arrayOffset.
+                nuSamples.add(nu);
+            } else if (lastIndex >= 0 &&
+                    buffer instanceof MappedByteBuffer && nuSamples.get(lastIndex) instanceof MappedByteBuffer &&
+                    nuSamples.get(lastIndex).limit() == nuSamples.get(lastIndex).capacity() - buffer.capacity()) {
+                // This can go wrong - but will it?
+                ByteBuffer oldBuffer = nuSamples.get(lastIndex);
+                oldBuffer.limit(buffer.limit() + oldBuffer.limit());
+            } else {
+                buffer.rewind();
+                nuSamples.add(buffer);
+            }
+        }
+        return nuSamples;
+    }
+}
diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/authoring/builder/DefaultMp4Builder.java b/isoparser/src/main/java/com/googlecode/mp4parser/authoring/builder/DefaultMp4Builder.java
new file mode 100644
index 0000000..9bd1ca6
--- /dev/null
+++ b/isoparser/src/main/java/com/googlecode/mp4parser/authoring/builder/DefaultMp4Builder.java
@@ -0,0 +1,576 @@
+/*
+ * Copyright 2012 Sebastian Annies, Hamburg
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.googlecode.mp4parser.authoring.builder;
+
+import com.coremedia.iso.BoxParser;
+import com.coremedia.iso.IsoFile;
+import com.coremedia.iso.IsoTypeWriter;
+import com.coremedia.iso.boxes.Box;
+import com.coremedia.iso.boxes.CompositionTimeToSample;
+import com.coremedia.iso.boxes.ContainerBox;
+import com.coremedia.iso.boxes.DataEntryUrlBox;
+import com.coremedia.iso.boxes.DataInformationBox;
+import com.coremedia.iso.boxes.DataReferenceBox;
+import com.coremedia.iso.boxes.FileTypeBox;
+import com.coremedia.iso.boxes.HandlerBox;
+import com.coremedia.iso.boxes.MediaBox;
+import com.coremedia.iso.boxes.MediaHeaderBox;
+import com.coremedia.iso.boxes.MediaInformationBox;
+import com.coremedia.iso.boxes.MovieBox;
+import com.coremedia.iso.boxes.MovieHeaderBox;
+import com.coremedia.iso.boxes.SampleDependencyTypeBox;
+import com.coremedia.iso.boxes.SampleSizeBox;
+import com.coremedia.iso.boxes.SampleTableBox;
+import com.coremedia.iso.boxes.SampleToChunkBox;
+import com.coremedia.iso.boxes.StaticChunkOffsetBox;
+import com.coremedia.iso.boxes.SyncSampleBox;
+import com.coremedia.iso.boxes.TimeToSampleBox;
+import com.coremedia.iso.boxes.TrackBox;
+import com.coremedia.iso.boxes.TrackHeaderBox;
+import com.googlecode.mp4parser.authoring.DateHelper;
+import com.googlecode.mp4parser.authoring.Movie;
+import com.googlecode.mp4parser.authoring.Track;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.nio.MappedByteBuffer;
+import java.nio.channels.GatheringByteChannel;
+import java.nio.channels.ReadableByteChannel;
+import java.nio.channels.WritableByteChannel;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import static com.googlecode.mp4parser.util.CastUtils.l2i;
+
+/**
+ * Creates a plain MP4 file from a video. Plain as plain can be.
+ */
+public class DefaultMp4Builder implements Mp4Builder {
+
+    public int STEPSIZE = 64;
+    Set<StaticChunkOffsetBox> chunkOffsetBoxes = new HashSet<StaticChunkOffsetBox>();
+    private static Logger LOG = Logger.getLogger(DefaultMp4Builder.class.getName());
+
+    HashMap<Track, List<ByteBuffer>> track2Sample = new HashMap<Track, List<ByteBuffer>>();
+    HashMap<Track, long[]> track2SampleSizes = new HashMap<Track, long[]>();
+    private FragmentIntersectionFinder intersectionFinder = new TwoSecondIntersectionFinder();
+
+    public void setIntersectionFinder(FragmentIntersectionFinder intersectionFinder) {
+        this.intersectionFinder = intersectionFinder;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public IsoFile build(Movie movie) {
+        LOG.fine("Creating movie " + movie);
+        for (Track track : movie.getTracks()) {
+            // getting the samples may be a time consuming activity
+            List<ByteBuffer> samples = track.getSamples();
+            putSamples(track, samples);
+            long[] sizes = new long[samples.size()];
+            for (int i = 0; i < sizes.length; i++) {
+                sizes[i] = samples.get(i).limit();
+            }
+            putSampleSizes(track, sizes);
+        }
+
+        IsoFile isoFile = new IsoFile();
+        // ouch that is ugly but I don't know how to do it else
+        List<String> minorBrands = new LinkedList<String>();
+        minorBrands.add("isom");
+        minorBrands.add("iso2");
+        minorBrands.add("avc1");
+
+        isoFile.addBox(new FileTypeBox("isom", 0, minorBrands));
+        isoFile.addBox(createMovieBox(movie));
+        InterleaveChunkMdat mdat = new InterleaveChunkMdat(movie);
+        isoFile.addBox(mdat);
+
+        /*
+        dataOffset is where the first sample starts. In this special mdat the samples always start
+        at offset 16 so that we can use the same offset for large boxes and small boxes
+         */
+        long dataOffset = mdat.getDataOffset();
+        for (StaticChunkOffsetBox chunkOffsetBox : chunkOffsetBoxes) {
+            long[] offsets = chunkOffsetBox.getChunkOffsets();
+            for (int i = 0; i < offsets.length; i++) {
+                offsets[i] += dataOffset;
+            }
+        }
+
+
+        return isoFile;
+    }
+
+    public FragmentIntersectionFinder getFragmentIntersectionFinder() {
+        throw new UnsupportedOperationException("No fragment intersection finder in default MP4 builder!");
+    }
+
+    protected long[] putSampleSizes(Track track, long[] sizes) {
+        return track2SampleSizes.put(track, sizes);
+    }
+
+    protected List<ByteBuffer> putSamples(Track track, List<ByteBuffer> samples) {
+        return track2Sample.put(track, samples);
+    }
+
+    private MovieBox createMovieBox(Movie movie) {
+        MovieBox movieBox = new MovieBox();
+        MovieHeaderBox mvhd = new MovieHeaderBox();
+
+        mvhd.setCreationTime(DateHelper.convert(new Date()));
+        mvhd.setModificationTime(DateHelper.convert(new Date()));
+
+        long movieTimeScale = getTimescale(movie);
+        long duration = 0;
+
+        for (Track track : movie.getTracks()) {
+            long tracksDuration = getDuration(track) * movieTimeScale / track.getTrackMetaData().getTimescale();
+            if (tracksDuration > duration) {
+                duration = tracksDuration;
+            }
+
+
+        }
+
+        mvhd.setDuration(duration);
+        mvhd.setTimescale(movieTimeScale);
+        // find the next available trackId
+        long nextTrackId = 0;
+        for (Track track : movie.getTracks()) {
+            nextTrackId = nextTrackId < track.getTrackMetaData().getTrackId() ? track.getTrackMetaData().getTrackId() : nextTrackId;
+        }
+        mvhd.setNextTrackId(++nextTrackId);
+        if (mvhd.getCreationTime() >= 1l << 32 ||
+                mvhd.getModificationTime() >= 1l << 32 ||
+                mvhd.getDuration() >= 1l << 32) {
+            mvhd.setVersion(1);
+        }
+
+        movieBox.addBox(mvhd);
+        for (Track track : movie.getTracks()) {
+            movieBox.addBox(createTrackBox(track, movie));
+        }
+        // metadata here
+        Box udta = createUdta(movie);
+        if (udta != null) {
+            movieBox.addBox(udta);
+        }
+        return movieBox;
+
+    }
+
+    /**
+     * Override to create a user data box that may contain metadata.
+     *
+     * @return a 'udta' box or <code>null</code> if none provided
+     */
+    protected Box createUdta(Movie movie) {
+        return null;
+    }
+
+    private TrackBox createTrackBox(Track track, Movie movie) {
+
+        LOG.info("Creating Mp4TrackImpl " + track);
+        TrackBox trackBox = new TrackBox();
+        TrackHeaderBox tkhd = new TrackHeaderBox();
+        int flags = 0;
+        if (track.isEnabled()) {
+            flags += 1;
+        }
+
+        if (track.isInMovie()) {
+            flags += 2;
+        }
+
+        if (track.isInPreview()) {
+            flags += 4;
+        }
+
+        if (track.isInPoster()) {
+            flags += 8;
+        }
+        tkhd.setFlags(flags);
+
+        tkhd.setAlternateGroup(track.getTrackMetaData().getGroup());
+        tkhd.setCreationTime(DateHelper.convert(track.getTrackMetaData().getCreationTime()));
+        // We need to take edit list box into account in trackheader duration
+        // but as long as I don't support edit list boxes it is sufficient to
+        // just translate media duration to movie timescale
+        tkhd.setDuration(getDuration(track) * getTimescale(movie) / track.getTrackMetaData().getTimescale());
+        tkhd.setHeight(track.getTrackMetaData().getHeight());
+        tkhd.setWidth(track.getTrackMetaData().getWidth());
+        tkhd.setLayer(track.getTrackMetaData().getLayer());
+        tkhd.setModificationTime(DateHelper.convert(new Date()));
+        tkhd.setTrackId(track.getTrackMetaData().getTrackId());
+        tkhd.setVolume(track.getTrackMetaData().getVolume());
+        if (tkhd.getCreationTime() >= 1l << 32 ||
+                tkhd.getModificationTime() >= 1l << 32 ||
+                tkhd.getDuration() >= 1l << 32) {
+            tkhd.setVersion(1);
+        }
+
+        trackBox.addBox(tkhd);
+
+/*
+        EditBox edit = new EditBox();
+        EditListBox editListBox = new EditListBox();
+        editListBox.setEntries(Collections.singletonList(
+                new EditListBox.Entry(editListBox, (long) (track.getTrackMetaData().getStartTime() * getTimescale(movie)), -1, 1)));
+        edit.addBox(editListBox);
+        trackBox.addBox(edit);
+*/
+
+        MediaBox mdia = new MediaBox();
+        trackBox.addBox(mdia);
+        MediaHeaderBox mdhd = new MediaHeaderBox();
+        mdhd.setCreationTime(DateHelper.convert(track.getTrackMetaData().getCreationTime()));
+        mdhd.setDuration(getDuration(track));
+        mdhd.setTimescale(track.getTrackMetaData().getTimescale());
+        mdhd.setLanguage(track.getTrackMetaData().getLanguage());
+        mdia.addBox(mdhd);
+        HandlerBox hdlr = new HandlerBox();
+        mdia.addBox(hdlr);
+
+        hdlr.setHandlerType(track.getHandler());
+
+        MediaInformationBox minf = new MediaInformationBox();
+        minf.addBox(track.getMediaHeaderBox());
+
+        // dinf: all these three boxes tell us is that the actual
+        // data is in the current file and not somewhere external
+        DataInformationBox dinf = new DataInformationBox();
+        DataReferenceBox dref = new DataReferenceBox();
+        dinf.addBox(dref);
+        DataEntryUrlBox url = new DataEntryUrlBox();
+        url.setFlags(1);
+        dref.addBox(url);
+        minf.addBox(dinf);
+        //
+
+        SampleTableBox stbl = new SampleTableBox();
+
+        stbl.addBox(track.getSampleDescriptionBox());
+
+        List<TimeToSampleBox.Entry> decodingTimeToSampleEntries = track.getDecodingTimeEntries();
+        if (decodingTimeToSampleEntries != null && !track.getDecodingTimeEntries().isEmpty()) {
+            TimeToSampleBox stts = new TimeToSampleBox();
+            stts.setEntries(track.getDecodingTimeEntries());
+            stbl.addBox(stts);
+        }
+
+        List<CompositionTimeToSample.Entry> compositionTimeToSampleEntries = track.getCompositionTimeEntries();
+        if (compositionTimeToSampleEntries != null && !compositionTimeToSampleEntries.isEmpty()) {
+            CompositionTimeToSample ctts = new CompositionTimeToSample();
+            ctts.setEntries(compositionTimeToSampleEntries);
+            stbl.addBox(ctts);
+        }
+
+        long[] syncSamples = track.getSyncSamples();
+        if (syncSamples != null && syncSamples.length > 0) {
+            SyncSampleBox stss = new SyncSampleBox();
+            stss.setSampleNumber(syncSamples);
+            stbl.addBox(stss);
+        }
+
+        if (track.getSampleDependencies() != null && !track.getSampleDependencies().isEmpty()) {
+            SampleDependencyTypeBox sdtp = new SampleDependencyTypeBox();
+            sdtp.setEntries(track.getSampleDependencies());
+            stbl.addBox(sdtp);
+        }
+        HashMap<Track, int[]> track2ChunkSizes = new HashMap<Track, int[]>();
+        for (Track current : movie.getTracks()) {
+            track2ChunkSizes.put(current, getChunkSizes(current, movie));
+        }
+        int[] tracksChunkSizes = track2ChunkSizes.get(track);
+
+        SampleToChunkBox stsc = new SampleToChunkBox();
+        stsc.setEntries(new LinkedList<SampleToChunkBox.Entry>());
+        long lastChunkSize = Integer.MIN_VALUE; // to be sure the first chunks hasn't got the same size
+        for (int i = 0; i < tracksChunkSizes.length; i++) {
+            // The sample description index references the sample description box
+            // that describes the samples of this chunk. My Tracks cannot have more
+            // than one sample description box. Therefore 1 is always right
+            // the first chunk has the number '1'
+            if (lastChunkSize != tracksChunkSizes[i]) {
+                stsc.getEntries().add(new SampleToChunkBox.Entry(i + 1, tracksChunkSizes[i], 1));
+                lastChunkSize = tracksChunkSizes[i];
+            }
+        }
+        stbl.addBox(stsc);
+
+        SampleSizeBox stsz = new SampleSizeBox();
+        stsz.setSampleSizes(track2SampleSizes.get(track));
+
+        stbl.addBox(stsz);
+        // The ChunkOffsetBox we create here is just a stub
+        // since we haven't created the whole structure we can't tell where the
+        // first chunk starts (mdat box). So I just let the chunk offset
+        // start at zero and I will add the mdat offset later.
+        StaticChunkOffsetBox stco = new StaticChunkOffsetBox();
+        this.chunkOffsetBoxes.add(stco);
+        long offset = 0;
+        long[] chunkOffset = new long[tracksChunkSizes.length];
+        // all tracks have the same number of chunks
+        if (LOG.isLoggable(Level.FINE)) {
+            LOG.fine("Calculating chunk offsets for track_" + track.getTrackMetaData().getTrackId());
+        }
+
+
+        for (int i = 0; i < tracksChunkSizes.length; i++) {
+            // The filelayout will be:
+            // chunk_1_track_1,... ,chunk_1_track_n, chunk_2_track_1,... ,chunk_2_track_n, ... , chunk_m_track_1,... ,chunk_m_track_n
+            // calculating the offsets
+            if (LOG.isLoggable(Level.FINER)) {
+                LOG.finer("Calculating chunk offsets for track_" + track.getTrackMetaData().getTrackId() + " chunk " + i);
+            }
+            for (Track current : movie.getTracks()) {
+                if (LOG.isLoggable(Level.FINEST)) {
+                    LOG.finest("Adding offsets of track_" + current.getTrackMetaData().getTrackId());
+                }
+                int[] chunkSizes = track2ChunkSizes.get(current);
+                long firstSampleOfChunk = 0;
+                for (int j = 0; j < i; j++) {
+                    firstSampleOfChunk += chunkSizes[j];
+                }
+                if (current == track) {
+                    chunkOffset[i] = offset;
+                }
+                for (int j = l2i(firstSampleOfChunk); j < firstSampleOfChunk + chunkSizes[i]; j++) {
+                    offset += track2SampleSizes.get(current)[j];
+                }
+            }
+        }
+        stco.setChunkOffsets(chunkOffset);
+        stbl.addBox(stco);
+        minf.addBox(stbl);
+        mdia.addBox(minf);
+
+        return trackBox;
+    }
+
+    private class InterleaveChunkMdat implements Box {
+        List<Track> tracks;
+        List<ByteBuffer> samples = new ArrayList<ByteBuffer>();
+        ContainerBox parent;
+
+        long contentSize = 0;
+
+        public ContainerBox getParent() {
+            return parent;
+        }
+
+        public void setParent(ContainerBox parent) {
+            this.parent = parent;
+        }
+
+        public void parse(ReadableByteChannel readableByteChannel, ByteBuffer header, long contentSize, BoxParser boxParser) throws IOException {
+        }
+
+        private InterleaveChunkMdat(Movie movie) {
+
+            tracks = movie.getTracks();
+            Map<Track, int[]> chunks = new HashMap<Track, int[]>();
+            for (Track track : movie.getTracks()) {
+                chunks.put(track, getChunkSizes(track, movie));
+            }
+
+            for (int i = 0; i < chunks.values().iterator().next().length; i++) {
+                for (Track track : tracks) {
+
+                    int[] chunkSizes = chunks.get(track);
+                    long firstSampleOfChunk = 0;
+                    for (int j = 0; j < i; j++) {
+                        firstSampleOfChunk += chunkSizes[j];
+                    }
+
+                    for (int j = l2i(firstSampleOfChunk); j < firstSampleOfChunk + chunkSizes[i]; j++) {
+
+                        ByteBuffer s = DefaultMp4Builder.this.track2Sample.get(track).get(j);
+                        contentSize += s.limit();
+                        samples.add((ByteBuffer) s.rewind());
+                    }
+
+                }
+
+            }
+
+        }
+
+        public long getDataOffset() {
+            Box b = this;
+            long offset = 16;
+            while (b.getParent() != null) {
+                for (Box box : b.getParent().getBoxes()) {
+                    if (b == box) {
+                        break;
+                    }
+                    offset += box.getSize();
+                }
+                b = b.getParent();
+            }
+            return offset;
+        }
+
+
+        public String getType() {
+            return "mdat";
+        }
+
+        public long getSize() {
+            return 16 + contentSize;
+        }
+
+        private boolean isSmallBox(long contentSize) {
+            return (contentSize + 8) < 4294967296L;
+        }
+
+
+        public void getBox(WritableByteChannel writableByteChannel) throws IOException {
+            ByteBuffer bb = ByteBuffer.allocate(16);
+            long size = getSize();
+            if (isSmallBox(size)) {
+                IsoTypeWriter.writeUInt32(bb, size);
+            } else {
+                IsoTypeWriter.writeUInt32(bb, 1);
+            }
+            bb.put(IsoFile.fourCCtoBytes("mdat"));
+            if (isSmallBox(size)) {
+                bb.put(new byte[8]);
+            } else {
+                IsoTypeWriter.writeUInt64(bb, size);
+            }
+            bb.rewind();
+            writableByteChannel.write(bb);
+            if (writableByteChannel instanceof GatheringByteChannel) {
+                List<ByteBuffer> nuSamples = unifyAdjacentBuffers(samples);
+
+
+                for (int i = 0; i < Math.ceil((double) nuSamples.size() / STEPSIZE); i++) {
+                    List<ByteBuffer> sublist = nuSamples.subList(
+                            i * STEPSIZE, // start
+                            (i + 1) * STEPSIZE < nuSamples.size() ? (i + 1) * STEPSIZE : nuSamples.size()); // end
+                    ByteBuffer sampleArray[] = sublist.toArray(new ByteBuffer[sublist.size()]);
+                    do {
+                        ((GatheringByteChannel) writableByteChannel).write(sampleArray);
+                    } while (sampleArray[sampleArray.length - 1].remaining() > 0);
+                }
+                //System.err.println(bytesWritten);
+            } else {
+                for (ByteBuffer sample : samples) {
+                    sample.rewind();
+                    writableByteChannel.write(sample);
+                }
+            }
+        }
+
+    }
+
+    /**
+     * Gets the chunk sizes for the given track.
+     *
+     * @param track
+     * @param movie
+     * @return
+     */
+    int[] getChunkSizes(Track track, Movie movie) {
+
+        long[] referenceChunkStarts = intersectionFinder.sampleNumbers(track, movie);
+        int[] chunkSizes = new int[referenceChunkStarts.length];
+
+
+        for (int i = 0; i < referenceChunkStarts.length; i++) {
+            long start = referenceChunkStarts[i] - 1;
+            long end;
+            if (referenceChunkStarts.length == i + 1) {
+                end = track.getSamples().size();
+            } else {
+                end = referenceChunkStarts[i + 1] - 1;
+            }
+
+            chunkSizes[i] = l2i(end - start);
+            // The Stretch makes sure that there are as much audio and video chunks!
+        }
+        assert DefaultMp4Builder.this.track2Sample.get(track).size() == sum(chunkSizes) : "The number of samples and the sum of all chunk lengths must be equal";
+        return chunkSizes;
+
+
+    }
+
+
+    private static long sum(int[] ls) {
+        long rc = 0;
+        for (long l : ls) {
+            rc += l;
+        }
+        return rc;
+    }
+
+    protected static long getDuration(Track track) {
+        long duration = 0;
+        for (TimeToSampleBox.Entry entry : track.getDecodingTimeEntries()) {
+            duration += entry.getCount() * entry.getDelta();
+        }
+        return duration;
+    }
+
+    public long getTimescale(Movie movie) {
+        long timescale = movie.getTracks().iterator().next().getTrackMetaData().getTimescale();
+        for (Track track : movie.getTracks()) {
+            timescale = gcd(track.getTrackMetaData().getTimescale(), timescale);
+        }
+        return timescale;
+    }
+
+    public static long gcd(long a, long b) {
+        if (b == 0) {
+            return a;
+        }
+        return gcd(b, a % b);
+    }
+
+    public List<ByteBuffer> unifyAdjacentBuffers(List<ByteBuffer> samples) {
+        ArrayList<ByteBuffer> nuSamples = new ArrayList<ByteBuffer>(samples.size());
+        for (ByteBuffer buffer : samples) {
+            int lastIndex = nuSamples.size() - 1;
+            if (lastIndex >= 0 && buffer.hasArray() && nuSamples.get(lastIndex).hasArray() && buffer.array() == nuSamples.get(lastIndex).array() &&
+                    nuSamples.get(lastIndex).arrayOffset() + nuSamples.get(lastIndex).limit() == buffer.arrayOffset()) {
+                ByteBuffer oldBuffer = nuSamples.remove(lastIndex);
+                ByteBuffer nu = ByteBuffer.wrap(buffer.array(), oldBuffer.arrayOffset(), oldBuffer.limit() + buffer.limit()).slice();
+                // We need to slice here since wrap([], offset, length) just sets position and not the arrayOffset.
+                nuSamples.add(nu);
+            } else if (lastIndex >= 0 &&
+                    buffer instanceof MappedByteBuffer && nuSamples.get(lastIndex) instanceof MappedByteBuffer &&
+                    nuSamples.get(lastIndex).limit() == nuSamples.get(lastIndex).capacity() - buffer.capacity()) {
+                // This can go wrong - but will it?
+                ByteBuffer oldBuffer = nuSamples.get(lastIndex);
+                oldBuffer.limit(buffer.limit() + oldBuffer.limit());
+            } else {
+                nuSamples.add(buffer);
+            }
+        }
+        return nuSamples;
+    }
+}
diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/authoring/builder/FragmentIntersectionFinder.java b/isoparser/src/main/java/com/googlecode/mp4parser/authoring/builder/FragmentIntersectionFinder.java
new file mode 100644
index 0000000..1224bbf
--- /dev/null
+++ b/isoparser/src/main/java/com/googlecode/mp4parser/authoring/builder/FragmentIntersectionFinder.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright 2012 Sebastian Annies, Hamburg
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.googlecode.mp4parser.authoring.builder;
+
+import com.googlecode.mp4parser.authoring.Movie;
+import com.googlecode.mp4parser.authoring.Track;
+
+/**
+ *
+ */
+public interface FragmentIntersectionFinder {
+    /**
+     * Gets the ordinal number of the samples which will be the first sample
+     * in each fragment.
+     *
+     * @param track concerned track
+     * @param movie the context of the track
+     * @return an array containing the ordinal of each fragment's first sample
+     */
+    public long[] sampleNumbers(Track track, Movie movie);
+}
diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/authoring/builder/FragmentedMp4Builder.java b/isoparser/src/main/java/com/googlecode/mp4parser/authoring/builder/FragmentedMp4Builder.java
new file mode 100644
index 0000000..c65ff1c
--- /dev/null
+++ b/isoparser/src/main/java/com/googlecode/mp4parser/authoring/builder/FragmentedMp4Builder.java
@@ -0,0 +1,742 @@
+/*
+ * Copyright 2012 Sebastian Annies, Hamburg
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.googlecode.mp4parser.authoring.builder;
+
+import com.coremedia.iso.BoxParser;
+import com.coremedia.iso.IsoFile;
+import com.coremedia.iso.IsoTypeWriter;
+import com.coremedia.iso.boxes.*;
+import com.coremedia.iso.boxes.fragment.*;
+import com.googlecode.mp4parser.authoring.DateHelper;
+import com.googlecode.mp4parser.authoring.Movie;
+import com.googlecode.mp4parser.authoring.Track;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.nio.channels.GatheringByteChannel;
+import java.nio.channels.ReadableByteChannel;
+import java.nio.channels.WritableByteChannel;
+import java.util.*;
+import java.util.logging.Logger;
+
+import static com.googlecode.mp4parser.util.CastUtils.l2i;
+
+/**
+ * Creates a fragmented MP4 file.
+ */
+public class FragmentedMp4Builder implements Mp4Builder {
+    private static final Logger LOG = Logger.getLogger(FragmentedMp4Builder.class.getName());
+
+    protected FragmentIntersectionFinder intersectionFinder;
+
+    public FragmentedMp4Builder() {
+        this.intersectionFinder = new SyncSampleIntersectFinderImpl();
+    }
+
+    public List<String> getAllowedHandlers() {
+        return Arrays.asList("soun", "vide");
+    }
+
+    public Box createFtyp(Movie movie) {
+        List<String> minorBrands = new LinkedList<String>();
+        minorBrands.add("isom");
+        minorBrands.add("iso2");
+        minorBrands.add("avc1");
+        return new FileTypeBox("isom", 0, minorBrands);
+    }
+
+    /**
+     * Some formats require sorting of the fragments. E.g. Ultraviolet CFF files are required
+     * to contain the fragments size sort:
+     * <ul>
+     * <li>video[1].getBytes().length < audio[1].getBytes().length < subs[1].getBytes().length</li>
+     * <li> audio[2].getBytes().length < video[2].getBytes().length < subs[2].getBytes().length</li>
+     * </ul>
+     *
+     * make this fragment:
+     *
+     * <ol>
+     *     <li>video[1]</li>
+     *     <li>audio[1]</li>
+     *     <li>subs[1]</li>
+     *     <li>audio[2]</li>
+     *     <li>video[2]</li>
+     *     <li>subs[2]</li>
+     * </ol>
+     *
+     * @param tracks the list of tracks to returned sorted
+     * @param cycle current fragment (sorting may vary between the fragments)
+     * @param intersectionMap a map from tracks to their fragments' first samples.
+     * @return the list of tracks in order of appearance in the fragment
+     */
+    protected List<Track> sortTracksInSequence(List<Track> tracks, final int cycle, final Map<Track, long[]> intersectionMap) {
+        tracks = new LinkedList<Track>(tracks);
+        Collections.sort(tracks, new Comparator<Track>() {
+            public int compare(Track o1, Track o2) {
+                long[] startSamples1 = intersectionMap.get(o1);
+                long startSample1 = startSamples1[cycle];
+                // one based sample numbers - the first sample is 1
+                long endSample1 = cycle + 1 < startSamples1.length ? startSamples1[cycle + 1] : o1.getSamples().size() + 1;
+                long[] startSamples2 = intersectionMap.get(o2);
+                long startSample2 = startSamples2[cycle];
+                // one based sample numbers - the first sample is 1
+                long endSample2 = cycle + 1 < startSamples2.length ? startSamples2[cycle + 1] : o2.getSamples().size() + 1;
+                List<ByteBuffer> samples1 = o1.getSamples().subList(l2i(startSample1) - 1, l2i(endSample1) - 1);
+                List<ByteBuffer> samples2 = o2.getSamples().subList(l2i(startSample2) - 1, l2i(endSample2) - 1);
+                int size1 = 0;
+                for (ByteBuffer byteBuffer : samples1) {
+                    size1 += byteBuffer.limit();
+                }
+                int size2 = 0;
+                for (ByteBuffer byteBuffer : samples2) {
+                    size2 += byteBuffer.limit();
+                }
+                return size1 - size2;
+            }
+        });
+        return tracks;
+    }
+
+    protected List<Box> createMoofMdat(final Movie movie) {
+        List<Box> boxes = new LinkedList<Box>();
+        HashMap<Track, long[]> intersectionMap = new HashMap<Track, long[]>();
+        int maxNumberOfFragments = 0;
+        for (Track track : movie.getTracks()) {
+            long[] intersects = intersectionFinder.sampleNumbers(track, movie);
+            intersectionMap.put(track, intersects);
+            maxNumberOfFragments = Math.max(maxNumberOfFragments, intersects.length);
+        }
+
+
+        int sequence = 1;
+        // this loop has two indices:
+
+        for (int cycle = 0; cycle < maxNumberOfFragments; cycle++) {
+
+            final List<Track> sortedTracks = sortTracksInSequence(movie.getTracks(), cycle, intersectionMap);
+
+            for (Track track : sortedTracks) {
+                if (getAllowedHandlers().isEmpty() || getAllowedHandlers().contains(track.getHandler())) {
+                    long[] startSamples = intersectionMap.get(track);
+                    //some tracks may have less fragments -> skip them
+                    if (cycle < startSamples.length) {
+
+                        long startSample = startSamples[cycle];
+                        // one based sample numbers - the first sample is 1
+                        long endSample = cycle + 1 < startSamples.length ? startSamples[cycle + 1] : track.getSamples().size() + 1;
+
+                        // if startSample == endSample the cycle is empty!
+                        if (startSample != endSample) {
+                            boxes.add(createMoof(startSample, endSample, track, sequence));
+                            boxes.add(createMdat(startSample, endSample, track, sequence++));
+                        }
+                    }
+                }
+            }
+        }
+        return boxes;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public IsoFile build(Movie movie) {
+        LOG.fine("Creating movie " + movie);
+        IsoFile isoFile = new IsoFile();
+
+
+        isoFile.addBox(createFtyp(movie));
+        isoFile.addBox(createMoov(movie));
+
+        for (Box box : createMoofMdat(movie)) {
+            isoFile.addBox(box);
+        }
+        isoFile.addBox(createMfra(movie, isoFile));
+
+        return isoFile;
+    }
+
+    protected Box createMdat(final long startSample, final long endSample, final Track track, final int i) {
+
+        class Mdat implements Box {
+            ContainerBox parent;
+
+            public ContainerBox getParent() {
+                return parent;
+            }
+
+            public void setParent(ContainerBox parent) {
+                this.parent = parent;
+            }
+
+            public long getSize() {
+                long size = 8; // I don't expect 2gig fragments
+                for (ByteBuffer sample : getSamples(startSample, endSample, track, i)) {
+                    size += sample.limit();
+                }
+                return size;
+            }
+
+            public String getType() {
+                return "mdat";
+            }
+
+            public void getBox(WritableByteChannel writableByteChannel) throws IOException {
+                List<ByteBuffer> bbs = getSamples(startSample, endSample, track, i);
+                final List<ByteBuffer> samples = ByteBufferHelper.mergeAdjacentBuffers(bbs);
+                ByteBuffer header = ByteBuffer.allocate(8);
+                IsoTypeWriter.writeUInt32(header, l2i(getSize()));
+                header.put(IsoFile.fourCCtoBytes(getType()));
+                header.rewind();
+                writableByteChannel.write(header);
+                if (writableByteChannel instanceof GatheringByteChannel) {
+
+                    int STEPSIZE = 1024;
+                    // This is required to prevent android from crashing
+                    // it seems that {@link GatheringByteChannel#write(java.nio.ByteBuffer[])}
+                    // just handles up to 1024 buffers
+                    for (int i = 0; i < Math.ceil((double) samples.size() / STEPSIZE); i++) {
+                        List<ByteBuffer> sublist = samples.subList(
+                                i * STEPSIZE, // start
+                                (i + 1) * STEPSIZE < samples.size() ? (i + 1) * STEPSIZE : samples.size()); // end
+                        ByteBuffer sampleArray[] = sublist.toArray(new ByteBuffer[sublist.size()]);
+                        do {
+                            ((GatheringByteChannel) writableByteChannel).write(sampleArray);
+                        } while (sampleArray[sampleArray.length - 1].remaining() > 0);
+                    }
+                    //System.err.println(bytesWritten);
+                } else {
+                    for (ByteBuffer sample : samples) {
+                        sample.rewind();
+                        writableByteChannel.write(sample);
+                    }
+                }
+
+            }
+
+            public void parse(ReadableByteChannel readableByteChannel, ByteBuffer header, long contentSize, BoxParser boxParser) throws IOException {
+
+            }
+        }
+
+        return new Mdat();
+    }
+
+    protected Box createTfhd(long startSample, long endSample, Track track, int sequenceNumber) {
+        TrackFragmentHeaderBox tfhd = new TrackFragmentHeaderBox();
+        SampleFlags sf = new SampleFlags();
+
+        tfhd.setDefaultSampleFlags(sf);
+        tfhd.setBaseDataOffset(-1);
+        tfhd.setTrackId(track.getTrackMetaData().getTrackId());
+        return tfhd;
+    }
+
+    protected Box createMfhd(long startSample, long endSample, Track track, int sequenceNumber) {
+        MovieFragmentHeaderBox mfhd = new MovieFragmentHeaderBox();
+        mfhd.setSequenceNumber(sequenceNumber);
+        return mfhd;
+    }
+
+    protected Box createTraf(long startSample, long endSample, Track track, int sequenceNumber) {
+        TrackFragmentBox traf = new TrackFragmentBox();
+        traf.addBox(createTfhd(startSample, endSample, track, sequenceNumber));
+        for (Box trun : createTruns(startSample, endSample, track, sequenceNumber)) {
+            traf.addBox(trun);
+        }
+
+        return traf;
+    }
+
+
+    /**
+     * Gets the all samples starting with <code>startSample</code> (one based -> one is the first) and
+     * ending with <code>endSample</code> (exclusive).
+     *
+     * @param startSample    low endpoint (inclusive) of the sample sequence
+     * @param endSample      high endpoint (exclusive) of the sample sequence
+     * @param track          source of the samples
+     * @param sequenceNumber the fragment index of the requested list of samples
+     * @return a <code>List&lt;ByteBuffer></code> of raw samples
+     */
+    protected List<ByteBuffer> getSamples(long startSample, long endSample, Track track, int sequenceNumber) {
+        // since startSample and endSample are one-based substract 1 before addressing list elements
+        return track.getSamples().subList(l2i(startSample) - 1, l2i(endSample) - 1);
+    }
+
+    /**
+     * Gets the sizes of a sequence of samples-
+     *
+     * @param startSample    low endpoint (inclusive) of the sample sequence
+     * @param endSample      high endpoint (exclusive) of the sample sequence
+     * @param track          source of the samples
+     * @param sequenceNumber the fragment index of the requested list of samples
+     * @return
+     */
+    protected long[] getSampleSizes(long startSample, long endSample, Track track, int sequenceNumber) {
+        List<ByteBuffer> samples = getSamples(startSample, endSample, track, sequenceNumber);
+
+        long[] sampleSizes = new long[samples.size()];
+        for (int i = 0; i < sampleSizes.length; i++) {
+            sampleSizes[i] = samples.get(i).limit();
+        }
+        return sampleSizes;
+    }
+
+    /**
+     * Creates one or more track run boxes for a given sequence.
+     *
+     * @param startSample    low endpoint (inclusive) of the sample sequence
+     * @param endSample      high endpoint (exclusive) of the sample sequence
+     * @param track          source of the samples
+     * @param sequenceNumber the fragment index of the requested list of samples
+     * @return the list of TrackRun boxes.
+     */
+    protected List<? extends Box> createTruns(long startSample, long endSample, Track track, int sequenceNumber) {
+        TrackRunBox trun = new TrackRunBox();
+        long[] sampleSizes = getSampleSizes(startSample, endSample, track, sequenceNumber);
+
+        trun.setSampleDurationPresent(true);
+        trun.setSampleSizePresent(true);
+        List<TrackRunBox.Entry> entries = new ArrayList<TrackRunBox.Entry>(l2i(endSample - startSample));
+
+
+        Queue<TimeToSampleBox.Entry> timeQueue = new LinkedList<TimeToSampleBox.Entry>(track.getDecodingTimeEntries());
+        long left = startSample - 1;
+        long curEntryLeft = timeQueue.peek().getCount();
+        while (left > curEntryLeft) {
+            left -= curEntryLeft;
+            timeQueue.remove();
+            curEntryLeft = timeQueue.peek().getCount();
+        }
+        curEntryLeft -= left;
+
+
+        Queue<CompositionTimeToSample.Entry> compositionTimeQueue =
+                track.getCompositionTimeEntries() != null && track.getCompositionTimeEntries().size() > 0 ?
+                        new LinkedList<CompositionTimeToSample.Entry>(track.getCompositionTimeEntries()) : null;
+        long compositionTimeEntriesLeft = compositionTimeQueue != null ? compositionTimeQueue.peek().getCount() : -1;
+
+
+        trun.setSampleCompositionTimeOffsetPresent(compositionTimeEntriesLeft > 0);
+
+        // fast forward composition stuff
+        for (long i = 1; i < startSample; i++) {
+            if (compositionTimeQueue != null) {
+                //trun.setSampleCompositionTimeOffsetPresent(true);
+                if (--compositionTimeEntriesLeft == 0 && compositionTimeQueue.size() > 1) {
+                    compositionTimeQueue.remove();
+                    compositionTimeEntriesLeft = compositionTimeQueue.element().getCount();
+                }
+            }
+        }
+
+        boolean sampleFlagsRequired = (track.getSampleDependencies() != null && !track.getSampleDependencies().isEmpty() ||
+                track.getSyncSamples() != null && track.getSyncSamples().length != 0);
+
+        trun.setSampleFlagsPresent(sampleFlagsRequired);
+
+        for (int i = 0; i < sampleSizes.length; i++) {
+            TrackRunBox.Entry entry = new TrackRunBox.Entry();
+            entry.setSampleSize(sampleSizes[i]);
+            if (sampleFlagsRequired) {
+                //if (false) {
+                SampleFlags sflags = new SampleFlags();
+
+                if (track.getSampleDependencies() != null && !track.getSampleDependencies().isEmpty()) {
+                    SampleDependencyTypeBox.Entry e = track.getSampleDependencies().get(i);
+                    sflags.setSampleDependsOn(e.getSampleDependsOn());
+                    sflags.setSampleIsDependedOn(e.getSampleIsDependentOn());
+                    sflags.setSampleHasRedundancy(e.getSampleHasRedundancy());
+                }
+                if (track.getSyncSamples() != null && track.getSyncSamples().length > 0) {
+                    // we have to mark non-sync samples!
+                    if (Arrays.binarySearch(track.getSyncSamples(), startSample + i) >= 0) {
+                        sflags.setSampleIsDifferenceSample(false);
+                        sflags.setSampleDependsOn(2);
+                    } else {
+                        sflags.setSampleIsDifferenceSample(true);
+                        sflags.setSampleDependsOn(1);
+                    }
+                }
+                // i don't have sample degradation
+                entry.setSampleFlags(sflags);
+
+            }
+
+            entry.setSampleDuration(timeQueue.peek().getDelta());
+            if (--curEntryLeft == 0 && timeQueue.size() > 1) {
+                timeQueue.remove();
+                curEntryLeft = timeQueue.peek().getCount();
+            }
+
+            if (compositionTimeQueue != null) {
+                entry.setSampleCompositionTimeOffset(compositionTimeQueue.peek().getOffset());
+                if (--compositionTimeEntriesLeft == 0 && compositionTimeQueue.size() > 1) {
+                    compositionTimeQueue.remove();
+                    compositionTimeEntriesLeft = compositionTimeQueue.element().getCount();
+                }
+            }
+            entries.add(entry);
+        }
+
+        trun.setEntries(entries);
+
+        return Collections.singletonList(trun);
+    }
+
+    /**
+     * Creates a 'moof' box for a given sequence of samples.
+     *
+     * @param startSample    low endpoint (inclusive) of the sample sequence
+     * @param endSample      high endpoint (exclusive) of the sample sequence
+     * @param track          source of the samples
+     * @param sequenceNumber the fragment index of the requested list of samples
+     * @return the list of TrackRun boxes.
+     */
+    protected Box createMoof(long startSample, long endSample, Track track, int sequenceNumber) {
+        MovieFragmentBox moof = new MovieFragmentBox();
+        moof.addBox(createMfhd(startSample, endSample, track, sequenceNumber));
+        moof.addBox(createTraf(startSample, endSample, track, sequenceNumber));
+
+        TrackRunBox firstTrun = moof.getTrackRunBoxes().get(0);
+        firstTrun.setDataOffset(1); // dummy to make size correct
+        firstTrun.setDataOffset((int) (8 + moof.getSize())); // mdat header + moof size
+
+        return moof;
+    }
+
+    /**
+     * Creates a single 'mvhd' movie header box for a given movie.
+     *
+     * @param movie the concerned movie
+     * @return an 'mvhd' box
+     */
+    protected Box createMvhd(Movie movie) {
+        MovieHeaderBox mvhd = new MovieHeaderBox();
+        mvhd.setVersion(1);
+        mvhd.setCreationTime(DateHelper.convert(new Date()));
+        mvhd.setModificationTime(DateHelper.convert(new Date()));
+        long movieTimeScale = movie.getTimescale();
+        long duration = 0;
+
+        for (Track track : movie.getTracks()) {
+            long tracksDuration = getDuration(track) * movieTimeScale / track.getTrackMetaData().getTimescale();
+            if (tracksDuration > duration) {
+                duration = tracksDuration;
+            }
+
+
+        }
+
+        mvhd.setDuration(duration);
+        mvhd.setTimescale(movieTimeScale);
+        // find the next available trackId
+        long nextTrackId = 0;
+        for (Track track : movie.getTracks()) {
+            nextTrackId = nextTrackId < track.getTrackMetaData().getTrackId() ? track.getTrackMetaData().getTrackId() : nextTrackId;
+        }
+        mvhd.setNextTrackId(++nextTrackId);
+        return mvhd;
+    }
+
+    /**
+     * Creates a fully populated 'moov' box with all child boxes. Child boxes are:
+     * <ul>
+     * <li>{@link #createMvhd(com.googlecode.mp4parser.authoring.Movie) mvhd}</li>
+     * <li>{@link #createMvex(com.googlecode.mp4parser.authoring.Movie)  mvex}</li>
+     * <li>a {@link #createTrak(com.googlecode.mp4parser.authoring.Track, com.googlecode.mp4parser.authoring.Movie)  trak} for every track</li>
+     * </ul>
+     *
+     * @param movie the concerned movie
+     * @return fully populated 'moov'
+     */
+    protected Box createMoov(Movie movie) {
+        MovieBox movieBox = new MovieBox();
+
+        movieBox.addBox(createMvhd(movie));
+        movieBox.addBox(createMvex(movie));
+
+        for (Track track : movie.getTracks()) {
+            movieBox.addBox(createTrak(track, movie));
+        }
+        // metadata here
+        return movieBox;
+
+    }
+
+    /**
+     * Creates a 'tfra' - track fragment random access box for the given track with the isoFile.
+     * The tfra contains a map of random access points with time as key and offset within the isofile
+     * as value.
+     *
+     * @param track   the concerned track
+     * @param isoFile the track is contained in
+     * @return a track fragment random access box.
+     */
+    protected Box createTfra(Track track, IsoFile isoFile) {
+        TrackFragmentRandomAccessBox tfra = new TrackFragmentRandomAccessBox();
+        tfra.setVersion(1); // use long offsets and times
+        List<TrackFragmentRandomAccessBox.Entry> offset2timeEntries = new LinkedList<TrackFragmentRandomAccessBox.Entry>();
+        List<Box> boxes = isoFile.getBoxes();
+        long offset = 0;
+        long duration = 0;
+        for (Box box : boxes) {
+            if (box instanceof MovieFragmentBox) {
+                List<TrackFragmentBox> trafs = ((MovieFragmentBox) box).getBoxes(TrackFragmentBox.class);
+                for (int i = 0; i < trafs.size(); i++) {
+                    TrackFragmentBox traf = trafs.get(i);
+                    if (traf.getTrackFragmentHeaderBox().getTrackId() == track.getTrackMetaData().getTrackId()) {
+                        // here we are at the offset required for the current entry.
+                        List<TrackRunBox> truns = traf.getBoxes(TrackRunBox.class);
+                        for (int j = 0; j < truns.size(); j++) {
+                            List<TrackFragmentRandomAccessBox.Entry> offset2timeEntriesThisTrun = new LinkedList<TrackFragmentRandomAccessBox.Entry>();
+                            TrackRunBox trun = truns.get(j);
+                            for (int k = 0; k < trun.getEntries().size(); k++) {
+                                TrackRunBox.Entry trunEntry = trun.getEntries().get(k);
+                                SampleFlags sf = null;
+                                if (k == 0 && trun.isFirstSampleFlagsPresent()) {
+                                    sf = trun.getFirstSampleFlags();
+                                } else if (trun.isSampleFlagsPresent()) {
+                                    sf = trunEntry.getSampleFlags();
+                                } else {
+                                    List<MovieExtendsBox> mvexs = isoFile.getMovieBox().getBoxes(MovieExtendsBox.class);
+                                    for (MovieExtendsBox mvex : mvexs) {
+                                        List<TrackExtendsBox> trexs = mvex.getBoxes(TrackExtendsBox.class);
+                                        for (TrackExtendsBox trex : trexs) {
+                                            if (trex.getTrackId() == track.getTrackMetaData().getTrackId()) {
+                                                sf = trex.getDefaultSampleFlags();
+                                            }
+                                        }
+                                    }
+
+                                }
+                                if (sf == null) {
+                                    throw new RuntimeException("Could not find any SampleFlags to indicate random access or not");
+                                }
+                                if (sf.getSampleDependsOn() == 2) {
+                                    offset2timeEntriesThisTrun.add(new TrackFragmentRandomAccessBox.Entry(
+                                            duration,
+                                            offset,
+                                            i + 1, j + 1, k + 1));
+                                }
+                                duration += trunEntry.getSampleDuration();
+                            }
+                            if (offset2timeEntriesThisTrun.size() == trun.getEntries().size() && trun.getEntries().size() > 0) {
+                                // Oooops every sample seems to be random access sample
+                                // is this an audio track? I don't care.
+                                // I just use the first for trun sample for tfra random access
+                                offset2timeEntries.add(offset2timeEntriesThisTrun.get(0));
+                            } else {
+                                offset2timeEntries.addAll(offset2timeEntriesThisTrun);
+                            }
+                        }
+                    }
+                }
+            }
+
+
+            offset += box.getSize();
+        }
+        tfra.setEntries(offset2timeEntries);
+        tfra.setTrackId(track.getTrackMetaData().getTrackId());
+        return tfra;
+    }
+
+    /**
+     * Creates a 'mfra' - movie fragment random access box for the given movie in the given
+     * isofile. Uses {@link #createTfra(com.googlecode.mp4parser.authoring.Track, com.coremedia.iso.IsoFile)}
+     * to generate the child boxes.
+     *
+     * @param movie   concerned movie
+     * @param isoFile concerned isofile
+     * @return a complete 'mfra' box
+     */
+    protected Box createMfra(Movie movie, IsoFile isoFile) {
+        MovieFragmentRandomAccessBox mfra = new MovieFragmentRandomAccessBox();
+        for (Track track : movie.getTracks()) {
+            mfra.addBox(createTfra(track, isoFile));
+        }
+
+        MovieFragmentRandomAccessOffsetBox mfro = new MovieFragmentRandomAccessOffsetBox();
+        mfra.addBox(mfro);
+        mfro.setMfraSize(mfra.getSize());
+        return mfra;
+    }
+
+    protected Box createTrex(Movie movie, Track track) {
+        TrackExtendsBox trex = new TrackExtendsBox();
+        trex.setTrackId(track.getTrackMetaData().getTrackId());
+        trex.setDefaultSampleDescriptionIndex(1);
+        trex.setDefaultSampleDuration(0);
+        trex.setDefaultSampleSize(0);
+        SampleFlags sf = new SampleFlags();
+        if ("soun".equals(track.getHandler())) {
+            // as far as I know there is no audio encoding
+            // where the sample are not self contained.
+            sf.setSampleDependsOn(2);
+            sf.setSampleIsDependedOn(2);
+        }
+        trex.setDefaultSampleFlags(sf);
+        return trex;
+    }
+
+    /**
+     * Creates a 'mvex' - movie extends box and populates it with 'trex' boxes
+     * by calling {@link #createTrex(com.googlecode.mp4parser.authoring.Movie, com.googlecode.mp4parser.authoring.Track)}
+     * for each track to generate them
+     *
+     * @param movie the source movie
+     * @return a complete 'mvex'
+     */
+    protected Box createMvex(Movie movie) {
+        MovieExtendsBox mvex = new MovieExtendsBox();
+        final MovieExtendsHeaderBox mved = new MovieExtendsHeaderBox();
+        for (Track track : movie.getTracks()) {
+            final long trackDuration = getTrackDuration(movie, track);
+            if (mved.getFragmentDuration() < trackDuration) {
+                mved.setFragmentDuration(trackDuration);
+            }
+        }
+        mvex.addBox(mved);
+
+        for (Track track : movie.getTracks()) {
+            mvex.addBox(createTrex(movie, track));
+        }
+        return mvex;
+    }
+
+    protected Box createTkhd(Movie movie, Track track) {
+        TrackHeaderBox tkhd = new TrackHeaderBox();
+        tkhd.setVersion(1);
+        int flags = 0;
+        if (track.isEnabled()) {
+            flags += 1;
+        }
+
+        if (track.isInMovie()) {
+            flags += 2;
+        }
+
+        if (track.isInPreview()) {
+            flags += 4;
+        }
+
+        if (track.isInPoster()) {
+            flags += 8;
+        }
+        tkhd.setFlags(flags);
+
+        tkhd.setAlternateGroup(track.getTrackMetaData().getGroup());
+        tkhd.setCreationTime(DateHelper.convert(track.getTrackMetaData().getCreationTime()));
+        // We need to take edit list box into account in trackheader duration
+        // but as long as I don't support edit list boxes it is sufficient to
+        // just translate media duration to movie timescale
+        tkhd.setDuration(getTrackDuration(movie, track));
+        tkhd.setHeight(track.getTrackMetaData().getHeight());
+        tkhd.setWidth(track.getTrackMetaData().getWidth());
+        tkhd.setLayer(track.getTrackMetaData().getLayer());
+        tkhd.setModificationTime(DateHelper.convert(new Date()));
+        tkhd.setTrackId(track.getTrackMetaData().getTrackId());
+        tkhd.setVolume(track.getTrackMetaData().getVolume());
+        return tkhd;
+    }
+
+    private long getTrackDuration(Movie movie, Track track) {
+        return getDuration(track) * movie.getTimescale() / track.getTrackMetaData().getTimescale();
+    }
+
+    protected Box createMdhd(Movie movie, Track track) {
+        MediaHeaderBox mdhd = new MediaHeaderBox();
+        mdhd.setCreationTime(DateHelper.convert(track.getTrackMetaData().getCreationTime()));
+        mdhd.setDuration(getDuration(track));
+        mdhd.setTimescale(track.getTrackMetaData().getTimescale());
+        mdhd.setLanguage(track.getTrackMetaData().getLanguage());
+        return mdhd;
+    }
+
+    protected Box createStbl(Movie movie, Track track) {
+        SampleTableBox stbl = new SampleTableBox();
+
+        stbl.addBox(track.getSampleDescriptionBox());
+        stbl.addBox(new TimeToSampleBox());
+        //stbl.addBox(new SampleToChunkBox());
+        stbl.addBox(new StaticChunkOffsetBox());
+        return stbl;
+    }
+
+    protected Box createMinf(Track track, Movie movie) {
+        MediaInformationBox minf = new MediaInformationBox();
+        minf.addBox(track.getMediaHeaderBox());
+        minf.addBox(createDinf(movie, track));
+        minf.addBox(createStbl(movie, track));
+        return minf;
+    }
+
+    protected Box createMdiaHdlr(Track track, Movie movie) {
+        HandlerBox hdlr = new HandlerBox();
+        hdlr.setHandlerType(track.getHandler());
+        return hdlr;
+    }
+
+    protected Box createMdia(Track track, Movie movie) {
+        MediaBox mdia = new MediaBox();
+        mdia.addBox(createMdhd(movie, track));
+
+
+        mdia.addBox(createMdiaHdlr(track, movie));
+
+
+        mdia.addBox(createMinf(track, movie));
+        return mdia;
+    }
+
+    protected Box createTrak(Track track, Movie movie) {
+        LOG.fine("Creating Track " + track);
+        TrackBox trackBox = new TrackBox();
+        trackBox.addBox(createTkhd(movie, track));
+        trackBox.addBox(createMdia(track, movie));
+        return trackBox;
+    }
+
+    protected DataInformationBox createDinf(Movie movie, Track track) {
+        DataInformationBox dinf = new DataInformationBox();
+        DataReferenceBox dref = new DataReferenceBox();
+        dinf.addBox(dref);
+        DataEntryUrlBox url = new DataEntryUrlBox();
+        url.setFlags(1);
+        dref.addBox(url);
+        return dinf;
+    }
+
+    public FragmentIntersectionFinder getFragmentIntersectionFinder() {
+        return intersectionFinder;
+    }
+
+    public void setIntersectionFinder(FragmentIntersectionFinder intersectionFinder) {
+        this.intersectionFinder = intersectionFinder;
+    }
+
+    protected long getDuration(Track track) {
+        long duration = 0;
+        for (TimeToSampleBox.Entry entry : track.getDecodingTimeEntries()) {
+            duration += entry.getCount() * entry.getDelta();
+        }
+        return duration;
+    }
+
+
+}
diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/authoring/builder/Mp4Builder.java b/isoparser/src/main/java/com/googlecode/mp4parser/authoring/builder/Mp4Builder.java
new file mode 100644
index 0000000..725745e
--- /dev/null
+++ b/isoparser/src/main/java/com/googlecode/mp4parser/authoring/builder/Mp4Builder.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2012 Sebastian Annies, Hamburg
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.googlecode.mp4parser.authoring.builder;
+
+import com.coremedia.iso.IsoFile;
+import com.googlecode.mp4parser.authoring.Movie;
+
+/**
+ * Transforms a <code>Movie</code> object to an IsoFile. Implementations can
+ * determine the specific format: Fragmented MP4, MP4, MP4 with Apple Metadata,
+ * MP4 with 3GPP Metadata, MOV.
+ */
+public interface Mp4Builder {
+    /**
+     * Builds the actual IsoFile from the Movie.
+     *
+     * @param movie data source
+     * @return the freshly built IsoFile
+     */
+    public IsoFile build(Movie movie);
+
+}
diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/authoring/builder/SyncSampleIntersectFinderImpl.java b/isoparser/src/main/java/com/googlecode/mp4parser/authoring/builder/SyncSampleIntersectFinderImpl.java
new file mode 100644
index 0000000..2766c5e
--- /dev/null
+++ b/isoparser/src/main/java/com/googlecode/mp4parser/authoring/builder/SyncSampleIntersectFinderImpl.java
@@ -0,0 +1,334 @@
+/*
+ * Copyright 2012 Sebastian Annies, Hamburg
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.googlecode.mp4parser.authoring.builder;
+
+import com.coremedia.iso.boxes.TimeToSampleBox;
+import com.coremedia.iso.boxes.sampleentry.AudioSampleEntry;
+import com.googlecode.mp4parser.authoring.Movie;
+import com.googlecode.mp4parser.authoring.Track;
+
+import java.util.*;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.logging.Logger;
+
+import static com.googlecode.mp4parser.util.Math.lcm;
+
+/**
+ * This <code>FragmentIntersectionFinder</code> cuts the input movie video tracks in
+ * fragments of the same length exactly before the sync samples. Audio tracks are cut
+ * into pieces of similar length.
+ */
+public class SyncSampleIntersectFinderImpl implements FragmentIntersectionFinder {
+
+    private static Logger LOG = Logger.getLogger(SyncSampleIntersectFinderImpl.class.getName());
+    private static Map<CacheTuple, long[]> getTimesCache = new ConcurrentHashMap<CacheTuple, long[]>();
+    private static Map<CacheTuple, long[]> getSampleNumbersCache = new ConcurrentHashMap<CacheTuple, long[]>();
+
+    private final int minFragmentDurationSeconds;
+
+    public SyncSampleIntersectFinderImpl() {
+        minFragmentDurationSeconds = 0;
+    }
+
+    /**
+     * Creates a <code>SyncSampleIntersectFinderImpl</code> that will not create any fragment
+     * smaller than the given <code>minFragmentDurationSeconds</code>
+     *
+     * @param minFragmentDurationSeconds the smallest allowable duration of a fragment.
+     */
+    public SyncSampleIntersectFinderImpl(int minFragmentDurationSeconds) {
+        this.minFragmentDurationSeconds = minFragmentDurationSeconds;
+    }
+
+    /**
+     * Gets an array of sample numbers that are meant to be the first sample of each
+     * chunk or fragment.
+     *
+     * @param track concerned track
+     * @param movie the context of the track
+     * @return an array containing the ordinal of each fragment's first sample
+     */
+    public long[] sampleNumbers(Track track, Movie movie) {
+        final CacheTuple key = new CacheTuple(track, movie);
+        final long[] result = getSampleNumbersCache.get(key);
+        if (result != null) {
+            return result;
+        }
+
+        if ("vide".equals(track.getHandler())) {
+            if (track.getSyncSamples() != null && track.getSyncSamples().length > 0) {
+                List<long[]> times = getSyncSamplesTimestamps(movie, track);
+                final long[] commonIndices = getCommonIndices(track.getSyncSamples(), getTimes(track, movie), track.getTrackMetaData().getTimescale(), times.toArray(new long[times.size()][]));
+                getSampleNumbersCache.put(key, commonIndices);
+                return commonIndices;
+            } else {
+                throw new RuntimeException("Video Tracks need sync samples. Only tracks other than video may have no sync samples.");
+            }
+        } else if ("soun".equals(track.getHandler())) {
+            Track referenceTrack = null;
+            for (Track candidate : movie.getTracks()) {
+                if (candidate.getSyncSamples() != null && "vide".equals(candidate.getHandler()) && candidate.getSyncSamples().length > 0) {
+                    referenceTrack = candidate;
+                }
+            }
+            if (referenceTrack != null) {
+
+                // Gets the reference track's fra
+                long[] refSyncSamples = sampleNumbers(referenceTrack, movie);
+
+                int refSampleCount = referenceTrack.getSamples().size();
+
+                long[] syncSamples = new long[refSyncSamples.length];
+                long minSampleRate = 192000;
+                for (Track testTrack : movie.getTracks()) {
+                    if ("soun".equals(testTrack.getHandler())) {
+                        AudioSampleEntry ase = (AudioSampleEntry) testTrack.getSampleDescriptionBox().getSampleEntry();
+                        if (ase.getSampleRate() < minSampleRate) {
+                            minSampleRate = ase.getSampleRate();
+                            long sc = testTrack.getSamples().size();
+                            double stretch = (double) sc / refSampleCount;
+                            TimeToSampleBox.Entry sttsEntry = testTrack.getDecodingTimeEntries().get(0);
+                            long samplesPerFrame = sttsEntry.getDelta(); // Assuming all audio tracks have the same number of samples per frame, which they do for all known types
+
+                            for (int i = 0; i < syncSamples.length; i++) {
+                                long start = (long) Math.ceil(stretch * (refSyncSamples[i] - 1) * samplesPerFrame);
+                                syncSamples[i] = start;
+                                // The Stretch makes sure that there are as much audio and video chunks!
+                            }
+                            break;
+                        }
+                    }
+                }
+                AudioSampleEntry ase = (AudioSampleEntry) track.getSampleDescriptionBox().getSampleEntry();
+                TimeToSampleBox.Entry sttsEntry = track.getDecodingTimeEntries().get(0);
+                long samplesPerFrame = sttsEntry.getDelta(); // Assuming all audio tracks have the same number of samples per frame, which they do for all known types
+                double factor = (double) ase.getSampleRate() / (double) minSampleRate;
+                if (factor != Math.rint(factor)) { // Not an integer
+                    throw new RuntimeException("Sample rates must be a multiple of the lowest sample rate to create a correct file!");
+                }
+                for (int i = 0; i < syncSamples.length; i++) {
+                    syncSamples[i] = (long) (1 + syncSamples[i] * factor / (double) samplesPerFrame);
+                }
+                getSampleNumbersCache.put(key, syncSamples);
+                return syncSamples;
+            }
+            throw new RuntimeException("There was absolutely no Track with sync samples. I can't work with that!");
+        } else {
+            // Ok, my track has no sync samples - let's find one with sync samples.
+            for (Track candidate : movie.getTracks()) {
+                if (candidate.getSyncSamples() != null && candidate.getSyncSamples().length > 0) {
+                    long[] refSyncSamples = sampleNumbers(candidate, movie);
+                    int refSampleCount = candidate.getSamples().size();
+
+                    long[] syncSamples = new long[refSyncSamples.length];
+                    long sc = track.getSamples().size();
+                    double stretch = (double) sc / refSampleCount;
+
+                    for (int i = 0; i < syncSamples.length; i++) {
+                        long start = (long) Math.ceil(stretch * (refSyncSamples[i] - 1)) + 1;
+                        syncSamples[i] = start;
+                        // The Stretch makes sure that there are as much audio and video chunks!
+                    }
+                    getSampleNumbersCache.put(key, syncSamples);
+                    return syncSamples;
+                }
+            }
+            throw new RuntimeException("There was absolutely no Track with sync samples. I can't work with that!");
+        }
+
+
+    }
+
+    /**
+     * Calculates the timestamp of all tracks' sync samples.
+     *
+     * @param movie
+     * @param track
+     * @return
+     */
+    public static List<long[]> getSyncSamplesTimestamps(Movie movie, Track track) {
+        List<long[]> times = new LinkedList<long[]>();
+        for (Track currentTrack : movie.getTracks()) {
+            if (currentTrack.getHandler().equals(track.getHandler())) {
+                long[] currentTrackSyncSamples = currentTrack.getSyncSamples();
+                if (currentTrackSyncSamples != null && currentTrackSyncSamples.length > 0) {
+                    final long[] currentTrackTimes = getTimes(currentTrack, movie);
+                    times.add(currentTrackTimes);
+                }
+            }
+        }
+        return times;
+    }
+
+    public long[] getCommonIndices(long[] syncSamples, long[] syncSampleTimes, long timeScale, long[]... otherTracksTimes) {
+        List<Long> nuSyncSamples = new LinkedList<Long>();
+        List<Long> nuSyncSampleTimes = new LinkedList<Long>();
+
+
+        for (int i = 0; i < syncSampleTimes.length; i++) {
+            boolean foundInEveryRef = true;
+            for (long[] times : otherTracksTimes) {
+                foundInEveryRef &= (Arrays.binarySearch(times, syncSampleTimes[i]) >= 0);
+            }
+
+            if (foundInEveryRef) {
+                // use sample only if found in every other track.
+                nuSyncSamples.add(syncSamples[i]);
+                nuSyncSampleTimes.add(syncSampleTimes[i]);
+            }
+        }
+        // We have two arrays now:
+        // nuSyncSamples: Contains all common sync samples
+        // nuSyncSampleTimes: Contains the times of all sync samples
+
+        // Start: Warn user if samples are not matching!
+        if (nuSyncSamples.size() < (syncSamples.length * 0.25)) {
+            String log = "";
+            log += String.format("%5d - Common:  [", nuSyncSamples.size());
+            for (long l : nuSyncSamples) {
+                log += (String.format("%10d,", l));
+            }
+            log += ("]");
+            LOG.warning(log);
+            log = "";
+
+            log += String.format("%5d - In    :  [", syncSamples.length);
+            for (long l : syncSamples) {
+                log += (String.format("%10d,", l));
+            }
+            log += ("]");
+            LOG.warning(log);
+            LOG.warning("There are less than 25% of common sync samples in the given track.");
+            throw new RuntimeException("There are less than 25% of common sync samples in the given track.");
+        } else if (nuSyncSamples.size() < (syncSamples.length * 0.5)) {
+            LOG.fine("There are less than 50% of common sync samples in the given track. This is implausible but I'm ok to continue.");
+        } else if (nuSyncSamples.size() < syncSamples.length) {
+            LOG.finest("Common SyncSample positions vs. this tracks SyncSample positions: " + nuSyncSamples.size() + " vs. " + syncSamples.length);
+        }
+        // End: Warn user if samples are not matching!
+
+
+
+
+        List<Long> finalSampleList = new LinkedList<Long>();
+
+        if (minFragmentDurationSeconds > 0) {
+            // if minFragmentDurationSeconds is greater 0
+            // we need to throw away certain samples.
+            long lastSyncSampleTime = -1;
+            Iterator<Long> nuSyncSamplesIterator = nuSyncSamples.iterator();
+            Iterator<Long> nuSyncSampleTimesIterator = nuSyncSampleTimes.iterator();
+            while (nuSyncSamplesIterator.hasNext() && nuSyncSampleTimesIterator.hasNext()) {
+                long curSyncSample = nuSyncSamplesIterator.next();
+                long curSyncSampleTime = nuSyncSampleTimesIterator.next();
+                if (lastSyncSampleTime == -1 || (curSyncSampleTime - lastSyncSampleTime) / timeScale >= minFragmentDurationSeconds) {
+                    finalSampleList.add(curSyncSample);
+                    lastSyncSampleTime = curSyncSampleTime;
+                }
+            }
+        } else {
+            // the list of all samples is the final list of samples
+            // since minFragmentDurationSeconds ist not used.
+            finalSampleList = nuSyncSamples;
+        }
+
+
+        // transform the list to an array
+        long[] finalSampleArray = new long[finalSampleList.size()];
+        for (int i = 0; i < finalSampleArray.length; i++) {
+            finalSampleArray[i] = finalSampleList.get(i);
+        }
+        return finalSampleArray;
+
+    }
+
+
+    private static long[] getTimes(Track track, Movie m) {
+        final CacheTuple key = new CacheTuple(track, m);
+        final long[] result = getTimesCache.get(key);
+        if (result != null) {
+            return result;
+        }
+
+        long[] syncSamples = track.getSyncSamples();
+        long[] syncSampleTimes = new long[syncSamples.length];
+        Queue<TimeToSampleBox.Entry> timeQueue = new LinkedList<TimeToSampleBox.Entry>(track.getDecodingTimeEntries());
+
+        int currentSample = 1;  // first syncsample is 1
+        long currentDuration = 0;
+        long currentDelta = 0;
+        int currentSyncSampleIndex = 0;
+        long left = 0;
+
+        final long scalingFactor = calculateTracktimesScalingFactor(m, track);
+
+        while (currentSample <= syncSamples[syncSamples.length - 1]) {
+            if (currentSample++ == syncSamples[currentSyncSampleIndex]) {
+                syncSampleTimes[currentSyncSampleIndex++] = currentDuration * scalingFactor;
+            }
+            if (left-- == 0) {
+                TimeToSampleBox.Entry entry = timeQueue.poll();
+                left = entry.getCount() - 1;
+                currentDelta = entry.getDelta();
+            }
+            currentDuration += currentDelta;
+        }
+        getTimesCache.put(key, syncSampleTimes);
+        return syncSampleTimes;
+    }
+
+    private static long calculateTracktimesScalingFactor(Movie m, Track track) {
+        long timeScale = 1;
+        for (Track track1 : m.getTracks()) {
+            if (track1.getHandler().equals(track.getHandler())) {
+                if (track1.getTrackMetaData().getTimescale() != track.getTrackMetaData().getTimescale()) {
+                    timeScale = lcm(timeScale, track1.getTrackMetaData().getTimescale());
+                }
+            }
+        }
+        return timeScale;
+    }
+
+    public static class CacheTuple {
+        Track track;
+        Movie movie;
+
+        public CacheTuple(Track track, Movie movie) {
+            this.track = track;
+            this.movie = movie;
+        }
+
+        @Override
+        public boolean equals(Object o) {
+            if (this == o) return true;
+            if (o == null || getClass() != o.getClass()) return false;
+
+            CacheTuple that = (CacheTuple) o;
+
+            if (movie != null ? !movie.equals(that.movie) : that.movie != null) return false;
+            if (track != null ? !track.equals(that.track) : that.track != null) return false;
+
+            return true;
+        }
+
+        @Override
+        public int hashCode() {
+            int result = track != null ? track.hashCode() : 0;
+            result = 31 * result + (movie != null ? movie.hashCode() : 0);
+            return result;
+        }
+    }
+}
diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/authoring/builder/TwoSecondIntersectionFinder.java b/isoparser/src/main/java/com/googlecode/mp4parser/authoring/builder/TwoSecondIntersectionFinder.java
new file mode 100644
index 0000000..88aa4ab
--- /dev/null
+++ b/isoparser/src/main/java/com/googlecode/mp4parser/authoring/builder/TwoSecondIntersectionFinder.java
@@ -0,0 +1,86 @@
+/*
+ * Copyright 2012 Sebastian Annies, Hamburg
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.googlecode.mp4parser.authoring.builder;
+
+import com.coremedia.iso.boxes.TimeToSampleBox;
+import com.googlecode.mp4parser.authoring.Movie;
+import com.googlecode.mp4parser.authoring.Track;
+
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * This <code>FragmentIntersectionFinder</code> cuts the input movie in 2 second
+ * snippets.
+ */
+public class TwoSecondIntersectionFinder implements FragmentIntersectionFinder {
+
+    protected long getDuration(Track track) {
+        long duration = 0;
+        for (TimeToSampleBox.Entry entry : track.getDecodingTimeEntries()) {
+            duration += entry.getCount() * entry.getDelta();
+        }
+        return duration;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public long[] sampleNumbers(Track track, Movie movie) {
+        List<TimeToSampleBox.Entry> entries = track.getDecodingTimeEntries();
+
+        double trackLength = 0;
+        for (Track thisTrack : movie.getTracks()) {
+            double thisTracksLength = getDuration(thisTrack) / thisTrack.getTrackMetaData().getTimescale();
+            if (trackLength < thisTracksLength) {
+                trackLength = thisTracksLength;
+            }
+        }
+
+        int fragmentCount = (int)Math.ceil(trackLength / 2) - 1;
+        if (fragmentCount < 1) {
+            fragmentCount = 1;
+        }
+
+        long fragments[] = new long[fragmentCount];
+        Arrays.fill(fragments, -1);
+        fragments[0] = 1;
+
+        long time = 0;
+        int samples = 0;
+        for (TimeToSampleBox.Entry entry : entries) {
+            for (int i = 0; i < entry.getCount(); i++) {
+                int currentFragment = (int) (time / track.getTrackMetaData().getTimescale() / 2) + 1;
+                if (currentFragment >= fragments.length) {
+                    break;
+                }
+                fragments[currentFragment] = samples++ + 1;
+                time += entry.getDelta();
+            }
+        }
+        long last = samples + 1;
+        // fill all -1 ones.
+        for (int i = fragments.length - 1; i >= 0; i--) {
+            if (fragments[i] == -1) {
+                fragments[i] = last ;
+            }
+            last = fragments[i];
+        }
+        return fragments;
+
+    }
+
+}
diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/authoring/container/.svn/all-wcprops b/isoparser/src/main/java/com/googlecode/mp4parser/authoring/container/.svn/all-wcprops
new file mode 100644
index 0000000..a7245be
--- /dev/null
+++ b/isoparser/src/main/java/com/googlecode/mp4parser/authoring/container/.svn/all-wcprops
@@ -0,0 +1,5 @@
+K 25
+svn:wc:ra_dav:version-url
+V 92
+/svn/!svn/ver/418/trunk/isoparser/src/main/java/com/googlecode/mp4parser/authoring/container
+END
diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/authoring/container/.svn/entries b/isoparser/src/main/java/com/googlecode/mp4parser/authoring/container/.svn/entries
new file mode 100644
index 0000000..bde4d0e
--- /dev/null
+++ b/isoparser/src/main/java/com/googlecode/mp4parser/authoring/container/.svn/entries
@@ -0,0 +1,31 @@
+10
+
+dir
+778
+http://mp4parser.googlecode.com/svn/trunk/isoparser/src/main/java/com/googlecode/mp4parser/authoring/container
+http://mp4parser.googlecode.com/svn
+
+
+
+2012-03-11T20:54:45.638478Z
+418
+Sebastian.Annies@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+7decde4b-c250-0410-a0da-51896bc88be6
+
+mp4
+dir
+
diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/authoring/container/mp4/.svn/all-wcprops b/isoparser/src/main/java/com/googlecode/mp4parser/authoring/container/mp4/.svn/all-wcprops
new file mode 100644
index 0000000..ec2a4f9
--- /dev/null
+++ b/isoparser/src/main/java/com/googlecode/mp4parser/authoring/container/mp4/.svn/all-wcprops
@@ -0,0 +1,11 @@
+K 25
+svn:wc:ra_dav:version-url
+V 96
+/svn/!svn/ver/418/trunk/isoparser/src/main/java/com/googlecode/mp4parser/authoring/container/mp4
+END
+MovieCreator.java
+K 25
+svn:wc:ra_dav:version-url
+V 114
+/svn/!svn/ver/418/trunk/isoparser/src/main/java/com/googlecode/mp4parser/authoring/container/mp4/MovieCreator.java
+END
diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/authoring/container/mp4/.svn/entries b/isoparser/src/main/java/com/googlecode/mp4parser/authoring/container/mp4/.svn/entries
new file mode 100644
index 0000000..d7d7f30
--- /dev/null
+++ b/isoparser/src/main/java/com/googlecode/mp4parser/authoring/container/mp4/.svn/entries
@@ -0,0 +1,62 @@
+10
+
+dir
+778
+http://mp4parser.googlecode.com/svn/trunk/isoparser/src/main/java/com/googlecode/mp4parser/authoring/container/mp4
+http://mp4parser.googlecode.com/svn
+
+
+
+2012-03-11T20:54:45.638478Z
+418
+Sebastian.Annies@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+7decde4b-c250-0410-a0da-51896bc88be6
+
+MovieCreator.java
+file
+
+
+
+
+2012-09-14T17:27:49.987212Z
+ecb22de8d79473683de67e40f494641d
+2012-03-11T20:54:45.638478Z
+418
+Sebastian.Annies@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+1404
+
diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/authoring/container/mp4/.svn/text-base/MovieCreator.java.svn-base b/isoparser/src/main/java/com/googlecode/mp4parser/authoring/container/mp4/.svn/text-base/MovieCreator.java.svn-base
new file mode 100644
index 0000000..ed9d15f
--- /dev/null
+++ b/isoparser/src/main/java/com/googlecode/mp4parser/authoring/container/mp4/.svn/text-base/MovieCreator.java.svn-base
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2012 Sebastian Annies, Hamburg
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.googlecode.mp4parser.authoring.container.mp4;
+
+import com.coremedia.iso.IsoFile;
+import com.coremedia.iso.boxes.TrackBox;
+import com.googlecode.mp4parser.authoring.Movie;
+import com.googlecode.mp4parser.authoring.Mp4TrackImpl;
+
+import java.io.IOException;
+import java.nio.channels.ReadableByteChannel;
+import java.util.List;
+
+/**
+ * Shortcut to build a movie from an MP4 file.
+ */
+public class MovieCreator {
+    public static Movie build(ReadableByteChannel channel) throws IOException {
+        IsoFile isoFile = new IsoFile(channel);
+        Movie m = new Movie();
+        List<TrackBox> trackBoxes = isoFile.getMovieBox().getBoxes(TrackBox.class);
+        for (TrackBox trackBox : trackBoxes) {
+            m.addTrack(new Mp4TrackImpl(trackBox));
+        }
+        return m;
+    }
+}
diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/authoring/container/mp4/MovieCreator.java b/isoparser/src/main/java/com/googlecode/mp4parser/authoring/container/mp4/MovieCreator.java
new file mode 100644
index 0000000..ed9d15f
--- /dev/null
+++ b/isoparser/src/main/java/com/googlecode/mp4parser/authoring/container/mp4/MovieCreator.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2012 Sebastian Annies, Hamburg
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.googlecode.mp4parser.authoring.container.mp4;
+
+import com.coremedia.iso.IsoFile;
+import com.coremedia.iso.boxes.TrackBox;
+import com.googlecode.mp4parser.authoring.Movie;
+import com.googlecode.mp4parser.authoring.Mp4TrackImpl;
+
+import java.io.IOException;
+import java.nio.channels.ReadableByteChannel;
+import java.util.List;
+
+/**
+ * Shortcut to build a movie from an MP4 file.
+ */
+public class MovieCreator {
+    public static Movie build(ReadableByteChannel channel) throws IOException {
+        IsoFile isoFile = new IsoFile(channel);
+        Movie m = new Movie();
+        List<TrackBox> trackBoxes = isoFile.getMovieBox().getBoxes(TrackBox.class);
+        for (TrackBox trackBox : trackBoxes) {
+            m.addTrack(new Mp4TrackImpl(trackBox));
+        }
+        return m;
+    }
+}
diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/authoring/tracks/.svn/all-wcprops b/isoparser/src/main/java/com/googlecode/mp4parser/authoring/tracks/.svn/all-wcprops
new file mode 100644
index 0000000..496d7bb
--- /dev/null
+++ b/isoparser/src/main/java/com/googlecode/mp4parser/authoring/tracks/.svn/all-wcprops
@@ -0,0 +1,89 @@
+K 25
+svn:wc:ra_dav:version-url
+V 89
+/svn/!svn/ver/756/trunk/isoparser/src/main/java/com/googlecode/mp4parser/authoring/tracks
+END
+DivideTimeScaleTrack.java
+K 25
+svn:wc:ra_dav:version-url
+V 115
+/svn/!svn/ver/686/trunk/isoparser/src/main/java/com/googlecode/mp4parser/authoring/tracks/DivideTimeScaleTrack.java
+END
+CroppedTrack.java
+K 25
+svn:wc:ra_dav:version-url
+V 107
+/svn/!svn/ver/686/trunk/isoparser/src/main/java/com/googlecode/mp4parser/authoring/tracks/CroppedTrack.java
+END
+ChangeTimeScaleTrack.java
+K 25
+svn:wc:ra_dav:version-url
+V 115
+/svn/!svn/ver/686/trunk/isoparser/src/main/java/com/googlecode/mp4parser/authoring/tracks/ChangeTimeScaleTrack.java
+END
+EC3TrackImpl.java
+K 25
+svn:wc:ra_dav:version-url
+V 107
+/svn/!svn/ver/756/trunk/isoparser/src/main/java/com/googlecode/mp4parser/authoring/tracks/EC3TrackImpl.java
+END
+ReplaceSampleTrack.java
+K 25
+svn:wc:ra_dav:version-url
+V 113
+/svn/!svn/ver/686/trunk/isoparser/src/main/java/com/googlecode/mp4parser/authoring/tracks/ReplaceSampleTrack.java
+END
+QuicktimeTextTrackImpl.java
+K 25
+svn:wc:ra_dav:version-url
+V 117
+/svn/!svn/ver/691/trunk/isoparser/src/main/java/com/googlecode/mp4parser/authoring/tracks/QuicktimeTextTrackImpl.java
+END
+Amf0Track.java
+K 25
+svn:wc:ra_dav:version-url
+V 104
+/svn/!svn/ver/686/trunk/isoparser/src/main/java/com/googlecode/mp4parser/authoring/tracks/Amf0Track.java
+END
+SilenceTrackImpl.java
+K 25
+svn:wc:ra_dav:version-url
+V 111
+/svn/!svn/ver/698/trunk/isoparser/src/main/java/com/googlecode/mp4parser/authoring/tracks/SilenceTrackImpl.java
+END
+H264TrackImpl.java
+K 25
+svn:wc:ra_dav:version-url
+V 108
+/svn/!svn/ver/756/trunk/isoparser/src/main/java/com/googlecode/mp4parser/authoring/tracks/H264TrackImpl.java
+END
+TextTrackImpl.java
+K 25
+svn:wc:ra_dav:version-url
+V 108
+/svn/!svn/ver/684/trunk/isoparser/src/main/java/com/googlecode/mp4parser/authoring/tracks/TextTrackImpl.java
+END
+AACTrackImpl.java
+K 25
+svn:wc:ra_dav:version-url
+V 107
+/svn/!svn/ver/756/trunk/isoparser/src/main/java/com/googlecode/mp4parser/authoring/tracks/AACTrackImpl.java
+END
+MultiplyTimeScaleTrack.java
+K 25
+svn:wc:ra_dav:version-url
+V 117
+/svn/!svn/ver/686/trunk/isoparser/src/main/java/com/googlecode/mp4parser/authoring/tracks/MultiplyTimeScaleTrack.java
+END
+AppendTrack.java
+K 25
+svn:wc:ra_dav:version-url
+V 106
+/svn/!svn/ver/714/trunk/isoparser/src/main/java/com/googlecode/mp4parser/authoring/tracks/AppendTrack.java
+END
+AC3TrackImpl.java
+K 25
+svn:wc:ra_dav:version-url
+V 107
+/svn/!svn/ver/756/trunk/isoparser/src/main/java/com/googlecode/mp4parser/authoring/tracks/AC3TrackImpl.java
+END
diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/authoring/tracks/.svn/entries b/isoparser/src/main/java/com/googlecode/mp4parser/authoring/tracks/.svn/entries
new file mode 100644
index 0000000..dbe8ae3
--- /dev/null
+++ b/isoparser/src/main/java/com/googlecode/mp4parser/authoring/tracks/.svn/entries
@@ -0,0 +1,504 @@
+10
+
+dir
+778
+http://mp4parser.googlecode.com/svn/trunk/isoparser/src/main/java/com/googlecode/mp4parser/authoring/tracks
+http://mp4parser.googlecode.com/svn
+
+
+
+2012-08-17T01:19:11.953078Z
+756
+michael.stattmann@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+7decde4b-c250-0410-a0da-51896bc88be6
+
+DivideTimeScaleTrack.java
+file
+
+
+
+
+2012-09-14T17:27:50.507219Z
+6aa41cdb7489e16e879ddebd68b7ac52
+2012-06-24T19:52:05.961412Z
+686
+Sebastian.Annies@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+3893
+
+CroppedTrack.java
+file
+
+
+
+
+2012-09-14T17:27:50.507219Z
+5d9c65d9aac52a26372aa3fdf6f1b7ea
+2012-06-24T19:52:05.961412Z
+686
+Sebastian.Annies@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+6025
+
+ChangeTimeScaleTrack.java
+file
+
+
+
+
+2012-09-14T17:27:50.507219Z
+ba01d30ac4b7c4fa9a2c6538ee537594
+2012-06-24T19:52:05.961412Z
+686
+Sebastian.Annies@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+7152
+
+EC3TrackImpl.java
+file
+
+
+
+
+2012-09-14T17:27:50.507219Z
+1d568bfaa0f41c3771986a7790347072
+2012-08-17T01:19:11.953078Z
+756
+michael.stattmann@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+13623
+
+ReplaceSampleTrack.java
+file
+
+
+
+
+2012-09-14T17:27:50.507219Z
+f6846b7a262ab0e530da46f4d7e34850
+2012-06-24T19:52:05.961412Z
+686
+Sebastian.Annies@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+3139
+
+QuicktimeTextTrackImpl.java
+file
+
+
+
+
+2012-09-14T17:27:50.507219Z
+7ccd01a58545fb02b507b57892eb53e5
+2012-06-24T21:35:59.546504Z
+691
+Sebastian.Annies@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+5128
+
+Amf0Track.java
+file
+
+
+
+
+2012-09-14T17:27:50.507219Z
+4718a34bc271adf4517de9829ac74a9d
+2012-06-24T19:52:05.961412Z
+686
+Sebastian.Annies@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+3858
+
+SilenceTrackImpl.java
+file
+
+
+
+
+2012-09-14T17:27:50.507219Z
+a897677e602dfa0d64af1b0d33a04ca8
+2012-06-26T08:37:32.910396Z
+698
+Sebastian.Annies@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+2623
+
+H264TrackImpl.java
+file
+
+
+
+
+2012-09-14T17:27:50.507219Z
+76abb4b21c13d11215a2ac4cb0c7e461
+2012-08-17T01:19:11.953078Z
+756
+michael.stattmann@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+28816
+
+TextTrackImpl.java
+file
+
+
+
+
+2012-09-14T17:27:50.507219Z
+5a643c876754eb5c7bcf75b4b71114a1
+2012-06-24T14:45:45.932648Z
+684
+Sebastian.Annies@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+4963
+
+AACTrackImpl.java
+file
+
+
+
+
+2012-09-14T17:27:50.507219Z
+ece8d364a9a5aeabf6a281f6d428e3cf
+2012-08-17T01:19:11.953078Z
+756
+michael.stattmann@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+10097
+
+MultiplyTimeScaleTrack.java
+file
+
+
+
+
+2012-09-14T17:27:50.507219Z
+b0ea53239c124607a26a181f594f82a1
+2012-06-24T19:52:05.961412Z
+686
+Sebastian.Annies@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+4192
+
+AppendTrack.java
+file
+
+
+
+
+2012-09-14T17:27:50.507219Z
+e7814aebc4500724771fd0582455a7ca
+2012-07-18T23:22:45.506793Z
+714
+Sebastian.Annies@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+15783
+
+AC3TrackImpl.java
+file
+
+
+
+
+2012-09-14T17:27:50.507219Z
+fbd724739cd9a5f2b28f16b412b27309
+2012-08-17T01:19:11.953078Z
+756
+michael.stattmann@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+19303
+
diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/authoring/tracks/.svn/text-base/AACTrackImpl.java.svn-base b/isoparser/src/main/java/com/googlecode/mp4parser/authoring/tracks/.svn/text-base/AACTrackImpl.java.svn-base
new file mode 100644
index 0000000..df51a1a
--- /dev/null
+++ b/isoparser/src/main/java/com/googlecode/mp4parser/authoring/tracks/.svn/text-base/AACTrackImpl.java.svn-base
@@ -0,0 +1,292 @@
+/*
+ * Copyright 2012 castLabs GmbH, Berlin
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.googlecode.mp4parser.authoring.tracks;
+
+import com.coremedia.iso.boxes.*;
+import com.coremedia.iso.boxes.sampleentry.AudioSampleEntry;
+import com.googlecode.mp4parser.authoring.AbstractTrack;
+import com.googlecode.mp4parser.authoring.TrackMetaData;
+import com.googlecode.mp4parser.boxes.AC3SpecificBox;
+import com.googlecode.mp4parser.boxes.mp4.ESDescriptorBox;
+import com.googlecode.mp4parser.boxes.mp4.objectdescriptors.*;
+
+import java.io.BufferedInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.ByteBuffer;
+import java.util.*;
+
+/**
+ */
+public class AACTrackImpl extends AbstractTrack {
+    public static Map<Integer, Integer> samplingFrequencyIndexMap = new HashMap<Integer, Integer>();
+
+    static {
+        samplingFrequencyIndexMap.put(96000, 0);
+        samplingFrequencyIndexMap.put(88200, 1);
+        samplingFrequencyIndexMap.put(64000, 2);
+        samplingFrequencyIndexMap.put(48000, 3);
+        samplingFrequencyIndexMap.put(44100, 4);
+        samplingFrequencyIndexMap.put(32000, 5);
+        samplingFrequencyIndexMap.put(24000, 6);
+        samplingFrequencyIndexMap.put(22050, 7);
+        samplingFrequencyIndexMap.put(16000, 8);
+        samplingFrequencyIndexMap.put(12000, 9);
+        samplingFrequencyIndexMap.put(11025, 10);
+        samplingFrequencyIndexMap.put(8000, 11);
+        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);
+    }
+
+    TrackMetaData trackMetaData = new TrackMetaData();
+    SampleDescriptionBox sampleDescriptionBox;
+
+    int samplerate;
+    int bitrate;
+    int channelCount;
+    int channelconfig;
+
+    int bufferSizeDB;
+    long maxBitRate;
+    long avgBitRate;
+
+    private BufferedInputStream inputStream;
+    private List<ByteBuffer> samples;
+    boolean readSamples = false;
+    List<TimeToSampleBox.Entry> stts;
+    private String lang = "und";
+
+
+    public AACTrackImpl(InputStream inputStream, String lang) throws IOException {
+        this.lang = lang;
+        parse(inputStream);
+     }
+
+    public AACTrackImpl(InputStream inputStream) throws IOException {
+        parse(inputStream);
+     }
+
+    private void parse(InputStream inputStream) throws IOException {
+        this.inputStream = new BufferedInputStream(inputStream);
+        stts = new LinkedList<TimeToSampleBox.Entry>();
+
+        if (!readVariables()) {
+            throw new IOException();
+        }
+
+        samples = new LinkedList<ByteBuffer>();
+        if (!readSamples()) {
+            throw new IOException();
+        }
+
+        double packetsPerSecond = (double)samplerate / 1024.0;
+        double duration = samples.size() / packetsPerSecond;
+
+        long dataSize = 0;
+        LinkedList<Integer> queue = new LinkedList<Integer>();
+        for (int i = 0; i < samples.size(); i++) {
+            int size = samples.get(i).capacity();
+            dataSize += size;
+            queue.add(size);
+            while (queue.size() > packetsPerSecond) {
+                queue.pop();
+            }
+            if (queue.size() == (int) packetsPerSecond) {
+                int currSize = 0;
+                for (int j = 0 ; j < queue.size(); j++) {
+                    currSize += queue.get(j);
+                }
+                double currBitrate = 8.0 * currSize / queue.size() * packetsPerSecond;
+                if (currBitrate > maxBitRate) {
+                    maxBitRate = (int)currBitrate;
+                }
+            }
+        }
+
+        avgBitRate = (int) (8 * dataSize / duration);
+
+        bufferSizeDB = 1536; /* TODO: Calcultate this somehow! */
+
+        sampleDescriptionBox = new SampleDescriptionBox();
+        AudioSampleEntry audioSampleEntry = new AudioSampleEntry("mp4a");
+        audioSampleEntry.setChannelCount(2);
+        audioSampleEntry.setSampleRate(samplerate);
+        audioSampleEntry.setDataReferenceIndex(1);
+        audioSampleEntry.setSampleSize(16);
+
+
+        ESDescriptorBox esds = new ESDescriptorBox();
+        ESDescriptor descriptor = new ESDescriptor();
+        descriptor.setEsId(0);
+
+        SLConfigDescriptor slConfigDescriptor = new SLConfigDescriptor();
+        slConfigDescriptor.setPredefined(2);
+        descriptor.setSlConfigDescriptor(slConfigDescriptor);
+
+        DecoderConfigDescriptor decoderConfigDescriptor = new DecoderConfigDescriptor();
+        decoderConfigDescriptor.setObjectTypeIndication(0x40);
+        decoderConfigDescriptor.setStreamType(5);
+        decoderConfigDescriptor.setBufferSizeDB(bufferSizeDB);
+        decoderConfigDescriptor.setMaxBitRate(maxBitRate);
+        decoderConfigDescriptor.setAvgBitRate(avgBitRate);
+
+        AudioSpecificConfig audioSpecificConfig = new AudioSpecificConfig();
+        audioSpecificConfig.setAudioObjectType(2); // AAC LC
+        audioSpecificConfig.setSamplingFrequencyIndex(samplingFrequencyIndexMap.get(samplerate));
+        audioSpecificConfig.setChannelConfiguration(channelconfig);
+        decoderConfigDescriptor.setAudioSpecificInfo(audioSpecificConfig);
+
+        descriptor.setDecoderConfigDescriptor(decoderConfigDescriptor);
+
+        ByteBuffer data = descriptor.serialize();
+        esds.setData(data);
+        audioSampleEntry.addBox(esds);
+        sampleDescriptionBox.addBox(audioSampleEntry);
+
+        trackMetaData.setCreationTime(new Date());
+        trackMetaData.setModificationTime(new Date());
+        trackMetaData.setLanguage(lang);
+        trackMetaData.setTimescale(samplerate); // Audio tracks always use samplerate as timescale
+    }
+
+    public SampleDescriptionBox getSampleDescriptionBox() {
+        return sampleDescriptionBox;
+    }
+
+    public List<TimeToSampleBox.Entry> getDecodingTimeEntries() {
+        return stts;
+    }
+
+    public List<CompositionTimeToSample.Entry> getCompositionTimeEntries() {
+        return null;
+    }
+
+    public long[] getSyncSamples() {
+        return null;
+    }
+
+    public List<SampleDependencyTypeBox.Entry> getSampleDependencies() {
+        return null;
+    }
+
+    public TrackMetaData getTrackMetaData() {
+        return trackMetaData;
+    }
+
+    public String getHandler() {
+        return "soun";
+    }
+
+    public List<ByteBuffer> getSamples() {
+        return samples;
+    }
+
+    public Box getMediaHeaderBox() {
+        return new SoundMediaHeaderBox();
+    }
+
+    public SubSampleInformationBox getSubsampleInformationBox() {
+        return null;
+    }
+
+    private boolean readVariables() throws IOException {
+        byte[] data = new byte[100];
+        inputStream.mark(100);
+        if (100 != inputStream.read(data, 0, 100)) {
+            return false;
+        }
+        inputStream.reset(); // Rewind
+        ByteBuffer bb = ByteBuffer.wrap(data);
+        BitReaderBuffer brb = new BitReaderBuffer(bb);
+        int syncword = brb.readBits(12);
+        if (syncword != 0xfff) {
+            return false;
+        }
+        int id = brb.readBits(1);
+        int layer = brb.readBits(2);
+        int protectionAbsent = brb.readBits(1);
+        int profile = brb.readBits(2);
+        samplerate = samplingFrequencyIndexMap.get(brb.readBits(4));
+        brb.readBits(1);
+        channelconfig = brb.readBits(3);
+        int original = brb.readBits(1);
+        int home = brb.readBits(1);
+        int emphasis = brb.readBits(2);
+
+        return true;
+    }
+
+    private boolean readSamples() throws IOException {
+        if (readSamples) {
+            return true;
+        }
+
+        readSamples = true;
+        byte[] header = new byte[15];
+        boolean ret = false;
+        inputStream.mark(15);
+        while (-1 != inputStream.read(header)) {
+            ret = true;
+            ByteBuffer bb = ByteBuffer.wrap(header);
+            inputStream.reset();
+            BitReaderBuffer brb = new BitReaderBuffer(bb);
+            int syncword = brb.readBits(12);
+            if (syncword != 0xfff) {
+                return false;
+            }
+            brb.readBits(3);
+            int protectionAbsent = brb.readBits(1);
+            brb.readBits(14);
+            int frameSize = brb.readBits(13);
+            int bufferFullness = brb.readBits(11);
+            int noBlocks = brb.readBits(2);
+            int used = (int) Math.ceil(brb.getPosition() / 8.0);
+            if (protectionAbsent == 0) {
+                used += 2;
+            }
+            inputStream.skip(used);
+            frameSize -= used;
+//            System.out.println("Size: " + frameSize + " fullness: " + bufferFullness + " no blocks: " + noBlocks);
+            byte[] data = new byte[frameSize];
+            inputStream.read(data);
+            samples.add(ByteBuffer.wrap(data));
+            stts.add(new TimeToSampleBox.Entry(1, 1024));
+            inputStream.mark(15);
+        }
+        return ret;
+    }
+
+    @Override
+    public String toString() {
+        return "AACTrackImpl{" +
+                "samplerate=" + samplerate +
+                ", bitrate=" + bitrate +
+                ", channelCount=" + channelCount +
+                ", channelconfig=" + channelconfig +
+                '}';
+    }
+}
+
diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/authoring/tracks/.svn/text-base/AC3TrackImpl.java.svn-base b/isoparser/src/main/java/com/googlecode/mp4parser/authoring/tracks/.svn/text-base/AC3TrackImpl.java.svn-base
new file mode 100644
index 0000000..5e5b2cd
--- /dev/null
+++ b/isoparser/src/main/java/com/googlecode/mp4parser/authoring/tracks/.svn/text-base/AC3TrackImpl.java.svn-base
@@ -0,0 +1,513 @@
+package com.googlecode.mp4parser.authoring.tracks;
+
+import com.coremedia.iso.boxes.*;
+import com.coremedia.iso.boxes.sampleentry.AudioSampleEntry;
+import com.googlecode.mp4parser.authoring.AbstractTrack;
+import com.googlecode.mp4parser.authoring.TrackMetaData;
+import com.googlecode.mp4parser.boxes.AC3SpecificBox;
+import com.googlecode.mp4parser.boxes.mp4.objectdescriptors.BitReaderBuffer;
+
+import java.io.InputStream;
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.util.Date;
+import java.util.LinkedList;
+import java.util.List;
+
+public class AC3TrackImpl extends AbstractTrack {
+    TrackMetaData trackMetaData = new TrackMetaData();
+    SampleDescriptionBox sampleDescriptionBox;
+
+    int samplerate;
+    int bitrate;
+    int channelCount;
+
+    int fscod;
+    int bsid;
+    int bsmod;
+    int acmod;
+    int lfeon;
+    int frmsizecod;
+
+    int frameSize;
+    int[][][][] bitRateAndFrameSizeTable;
+
+    private InputStream inputStream;
+    private List<ByteBuffer> samples;
+    boolean readSamples = false;
+    List<TimeToSampleBox.Entry> stts;
+    private String lang = "und";
+
+    public AC3TrackImpl(InputStream fin, String lang) throws IOException {
+        this.lang = lang;
+        parse(fin);
+    }
+
+    public AC3TrackImpl(InputStream fin) throws IOException {
+        parse(fin);
+    }
+
+    private void parse(InputStream fin) throws IOException {
+        inputStream = fin;
+        bitRateAndFrameSizeTable = new int[19][2][3][2];
+        stts = new LinkedList<TimeToSampleBox.Entry>();
+        initBitRateAndFrameSizeTable();
+        if (!readVariables()) {
+            throw new IOException();
+        }
+
+        sampleDescriptionBox = new SampleDescriptionBox();
+        AudioSampleEntry audioSampleEntry = new AudioSampleEntry("ac-3");
+        audioSampleEntry.setChannelCount(2);  // According to  ETSI TS 102 366 Annex F
+        audioSampleEntry.setSampleRate(samplerate);
+        audioSampleEntry.setDataReferenceIndex(1);
+        audioSampleEntry.setSampleSize(16);
+
+        AC3SpecificBox ac3 = new AC3SpecificBox();
+        ac3.setAcmod(acmod);
+        ac3.setBitRateCode(frmsizecod >> 1);
+        ac3.setBsid(bsid);
+        ac3.setBsmod(bsmod);
+        ac3.setFscod(fscod);
+        ac3.setLfeon(lfeon);
+        ac3.setReserved(0);
+
+        audioSampleEntry.addBox(ac3);
+        sampleDescriptionBox.addBox(audioSampleEntry);
+
+        trackMetaData.setCreationTime(new Date());
+        trackMetaData.setModificationTime(new Date());
+        trackMetaData.setLanguage(lang);
+        trackMetaData.setTimescale(samplerate); // Audio tracks always use samplerate as timescale
+
+        samples = new LinkedList<ByteBuffer>();
+        if (!readSamples()) {
+            throw new IOException();
+        }
+    }
+
+
+    public List<ByteBuffer> getSamples() {
+
+        return samples;
+    }
+
+    public SampleDescriptionBox getSampleDescriptionBox() {
+        return sampleDescriptionBox;
+    }
+
+    public List<TimeToSampleBox.Entry> getDecodingTimeEntries() {
+        return stts;
+    }
+
+    public List<CompositionTimeToSample.Entry> getCompositionTimeEntries() {
+        return null;
+    }
+
+    public long[] getSyncSamples() {
+        return null;
+    }
+
+    public List<SampleDependencyTypeBox.Entry> getSampleDependencies() {
+        return null;
+    }
+
+    public TrackMetaData getTrackMetaData() {
+        return trackMetaData;
+    }
+
+    public String getHandler() {
+        return "soun";
+    }
+
+    public Box getMediaHeaderBox() {
+        return new SoundMediaHeaderBox();
+    }
+
+    public SubSampleInformationBox getSubsampleInformationBox() {
+        return null;
+    }
+
+    private boolean readVariables() throws IOException {
+        byte[] data = new byte[100];
+        inputStream.mark(100);
+        if (100 != inputStream.read(data, 0, 100)) {
+            return false;
+        }
+        inputStream.reset(); // Rewind
+        ByteBuffer bb = ByteBuffer.wrap(data);
+        BitReaderBuffer brb = new BitReaderBuffer(bb);
+        int syncword = brb.readBits(16);
+        if (syncword != 0xb77) {
+            return false;
+        }
+        brb.readBits(16); // CRC-1
+        fscod = brb.readBits(2);
+
+        switch (fscod) {
+            case 0:
+                samplerate = 48000;
+                break;
+
+            case 1:
+                samplerate = 44100;
+                break;
+
+            case 2:
+                samplerate = 32000;
+                break;
+
+            case 3:
+                samplerate = 0;
+                break;
+
+        }
+        if (samplerate == 0) {
+            return false;
+        }
+
+        frmsizecod = brb.readBits(6);
+
+        if (!calcBitrateAndFrameSize(frmsizecod)) {
+            return false;
+        }
+
+        if (frameSize == 0) {
+            return false;
+        }
+        bsid = brb.readBits(5);
+        bsmod = brb.readBits(3);
+        acmod = brb.readBits(3);
+
+        if (bsid == 9) {
+            samplerate /= 2;
+        } else if (bsid != 8 && bsid != 6) {
+            return false;
+        }
+
+        if ((acmod != 1) && ((acmod & 1) == 1)) {
+            brb.readBits(2);
+        }
+
+        if (0 != (acmod & 4)) {
+            brb.readBits(2);
+        }
+
+        if (acmod == 2) {
+            brb.readBits(2);
+        }
+
+        switch (acmod) {
+            case 0:
+                channelCount = 2;
+                break;
+
+            case 1:
+                channelCount = 1;
+                break;
+
+            case 2:
+                channelCount = 2;
+                break;
+
+            case 3:
+                channelCount = 3;
+                break;
+
+            case 4:
+                channelCount = 3;
+                break;
+
+            case 5:
+                channelCount = 4;
+                break;
+
+            case 6:
+                channelCount = 4;
+                break;
+
+            case 7:
+                channelCount = 5;
+                break;
+
+        }
+
+        lfeon = brb.readBits(1);
+
+        if (lfeon == 1) {
+            channelCount++;
+        }
+        return true;
+    }
+
+    private boolean calcBitrateAndFrameSize(int code) {
+        int frmsizecode = code >>> 1;
+        int flag = code & 1;
+        if (frmsizecode > 18 || flag > 1 || fscod > 2) {
+            return false;
+        }
+        bitrate = bitRateAndFrameSizeTable[frmsizecode][flag][fscod][0];
+        frameSize = 2 * bitRateAndFrameSizeTable[frmsizecode][flag][fscod][1];
+        return true;
+    }
+
+    private boolean readSamples() throws IOException {
+        if (readSamples) {
+            return true;
+        }
+        readSamples = true;
+        byte[] header = new byte[5];
+        boolean ret = false;
+        inputStream.mark(5);
+        while (-1 != inputStream.read(header)) {
+            ret = true;
+            int frmsizecode = header[4] & 63;
+            calcBitrateAndFrameSize(frmsizecode);
+            inputStream.reset();
+            byte[] data = new byte[frameSize];
+            inputStream.read(data);
+            samples.add(ByteBuffer.wrap(data));
+            stts.add(new TimeToSampleBox.Entry(1, 1536));
+            inputStream.mark(5);
+        }
+        return ret;
+    }
+
+    private void initBitRateAndFrameSizeTable() {
+        // ETSI 102 366 Table 4.13, in frmsizecod, flag, fscod, bitrate/size order. Note that all sizes are in words, and all bitrates in kbps
+
+        // 48kHz
+        bitRateAndFrameSizeTable[0][0][0][0] = 32;
+        bitRateAndFrameSizeTable[0][1][0][0] = 32;
+        bitRateAndFrameSizeTable[0][0][0][1] = 64;
+        bitRateAndFrameSizeTable[0][1][0][1] = 64;
+        bitRateAndFrameSizeTable[1][0][0][0] = 40;
+        bitRateAndFrameSizeTable[1][1][0][0] = 40;
+        bitRateAndFrameSizeTable[1][0][0][1] = 80;
+        bitRateAndFrameSizeTable[1][1][0][1] = 80;
+        bitRateAndFrameSizeTable[2][0][0][0] = 48;
+        bitRateAndFrameSizeTable[2][1][0][0] = 48;
+        bitRateAndFrameSizeTable[2][0][0][1] = 96;
+        bitRateAndFrameSizeTable[2][1][0][1] = 96;
+        bitRateAndFrameSizeTable[3][0][0][0] = 56;
+        bitRateAndFrameSizeTable[3][1][0][0] = 56;
+        bitRateAndFrameSizeTable[3][0][0][1] = 112;
+        bitRateAndFrameSizeTable[3][1][0][1] = 112;
+        bitRateAndFrameSizeTable[4][0][0][0] = 64;
+        bitRateAndFrameSizeTable[4][1][0][0] = 64;
+        bitRateAndFrameSizeTable[4][0][0][1] = 128;
+        bitRateAndFrameSizeTable[4][1][0][1] = 128;
+        bitRateAndFrameSizeTable[5][0][0][0] = 80;
+        bitRateAndFrameSizeTable[5][1][0][0] = 80;
+        bitRateAndFrameSizeTable[5][0][0][1] = 160;
+        bitRateAndFrameSizeTable[5][1][0][1] = 160;
+        bitRateAndFrameSizeTable[6][0][0][0] = 96;
+        bitRateAndFrameSizeTable[6][1][0][0] = 96;
+        bitRateAndFrameSizeTable[6][0][0][1] = 192;
+        bitRateAndFrameSizeTable[6][1][0][1] = 192;
+        bitRateAndFrameSizeTable[7][0][0][0] = 112;
+        bitRateAndFrameSizeTable[7][1][0][0] = 112;
+        bitRateAndFrameSizeTable[7][0][0][1] = 224;
+        bitRateAndFrameSizeTable[7][1][0][1] = 224;
+        bitRateAndFrameSizeTable[8][0][0][0] = 128;
+        bitRateAndFrameSizeTable[8][1][0][0] = 128;
+        bitRateAndFrameSizeTable[8][0][0][1] = 256;
+        bitRateAndFrameSizeTable[8][1][0][1] = 256;
+        bitRateAndFrameSizeTable[9][0][0][0] = 160;
+        bitRateAndFrameSizeTable[9][1][0][0] = 160;
+        bitRateAndFrameSizeTable[9][0][0][1] = 320;
+        bitRateAndFrameSizeTable[9][1][0][1] = 320;
+        bitRateAndFrameSizeTable[10][0][0][0] = 192;
+        bitRateAndFrameSizeTable[10][1][0][0] = 192;
+        bitRateAndFrameSizeTable[10][0][0][1] = 384;
+        bitRateAndFrameSizeTable[10][1][0][1] = 384;
+        bitRateAndFrameSizeTable[11][0][0][0] = 224;
+        bitRateAndFrameSizeTable[11][1][0][0] = 224;
+        bitRateAndFrameSizeTable[11][0][0][1] = 448;
+        bitRateAndFrameSizeTable[11][1][0][1] = 448;
+        bitRateAndFrameSizeTable[12][0][0][0] = 256;
+        bitRateAndFrameSizeTable[12][1][0][0] = 256;
+        bitRateAndFrameSizeTable[12][0][0][1] = 512;
+        bitRateAndFrameSizeTable[12][1][0][1] = 512;
+        bitRateAndFrameSizeTable[13][0][0][0] = 320;
+        bitRateAndFrameSizeTable[13][1][0][0] = 320;
+        bitRateAndFrameSizeTable[13][0][0][1] = 640;
+        bitRateAndFrameSizeTable[13][1][0][1] = 640;
+        bitRateAndFrameSizeTable[14][0][0][0] = 384;
+        bitRateAndFrameSizeTable[14][1][0][0] = 384;
+        bitRateAndFrameSizeTable[14][0][0][1] = 768;
+        bitRateAndFrameSizeTable[14][1][0][1] = 768;
+        bitRateAndFrameSizeTable[15][0][0][0] = 448;
+        bitRateAndFrameSizeTable[15][1][0][0] = 448;
+        bitRateAndFrameSizeTable[15][0][0][1] = 896;
+        bitRateAndFrameSizeTable[15][1][0][1] = 896;
+        bitRateAndFrameSizeTable[16][0][0][0] = 512;
+        bitRateAndFrameSizeTable[16][1][0][0] = 512;
+        bitRateAndFrameSizeTable[16][0][0][1] = 1024;
+        bitRateAndFrameSizeTable[16][1][0][1] = 1024;
+        bitRateAndFrameSizeTable[17][0][0][0] = 576;
+        bitRateAndFrameSizeTable[17][1][0][0] = 576;
+        bitRateAndFrameSizeTable[17][0][0][1] = 1152;
+        bitRateAndFrameSizeTable[17][1][0][1] = 1152;
+        bitRateAndFrameSizeTable[18][0][0][0] = 640;
+        bitRateAndFrameSizeTable[18][1][0][0] = 640;
+        bitRateAndFrameSizeTable[18][0][0][1] = 1280;
+        bitRateAndFrameSizeTable[18][1][0][1] = 1280;
+
+        // 44.1 kHz
+        bitRateAndFrameSizeTable[0][0][1][0] = 32;
+        bitRateAndFrameSizeTable[0][1][1][0] = 32;
+        bitRateAndFrameSizeTable[0][0][1][1] = 69;
+        bitRateAndFrameSizeTable[0][1][1][1] = 70;
+        bitRateAndFrameSizeTable[1][0][1][0] = 40;
+        bitRateAndFrameSizeTable[1][1][1][0] = 40;
+        bitRateAndFrameSizeTable[1][0][1][1] = 87;
+        bitRateAndFrameSizeTable[1][1][1][1] = 88;
+        bitRateAndFrameSizeTable[2][0][1][0] = 48;
+        bitRateAndFrameSizeTable[2][1][1][0] = 48;
+        bitRateAndFrameSizeTable[2][0][1][1] = 104;
+        bitRateAndFrameSizeTable[2][1][1][1] = 105;
+        bitRateAndFrameSizeTable[3][0][1][0] = 56;
+        bitRateAndFrameSizeTable[3][1][1][0] = 56;
+        bitRateAndFrameSizeTable[3][0][1][1] = 121;
+        bitRateAndFrameSizeTable[3][1][1][1] = 122;
+        bitRateAndFrameSizeTable[4][0][1][0] = 64;
+        bitRateAndFrameSizeTable[4][1][1][0] = 64;
+        bitRateAndFrameSizeTable[4][0][1][1] = 139;
+        bitRateAndFrameSizeTable[4][1][1][1] = 140;
+        bitRateAndFrameSizeTable[5][0][1][0] = 80;
+        bitRateAndFrameSizeTable[5][1][1][0] = 80;
+        bitRateAndFrameSizeTable[5][0][1][1] = 174;
+        bitRateAndFrameSizeTable[5][1][1][1] = 175;
+        bitRateAndFrameSizeTable[6][0][1][0] = 96;
+        bitRateAndFrameSizeTable[6][1][1][0] = 96;
+        bitRateAndFrameSizeTable[6][0][1][1] = 208;
+        bitRateAndFrameSizeTable[6][1][1][1] = 209;
+        bitRateAndFrameSizeTable[7][0][1][0] = 112;
+        bitRateAndFrameSizeTable[7][1][1][0] = 112;
+        bitRateAndFrameSizeTable[7][0][1][1] = 243;
+        bitRateAndFrameSizeTable[7][1][1][1] = 244;
+        bitRateAndFrameSizeTable[8][0][1][0] = 128;
+        bitRateAndFrameSizeTable[8][1][1][0] = 128;
+        bitRateAndFrameSizeTable[8][0][1][1] = 278;
+        bitRateAndFrameSizeTable[8][1][1][1] = 279;
+        bitRateAndFrameSizeTable[9][0][1][0] = 160;
+        bitRateAndFrameSizeTable[9][1][1][0] = 160;
+        bitRateAndFrameSizeTable[9][0][1][1] = 348;
+        bitRateAndFrameSizeTable[9][1][1][1] = 349;
+        bitRateAndFrameSizeTable[10][0][1][0] = 192;
+        bitRateAndFrameSizeTable[10][1][1][0] = 192;
+        bitRateAndFrameSizeTable[10][0][1][1] = 417;
+        bitRateAndFrameSizeTable[10][1][1][1] = 418;
+        bitRateAndFrameSizeTable[11][0][1][0] = 224;
+        bitRateAndFrameSizeTable[11][1][1][0] = 224;
+        bitRateAndFrameSizeTable[11][0][1][1] = 487;
+        bitRateAndFrameSizeTable[11][1][1][1] = 488;
+        bitRateAndFrameSizeTable[12][0][1][0] = 256;
+        bitRateAndFrameSizeTable[12][1][1][0] = 256;
+        bitRateAndFrameSizeTable[12][0][1][1] = 557;
+        bitRateAndFrameSizeTable[12][1][1][1] = 558;
+        bitRateAndFrameSizeTable[13][0][1][0] = 320;
+        bitRateAndFrameSizeTable[13][1][1][0] = 320;
+        bitRateAndFrameSizeTable[13][0][1][1] = 696;
+        bitRateAndFrameSizeTable[13][1][1][1] = 697;
+        bitRateAndFrameSizeTable[14][0][1][0] = 384;
+        bitRateAndFrameSizeTable[14][1][1][0] = 384;
+        bitRateAndFrameSizeTable[14][0][1][1] = 835;
+        bitRateAndFrameSizeTable[14][1][1][1] = 836;
+        bitRateAndFrameSizeTable[15][0][1][0] = 448;
+        bitRateAndFrameSizeTable[15][1][1][0] = 448;
+        bitRateAndFrameSizeTable[15][0][1][1] = 975;
+        bitRateAndFrameSizeTable[15][1][1][1] = 975;
+        bitRateAndFrameSizeTable[16][0][1][0] = 512;
+        bitRateAndFrameSizeTable[16][1][1][0] = 512;
+        bitRateAndFrameSizeTable[16][0][1][1] = 1114;
+        bitRateAndFrameSizeTable[16][1][1][1] = 1115;
+        bitRateAndFrameSizeTable[17][0][1][0] = 576;
+        bitRateAndFrameSizeTable[17][1][1][0] = 576;
+        bitRateAndFrameSizeTable[17][0][1][1] = 1253;
+        bitRateAndFrameSizeTable[17][1][1][1] = 1254;
+        bitRateAndFrameSizeTable[18][0][1][0] = 640;
+        bitRateAndFrameSizeTable[18][1][1][0] = 640;
+        bitRateAndFrameSizeTable[18][0][1][1] = 1393;
+        bitRateAndFrameSizeTable[18][1][1][1] = 1394;
+
+        // 32kHz
+        bitRateAndFrameSizeTable[0][0][2][0] = 32;
+        bitRateAndFrameSizeTable[0][1][2][0] = 32;
+        bitRateAndFrameSizeTable[0][0][2][1] = 96;
+        bitRateAndFrameSizeTable[0][1][2][1] = 96;
+        bitRateAndFrameSizeTable[1][0][2][0] = 40;
+        bitRateAndFrameSizeTable[1][1][2][0] = 40;
+        bitRateAndFrameSizeTable[1][0][2][1] = 120;
+        bitRateAndFrameSizeTable[1][1][2][1] = 120;
+        bitRateAndFrameSizeTable[2][0][2][0] = 48;
+        bitRateAndFrameSizeTable[2][1][2][0] = 48;
+        bitRateAndFrameSizeTable[2][0][2][1] = 144;
+        bitRateAndFrameSizeTable[2][1][2][1] = 144;
+        bitRateAndFrameSizeTable[3][0][2][0] = 56;
+        bitRateAndFrameSizeTable[3][1][2][0] = 56;
+        bitRateAndFrameSizeTable[3][0][2][1] = 168;
+        bitRateAndFrameSizeTable[3][1][2][1] = 168;
+        bitRateAndFrameSizeTable[4][0][2][0] = 64;
+        bitRateAndFrameSizeTable[4][1][2][0] = 64;
+        bitRateAndFrameSizeTable[4][0][2][1] = 192;
+        bitRateAndFrameSizeTable[4][1][2][1] = 192;
+        bitRateAndFrameSizeTable[5][0][2][0] = 80;
+        bitRateAndFrameSizeTable[5][1][2][0] = 80;
+        bitRateAndFrameSizeTable[5][0][2][1] = 240;
+        bitRateAndFrameSizeTable[5][1][2][1] = 240;
+        bitRateAndFrameSizeTable[6][0][2][0] = 96;
+        bitRateAndFrameSizeTable[6][1][2][0] = 96;
+        bitRateAndFrameSizeTable[6][0][2][1] = 288;
+        bitRateAndFrameSizeTable[6][1][2][1] = 288;
+        bitRateAndFrameSizeTable[7][0][2][0] = 112;
+        bitRateAndFrameSizeTable[7][1][2][0] = 112;
+        bitRateAndFrameSizeTable[7][0][2][1] = 336;
+        bitRateAndFrameSizeTable[7][1][2][1] = 336;
+        bitRateAndFrameSizeTable[8][0][2][0] = 128;
+        bitRateAndFrameSizeTable[8][1][2][0] = 128;
+        bitRateAndFrameSizeTable[8][0][2][1] = 384;
+        bitRateAndFrameSizeTable[8][1][2][1] = 384;
+        bitRateAndFrameSizeTable[9][0][2][0] = 160;
+        bitRateAndFrameSizeTable[9][1][2][0] = 160;
+        bitRateAndFrameSizeTable[9][0][2][1] = 480;
+        bitRateAndFrameSizeTable[9][1][2][1] = 480;
+        bitRateAndFrameSizeTable[10][0][2][0] = 192;
+        bitRateAndFrameSizeTable[10][1][2][0] = 192;
+        bitRateAndFrameSizeTable[10][0][2][1] = 576;
+        bitRateAndFrameSizeTable[10][1][2][1] = 576;
+        bitRateAndFrameSizeTable[11][0][2][0] = 224;
+        bitRateAndFrameSizeTable[11][1][2][0] = 224;
+        bitRateAndFrameSizeTable[11][0][2][1] = 672;
+        bitRateAndFrameSizeTable[11][1][2][1] = 672;
+        bitRateAndFrameSizeTable[12][0][2][0] = 256;
+        bitRateAndFrameSizeTable[12][1][2][0] = 256;
+        bitRateAndFrameSizeTable[12][0][2][1] = 768;
+        bitRateAndFrameSizeTable[12][1][2][1] = 768;
+        bitRateAndFrameSizeTable[13][0][2][0] = 320;
+        bitRateAndFrameSizeTable[13][1][2][0] = 320;
+        bitRateAndFrameSizeTable[13][0][2][1] = 960;
+        bitRateAndFrameSizeTable[13][1][2][1] = 960;
+        bitRateAndFrameSizeTable[14][0][2][0] = 384;
+        bitRateAndFrameSizeTable[14][1][2][0] = 384;
+        bitRateAndFrameSizeTable[14][0][2][1] = 1152;
+        bitRateAndFrameSizeTable[14][1][2][1] = 1152;
+        bitRateAndFrameSizeTable[15][0][2][0] = 448;
+        bitRateAndFrameSizeTable[15][1][2][0] = 448;
+        bitRateAndFrameSizeTable[15][0][2][1] = 1344;
+        bitRateAndFrameSizeTable[15][1][2][1] = 1344;
+        bitRateAndFrameSizeTable[16][0][2][0] = 512;
+        bitRateAndFrameSizeTable[16][1][2][0] = 512;
+        bitRateAndFrameSizeTable[16][0][2][1] = 1536;
+        bitRateAndFrameSizeTable[16][1][2][1] = 1536;
+        bitRateAndFrameSizeTable[17][0][2][0] = 576;
+        bitRateAndFrameSizeTable[17][1][2][0] = 576;
+        bitRateAndFrameSizeTable[17][0][2][1] = 1728;
+        bitRateAndFrameSizeTable[17][1][2][1] = 1728;
+        bitRateAndFrameSizeTable[18][0][2][0] = 640;
+        bitRateAndFrameSizeTable[18][1][2][0] = 640;
+        bitRateAndFrameSizeTable[18][0][2][1] = 1920;
+        bitRateAndFrameSizeTable[18][1][2][1] = 1920;
+    }
+}
\ No newline at end of file
diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/authoring/tracks/.svn/text-base/Amf0Track.java.svn-base b/isoparser/src/main/java/com/googlecode/mp4parser/authoring/tracks/.svn/text-base/Amf0Track.java.svn-base
new file mode 100644
index 0000000..0917767
--- /dev/null
+++ b/isoparser/src/main/java/com/googlecode/mp4parser/authoring/tracks/.svn/text-base/Amf0Track.java.svn-base
@@ -0,0 +1,116 @@
+/*
+ * Copyright 2012 Sebastian Annies, Hamburg
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.googlecode.mp4parser.authoring.tracks;
+
+import com.coremedia.iso.boxes.*;
+import com.googlecode.mp4parser.authoring.AbstractTrack;
+import com.googlecode.mp4parser.authoring.TrackMetaData;
+import com.googlecode.mp4parser.boxes.adobe.ActionMessageFormat0SampleEntryBox;
+
+import java.nio.ByteBuffer;
+import java.util.Collections;
+import java.util.Date;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.SortedMap;
+import java.util.TreeMap;
+
+public class Amf0Track extends AbstractTrack {
+    SortedMap<Long, byte[]> rawSamples = new TreeMap<Long, byte[]>() {
+    };
+    private TrackMetaData trackMetaData = new TrackMetaData();
+
+
+    /**
+     * Creates a new AMF0 track from
+     *
+     * @param rawSamples
+     */
+    public Amf0Track(Map<Long, byte[]> rawSamples) {
+        this.rawSamples = new TreeMap<Long, byte[]>(rawSamples);
+        trackMetaData.setCreationTime(new Date());
+        trackMetaData.setModificationTime(new Date());
+        trackMetaData.setTimescale(1000); // Text tracks use millieseconds
+        trackMetaData.setLanguage("eng");
+    }
+
+    public List<ByteBuffer> getSamples() {
+        LinkedList<ByteBuffer> samples = new LinkedList<ByteBuffer>();
+        for (byte[] bytes : rawSamples.values()) {
+            samples.add(ByteBuffer.wrap(bytes));
+        }
+        return samples;
+    }
+
+    public SampleDescriptionBox getSampleDescriptionBox() {
+        SampleDescriptionBox stsd = new SampleDescriptionBox();
+        ActionMessageFormat0SampleEntryBox amf0 = new ActionMessageFormat0SampleEntryBox();
+        amf0.setDataReferenceIndex(1);
+        stsd.addBox(amf0);
+        return stsd;
+    }
+
+    public List<TimeToSampleBox.Entry> getDecodingTimeEntries() {
+        LinkedList<TimeToSampleBox.Entry> timesToSample = new LinkedList<TimeToSampleBox.Entry>();
+        LinkedList<Long> keys = new LinkedList<Long>(rawSamples.keySet());
+        Collections.sort(keys);
+        long lastTimeStamp = 0;
+        for (Long key : keys) {
+            long delta = key - lastTimeStamp;
+            if (timesToSample.size() > 0 && timesToSample.peek().getDelta() == delta) {
+                timesToSample.peek().setCount(timesToSample.peek().getCount() + 1);
+            } else {
+                timesToSample.add(new TimeToSampleBox.Entry(1, delta));
+            }
+            lastTimeStamp = key;
+        }
+        return timesToSample;
+    }
+
+    public List<CompositionTimeToSample.Entry> getCompositionTimeEntries() {
+        // AMF0 tracks do not have Composition Time
+        return null;
+    }
+
+    public long[] getSyncSamples() {
+        // AMF0 tracks do not have Sync Samples
+        return null;
+    }
+
+    public List<SampleDependencyTypeBox.Entry> getSampleDependencies() {
+        // AMF0 tracks do not have Sample Dependencies
+        return null;
+    }
+
+    public TrackMetaData getTrackMetaData() {
+        return trackMetaData;  //To change body of implemented methods use File | Settings | File Templates.
+    }
+
+    public String getHandler() {
+        return "data";
+    }
+
+    public Box getMediaHeaderBox() {
+        return new NullMediaHeaderBox();
+    }
+
+    public SubSampleInformationBox getSubsampleInformationBox() {
+        return null;
+    }
+
+}
diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/authoring/tracks/.svn/text-base/AppendTrack.java.svn-base b/isoparser/src/main/java/com/googlecode/mp4parser/authoring/tracks/.svn/text-base/AppendTrack.java.svn-base
new file mode 100644
index 0000000..93ee0cd
--- /dev/null
+++ b/isoparser/src/main/java/com/googlecode/mp4parser/authoring/tracks/.svn/text-base/AppendTrack.java.svn-base
@@ -0,0 +1,348 @@
+/*
+ * Copyright 2012 Sebastian Annies, Hamburg
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.googlecode.mp4parser.authoring.tracks;
+
+import com.coremedia.iso.boxes.*;
+import com.coremedia.iso.boxes.sampleentry.AudioSampleEntry;
+import com.googlecode.mp4parser.authoring.AbstractTrack;
+import com.googlecode.mp4parser.authoring.Track;
+import com.googlecode.mp4parser.authoring.TrackMetaData;
+import com.googlecode.mp4parser.boxes.mp4.ESDescriptorBox;
+import com.googlecode.mp4parser.boxes.mp4.objectdescriptors.DecoderConfigDescriptor;
+import com.googlecode.mp4parser.boxes.mp4.objectdescriptors.ESDescriptor;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.nio.channels.Channels;
+import java.util.*;
+
+/**
+ * Appends two or more <code>Tracks</code> of the same type. No only that the type must be equal
+ * also the decoder settings must be the same.
+ */
+public class AppendTrack extends AbstractTrack {
+    Track[] tracks;
+    SampleDescriptionBox stsd;
+
+    public AppendTrack(Track... tracks) throws IOException {
+        this.tracks = tracks;
+
+        for (Track track : tracks) {
+
+            if (stsd == null) {
+                stsd = track.getSampleDescriptionBox();
+            } else {
+                ByteArrayOutputStream curBaos = new ByteArrayOutputStream();
+                ByteArrayOutputStream refBaos = new ByteArrayOutputStream();
+                track.getSampleDescriptionBox().getBox(Channels.newChannel(curBaos));
+                stsd.getBox(Channels.newChannel(refBaos));
+                byte[] cur = curBaos.toByteArray();
+                byte[] ref = refBaos.toByteArray();
+
+                if (!Arrays.equals(ref, cur)) {
+                    SampleDescriptionBox curStsd = track.getSampleDescriptionBox();
+                    if (stsd.getBoxes().size() == 1 && curStsd.getBoxes().size() == 1) {
+                        if (stsd.getBoxes().get(0) instanceof AudioSampleEntry && curStsd.getBoxes().get(0) instanceof AudioSampleEntry) {
+                            AudioSampleEntry aseResult = mergeAudioSampleEntries((AudioSampleEntry) stsd.getBoxes().get(0), (AudioSampleEntry) curStsd.getBoxes().get(0));
+                            if (aseResult != null) {
+                                stsd.setBoxes(Collections.<Box>singletonList(aseResult));
+                                return;
+                            }
+                        }
+                    }
+                    throw new IOException("Cannot append " + track + " to " + tracks[0] + " since their Sample Description Boxes differ: \n" + track.getSampleDescriptionBox() + "\n vs. \n" + tracks[0].getSampleDescriptionBox());
+                }
+            }
+        }
+    }
+
+    private AudioSampleEntry mergeAudioSampleEntries(AudioSampleEntry ase1, AudioSampleEntry ase2) throws IOException {
+        if (ase1.getType().equals(ase2.getType())) {
+            AudioSampleEntry ase = new AudioSampleEntry(ase2.getType());
+            if (ase1.getBytesPerFrame() == ase2.getBytesPerFrame()) {
+                ase.setBytesPerFrame(ase1.getBytesPerFrame());
+            } else {
+                return null;
+            }
+            if (ase1.getBytesPerPacket() == ase2.getBytesPerPacket()) {
+                ase.setBytesPerPacket(ase1.getBytesPerPacket());
+            } else {
+                return null;
+            }
+            if (ase1.getBytesPerSample() == ase2.getBytesPerSample()) {
+                ase.setBytesPerSample(ase1.getBytesPerSample());
+            } else {
+                return null;
+            }
+            if (ase1.getChannelCount() == ase2.getChannelCount()) {
+                ase.setChannelCount(ase1.getChannelCount());
+            } else {
+                return null;
+            }
+            if (ase1.getPacketSize() == ase2.getPacketSize()) {
+                ase.setPacketSize(ase1.getPacketSize());
+            } else {
+                return null;
+            }
+            if (ase1.getCompressionId() == ase2.getCompressionId()) {
+                ase.setCompressionId(ase1.getCompressionId());
+            } else {
+                return null;
+            }
+            if (ase1.getSampleRate() == ase2.getSampleRate()) {
+                ase.setSampleRate(ase1.getSampleRate());
+            } else {
+                return null;
+            }
+            if (ase1.getSampleSize() == ase2.getSampleSize()) {
+                ase.setSampleSize(ase1.getSampleSize());
+            } else {
+                return null;
+            }
+            if (ase1.getSamplesPerPacket() == ase2.getSamplesPerPacket()) {
+                ase.setSamplesPerPacket(ase1.getSamplesPerPacket());
+            } else {
+                return null;
+            }
+            if (ase1.getSoundVersion() == ase2.getSoundVersion()) {
+                ase.setSoundVersion(ase1.getSoundVersion());
+            } else {
+                return null;
+            }
+            if (Arrays.equals(ase1.getSoundVersion2Data(), ase2.getSoundVersion2Data())) {
+                ase.setSoundVersion2Data(ase1.getSoundVersion2Data());
+            } else {
+                return null;
+            }
+            if (ase1.getBoxes().size() == ase2.getBoxes().size()) {
+                Iterator<Box> bxs1 = ase1.getBoxes().iterator();
+                Iterator<Box> bxs2 = ase2.getBoxes().iterator();
+                while (bxs1.hasNext()) {
+                    Box cur1 = bxs1.next();
+                    Box cur2 = bxs2.next();
+                    ByteArrayOutputStream baos1 = new ByteArrayOutputStream();
+                    ByteArrayOutputStream baos2 = new ByteArrayOutputStream();
+                    cur1.getBox(Channels.newChannel(baos1));
+                    cur2.getBox(Channels.newChannel(baos2));
+                    if (Arrays.equals(baos1.toByteArray(), baos2.toByteArray())) {
+                        ase.addBox(cur1);
+                    } else {
+                        if (ESDescriptorBox.TYPE.equals(cur1.getType()) && ESDescriptorBox.TYPE.equals(cur2.getType())) {
+                            ESDescriptorBox esdsBox1 = (ESDescriptorBox) cur1;
+                            ESDescriptorBox esdsBox2 = (ESDescriptorBox) cur2;
+                            ESDescriptor esds1 = esdsBox1.getEsDescriptor();
+                            ESDescriptor esds2 = esdsBox2.getEsDescriptor();
+                            if (esds1.getURLFlag() != esds2.getURLFlag()) {
+                                return null;
+                            }
+                            if (esds1.getURLLength() != esds2.getURLLength()) {
+                                return null;
+                            }
+                            if (esds1.getDependsOnEsId() != esds2.getDependsOnEsId()) {
+                                return null;
+                            }
+                            if (esds1.getEsId() != esds2.getEsId()) {
+                                return null;
+                            }
+                            if (esds1.getoCREsId() != esds2.getoCREsId()) {
+                                return null;
+                            }
+                            if (esds1.getoCRstreamFlag() != esds2.getoCRstreamFlag()) {
+                                return null;
+                            }
+                            if (esds1.getRemoteODFlag() != esds2.getRemoteODFlag()) {
+                                return null;
+                            }
+                            if (esds1.getStreamDependenceFlag() != esds2.getStreamDependenceFlag()) {
+                                return null;
+                            }
+                            if (esds1.getStreamPriority() != esds2.getStreamPriority()) {
+                                return null;
+                            }
+                            if (esds1.getURLString() != null ? !esds1.getURLString().equals(esds2.getURLString()) : esds2.getURLString() != null) {
+                                return null;
+                            }
+                            if (esds1.getDecoderConfigDescriptor() != null ? !esds1.getDecoderConfigDescriptor().equals(esds2.getDecoderConfigDescriptor()) : esds2.getDecoderConfigDescriptor() != null) {
+                                DecoderConfigDescriptor dcd1 = esds1.getDecoderConfigDescriptor();
+                                DecoderConfigDescriptor dcd2 = esds2.getDecoderConfigDescriptor();
+                                if (!dcd1.getAudioSpecificInfo().equals(dcd2.getAudioSpecificInfo())) {
+                                    return null;
+                                }
+                                if (dcd1.getAvgBitRate() != dcd2.getAvgBitRate()) {
+                                    // I don't care
+                                }
+                                if (dcd1.getBufferSizeDB() != dcd2.getBufferSizeDB()) {
+                                    // I don't care
+                                }
+
+                                if (dcd1.getDecoderSpecificInfo() != null ? !dcd1.getDecoderSpecificInfo().equals(dcd2.getDecoderSpecificInfo()) : dcd2.getDecoderSpecificInfo() != null) {
+                                    return null;
+                                }
+
+                                if (dcd1.getMaxBitRate() != dcd2.getMaxBitRate()) {
+                                    // I don't care
+                                }
+                                if (!dcd1.getProfileLevelIndicationDescriptors().equals(dcd2.getProfileLevelIndicationDescriptors())) {
+                                    return null;
+                                }
+
+                                if (dcd1.getObjectTypeIndication() != dcd2.getObjectTypeIndication()) {
+                                    return null;
+                                }
+                                if (dcd1.getStreamType() != dcd2.getStreamType()) {
+                                    return null;
+                                }
+                                if (dcd1.getUpStream() != dcd2.getUpStream()) {
+                                    return null;
+                                }
+
+
+                            }
+                            if (esds1.getOtherDescriptors() != null ? !esds1.getOtherDescriptors().equals(esds2.getOtherDescriptors()) : esds2.getOtherDescriptors() != null) {
+                                return null;
+                            }
+                            if (esds1.getSlConfigDescriptor() != null ? !esds1.getSlConfigDescriptor().equals(esds2.getSlConfigDescriptor()) : esds2.getSlConfigDescriptor() != null) {
+                                return null;
+                            }
+                            ase.addBox(cur1);
+                        }
+                    }
+                }
+            }
+            return ase;
+        } else {
+            return null;
+        }
+
+
+    }
+
+
+    public List<ByteBuffer> getSamples() {
+        ArrayList<ByteBuffer> lists = new ArrayList<ByteBuffer>();
+
+        for (Track track : tracks) {
+            lists.addAll(track.getSamples());
+        }
+
+        return lists;
+    }
+
+    public SampleDescriptionBox getSampleDescriptionBox() {
+        return stsd;
+    }
+
+    public List<TimeToSampleBox.Entry> getDecodingTimeEntries() {
+        if (tracks[0].getDecodingTimeEntries() != null && !tracks[0].getDecodingTimeEntries().isEmpty()) {
+            List<long[]> lists = new LinkedList<long[]>();
+            for (Track track : tracks) {
+                lists.add(TimeToSampleBox.blowupTimeToSamples(track.getDecodingTimeEntries()));
+            }
+
+            LinkedList<TimeToSampleBox.Entry> returnDecodingEntries = new LinkedList<TimeToSampleBox.Entry>();
+            for (long[] list : lists) {
+                for (long nuDecodingTime : list) {
+                    if (returnDecodingEntries.isEmpty() || returnDecodingEntries.getLast().getDelta() != nuDecodingTime) {
+                        TimeToSampleBox.Entry e = new TimeToSampleBox.Entry(1, nuDecodingTime);
+                        returnDecodingEntries.add(e);
+                    } else {
+                        TimeToSampleBox.Entry e = returnDecodingEntries.getLast();
+                        e.setCount(e.getCount() + 1);
+                    }
+                }
+            }
+            return returnDecodingEntries;
+        } else {
+            return null;
+        }
+    }
+
+    public List<CompositionTimeToSample.Entry> getCompositionTimeEntries() {
+        if (tracks[0].getCompositionTimeEntries() != null && !tracks[0].getCompositionTimeEntries().isEmpty()) {
+            List<int[]> lists = new LinkedList<int[]>();
+            for (Track track : tracks) {
+                lists.add(CompositionTimeToSample.blowupCompositionTimes(track.getCompositionTimeEntries()));
+            }
+            LinkedList<CompositionTimeToSample.Entry> compositionTimeEntries = new LinkedList<CompositionTimeToSample.Entry>();
+            for (int[] list : lists) {
+                for (int compositionTime : list) {
+                    if (compositionTimeEntries.isEmpty() || compositionTimeEntries.getLast().getOffset() != compositionTime) {
+                        CompositionTimeToSample.Entry e = new CompositionTimeToSample.Entry(1, compositionTime);
+                        compositionTimeEntries.add(e);
+                    } else {
+                        CompositionTimeToSample.Entry e = compositionTimeEntries.getLast();
+                        e.setCount(e.getCount() + 1);
+                    }
+                }
+            }
+            return compositionTimeEntries;
+        } else {
+            return null;
+        }
+    }
+
+    public long[] getSyncSamples() {
+        if (tracks[0].getSyncSamples() != null && tracks[0].getSyncSamples().length > 0) {
+            int numSyncSamples = 0;
+            for (Track track : tracks) {
+                numSyncSamples += track.getSyncSamples().length;
+            }
+            long[] returnSyncSamples = new long[numSyncSamples];
+
+            int pos = 0;
+            long samplesBefore = 0;
+            for (Track track : tracks) {
+                for (long l : track.getSyncSamples()) {
+                    returnSyncSamples[pos++] = samplesBefore + l;
+                }
+                samplesBefore += track.getSamples().size();
+            }
+            return returnSyncSamples;
+        } else {
+            return null;
+        }
+    }
+
+    public List<SampleDependencyTypeBox.Entry> getSampleDependencies() {
+        if (tracks[0].getSampleDependencies() != null && !tracks[0].getSampleDependencies().isEmpty()) {
+            List<SampleDependencyTypeBox.Entry> list = new LinkedList<SampleDependencyTypeBox.Entry>();
+            for (Track track : tracks) {
+                list.addAll(track.getSampleDependencies());
+            }
+            return list;
+        } else {
+            return null;
+        }
+    }
+
+    public TrackMetaData getTrackMetaData() {
+        return tracks[0].getTrackMetaData();
+    }
+
+    public String getHandler() {
+        return tracks[0].getHandler();
+    }
+
+    public Box getMediaHeaderBox() {
+        return tracks[0].getMediaHeaderBox();
+    }
+
+    public SubSampleInformationBox getSubsampleInformationBox() {
+        return tracks[0].getSubsampleInformationBox();
+    }
+
+}
diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/authoring/tracks/.svn/text-base/ChangeTimeScaleTrack.java.svn-base b/isoparser/src/main/java/com/googlecode/mp4parser/authoring/tracks/.svn/text-base/ChangeTimeScaleTrack.java.svn-base
new file mode 100644
index 0000000..50f76c2
--- /dev/null
+++ b/isoparser/src/main/java/com/googlecode/mp4parser/authoring/tracks/.svn/text-base/ChangeTimeScaleTrack.java.svn-base
@@ -0,0 +1,203 @@
+/*
+ * Copyright 2012 Sebastian Annies, Hamburg
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.googlecode.mp4parser.authoring.tracks;
+
+import com.coremedia.iso.boxes.*;
+import com.googlecode.mp4parser.authoring.Track;
+import com.googlecode.mp4parser.authoring.TrackMetaData;
+
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Queue;
+import java.util.logging.Logger;
+
+/**
+ * Changes the timescale of a track by wrapping the track.
+ */
+public class ChangeTimeScaleTrack implements Track {
+    private static final Logger LOG = Logger.getLogger(ChangeTimeScaleTrack.class.getName());
+
+    Track source;
+    List<CompositionTimeToSample.Entry> ctts;
+    List<TimeToSampleBox.Entry> tts;
+    long timeScale;
+
+    /**
+     * Changes the time scale of the source track to the target time scale and makes sure
+     * that any rounding errors that may have summed are corrected exactly before the syncSamples.
+     *
+     * @param source          the source track
+     * @param targetTimeScale the resulting time scale of this track.
+     * @param syncSamples     at these sync points where rounding error are corrected.
+     */
+    public ChangeTimeScaleTrack(Track source, long targetTimeScale, long[] syncSamples) {
+        this.source = source;
+        this.timeScale = targetTimeScale;
+        double timeScaleFactor = (double) targetTimeScale / source.getTrackMetaData().getTimescale();
+        ctts = adjustCtts(source.getCompositionTimeEntries(), timeScaleFactor);
+        tts = adjustTts(source.getDecodingTimeEntries(), timeScaleFactor, syncSamples, getTimes(source, syncSamples, targetTimeScale));
+    }
+
+    private static long[] getTimes(Track track, long[] syncSamples, long targetTimeScale) {
+        long[] syncSampleTimes = new long[syncSamples.length];
+        Queue<TimeToSampleBox.Entry> timeQueue = new LinkedList<TimeToSampleBox.Entry>(track.getDecodingTimeEntries());
+
+        int currentSample = 1;  // first syncsample is 1
+        long currentDuration = 0;
+        long currentDelta = 0;
+        int currentSyncSampleIndex = 0;
+        long left = 0;
+
+
+        while (currentSample <= syncSamples[syncSamples.length - 1]) {
+            if (currentSample++ == syncSamples[currentSyncSampleIndex]) {
+                syncSampleTimes[currentSyncSampleIndex++] = (currentDuration * targetTimeScale) / track.getTrackMetaData().getTimescale();
+            }
+            if (left-- == 0) {
+                TimeToSampleBox.Entry entry = timeQueue.poll();
+                left = entry.getCount() - 1;
+                currentDelta = entry.getDelta();
+            }
+            currentDuration += currentDelta;
+        }
+        return syncSampleTimes;
+
+    }
+
+    public SampleDescriptionBox getSampleDescriptionBox() {
+        return source.getSampleDescriptionBox();
+    }
+
+    public List<TimeToSampleBox.Entry> getDecodingTimeEntries() {
+        return tts;
+    }
+
+    public List<CompositionTimeToSample.Entry> getCompositionTimeEntries() {
+        return ctts;
+    }
+
+    public long[] getSyncSamples() {
+        return source.getSyncSamples();
+    }
+
+    public List<SampleDependencyTypeBox.Entry> getSampleDependencies() {
+        return source.getSampleDependencies();
+    }
+
+    public TrackMetaData getTrackMetaData() {
+        TrackMetaData trackMetaData = (TrackMetaData) source.getTrackMetaData().clone();
+        trackMetaData.setTimescale(timeScale);
+        return trackMetaData;
+    }
+
+    public String getHandler() {
+        return source.getHandler();
+    }
+
+    public boolean isEnabled() {
+        return source.isEnabled();
+    }
+
+    public boolean isInMovie() {
+        return source.isInMovie();
+    }
+
+    public boolean isInPreview() {
+        return source.isInPreview();
+    }
+
+    public boolean isInPoster() {
+        return source.isInPoster();
+    }
+
+    public List<ByteBuffer> getSamples() {
+        return source.getSamples();
+    }
+
+
+    /**
+     * Adjusting the composition times is easy. Just scale it by the factor - that's it. There is no rounding
+     * error summing up.
+     *
+     * @param source
+     * @param timeScaleFactor
+     * @return
+     */
+    static List<CompositionTimeToSample.Entry> adjustCtts(List<CompositionTimeToSample.Entry> source, double timeScaleFactor) {
+        if (source != null) {
+            List<CompositionTimeToSample.Entry> entries2 = new ArrayList<CompositionTimeToSample.Entry>(source.size());
+            for (CompositionTimeToSample.Entry entry : source) {
+                entries2.add(new CompositionTimeToSample.Entry(entry.getCount(), (int) Math.round(timeScaleFactor * entry.getOffset())));
+            }
+            return entries2;
+        } else {
+            return null;
+        }
+    }
+
+    static List<TimeToSampleBox.Entry> adjustTts(List<TimeToSampleBox.Entry> source, double timeScaleFactor, long[] syncSample, long[] syncSampleTimes) {
+
+        long[] sourceArray = TimeToSampleBox.blowupTimeToSamples(source);
+        long summedDurations = 0;
+
+        LinkedList<TimeToSampleBox.Entry> entries2 = new LinkedList<TimeToSampleBox.Entry>();
+        for (int i = 1; i <= sourceArray.length; i++) {
+            long duration = sourceArray[i - 1];
+
+            long x = Math.round(timeScaleFactor * duration);
+
+
+            TimeToSampleBox.Entry last = entries2.peekLast();
+            int ssIndex;
+            if ((ssIndex = Arrays.binarySearch(syncSample, i + 1)) >= 0) {
+                // we are at the sample before sync point
+                if (syncSampleTimes[ssIndex] != summedDurations) {
+                    long correction = syncSampleTimes[ssIndex] - (summedDurations + x);
+                    LOG.finest(String.format("Sample %d %d / %d - correct by %d", i, summedDurations, syncSampleTimes[ssIndex], correction));
+                    x += correction;
+                }
+            }
+            summedDurations += x;
+            if (last == null) {
+                entries2.add(new TimeToSampleBox.Entry(1, x));
+            } else if (last.getDelta() != x) {
+                entries2.add(new TimeToSampleBox.Entry(1, x));
+            } else {
+                last.setCount(last.getCount() + 1);
+            }
+
+        }
+        return entries2;
+    }
+
+    public Box getMediaHeaderBox() {
+        return source.getMediaHeaderBox();
+    }
+
+    public SubSampleInformationBox getSubsampleInformationBox() {
+        return source.getSubsampleInformationBox();
+    }
+
+    @Override
+    public String toString() {
+        return "ChangeTimeScaleTrack{" +
+                "source=" + source +
+                '}';
+    }
+}
\ No newline at end of file
diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/authoring/tracks/.svn/text-base/CroppedTrack.java.svn-base b/isoparser/src/main/java/com/googlecode/mp4parser/authoring/tracks/.svn/text-base/CroppedTrack.java.svn-base
new file mode 100644
index 0000000..2389961
--- /dev/null
+++ b/isoparser/src/main/java/com/googlecode/mp4parser/authoring/tracks/.svn/text-base/CroppedTrack.java.svn-base
@@ -0,0 +1,151 @@
+/*
+ * Copyright 2012 Sebastian Annies, Hamburg
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.googlecode.mp4parser.authoring.tracks;
+
+import com.coremedia.iso.boxes.*;
+import com.googlecode.mp4parser.authoring.AbstractTrack;
+import com.googlecode.mp4parser.authoring.Track;
+import com.googlecode.mp4parser.authoring.TrackMetaData;
+
+import java.nio.ByteBuffer;
+import java.util.LinkedList;
+import java.util.List;
+
+/**
+ * Generates a Track that starts at fromSample and ends at toSample (exclusive). The user of this class
+ * has to make sure that the fromSample is a random access sample.
+ * <ul>
+ * <li>In AAC this is every single sample</li>
+ * <li>In H264 this is every sample that is marked in the SyncSampleBox</li>
+ * </ul>
+ */
+public class CroppedTrack extends AbstractTrack {
+    Track origTrack;
+    private int fromSample;
+    private int toSample;
+    private long[] syncSampleArray;
+
+    public CroppedTrack(Track origTrack, long fromSample, long toSample) {
+        this.origTrack = origTrack;
+        assert fromSample <= Integer.MAX_VALUE;
+        assert toSample <= Integer.MAX_VALUE;
+        this.fromSample = (int) fromSample;
+        this.toSample = (int) toSample;
+    }
+
+    public List<ByteBuffer> getSamples() {
+        return origTrack.getSamples().subList(fromSample, toSample);
+    }
+
+    public SampleDescriptionBox getSampleDescriptionBox() {
+        return origTrack.getSampleDescriptionBox();
+    }
+
+    public List<TimeToSampleBox.Entry> getDecodingTimeEntries() {
+        if (origTrack.getDecodingTimeEntries() != null && !origTrack.getDecodingTimeEntries().isEmpty()) {
+            // todo optimize! too much long is allocated but then not used
+            long[] decodingTimes = TimeToSampleBox.blowupTimeToSamples(origTrack.getDecodingTimeEntries());
+            long[] nuDecodingTimes = new long[toSample - fromSample];
+            System.arraycopy(decodingTimes, fromSample, nuDecodingTimes, 0, toSample - fromSample);
+
+            LinkedList<TimeToSampleBox.Entry> returnDecodingEntries = new LinkedList<TimeToSampleBox.Entry>();
+
+            for (long nuDecodingTime : nuDecodingTimes) {
+                if (returnDecodingEntries.isEmpty() || returnDecodingEntries.getLast().getDelta() != nuDecodingTime) {
+                    TimeToSampleBox.Entry e = new TimeToSampleBox.Entry(1, nuDecodingTime);
+                    returnDecodingEntries.add(e);
+                } else {
+                    TimeToSampleBox.Entry e = returnDecodingEntries.getLast();
+                    e.setCount(e.getCount() + 1);
+                }
+            }
+            return returnDecodingEntries;
+        } else {
+            return null;
+        }
+    }
+
+    public List<CompositionTimeToSample.Entry> getCompositionTimeEntries() {
+        if (origTrack.getCompositionTimeEntries() != null && !origTrack.getCompositionTimeEntries().isEmpty()) {
+            int[] compositionTime = CompositionTimeToSample.blowupCompositionTimes(origTrack.getCompositionTimeEntries());
+            int[] nuCompositionTimes = new int[toSample - fromSample];
+            System.arraycopy(compositionTime, fromSample, nuCompositionTimes, 0, toSample - fromSample);
+
+            LinkedList<CompositionTimeToSample.Entry> returnDecodingEntries = new LinkedList<CompositionTimeToSample.Entry>();
+
+            for (int nuDecodingTime : nuCompositionTimes) {
+                if (returnDecodingEntries.isEmpty() || returnDecodingEntries.getLast().getOffset() != nuDecodingTime) {
+                    CompositionTimeToSample.Entry e = new CompositionTimeToSample.Entry(1, nuDecodingTime);
+                    returnDecodingEntries.add(e);
+                } else {
+                    CompositionTimeToSample.Entry e = returnDecodingEntries.getLast();
+                    e.setCount(e.getCount() + 1);
+                }
+            }
+            return returnDecodingEntries;
+        } else {
+            return null;
+        }
+    }
+
+    synchronized public long[] getSyncSamples() {
+        if (this.syncSampleArray == null) {
+            if (origTrack.getSyncSamples() != null && origTrack.getSyncSamples().length > 0) {
+                List<Long> syncSamples = new LinkedList<Long>();
+                for (long l : origTrack.getSyncSamples()) {
+                    if (l >= fromSample && l < toSample) {
+                        syncSamples.add(l - fromSample);
+                    }
+                }
+                syncSampleArray = new long[syncSamples.size()];
+                for (int i = 0; i < syncSampleArray.length; i++) {
+                    syncSampleArray[i] = syncSamples.get(i);
+
+                }
+                return syncSampleArray;
+            } else {
+                return null;
+            }
+        } else {
+            return this.syncSampleArray;
+        }
+    }
+
+    public List<SampleDependencyTypeBox.Entry> getSampleDependencies() {
+        if (origTrack.getSampleDependencies() != null && !origTrack.getSampleDependencies().isEmpty()) {
+            return origTrack.getSampleDependencies().subList(fromSample, toSample);
+        } else {
+            return null;
+        }
+    }
+
+    public TrackMetaData getTrackMetaData() {
+        return origTrack.getTrackMetaData();
+    }
+
+    public String getHandler() {
+        return origTrack.getHandler();
+    }
+
+    public Box getMediaHeaderBox() {
+        return origTrack.getMediaHeaderBox();
+    }
+
+    public SubSampleInformationBox getSubsampleInformationBox() {
+        return origTrack.getSubsampleInformationBox();
+    }
+
+}
\ No newline at end of file
diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/authoring/tracks/.svn/text-base/DivideTimeScaleTrack.java.svn-base b/isoparser/src/main/java/com/googlecode/mp4parser/authoring/tracks/.svn/text-base/DivideTimeScaleTrack.java.svn-base
new file mode 100644
index 0000000..c51e8e0
--- /dev/null
+++ b/isoparser/src/main/java/com/googlecode/mp4parser/authoring/tracks/.svn/text-base/DivideTimeScaleTrack.java.svn-base
@@ -0,0 +1,126 @@
+/*
+ * Copyright 2012 Sebastian Annies, Hamburg
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.googlecode.mp4parser.authoring.tracks;
+
+import com.coremedia.iso.boxes.*;
+import com.googlecode.mp4parser.authoring.Track;
+import com.googlecode.mp4parser.authoring.TrackMetaData;
+
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
+import java.util.LinkedList;
+import java.util.List;
+
+/**
+ * Changes the timescale of a track by wrapping the track.
+ */
+public class DivideTimeScaleTrack implements Track {
+    Track source;
+    private int timeScaleDivisor;
+
+    public DivideTimeScaleTrack(Track source, int timeScaleDivisor) {
+        this.source = source;
+        this.timeScaleDivisor = timeScaleDivisor;
+    }
+
+    public SampleDescriptionBox getSampleDescriptionBox() {
+        return source.getSampleDescriptionBox();
+    }
+
+    public List<TimeToSampleBox.Entry> getDecodingTimeEntries() {
+        return adjustTts();
+    }
+
+    public List<CompositionTimeToSample.Entry> getCompositionTimeEntries() {
+        return adjustCtts();
+    }
+
+    public long[] getSyncSamples() {
+        return source.getSyncSamples();
+    }
+
+    public List<SampleDependencyTypeBox.Entry> getSampleDependencies() {
+        return source.getSampleDependencies();
+    }
+
+    public TrackMetaData getTrackMetaData() {
+        TrackMetaData trackMetaData = (TrackMetaData) source.getTrackMetaData().clone();
+        trackMetaData.setTimescale(source.getTrackMetaData().getTimescale() / this.timeScaleDivisor);
+        return trackMetaData;
+    }
+
+    public String getHandler() {
+        return source.getHandler();
+    }
+
+    public boolean isEnabled() {
+        return source.isEnabled();
+    }
+
+    public boolean isInMovie() {
+        return source.isInMovie();
+    }
+
+    public boolean isInPreview() {
+        return source.isInPreview();
+    }
+
+    public boolean isInPoster() {
+        return source.isInPoster();
+    }
+
+    public List<ByteBuffer> getSamples() {
+        return source.getSamples();
+    }
+
+
+    List<CompositionTimeToSample.Entry> adjustCtts() {
+        List<CompositionTimeToSample.Entry> origCtts = this.source.getCompositionTimeEntries();
+        if (origCtts != null) {
+            List<CompositionTimeToSample.Entry> entries2 = new ArrayList<CompositionTimeToSample.Entry>(origCtts.size());
+            for (CompositionTimeToSample.Entry entry : origCtts) {
+                entries2.add(new CompositionTimeToSample.Entry(entry.getCount(), entry.getOffset() / timeScaleDivisor));
+            }
+            return entries2;
+        } else {
+            return null;
+        }
+    }
+
+    List<TimeToSampleBox.Entry> adjustTts() {
+        List<TimeToSampleBox.Entry> origTts = source.getDecodingTimeEntries();
+        LinkedList<TimeToSampleBox.Entry> entries2 = new LinkedList<TimeToSampleBox.Entry>();
+        for (TimeToSampleBox.Entry e : origTts) {
+            entries2.add(new TimeToSampleBox.Entry(e.getCount(), e.getDelta() / timeScaleDivisor));
+        }
+        return entries2;
+    }
+
+    public Box getMediaHeaderBox() {
+        return source.getMediaHeaderBox();
+    }
+
+    public SubSampleInformationBox getSubsampleInformationBox() {
+        return source.getSubsampleInformationBox();
+    }
+
+    @Override
+    public String toString() {
+        return "MultiplyTimeScaleTrack{" +
+                "source=" + source +
+                '}';
+    }
+}
diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/authoring/tracks/.svn/text-base/EC3TrackImpl.java.svn-base b/isoparser/src/main/java/com/googlecode/mp4parser/authoring/tracks/.svn/text-base/EC3TrackImpl.java.svn-base
new file mode 100644
index 0000000..d0b2d76
--- /dev/null
+++ b/isoparser/src/main/java/com/googlecode/mp4parser/authoring/tracks/.svn/text-base/EC3TrackImpl.java.svn-base
@@ -0,0 +1,436 @@
+package com.googlecode.mp4parser.authoring.tracks;
+
+import com.coremedia.iso.boxes.*;
+import com.coremedia.iso.boxes.sampleentry.AudioSampleEntry;
+import com.googlecode.mp4parser.authoring.AbstractTrack;
+import com.googlecode.mp4parser.authoring.TrackMetaData;
+import com.googlecode.mp4parser.boxes.EC3SpecificBox;
+import com.googlecode.mp4parser.boxes.mp4.objectdescriptors.BitReaderBuffer;
+
+import java.io.BufferedInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.ByteBuffer;
+import java.util.Date;
+import java.util.LinkedList;
+import java.util.List;
+
+/**
+ * Created by IntelliJ IDEA.
+ * User: magnus
+ * Date: 2012-03-14
+ * Time: 10:39
+ * To change this template use File | Settings | File Templates.
+ */
+public class EC3TrackImpl extends AbstractTrack {
+    TrackMetaData trackMetaData = new TrackMetaData();
+    SampleDescriptionBox sampleDescriptionBox;
+
+    int samplerate;
+    int bitrate;
+    int frameSize;
+
+    List<BitStreamInfo> entries = new LinkedList<BitStreamInfo>();
+
+    private BufferedInputStream inputStream;
+    private List<ByteBuffer> samples;
+    List<TimeToSampleBox.Entry> stts = new LinkedList<TimeToSampleBox.Entry>();
+    private String lang = "und";
+
+    public EC3TrackImpl(InputStream fin, String lang) throws IOException {
+        this.lang = lang;
+        parse(fin);
+    }
+
+    public EC3TrackImpl(InputStream fin) throws IOException {
+        parse(fin);
+    }
+
+    private void parse(InputStream fin) throws IOException {
+        inputStream = new BufferedInputStream(fin);
+
+        boolean done = false;
+        inputStream.mark(10000);
+        while (!done) {
+            BitStreamInfo bsi = readVariables();
+            if (bsi == null) {
+                throw new IOException();
+            }
+            for (BitStreamInfo entry : entries) {
+                if (bsi.strmtyp != 1 && entry.substreamid == bsi.substreamid) {
+                    done = true;
+                }
+            }
+            if (!done) {
+                entries.add(bsi);
+                long skipped = inputStream.skip(bsi.frameSize);
+                assert skipped == bsi.frameSize;
+            }
+        }
+
+        inputStream.reset();
+
+        if (entries.size() == 0) {
+            throw new IOException();
+        }
+        samplerate = entries.get(0).samplerate;
+
+        sampleDescriptionBox = new SampleDescriptionBox();
+        AudioSampleEntry audioSampleEntry = new AudioSampleEntry("ec-3");
+        audioSampleEntry.setChannelCount(2);  // According to  ETSI TS 102 366 Annex F
+        audioSampleEntry.setSampleRate(samplerate);
+        audioSampleEntry.setDataReferenceIndex(1);
+        audioSampleEntry.setSampleSize(16);
+
+        EC3SpecificBox ec3 = new EC3SpecificBox();
+        int[] deps = new int[entries.size()];
+        int[] chan_locs = new int[entries.size()];
+        for (BitStreamInfo bsi : entries) {
+            if (bsi.strmtyp == 1) {
+                deps[bsi.substreamid]++;
+                chan_locs[bsi.substreamid] = ((bsi.chanmap >> 6) & 0x100) | ((bsi.chanmap >> 5) & 0xff);
+            }
+        }
+        for (BitStreamInfo bsi : entries) {
+            if (bsi.strmtyp != 1) {
+                EC3SpecificBox.Entry e = new EC3SpecificBox.Entry();
+                e.fscod = bsi.fscod;
+                e.bsid = bsi.bsid;
+                e.bsmod = bsi.bsmod;
+                e.acmod = bsi.acmod;
+                e.lfeon = bsi.lfeon;
+                e.reserved = 0;
+                e.num_dep_sub = deps[bsi.substreamid];
+                e.chan_loc = chan_locs[bsi.substreamid];
+                e.reserved2 = 0;
+                ec3.addEntry(e);
+            }
+            bitrate += bsi.bitrate;
+            frameSize += bsi.frameSize;
+        }
+
+        ec3.setDataRate(bitrate / 1000);
+        audioSampleEntry.addBox(ec3);
+        sampleDescriptionBox.addBox(audioSampleEntry);
+
+        trackMetaData.setCreationTime(new Date());
+        trackMetaData.setModificationTime(new Date());
+        trackMetaData.setLanguage(lang);
+        trackMetaData.setTimescale(samplerate); // Audio tracks always use samplerate as timescale
+
+        samples = new LinkedList<ByteBuffer>();
+        if (!readSamples()) {
+            throw new IOException();
+        }
+    }
+
+
+    public List<ByteBuffer> getSamples() {
+
+        return samples;
+    }
+
+    public SampleDescriptionBox getSampleDescriptionBox() {
+        return sampleDescriptionBox;
+    }
+
+    public List<TimeToSampleBox.Entry> getDecodingTimeEntries() {
+        return stts;
+    }
+
+    public List<CompositionTimeToSample.Entry> getCompositionTimeEntries() {
+        return null;
+    }
+
+    public long[] getSyncSamples() {
+        return null;
+    }
+
+    public List<SampleDependencyTypeBox.Entry> getSampleDependencies() {
+        return null;
+    }
+
+    public TrackMetaData getTrackMetaData() {
+        return trackMetaData;
+    }
+
+    public String getHandler() {
+        return "soun";
+    }
+
+    public AbstractMediaHeaderBox getMediaHeaderBox() {
+        return new SoundMediaHeaderBox();
+    }
+
+    public SubSampleInformationBox getSubsampleInformationBox() {
+        return null;
+    }
+
+    private BitStreamInfo readVariables() throws IOException {
+        byte[] data = new byte[200];
+        inputStream.mark(200);
+        if (200 != inputStream.read(data, 0, 200)) {
+            return null;
+        }
+        inputStream.reset(); // Rewind
+        ByteBuffer bb = ByteBuffer.wrap(data);
+        BitReaderBuffer brb = new BitReaderBuffer(bb);
+        int syncword = brb.readBits(16);
+        if (syncword != 0xb77) {
+            return null;
+        }
+
+        BitStreamInfo entry = new BitStreamInfo();
+
+        entry.strmtyp = brb.readBits(2);
+        entry.substreamid = brb.readBits(3);
+        int frmsiz = brb.readBits(11);
+        entry.frameSize = 2 * (frmsiz + 1);
+
+        entry.fscod = brb.readBits(2);
+        int fscod2 = -1;
+        int numblkscod;
+        if (entry.fscod == 3) {
+            fscod2 = brb.readBits(2);
+            numblkscod = 3;
+        } else {
+            numblkscod = brb.readBits(2);
+        }
+        int numberOfBlocksPerSyncFrame = 0;
+        switch (numblkscod) {
+            case 0:
+                numberOfBlocksPerSyncFrame = 1;
+                break;
+
+            case 1:
+                numberOfBlocksPerSyncFrame = 2;
+                break;
+
+            case 2:
+                numberOfBlocksPerSyncFrame = 3;
+                break;
+
+            case 3:
+                numberOfBlocksPerSyncFrame = 6;
+                break;
+
+        }
+        entry.frameSize *= (6 / numberOfBlocksPerSyncFrame);
+
+        entry.acmod = brb.readBits(3);
+        entry.lfeon = brb.readBits(1);
+        entry.bsid = brb.readBits(5);
+        brb.readBits(5);
+        if (1 == brb.readBits(1)) {
+            brb.readBits(8); // compr
+        }
+        if (0 == entry.acmod) {
+            brb.readBits(5);
+            if (1 == brb.readBits(1)) {
+                brb.readBits(8);
+            }
+        }
+        if (1 == entry.strmtyp) {
+            if (1 == brb.readBits(1)) {
+                entry.chanmap = brb.readBits(16);
+            }
+        }
+        if (1 == brb.readBits(1)) {     // mixing metadata
+            if (entry.acmod > 2) {
+                brb.readBits(2);
+            }
+            if (1 == (entry.acmod & 1) && entry.acmod > 2) {
+                brb.readBits(3);
+                brb.readBits(3);
+            }
+            if (0 < (entry.acmod & 4)) {
+                brb.readBits(3);
+                brb.readBits(3);
+            }
+            if (1 == entry.lfeon) {
+                if (1 == brb.readBits(1)) {
+                    brb.readBits(5);
+                }
+            }
+            if (0 == entry.strmtyp) {
+                if (1 == brb.readBits(1)) {
+                    brb.readBits(6);
+                }
+                if (0 == entry.acmod) {
+                    if (1 == brb.readBits(1)) {
+                        brb.readBits(6);
+                    }
+                }
+                if (1 == brb.readBits(1)) {
+                    brb.readBits(6);
+                }
+                int mixdef = brb.readBits(2);
+                if (1 == mixdef) {
+                    brb.readBits(5);
+                } else if (2 == mixdef) {
+                    brb.readBits(12);
+                } else if (3 == mixdef) {
+                    int mixdeflen = brb.readBits(5);
+                    if (1 == brb.readBits(1)) {
+                        brb.readBits(5);
+                        if (1 == brb.readBits(1)) {
+                            brb.readBits(4);
+                        }
+                        if (1 == brb.readBits(1)) {
+                            brb.readBits(4);
+                        }
+                        if (1 == brb.readBits(1)) {
+                            brb.readBits(4);
+                        }
+                        if (1 == brb.readBits(1)) {
+                            brb.readBits(4);
+                        }
+                        if (1 == brb.readBits(1)) {
+                            brb.readBits(4);
+                        }
+                        if (1 == brb.readBits(1)) {
+                            brb.readBits(4);
+                        }
+                        if (1 == brb.readBits(1)) {
+                            brb.readBits(4);
+                        }
+                        if (1 == brb.readBits(1)) {
+                            if (1 == brb.readBits(1)) {
+                                brb.readBits(4);
+                            }
+                            if (1 == brb.readBits(1)) {
+                                brb.readBits(4);
+                            }
+                        }
+                    }
+                    if (1 == brb.readBits(1)) {
+                        brb.readBits(5);
+                        if (1 == brb.readBits(1)) {
+                            brb.readBits(7);
+                            if (1 == brb.readBits(1)) {
+                                brb.readBits(8);
+                            }
+                        }
+                    }
+                    for (int i = 0; i < (mixdeflen + 2); i++) {
+                        brb.readBits(8);
+                    }
+                    brb.byteSync();
+                }
+                if (entry.acmod < 2) {
+                    if (1 == brb.readBits(1)) {
+                        brb.readBits(14);
+                    }
+                    if (0 == entry.acmod) {
+                        if (1 == brb.readBits(1)) {
+                            brb.readBits(14);
+                        }
+                    }
+                    if (1 == brb.readBits(1)) {
+                        if (numblkscod == 0) {
+                            brb.readBits(5);
+                        } else {
+                            for (int i = 0; i < numberOfBlocksPerSyncFrame; i++) {
+                                if (1 == brb.readBits(1)) {
+                                    brb.readBits(5);
+                                }
+                            }
+                        }
+
+                    }
+                }
+            }
+        }
+        if (1 == brb.readBits(1)) { // infomdate
+            entry.bsmod = brb.readBits(3);
+        }
+
+        switch (entry.fscod) {
+            case 0:
+                entry.samplerate = 48000;
+                break;
+
+            case 1:
+                entry.samplerate = 44100;
+                break;
+
+            case 2:
+                entry.samplerate = 32000;
+                break;
+
+            case 3: {
+                switch (fscod2) {
+                    case 0:
+                        entry.samplerate = 24000;
+                        break;
+
+                    case 1:
+                        entry.samplerate = 22050;
+                        break;
+
+                    case 2:
+                        entry.samplerate = 16000;
+                        break;
+
+                    case 3:
+                        entry.samplerate = 0;
+                        break;
+                }
+                break;
+            }
+
+        }
+        if (entry.samplerate == 0) {
+            return null;
+        }
+
+        entry.bitrate = (int) (((double) entry.samplerate) / 1536.0 * entry.frameSize * 8);
+
+        return entry;
+    }
+
+    private boolean readSamples() throws IOException {
+        int read = frameSize;
+        boolean ret = false;
+        while (frameSize == read) {
+            ret = true;
+            byte[] data = new byte[frameSize];
+            read = inputStream.read(data);
+            if (read == frameSize) {
+                samples.add(ByteBuffer.wrap(data));
+                stts.add(new TimeToSampleBox.Entry(1, 1536));
+            }
+        }
+        return ret;
+    }
+
+    public static class BitStreamInfo extends EC3SpecificBox.Entry {
+        public int frameSize;
+        public int substreamid;
+        public int bitrate;
+        public int samplerate;
+        public int strmtyp;
+        public int chanmap;
+
+        @Override
+        public String toString() {
+            return "BitStreamInfo{" +
+                    "frameSize=" + frameSize +
+                    ", substreamid=" + substreamid +
+                    ", bitrate=" + bitrate +
+                    ", samplerate=" + samplerate +
+                    ", strmtyp=" + strmtyp +
+                    ", chanmap=" + chanmap +
+                    '}';
+        }
+    }
+
+    @Override
+    public String toString() {
+        return "EC3TrackImpl{" +
+                "bitrate=" + bitrate +
+                ", samplerate=" + samplerate +
+                ", entries=" + entries +
+                '}';
+    }
+}
diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/authoring/tracks/.svn/text-base/H264TrackImpl.java.svn-base b/isoparser/src/main/java/com/googlecode/mp4parser/authoring/tracks/.svn/text-base/H264TrackImpl.java.svn-base
new file mode 100644
index 0000000..b3c1866
--- /dev/null
+++ b/isoparser/src/main/java/com/googlecode/mp4parser/authoring/tracks/.svn/text-base/H264TrackImpl.java.svn-base
@@ -0,0 +1,740 @@
+package com.googlecode.mp4parser.authoring.tracks;
+
+import com.coremedia.iso.boxes.*;
+import com.coremedia.iso.boxes.h264.AvcConfigurationBox;
+import com.coremedia.iso.boxes.sampleentry.VisualSampleEntry;
+import com.googlecode.mp4parser.authoring.AbstractTrack;
+import com.googlecode.mp4parser.authoring.TrackMetaData;
+import com.googlecode.mp4parser.h264.model.PictureParameterSet;
+import com.googlecode.mp4parser.h264.model.SeqParameterSet;
+import com.googlecode.mp4parser.h264.read.CAVLCReader;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.logging.Logger;
+
+/**
+ * The <code>H264TrackImpl</code> creates a <code>Track</code> from an H.264
+ * Annex B file.
+ */
+public class H264TrackImpl extends AbstractTrack {
+    private static final Logger LOG = Logger.getLogger(H264TrackImpl.class.getName());
+    
+    TrackMetaData trackMetaData = new TrackMetaData();
+    SampleDescriptionBox sampleDescriptionBox;
+
+    private ReaderWrapper reader;
+    private List<ByteBuffer> samples;
+    boolean readSamples = false;
+
+    List<TimeToSampleBox.Entry> stts;
+    List<CompositionTimeToSample.Entry> ctts;
+    List<SampleDependencyTypeBox.Entry> sdtp;
+    List<Integer> stss;
+
+    SeqParameterSet seqParameterSet = null;
+    PictureParameterSet pictureParameterSet = null;
+    LinkedList<byte[]> seqParameterSetList = new LinkedList<byte[]>();
+    LinkedList<byte[]> pictureParameterSetList = new LinkedList<byte[]>();
+
+    private int width;
+    private int height;
+    private int timescale;
+    private int frametick;
+    private int currentScSize;
+    private int prevScSize;
+
+    private SEIMessage seiMessage;
+    int frameNrInGop = 0;
+    private boolean determineFrameRate = true;
+    private String lang = "und";
+
+    public H264TrackImpl(InputStream inputStream, String lang, long timescale) throws IOException {
+        this.lang = lang;
+        if (timescale > 1000) {
+            timescale = timescale; //e.g. 23976
+            frametick = 1000;
+            determineFrameRate = false;
+        } else {
+            throw new IllegalArgumentException("Timescale must be specified in milliseconds!");
+        }
+        parse(inputStream);
+    }
+
+    public H264TrackImpl(InputStream inputStream, String lang) throws IOException {
+        this.lang = lang;
+        parse(inputStream);
+    }
+
+    public H264TrackImpl(InputStream inputStream) throws IOException {
+        parse(inputStream);
+    }
+
+    private void parse(InputStream inputStream) throws IOException {
+        this.reader = new ReaderWrapper(inputStream);
+        stts = new LinkedList<TimeToSampleBox.Entry>();
+        ctts = new LinkedList<CompositionTimeToSample.Entry>();
+        sdtp = new LinkedList<SampleDependencyTypeBox.Entry>();
+        stss = new LinkedList<Integer>();
+
+        samples = new LinkedList<ByteBuffer>();
+        if (!readSamples()) {
+            throw new IOException();
+        }
+
+        if (!readVariables()) {
+            throw new IOException();
+        }
+
+        sampleDescriptionBox = new SampleDescriptionBox();
+        VisualSampleEntry visualSampleEntry = new VisualSampleEntry("avc1");
+        visualSampleEntry.setDataReferenceIndex(1);
+        visualSampleEntry.setDepth(24);
+        visualSampleEntry.setFrameCount(1);
+        visualSampleEntry.setHorizresolution(72);
+        visualSampleEntry.setVertresolution(72);
+        visualSampleEntry.setWidth(width);
+        visualSampleEntry.setHeight(height);
+        visualSampleEntry.setCompressorname("AVC Coding");
+
+        AvcConfigurationBox avcConfigurationBox = new AvcConfigurationBox();
+
+        avcConfigurationBox.setSequenceParameterSets(seqParameterSetList);
+        avcConfigurationBox.setPictureParameterSets(pictureParameterSetList);
+        avcConfigurationBox.setAvcLevelIndication(seqParameterSet.level_idc);
+        avcConfigurationBox.setAvcProfileIndication(seqParameterSet.profile_idc);
+        avcConfigurationBox.setBitDepthLumaMinus8(seqParameterSet.bit_depth_luma_minus8);
+        avcConfigurationBox.setBitDepthChromaMinus8(seqParameterSet.bit_depth_chroma_minus8);
+        avcConfigurationBox.setChromaFormat(seqParameterSet.chroma_format_idc.getId());
+        avcConfigurationBox.setConfigurationVersion(1);
+        avcConfigurationBox.setLengthSizeMinusOne(3);
+        avcConfigurationBox.setProfileCompatibility(seqParameterSetList.get(0)[1]);
+
+        visualSampleEntry.addBox(avcConfigurationBox);
+        sampleDescriptionBox.addBox(visualSampleEntry);
+
+        trackMetaData.setCreationTime(new Date());
+        trackMetaData.setModificationTime(new Date());
+        trackMetaData.setLanguage(lang);
+        trackMetaData.setTimescale(timescale);
+        trackMetaData.setWidth(width);
+        trackMetaData.setHeight(height);
+    }
+
+    public SampleDescriptionBox getSampleDescriptionBox() {
+        return sampleDescriptionBox;
+    }
+
+    public List<TimeToSampleBox.Entry> getDecodingTimeEntries() {
+        return stts;
+    }
+
+    public List<CompositionTimeToSample.Entry> getCompositionTimeEntries() {
+        return ctts;
+    }
+
+    public long[] getSyncSamples() {
+        long[] returns = new long[stss.size()];
+        for (int i = 0; i < stss.size(); i++) {
+            returns[i] = stss.get(i);
+        }
+        return returns;
+    }
+
+    public List<SampleDependencyTypeBox.Entry> getSampleDependencies() {
+        return sdtp;
+    }
+
+    public TrackMetaData getTrackMetaData() {
+        return trackMetaData;
+    }
+
+    public String getHandler() {
+        return "vide";
+    }
+
+    public List<ByteBuffer> getSamples() {
+        return samples;
+    }
+
+    public AbstractMediaHeaderBox getMediaHeaderBox() {
+        return new VideoMediaHeaderBox();
+    }
+
+    public SubSampleInformationBox getSubsampleInformationBox() {
+        return null;
+    }
+
+    private boolean readVariables() {
+        width = (seqParameterSet.pic_width_in_mbs_minus1 + 1) * 16;
+        int mult = 2;
+        if (seqParameterSet.frame_mbs_only_flag) {
+            mult = 1;
+        }
+        height = 16 * (seqParameterSet.pic_height_in_map_units_minus1 + 1) * mult;
+        if (seqParameterSet.frame_cropping_flag) {
+            int chromaArrayType = 0;
+            if (seqParameterSet.residual_color_transform_flag == false) {
+                chromaArrayType = seqParameterSet.chroma_format_idc.getId();
+            }
+            int cropUnitX = 1;
+            int cropUnitY = mult;
+            if (chromaArrayType != 0) {
+                cropUnitX = seqParameterSet.chroma_format_idc.getSubWidth();
+                cropUnitY = seqParameterSet.chroma_format_idc.getSubHeight() * mult;
+            }
+
+            width -= cropUnitX * (seqParameterSet.frame_crop_left_offset + seqParameterSet.frame_crop_right_offset);
+            height -= cropUnitY * (seqParameterSet.frame_crop_top_offset + seqParameterSet.frame_crop_bottom_offset);
+        }
+        return true;
+    }
+
+    private boolean findNextStartcode() throws IOException {
+        byte[] test = new byte[]{-1, -1, -1, -1};
+
+        int c;
+        while ((c = reader.read()) != -1) {
+            test[0] = test[1];
+            test[1] = test[2];
+            test[2] = test[3];
+            test[3] = (byte) c;
+            if (test[0] == 0 && test[1] == 0 && test[2] == 0 && test[3] == 1) {
+                prevScSize = currentScSize;
+                currentScSize = 4;
+                return true;
+            }
+            if (test[0] == 0 && test[1] == 0 && test[2] == 1) {
+                prevScSize = currentScSize;
+                currentScSize = 3;
+                return true;
+            }
+        }
+        return false;
+    }
+
+    private enum NALActions {
+        IGNORE, BUFFER, STORE, END
+    }
+
+    private boolean readSamples() throws IOException {
+        if (readSamples) {
+            return true;
+        }
+
+        readSamples = true;
+
+
+        findNextStartcode();
+        reader.mark();
+        long pos = reader.getPos();
+
+        ArrayList<byte[]> buffered = new ArrayList<byte[]>();
+
+        int frameNr = 0;
+
+        while (findNextStartcode()) {
+            long newpos = reader.getPos();
+            int size = (int) (newpos - pos - prevScSize);
+            reader.reset();
+            byte[] data = new byte[size ];
+            reader.read(data);
+            int type = data[0];
+            int nal_ref_idc = (type >> 5) & 3;
+            int nal_unit_type = type & 0x1f;
+            LOG.fine("Found startcode at " + (pos -4)  + " Type: " + nal_unit_type + " ref idc: " + nal_ref_idc + " (size " + size + ")");
+            NALActions action = handleNALUnit(nal_ref_idc, nal_unit_type, data);
+            switch (action) {
+                case IGNORE:
+                    break;
+
+                case BUFFER:
+                    buffered.add(data);
+                    break;
+
+                case STORE:
+                    int stdpValue = 22;
+                    frameNr++;
+                    buffered.add(data);
+                    ByteBuffer bb = createSample(buffered);
+                    boolean IdrPicFlag = false;
+                    if (nal_unit_type == 5) {
+                        stdpValue += 16;
+                        IdrPicFlag = true;
+                    }
+                    ByteArrayInputStream bs = cleanBuffer(buffered.get(buffered.size() - 1));
+                    SliceHeader sh = new SliceHeader(bs, seqParameterSet, pictureParameterSet, IdrPicFlag);
+                    if (sh.slice_type == SliceHeader.SliceType.B) {
+                        stdpValue += 4;
+                    }
+                    LOG.fine("Adding sample with size " + bb.capacity() + " and header " + sh);
+                    buffered.clear();
+                    samples.add(bb);
+                    stts.add(new TimeToSampleBox.Entry(1, frametick));
+                    if (nal_unit_type == 5) { // IDR Picture
+                        stss.add(frameNr);
+                    }
+                    if (seiMessage.n_frames == 0) {
+                        frameNrInGop = 0;
+                    }
+                    int offset = 0;
+                    if (seiMessage.clock_timestamp_flag) {
+                        offset = seiMessage.n_frames - frameNrInGop;
+                    } else if (seiMessage.removal_delay_flag) {
+                        offset = seiMessage.dpb_removal_delay / 2;
+                    }
+                    ctts.add(new CompositionTimeToSample.Entry(1, offset * frametick));
+                    sdtp.add(new SampleDependencyTypeBox.Entry(stdpValue));
+                    frameNrInGop++;
+                    break;
+
+                case END:
+                    return true;
+
+
+            }
+            pos = newpos;
+            reader.seek(currentScSize);
+            reader.mark();
+        }
+        return true;
+    }
+
+    private ByteBuffer createSample(List<byte[]> buffers) {
+        int outsize = 0;
+        for (int i = 0; i < buffers.size(); i++) {
+            outsize += buffers.get(i).length + 4;
+        }
+        byte[] output = new byte[outsize];
+
+        ByteBuffer bb = ByteBuffer.wrap(output);
+        for (int i = 0; i < buffers.size(); i++) {
+            bb.putInt(buffers.get(i).length);
+            bb.put(buffers.get(i));
+        }
+        bb.rewind();
+        return bb;
+    }
+
+    private ByteArrayInputStream cleanBuffer(byte[] data) {
+        byte[] output = new byte[data.length];
+        int inPos = 0;
+        int outPos = 0;
+        while (inPos < data.length) {
+            if (data[inPos] == 0 && data[inPos + 1] == 0 && data[inPos + 2] == 3) {
+                output[outPos] = 0;
+                output[outPos + 1] = 0;
+                inPos += 3;
+                outPos += 2;
+            } else {
+                output[outPos] = data[inPos];
+                inPos++;
+                outPos++;
+            }
+        }
+        return new ByteArrayInputStream(output, 0, outPos);
+    }
+
+    private NALActions handleNALUnit(int nal_ref_idc, int nal_unit_type, byte[] data) throws IOException {
+        NALActions action;
+        switch (nal_unit_type) {
+            case 1:
+            case 2:
+            case 3:
+            case 4:
+            case 5:
+                action = NALActions.STORE; // Will only work in single slice per frame mode!
+                break;
+
+            case 6:
+                seiMessage = new SEIMessage(cleanBuffer(data), seqParameterSet);
+                action = NALActions.BUFFER;
+                break;
+
+            case 9:
+//                printAccessUnitDelimiter(data);
+                int type = data[1] >> 5;
+                LOG.fine("Access unit delimiter type: " + type);
+                action = NALActions.BUFFER;
+                break;
+
+
+            case 7:
+                if (seqParameterSet == null) {
+                    ByteArrayInputStream is = cleanBuffer(data);
+                    is.read();
+                    seqParameterSet = SeqParameterSet.read(is);
+                    seqParameterSetList.add(data);
+                    configureFramerate();
+                }
+                action = NALActions.IGNORE;
+                break;
+
+            case 8:
+                if (pictureParameterSet == null) {
+                    ByteArrayInputStream is = new ByteArrayInputStream(data);
+                    is.read();
+                    pictureParameterSet = PictureParameterSet.read(is);
+                    pictureParameterSetList.add(data);
+                }
+                action = NALActions.IGNORE;
+                break;
+
+            case 10:
+            case 11:
+                action = NALActions.END;
+                break;
+
+            default:
+                System.err.println("Unknown NAL unit type: " + nal_unit_type);
+                action = NALActions.IGNORE;
+
+        }
+
+        return action;
+    }
+
+    private void configureFramerate() {
+        if (determineFrameRate) {
+            if (seqParameterSet.vuiParams != null) {
+                timescale = seqParameterSet.vuiParams.time_scale >> 1; // Not sure why, but I found this in several places, and it works...
+                frametick = seqParameterSet.vuiParams.num_units_in_tick;
+                if (timescale == 0 || frametick == 0) {
+                    System.err.println("Warning: vuiParams contain invalid values: time_scale: " + timescale + " and frame_tick: " + frametick + ". Setting frame rate to 25fps");
+                    timescale = 90000;
+                    frametick = 3600;
+                }
+            } else {
+                System.err.println("Warning: Can't determine frame rate. Guessing 25 fps");
+                timescale = 90000;
+                frametick = 3600;
+            }
+        }
+    }
+
+    public void printAccessUnitDelimiter(byte[] data) {
+        LOG.fine("Access unit delimiter: " + (data[1] >> 5));
+    }
+
+    public static class SliceHeader {
+
+        public enum SliceType {
+            P, B, I, SP, SI
+        }
+
+        public int first_mb_in_slice;
+        public SliceType slice_type;
+        public int pic_parameter_set_id;
+        public int colour_plane_id;
+        public int frame_num;
+        public boolean field_pic_flag = false;
+        public boolean bottom_field_flag = false;
+        public int idr_pic_id;
+        public int pic_order_cnt_lsb;
+        public int delta_pic_order_cnt_bottom;
+
+        public SliceHeader(InputStream is, SeqParameterSet sps, PictureParameterSet pps, boolean IdrPicFlag) throws IOException {
+            is.read();
+            CAVLCReader reader = new CAVLCReader(is);
+            first_mb_in_slice = reader.readUE("SliceHeader: first_mb_in_slice");
+            switch (reader.readUE("SliceHeader: slice_type")) {
+                case 0:
+                case 5:
+                    slice_type = SliceType.P;
+                    break;
+
+                case 1:
+                case 6:
+                    slice_type = SliceType.B;
+                    break;
+
+                case 2:
+                case 7:
+                    slice_type = SliceType.I;
+                    break;
+
+                case 3:
+                case 8:
+                    slice_type = SliceType.SP;
+                    break;
+
+                case 4:
+                case 9:
+                    slice_type = SliceType.SI;
+                    break;
+
+            }
+            pic_parameter_set_id = reader.readUE("SliceHeader: pic_parameter_set_id");
+            if (sps.residual_color_transform_flag) {
+                colour_plane_id = reader.readU(2, "SliceHeader: colour_plane_id");
+            }
+            frame_num = reader.readU(sps.log2_max_frame_num_minus4 + 4, "SliceHeader: frame_num");
+
+            if (!sps.frame_mbs_only_flag) {
+                field_pic_flag = reader.readBool("SliceHeader: field_pic_flag");
+                if (field_pic_flag) {
+                    bottom_field_flag = reader.readBool("SliceHeader: bottom_field_flag");
+                }
+            }
+            if (IdrPicFlag) {
+                idr_pic_id = reader.readUE("SliceHeader: idr_pic_id");
+                if (sps.pic_order_cnt_type == 0) {
+                    pic_order_cnt_lsb = reader.readU(sps.log2_max_pic_order_cnt_lsb_minus4 + 4, "SliceHeader: pic_order_cnt_lsb");
+                    if (pps.pic_order_present_flag && !field_pic_flag) {
+                        delta_pic_order_cnt_bottom = reader.readSE("SliceHeader: delta_pic_order_cnt_bottom");
+                    }
+                }
+            }
+        }
+
+        @Override
+        public String toString() {
+            return "SliceHeader{" +
+                    "first_mb_in_slice=" + first_mb_in_slice +
+                    ", slice_type=" + slice_type +
+                    ", pic_parameter_set_id=" + pic_parameter_set_id +
+                    ", colour_plane_id=" + colour_plane_id +
+                    ", frame_num=" + frame_num +
+                    ", field_pic_flag=" + field_pic_flag +
+                    ", bottom_field_flag=" + bottom_field_flag +
+                    ", idr_pic_id=" + idr_pic_id +
+                    ", pic_order_cnt_lsb=" + pic_order_cnt_lsb +
+                    ", delta_pic_order_cnt_bottom=" + delta_pic_order_cnt_bottom +
+                    '}';
+        }
+    }
+
+    private class ReaderWrapper {
+        private InputStream inputStream;
+        private long pos = 0;
+
+        private long markPos = 0;
+
+
+        private ReaderWrapper(InputStream inputStream) {
+            this.inputStream = inputStream;
+        }
+
+        int read() throws IOException {
+            pos++;
+            return inputStream.read();
+        }
+
+        long read(byte[] data) throws IOException {
+            long read = inputStream.read(data);
+            pos += read;
+            return read;
+        }
+
+        long seek(int dist) throws IOException {
+            long seeked = inputStream.skip(dist);
+            pos += seeked;
+            return seeked;
+        }
+
+        public long getPos() {
+            return pos;
+        }
+
+        public void mark() {
+            int i = 1048576;
+            LOG.fine("Marking with " + i + " at " + pos);
+            inputStream.mark(i);
+            markPos = pos;
+        }
+
+
+        public void reset() throws IOException {
+            long diff = pos - markPos;
+            LOG.fine("Resetting to " + markPos + " (pos is " + pos + ") which makes the buffersize " + diff);
+            inputStream.reset();
+            pos = markPos;
+        }
+    }
+
+    public class SEIMessage {
+
+        int payloadType = 0;
+        int payloadSize = 0;
+
+        boolean removal_delay_flag;
+        int cpb_removal_delay;
+        int dpb_removal_delay;
+
+        boolean clock_timestamp_flag;
+        int pic_struct;
+        int ct_type;
+        int nuit_field_based_flag;
+        int counting_type;
+        int full_timestamp_flag;
+        int discontinuity_flag;
+        int cnt_dropped_flag;
+        int n_frames;
+        int seconds_value;
+        int minutes_value;
+        int hours_value;
+        int time_offset_length;
+        int time_offset;
+
+        SeqParameterSet sps;
+
+        public SEIMessage(InputStream is, SeqParameterSet sps) throws IOException {
+            this.sps = sps;
+            is.read();
+            int datasize = is.available();
+            int read = 0;
+            while (read < datasize) {
+                payloadType = 0;
+                payloadSize = 0;
+                int last_payload_type_bytes = is.read();
+                read++;
+                while (last_payload_type_bytes == 0xff) {
+                    payloadType += last_payload_type_bytes;
+                    last_payload_type_bytes = is.read();
+                    read++;
+                }
+                payloadType += last_payload_type_bytes;
+                int last_payload_size_bytes = is.read();
+                read++;
+
+                while (last_payload_size_bytes == 0xff) {
+                    payloadSize += last_payload_size_bytes;
+                    last_payload_size_bytes = is.read();
+                    read++;
+                }
+                payloadSize += last_payload_size_bytes;
+                if (datasize - read >= payloadSize) {
+                    if (payloadType == 1) { // pic_timing is what we are interested in!
+                        if (sps.vuiParams != null && (sps.vuiParams.nalHRDParams != null || sps.vuiParams.vclHRDParams != null || sps.vuiParams.pic_struct_present_flag)) {
+                            byte[] data = new byte[payloadSize];
+                            is.read(data);
+                            read += payloadSize;
+                            CAVLCReader reader = new CAVLCReader(new ByteArrayInputStream(data));
+                            if (sps.vuiParams.nalHRDParams != null || sps.vuiParams.vclHRDParams != null) {
+                                removal_delay_flag = true;
+                                cpb_removal_delay = reader.readU(sps.vuiParams.nalHRDParams.cpb_removal_delay_length_minus1 + 1, "SEI: cpb_removal_delay");
+                                dpb_removal_delay = reader.readU(sps.vuiParams.nalHRDParams.dpb_output_delay_length_minus1 + 1, "SEI: dpb_removal_delay");
+                            } else {
+                                removal_delay_flag = false;
+                            }
+                            if (sps.vuiParams.pic_struct_present_flag) {
+                                pic_struct = reader.readU(4, "SEI: pic_struct");
+                                int numClockTS;
+                                switch (pic_struct) {
+                                    case 0:
+                                    case 1:
+                                    case 2:
+                                    default:
+                                        numClockTS = 1;
+                                        break;
+
+                                    case 3:
+                                    case 4:
+                                    case 7:
+                                        numClockTS = 2;
+                                        break;
+
+                                    case 5:
+                                    case 6:
+                                    case 8:
+                                        numClockTS = 3;
+                                        break;
+                                }
+                                for (int i = 0; i < numClockTS; i++) {
+                                    clock_timestamp_flag = reader.readBool("pic_timing SEI: clock_timestamp_flag[" + i + "]");
+                                    if (clock_timestamp_flag) {
+                                        ct_type = reader.readU(2, "pic_timing SEI: ct_type");
+                                        nuit_field_based_flag = reader.readU(1, "pic_timing SEI: nuit_field_based_flag");
+                                        counting_type = reader.readU(5, "pic_timing SEI: counting_type");
+                                        full_timestamp_flag = reader.readU(1, "pic_timing SEI: full_timestamp_flag");
+                                        discontinuity_flag = reader.readU(1, "pic_timing SEI: discontinuity_flag");
+                                        cnt_dropped_flag = reader.readU(1, "pic_timing SEI: cnt_dropped_flag");
+                                        n_frames = reader.readU(8, "pic_timing SEI: n_frames");
+                                        if (full_timestamp_flag == 1) {
+                                            seconds_value = reader.readU(6, "pic_timing SEI: seconds_value");
+                                            minutes_value = reader.readU(6, "pic_timing SEI: minutes_value");
+                                            hours_value = reader.readU(5, "pic_timing SEI: hours_value");
+                                        } else {
+                                            if (reader.readBool("pic_timing SEI: seconds_flag")) {
+                                                seconds_value = reader.readU(6, "pic_timing SEI: seconds_value");
+                                                if (reader.readBool("pic_timing SEI: minutes_flag")) {
+                                                    minutes_value = reader.readU(6, "pic_timing SEI: minutes_value");
+                                                    if (reader.readBool("pic_timing SEI: hours_flag")) {
+                                                        hours_value = reader.readU(5, "pic_timing SEI: hours_value");
+                                                    }
+                                                }
+                                            }
+                                        }
+                                        if (true) {
+                                            if (sps.vuiParams.nalHRDParams != null) {
+                                                time_offset_length = sps.vuiParams.nalHRDParams.time_offset_length;
+                                            } else if (sps.vuiParams.vclHRDParams != null) {
+                                                time_offset_length = sps.vuiParams.vclHRDParams.time_offset_length;
+                                            } else {
+                                                time_offset_length = 24;
+                                            }
+                                            time_offset = reader.readU(24, "pic_timing SEI: time_offset");
+                                        }
+                                    }
+                                }
+                            }
+
+                        } else {
+                            for (int i = 0; i < payloadSize; i++) {
+                                is.read();
+                                read++;
+                            }
+                        }
+                    } else {
+                        for (int i = 0; i < payloadSize; i++) {
+                            is.read();
+                            read++;
+                        }
+                    }
+                } else {
+                    read = datasize;
+                }
+                LOG.fine(this.toString());
+            }
+        }
+
+        @Override
+        public String toString() {
+            String out = "SEIMessage{" +
+                    "payloadType=" + payloadType +
+                    ", payloadSize=" + payloadSize;
+            if (payloadType == 1) {
+                if (sps.vuiParams.nalHRDParams != null || sps.vuiParams.vclHRDParams != null) {
+
+                    out += ", cpb_removal_delay=" + cpb_removal_delay +
+                            ", dpb_removal_delay=" + dpb_removal_delay;
+                }
+                if (sps.vuiParams.pic_struct_present_flag) {
+                    out += ", pic_struct=" + pic_struct;
+                    if (clock_timestamp_flag) {
+                        out += ", ct_type=" + ct_type +
+                                ", nuit_field_based_flag=" + nuit_field_based_flag +
+                                ", counting_type=" + counting_type +
+                                ", full_timestamp_flag=" + full_timestamp_flag +
+                                ", discontinuity_flag=" + discontinuity_flag +
+                                ", cnt_dropped_flag=" + cnt_dropped_flag +
+                                ", n_frames=" + n_frames +
+                                ", seconds_value=" + seconds_value +
+                                ", minutes_value=" + minutes_value +
+                                ", hours_value=" + hours_value +
+                                ", time_offset_length=" + time_offset_length +
+                                ", time_offset=" + time_offset;
+                    }
+                }
+            }
+            out += '}';
+            return out;
+        }
+    }
+}
diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/authoring/tracks/.svn/text-base/MultiplyTimeScaleTrack.java.svn-base b/isoparser/src/main/java/com/googlecode/mp4parser/authoring/tracks/.svn/text-base/MultiplyTimeScaleTrack.java.svn-base
new file mode 100644
index 0000000..e9a90e4
--- /dev/null
+++ b/isoparser/src/main/java/com/googlecode/mp4parser/authoring/tracks/.svn/text-base/MultiplyTimeScaleTrack.java.svn-base
@@ -0,0 +1,130 @@
+/*
+ * Copyright 2012 Sebastian Annies, Hamburg
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.googlecode.mp4parser.authoring.tracks;
+
+import com.coremedia.iso.boxes.*;
+import com.googlecode.mp4parser.authoring.Movie;
+import com.googlecode.mp4parser.authoring.Track;
+import com.googlecode.mp4parser.authoring.TrackMetaData;
+
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
+import java.util.LinkedList;
+import java.util.List;
+
+import static com.googlecode.mp4parser.util.CastUtils.l2i;
+import static com.googlecode.mp4parser.util.Math.gcd;
+import static com.googlecode.mp4parser.util.Math.lcm;
+import static java.lang.Math.round;
+
+/**
+ * Changes the timescale of a track by wrapping the track.
+ */
+public class MultiplyTimeScaleTrack implements Track {
+    Track source;
+    private int timeScaleFactor;
+
+    public MultiplyTimeScaleTrack(Track source, int timeScaleFactor) {
+        this.source = source;
+        this.timeScaleFactor = timeScaleFactor;
+    }
+
+    public SampleDescriptionBox getSampleDescriptionBox() {
+        return source.getSampleDescriptionBox();
+    }
+
+    public List<TimeToSampleBox.Entry> getDecodingTimeEntries() {
+        return adjustTts(source.getDecodingTimeEntries(), timeScaleFactor);
+    }
+
+    public List<CompositionTimeToSample.Entry> getCompositionTimeEntries() {
+        return adjustCtts(source.getCompositionTimeEntries(), timeScaleFactor);
+    }
+
+    public long[] getSyncSamples() {
+        return source.getSyncSamples();
+    }
+
+    public List<SampleDependencyTypeBox.Entry> getSampleDependencies() {
+        return source.getSampleDependencies();
+    }
+
+    public TrackMetaData getTrackMetaData() {
+        TrackMetaData trackMetaData = (TrackMetaData) source.getTrackMetaData().clone();
+        trackMetaData.setTimescale(source.getTrackMetaData().getTimescale() * this.timeScaleFactor);
+        return trackMetaData;
+    }
+
+    public String getHandler() {
+        return source.getHandler();
+    }
+
+    public boolean isEnabled() {
+        return source.isEnabled();
+    }
+
+    public boolean isInMovie() {
+        return source.isInMovie();
+    }
+
+    public boolean isInPreview() {
+        return source.isInPreview();
+    }
+
+    public boolean isInPoster() {
+        return source.isInPoster();
+    }
+
+    public List<ByteBuffer> getSamples() {
+        return source.getSamples();
+    }
+
+
+    static List<CompositionTimeToSample.Entry> adjustCtts(List<CompositionTimeToSample.Entry> source, int timeScaleFactor) {
+        if (source != null) {
+            List<CompositionTimeToSample.Entry> entries2 = new ArrayList<CompositionTimeToSample.Entry>(source.size());
+            for (CompositionTimeToSample.Entry entry : source) {
+                entries2.add(new CompositionTimeToSample.Entry(entry.getCount(), timeScaleFactor * entry.getOffset()));
+            }
+            return entries2;
+        } else {
+            return null;
+        }
+    }
+
+    static List<TimeToSampleBox.Entry> adjustTts(List<TimeToSampleBox.Entry> source, int timeScaleFactor) {
+        LinkedList<TimeToSampleBox.Entry> entries2 = new LinkedList<TimeToSampleBox.Entry>();
+        for (TimeToSampleBox.Entry e : source) {
+            entries2.add(new TimeToSampleBox.Entry(e.getCount(), timeScaleFactor * e.getDelta()));
+        }
+        return entries2;
+    }
+
+    public Box getMediaHeaderBox() {
+        return source.getMediaHeaderBox();
+    }
+
+    public SubSampleInformationBox getSubsampleInformationBox() {
+        return source.getSubsampleInformationBox();
+    }
+
+    @Override
+    public String toString() {
+        return "MultiplyTimeScaleTrack{" +
+                "source=" + source +
+                '}';
+    }
+}
diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/authoring/tracks/.svn/text-base/QuicktimeTextTrackImpl.java.svn-base b/isoparser/src/main/java/com/googlecode/mp4parser/authoring/tracks/.svn/text-base/QuicktimeTextTrackImpl.java.svn-base
new file mode 100644
index 0000000..8efa399
--- /dev/null
+++ b/isoparser/src/main/java/com/googlecode/mp4parser/authoring/tracks/.svn/text-base/QuicktimeTextTrackImpl.java.svn-base
@@ -0,0 +1,165 @@
+/*
+ * Copyright 2012 Sebastian Annies, Hamburg
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.googlecode.mp4parser.authoring.tracks;
+
+import com.coremedia.iso.boxes.*;
+import com.coremedia.iso.boxes.sampleentry.TextSampleEntry;
+import com.googlecode.mp4parser.authoring.AbstractTrack;
+import com.googlecode.mp4parser.authoring.TrackMetaData;
+import com.googlecode.mp4parser.boxes.apple.BaseMediaInfoAtom;
+import com.googlecode.mp4parser.boxes.apple.GenericMediaHeaderAtom;
+import com.googlecode.mp4parser.boxes.apple.GenericMediaHeaderTextAtom;
+import com.googlecode.mp4parser.boxes.apple.QuicktimeTextSampleEntry;
+import com.googlecode.mp4parser.boxes.threegpp26245.FontTableBox;
+
+import java.io.ByteArrayOutputStream;
+import java.io.DataOutputStream;
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.util.Collections;
+import java.util.Date;
+import java.util.LinkedList;
+import java.util.List;
+
+/**
+ * A Text track as Quicktime Pro would create.
+ */
+public class QuicktimeTextTrackImpl extends AbstractTrack {
+    TrackMetaData trackMetaData = new TrackMetaData();
+    SampleDescriptionBox sampleDescriptionBox;
+    List<Line> subs = new LinkedList<Line>();
+
+    public List<Line> getSubs() {
+        return subs;
+    }
+
+    public QuicktimeTextTrackImpl() {
+        sampleDescriptionBox = new SampleDescriptionBox();
+        QuicktimeTextSampleEntry textTrack = new QuicktimeTextSampleEntry();
+        textTrack.setDataReferenceIndex(1);
+        sampleDescriptionBox.addBox(textTrack);
+
+
+        trackMetaData.setCreationTime(new Date());
+        trackMetaData.setModificationTime(new Date());
+        trackMetaData.setTimescale(1000);
+
+
+    }
+
+
+    public List<ByteBuffer> getSamples() {
+        List<ByteBuffer> samples = new LinkedList<ByteBuffer>();
+        long lastEnd = 0;
+        for (Line sub : subs) {
+            long silentTime = sub.from - lastEnd;
+            if (silentTime > 0) {
+                samples.add(ByteBuffer.wrap(new byte[]{0, 0}));
+            } else if (silentTime < 0) {
+                throw new Error("Subtitle display times may not intersect");
+            }
+            ByteArrayOutputStream baos = new ByteArrayOutputStream();
+            DataOutputStream dos = new DataOutputStream(baos);
+            try {
+                dos.writeShort(sub.text.getBytes("UTF-8").length);
+                dos.write(sub.text.getBytes("UTF-8"));
+                dos.close();
+            } catch (IOException e) {
+                throw new Error("VM is broken. Does not support UTF-8");
+            }
+            samples.add(ByteBuffer.wrap(baos.toByteArray()));
+            lastEnd = sub.to;
+        }
+        return samples;
+    }
+
+    public SampleDescriptionBox getSampleDescriptionBox() {
+        return sampleDescriptionBox;
+    }
+
+    public List<TimeToSampleBox.Entry> getDecodingTimeEntries() {
+        List<TimeToSampleBox.Entry> stts = new LinkedList<TimeToSampleBox.Entry>();
+        long lastEnd = 0;
+        for (Line sub : subs) {
+            long silentTime = sub.from - lastEnd;
+            if (silentTime > 0) {
+                stts.add(new TimeToSampleBox.Entry(1, silentTime));
+            } else if (silentTime < 0) {
+                throw new Error("Subtitle display times may not intersect");
+            }
+            stts.add(new TimeToSampleBox.Entry(1, sub.to - sub.from));
+            lastEnd = sub.to;
+        }
+        return stts;
+    }
+
+    public List<CompositionTimeToSample.Entry> getCompositionTimeEntries() {
+        return null;
+    }
+
+    public long[] getSyncSamples() {
+        return null;
+    }
+
+    public List<SampleDependencyTypeBox.Entry> getSampleDependencies() {
+        return null;
+    }
+
+    public TrackMetaData getTrackMetaData() {
+        return trackMetaData;
+    }
+
+    public String getHandler() {
+        return "text";
+    }
+
+
+    public static class Line {
+        long from;
+        long to;
+        String text;
+
+
+        public Line(long from, long to, String text) {
+            this.from = from;
+            this.to = to;
+            this.text = text;
+        }
+
+        public long getFrom() {
+            return from;
+        }
+
+        public String getText() {
+            return text;
+        }
+
+        public long getTo() {
+            return to;
+        }
+    }
+
+    public Box getMediaHeaderBox() {
+        GenericMediaHeaderAtom ghmd = new GenericMediaHeaderAtom();
+        ghmd.addBox(new BaseMediaInfoAtom());
+        ghmd.addBox(new GenericMediaHeaderTextAtom());
+        return ghmd;
+    }
+
+    public SubSampleInformationBox getSubsampleInformationBox() {
+        return null;
+    }
+}
diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/authoring/tracks/.svn/text-base/ReplaceSampleTrack.java.svn-base b/isoparser/src/main/java/com/googlecode/mp4parser/authoring/tracks/.svn/text-base/ReplaceSampleTrack.java.svn-base
new file mode 100644
index 0000000..81a129d
--- /dev/null
+++ b/isoparser/src/main/java/com/googlecode/mp4parser/authoring/tracks/.svn/text-base/ReplaceSampleTrack.java.svn-base
@@ -0,0 +1,104 @@
+/*
+ * Copyright 2012 Sebastian Annies, Hamburg
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.googlecode.mp4parser.authoring.tracks;
+
+import com.coremedia.iso.boxes.*;
+import com.googlecode.mp4parser.authoring.AbstractTrack;
+import com.googlecode.mp4parser.authoring.Track;
+import com.googlecode.mp4parser.authoring.TrackMetaData;
+
+import java.nio.ByteBuffer;
+import java.util.AbstractList;
+import java.util.LinkedList;
+import java.util.List;
+
+/**
+ * Generates a Track where a single sample has been replaced by a given <code>ByteBuffer</code>.
+ */
+
+public class ReplaceSampleTrack extends AbstractTrack {
+    Track origTrack;
+    private long sampleNumber;
+    private ByteBuffer sampleContent;
+    private List<ByteBuffer>  samples;
+
+    public ReplaceSampleTrack(Track origTrack, long sampleNumber, ByteBuffer content) {
+        this.origTrack = origTrack;
+        this.sampleNumber = sampleNumber;
+        this.sampleContent = content;
+        this.samples = new ReplaceASingleEntryList();
+
+    }
+
+    public List<ByteBuffer> getSamples() {
+        return samples;
+    }
+
+    public SampleDescriptionBox getSampleDescriptionBox() {
+        return origTrack.getSampleDescriptionBox();
+    }
+
+    public List<TimeToSampleBox.Entry> getDecodingTimeEntries() {
+        return origTrack.getDecodingTimeEntries();
+
+    }
+
+    public List<CompositionTimeToSample.Entry> getCompositionTimeEntries() {
+        return origTrack.getCompositionTimeEntries();
+
+    }
+
+    synchronized public long[] getSyncSamples() {
+        return origTrack.getSyncSamples();
+    }
+
+    public List<SampleDependencyTypeBox.Entry> getSampleDependencies() {
+        return origTrack.getSampleDependencies();
+    }
+
+    public TrackMetaData getTrackMetaData() {
+        return origTrack.getTrackMetaData();
+    }
+
+    public String getHandler() {
+        return origTrack.getHandler();
+    }
+
+    public Box getMediaHeaderBox() {
+        return origTrack.getMediaHeaderBox();
+    }
+
+    public SubSampleInformationBox getSubsampleInformationBox() {
+        return origTrack.getSubsampleInformationBox();
+    }
+
+    private class ReplaceASingleEntryList extends AbstractList<ByteBuffer> {
+        @Override
+        public ByteBuffer get(int index) {
+            if (ReplaceSampleTrack.this.sampleNumber == index) {
+                return ReplaceSampleTrack.this.sampleContent;
+            } else {
+                return ReplaceSampleTrack.this.origTrack.getSamples().get(index);
+            }
+        }
+
+        @Override
+        public int size() {
+            return ReplaceSampleTrack.this.origTrack.getSamples().size();
+        }
+    }
+
+}
diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/authoring/tracks/.svn/text-base/SilenceTrackImpl.java.svn-base b/isoparser/src/main/java/com/googlecode/mp4parser/authoring/tracks/.svn/text-base/SilenceTrackImpl.java.svn-base
new file mode 100644
index 0000000..f74ab3c
--- /dev/null
+++ b/isoparser/src/main/java/com/googlecode/mp4parser/authoring/tracks/.svn/text-base/SilenceTrackImpl.java.svn-base
@@ -0,0 +1,98 @@
+package com.googlecode.mp4parser.authoring.tracks;
+
+import com.coremedia.iso.boxes.*;
+import com.googlecode.mp4parser.authoring.Mp4TrackImpl;
+import com.googlecode.mp4parser.authoring.Track;
+import com.googlecode.mp4parser.authoring.TrackMetaData;
+
+import java.nio.ByteBuffer;
+import java.util.Collections;
+import java.util.LinkedList;
+import java.util.List;
+
+/**
+ * This is just a basic idea how things could work but they don't.
+ */
+public class SilenceTrackImpl implements Track {
+    Track source;
+
+    List<ByteBuffer> samples = new LinkedList<ByteBuffer>();
+    TimeToSampleBox.Entry entry;
+
+    public SilenceTrackImpl(Track ofType, long ms) {
+        source = ofType;
+        if ("mp4a".equals(ofType.getSampleDescriptionBox().getSampleEntry().getType())) {
+            long numFrames = getTrackMetaData().getTimescale() * ms / 1000 / 1024;
+            long standZeit = getTrackMetaData().getTimescale() * ms / numFrames / 1000;
+            entry = new TimeToSampleBox.Entry(numFrames, standZeit);
+
+
+            while (numFrames-- > 0) {
+                samples.add((ByteBuffer) ByteBuffer.wrap(new byte[]{
+                        0x21, 0x10, 0x04, 0x60, (byte) 0x8c, 0x1c,
+                }).rewind());
+            }
+
+        } else {
+            throw new RuntimeException("Tracks of type " + ofType.getClass().getSimpleName() + " are not supported");
+        }
+    }
+
+    public SampleDescriptionBox getSampleDescriptionBox() {
+        return source.getSampleDescriptionBox();
+    }
+
+    public List<TimeToSampleBox.Entry> getDecodingTimeEntries() {
+        return Collections.singletonList(entry);
+
+    }
+
+    public TrackMetaData getTrackMetaData() {
+        return source.getTrackMetaData();
+    }
+
+    public String getHandler() {
+        return source.getHandler();
+    }
+
+    public boolean isEnabled() {
+        return source.isEnabled();
+    }
+
+    public boolean isInMovie() {
+        return source.isInMovie();
+    }
+
+    public boolean isInPreview() {
+        return source.isInPreview();
+    }
+
+    public boolean isInPoster() {
+        return source.isInPoster();
+    }
+
+    public List<ByteBuffer> getSamples() {
+        return samples;
+    }
+
+    public Box getMediaHeaderBox() {
+        return source.getMediaHeaderBox();
+    }
+
+    public SubSampleInformationBox getSubsampleInformationBox() {
+        return null;
+    }
+
+    public List<CompositionTimeToSample.Entry> getCompositionTimeEntries() {
+        return null;
+    }
+
+    public long[] getSyncSamples() {
+        return null;
+    }
+
+    public List<SampleDependencyTypeBox.Entry> getSampleDependencies() {
+        return null;
+    }
+
+}
diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/authoring/tracks/.svn/text-base/TextTrackImpl.java.svn-base b/isoparser/src/main/java/com/googlecode/mp4parser/authoring/tracks/.svn/text-base/TextTrackImpl.java.svn-base
new file mode 100644
index 0000000..3bae143
--- /dev/null
+++ b/isoparser/src/main/java/com/googlecode/mp4parser/authoring/tracks/.svn/text-base/TextTrackImpl.java.svn-base
@@ -0,0 +1,165 @@
+/*
+ * Copyright 2012 Sebastian Annies, Hamburg
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.googlecode.mp4parser.authoring.tracks;
+
+import com.coremedia.iso.boxes.*;
+import com.coremedia.iso.boxes.sampleentry.TextSampleEntry;
+import com.googlecode.mp4parser.authoring.AbstractTrack;
+import com.googlecode.mp4parser.authoring.TrackMetaData;
+import com.googlecode.mp4parser.boxes.threegpp26245.FontTableBox;
+
+import java.io.ByteArrayOutputStream;
+import java.io.DataOutputStream;
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.util.Collections;
+import java.util.Date;
+import java.util.LinkedList;
+import java.util.List;
+
+/**
+ *
+ */
+public class TextTrackImpl extends AbstractTrack {
+    TrackMetaData trackMetaData = new TrackMetaData();
+    SampleDescriptionBox sampleDescriptionBox;
+    List<Line> subs = new LinkedList<Line>();
+
+    public List<Line> getSubs() {
+        return subs;
+    }
+
+    public TextTrackImpl() {
+        sampleDescriptionBox = new SampleDescriptionBox();
+        TextSampleEntry tx3g = new TextSampleEntry("tx3g");
+        tx3g.setDataReferenceIndex(1);
+        tx3g.setStyleRecord(new TextSampleEntry.StyleRecord());
+        tx3g.setBoxRecord(new TextSampleEntry.BoxRecord());
+        sampleDescriptionBox.addBox(tx3g);
+
+        FontTableBox ftab = new FontTableBox();
+        ftab.setEntries(Collections.singletonList(new FontTableBox.FontRecord(1, "Serif")));
+
+        tx3g.addBox(ftab);
+
+
+        trackMetaData.setCreationTime(new Date());
+        trackMetaData.setModificationTime(new Date());
+        trackMetaData.setTimescale(1000); // Text tracks use millieseconds
+
+
+    }
+
+
+    public List<ByteBuffer> getSamples() {
+        List<ByteBuffer> samples = new LinkedList<ByteBuffer>();
+        long lastEnd = 0;
+        for (Line sub : subs) {
+            long silentTime = sub.from - lastEnd;
+            if (silentTime > 0) {
+                samples.add(ByteBuffer.wrap(new byte[]{0, 0}));
+            } else if (silentTime < 0) {
+                throw new Error("Subtitle display times may not intersect");
+            }
+            ByteArrayOutputStream baos = new ByteArrayOutputStream();
+            DataOutputStream dos = new DataOutputStream(baos);
+            try {
+                dos.writeShort(sub.text.getBytes("UTF-8").length);
+                dos.write(sub.text.getBytes("UTF-8"));
+                dos.close();
+            } catch (IOException e) {
+                throw new Error("VM is broken. Does not support UTF-8");
+            }
+            samples.add(ByteBuffer.wrap(baos.toByteArray()));
+            lastEnd = sub.to;
+        }
+        return samples;
+    }
+
+    public SampleDescriptionBox getSampleDescriptionBox() {
+        return sampleDescriptionBox;
+    }
+
+    public List<TimeToSampleBox.Entry> getDecodingTimeEntries() {
+        List<TimeToSampleBox.Entry> stts = new LinkedList<TimeToSampleBox.Entry>();
+        long lastEnd = 0;
+        for (Line sub : subs) {
+            long silentTime = sub.from - lastEnd;
+            if (silentTime > 0) {
+                stts.add(new TimeToSampleBox.Entry(1, silentTime));
+            } else if (silentTime < 0) {
+                throw new Error("Subtitle display times may not intersect");
+            }
+            stts.add(new TimeToSampleBox.Entry(1, sub.to - sub.from));
+            lastEnd = sub.to;
+        }
+        return stts;
+    }
+
+    public List<CompositionTimeToSample.Entry> getCompositionTimeEntries() {
+        return null;
+    }
+
+    public long[] getSyncSamples() {
+        return null;
+    }
+
+    public List<SampleDependencyTypeBox.Entry> getSampleDependencies() {
+        return null;
+    }
+
+    public TrackMetaData getTrackMetaData() {
+        return trackMetaData;
+    }
+
+    public String getHandler() {
+        return "sbtl";
+    }
+
+
+    public static class Line {
+        long from;
+        long to;
+        String text;
+
+
+        public Line(long from, long to, String text) {
+            this.from = from;
+            this.to = to;
+            this.text = text;
+        }
+
+        public long getFrom() {
+            return from;
+        }
+
+        public String getText() {
+            return text;
+        }
+
+        public long getTo() {
+            return to;
+        }
+    }
+
+    public AbstractMediaHeaderBox getMediaHeaderBox() {
+        return new NullMediaHeaderBox();
+    }
+
+    public SubSampleInformationBox getSubsampleInformationBox() {
+        return null;
+    }
+}
diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/authoring/tracks/AACTrackImpl.java b/isoparser/src/main/java/com/googlecode/mp4parser/authoring/tracks/AACTrackImpl.java
new file mode 100644
index 0000000..df51a1a
--- /dev/null
+++ b/isoparser/src/main/java/com/googlecode/mp4parser/authoring/tracks/AACTrackImpl.java
@@ -0,0 +1,292 @@
+/*
+ * Copyright 2012 castLabs GmbH, Berlin
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.googlecode.mp4parser.authoring.tracks;
+
+import com.coremedia.iso.boxes.*;
+import com.coremedia.iso.boxes.sampleentry.AudioSampleEntry;
+import com.googlecode.mp4parser.authoring.AbstractTrack;
+import com.googlecode.mp4parser.authoring.TrackMetaData;
+import com.googlecode.mp4parser.boxes.AC3SpecificBox;
+import com.googlecode.mp4parser.boxes.mp4.ESDescriptorBox;
+import com.googlecode.mp4parser.boxes.mp4.objectdescriptors.*;
+
+import java.io.BufferedInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.ByteBuffer;
+import java.util.*;
+
+/**
+ */
+public class AACTrackImpl extends AbstractTrack {
+    public static Map<Integer, Integer> samplingFrequencyIndexMap = new HashMap<Integer, Integer>();
+
+    static {
+        samplingFrequencyIndexMap.put(96000, 0);
+        samplingFrequencyIndexMap.put(88200, 1);
+        samplingFrequencyIndexMap.put(64000, 2);
+        samplingFrequencyIndexMap.put(48000, 3);
+        samplingFrequencyIndexMap.put(44100, 4);
+        samplingFrequencyIndexMap.put(32000, 5);
+        samplingFrequencyIndexMap.put(24000, 6);
+        samplingFrequencyIndexMap.put(22050, 7);
+        samplingFrequencyIndexMap.put(16000, 8);
+        samplingFrequencyIndexMap.put(12000, 9);
+        samplingFrequencyIndexMap.put(11025, 10);
+        samplingFrequencyIndexMap.put(8000, 11);
+        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);
+    }
+
+    TrackMetaData trackMetaData = new TrackMetaData();
+    SampleDescriptionBox sampleDescriptionBox;
+
+    int samplerate;
+    int bitrate;
+    int channelCount;
+    int channelconfig;
+
+    int bufferSizeDB;
+    long maxBitRate;
+    long avgBitRate;
+
+    private BufferedInputStream inputStream;
+    private List<ByteBuffer> samples;
+    boolean readSamples = false;
+    List<TimeToSampleBox.Entry> stts;
+    private String lang = "und";
+
+
+    public AACTrackImpl(InputStream inputStream, String lang) throws IOException {
+        this.lang = lang;
+        parse(inputStream);
+     }
+
+    public AACTrackImpl(InputStream inputStream) throws IOException {
+        parse(inputStream);
+     }
+
+    private void parse(InputStream inputStream) throws IOException {
+        this.inputStream = new BufferedInputStream(inputStream);
+        stts = new LinkedList<TimeToSampleBox.Entry>();
+
+        if (!readVariables()) {
+            throw new IOException();
+        }
+
+        samples = new LinkedList<ByteBuffer>();
+        if (!readSamples()) {
+            throw new IOException();
+        }
+
+        double packetsPerSecond = (double)samplerate / 1024.0;
+        double duration = samples.size() / packetsPerSecond;
+
+        long dataSize = 0;
+        LinkedList<Integer> queue = new LinkedList<Integer>();
+        for (int i = 0; i < samples.size(); i++) {
+            int size = samples.get(i).capacity();
+            dataSize += size;
+            queue.add(size);
+            while (queue.size() > packetsPerSecond) {
+                queue.pop();
+            }
+            if (queue.size() == (int) packetsPerSecond) {
+                int currSize = 0;
+                for (int j = 0 ; j < queue.size(); j++) {
+                    currSize += queue.get(j);
+                }
+                double currBitrate = 8.0 * currSize / queue.size() * packetsPerSecond;
+                if (currBitrate > maxBitRate) {
+                    maxBitRate = (int)currBitrate;
+                }
+            }
+        }
+
+        avgBitRate = (int) (8 * dataSize / duration);
+
+        bufferSizeDB = 1536; /* TODO: Calcultate this somehow! */
+
+        sampleDescriptionBox = new SampleDescriptionBox();
+        AudioSampleEntry audioSampleEntry = new AudioSampleEntry("mp4a");
+        audioSampleEntry.setChannelCount(2);
+        audioSampleEntry.setSampleRate(samplerate);
+        audioSampleEntry.setDataReferenceIndex(1);
+        audioSampleEntry.setSampleSize(16);
+
+
+        ESDescriptorBox esds = new ESDescriptorBox();
+        ESDescriptor descriptor = new ESDescriptor();
+        descriptor.setEsId(0);
+
+        SLConfigDescriptor slConfigDescriptor = new SLConfigDescriptor();
+        slConfigDescriptor.setPredefined(2);
+        descriptor.setSlConfigDescriptor(slConfigDescriptor);
+
+        DecoderConfigDescriptor decoderConfigDescriptor = new DecoderConfigDescriptor();
+        decoderConfigDescriptor.setObjectTypeIndication(0x40);
+        decoderConfigDescriptor.setStreamType(5);
+        decoderConfigDescriptor.setBufferSizeDB(bufferSizeDB);
+        decoderConfigDescriptor.setMaxBitRate(maxBitRate);
+        decoderConfigDescriptor.setAvgBitRate(avgBitRate);
+
+        AudioSpecificConfig audioSpecificConfig = new AudioSpecificConfig();
+        audioSpecificConfig.setAudioObjectType(2); // AAC LC
+        audioSpecificConfig.setSamplingFrequencyIndex(samplingFrequencyIndexMap.get(samplerate));
+        audioSpecificConfig.setChannelConfiguration(channelconfig);
+        decoderConfigDescriptor.setAudioSpecificInfo(audioSpecificConfig);
+
+        descriptor.setDecoderConfigDescriptor(decoderConfigDescriptor);
+
+        ByteBuffer data = descriptor.serialize();
+        esds.setData(data);
+        audioSampleEntry.addBox(esds);
+        sampleDescriptionBox.addBox(audioSampleEntry);
+
+        trackMetaData.setCreationTime(new Date());
+        trackMetaData.setModificationTime(new Date());
+        trackMetaData.setLanguage(lang);
+        trackMetaData.setTimescale(samplerate); // Audio tracks always use samplerate as timescale
+    }
+
+    public SampleDescriptionBox getSampleDescriptionBox() {
+        return sampleDescriptionBox;
+    }
+
+    public List<TimeToSampleBox.Entry> getDecodingTimeEntries() {
+        return stts;
+    }
+
+    public List<CompositionTimeToSample.Entry> getCompositionTimeEntries() {
+        return null;
+    }
+
+    public long[] getSyncSamples() {
+        return null;
+    }
+
+    public List<SampleDependencyTypeBox.Entry> getSampleDependencies() {
+        return null;
+    }
+
+    public TrackMetaData getTrackMetaData() {
+        return trackMetaData;
+    }
+
+    public String getHandler() {
+        return "soun";
+    }
+
+    public List<ByteBuffer> getSamples() {
+        return samples;
+    }
+
+    public Box getMediaHeaderBox() {
+        return new SoundMediaHeaderBox();
+    }
+
+    public SubSampleInformationBox getSubsampleInformationBox() {
+        return null;
+    }
+
+    private boolean readVariables() throws IOException {
+        byte[] data = new byte[100];
+        inputStream.mark(100);
+        if (100 != inputStream.read(data, 0, 100)) {
+            return false;
+        }
+        inputStream.reset(); // Rewind
+        ByteBuffer bb = ByteBuffer.wrap(data);
+        BitReaderBuffer brb = new BitReaderBuffer(bb);
+        int syncword = brb.readBits(12);
+        if (syncword != 0xfff) {
+            return false;
+        }
+        int id = brb.readBits(1);
+        int layer = brb.readBits(2);
+        int protectionAbsent = brb.readBits(1);
+        int profile = brb.readBits(2);
+        samplerate = samplingFrequencyIndexMap.get(brb.readBits(4));
+        brb.readBits(1);
+        channelconfig = brb.readBits(3);
+        int original = brb.readBits(1);
+        int home = brb.readBits(1);
+        int emphasis = brb.readBits(2);
+
+        return true;
+    }
+
+    private boolean readSamples() throws IOException {
+        if (readSamples) {
+            return true;
+        }
+
+        readSamples = true;
+        byte[] header = new byte[15];
+        boolean ret = false;
+        inputStream.mark(15);
+        while (-1 != inputStream.read(header)) {
+            ret = true;
+            ByteBuffer bb = ByteBuffer.wrap(header);
+            inputStream.reset();
+            BitReaderBuffer brb = new BitReaderBuffer(bb);
+            int syncword = brb.readBits(12);
+            if (syncword != 0xfff) {
+                return false;
+            }
+            brb.readBits(3);
+            int protectionAbsent = brb.readBits(1);
+            brb.readBits(14);
+            int frameSize = brb.readBits(13);
+            int bufferFullness = brb.readBits(11);
+            int noBlocks = brb.readBits(2);
+            int used = (int) Math.ceil(brb.getPosition() / 8.0);
+            if (protectionAbsent == 0) {
+                used += 2;
+            }
+            inputStream.skip(used);
+            frameSize -= used;
+//            System.out.println("Size: " + frameSize + " fullness: " + bufferFullness + " no blocks: " + noBlocks);
+            byte[] data = new byte[frameSize];
+            inputStream.read(data);
+            samples.add(ByteBuffer.wrap(data));
+            stts.add(new TimeToSampleBox.Entry(1, 1024));
+            inputStream.mark(15);
+        }
+        return ret;
+    }
+
+    @Override
+    public String toString() {
+        return "AACTrackImpl{" +
+                "samplerate=" + samplerate +
+                ", bitrate=" + bitrate +
+                ", channelCount=" + channelCount +
+                ", channelconfig=" + channelconfig +
+                '}';
+    }
+}
+
diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/authoring/tracks/AC3TrackImpl.java b/isoparser/src/main/java/com/googlecode/mp4parser/authoring/tracks/AC3TrackImpl.java
new file mode 100644
index 0000000..5e5b2cd
--- /dev/null
+++ b/isoparser/src/main/java/com/googlecode/mp4parser/authoring/tracks/AC3TrackImpl.java
@@ -0,0 +1,513 @@
+package com.googlecode.mp4parser.authoring.tracks;
+
+import com.coremedia.iso.boxes.*;
+import com.coremedia.iso.boxes.sampleentry.AudioSampleEntry;
+import com.googlecode.mp4parser.authoring.AbstractTrack;
+import com.googlecode.mp4parser.authoring.TrackMetaData;
+import com.googlecode.mp4parser.boxes.AC3SpecificBox;
+import com.googlecode.mp4parser.boxes.mp4.objectdescriptors.BitReaderBuffer;
+
+import java.io.InputStream;
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.util.Date;
+import java.util.LinkedList;
+import java.util.List;
+
+public class AC3TrackImpl extends AbstractTrack {
+    TrackMetaData trackMetaData = new TrackMetaData();
+    SampleDescriptionBox sampleDescriptionBox;
+
+    int samplerate;
+    int bitrate;
+    int channelCount;
+
+    int fscod;
+    int bsid;
+    int bsmod;
+    int acmod;
+    int lfeon;
+    int frmsizecod;
+
+    int frameSize;
+    int[][][][] bitRateAndFrameSizeTable;
+
+    private InputStream inputStream;
+    private List<ByteBuffer> samples;
+    boolean readSamples = false;
+    List<TimeToSampleBox.Entry> stts;
+    private String lang = "und";
+
+    public AC3TrackImpl(InputStream fin, String lang) throws IOException {
+        this.lang = lang;
+        parse(fin);
+    }
+
+    public AC3TrackImpl(InputStream fin) throws IOException {
+        parse(fin);
+    }
+
+    private void parse(InputStream fin) throws IOException {
+        inputStream = fin;
+        bitRateAndFrameSizeTable = new int[19][2][3][2];
+        stts = new LinkedList<TimeToSampleBox.Entry>();
+        initBitRateAndFrameSizeTable();
+        if (!readVariables()) {
+            throw new IOException();
+        }
+
+        sampleDescriptionBox = new SampleDescriptionBox();
+        AudioSampleEntry audioSampleEntry = new AudioSampleEntry("ac-3");
+        audioSampleEntry.setChannelCount(2);  // According to  ETSI TS 102 366 Annex F
+        audioSampleEntry.setSampleRate(samplerate);
+        audioSampleEntry.setDataReferenceIndex(1);
+        audioSampleEntry.setSampleSize(16);
+
+        AC3SpecificBox ac3 = new AC3SpecificBox();
+        ac3.setAcmod(acmod);
+        ac3.setBitRateCode(frmsizecod >> 1);
+        ac3.setBsid(bsid);
+        ac3.setBsmod(bsmod);
+        ac3.setFscod(fscod);
+        ac3.setLfeon(lfeon);
+        ac3.setReserved(0);
+
+        audioSampleEntry.addBox(ac3);
+        sampleDescriptionBox.addBox(audioSampleEntry);
+
+        trackMetaData.setCreationTime(new Date());
+        trackMetaData.setModificationTime(new Date());
+        trackMetaData.setLanguage(lang);
+        trackMetaData.setTimescale(samplerate); // Audio tracks always use samplerate as timescale
+
+        samples = new LinkedList<ByteBuffer>();
+        if (!readSamples()) {
+            throw new IOException();
+        }
+    }
+
+
+    public List<ByteBuffer> getSamples() {
+
+        return samples;
+    }
+
+    public SampleDescriptionBox getSampleDescriptionBox() {
+        return sampleDescriptionBox;
+    }
+
+    public List<TimeToSampleBox.Entry> getDecodingTimeEntries() {
+        return stts;
+    }
+
+    public List<CompositionTimeToSample.Entry> getCompositionTimeEntries() {
+        return null;
+    }
+
+    public long[] getSyncSamples() {
+        return null;
+    }
+
+    public List<SampleDependencyTypeBox.Entry> getSampleDependencies() {
+        return null;
+    }
+
+    public TrackMetaData getTrackMetaData() {
+        return trackMetaData;
+    }
+
+    public String getHandler() {
+        return "soun";
+    }
+
+    public Box getMediaHeaderBox() {
+        return new SoundMediaHeaderBox();
+    }
+
+    public SubSampleInformationBox getSubsampleInformationBox() {
+        return null;
+    }
+
+    private boolean readVariables() throws IOException {
+        byte[] data = new byte[100];
+        inputStream.mark(100);
+        if (100 != inputStream.read(data, 0, 100)) {
+            return false;
+        }
+        inputStream.reset(); // Rewind
+        ByteBuffer bb = ByteBuffer.wrap(data);
+        BitReaderBuffer brb = new BitReaderBuffer(bb);
+        int syncword = brb.readBits(16);
+        if (syncword != 0xb77) {
+            return false;
+        }
+        brb.readBits(16); // CRC-1
+        fscod = brb.readBits(2);
+
+        switch (fscod) {
+            case 0:
+                samplerate = 48000;
+                break;
+
+            case 1:
+                samplerate = 44100;
+                break;
+
+            case 2:
+                samplerate = 32000;
+                break;
+
+            case 3:
+                samplerate = 0;
+                break;
+
+        }
+        if (samplerate == 0) {
+            return false;
+        }
+
+        frmsizecod = brb.readBits(6);
+
+        if (!calcBitrateAndFrameSize(frmsizecod)) {
+            return false;
+        }
+
+        if (frameSize == 0) {
+            return false;
+        }
+        bsid = brb.readBits(5);
+        bsmod = brb.readBits(3);
+        acmod = brb.readBits(3);
+
+        if (bsid == 9) {
+            samplerate /= 2;
+        } else if (bsid != 8 && bsid != 6) {
+            return false;
+        }
+
+        if ((acmod != 1) && ((acmod & 1) == 1)) {
+            brb.readBits(2);
+        }
+
+        if (0 != (acmod & 4)) {
+            brb.readBits(2);
+        }
+
+        if (acmod == 2) {
+            brb.readBits(2);
+        }
+
+        switch (acmod) {
+            case 0:
+                channelCount = 2;
+                break;
+
+            case 1:
+                channelCount = 1;
+                break;
+
+            case 2:
+                channelCount = 2;
+                break;
+
+            case 3:
+                channelCount = 3;
+                break;
+
+            case 4:
+                channelCount = 3;
+                break;
+
+            case 5:
+                channelCount = 4;
+                break;
+
+            case 6:
+                channelCount = 4;
+                break;
+
+            case 7:
+                channelCount = 5;
+                break;
+
+        }
+
+        lfeon = brb.readBits(1);
+
+        if (lfeon == 1) {
+            channelCount++;
+        }
+        return true;
+    }
+
+    private boolean calcBitrateAndFrameSize(int code) {
+        int frmsizecode = code >>> 1;
+        int flag = code & 1;
+        if (frmsizecode > 18 || flag > 1 || fscod > 2) {
+            return false;
+        }
+        bitrate = bitRateAndFrameSizeTable[frmsizecode][flag][fscod][0];
+        frameSize = 2 * bitRateAndFrameSizeTable[frmsizecode][flag][fscod][1];
+        return true;
+    }
+
+    private boolean readSamples() throws IOException {
+        if (readSamples) {
+            return true;
+        }
+        readSamples = true;
+        byte[] header = new byte[5];
+        boolean ret = false;
+        inputStream.mark(5);
+        while (-1 != inputStream.read(header)) {
+            ret = true;
+            int frmsizecode = header[4] & 63;
+            calcBitrateAndFrameSize(frmsizecode);
+            inputStream.reset();
+            byte[] data = new byte[frameSize];
+            inputStream.read(data);
+            samples.add(ByteBuffer.wrap(data));
+            stts.add(new TimeToSampleBox.Entry(1, 1536));
+            inputStream.mark(5);
+        }
+        return ret;
+    }
+
+    private void initBitRateAndFrameSizeTable() {
+        // ETSI 102 366 Table 4.13, in frmsizecod, flag, fscod, bitrate/size order. Note that all sizes are in words, and all bitrates in kbps
+
+        // 48kHz
+        bitRateAndFrameSizeTable[0][0][0][0] = 32;
+        bitRateAndFrameSizeTable[0][1][0][0] = 32;
+        bitRateAndFrameSizeTable[0][0][0][1] = 64;
+        bitRateAndFrameSizeTable[0][1][0][1] = 64;
+        bitRateAndFrameSizeTable[1][0][0][0] = 40;
+        bitRateAndFrameSizeTable[1][1][0][0] = 40;
+        bitRateAndFrameSizeTable[1][0][0][1] = 80;
+        bitRateAndFrameSizeTable[1][1][0][1] = 80;
+        bitRateAndFrameSizeTable[2][0][0][0] = 48;
+        bitRateAndFrameSizeTable[2][1][0][0] = 48;
+        bitRateAndFrameSizeTable[2][0][0][1] = 96;
+        bitRateAndFrameSizeTable[2][1][0][1] = 96;
+        bitRateAndFrameSizeTable[3][0][0][0] = 56;
+        bitRateAndFrameSizeTable[3][1][0][0] = 56;
+        bitRateAndFrameSizeTable[3][0][0][1] = 112;
+        bitRateAndFrameSizeTable[3][1][0][1] = 112;
+        bitRateAndFrameSizeTable[4][0][0][0] = 64;
+        bitRateAndFrameSizeTable[4][1][0][0] = 64;
+        bitRateAndFrameSizeTable[4][0][0][1] = 128;
+        bitRateAndFrameSizeTable[4][1][0][1] = 128;
+        bitRateAndFrameSizeTable[5][0][0][0] = 80;
+        bitRateAndFrameSizeTable[5][1][0][0] = 80;
+        bitRateAndFrameSizeTable[5][0][0][1] = 160;
+        bitRateAndFrameSizeTable[5][1][0][1] = 160;
+        bitRateAndFrameSizeTable[6][0][0][0] = 96;
+        bitRateAndFrameSizeTable[6][1][0][0] = 96;
+        bitRateAndFrameSizeTable[6][0][0][1] = 192;
+        bitRateAndFrameSizeTable[6][1][0][1] = 192;
+        bitRateAndFrameSizeTable[7][0][0][0] = 112;
+        bitRateAndFrameSizeTable[7][1][0][0] = 112;
+        bitRateAndFrameSizeTable[7][0][0][1] = 224;
+        bitRateAndFrameSizeTable[7][1][0][1] = 224;
+        bitRateAndFrameSizeTable[8][0][0][0] = 128;
+        bitRateAndFrameSizeTable[8][1][0][0] = 128;
+        bitRateAndFrameSizeTable[8][0][0][1] = 256;
+        bitRateAndFrameSizeTable[8][1][0][1] = 256;
+        bitRateAndFrameSizeTable[9][0][0][0] = 160;
+        bitRateAndFrameSizeTable[9][1][0][0] = 160;
+        bitRateAndFrameSizeTable[9][0][0][1] = 320;
+        bitRateAndFrameSizeTable[9][1][0][1] = 320;
+        bitRateAndFrameSizeTable[10][0][0][0] = 192;
+        bitRateAndFrameSizeTable[10][1][0][0] = 192;
+        bitRateAndFrameSizeTable[10][0][0][1] = 384;
+        bitRateAndFrameSizeTable[10][1][0][1] = 384;
+        bitRateAndFrameSizeTable[11][0][0][0] = 224;
+        bitRateAndFrameSizeTable[11][1][0][0] = 224;
+        bitRateAndFrameSizeTable[11][0][0][1] = 448;
+        bitRateAndFrameSizeTable[11][1][0][1] = 448;
+        bitRateAndFrameSizeTable[12][0][0][0] = 256;
+        bitRateAndFrameSizeTable[12][1][0][0] = 256;
+        bitRateAndFrameSizeTable[12][0][0][1] = 512;
+        bitRateAndFrameSizeTable[12][1][0][1] = 512;
+        bitRateAndFrameSizeTable[13][0][0][0] = 320;
+        bitRateAndFrameSizeTable[13][1][0][0] = 320;
+        bitRateAndFrameSizeTable[13][0][0][1] = 640;
+        bitRateAndFrameSizeTable[13][1][0][1] = 640;
+        bitRateAndFrameSizeTable[14][0][0][0] = 384;
+        bitRateAndFrameSizeTable[14][1][0][0] = 384;
+        bitRateAndFrameSizeTable[14][0][0][1] = 768;
+        bitRateAndFrameSizeTable[14][1][0][1] = 768;
+        bitRateAndFrameSizeTable[15][0][0][0] = 448;
+        bitRateAndFrameSizeTable[15][1][0][0] = 448;
+        bitRateAndFrameSizeTable[15][0][0][1] = 896;
+        bitRateAndFrameSizeTable[15][1][0][1] = 896;
+        bitRateAndFrameSizeTable[16][0][0][0] = 512;
+        bitRateAndFrameSizeTable[16][1][0][0] = 512;
+        bitRateAndFrameSizeTable[16][0][0][1] = 1024;
+        bitRateAndFrameSizeTable[16][1][0][1] = 1024;
+        bitRateAndFrameSizeTable[17][0][0][0] = 576;
+        bitRateAndFrameSizeTable[17][1][0][0] = 576;
+        bitRateAndFrameSizeTable[17][0][0][1] = 1152;
+        bitRateAndFrameSizeTable[17][1][0][1] = 1152;
+        bitRateAndFrameSizeTable[18][0][0][0] = 640;
+        bitRateAndFrameSizeTable[18][1][0][0] = 640;
+        bitRateAndFrameSizeTable[18][0][0][1] = 1280;
+        bitRateAndFrameSizeTable[18][1][0][1] = 1280;
+
+        // 44.1 kHz
+        bitRateAndFrameSizeTable[0][0][1][0] = 32;
+        bitRateAndFrameSizeTable[0][1][1][0] = 32;
+        bitRateAndFrameSizeTable[0][0][1][1] = 69;
+        bitRateAndFrameSizeTable[0][1][1][1] = 70;
+        bitRateAndFrameSizeTable[1][0][1][0] = 40;
+        bitRateAndFrameSizeTable[1][1][1][0] = 40;
+        bitRateAndFrameSizeTable[1][0][1][1] = 87;
+        bitRateAndFrameSizeTable[1][1][1][1] = 88;
+        bitRateAndFrameSizeTable[2][0][1][0] = 48;
+        bitRateAndFrameSizeTable[2][1][1][0] = 48;
+        bitRateAndFrameSizeTable[2][0][1][1] = 104;
+        bitRateAndFrameSizeTable[2][1][1][1] = 105;
+        bitRateAndFrameSizeTable[3][0][1][0] = 56;
+        bitRateAndFrameSizeTable[3][1][1][0] = 56;
+        bitRateAndFrameSizeTable[3][0][1][1] = 121;
+        bitRateAndFrameSizeTable[3][1][1][1] = 122;
+        bitRateAndFrameSizeTable[4][0][1][0] = 64;
+        bitRateAndFrameSizeTable[4][1][1][0] = 64;
+        bitRateAndFrameSizeTable[4][0][1][1] = 139;
+        bitRateAndFrameSizeTable[4][1][1][1] = 140;
+        bitRateAndFrameSizeTable[5][0][1][0] = 80;
+        bitRateAndFrameSizeTable[5][1][1][0] = 80;
+        bitRateAndFrameSizeTable[5][0][1][1] = 174;
+        bitRateAndFrameSizeTable[5][1][1][1] = 175;
+        bitRateAndFrameSizeTable[6][0][1][0] = 96;
+        bitRateAndFrameSizeTable[6][1][1][0] = 96;
+        bitRateAndFrameSizeTable[6][0][1][1] = 208;
+        bitRateAndFrameSizeTable[6][1][1][1] = 209;
+        bitRateAndFrameSizeTable[7][0][1][0] = 112;
+        bitRateAndFrameSizeTable[7][1][1][0] = 112;
+        bitRateAndFrameSizeTable[7][0][1][1] = 243;
+        bitRateAndFrameSizeTable[7][1][1][1] = 244;
+        bitRateAndFrameSizeTable[8][0][1][0] = 128;
+        bitRateAndFrameSizeTable[8][1][1][0] = 128;
+        bitRateAndFrameSizeTable[8][0][1][1] = 278;
+        bitRateAndFrameSizeTable[8][1][1][1] = 279;
+        bitRateAndFrameSizeTable[9][0][1][0] = 160;
+        bitRateAndFrameSizeTable[9][1][1][0] = 160;
+        bitRateAndFrameSizeTable[9][0][1][1] = 348;
+        bitRateAndFrameSizeTable[9][1][1][1] = 349;
+        bitRateAndFrameSizeTable[10][0][1][0] = 192;
+        bitRateAndFrameSizeTable[10][1][1][0] = 192;
+        bitRateAndFrameSizeTable[10][0][1][1] = 417;
+        bitRateAndFrameSizeTable[10][1][1][1] = 418;
+        bitRateAndFrameSizeTable[11][0][1][0] = 224;
+        bitRateAndFrameSizeTable[11][1][1][0] = 224;
+        bitRateAndFrameSizeTable[11][0][1][1] = 487;
+        bitRateAndFrameSizeTable[11][1][1][1] = 488;
+        bitRateAndFrameSizeTable[12][0][1][0] = 256;
+        bitRateAndFrameSizeTable[12][1][1][0] = 256;
+        bitRateAndFrameSizeTable[12][0][1][1] = 557;
+        bitRateAndFrameSizeTable[12][1][1][1] = 558;
+        bitRateAndFrameSizeTable[13][0][1][0] = 320;
+        bitRateAndFrameSizeTable[13][1][1][0] = 320;
+        bitRateAndFrameSizeTable[13][0][1][1] = 696;
+        bitRateAndFrameSizeTable[13][1][1][1] = 697;
+        bitRateAndFrameSizeTable[14][0][1][0] = 384;
+        bitRateAndFrameSizeTable[14][1][1][0] = 384;
+        bitRateAndFrameSizeTable[14][0][1][1] = 835;
+        bitRateAndFrameSizeTable[14][1][1][1] = 836;
+        bitRateAndFrameSizeTable[15][0][1][0] = 448;
+        bitRateAndFrameSizeTable[15][1][1][0] = 448;
+        bitRateAndFrameSizeTable[15][0][1][1] = 975;
+        bitRateAndFrameSizeTable[15][1][1][1] = 975;
+        bitRateAndFrameSizeTable[16][0][1][0] = 512;
+        bitRateAndFrameSizeTable[16][1][1][0] = 512;
+        bitRateAndFrameSizeTable[16][0][1][1] = 1114;
+        bitRateAndFrameSizeTable[16][1][1][1] = 1115;
+        bitRateAndFrameSizeTable[17][0][1][0] = 576;
+        bitRateAndFrameSizeTable[17][1][1][0] = 576;
+        bitRateAndFrameSizeTable[17][0][1][1] = 1253;
+        bitRateAndFrameSizeTable[17][1][1][1] = 1254;
+        bitRateAndFrameSizeTable[18][0][1][0] = 640;
+        bitRateAndFrameSizeTable[18][1][1][0] = 640;
+        bitRateAndFrameSizeTable[18][0][1][1] = 1393;
+        bitRateAndFrameSizeTable[18][1][1][1] = 1394;
+
+        // 32kHz
+        bitRateAndFrameSizeTable[0][0][2][0] = 32;
+        bitRateAndFrameSizeTable[0][1][2][0] = 32;
+        bitRateAndFrameSizeTable[0][0][2][1] = 96;
+        bitRateAndFrameSizeTable[0][1][2][1] = 96;
+        bitRateAndFrameSizeTable[1][0][2][0] = 40;
+        bitRateAndFrameSizeTable[1][1][2][0] = 40;
+        bitRateAndFrameSizeTable[1][0][2][1] = 120;
+        bitRateAndFrameSizeTable[1][1][2][1] = 120;
+        bitRateAndFrameSizeTable[2][0][2][0] = 48;
+        bitRateAndFrameSizeTable[2][1][2][0] = 48;
+        bitRateAndFrameSizeTable[2][0][2][1] = 144;
+        bitRateAndFrameSizeTable[2][1][2][1] = 144;
+        bitRateAndFrameSizeTable[3][0][2][0] = 56;
+        bitRateAndFrameSizeTable[3][1][2][0] = 56;
+        bitRateAndFrameSizeTable[3][0][2][1] = 168;
+        bitRateAndFrameSizeTable[3][1][2][1] = 168;
+        bitRateAndFrameSizeTable[4][0][2][0] = 64;
+        bitRateAndFrameSizeTable[4][1][2][0] = 64;
+        bitRateAndFrameSizeTable[4][0][2][1] = 192;
+        bitRateAndFrameSizeTable[4][1][2][1] = 192;
+        bitRateAndFrameSizeTable[5][0][2][0] = 80;
+        bitRateAndFrameSizeTable[5][1][2][0] = 80;
+        bitRateAndFrameSizeTable[5][0][2][1] = 240;
+        bitRateAndFrameSizeTable[5][1][2][1] = 240;
+        bitRateAndFrameSizeTable[6][0][2][0] = 96;
+        bitRateAndFrameSizeTable[6][1][2][0] = 96;
+        bitRateAndFrameSizeTable[6][0][2][1] = 288;
+        bitRateAndFrameSizeTable[6][1][2][1] = 288;
+        bitRateAndFrameSizeTable[7][0][2][0] = 112;
+        bitRateAndFrameSizeTable[7][1][2][0] = 112;
+        bitRateAndFrameSizeTable[7][0][2][1] = 336;
+        bitRateAndFrameSizeTable[7][1][2][1] = 336;
+        bitRateAndFrameSizeTable[8][0][2][0] = 128;
+        bitRateAndFrameSizeTable[8][1][2][0] = 128;
+        bitRateAndFrameSizeTable[8][0][2][1] = 384;
+        bitRateAndFrameSizeTable[8][1][2][1] = 384;
+        bitRateAndFrameSizeTable[9][0][2][0] = 160;
+        bitRateAndFrameSizeTable[9][1][2][0] = 160;
+        bitRateAndFrameSizeTable[9][0][2][1] = 480;
+        bitRateAndFrameSizeTable[9][1][2][1] = 480;
+        bitRateAndFrameSizeTable[10][0][2][0] = 192;
+        bitRateAndFrameSizeTable[10][1][2][0] = 192;
+        bitRateAndFrameSizeTable[10][0][2][1] = 576;
+        bitRateAndFrameSizeTable[10][1][2][1] = 576;
+        bitRateAndFrameSizeTable[11][0][2][0] = 224;
+        bitRateAndFrameSizeTable[11][1][2][0] = 224;
+        bitRateAndFrameSizeTable[11][0][2][1] = 672;
+        bitRateAndFrameSizeTable[11][1][2][1] = 672;
+        bitRateAndFrameSizeTable[12][0][2][0] = 256;
+        bitRateAndFrameSizeTable[12][1][2][0] = 256;
+        bitRateAndFrameSizeTable[12][0][2][1] = 768;
+        bitRateAndFrameSizeTable[12][1][2][1] = 768;
+        bitRateAndFrameSizeTable[13][0][2][0] = 320;
+        bitRateAndFrameSizeTable[13][1][2][0] = 320;
+        bitRateAndFrameSizeTable[13][0][2][1] = 960;
+        bitRateAndFrameSizeTable[13][1][2][1] = 960;
+        bitRateAndFrameSizeTable[14][0][2][0] = 384;
+        bitRateAndFrameSizeTable[14][1][2][0] = 384;
+        bitRateAndFrameSizeTable[14][0][2][1] = 1152;
+        bitRateAndFrameSizeTable[14][1][2][1] = 1152;
+        bitRateAndFrameSizeTable[15][0][2][0] = 448;
+        bitRateAndFrameSizeTable[15][1][2][0] = 448;
+        bitRateAndFrameSizeTable[15][0][2][1] = 1344;
+        bitRateAndFrameSizeTable[15][1][2][1] = 1344;
+        bitRateAndFrameSizeTable[16][0][2][0] = 512;
+        bitRateAndFrameSizeTable[16][1][2][0] = 512;
+        bitRateAndFrameSizeTable[16][0][2][1] = 1536;
+        bitRateAndFrameSizeTable[16][1][2][1] = 1536;
+        bitRateAndFrameSizeTable[17][0][2][0] = 576;
+        bitRateAndFrameSizeTable[17][1][2][0] = 576;
+        bitRateAndFrameSizeTable[17][0][2][1] = 1728;
+        bitRateAndFrameSizeTable[17][1][2][1] = 1728;
+        bitRateAndFrameSizeTable[18][0][2][0] = 640;
+        bitRateAndFrameSizeTable[18][1][2][0] = 640;
+        bitRateAndFrameSizeTable[18][0][2][1] = 1920;
+        bitRateAndFrameSizeTable[18][1][2][1] = 1920;
+    }
+}
\ No newline at end of file
diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/authoring/tracks/Amf0Track.java b/isoparser/src/main/java/com/googlecode/mp4parser/authoring/tracks/Amf0Track.java
new file mode 100644
index 0000000..0917767
--- /dev/null
+++ b/isoparser/src/main/java/com/googlecode/mp4parser/authoring/tracks/Amf0Track.java
@@ -0,0 +1,116 @@
+/*
+ * Copyright 2012 Sebastian Annies, Hamburg
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.googlecode.mp4parser.authoring.tracks;
+
+import com.coremedia.iso.boxes.*;
+import com.googlecode.mp4parser.authoring.AbstractTrack;
+import com.googlecode.mp4parser.authoring.TrackMetaData;
+import com.googlecode.mp4parser.boxes.adobe.ActionMessageFormat0SampleEntryBox;
+
+import java.nio.ByteBuffer;
+import java.util.Collections;
+import java.util.Date;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.SortedMap;
+import java.util.TreeMap;
+
+public class Amf0Track extends AbstractTrack {
+    SortedMap<Long, byte[]> rawSamples = new TreeMap<Long, byte[]>() {
+    };
+    private TrackMetaData trackMetaData = new TrackMetaData();
+
+
+    /**
+     * Creates a new AMF0 track from
+     *
+     * @param rawSamples
+     */
+    public Amf0Track(Map<Long, byte[]> rawSamples) {
+        this.rawSamples = new TreeMap<Long, byte[]>(rawSamples);
+        trackMetaData.setCreationTime(new Date());
+        trackMetaData.setModificationTime(new Date());
+        trackMetaData.setTimescale(1000); // Text tracks use millieseconds
+        trackMetaData.setLanguage("eng");
+    }
+
+    public List<ByteBuffer> getSamples() {
+        LinkedList<ByteBuffer> samples = new LinkedList<ByteBuffer>();
+        for (byte[] bytes : rawSamples.values()) {
+            samples.add(ByteBuffer.wrap(bytes));
+        }
+        return samples;
+    }
+
+    public SampleDescriptionBox getSampleDescriptionBox() {
+        SampleDescriptionBox stsd = new SampleDescriptionBox();
+        ActionMessageFormat0SampleEntryBox amf0 = new ActionMessageFormat0SampleEntryBox();
+        amf0.setDataReferenceIndex(1);
+        stsd.addBox(amf0);
+        return stsd;
+    }
+
+    public List<TimeToSampleBox.Entry> getDecodingTimeEntries() {
+        LinkedList<TimeToSampleBox.Entry> timesToSample = new LinkedList<TimeToSampleBox.Entry>();
+        LinkedList<Long> keys = new LinkedList<Long>(rawSamples.keySet());
+        Collections.sort(keys);
+        long lastTimeStamp = 0;
+        for (Long key : keys) {
+            long delta = key - lastTimeStamp;
+            if (timesToSample.size() > 0 && timesToSample.peek().getDelta() == delta) {
+                timesToSample.peek().setCount(timesToSample.peek().getCount() + 1);
+            } else {
+                timesToSample.add(new TimeToSampleBox.Entry(1, delta));
+            }
+            lastTimeStamp = key;
+        }
+        return timesToSample;
+    }
+
+    public List<CompositionTimeToSample.Entry> getCompositionTimeEntries() {
+        // AMF0 tracks do not have Composition Time
+        return null;
+    }
+
+    public long[] getSyncSamples() {
+        // AMF0 tracks do not have Sync Samples
+        return null;
+    }
+
+    public List<SampleDependencyTypeBox.Entry> getSampleDependencies() {
+        // AMF0 tracks do not have Sample Dependencies
+        return null;
+    }
+
+    public TrackMetaData getTrackMetaData() {
+        return trackMetaData;  //To change body of implemented methods use File | Settings | File Templates.
+    }
+
+    public String getHandler() {
+        return "data";
+    }
+
+    public Box getMediaHeaderBox() {
+        return new NullMediaHeaderBox();
+    }
+
+    public SubSampleInformationBox getSubsampleInformationBox() {
+        return null;
+    }
+
+}
diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/authoring/tracks/AppendTrack.java b/isoparser/src/main/java/com/googlecode/mp4parser/authoring/tracks/AppendTrack.java
new file mode 100644
index 0000000..93ee0cd
--- /dev/null
+++ b/isoparser/src/main/java/com/googlecode/mp4parser/authoring/tracks/AppendTrack.java
@@ -0,0 +1,348 @@
+/*
+ * Copyright 2012 Sebastian Annies, Hamburg
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.googlecode.mp4parser.authoring.tracks;
+
+import com.coremedia.iso.boxes.*;
+import com.coremedia.iso.boxes.sampleentry.AudioSampleEntry;
+import com.googlecode.mp4parser.authoring.AbstractTrack;
+import com.googlecode.mp4parser.authoring.Track;
+import com.googlecode.mp4parser.authoring.TrackMetaData;
+import com.googlecode.mp4parser.boxes.mp4.ESDescriptorBox;
+import com.googlecode.mp4parser.boxes.mp4.objectdescriptors.DecoderConfigDescriptor;
+import com.googlecode.mp4parser.boxes.mp4.objectdescriptors.ESDescriptor;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.nio.channels.Channels;
+import java.util.*;
+
+/**
+ * Appends two or more <code>Tracks</code> of the same type. No only that the type must be equal
+ * also the decoder settings must be the same.
+ */
+public class AppendTrack extends AbstractTrack {
+    Track[] tracks;
+    SampleDescriptionBox stsd;
+
+    public AppendTrack(Track... tracks) throws IOException {
+        this.tracks = tracks;
+
+        for (Track track : tracks) {
+
+            if (stsd == null) {
+                stsd = track.getSampleDescriptionBox();
+            } else {
+                ByteArrayOutputStream curBaos = new ByteArrayOutputStream();
+                ByteArrayOutputStream refBaos = new ByteArrayOutputStream();
+                track.getSampleDescriptionBox().getBox(Channels.newChannel(curBaos));
+                stsd.getBox(Channels.newChannel(refBaos));
+                byte[] cur = curBaos.toByteArray();
+                byte[] ref = refBaos.toByteArray();
+
+                if (!Arrays.equals(ref, cur)) {
+                    SampleDescriptionBox curStsd = track.getSampleDescriptionBox();
+                    if (stsd.getBoxes().size() == 1 && curStsd.getBoxes().size() == 1) {
+                        if (stsd.getBoxes().get(0) instanceof AudioSampleEntry && curStsd.getBoxes().get(0) instanceof AudioSampleEntry) {
+                            AudioSampleEntry aseResult = mergeAudioSampleEntries((AudioSampleEntry) stsd.getBoxes().get(0), (AudioSampleEntry) curStsd.getBoxes().get(0));
+                            if (aseResult != null) {
+                                stsd.setBoxes(Collections.<Box>singletonList(aseResult));
+                                return;
+                            }
+                        }
+                    }
+                    throw new IOException("Cannot append " + track + " to " + tracks[0] + " since their Sample Description Boxes differ: \n" + track.getSampleDescriptionBox() + "\n vs. \n" + tracks[0].getSampleDescriptionBox());
+                }
+            }
+        }
+    }
+
+    private AudioSampleEntry mergeAudioSampleEntries(AudioSampleEntry ase1, AudioSampleEntry ase2) throws IOException {
+        if (ase1.getType().equals(ase2.getType())) {
+            AudioSampleEntry ase = new AudioSampleEntry(ase2.getType());
+            if (ase1.getBytesPerFrame() == ase2.getBytesPerFrame()) {
+                ase.setBytesPerFrame(ase1.getBytesPerFrame());
+            } else {
+                return null;
+            }
+            if (ase1.getBytesPerPacket() == ase2.getBytesPerPacket()) {
+                ase.setBytesPerPacket(ase1.getBytesPerPacket());
+            } else {
+                return null;
+            }
+            if (ase1.getBytesPerSample() == ase2.getBytesPerSample()) {
+                ase.setBytesPerSample(ase1.getBytesPerSample());
+            } else {
+                return null;
+            }
+            if (ase1.getChannelCount() == ase2.getChannelCount()) {
+                ase.setChannelCount(ase1.getChannelCount());
+            } else {
+                return null;
+            }
+            if (ase1.getPacketSize() == ase2.getPacketSize()) {
+                ase.setPacketSize(ase1.getPacketSize());
+            } else {
+                return null;
+            }
+            if (ase1.getCompressionId() == ase2.getCompressionId()) {
+                ase.setCompressionId(ase1.getCompressionId());
+            } else {
+                return null;
+            }
+            if (ase1.getSampleRate() == ase2.getSampleRate()) {
+                ase.setSampleRate(ase1.getSampleRate());
+            } else {
+                return null;
+            }
+            if (ase1.getSampleSize() == ase2.getSampleSize()) {
+                ase.setSampleSize(ase1.getSampleSize());
+            } else {
+                return null;
+            }
+            if (ase1.getSamplesPerPacket() == ase2.getSamplesPerPacket()) {
+                ase.setSamplesPerPacket(ase1.getSamplesPerPacket());
+            } else {
+                return null;
+            }
+            if (ase1.getSoundVersion() == ase2.getSoundVersion()) {
+                ase.setSoundVersion(ase1.getSoundVersion());
+            } else {
+                return null;
+            }
+            if (Arrays.equals(ase1.getSoundVersion2Data(), ase2.getSoundVersion2Data())) {
+                ase.setSoundVersion2Data(ase1.getSoundVersion2Data());
+            } else {
+                return null;
+            }
+            if (ase1.getBoxes().size() == ase2.getBoxes().size()) {
+                Iterator<Box> bxs1 = ase1.getBoxes().iterator();
+                Iterator<Box> bxs2 = ase2.getBoxes().iterator();
+                while (bxs1.hasNext()) {
+                    Box cur1 = bxs1.next();
+                    Box cur2 = bxs2.next();
+                    ByteArrayOutputStream baos1 = new ByteArrayOutputStream();
+                    ByteArrayOutputStream baos2 = new ByteArrayOutputStream();
+                    cur1.getBox(Channels.newChannel(baos1));
+                    cur2.getBox(Channels.newChannel(baos2));
+                    if (Arrays.equals(baos1.toByteArray(), baos2.toByteArray())) {
+                        ase.addBox(cur1);
+                    } else {
+                        if (ESDescriptorBox.TYPE.equals(cur1.getType()) && ESDescriptorBox.TYPE.equals(cur2.getType())) {
+                            ESDescriptorBox esdsBox1 = (ESDescriptorBox) cur1;
+                            ESDescriptorBox esdsBox2 = (ESDescriptorBox) cur2;
+                            ESDescriptor esds1 = esdsBox1.getEsDescriptor();
+                            ESDescriptor esds2 = esdsBox2.getEsDescriptor();
+                            if (esds1.getURLFlag() != esds2.getURLFlag()) {
+                                return null;
+                            }
+                            if (esds1.getURLLength() != esds2.getURLLength()) {
+                                return null;
+                            }
+                            if (esds1.getDependsOnEsId() != esds2.getDependsOnEsId()) {
+                                return null;
+                            }
+                            if (esds1.getEsId() != esds2.getEsId()) {
+                                return null;
+                            }
+                            if (esds1.getoCREsId() != esds2.getoCREsId()) {
+                                return null;
+                            }
+                            if (esds1.getoCRstreamFlag() != esds2.getoCRstreamFlag()) {
+                                return null;
+                            }
+                            if (esds1.getRemoteODFlag() != esds2.getRemoteODFlag()) {
+                                return null;
+                            }
+                            if (esds1.getStreamDependenceFlag() != esds2.getStreamDependenceFlag()) {
+                                return null;
+                            }
+                            if (esds1.getStreamPriority() != esds2.getStreamPriority()) {
+                                return null;
+                            }
+                            if (esds1.getURLString() != null ? !esds1.getURLString().equals(esds2.getURLString()) : esds2.getURLString() != null) {
+                                return null;
+                            }
+                            if (esds1.getDecoderConfigDescriptor() != null ? !esds1.getDecoderConfigDescriptor().equals(esds2.getDecoderConfigDescriptor()) : esds2.getDecoderConfigDescriptor() != null) {
+                                DecoderConfigDescriptor dcd1 = esds1.getDecoderConfigDescriptor();
+                                DecoderConfigDescriptor dcd2 = esds2.getDecoderConfigDescriptor();
+                                if (!dcd1.getAudioSpecificInfo().equals(dcd2.getAudioSpecificInfo())) {
+                                    return null;
+                                }
+                                if (dcd1.getAvgBitRate() != dcd2.getAvgBitRate()) {
+                                    // I don't care
+                                }
+                                if (dcd1.getBufferSizeDB() != dcd2.getBufferSizeDB()) {
+                                    // I don't care
+                                }
+
+                                if (dcd1.getDecoderSpecificInfo() != null ? !dcd1.getDecoderSpecificInfo().equals(dcd2.getDecoderSpecificInfo()) : dcd2.getDecoderSpecificInfo() != null) {
+                                    return null;
+                                }
+
+                                if (dcd1.getMaxBitRate() != dcd2.getMaxBitRate()) {
+                                    // I don't care
+                                }
+                                if (!dcd1.getProfileLevelIndicationDescriptors().equals(dcd2.getProfileLevelIndicationDescriptors())) {
+                                    return null;
+                                }
+
+                                if (dcd1.getObjectTypeIndication() != dcd2.getObjectTypeIndication()) {
+                                    return null;
+                                }
+                                if (dcd1.getStreamType() != dcd2.getStreamType()) {
+                                    return null;
+                                }
+                                if (dcd1.getUpStream() != dcd2.getUpStream()) {
+                                    return null;
+                                }
+
+
+                            }
+                            if (esds1.getOtherDescriptors() != null ? !esds1.getOtherDescriptors().equals(esds2.getOtherDescriptors()) : esds2.getOtherDescriptors() != null) {
+                                return null;
+                            }
+                            if (esds1.getSlConfigDescriptor() != null ? !esds1.getSlConfigDescriptor().equals(esds2.getSlConfigDescriptor()) : esds2.getSlConfigDescriptor() != null) {
+                                return null;
+                            }
+                            ase.addBox(cur1);
+                        }
+                    }
+                }
+            }
+            return ase;
+        } else {
+            return null;
+        }
+
+
+    }
+
+
+    public List<ByteBuffer> getSamples() {
+        ArrayList<ByteBuffer> lists = new ArrayList<ByteBuffer>();
+
+        for (Track track : tracks) {
+            lists.addAll(track.getSamples());
+        }
+
+        return lists;
+    }
+
+    public SampleDescriptionBox getSampleDescriptionBox() {
+        return stsd;
+    }
+
+    public List<TimeToSampleBox.Entry> getDecodingTimeEntries() {
+        if (tracks[0].getDecodingTimeEntries() != null && !tracks[0].getDecodingTimeEntries().isEmpty()) {
+            List<long[]> lists = new LinkedList<long[]>();
+            for (Track track : tracks) {
+                lists.add(TimeToSampleBox.blowupTimeToSamples(track.getDecodingTimeEntries()));
+            }
+
+            LinkedList<TimeToSampleBox.Entry> returnDecodingEntries = new LinkedList<TimeToSampleBox.Entry>();
+            for (long[] list : lists) {
+                for (long nuDecodingTime : list) {
+                    if (returnDecodingEntries.isEmpty() || returnDecodingEntries.getLast().getDelta() != nuDecodingTime) {
+                        TimeToSampleBox.Entry e = new TimeToSampleBox.Entry(1, nuDecodingTime);
+                        returnDecodingEntries.add(e);
+                    } else {
+                        TimeToSampleBox.Entry e = returnDecodingEntries.getLast();
+                        e.setCount(e.getCount() + 1);
+                    }
+                }
+            }
+            return returnDecodingEntries;
+        } else {
+            return null;
+        }
+    }
+
+    public List<CompositionTimeToSample.Entry> getCompositionTimeEntries() {
+        if (tracks[0].getCompositionTimeEntries() != null && !tracks[0].getCompositionTimeEntries().isEmpty()) {
+            List<int[]> lists = new LinkedList<int[]>();
+            for (Track track : tracks) {
+                lists.add(CompositionTimeToSample.blowupCompositionTimes(track.getCompositionTimeEntries()));
+            }
+            LinkedList<CompositionTimeToSample.Entry> compositionTimeEntries = new LinkedList<CompositionTimeToSample.Entry>();
+            for (int[] list : lists) {
+                for (int compositionTime : list) {
+                    if (compositionTimeEntries.isEmpty() || compositionTimeEntries.getLast().getOffset() != compositionTime) {
+                        CompositionTimeToSample.Entry e = new CompositionTimeToSample.Entry(1, compositionTime);
+                        compositionTimeEntries.add(e);
+                    } else {
+                        CompositionTimeToSample.Entry e = compositionTimeEntries.getLast();
+                        e.setCount(e.getCount() + 1);
+                    }
+                }
+            }
+            return compositionTimeEntries;
+        } else {
+            return null;
+        }
+    }
+
+    public long[] getSyncSamples() {
+        if (tracks[0].getSyncSamples() != null && tracks[0].getSyncSamples().length > 0) {
+            int numSyncSamples = 0;
+            for (Track track : tracks) {
+                numSyncSamples += track.getSyncSamples().length;
+            }
+            long[] returnSyncSamples = new long[numSyncSamples];
+
+            int pos = 0;
+            long samplesBefore = 0;
+            for (Track track : tracks) {
+                for (long l : track.getSyncSamples()) {
+                    returnSyncSamples[pos++] = samplesBefore + l;
+                }
+                samplesBefore += track.getSamples().size();
+            }
+            return returnSyncSamples;
+        } else {
+            return null;
+        }
+    }
+
+    public List<SampleDependencyTypeBox.Entry> getSampleDependencies() {
+        if (tracks[0].getSampleDependencies() != null && !tracks[0].getSampleDependencies().isEmpty()) {
+            List<SampleDependencyTypeBox.Entry> list = new LinkedList<SampleDependencyTypeBox.Entry>();
+            for (Track track : tracks) {
+                list.addAll(track.getSampleDependencies());
+            }
+            return list;
+        } else {
+            return null;
+        }
+    }
+
+    public TrackMetaData getTrackMetaData() {
+        return tracks[0].getTrackMetaData();
+    }
+
+    public String getHandler() {
+        return tracks[0].getHandler();
+    }
+
+    public Box getMediaHeaderBox() {
+        return tracks[0].getMediaHeaderBox();
+    }
+
+    public SubSampleInformationBox getSubsampleInformationBox() {
+        return tracks[0].getSubsampleInformationBox();
+    }
+
+}
diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/authoring/tracks/ChangeTimeScaleTrack.java b/isoparser/src/main/java/com/googlecode/mp4parser/authoring/tracks/ChangeTimeScaleTrack.java
new file mode 100644
index 0000000..50f76c2
--- /dev/null
+++ b/isoparser/src/main/java/com/googlecode/mp4parser/authoring/tracks/ChangeTimeScaleTrack.java
@@ -0,0 +1,203 @@
+/*
+ * Copyright 2012 Sebastian Annies, Hamburg
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.googlecode.mp4parser.authoring.tracks;
+
+import com.coremedia.iso.boxes.*;
+import com.googlecode.mp4parser.authoring.Track;
+import com.googlecode.mp4parser.authoring.TrackMetaData;
+
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Queue;
+import java.util.logging.Logger;
+
+/**
+ * Changes the timescale of a track by wrapping the track.
+ */
+public class ChangeTimeScaleTrack implements Track {
+    private static final Logger LOG = Logger.getLogger(ChangeTimeScaleTrack.class.getName());
+
+    Track source;
+    List<CompositionTimeToSample.Entry> ctts;
+    List<TimeToSampleBox.Entry> tts;
+    long timeScale;
+
+    /**
+     * Changes the time scale of the source track to the target time scale and makes sure
+     * that any rounding errors that may have summed are corrected exactly before the syncSamples.
+     *
+     * @param source          the source track
+     * @param targetTimeScale the resulting time scale of this track.
+     * @param syncSamples     at these sync points where rounding error are corrected.
+     */
+    public ChangeTimeScaleTrack(Track source, long targetTimeScale, long[] syncSamples) {
+        this.source = source;
+        this.timeScale = targetTimeScale;
+        double timeScaleFactor = (double) targetTimeScale / source.getTrackMetaData().getTimescale();
+        ctts = adjustCtts(source.getCompositionTimeEntries(), timeScaleFactor);
+        tts = adjustTts(source.getDecodingTimeEntries(), timeScaleFactor, syncSamples, getTimes(source, syncSamples, targetTimeScale));
+    }
+
+    private static long[] getTimes(Track track, long[] syncSamples, long targetTimeScale) {
+        long[] syncSampleTimes = new long[syncSamples.length];
+        Queue<TimeToSampleBox.Entry> timeQueue = new LinkedList<TimeToSampleBox.Entry>(track.getDecodingTimeEntries());
+
+        int currentSample = 1;  // first syncsample is 1
+        long currentDuration = 0;
+        long currentDelta = 0;
+        int currentSyncSampleIndex = 0;
+        long left = 0;
+
+
+        while (currentSample <= syncSamples[syncSamples.length - 1]) {
+            if (currentSample++ == syncSamples[currentSyncSampleIndex]) {
+                syncSampleTimes[currentSyncSampleIndex++] = (currentDuration * targetTimeScale) / track.getTrackMetaData().getTimescale();
+            }
+            if (left-- == 0) {
+                TimeToSampleBox.Entry entry = timeQueue.poll();
+                left = entry.getCount() - 1;
+                currentDelta = entry.getDelta();
+            }
+            currentDuration += currentDelta;
+        }
+        return syncSampleTimes;
+
+    }
+
+    public SampleDescriptionBox getSampleDescriptionBox() {
+        return source.getSampleDescriptionBox();
+    }
+
+    public List<TimeToSampleBox.Entry> getDecodingTimeEntries() {
+        return tts;
+    }
+
+    public List<CompositionTimeToSample.Entry> getCompositionTimeEntries() {
+        return ctts;
+    }
+
+    public long[] getSyncSamples() {
+        return source.getSyncSamples();
+    }
+
+    public List<SampleDependencyTypeBox.Entry> getSampleDependencies() {
+        return source.getSampleDependencies();
+    }
+
+    public TrackMetaData getTrackMetaData() {
+        TrackMetaData trackMetaData = (TrackMetaData) source.getTrackMetaData().clone();
+        trackMetaData.setTimescale(timeScale);
+        return trackMetaData;
+    }
+
+    public String getHandler() {
+        return source.getHandler();
+    }
+
+    public boolean isEnabled() {
+        return source.isEnabled();
+    }
+
+    public boolean isInMovie() {
+        return source.isInMovie();
+    }
+
+    public boolean isInPreview() {
+        return source.isInPreview();
+    }
+
+    public boolean isInPoster() {
+        return source.isInPoster();
+    }
+
+    public List<ByteBuffer> getSamples() {
+        return source.getSamples();
+    }
+
+
+    /**
+     * Adjusting the composition times is easy. Just scale it by the factor - that's it. There is no rounding
+     * error summing up.
+     *
+     * @param source
+     * @param timeScaleFactor
+     * @return
+     */
+    static List<CompositionTimeToSample.Entry> adjustCtts(List<CompositionTimeToSample.Entry> source, double timeScaleFactor) {
+        if (source != null) {
+            List<CompositionTimeToSample.Entry> entries2 = new ArrayList<CompositionTimeToSample.Entry>(source.size());
+            for (CompositionTimeToSample.Entry entry : source) {
+                entries2.add(new CompositionTimeToSample.Entry(entry.getCount(), (int) Math.round(timeScaleFactor * entry.getOffset())));
+            }
+            return entries2;
+        } else {
+            return null;
+        }
+    }
+
+    static List<TimeToSampleBox.Entry> adjustTts(List<TimeToSampleBox.Entry> source, double timeScaleFactor, long[] syncSample, long[] syncSampleTimes) {
+
+        long[] sourceArray = TimeToSampleBox.blowupTimeToSamples(source);
+        long summedDurations = 0;
+
+        LinkedList<TimeToSampleBox.Entry> entries2 = new LinkedList<TimeToSampleBox.Entry>();
+        for (int i = 1; i <= sourceArray.length; i++) {
+            long duration = sourceArray[i - 1];
+
+            long x = Math.round(timeScaleFactor * duration);
+
+
+            TimeToSampleBox.Entry last = entries2.peekLast();
+            int ssIndex;
+            if ((ssIndex = Arrays.binarySearch(syncSample, i + 1)) >= 0) {
+                // we are at the sample before sync point
+                if (syncSampleTimes[ssIndex] != summedDurations) {
+                    long correction = syncSampleTimes[ssIndex] - (summedDurations + x);
+                    LOG.finest(String.format("Sample %d %d / %d - correct by %d", i, summedDurations, syncSampleTimes[ssIndex], correction));
+                    x += correction;
+                }
+            }
+            summedDurations += x;
+            if (last == null) {
+                entries2.add(new TimeToSampleBox.Entry(1, x));
+            } else if (last.getDelta() != x) {
+                entries2.add(new TimeToSampleBox.Entry(1, x));
+            } else {
+                last.setCount(last.getCount() + 1);
+            }
+
+        }
+        return entries2;
+    }
+
+    public Box getMediaHeaderBox() {
+        return source.getMediaHeaderBox();
+    }
+
+    public SubSampleInformationBox getSubsampleInformationBox() {
+        return source.getSubsampleInformationBox();
+    }
+
+    @Override
+    public String toString() {
+        return "ChangeTimeScaleTrack{" +
+                "source=" + source +
+                '}';
+    }
+}
\ No newline at end of file
diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/authoring/tracks/CroppedTrack.java b/isoparser/src/main/java/com/googlecode/mp4parser/authoring/tracks/CroppedTrack.java
new file mode 100644
index 0000000..2389961
--- /dev/null
+++ b/isoparser/src/main/java/com/googlecode/mp4parser/authoring/tracks/CroppedTrack.java
@@ -0,0 +1,151 @@
+/*
+ * Copyright 2012 Sebastian Annies, Hamburg
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.googlecode.mp4parser.authoring.tracks;
+
+import com.coremedia.iso.boxes.*;
+import com.googlecode.mp4parser.authoring.AbstractTrack;
+import com.googlecode.mp4parser.authoring.Track;
+import com.googlecode.mp4parser.authoring.TrackMetaData;
+
+import java.nio.ByteBuffer;
+import java.util.LinkedList;
+import java.util.List;
+
+/**
+ * Generates a Track that starts at fromSample and ends at toSample (exclusive). The user of this class
+ * has to make sure that the fromSample is a random access sample.
+ * <ul>
+ * <li>In AAC this is every single sample</li>
+ * <li>In H264 this is every sample that is marked in the SyncSampleBox</li>
+ * </ul>
+ */
+public class CroppedTrack extends AbstractTrack {
+    Track origTrack;
+    private int fromSample;
+    private int toSample;
+    private long[] syncSampleArray;
+
+    public CroppedTrack(Track origTrack, long fromSample, long toSample) {
+        this.origTrack = origTrack;
+        assert fromSample <= Integer.MAX_VALUE;
+        assert toSample <= Integer.MAX_VALUE;
+        this.fromSample = (int) fromSample;
+        this.toSample = (int) toSample;
+    }
+
+    public List<ByteBuffer> getSamples() {
+        return origTrack.getSamples().subList(fromSample, toSample);
+    }
+
+    public SampleDescriptionBox getSampleDescriptionBox() {
+        return origTrack.getSampleDescriptionBox();
+    }
+
+    public List<TimeToSampleBox.Entry> getDecodingTimeEntries() {
+        if (origTrack.getDecodingTimeEntries() != null && !origTrack.getDecodingTimeEntries().isEmpty()) {
+            // todo optimize! too much long is allocated but then not used
+            long[] decodingTimes = TimeToSampleBox.blowupTimeToSamples(origTrack.getDecodingTimeEntries());
+            long[] nuDecodingTimes = new long[toSample - fromSample];
+            System.arraycopy(decodingTimes, fromSample, nuDecodingTimes, 0, toSample - fromSample);
+
+            LinkedList<TimeToSampleBox.Entry> returnDecodingEntries = new LinkedList<TimeToSampleBox.Entry>();
+
+            for (long nuDecodingTime : nuDecodingTimes) {
+                if (returnDecodingEntries.isEmpty() || returnDecodingEntries.getLast().getDelta() != nuDecodingTime) {
+                    TimeToSampleBox.Entry e = new TimeToSampleBox.Entry(1, nuDecodingTime);
+                    returnDecodingEntries.add(e);
+                } else {
+                    TimeToSampleBox.Entry e = returnDecodingEntries.getLast();
+                    e.setCount(e.getCount() + 1);
+                }
+            }
+            return returnDecodingEntries;
+        } else {
+            return null;
+        }
+    }
+
+    public List<CompositionTimeToSample.Entry> getCompositionTimeEntries() {
+        if (origTrack.getCompositionTimeEntries() != null && !origTrack.getCompositionTimeEntries().isEmpty()) {
+            int[] compositionTime = CompositionTimeToSample.blowupCompositionTimes(origTrack.getCompositionTimeEntries());
+            int[] nuCompositionTimes = new int[toSample - fromSample];
+            System.arraycopy(compositionTime, fromSample, nuCompositionTimes, 0, toSample - fromSample);
+
+            LinkedList<CompositionTimeToSample.Entry> returnDecodingEntries = new LinkedList<CompositionTimeToSample.Entry>();
+
+            for (int nuDecodingTime : nuCompositionTimes) {
+                if (returnDecodingEntries.isEmpty() || returnDecodingEntries.getLast().getOffset() != nuDecodingTime) {
+                    CompositionTimeToSample.Entry e = new CompositionTimeToSample.Entry(1, nuDecodingTime);
+                    returnDecodingEntries.add(e);
+                } else {
+                    CompositionTimeToSample.Entry e = returnDecodingEntries.getLast();
+                    e.setCount(e.getCount() + 1);
+                }
+            }
+            return returnDecodingEntries;
+        } else {
+            return null;
+        }
+    }
+
+    synchronized public long[] getSyncSamples() {
+        if (this.syncSampleArray == null) {
+            if (origTrack.getSyncSamples() != null && origTrack.getSyncSamples().length > 0) {
+                List<Long> syncSamples = new LinkedList<Long>();
+                for (long l : origTrack.getSyncSamples()) {
+                    if (l >= fromSample && l < toSample) {
+                        syncSamples.add(l - fromSample);
+                    }
+                }
+                syncSampleArray = new long[syncSamples.size()];
+                for (int i = 0; i < syncSampleArray.length; i++) {
+                    syncSampleArray[i] = syncSamples.get(i);
+
+                }
+                return syncSampleArray;
+            } else {
+                return null;
+            }
+        } else {
+            return this.syncSampleArray;
+        }
+    }
+
+    public List<SampleDependencyTypeBox.Entry> getSampleDependencies() {
+        if (origTrack.getSampleDependencies() != null && !origTrack.getSampleDependencies().isEmpty()) {
+            return origTrack.getSampleDependencies().subList(fromSample, toSample);
+        } else {
+            return null;
+        }
+    }
+
+    public TrackMetaData getTrackMetaData() {
+        return origTrack.getTrackMetaData();
+    }
+
+    public String getHandler() {
+        return origTrack.getHandler();
+    }
+
+    public Box getMediaHeaderBox() {
+        return origTrack.getMediaHeaderBox();
+    }
+
+    public SubSampleInformationBox getSubsampleInformationBox() {
+        return origTrack.getSubsampleInformationBox();
+    }
+
+}
\ No newline at end of file
diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/authoring/tracks/DivideTimeScaleTrack.java b/isoparser/src/main/java/com/googlecode/mp4parser/authoring/tracks/DivideTimeScaleTrack.java
new file mode 100644
index 0000000..c51e8e0
--- /dev/null
+++ b/isoparser/src/main/java/com/googlecode/mp4parser/authoring/tracks/DivideTimeScaleTrack.java
@@ -0,0 +1,126 @@
+/*
+ * Copyright 2012 Sebastian Annies, Hamburg
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.googlecode.mp4parser.authoring.tracks;
+
+import com.coremedia.iso.boxes.*;
+import com.googlecode.mp4parser.authoring.Track;
+import com.googlecode.mp4parser.authoring.TrackMetaData;
+
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
+import java.util.LinkedList;
+import java.util.List;
+
+/**
+ * Changes the timescale of a track by wrapping the track.
+ */
+public class DivideTimeScaleTrack implements Track {
+    Track source;
+    private int timeScaleDivisor;
+
+    public DivideTimeScaleTrack(Track source, int timeScaleDivisor) {
+        this.source = source;
+        this.timeScaleDivisor = timeScaleDivisor;
+    }
+
+    public SampleDescriptionBox getSampleDescriptionBox() {
+        return source.getSampleDescriptionBox();
+    }
+
+    public List<TimeToSampleBox.Entry> getDecodingTimeEntries() {
+        return adjustTts();
+    }
+
+    public List<CompositionTimeToSample.Entry> getCompositionTimeEntries() {
+        return adjustCtts();
+    }
+
+    public long[] getSyncSamples() {
+        return source.getSyncSamples();
+    }
+
+    public List<SampleDependencyTypeBox.Entry> getSampleDependencies() {
+        return source.getSampleDependencies();
+    }
+
+    public TrackMetaData getTrackMetaData() {
+        TrackMetaData trackMetaData = (TrackMetaData) source.getTrackMetaData().clone();
+        trackMetaData.setTimescale(source.getTrackMetaData().getTimescale() / this.timeScaleDivisor);
+        return trackMetaData;
+    }
+
+    public String getHandler() {
+        return source.getHandler();
+    }
+
+    public boolean isEnabled() {
+        return source.isEnabled();
+    }
+
+    public boolean isInMovie() {
+        return source.isInMovie();
+    }
+
+    public boolean isInPreview() {
+        return source.isInPreview();
+    }
+
+    public boolean isInPoster() {
+        return source.isInPoster();
+    }
+
+    public List<ByteBuffer> getSamples() {
+        return source.getSamples();
+    }
+
+
+    List<CompositionTimeToSample.Entry> adjustCtts() {
+        List<CompositionTimeToSample.Entry> origCtts = this.source.getCompositionTimeEntries();
+        if (origCtts != null) {
+            List<CompositionTimeToSample.Entry> entries2 = new ArrayList<CompositionTimeToSample.Entry>(origCtts.size());
+            for (CompositionTimeToSample.Entry entry : origCtts) {
+                entries2.add(new CompositionTimeToSample.Entry(entry.getCount(), entry.getOffset() / timeScaleDivisor));
+            }
+            return entries2;
+        } else {
+            return null;
+        }
+    }
+
+    List<TimeToSampleBox.Entry> adjustTts() {
+        List<TimeToSampleBox.Entry> origTts = source.getDecodingTimeEntries();
+        LinkedList<TimeToSampleBox.Entry> entries2 = new LinkedList<TimeToSampleBox.Entry>();
+        for (TimeToSampleBox.Entry e : origTts) {
+            entries2.add(new TimeToSampleBox.Entry(e.getCount(), e.getDelta() / timeScaleDivisor));
+        }
+        return entries2;
+    }
+
+    public Box getMediaHeaderBox() {
+        return source.getMediaHeaderBox();
+    }
+
+    public SubSampleInformationBox getSubsampleInformationBox() {
+        return source.getSubsampleInformationBox();
+    }
+
+    @Override
+    public String toString() {
+        return "MultiplyTimeScaleTrack{" +
+                "source=" + source +
+                '}';
+    }
+}
diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/authoring/tracks/EC3TrackImpl.java b/isoparser/src/main/java/com/googlecode/mp4parser/authoring/tracks/EC3TrackImpl.java
new file mode 100644
index 0000000..d0b2d76
--- /dev/null
+++ b/isoparser/src/main/java/com/googlecode/mp4parser/authoring/tracks/EC3TrackImpl.java
@@ -0,0 +1,436 @@
+package com.googlecode.mp4parser.authoring.tracks;
+
+import com.coremedia.iso.boxes.*;
+import com.coremedia.iso.boxes.sampleentry.AudioSampleEntry;
+import com.googlecode.mp4parser.authoring.AbstractTrack;
+import com.googlecode.mp4parser.authoring.TrackMetaData;
+import com.googlecode.mp4parser.boxes.EC3SpecificBox;
+import com.googlecode.mp4parser.boxes.mp4.objectdescriptors.BitReaderBuffer;
+
+import java.io.BufferedInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.ByteBuffer;
+import java.util.Date;
+import java.util.LinkedList;
+import java.util.List;
+
+/**
+ * Created by IntelliJ IDEA.
+ * User: magnus
+ * Date: 2012-03-14
+ * Time: 10:39
+ * To change this template use File | Settings | File Templates.
+ */
+public class EC3TrackImpl extends AbstractTrack {
+    TrackMetaData trackMetaData = new TrackMetaData();
+    SampleDescriptionBox sampleDescriptionBox;
+
+    int samplerate;
+    int bitrate;
+    int frameSize;
+
+    List<BitStreamInfo> entries = new LinkedList<BitStreamInfo>();
+
+    private BufferedInputStream inputStream;
+    private List<ByteBuffer> samples;
+    List<TimeToSampleBox.Entry> stts = new LinkedList<TimeToSampleBox.Entry>();
+    private String lang = "und";
+
+    public EC3TrackImpl(InputStream fin, String lang) throws IOException {
+        this.lang = lang;
+        parse(fin);
+    }
+
+    public EC3TrackImpl(InputStream fin) throws IOException {
+        parse(fin);
+    }
+
+    private void parse(InputStream fin) throws IOException {
+        inputStream = new BufferedInputStream(fin);
+
+        boolean done = false;
+        inputStream.mark(10000);
+        while (!done) {
+            BitStreamInfo bsi = readVariables();
+            if (bsi == null) {
+                throw new IOException();
+            }
+            for (BitStreamInfo entry : entries) {
+                if (bsi.strmtyp != 1 && entry.substreamid == bsi.substreamid) {
+                    done = true;
+                }
+            }
+            if (!done) {
+                entries.add(bsi);
+                long skipped = inputStream.skip(bsi.frameSize);
+                assert skipped == bsi.frameSize;
+            }
+        }
+
+        inputStream.reset();
+
+        if (entries.size() == 0) {
+            throw new IOException();
+        }
+        samplerate = entries.get(0).samplerate;
+
+        sampleDescriptionBox = new SampleDescriptionBox();
+        AudioSampleEntry audioSampleEntry = new AudioSampleEntry("ec-3");
+        audioSampleEntry.setChannelCount(2);  // According to  ETSI TS 102 366 Annex F
+        audioSampleEntry.setSampleRate(samplerate);
+        audioSampleEntry.setDataReferenceIndex(1);
+        audioSampleEntry.setSampleSize(16);
+
+        EC3SpecificBox ec3 = new EC3SpecificBox();
+        int[] deps = new int[entries.size()];
+        int[] chan_locs = new int[entries.size()];
+        for (BitStreamInfo bsi : entries) {
+            if (bsi.strmtyp == 1) {
+                deps[bsi.substreamid]++;
+                chan_locs[bsi.substreamid] = ((bsi.chanmap >> 6) & 0x100) | ((bsi.chanmap >> 5) & 0xff);
+            }
+        }
+        for (BitStreamInfo bsi : entries) {
+            if (bsi.strmtyp != 1) {
+                EC3SpecificBox.Entry e = new EC3SpecificBox.Entry();
+                e.fscod = bsi.fscod;
+                e.bsid = bsi.bsid;
+                e.bsmod = bsi.bsmod;
+                e.acmod = bsi.acmod;
+                e.lfeon = bsi.lfeon;
+                e.reserved = 0;
+                e.num_dep_sub = deps[bsi.substreamid];
+                e.chan_loc = chan_locs[bsi.substreamid];
+                e.reserved2 = 0;
+                ec3.addEntry(e);
+            }
+            bitrate += bsi.bitrate;
+            frameSize += bsi.frameSize;
+        }
+
+        ec3.setDataRate(bitrate / 1000);
+        audioSampleEntry.addBox(ec3);
+        sampleDescriptionBox.addBox(audioSampleEntry);
+
+        trackMetaData.setCreationTime(new Date());
+        trackMetaData.setModificationTime(new Date());
+        trackMetaData.setLanguage(lang);
+        trackMetaData.setTimescale(samplerate); // Audio tracks always use samplerate as timescale
+
+        samples = new LinkedList<ByteBuffer>();
+        if (!readSamples()) {
+            throw new IOException();
+        }
+    }
+
+
+    public List<ByteBuffer> getSamples() {
+
+        return samples;
+    }
+
+    public SampleDescriptionBox getSampleDescriptionBox() {
+        return sampleDescriptionBox;
+    }
+
+    public List<TimeToSampleBox.Entry> getDecodingTimeEntries() {
+        return stts;
+    }
+
+    public List<CompositionTimeToSample.Entry> getCompositionTimeEntries() {
+        return null;
+    }
+
+    public long[] getSyncSamples() {
+        return null;
+    }
+
+    public List<SampleDependencyTypeBox.Entry> getSampleDependencies() {
+        return null;
+    }
+
+    public TrackMetaData getTrackMetaData() {
+        return trackMetaData;
+    }
+
+    public String getHandler() {
+        return "soun";
+    }
+
+    public AbstractMediaHeaderBox getMediaHeaderBox() {
+        return new SoundMediaHeaderBox();
+    }
+
+    public SubSampleInformationBox getSubsampleInformationBox() {
+        return null;
+    }
+
+    private BitStreamInfo readVariables() throws IOException {
+        byte[] data = new byte[200];
+        inputStream.mark(200);
+        if (200 != inputStream.read(data, 0, 200)) {
+            return null;
+        }
+        inputStream.reset(); // Rewind
+        ByteBuffer bb = ByteBuffer.wrap(data);
+        BitReaderBuffer brb = new BitReaderBuffer(bb);
+        int syncword = brb.readBits(16);
+        if (syncword != 0xb77) {
+            return null;
+        }
+
+        BitStreamInfo entry = new BitStreamInfo();
+
+        entry.strmtyp = brb.readBits(2);
+        entry.substreamid = brb.readBits(3);
+        int frmsiz = brb.readBits(11);
+        entry.frameSize = 2 * (frmsiz + 1);
+
+        entry.fscod = brb.readBits(2);
+        int fscod2 = -1;
+        int numblkscod;
+        if (entry.fscod == 3) {
+            fscod2 = brb.readBits(2);
+            numblkscod = 3;
+        } else {
+            numblkscod = brb.readBits(2);
+        }
+        int numberOfBlocksPerSyncFrame = 0;
+        switch (numblkscod) {
+            case 0:
+                numberOfBlocksPerSyncFrame = 1;
+                break;
+
+            case 1:
+                numberOfBlocksPerSyncFrame = 2;
+                break;
+
+            case 2:
+                numberOfBlocksPerSyncFrame = 3;
+                break;
+
+            case 3:
+                numberOfBlocksPerSyncFrame = 6;
+                break;
+
+        }
+        entry.frameSize *= (6 / numberOfBlocksPerSyncFrame);
+
+        entry.acmod = brb.readBits(3);
+        entry.lfeon = brb.readBits(1);
+        entry.bsid = brb.readBits(5);
+        brb.readBits(5);
+        if (1 == brb.readBits(1)) {
+            brb.readBits(8); // compr
+        }
+        if (0 == entry.acmod) {
+            brb.readBits(5);
+            if (1 == brb.readBits(1)) {
+                brb.readBits(8);
+            }
+        }
+        if (1 == entry.strmtyp) {
+            if (1 == brb.readBits(1)) {
+                entry.chanmap = brb.readBits(16);
+            }
+        }
+        if (1 == brb.readBits(1)) {     // mixing metadata
+            if (entry.acmod > 2) {
+                brb.readBits(2);
+            }
+            if (1 == (entry.acmod & 1) && entry.acmod > 2) {
+                brb.readBits(3);
+                brb.readBits(3);
+            }
+            if (0 < (entry.acmod & 4)) {
+                brb.readBits(3);
+                brb.readBits(3);
+            }
+            if (1 == entry.lfeon) {
+                if (1 == brb.readBits(1)) {
+                    brb.readBits(5);
+                }
+            }
+            if (0 == entry.strmtyp) {
+                if (1 == brb.readBits(1)) {
+                    brb.readBits(6);
+                }
+                if (0 == entry.acmod) {
+                    if (1 == brb.readBits(1)) {
+                        brb.readBits(6);
+                    }
+                }
+                if (1 == brb.readBits(1)) {
+                    brb.readBits(6);
+                }
+                int mixdef = brb.readBits(2);
+                if (1 == mixdef) {
+                    brb.readBits(5);
+                } else if (2 == mixdef) {
+                    brb.readBits(12);
+                } else if (3 == mixdef) {
+                    int mixdeflen = brb.readBits(5);
+                    if (1 == brb.readBits(1)) {
+                        brb.readBits(5);
+                        if (1 == brb.readBits(1)) {
+                            brb.readBits(4);
+                        }
+                        if (1 == brb.readBits(1)) {
+                            brb.readBits(4);
+                        }
+                        if (1 == brb.readBits(1)) {
+                            brb.readBits(4);
+                        }
+                        if (1 == brb.readBits(1)) {
+                            brb.readBits(4);
+                        }
+                        if (1 == brb.readBits(1)) {
+                            brb.readBits(4);
+                        }
+                        if (1 == brb.readBits(1)) {
+                            brb.readBits(4);
+                        }
+                        if (1 == brb.readBits(1)) {
+                            brb.readBits(4);
+                        }
+                        if (1 == brb.readBits(1)) {
+                            if (1 == brb.readBits(1)) {
+                                brb.readBits(4);
+                            }
+                            if (1 == brb.readBits(1)) {
+                                brb.readBits(4);
+                            }
+                        }
+                    }
+                    if (1 == brb.readBits(1)) {
+                        brb.readBits(5);
+                        if (1 == brb.readBits(1)) {
+                            brb.readBits(7);
+                            if (1 == brb.readBits(1)) {
+                                brb.readBits(8);
+                            }
+                        }
+                    }
+                    for (int i = 0; i < (mixdeflen + 2); i++) {
+                        brb.readBits(8);
+                    }
+                    brb.byteSync();
+                }
+                if (entry.acmod < 2) {
+                    if (1 == brb.readBits(1)) {
+                        brb.readBits(14);
+                    }
+                    if (0 == entry.acmod) {
+                        if (1 == brb.readBits(1)) {
+                            brb.readBits(14);
+                        }
+                    }
+                    if (1 == brb.readBits(1)) {
+                        if (numblkscod == 0) {
+                            brb.readBits(5);
+                        } else {
+                            for (int i = 0; i < numberOfBlocksPerSyncFrame; i++) {
+                                if (1 == brb.readBits(1)) {
+                                    brb.readBits(5);
+                                }
+                            }
+                        }
+
+                    }
+                }
+            }
+        }
+        if (1 == brb.readBits(1)) { // infomdate
+            entry.bsmod = brb.readBits(3);
+        }
+
+        switch (entry.fscod) {
+            case 0:
+                entry.samplerate = 48000;
+                break;
+
+            case 1:
+                entry.samplerate = 44100;
+                break;
+
+            case 2:
+                entry.samplerate = 32000;
+                break;
+
+            case 3: {
+                switch (fscod2) {
+                    case 0:
+                        entry.samplerate = 24000;
+                        break;
+
+                    case 1:
+                        entry.samplerate = 22050;
+                        break;
+
+                    case 2:
+                        entry.samplerate = 16000;
+                        break;
+
+                    case 3:
+                        entry.samplerate = 0;
+                        break;
+                }
+                break;
+            }
+
+        }
+        if (entry.samplerate == 0) {
+            return null;
+        }
+
+        entry.bitrate = (int) (((double) entry.samplerate) / 1536.0 * entry.frameSize * 8);
+
+        return entry;
+    }
+
+    private boolean readSamples() throws IOException {
+        int read = frameSize;
+        boolean ret = false;
+        while (frameSize == read) {
+            ret = true;
+            byte[] data = new byte[frameSize];
+            read = inputStream.read(data);
+            if (read == frameSize) {
+                samples.add(ByteBuffer.wrap(data));
+                stts.add(new TimeToSampleBox.Entry(1, 1536));
+            }
+        }
+        return ret;
+    }
+
+    public static class BitStreamInfo extends EC3SpecificBox.Entry {
+        public int frameSize;
+        public int substreamid;
+        public int bitrate;
+        public int samplerate;
+        public int strmtyp;
+        public int chanmap;
+
+        @Override
+        public String toString() {
+            return "BitStreamInfo{" +
+                    "frameSize=" + frameSize +
+                    ", substreamid=" + substreamid +
+                    ", bitrate=" + bitrate +
+                    ", samplerate=" + samplerate +
+                    ", strmtyp=" + strmtyp +
+                    ", chanmap=" + chanmap +
+                    '}';
+        }
+    }
+
+    @Override
+    public String toString() {
+        return "EC3TrackImpl{" +
+                "bitrate=" + bitrate +
+                ", samplerate=" + samplerate +
+                ", entries=" + entries +
+                '}';
+    }
+}
diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/authoring/tracks/H264TrackImpl.java b/isoparser/src/main/java/com/googlecode/mp4parser/authoring/tracks/H264TrackImpl.java
new file mode 100644
index 0000000..b3c1866
--- /dev/null
+++ b/isoparser/src/main/java/com/googlecode/mp4parser/authoring/tracks/H264TrackImpl.java
@@ -0,0 +1,740 @@
+package com.googlecode.mp4parser.authoring.tracks;
+
+import com.coremedia.iso.boxes.*;
+import com.coremedia.iso.boxes.h264.AvcConfigurationBox;
+import com.coremedia.iso.boxes.sampleentry.VisualSampleEntry;
+import com.googlecode.mp4parser.authoring.AbstractTrack;
+import com.googlecode.mp4parser.authoring.TrackMetaData;
+import com.googlecode.mp4parser.h264.model.PictureParameterSet;
+import com.googlecode.mp4parser.h264.model.SeqParameterSet;
+import com.googlecode.mp4parser.h264.read.CAVLCReader;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.logging.Logger;
+
+/**
+ * The <code>H264TrackImpl</code> creates a <code>Track</code> from an H.264
+ * Annex B file.
+ */
+public class H264TrackImpl extends AbstractTrack {
+    private static final Logger LOG = Logger.getLogger(H264TrackImpl.class.getName());
+    
+    TrackMetaData trackMetaData = new TrackMetaData();
+    SampleDescriptionBox sampleDescriptionBox;
+
+    private ReaderWrapper reader;
+    private List<ByteBuffer> samples;
+    boolean readSamples = false;
+
+    List<TimeToSampleBox.Entry> stts;
+    List<CompositionTimeToSample.Entry> ctts;
+    List<SampleDependencyTypeBox.Entry> sdtp;
+    List<Integer> stss;
+
+    SeqParameterSet seqParameterSet = null;
+    PictureParameterSet pictureParameterSet = null;
+    LinkedList<byte[]> seqParameterSetList = new LinkedList<byte[]>();
+    LinkedList<byte[]> pictureParameterSetList = new LinkedList<byte[]>();
+
+    private int width;
+    private int height;
+    private int timescale;
+    private int frametick;
+    private int currentScSize;
+    private int prevScSize;
+
+    private SEIMessage seiMessage;
+    int frameNrInGop = 0;
+    private boolean determineFrameRate = true;
+    private String lang = "und";
+
+    public H264TrackImpl(InputStream inputStream, String lang, long timescale) throws IOException {
+        this.lang = lang;
+        if (timescale > 1000) {
+            timescale = timescale; //e.g. 23976
+            frametick = 1000;
+            determineFrameRate = false;
+        } else {
+            throw new IllegalArgumentException("Timescale must be specified in milliseconds!");
+        }
+        parse(inputStream);
+    }
+
+    public H264TrackImpl(InputStream inputStream, String lang) throws IOException {
+        this.lang = lang;
+        parse(inputStream);
+    }
+
+    public H264TrackImpl(InputStream inputStream) throws IOException {
+        parse(inputStream);
+    }
+
+    private void parse(InputStream inputStream) throws IOException {
+        this.reader = new ReaderWrapper(inputStream);
+        stts = new LinkedList<TimeToSampleBox.Entry>();
+        ctts = new LinkedList<CompositionTimeToSample.Entry>();
+        sdtp = new LinkedList<SampleDependencyTypeBox.Entry>();
+        stss = new LinkedList<Integer>();
+
+        samples = new LinkedList<ByteBuffer>();
+        if (!readSamples()) {
+            throw new IOException();
+        }
+
+        if (!readVariables()) {
+            throw new IOException();
+        }
+
+        sampleDescriptionBox = new SampleDescriptionBox();
+        VisualSampleEntry visualSampleEntry = new VisualSampleEntry("avc1");
+        visualSampleEntry.setDataReferenceIndex(1);
+        visualSampleEntry.setDepth(24);
+        visualSampleEntry.setFrameCount(1);
+        visualSampleEntry.setHorizresolution(72);
+        visualSampleEntry.setVertresolution(72);
+        visualSampleEntry.setWidth(width);
+        visualSampleEntry.setHeight(height);
+        visualSampleEntry.setCompressorname("AVC Coding");
+
+        AvcConfigurationBox avcConfigurationBox = new AvcConfigurationBox();
+
+        avcConfigurationBox.setSequenceParameterSets(seqParameterSetList);
+        avcConfigurationBox.setPictureParameterSets(pictureParameterSetList);
+        avcConfigurationBox.setAvcLevelIndication(seqParameterSet.level_idc);
+        avcConfigurationBox.setAvcProfileIndication(seqParameterSet.profile_idc);
+        avcConfigurationBox.setBitDepthLumaMinus8(seqParameterSet.bit_depth_luma_minus8);
+        avcConfigurationBox.setBitDepthChromaMinus8(seqParameterSet.bit_depth_chroma_minus8);
+        avcConfigurationBox.setChromaFormat(seqParameterSet.chroma_format_idc.getId());
+        avcConfigurationBox.setConfigurationVersion(1);
+        avcConfigurationBox.setLengthSizeMinusOne(3);
+        avcConfigurationBox.setProfileCompatibility(seqParameterSetList.get(0)[1]);
+
+        visualSampleEntry.addBox(avcConfigurationBox);
+        sampleDescriptionBox.addBox(visualSampleEntry);
+
+        trackMetaData.setCreationTime(new Date());
+        trackMetaData.setModificationTime(new Date());
+        trackMetaData.setLanguage(lang);
+        trackMetaData.setTimescale(timescale);
+        trackMetaData.setWidth(width);
+        trackMetaData.setHeight(height);
+    }
+
+    public SampleDescriptionBox getSampleDescriptionBox() {
+        return sampleDescriptionBox;
+    }
+
+    public List<TimeToSampleBox.Entry> getDecodingTimeEntries() {
+        return stts;
+    }
+
+    public List<CompositionTimeToSample.Entry> getCompositionTimeEntries() {
+        return ctts;
+    }
+
+    public long[] getSyncSamples() {
+        long[] returns = new long[stss.size()];
+        for (int i = 0; i < stss.size(); i++) {
+            returns[i] = stss.get(i);
+        }
+        return returns;
+    }
+
+    public List<SampleDependencyTypeBox.Entry> getSampleDependencies() {
+        return sdtp;
+    }
+
+    public TrackMetaData getTrackMetaData() {
+        return trackMetaData;
+    }
+
+    public String getHandler() {
+        return "vide";
+    }
+
+    public List<ByteBuffer> getSamples() {
+        return samples;
+    }
+
+    public AbstractMediaHeaderBox getMediaHeaderBox() {
+        return new VideoMediaHeaderBox();
+    }
+
+    public SubSampleInformationBox getSubsampleInformationBox() {
+        return null;
+    }
+
+    private boolean readVariables() {
+        width = (seqParameterSet.pic_width_in_mbs_minus1 + 1) * 16;
+        int mult = 2;
+        if (seqParameterSet.frame_mbs_only_flag) {
+            mult = 1;
+        }
+        height = 16 * (seqParameterSet.pic_height_in_map_units_minus1 + 1) * mult;
+        if (seqParameterSet.frame_cropping_flag) {
+            int chromaArrayType = 0;
+            if (seqParameterSet.residual_color_transform_flag == false) {
+                chromaArrayType = seqParameterSet.chroma_format_idc.getId();
+            }
+            int cropUnitX = 1;
+            int cropUnitY = mult;
+            if (chromaArrayType != 0) {
+                cropUnitX = seqParameterSet.chroma_format_idc.getSubWidth();
+                cropUnitY = seqParameterSet.chroma_format_idc.getSubHeight() * mult;
+            }
+
+            width -= cropUnitX * (seqParameterSet.frame_crop_left_offset + seqParameterSet.frame_crop_right_offset);
+            height -= cropUnitY * (seqParameterSet.frame_crop_top_offset + seqParameterSet.frame_crop_bottom_offset);
+        }
+        return true;
+    }
+
+    private boolean findNextStartcode() throws IOException {
+        byte[] test = new byte[]{-1, -1, -1, -1};
+
+        int c;
+        while ((c = reader.read()) != -1) {
+            test[0] = test[1];
+            test[1] = test[2];
+            test[2] = test[3];
+            test[3] = (byte) c;
+            if (test[0] == 0 && test[1] == 0 && test[2] == 0 && test[3] == 1) {
+                prevScSize = currentScSize;
+                currentScSize = 4;
+                return true;
+            }
+            if (test[0] == 0 && test[1] == 0 && test[2] == 1) {
+                prevScSize = currentScSize;
+                currentScSize = 3;
+                return true;
+            }
+        }
+        return false;
+    }
+
+    private enum NALActions {
+        IGNORE, BUFFER, STORE, END
+    }
+
+    private boolean readSamples() throws IOException {
+        if (readSamples) {
+            return true;
+        }
+
+        readSamples = true;
+
+
+        findNextStartcode();
+        reader.mark();
+        long pos = reader.getPos();
+
+        ArrayList<byte[]> buffered = new ArrayList<byte[]>();
+
+        int frameNr = 0;
+
+        while (findNextStartcode()) {
+            long newpos = reader.getPos();
+            int size = (int) (newpos - pos - prevScSize);
+            reader.reset();
+            byte[] data = new byte[size ];
+            reader.read(data);
+            int type = data[0];
+            int nal_ref_idc = (type >> 5) & 3;
+            int nal_unit_type = type & 0x1f;
+            LOG.fine("Found startcode at " + (pos -4)  + " Type: " + nal_unit_type + " ref idc: " + nal_ref_idc + " (size " + size + ")");
+            NALActions action = handleNALUnit(nal_ref_idc, nal_unit_type, data);
+            switch (action) {
+                case IGNORE:
+                    break;
+
+                case BUFFER:
+                    buffered.add(data);
+                    break;
+
+                case STORE:
+                    int stdpValue = 22;
+                    frameNr++;
+                    buffered.add(data);
+                    ByteBuffer bb = createSample(buffered);
+                    boolean IdrPicFlag = false;
+                    if (nal_unit_type == 5) {
+                        stdpValue += 16;
+                        IdrPicFlag = true;
+                    }
+                    ByteArrayInputStream bs = cleanBuffer(buffered.get(buffered.size() - 1));
+                    SliceHeader sh = new SliceHeader(bs, seqParameterSet, pictureParameterSet, IdrPicFlag);
+                    if (sh.slice_type == SliceHeader.SliceType.B) {
+                        stdpValue += 4;
+                    }
+                    LOG.fine("Adding sample with size " + bb.capacity() + " and header " + sh);
+                    buffered.clear();
+                    samples.add(bb);
+                    stts.add(new TimeToSampleBox.Entry(1, frametick));
+                    if (nal_unit_type == 5) { // IDR Picture
+                        stss.add(frameNr);
+                    }
+                    if (seiMessage.n_frames == 0) {
+                        frameNrInGop = 0;
+                    }
+                    int offset = 0;
+                    if (seiMessage.clock_timestamp_flag) {
+                        offset = seiMessage.n_frames - frameNrInGop;
+                    } else if (seiMessage.removal_delay_flag) {
+                        offset = seiMessage.dpb_removal_delay / 2;
+                    }
+                    ctts.add(new CompositionTimeToSample.Entry(1, offset * frametick));
+                    sdtp.add(new SampleDependencyTypeBox.Entry(stdpValue));
+                    frameNrInGop++;
+                    break;
+
+                case END:
+                    return true;
+
+
+            }
+            pos = newpos;
+            reader.seek(currentScSize);
+            reader.mark();
+        }
+        return true;
+    }
+
+    private ByteBuffer createSample(List<byte[]> buffers) {
+        int outsize = 0;
+        for (int i = 0; i < buffers.size(); i++) {
+            outsize += buffers.get(i).length + 4;
+        }
+        byte[] output = new byte[outsize];
+
+        ByteBuffer bb = ByteBuffer.wrap(output);
+        for (int i = 0; i < buffers.size(); i++) {
+            bb.putInt(buffers.get(i).length);
+            bb.put(buffers.get(i));
+        }
+        bb.rewind();
+        return bb;
+    }
+
+    private ByteArrayInputStream cleanBuffer(byte[] data) {
+        byte[] output = new byte[data.length];
+        int inPos = 0;
+        int outPos = 0;
+        while (inPos < data.length) {
+            if (data[inPos] == 0 && data[inPos + 1] == 0 && data[inPos + 2] == 3) {
+                output[outPos] = 0;
+                output[outPos + 1] = 0;
+                inPos += 3;
+                outPos += 2;
+            } else {
+                output[outPos] = data[inPos];
+                inPos++;
+                outPos++;
+            }
+        }
+        return new ByteArrayInputStream(output, 0, outPos);
+    }
+
+    private NALActions handleNALUnit(int nal_ref_idc, int nal_unit_type, byte[] data) throws IOException {
+        NALActions action;
+        switch (nal_unit_type) {
+            case 1:
+            case 2:
+            case 3:
+            case 4:
+            case 5:
+                action = NALActions.STORE; // Will only work in single slice per frame mode!
+                break;
+
+            case 6:
+                seiMessage = new SEIMessage(cleanBuffer(data), seqParameterSet);
+                action = NALActions.BUFFER;
+                break;
+
+            case 9:
+//                printAccessUnitDelimiter(data);
+                int type = data[1] >> 5;
+                LOG.fine("Access unit delimiter type: " + type);
+                action = NALActions.BUFFER;
+                break;
+
+
+            case 7:
+                if (seqParameterSet == null) {
+                    ByteArrayInputStream is = cleanBuffer(data);
+                    is.read();
+                    seqParameterSet = SeqParameterSet.read(is);
+                    seqParameterSetList.add(data);
+                    configureFramerate();
+                }
+                action = NALActions.IGNORE;
+                break;
+
+            case 8:
+                if (pictureParameterSet == null) {
+                    ByteArrayInputStream is = new ByteArrayInputStream(data);
+                    is.read();
+                    pictureParameterSet = PictureParameterSet.read(is);
+                    pictureParameterSetList.add(data);
+                }
+                action = NALActions.IGNORE;
+                break;
+
+            case 10:
+            case 11:
+                action = NALActions.END;
+                break;
+
+            default:
+                System.err.println("Unknown NAL unit type: " + nal_unit_type);
+                action = NALActions.IGNORE;
+
+        }
+
+        return action;
+    }
+
+    private void configureFramerate() {
+        if (determineFrameRate) {
+            if (seqParameterSet.vuiParams != null) {
+                timescale = seqParameterSet.vuiParams.time_scale >> 1; // Not sure why, but I found this in several places, and it works...
+                frametick = seqParameterSet.vuiParams.num_units_in_tick;
+                if (timescale == 0 || frametick == 0) {
+                    System.err.println("Warning: vuiParams contain invalid values: time_scale: " + timescale + " and frame_tick: " + frametick + ". Setting frame rate to 25fps");
+                    timescale = 90000;
+                    frametick = 3600;
+                }
+            } else {
+                System.err.println("Warning: Can't determine frame rate. Guessing 25 fps");
+                timescale = 90000;
+                frametick = 3600;
+            }
+        }
+    }
+
+    public void printAccessUnitDelimiter(byte[] data) {
+        LOG.fine("Access unit delimiter: " + (data[1] >> 5));
+    }
+
+    public static class SliceHeader {
+
+        public enum SliceType {
+            P, B, I, SP, SI
+        }
+
+        public int first_mb_in_slice;
+        public SliceType slice_type;
+        public int pic_parameter_set_id;
+        public int colour_plane_id;
+        public int frame_num;
+        public boolean field_pic_flag = false;
+        public boolean bottom_field_flag = false;
+        public int idr_pic_id;
+        public int pic_order_cnt_lsb;
+        public int delta_pic_order_cnt_bottom;
+
+        public SliceHeader(InputStream is, SeqParameterSet sps, PictureParameterSet pps, boolean IdrPicFlag) throws IOException {
+            is.read();
+            CAVLCReader reader = new CAVLCReader(is);
+            first_mb_in_slice = reader.readUE("SliceHeader: first_mb_in_slice");
+            switch (reader.readUE("SliceHeader: slice_type")) {
+                case 0:
+                case 5:
+                    slice_type = SliceType.P;
+                    break;
+
+                case 1:
+                case 6:
+                    slice_type = SliceType.B;
+                    break;
+
+                case 2:
+                case 7:
+                    slice_type = SliceType.I;
+                    break;
+
+                case 3:
+                case 8:
+                    slice_type = SliceType.SP;
+                    break;
+
+                case 4:
+                case 9:
+                    slice_type = SliceType.SI;
+                    break;
+
+            }
+            pic_parameter_set_id = reader.readUE("SliceHeader: pic_parameter_set_id");
+            if (sps.residual_color_transform_flag) {
+                colour_plane_id = reader.readU(2, "SliceHeader: colour_plane_id");
+            }
+            frame_num = reader.readU(sps.log2_max_frame_num_minus4 + 4, "SliceHeader: frame_num");
+
+            if (!sps.frame_mbs_only_flag) {
+                field_pic_flag = reader.readBool("SliceHeader: field_pic_flag");
+                if (field_pic_flag) {
+                    bottom_field_flag = reader.readBool("SliceHeader: bottom_field_flag");
+                }
+            }
+            if (IdrPicFlag) {
+                idr_pic_id = reader.readUE("SliceHeader: idr_pic_id");
+                if (sps.pic_order_cnt_type == 0) {
+                    pic_order_cnt_lsb = reader.readU(sps.log2_max_pic_order_cnt_lsb_minus4 + 4, "SliceHeader: pic_order_cnt_lsb");
+                    if (pps.pic_order_present_flag && !field_pic_flag) {
+                        delta_pic_order_cnt_bottom = reader.readSE("SliceHeader: delta_pic_order_cnt_bottom");
+                    }
+                }
+            }
+        }
+
+        @Override
+        public String toString() {
+            return "SliceHeader{" +
+                    "first_mb_in_slice=" + first_mb_in_slice +
+                    ", slice_type=" + slice_type +
+                    ", pic_parameter_set_id=" + pic_parameter_set_id +
+                    ", colour_plane_id=" + colour_plane_id +
+                    ", frame_num=" + frame_num +
+                    ", field_pic_flag=" + field_pic_flag +
+                    ", bottom_field_flag=" + bottom_field_flag +
+                    ", idr_pic_id=" + idr_pic_id +
+                    ", pic_order_cnt_lsb=" + pic_order_cnt_lsb +
+                    ", delta_pic_order_cnt_bottom=" + delta_pic_order_cnt_bottom +
+                    '}';
+        }
+    }
+
+    private class ReaderWrapper {
+        private InputStream inputStream;
+        private long pos = 0;
+
+        private long markPos = 0;
+
+
+        private ReaderWrapper(InputStream inputStream) {
+            this.inputStream = inputStream;
+        }
+
+        int read() throws IOException {
+            pos++;
+            return inputStream.read();
+        }
+
+        long read(byte[] data) throws IOException {
+            long read = inputStream.read(data);
+            pos += read;
+            return read;
+        }
+
+        long seek(int dist) throws IOException {
+            long seeked = inputStream.skip(dist);
+            pos += seeked;
+            return seeked;
+        }
+
+        public long getPos() {
+            return pos;
+        }
+
+        public void mark() {
+            int i = 1048576;
+            LOG.fine("Marking with " + i + " at " + pos);
+            inputStream.mark(i);
+            markPos = pos;
+        }
+
+
+        public void reset() throws IOException {
+            long diff = pos - markPos;
+            LOG.fine("Resetting to " + markPos + " (pos is " + pos + ") which makes the buffersize " + diff);
+            inputStream.reset();
+            pos = markPos;
+        }
+    }
+
+    public class SEIMessage {
+
+        int payloadType = 0;
+        int payloadSize = 0;
+
+        boolean removal_delay_flag;
+        int cpb_removal_delay;
+        int dpb_removal_delay;
+
+        boolean clock_timestamp_flag;
+        int pic_struct;
+        int ct_type;
+        int nuit_field_based_flag;
+        int counting_type;
+        int full_timestamp_flag;
+        int discontinuity_flag;
+        int cnt_dropped_flag;
+        int n_frames;
+        int seconds_value;
+        int minutes_value;
+        int hours_value;
+        int time_offset_length;
+        int time_offset;
+
+        SeqParameterSet sps;
+
+        public SEIMessage(InputStream is, SeqParameterSet sps) throws IOException {
+            this.sps = sps;
+            is.read();
+            int datasize = is.available();
+            int read = 0;
+            while (read < datasize) {
+                payloadType = 0;
+                payloadSize = 0;
+                int last_payload_type_bytes = is.read();
+                read++;
+                while (last_payload_type_bytes == 0xff) {
+                    payloadType += last_payload_type_bytes;
+                    last_payload_type_bytes = is.read();
+                    read++;
+                }
+                payloadType += last_payload_type_bytes;
+                int last_payload_size_bytes = is.read();
+                read++;
+
+                while (last_payload_size_bytes == 0xff) {
+                    payloadSize += last_payload_size_bytes;
+                    last_payload_size_bytes = is.read();
+                    read++;
+                }
+                payloadSize += last_payload_size_bytes;
+                if (datasize - read >= payloadSize) {
+                    if (payloadType == 1) { // pic_timing is what we are interested in!
+                        if (sps.vuiParams != null && (sps.vuiParams.nalHRDParams != null || sps.vuiParams.vclHRDParams != null || sps.vuiParams.pic_struct_present_flag)) {
+                            byte[] data = new byte[payloadSize];
+                            is.read(data);
+                            read += payloadSize;
+                            CAVLCReader reader = new CAVLCReader(new ByteArrayInputStream(data));
+                            if (sps.vuiParams.nalHRDParams != null || sps.vuiParams.vclHRDParams != null) {
+                                removal_delay_flag = true;
+                                cpb_removal_delay = reader.readU(sps.vuiParams.nalHRDParams.cpb_removal_delay_length_minus1 + 1, "SEI: cpb_removal_delay");
+                                dpb_removal_delay = reader.readU(sps.vuiParams.nalHRDParams.dpb_output_delay_length_minus1 + 1, "SEI: dpb_removal_delay");
+                            } else {
+                                removal_delay_flag = false;
+                            }
+                            if (sps.vuiParams.pic_struct_present_flag) {
+                                pic_struct = reader.readU(4, "SEI: pic_struct");
+                                int numClockTS;
+                                switch (pic_struct) {
+                                    case 0:
+                                    case 1:
+                                    case 2:
+                                    default:
+                                        numClockTS = 1;
+                                        break;
+
+                                    case 3:
+                                    case 4:
+                                    case 7:
+                                        numClockTS = 2;
+                                        break;
+
+                                    case 5:
+                                    case 6:
+                                    case 8:
+                                        numClockTS = 3;
+                                        break;
+                                }
+                                for (int i = 0; i < numClockTS; i++) {
+                                    clock_timestamp_flag = reader.readBool("pic_timing SEI: clock_timestamp_flag[" + i + "]");
+                                    if (clock_timestamp_flag) {
+                                        ct_type = reader.readU(2, "pic_timing SEI: ct_type");
+                                        nuit_field_based_flag = reader.readU(1, "pic_timing SEI: nuit_field_based_flag");
+                                        counting_type = reader.readU(5, "pic_timing SEI: counting_type");
+                                        full_timestamp_flag = reader.readU(1, "pic_timing SEI: full_timestamp_flag");
+                                        discontinuity_flag = reader.readU(1, "pic_timing SEI: discontinuity_flag");
+                                        cnt_dropped_flag = reader.readU(1, "pic_timing SEI: cnt_dropped_flag");
+                                        n_frames = reader.readU(8, "pic_timing SEI: n_frames");
+                                        if (full_timestamp_flag == 1) {
+                                            seconds_value = reader.readU(6, "pic_timing SEI: seconds_value");
+                                            minutes_value = reader.readU(6, "pic_timing SEI: minutes_value");
+                                            hours_value = reader.readU(5, "pic_timing SEI: hours_value");
+                                        } else {
+                                            if (reader.readBool("pic_timing SEI: seconds_flag")) {
+                                                seconds_value = reader.readU(6, "pic_timing SEI: seconds_value");
+                                                if (reader.readBool("pic_timing SEI: minutes_flag")) {
+                                                    minutes_value = reader.readU(6, "pic_timing SEI: minutes_value");
+                                                    if (reader.readBool("pic_timing SEI: hours_flag")) {
+                                                        hours_value = reader.readU(5, "pic_timing SEI: hours_value");
+                                                    }
+                                                }
+                                            }
+                                        }
+                                        if (true) {
+                                            if (sps.vuiParams.nalHRDParams != null) {
+                                                time_offset_length = sps.vuiParams.nalHRDParams.time_offset_length;
+                                            } else if (sps.vuiParams.vclHRDParams != null) {
+                                                time_offset_length = sps.vuiParams.vclHRDParams.time_offset_length;
+                                            } else {
+                                                time_offset_length = 24;
+                                            }
+                                            time_offset = reader.readU(24, "pic_timing SEI: time_offset");
+                                        }
+                                    }
+                                }
+                            }
+
+                        } else {
+                            for (int i = 0; i < payloadSize; i++) {
+                                is.read();
+                                read++;
+                            }
+                        }
+                    } else {
+                        for (int i = 0; i < payloadSize; i++) {
+                            is.read();
+                            read++;
+                        }
+                    }
+                } else {
+                    read = datasize;
+                }
+                LOG.fine(this.toString());
+            }
+        }
+
+        @Override
+        public String toString() {
+            String out = "SEIMessage{" +
+                    "payloadType=" + payloadType +
+                    ", payloadSize=" + payloadSize;
+            if (payloadType == 1) {
+                if (sps.vuiParams.nalHRDParams != null || sps.vuiParams.vclHRDParams != null) {
+
+                    out += ", cpb_removal_delay=" + cpb_removal_delay +
+                            ", dpb_removal_delay=" + dpb_removal_delay;
+                }
+                if (sps.vuiParams.pic_struct_present_flag) {
+                    out += ", pic_struct=" + pic_struct;
+                    if (clock_timestamp_flag) {
+                        out += ", ct_type=" + ct_type +
+                                ", nuit_field_based_flag=" + nuit_field_based_flag +
+                                ", counting_type=" + counting_type +
+                                ", full_timestamp_flag=" + full_timestamp_flag +
+                                ", discontinuity_flag=" + discontinuity_flag +
+                                ", cnt_dropped_flag=" + cnt_dropped_flag +
+                                ", n_frames=" + n_frames +
+                                ", seconds_value=" + seconds_value +
+                                ", minutes_value=" + minutes_value +
+                                ", hours_value=" + hours_value +
+                                ", time_offset_length=" + time_offset_length +
+                                ", time_offset=" + time_offset;
+                    }
+                }
+            }
+            out += '}';
+            return out;
+        }
+    }
+}
diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/authoring/tracks/MultiplyTimeScaleTrack.java b/isoparser/src/main/java/com/googlecode/mp4parser/authoring/tracks/MultiplyTimeScaleTrack.java
new file mode 100644
index 0000000..e9a90e4
--- /dev/null
+++ b/isoparser/src/main/java/com/googlecode/mp4parser/authoring/tracks/MultiplyTimeScaleTrack.java
@@ -0,0 +1,130 @@
+/*
+ * Copyright 2012 Sebastian Annies, Hamburg
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.googlecode.mp4parser.authoring.tracks;
+
+import com.coremedia.iso.boxes.*;
+import com.googlecode.mp4parser.authoring.Movie;
+import com.googlecode.mp4parser.authoring.Track;
+import com.googlecode.mp4parser.authoring.TrackMetaData;
+
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
+import java.util.LinkedList;
+import java.util.List;
+
+import static com.googlecode.mp4parser.util.CastUtils.l2i;
+import static com.googlecode.mp4parser.util.Math.gcd;
+import static com.googlecode.mp4parser.util.Math.lcm;
+import static java.lang.Math.round;
+
+/**
+ * Changes the timescale of a track by wrapping the track.
+ */
+public class MultiplyTimeScaleTrack implements Track {
+    Track source;
+    private int timeScaleFactor;
+
+    public MultiplyTimeScaleTrack(Track source, int timeScaleFactor) {
+        this.source = source;
+        this.timeScaleFactor = timeScaleFactor;
+    }
+
+    public SampleDescriptionBox getSampleDescriptionBox() {
+        return source.getSampleDescriptionBox();
+    }
+
+    public List<TimeToSampleBox.Entry> getDecodingTimeEntries() {
+        return adjustTts(source.getDecodingTimeEntries(), timeScaleFactor);
+    }
+
+    public List<CompositionTimeToSample.Entry> getCompositionTimeEntries() {
+        return adjustCtts(source.getCompositionTimeEntries(), timeScaleFactor);
+    }
+
+    public long[] getSyncSamples() {
+        return source.getSyncSamples();
+    }
+
+    public List<SampleDependencyTypeBox.Entry> getSampleDependencies() {
+        return source.getSampleDependencies();
+    }
+
+    public TrackMetaData getTrackMetaData() {
+        TrackMetaData trackMetaData = (TrackMetaData) source.getTrackMetaData().clone();
+        trackMetaData.setTimescale(source.getTrackMetaData().getTimescale() * this.timeScaleFactor);
+        return trackMetaData;
+    }
+
+    public String getHandler() {
+        return source.getHandler();
+    }
+
+    public boolean isEnabled() {
+        return source.isEnabled();
+    }
+
+    public boolean isInMovie() {
+        return source.isInMovie();
+    }
+
+    public boolean isInPreview() {
+        return source.isInPreview();
+    }
+
+    public boolean isInPoster() {
+        return source.isInPoster();
+    }
+
+    public List<ByteBuffer> getSamples() {
+        return source.getSamples();
+    }
+
+
+    static List<CompositionTimeToSample.Entry> adjustCtts(List<CompositionTimeToSample.Entry> source, int timeScaleFactor) {
+        if (source != null) {
+            List<CompositionTimeToSample.Entry> entries2 = new ArrayList<CompositionTimeToSample.Entry>(source.size());
+            for (CompositionTimeToSample.Entry entry : source) {
+                entries2.add(new CompositionTimeToSample.Entry(entry.getCount(), timeScaleFactor * entry.getOffset()));
+            }
+            return entries2;
+        } else {
+            return null;
+        }
+    }
+
+    static List<TimeToSampleBox.Entry> adjustTts(List<TimeToSampleBox.Entry> source, int timeScaleFactor) {
+        LinkedList<TimeToSampleBox.Entry> entries2 = new LinkedList<TimeToSampleBox.Entry>();
+        for (TimeToSampleBox.Entry e : source) {
+            entries2.add(new TimeToSampleBox.Entry(e.getCount(), timeScaleFactor * e.getDelta()));
+        }
+        return entries2;
+    }
+
+    public Box getMediaHeaderBox() {
+        return source.getMediaHeaderBox();
+    }
+
+    public SubSampleInformationBox getSubsampleInformationBox() {
+        return source.getSubsampleInformationBox();
+    }
+
+    @Override
+    public String toString() {
+        return "MultiplyTimeScaleTrack{" +
+                "source=" + source +
+                '}';
+    }
+}
diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/authoring/tracks/QuicktimeTextTrackImpl.java b/isoparser/src/main/java/com/googlecode/mp4parser/authoring/tracks/QuicktimeTextTrackImpl.java
new file mode 100644
index 0000000..8efa399
--- /dev/null
+++ b/isoparser/src/main/java/com/googlecode/mp4parser/authoring/tracks/QuicktimeTextTrackImpl.java
@@ -0,0 +1,165 @@
+/*
+ * Copyright 2012 Sebastian Annies, Hamburg
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.googlecode.mp4parser.authoring.tracks;
+
+import com.coremedia.iso.boxes.*;
+import com.coremedia.iso.boxes.sampleentry.TextSampleEntry;
+import com.googlecode.mp4parser.authoring.AbstractTrack;
+import com.googlecode.mp4parser.authoring.TrackMetaData;
+import com.googlecode.mp4parser.boxes.apple.BaseMediaInfoAtom;
+import com.googlecode.mp4parser.boxes.apple.GenericMediaHeaderAtom;
+import com.googlecode.mp4parser.boxes.apple.GenericMediaHeaderTextAtom;
+import com.googlecode.mp4parser.boxes.apple.QuicktimeTextSampleEntry;
+import com.googlecode.mp4parser.boxes.threegpp26245.FontTableBox;
+
+import java.io.ByteArrayOutputStream;
+import java.io.DataOutputStream;
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.util.Collections;
+import java.util.Date;
+import java.util.LinkedList;
+import java.util.List;
+
+/**
+ * A Text track as Quicktime Pro would create.
+ */
+public class QuicktimeTextTrackImpl extends AbstractTrack {
+    TrackMetaData trackMetaData = new TrackMetaData();
+    SampleDescriptionBox sampleDescriptionBox;
+    List<Line> subs = new LinkedList<Line>();
+
+    public List<Line> getSubs() {
+        return subs;
+    }
+
+    public QuicktimeTextTrackImpl() {
+        sampleDescriptionBox = new SampleDescriptionBox();
+        QuicktimeTextSampleEntry textTrack = new QuicktimeTextSampleEntry();
+        textTrack.setDataReferenceIndex(1);
+        sampleDescriptionBox.addBox(textTrack);
+
+
+        trackMetaData.setCreationTime(new Date());
+        trackMetaData.setModificationTime(new Date());
+        trackMetaData.setTimescale(1000);
+
+
+    }
+
+
+    public List<ByteBuffer> getSamples() {
+        List<ByteBuffer> samples = new LinkedList<ByteBuffer>();
+        long lastEnd = 0;
+        for (Line sub : subs) {
+            long silentTime = sub.from - lastEnd;
+            if (silentTime > 0) {
+                samples.add(ByteBuffer.wrap(new byte[]{0, 0}));
+            } else if (silentTime < 0) {
+                throw new Error("Subtitle display times may not intersect");
+            }
+            ByteArrayOutputStream baos = new ByteArrayOutputStream();
+            DataOutputStream dos = new DataOutputStream(baos);
+            try {
+                dos.writeShort(sub.text.getBytes("UTF-8").length);
+                dos.write(sub.text.getBytes("UTF-8"));
+                dos.close();
+            } catch (IOException e) {
+                throw new Error("VM is broken. Does not support UTF-8");
+            }
+            samples.add(ByteBuffer.wrap(baos.toByteArray()));
+            lastEnd = sub.to;
+        }
+        return samples;
+    }
+
+    public SampleDescriptionBox getSampleDescriptionBox() {
+        return sampleDescriptionBox;
+    }
+
+    public List<TimeToSampleBox.Entry> getDecodingTimeEntries() {
+        List<TimeToSampleBox.Entry> stts = new LinkedList<TimeToSampleBox.Entry>();
+        long lastEnd = 0;
+        for (Line sub : subs) {
+            long silentTime = sub.from - lastEnd;
+            if (silentTime > 0) {
+                stts.add(new TimeToSampleBox.Entry(1, silentTime));
+            } else if (silentTime < 0) {
+                throw new Error("Subtitle display times may not intersect");
+            }
+            stts.add(new TimeToSampleBox.Entry(1, sub.to - sub.from));
+            lastEnd = sub.to;
+        }
+        return stts;
+    }
+
+    public List<CompositionTimeToSample.Entry> getCompositionTimeEntries() {
+        return null;
+    }
+
+    public long[] getSyncSamples() {
+        return null;
+    }
+
+    public List<SampleDependencyTypeBox.Entry> getSampleDependencies() {
+        return null;
+    }
+
+    public TrackMetaData getTrackMetaData() {
+        return trackMetaData;
+    }
+
+    public String getHandler() {
+        return "text";
+    }
+
+
+    public static class Line {
+        long from;
+        long to;
+        String text;
+
+
+        public Line(long from, long to, String text) {
+            this.from = from;
+            this.to = to;
+            this.text = text;
+        }
+
+        public long getFrom() {
+            return from;
+        }
+
+        public String getText() {
+            return text;
+        }
+
+        public long getTo() {
+            return to;
+        }
+    }
+
+    public Box getMediaHeaderBox() {
+        GenericMediaHeaderAtom ghmd = new GenericMediaHeaderAtom();
+        ghmd.addBox(new BaseMediaInfoAtom());
+        ghmd.addBox(new GenericMediaHeaderTextAtom());
+        return ghmd;
+    }
+
+    public SubSampleInformationBox getSubsampleInformationBox() {
+        return null;
+    }
+}
diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/authoring/tracks/ReplaceSampleTrack.java b/isoparser/src/main/java/com/googlecode/mp4parser/authoring/tracks/ReplaceSampleTrack.java
new file mode 100644
index 0000000..81a129d
--- /dev/null
+++ b/isoparser/src/main/java/com/googlecode/mp4parser/authoring/tracks/ReplaceSampleTrack.java
@@ -0,0 +1,104 @@
+/*
+ * Copyright 2012 Sebastian Annies, Hamburg
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.googlecode.mp4parser.authoring.tracks;
+
+import com.coremedia.iso.boxes.*;
+import com.googlecode.mp4parser.authoring.AbstractTrack;
+import com.googlecode.mp4parser.authoring.Track;
+import com.googlecode.mp4parser.authoring.TrackMetaData;
+
+import java.nio.ByteBuffer;
+import java.util.AbstractList;
+import java.util.LinkedList;
+import java.util.List;
+
+/**
+ * Generates a Track where a single sample has been replaced by a given <code>ByteBuffer</code>.
+ */
+
+public class ReplaceSampleTrack extends AbstractTrack {
+    Track origTrack;
+    private long sampleNumber;
+    private ByteBuffer sampleContent;
+    private List<ByteBuffer>  samples;
+
+    public ReplaceSampleTrack(Track origTrack, long sampleNumber, ByteBuffer content) {
+        this.origTrack = origTrack;
+        this.sampleNumber = sampleNumber;
+        this.sampleContent = content;
+        this.samples = new ReplaceASingleEntryList();
+
+    }
+
+    public List<ByteBuffer> getSamples() {
+        return samples;
+    }
+
+    public SampleDescriptionBox getSampleDescriptionBox() {
+        return origTrack.getSampleDescriptionBox();
+    }
+
+    public List<TimeToSampleBox.Entry> getDecodingTimeEntries() {
+        return origTrack.getDecodingTimeEntries();
+
+    }
+
+    public List<CompositionTimeToSample.Entry> getCompositionTimeEntries() {
+        return origTrack.getCompositionTimeEntries();
+
+    }
+
+    synchronized public long[] getSyncSamples() {
+        return origTrack.getSyncSamples();
+    }
+
+    public List<SampleDependencyTypeBox.Entry> getSampleDependencies() {
+        return origTrack.getSampleDependencies();
+    }
+
+    public TrackMetaData getTrackMetaData() {
+        return origTrack.getTrackMetaData();
+    }
+
+    public String getHandler() {
+        return origTrack.getHandler();
+    }
+
+    public Box getMediaHeaderBox() {
+        return origTrack.getMediaHeaderBox();
+    }
+
+    public SubSampleInformationBox getSubsampleInformationBox() {
+        return origTrack.getSubsampleInformationBox();
+    }
+
+    private class ReplaceASingleEntryList extends AbstractList<ByteBuffer> {
+        @Override
+        public ByteBuffer get(int index) {
+            if (ReplaceSampleTrack.this.sampleNumber == index) {
+                return ReplaceSampleTrack.this.sampleContent;
+            } else {
+                return ReplaceSampleTrack.this.origTrack.getSamples().get(index);
+            }
+        }
+
+        @Override
+        public int size() {
+            return ReplaceSampleTrack.this.origTrack.getSamples().size();
+        }
+    }
+
+}
diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/authoring/tracks/SilenceTrackImpl.java b/isoparser/src/main/java/com/googlecode/mp4parser/authoring/tracks/SilenceTrackImpl.java
new file mode 100644
index 0000000..f74ab3c
--- /dev/null
+++ b/isoparser/src/main/java/com/googlecode/mp4parser/authoring/tracks/SilenceTrackImpl.java
@@ -0,0 +1,98 @@
+package com.googlecode.mp4parser.authoring.tracks;
+
+import com.coremedia.iso.boxes.*;
+import com.googlecode.mp4parser.authoring.Mp4TrackImpl;
+import com.googlecode.mp4parser.authoring.Track;
+import com.googlecode.mp4parser.authoring.TrackMetaData;
+
+import java.nio.ByteBuffer;
+import java.util.Collections;
+import java.util.LinkedList;
+import java.util.List;
+
+/**
+ * This is just a basic idea how things could work but they don't.
+ */
+public class SilenceTrackImpl implements Track {
+    Track source;
+
+    List<ByteBuffer> samples = new LinkedList<ByteBuffer>();
+    TimeToSampleBox.Entry entry;
+
+    public SilenceTrackImpl(Track ofType, long ms) {
+        source = ofType;
+        if ("mp4a".equals(ofType.getSampleDescriptionBox().getSampleEntry().getType())) {
+            long numFrames = getTrackMetaData().getTimescale() * ms / 1000 / 1024;
+            long standZeit = getTrackMetaData().getTimescale() * ms / numFrames / 1000;
+            entry = new TimeToSampleBox.Entry(numFrames, standZeit);
+
+
+            while (numFrames-- > 0) {
+                samples.add((ByteBuffer) ByteBuffer.wrap(new byte[]{
+                        0x21, 0x10, 0x04, 0x60, (byte) 0x8c, 0x1c,
+                }).rewind());
+            }
+
+        } else {
+            throw new RuntimeException("Tracks of type " + ofType.getClass().getSimpleName() + " are not supported");
+        }
+    }
+
+    public SampleDescriptionBox getSampleDescriptionBox() {
+        return source.getSampleDescriptionBox();
+    }
+
+    public List<TimeToSampleBox.Entry> getDecodingTimeEntries() {
+        return Collections.singletonList(entry);
+
+    }
+
+    public TrackMetaData getTrackMetaData() {
+        return source.getTrackMetaData();
+    }
+
+    public String getHandler() {
+        return source.getHandler();
+    }
+
+    public boolean isEnabled() {
+        return source.isEnabled();
+    }
+
+    public boolean isInMovie() {
+        return source.isInMovie();
+    }
+
+    public boolean isInPreview() {
+        return source.isInPreview();
+    }
+
+    public boolean isInPoster() {
+        return source.isInPoster();
+    }
+
+    public List<ByteBuffer> getSamples() {
+        return samples;
+    }
+
+    public Box getMediaHeaderBox() {
+        return source.getMediaHeaderBox();
+    }
+
+    public SubSampleInformationBox getSubsampleInformationBox() {
+        return null;
+    }
+
+    public List<CompositionTimeToSample.Entry> getCompositionTimeEntries() {
+        return null;
+    }
+
+    public long[] getSyncSamples() {
+        return null;
+    }
+
+    public List<SampleDependencyTypeBox.Entry> getSampleDependencies() {
+        return null;
+    }
+
+}
diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/authoring/tracks/TextTrackImpl.java b/isoparser/src/main/java/com/googlecode/mp4parser/authoring/tracks/TextTrackImpl.java
new file mode 100644
index 0000000..3bae143
--- /dev/null
+++ b/isoparser/src/main/java/com/googlecode/mp4parser/authoring/tracks/TextTrackImpl.java
@@ -0,0 +1,165 @@
+/*
+ * Copyright 2012 Sebastian Annies, Hamburg
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.googlecode.mp4parser.authoring.tracks;
+
+import com.coremedia.iso.boxes.*;
+import com.coremedia.iso.boxes.sampleentry.TextSampleEntry;
+import com.googlecode.mp4parser.authoring.AbstractTrack;
+import com.googlecode.mp4parser.authoring.TrackMetaData;
+import com.googlecode.mp4parser.boxes.threegpp26245.FontTableBox;
+
+import java.io.ByteArrayOutputStream;
+import java.io.DataOutputStream;
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.util.Collections;
+import java.util.Date;
+import java.util.LinkedList;
+import java.util.List;
+
+/**
+ *
+ */
+public class TextTrackImpl extends AbstractTrack {
+    TrackMetaData trackMetaData = new TrackMetaData();
+    SampleDescriptionBox sampleDescriptionBox;
+    List<Line> subs = new LinkedList<Line>();
+
+    public List<Line> getSubs() {
+        return subs;
+    }
+
+    public TextTrackImpl() {
+        sampleDescriptionBox = new SampleDescriptionBox();
+        TextSampleEntry tx3g = new TextSampleEntry("tx3g");
+        tx3g.setDataReferenceIndex(1);
+        tx3g.setStyleRecord(new TextSampleEntry.StyleRecord());
+        tx3g.setBoxRecord(new TextSampleEntry.BoxRecord());
+        sampleDescriptionBox.addBox(tx3g);
+
+        FontTableBox ftab = new FontTableBox();
+        ftab.setEntries(Collections.singletonList(new FontTableBox.FontRecord(1, "Serif")));
+
+        tx3g.addBox(ftab);
+
+
+        trackMetaData.setCreationTime(new Date());
+        trackMetaData.setModificationTime(new Date());
+        trackMetaData.setTimescale(1000); // Text tracks use millieseconds
+
+
+    }
+
+
+    public List<ByteBuffer> getSamples() {
+        List<ByteBuffer> samples = new LinkedList<ByteBuffer>();
+        long lastEnd = 0;
+        for (Line sub : subs) {
+            long silentTime = sub.from - lastEnd;
+            if (silentTime > 0) {
+                samples.add(ByteBuffer.wrap(new byte[]{0, 0}));
+            } else if (silentTime < 0) {
+                throw new Error("Subtitle display times may not intersect");
+            }
+            ByteArrayOutputStream baos = new ByteArrayOutputStream();
+            DataOutputStream dos = new DataOutputStream(baos);
+            try {
+                dos.writeShort(sub.text.getBytes("UTF-8").length);
+                dos.write(sub.text.getBytes("UTF-8"));
+                dos.close();
+            } catch (IOException e) {
+                throw new Error("VM is broken. Does not support UTF-8");
+            }
+            samples.add(ByteBuffer.wrap(baos.toByteArray()));
+            lastEnd = sub.to;
+        }
+        return samples;
+    }
+
+    public SampleDescriptionBox getSampleDescriptionBox() {
+        return sampleDescriptionBox;
+    }
+
+    public List<TimeToSampleBox.Entry> getDecodingTimeEntries() {
+        List<TimeToSampleBox.Entry> stts = new LinkedList<TimeToSampleBox.Entry>();
+        long lastEnd = 0;
+        for (Line sub : subs) {
+            long silentTime = sub.from - lastEnd;
+            if (silentTime > 0) {
+                stts.add(new TimeToSampleBox.Entry(1, silentTime));
+            } else if (silentTime < 0) {
+                throw new Error("Subtitle display times may not intersect");
+            }
+            stts.add(new TimeToSampleBox.Entry(1, sub.to - sub.from));
+            lastEnd = sub.to;
+        }
+        return stts;
+    }
+
+    public List<CompositionTimeToSample.Entry> getCompositionTimeEntries() {
+        return null;
+    }
+
+    public long[] getSyncSamples() {
+        return null;
+    }
+
+    public List<SampleDependencyTypeBox.Entry> getSampleDependencies() {
+        return null;
+    }
+
+    public TrackMetaData getTrackMetaData() {
+        return trackMetaData;
+    }
+
+    public String getHandler() {
+        return "sbtl";
+    }
+
+
+    public static class Line {
+        long from;
+        long to;
+        String text;
+
+
+        public Line(long from, long to, String text) {
+            this.from = from;
+            this.to = to;
+            this.text = text;
+        }
+
+        public long getFrom() {
+            return from;
+        }
+
+        public String getText() {
+            return text;
+        }
+
+        public long getTo() {
+            return to;
+        }
+    }
+
+    public AbstractMediaHeaderBox getMediaHeaderBox() {
+        return new NullMediaHeaderBox();
+    }
+
+    public SubSampleInformationBox getSubsampleInformationBox() {
+        return null;
+    }
+}
diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/boxes/.svn/all-wcprops b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/.svn/all-wcprops
new file mode 100644
index 0000000..b39616d
--- /dev/null
+++ b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/.svn/all-wcprops
@@ -0,0 +1,47 @@
+K 25
+svn:wc:ra_dav:version-url
+V 78
+/svn/!svn/ver/770/trunk/isoparser/src/main/java/com/googlecode/mp4parser/boxes
+END
+mp4-boxes.zip
+K 25
+svn:wc:ra_dav:version-url
+V 92
+/svn/!svn/ver/377/trunk/isoparser/src/main/java/com/googlecode/mp4parser/boxes/mp4-boxes.zip
+END
+AC3SpecificBox.java
+K 25
+svn:wc:ra_dav:version-url
+V 98
+/svn/!svn/ver/507/trunk/isoparser/src/main/java/com/googlecode/mp4parser/boxes/AC3SpecificBox.java
+END
+MLPSpecificBox.java
+K 25
+svn:wc:ra_dav:version-url
+V 98
+/svn/!svn/ver/507/trunk/isoparser/src/main/java/com/googlecode/mp4parser/boxes/MLPSpecificBox.java
+END
+DTSSpecificBox.java
+K 25
+svn:wc:ra_dav:version-url
+V 98
+/svn/!svn/ver/507/trunk/isoparser/src/main/java/com/googlecode/mp4parser/boxes/DTSSpecificBox.java
+END
+EC3SpecificBox.java
+K 25
+svn:wc:ra_dav:version-url
+V 98
+/svn/!svn/ver/755/trunk/isoparser/src/main/java/com/googlecode/mp4parser/boxes/EC3SpecificBox.java
+END
+AbstractSampleEncryptionBox.java
+K 25
+svn:wc:ra_dav:version-url
+V 111
+/svn/!svn/ver/744/trunk/isoparser/src/main/java/com/googlecode/mp4parser/boxes/AbstractSampleEncryptionBox.java
+END
+AbstractTrackEncryptionBox.java
+K 25
+svn:wc:ra_dav:version-url
+V 110
+/svn/!svn/ver/507/trunk/isoparser/src/main/java/com/googlecode/mp4parser/boxes/AbstractTrackEncryptionBox.java
+END
diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/boxes/.svn/entries b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/.svn/entries
new file mode 100644
index 0000000..46c357c
--- /dev/null
+++ b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/.svn/entries
@@ -0,0 +1,293 @@
+10
+
+dir
+778
+http://mp4parser.googlecode.com/svn/trunk/isoparser/src/main/java/com/googlecode/mp4parser/boxes
+http://mp4parser.googlecode.com/svn
+
+
+
+2012-08-31T05:20:57.236953Z
+770
+michael.stattmann@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+7decde4b-c250-0410-a0da-51896bc88be6
+
+mp4-boxes.zip
+file
+
+
+
+
+2012-09-14T17:27:51.307230Z
+03585a21ffb96d2fec7af185e1a9d11b
+2012-03-05T23:28:24.666173Z
+377
+Sebastian.Annies@gmail.com
+has-props
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+62700
+
+threegpp26244
+dir
+
+threegpp26245
+dir
+
+basemediaformat
+dir
+
+piff
+dir
+
+MLPSpecificBox.java
+file
+
+
+
+
+2012-09-14T17:27:51.307230Z
+f98e12a419f1111e27ea55eca285239b
+2012-04-21T22:05:38.425329Z
+507
+Sebastian.Annies@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+1868
+
+DTSSpecificBox.java
+file
+
+
+
+
+2012-09-14T17:27:51.307230Z
+7e647845ba17be37607c41420f886df0
+2012-04-21T22:05:38.425329Z
+507
+Sebastian.Annies@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+5730
+
+AbstractTrackEncryptionBox.java
+file
+
+
+
+
+2012-09-14T17:27:51.307230Z
+4621f8e06000ce397b5aae869fce1857
+2012-04-21T22:05:38.425329Z
+507
+Sebastian.Annies@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+2588
+
+mp4
+dir
+
+apple
+dir
+
+AC3SpecificBox.java
+file
+
+
+
+
+2012-09-14T17:27:51.307230Z
+3f4c28d22ec46abb5263d756387a4d5f
+2012-04-21T22:05:38.425329Z
+507
+Sebastian.Annies@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+2661
+
+cenc
+dir
+
+EC3SpecificBox.java
+file
+
+
+
+
+2012-09-14T17:27:51.307230Z
+80bcdd2db3972a22acdfa12a536dd1a5
+2012-08-17T01:13:17.213046Z
+755
+michael.stattmann@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+3860
+
+AbstractSampleEncryptionBox.java
+file
+
+
+
+
+2012-09-14T17:27:51.307230Z
+b729f787e78562982c5f5cf998c58e06
+2012-08-14T13:54:34.186978Z
+744
+Sebastian.Annies@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+10292
+
+ultraviolet
+dir
+
+adobe
+dir
+
diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/boxes/.svn/prop-base/mp4-boxes.zip.svn-base b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/.svn/prop-base/mp4-boxes.zip.svn-base
new file mode 100644
index 0000000..5e9587e
--- /dev/null
+++ b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/.svn/prop-base/mp4-boxes.zip.svn-base
@@ -0,0 +1,5 @@
+K 13
+svn:mime-type
+V 24
+application/octet-stream
+END
diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/boxes/.svn/text-base/AC3SpecificBox.java.svn-base b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/.svn/text-base/AC3SpecificBox.java.svn-base
new file mode 100644
index 0000000..a3006cd
--- /dev/null
+++ b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/.svn/text-base/AC3SpecificBox.java.svn-base
@@ -0,0 +1,119 @@
+package com.googlecode.mp4parser.boxes;
+
+import com.googlecode.mp4parser.AbstractBox;
+import com.googlecode.mp4parser.boxes.mp4.objectdescriptors.BitReaderBuffer;
+import com.googlecode.mp4parser.boxes.mp4.objectdescriptors.BitWriterBuffer;
+
+import java.nio.ByteBuffer;
+
+public class AC3SpecificBox extends AbstractBox {
+    int fscod;
+    int bsid;
+    int bsmod;
+    int acmod;
+    int lfeon;
+    int bitRateCode;
+    int reserved;
+
+    public AC3SpecificBox() {
+        super("dac3");
+    }
+
+    @Override
+    protected long getContentSize() {
+        return 3;
+    }
+
+    @Override
+    public void _parseDetails(ByteBuffer content) {
+        BitReaderBuffer brb = new BitReaderBuffer(content);
+        fscod = brb.readBits(2);
+        bsid = brb.readBits(5);
+        bsmod = brb.readBits(3);
+        acmod = brb.readBits(3);
+        lfeon = brb.readBits(1);
+        bitRateCode = brb.readBits(5);
+        reserved = brb.readBits(5);
+    }
+
+    @Override
+    protected void getContent(ByteBuffer byteBuffer) {
+        BitWriterBuffer bwb = new BitWriterBuffer(byteBuffer);
+        bwb.writeBits(fscod, 2);
+        bwb.writeBits(bsid, 5);
+        bwb.writeBits(bsmod, 3);
+        bwb.writeBits(acmod, 3);
+        bwb.writeBits(lfeon, 1);
+        bwb.writeBits(bitRateCode, 5);
+        bwb.writeBits(reserved, 5);
+    }
+
+    public int getFscod() {
+        return fscod;
+    }
+
+    public void setFscod(int fscod) {
+        this.fscod = fscod;
+    }
+
+    public int getBsid() {
+        return bsid;
+    }
+
+    public void setBsid(int bsid) {
+        this.bsid = bsid;
+    }
+
+    public int getBsmod() {
+        return bsmod;
+    }
+
+    public void setBsmod(int bsmod) {
+        this.bsmod = bsmod;
+    }
+
+    public int getAcmod() {
+        return acmod;
+    }
+
+    public void setAcmod(int acmod) {
+        this.acmod = acmod;
+    }
+
+    public int getLfeon() {
+        return lfeon;
+    }
+
+    public void setLfeon(int lfeon) {
+        this.lfeon = lfeon;
+    }
+
+    public int getBitRateCode() {
+        return bitRateCode;
+    }
+
+    public void setBitRateCode(int bitRateCode) {
+        this.bitRateCode = bitRateCode;
+    }
+
+    public int getReserved() {
+        return reserved;
+    }
+
+    public void setReserved(int reserved) {
+        this.reserved = reserved;
+    }
+
+    @Override
+    public String toString() {
+        return "AC3SpecificBox{" +
+                "fscod=" + fscod +
+                ", bsid=" + bsid +
+                ", bsmod=" + bsmod +
+                ", acmod=" + acmod +
+                ", lfeon=" + lfeon +
+                ", bitRateCode=" + bitRateCode +
+                ", reserved=" + reserved +
+                '}';
+    }
+}
diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/boxes/.svn/text-base/AbstractSampleEncryptionBox.java.svn-base b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/.svn/text-base/AbstractSampleEncryptionBox.java.svn-base
new file mode 100644
index 0000000..7ac4bba
--- /dev/null
+++ b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/.svn/text-base/AbstractSampleEncryptionBox.java.svn-base
@@ -0,0 +1,350 @@
+package com.googlecode.mp4parser.boxes;
+
+import com.coremedia.iso.Hex;
+import com.coremedia.iso.IsoTypeReader;
+import com.coremedia.iso.IsoTypeWriter;
+import com.coremedia.iso.boxes.Box;
+import com.coremedia.iso.boxes.TrackHeaderBox;
+import com.coremedia.iso.boxes.fragment.TrackFragmentHeaderBox;
+import com.googlecode.mp4parser.AbstractFullBox;
+import com.googlecode.mp4parser.boxes.basemediaformat.TrackEncryptionBox;
+import com.googlecode.mp4parser.util.Path;
+
+import java.io.IOException;
+import java.math.BigInteger;
+import java.nio.ByteBuffer;
+import java.nio.channels.WritableByteChannel;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.LinkedList;
+import java.util.List;
+
+
+public abstract class AbstractSampleEncryptionBox extends AbstractFullBox {
+    int algorithmId = -1;
+    int ivSize = -1;
+    byte[] kid = new byte[]{-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1};
+    List<Entry> entries = new LinkedList<Entry>();
+
+    protected AbstractSampleEncryptionBox(String type) {
+        super(type);
+    }
+
+    public int getOffsetToFirstIV() {
+        int offset = (getSize() > (1l << 32) ? 16 : 8);
+        offset += isOverrideTrackEncryptionBoxParameters() ? 20 : 0;
+        offset += 4; //num entries
+        return offset;
+    }
+
+    @Override
+    public void _parseDetails(ByteBuffer content) {
+        parseVersionAndFlags(content);
+        int useThisIvSize = -1;
+        if ((getFlags() & 0x1) > 0) {
+            algorithmId = IsoTypeReader.readUInt24(content);
+            ivSize = IsoTypeReader.readUInt8(content);
+            useThisIvSize = ivSize;
+            kid = new byte[16];
+            content.get(kid);
+        } else {
+            List<Box> tkhds = Path.getPaths(this, "/moov[0]/trak/tkhd");
+            for (Box tkhd : tkhds) {
+                if (((TrackHeaderBox) tkhd).getTrackId() == this.getParent().getBoxes(TrackFragmentHeaderBox.class).get(0).getTrackId()) {
+                    AbstractTrackEncryptionBox tenc = (AbstractTrackEncryptionBox) Path.getPath(tkhd, "../mdia[0]/minf[0]/stbl[0]/stsd[0]/enc.[0]/sinf[0]/schi[0]/tenc[0]");
+                    if (tenc == null) {
+                        tenc = (AbstractTrackEncryptionBox) Path.getPath(tkhd, "../mdia[0]/minf[0]/stbl[0]/stsd[0]/enc.[0]/sinf[0]/schi[0]/uuid[0]");
+                    }
+                    useThisIvSize = tenc.getDefaultIvSize();
+                }
+            }
+        }
+        long numOfEntries = IsoTypeReader.readUInt32(content);
+
+        while (numOfEntries-- > 0) {
+            Entry e = new Entry();
+            e.iv = new byte[useThisIvSize < 0 ? 8 : useThisIvSize];  // default to 8
+            content.get(e.iv);
+            if ((getFlags() & 0x2) > 0) {
+                int numOfPairs = IsoTypeReader.readUInt16(content);
+                e.pairs = new LinkedList<Entry.Pair>();
+                while (numOfPairs-- > 0) {
+                    e.pairs.add(e.createPair(IsoTypeReader.readUInt16(content), IsoTypeReader.readUInt32(content)));
+                }
+            }
+            entries.add(e);
+
+        }
+    }
+
+
+    public int getSampleCount() {
+        return entries.size();
+    }
+
+    public List<Entry> getEntries() {
+        return entries;
+    }
+
+    public void setEntries(List<Entry> entries) {
+        this.entries = entries;
+    }
+
+    public int getAlgorithmId() {
+        return algorithmId;
+    }
+
+    public void setAlgorithmId(int algorithmId) {
+        this.algorithmId = algorithmId;
+    }
+
+    public int getIvSize() {
+        return ivSize;
+    }
+
+    public void setIvSize(int ivSize) {
+        this.ivSize = ivSize;
+    }
+
+    public byte[] getKid() {
+        return kid;
+    }
+
+    public void setKid(byte[] kid) {
+        this.kid = kid;
+    }
+
+
+    public boolean isSubSampleEncryption() {
+        return (getFlags() & 0x2) > 0;
+    }
+
+    public boolean isOverrideTrackEncryptionBoxParameters() {
+        return (getFlags() & 0x1) > 0;
+    }
+
+    public void setSubSampleEncryption(boolean b) {
+        if (b) {
+            setFlags(getFlags() | 0x2);
+        } else {
+            setFlags(getFlags() & (0xffffff ^ 0x2));
+        }
+    }
+
+    public void setOverrideTrackEncryptionBoxParameters(boolean b) {
+        if (b) {
+            setFlags(getFlags() | 0x1);
+        } else {
+            setFlags(getFlags() & (0xffffff ^ 0x1));
+        }
+    }
+
+
+    @Override
+    protected void getContent(ByteBuffer byteBuffer) {
+        writeVersionAndFlags(byteBuffer);
+        if (isOverrideTrackEncryptionBoxParameters()) {
+            IsoTypeWriter.writeUInt24(byteBuffer, algorithmId);
+            IsoTypeWriter.writeUInt8(byteBuffer, ivSize);
+            byteBuffer.put(kid);
+        }
+        IsoTypeWriter.writeUInt32(byteBuffer, entries.size());
+        for (Entry entry : entries) {
+            if (isOverrideTrackEncryptionBoxParameters()) {
+                byte[] ivFull = new byte[ivSize];
+                System.arraycopy(entry.iv, 0, ivFull, ivSize - entry.iv.length, entry.iv.length);
+                byteBuffer.put(ivFull);
+            } else {
+                // just put the iv - i don't know any better
+                byteBuffer.put(entry.iv);
+            }
+            if (isSubSampleEncryption()) {
+                IsoTypeWriter.writeUInt16(byteBuffer, entry.pairs.size());
+                for (Entry.Pair pair : entry.pairs) {
+                    IsoTypeWriter.writeUInt16(byteBuffer, pair.clear);
+                    IsoTypeWriter.writeUInt32(byteBuffer, pair.encrypted);
+                }
+            }
+        }
+    }
+
+    @Override
+    protected long getContentSize() {
+        long contentSize = 4;
+        if (isOverrideTrackEncryptionBoxParameters()) {
+            contentSize += 4;
+            contentSize += kid.length;
+        }
+        contentSize += 4;
+        for (Entry entry : entries) {
+            contentSize += entry.getSize();
+        }
+        return contentSize;
+    }
+
+    @Override
+    public void getBox(WritableByteChannel os) throws IOException {
+        super.getBox(os);
+    }
+
+    public Entry createEntry() {
+        return new Entry();
+    }
+
+    public class Entry {
+        public byte[] iv;
+        public List<Pair> pairs = new LinkedList<Pair>();
+
+        public int getSize() {
+            int size = 0;
+            if (isOverrideTrackEncryptionBoxParameters()) {
+                size = ivSize;
+            } else {
+                size = iv.length;
+            }
+
+
+            if (isSubSampleEncryption()) {
+                size += 2;
+                for (Entry.Pair pair : pairs) {
+                    size += 6;
+                }
+            }
+            return size;
+        }
+
+        public Pair createPair(int clear, long encrypted) {
+            return new Pair(clear, encrypted);
+        }
+
+
+        public class Pair {
+            public int clear;
+            public long encrypted;
+
+            public Pair(int clear, long encrypted) {
+                this.clear = clear;
+                this.encrypted = encrypted;
+            }
+
+            @Override
+            public boolean equals(Object o) {
+                if (this == o) {
+                    return true;
+                }
+                if (o == null || getClass() != o.getClass()) {
+                    return false;
+                }
+
+                Pair pair = (Pair) o;
+
+                if (clear != pair.clear) {
+                    return false;
+                }
+                if (encrypted != pair.encrypted) {
+                    return false;
+                }
+
+                return true;
+            }
+
+            @Override
+            public int hashCode() {
+                int result = clear;
+                result = 31 * result + (int) (encrypted ^ (encrypted >>> 32));
+                return result;
+            }
+
+            @Override
+            public String toString() {
+                return "clr:" + clear + " enc:" + encrypted;
+            }
+        }
+
+
+        @Override
+        public boolean equals(Object o) {
+            if (this == o) {
+                return true;
+            }
+            if (o == null || getClass() != o.getClass()) {
+                return false;
+            }
+
+            Entry entry = (Entry) o;
+
+            if (!new BigInteger(iv).equals(new BigInteger(entry.iv))) {
+                return false;
+            }
+            if (pairs != null ? !pairs.equals(entry.pairs) : entry.pairs != null) {
+                return false;
+            }
+
+            return true;
+        }
+
+        @Override
+        public int hashCode() {
+            int result = iv != null ? Arrays.hashCode(iv) : 0;
+            result = 31 * result + (pairs != null ? pairs.hashCode() : 0);
+            return result;
+        }
+
+        @Override
+        public String toString() {
+            return "Entry{" +
+                    "iv=" + Hex.encodeHex(iv) +
+                    ", pairs=" + pairs +
+                    '}';
+        }
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) {
+            return true;
+        }
+        if (o == null || getClass() != o.getClass()) {
+            return false;
+        }
+
+        AbstractSampleEncryptionBox that = (AbstractSampleEncryptionBox) o;
+
+        if (algorithmId != that.algorithmId) {
+            return false;
+        }
+        if (ivSize != that.ivSize) {
+            return false;
+        }
+        if (entries != null ? !entries.equals(that.entries) : that.entries != null) {
+            return false;
+        }
+        if (!Arrays.equals(kid, that.kid)) {
+            return false;
+        }
+
+        return true;
+    }
+
+    @Override
+    public int hashCode() {
+        int result = algorithmId;
+        result = 31 * result + ivSize;
+        result = 31 * result + (kid != null ? Arrays.hashCode(kid) : 0);
+        result = 31 * result + (entries != null ? entries.hashCode() : 0);
+        return result;
+    }
+
+    public List<Short> getEntrySizes() {
+        List<Short> entrySizes = new ArrayList<Short>(entries.size());
+        for (Entry entry : entries) {
+            short size = (short) entry.iv.length;
+            if (isSubSampleEncryption()) {
+                size += 2; //numPairs
+                size += entry.pairs.size() * 6;
+            }
+            entrySizes.add(size);
+        }
+        return entrySizes;
+    }
+}
diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/boxes/.svn/text-base/AbstractTrackEncryptionBox.java.svn-base b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/.svn/text-base/AbstractTrackEncryptionBox.java.svn-base
new file mode 100644
index 0000000..fe35fde
--- /dev/null
+++ b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/.svn/text-base/AbstractTrackEncryptionBox.java.svn-base
@@ -0,0 +1,93 @@
+package com.googlecode.mp4parser.boxes;
+
+import com.coremedia.iso.IsoTypeReader;
+import com.coremedia.iso.IsoTypeWriter;
+import com.googlecode.mp4parser.AbstractFullBox;
+
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.util.Arrays;
+import java.util.UUID;
+
+/**
+ *
+ */
+public abstract class AbstractTrackEncryptionBox extends AbstractFullBox {
+    int defaultAlgorithmId;
+    int defaultIvSize;
+    byte[] default_KID;
+
+    protected AbstractTrackEncryptionBox(String type) {
+        super(type);
+    }
+
+    public int getDefaultAlgorithmId() {
+        return defaultAlgorithmId;
+    }
+
+    public void setDefaultAlgorithmId(int defaultAlgorithmId) {
+        this.defaultAlgorithmId = defaultAlgorithmId;
+    }
+
+    public int getDefaultIvSize() {
+        return defaultIvSize;
+    }
+
+    public void setDefaultIvSize(int defaultIvSize) {
+        this.defaultIvSize = defaultIvSize;
+    }
+
+    public String getDefault_KID() {
+        ByteBuffer b = ByteBuffer.wrap(default_KID);
+        b.order(ByteOrder.BIG_ENDIAN);
+        return new UUID(b.getLong(), b.getLong()).toString();
+    }
+
+    public void setDefault_KID(byte[] default_KID) {
+        this.default_KID = default_KID;
+    }
+
+    @Override
+    public void _parseDetails(ByteBuffer content) {
+        parseVersionAndFlags(content);
+        defaultAlgorithmId = IsoTypeReader.readUInt24(content);
+        defaultIvSize = IsoTypeReader.readUInt8(content);
+        default_KID = new byte[16];
+        content.get(default_KID);
+    }
+
+    @Override
+    protected void getContent(ByteBuffer byteBuffer) {
+        writeVersionAndFlags(byteBuffer);
+        IsoTypeWriter.writeUInt24(byteBuffer, defaultAlgorithmId);
+        IsoTypeWriter.writeUInt8(byteBuffer, defaultIvSize);
+        byteBuffer.put(default_KID);
+    }
+
+    @Override
+    protected long getContentSize() {
+        return 24;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (o == null || getClass() != o.getClass()) return false;
+
+        AbstractTrackEncryptionBox that = (AbstractTrackEncryptionBox) o;
+
+        if (defaultAlgorithmId != that.defaultAlgorithmId) return false;
+        if (defaultIvSize != that.defaultIvSize) return false;
+        if (!Arrays.equals(default_KID, that.default_KID)) return false;
+
+        return true;
+    }
+
+    @Override
+    public int hashCode() {
+        int result = defaultAlgorithmId;
+        result = 31 * result + defaultIvSize;
+        result = 31 * result + (default_KID != null ? Arrays.hashCode(default_KID) : 0);
+        return result;
+    }
+}
diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/boxes/.svn/text-base/DTSSpecificBox.java.svn-base b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/.svn/text-base/DTSSpecificBox.java.svn-base
new file mode 100644
index 0000000..a4cb346
--- /dev/null
+++ b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/.svn/text-base/DTSSpecificBox.java.svn-base
@@ -0,0 +1,217 @@
+package com.googlecode.mp4parser.boxes;
+
+import com.coremedia.iso.IsoTypeReader;
+import com.coremedia.iso.IsoTypeWriter;
+import com.googlecode.mp4parser.AbstractBox;
+import com.googlecode.mp4parser.boxes.mp4.objectdescriptors.BitReaderBuffer;
+import com.googlecode.mp4parser.boxes.mp4.objectdescriptors.BitWriterBuffer;
+
+import java.nio.ByteBuffer;
+
+/**
+ * Created by IntelliJ IDEA.
+ * User: magnus
+ * Date: 2012-03-09
+ * Time: 16:11
+ * To change this template use File | Settings | File Templates.
+ */
+public class DTSSpecificBox extends AbstractBox {
+    
+    long DTSSamplingFrequency;
+    long maxBitRate;
+    long avgBitRate;
+    int pcmSampleDepth;
+    int frameDuration;
+    int streamConstruction;
+    int coreLFEPresent;
+    int coreLayout;
+    int coreSize;
+    int stereoDownmix;
+    int representationType;
+    int channelLayout;
+    int multiAssetFlag;
+    int LBRDurationMod;
+    int reservedBoxPresent;
+    int reserved;
+
+    public DTSSpecificBox() {
+        super("ddts");
+    }
+
+    @Override
+    protected long getContentSize() {
+        return 20;
+    }
+
+    @Override
+    public void _parseDetails(ByteBuffer content) {
+        DTSSamplingFrequency = IsoTypeReader.readUInt32(content);
+        maxBitRate = IsoTypeReader.readUInt32(content);
+        avgBitRate = IsoTypeReader.readUInt32(content);
+        pcmSampleDepth = IsoTypeReader.readUInt8(content);
+        BitReaderBuffer brb = new BitReaderBuffer(content);
+        frameDuration = brb.readBits(2);
+        streamConstruction = brb.readBits(5);
+        coreLFEPresent = brb.readBits(1);
+        coreLayout = brb.readBits(6);
+        coreSize = brb.readBits(14);
+        stereoDownmix = brb.readBits(1);
+        representationType = brb.readBits(3);
+        channelLayout = brb.readBits(16);
+        multiAssetFlag = brb.readBits(1);
+        LBRDurationMod = brb.readBits(1);
+        reservedBoxPresent = brb.readBits(1);
+        reserved = brb.readBits(5);
+
+    }
+
+    @Override
+    protected void getContent(ByteBuffer byteBuffer) {
+        IsoTypeWriter.writeUInt32(byteBuffer, DTSSamplingFrequency);
+        IsoTypeWriter.writeUInt32(byteBuffer, maxBitRate);
+        IsoTypeWriter.writeUInt32(byteBuffer, avgBitRate);
+        IsoTypeWriter.writeUInt8(byteBuffer, pcmSampleDepth);
+        BitWriterBuffer bwb = new BitWriterBuffer(byteBuffer);
+        bwb.writeBits(frameDuration, 2);
+        bwb.writeBits(streamConstruction, 5);
+        bwb.writeBits(coreLFEPresent, 1);
+        bwb.writeBits(coreLayout, 6);
+        bwb.writeBits(coreSize, 14);
+        bwb.writeBits(stereoDownmix, 1);
+        bwb.writeBits(representationType, 3);
+        bwb.writeBits(channelLayout, 16);
+        bwb.writeBits(multiAssetFlag, 1);
+        bwb.writeBits(LBRDurationMod, 1);
+        bwb.writeBits(reservedBoxPresent, 1);
+        bwb.writeBits(reserved, 5);
+
+    }
+
+    public long getAvgBitRate() {
+        return avgBitRate;
+    }
+
+    public void setAvgBitRate(long avgBitRate) {
+        this.avgBitRate = avgBitRate;
+    }
+
+    public long getDTSSamplingFrequency() {
+        return DTSSamplingFrequency;
+    }
+
+    public void setDTSSamplingFrequency(long DTSSamplingFrequency) {
+        this.DTSSamplingFrequency = DTSSamplingFrequency;
+    }
+
+    public long getMaxBitRate() {
+        return maxBitRate;
+    }
+
+    public void setMaxBitRate(long maxBitRate) {
+        this.maxBitRate = maxBitRate;
+    }
+
+    public int getPcmSampleDepth() {
+        return pcmSampleDepth;
+    }
+
+    public void setPcmSampleDepth(int pcmSampleDepth) {
+        this.pcmSampleDepth = pcmSampleDepth;
+    }
+
+    public int getFrameDuration() {
+        return frameDuration;
+    }
+
+    public void setFrameDuration(int frameDuration) {
+        this.frameDuration = frameDuration;
+    }
+
+    public int getStreamConstruction() {
+        return streamConstruction;
+    }
+
+    public void setStreamConstruction(int streamConstruction) {
+        this.streamConstruction = streamConstruction;
+    }
+
+    public int getCoreLFEPresent() {
+        return coreLFEPresent;
+    }
+
+    public void setCoreLFEPresent(int coreLFEPresent) {
+        this.coreLFEPresent = coreLFEPresent;
+    }
+
+    public int getCoreLayout() {
+        return coreLayout;
+    }
+
+    public void setCoreLayout(int coreLayout) {
+        this.coreLayout = coreLayout;
+    }
+
+    public int getCoreSize() {
+        return coreSize;
+    }
+
+    public void setCoreSize(int coreSize) {
+        this.coreSize = coreSize;
+    }
+
+    public int getStereoDownmix() {
+        return stereoDownmix;
+    }
+
+    public void setStereoDownmix(int stereoDownmix) {
+        this.stereoDownmix = stereoDownmix;
+    }
+
+    public int getRepresentationType() {
+        return representationType;
+    }
+
+    public void setRepresentationType(int representationType) {
+        this.representationType = representationType;
+    }
+
+    public int getChannelLayout() {
+        return channelLayout;
+    }
+
+    public void setChannelLayout(int channelLayout) {
+        this.channelLayout = channelLayout;
+    }
+
+    public int getMultiAssetFlag() {
+        return multiAssetFlag;
+    }
+
+    public void setMultiAssetFlag(int multiAssetFlag) {
+        this.multiAssetFlag = multiAssetFlag;
+    }
+
+    public int getLBRDurationMod() {
+        return LBRDurationMod;
+    }
+
+    public void setLBRDurationMod(int LBRDurationMod) {
+        this.LBRDurationMod = LBRDurationMod;
+    }
+
+    public int getReserved() {
+        return reserved;
+    }
+
+    public void setReserved(int reserved) {
+        this.reserved = reserved;
+    }
+
+    public int getReservedBoxPresent() {
+        return reservedBoxPresent;
+    }
+
+    public void setReservedBoxPresent(int reservedBoxPresent) {
+        this.reservedBoxPresent = reservedBoxPresent;
+    }
+}
diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/boxes/.svn/text-base/EC3SpecificBox.java.svn-base b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/.svn/text-base/EC3SpecificBox.java.svn-base
new file mode 100644
index 0000000..412db04
--- /dev/null
+++ b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/.svn/text-base/EC3SpecificBox.java.svn-base
@@ -0,0 +1,140 @@
+package com.googlecode.mp4parser.boxes;
+
+import com.googlecode.mp4parser.AbstractBox;
+import com.googlecode.mp4parser.boxes.mp4.objectdescriptors.BitReaderBuffer;
+import com.googlecode.mp4parser.boxes.mp4.objectdescriptors.BitWriterBuffer;
+
+import java.nio.ByteBuffer;
+import java.util.LinkedList;
+import java.util.List;
+
+/**
+ *
+ */
+public class EC3SpecificBox extends AbstractBox {
+    List<Entry> entries = new LinkedList<Entry>();
+    int dataRate;
+    int numIndSub;
+
+    public EC3SpecificBox() {
+        super("dec3");
+    }
+
+    @Override
+    public long getContentSize() {
+        long size = 2;
+        for (Entry entry : entries) {
+            if (entry.num_dep_sub > 0) {
+                size += 4;
+            } else {
+                size += 3;
+            }
+        }
+        return size;
+    }
+
+    @Override
+    public void _parseDetails(ByteBuffer content) {
+        BitReaderBuffer brb = new BitReaderBuffer(content);
+        dataRate = brb.readBits(13);
+        numIndSub = brb.readBits(3) + 1;
+        // This field indicates the number of independent substreams that are present in the Enhanced AC-3 bitstream. The value
+        // of this field is one less than the number of independent substreams present.
+
+
+        for (int i = 0; i < numIndSub; i++) {
+            Entry e = new Entry();
+            e.fscod = brb.readBits(2);
+            e.bsid = brb.readBits(5);
+            e.bsmod = brb.readBits(5);
+            e.acmod = brb.readBits(3);
+            e.lfeon = brb.readBits(1);
+            e.reserved = brb.readBits(3);
+            e.num_dep_sub = brb.readBits(4);
+            if (e.num_dep_sub > 0) {
+                e.chan_loc = brb.readBits(9);
+            } else {
+                e.reserved2 = brb.readBits(1);
+            }
+            entries.add(e);
+        }
+    }
+
+    @Override
+    public void getContent(ByteBuffer byteBuffer) {
+        BitWriterBuffer bwb = new BitWriterBuffer(byteBuffer);
+        bwb.writeBits(dataRate, 13);
+        bwb.writeBits(entries.size() - 1, 3);
+        for (Entry e : entries) {
+            bwb.writeBits(e.fscod, 2);
+            bwb.writeBits(e.bsid, 5);
+            bwb.writeBits(e.bsmod, 5);
+            bwb.writeBits(e.acmod, 3);
+            bwb.writeBits(e.lfeon, 1);
+            bwb.writeBits(e.reserved, 3);
+            bwb.writeBits(e.num_dep_sub, 4);
+            if (e.num_dep_sub > 0) {
+                bwb.writeBits(e.chan_loc, 9);
+            } else {
+                bwb.writeBits(e.reserved2, 1);
+            }
+        }
+    }
+
+
+    public List<Entry> getEntries() {
+        return entries;
+    }
+
+    public void setEntries(List<Entry> entries) {
+        this.entries = entries;
+    }
+
+    public void addEntry(Entry entry) {
+        this.entries.add(entry);
+    }
+
+    public int getDataRate() {
+        return dataRate;
+    }
+
+    public void setDataRate(int dataRate) {
+        this.dataRate = dataRate;
+    }
+
+    public int getNumIndSub() {
+        return numIndSub;
+    }
+
+    public void setNumIndSub(int numIndSub) {
+        this.numIndSub = numIndSub;
+    }
+
+    public static class Entry {
+        public int fscod;
+        public int bsid;
+        public int bsmod;
+        public int acmod;
+        public int lfeon;
+        public int reserved;
+        public int num_dep_sub;
+        public int chan_loc;
+        public int reserved2;
+
+
+        @Override
+        public String toString() {
+            return "Entry{" +
+                    "fscod=" + fscod +
+                    ", bsid=" + bsid +
+                    ", bsmod=" + bsmod +
+                    ", acmod=" + acmod +
+                    ", lfeon=" + lfeon +
+                    ", reserved=" + reserved +
+                    ", num_dep_sub=" + num_dep_sub +
+                    ", chan_loc=" + chan_loc +
+                    ", reserved2=" + reserved2 +
+                    '}';
+        }
+    }
+}
diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/boxes/.svn/text-base/MLPSpecificBox.java.svn-base b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/.svn/text-base/MLPSpecificBox.java.svn-base
new file mode 100644
index 0000000..fe6f0d8
--- /dev/null
+++ b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/.svn/text-base/MLPSpecificBox.java.svn-base
@@ -0,0 +1,76 @@
+package com.googlecode.mp4parser.boxes;
+
+import com.googlecode.mp4parser.AbstractBox;
+import com.googlecode.mp4parser.boxes.mp4.objectdescriptors.BitReaderBuffer;
+import com.googlecode.mp4parser.boxes.mp4.objectdescriptors.BitWriterBuffer;
+
+import java.nio.ByteBuffer;
+
+
+public class MLPSpecificBox extends AbstractBox {
+
+    int format_info;
+    int peak_data_rate;
+    int reserved;
+    int reserved2;
+
+    public MLPSpecificBox() {
+        super("dmlp");
+    }
+
+    @Override
+    protected long getContentSize() {
+        return 10;
+    }
+
+    @Override
+    public void _parseDetails(ByteBuffer content) {
+        BitReaderBuffer brb = new BitReaderBuffer(content);
+        format_info = brb.readBits(32);
+        peak_data_rate = brb.readBits(15);
+        reserved = brb.readBits(1);
+        reserved2 = brb.readBits(32);
+    }
+
+    @Override
+    protected void getContent(ByteBuffer byteBuffer) {
+        BitWriterBuffer bwb = new BitWriterBuffer(byteBuffer);
+        bwb.writeBits(format_info, 32);
+        bwb.writeBits(peak_data_rate, 15);
+        bwb.writeBits(reserved, 1);
+        bwb.writeBits(reserved2, 32);
+        //To change body of implemented methods use File | Settings | File Templates.
+    }
+
+    public int getFormat_info() {
+        return format_info;
+    }
+
+    public void setFormat_info(int format_info) {
+        this.format_info = format_info;
+    }
+
+    public int getPeak_data_rate() {
+        return peak_data_rate;
+    }
+
+    public void setPeak_data_rate(int peak_data_rate) {
+        this.peak_data_rate = peak_data_rate;
+    }
+
+    public int getReserved() {
+        return reserved;
+    }
+
+    public void setReserved(int reserved) {
+        this.reserved = reserved;
+    }
+
+    public int getReserved2() {
+        return reserved2;
+    }
+
+    public void setReserved2(int reserved2) {
+        this.reserved2 = reserved2;
+    }
+}
diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/boxes/.svn/text-base/mp4-boxes.zip.svn-base b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/.svn/text-base/mp4-boxes.zip.svn-base
new file mode 100644
index 0000000..c9bcf8b
--- /dev/null
+++ b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/.svn/text-base/mp4-boxes.zip.svn-base
Binary files differ
diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/boxes/AC3SpecificBox.java b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/AC3SpecificBox.java
new file mode 100644
index 0000000..a3006cd
--- /dev/null
+++ b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/AC3SpecificBox.java
@@ -0,0 +1,119 @@
+package com.googlecode.mp4parser.boxes;
+
+import com.googlecode.mp4parser.AbstractBox;
+import com.googlecode.mp4parser.boxes.mp4.objectdescriptors.BitReaderBuffer;
+import com.googlecode.mp4parser.boxes.mp4.objectdescriptors.BitWriterBuffer;
+
+import java.nio.ByteBuffer;
+
+public class AC3SpecificBox extends AbstractBox {
+    int fscod;
+    int bsid;
+    int bsmod;
+    int acmod;
+    int lfeon;
+    int bitRateCode;
+    int reserved;
+
+    public AC3SpecificBox() {
+        super("dac3");
+    }
+
+    @Override
+    protected long getContentSize() {
+        return 3;
+    }
+
+    @Override
+    public void _parseDetails(ByteBuffer content) {
+        BitReaderBuffer brb = new BitReaderBuffer(content);
+        fscod = brb.readBits(2);
+        bsid = brb.readBits(5);
+        bsmod = brb.readBits(3);
+        acmod = brb.readBits(3);
+        lfeon = brb.readBits(1);
+        bitRateCode = brb.readBits(5);
+        reserved = brb.readBits(5);
+    }
+
+    @Override
+    protected void getContent(ByteBuffer byteBuffer) {
+        BitWriterBuffer bwb = new BitWriterBuffer(byteBuffer);
+        bwb.writeBits(fscod, 2);
+        bwb.writeBits(bsid, 5);
+        bwb.writeBits(bsmod, 3);
+        bwb.writeBits(acmod, 3);
+        bwb.writeBits(lfeon, 1);
+        bwb.writeBits(bitRateCode, 5);
+        bwb.writeBits(reserved, 5);
+    }
+
+    public int getFscod() {
+        return fscod;
+    }
+
+    public void setFscod(int fscod) {
+        this.fscod = fscod;
+    }
+
+    public int getBsid() {
+        return bsid;
+    }
+
+    public void setBsid(int bsid) {
+        this.bsid = bsid;
+    }
+
+    public int getBsmod() {
+        return bsmod;
+    }
+
+    public void setBsmod(int bsmod) {
+        this.bsmod = bsmod;
+    }
+
+    public int getAcmod() {
+        return acmod;
+    }
+
+    public void setAcmod(int acmod) {
+        this.acmod = acmod;
+    }
+
+    public int getLfeon() {
+        return lfeon;
+    }
+
+    public void setLfeon(int lfeon) {
+        this.lfeon = lfeon;
+    }
+
+    public int getBitRateCode() {
+        return bitRateCode;
+    }
+
+    public void setBitRateCode(int bitRateCode) {
+        this.bitRateCode = bitRateCode;
+    }
+
+    public int getReserved() {
+        return reserved;
+    }
+
+    public void setReserved(int reserved) {
+        this.reserved = reserved;
+    }
+
+    @Override
+    public String toString() {
+        return "AC3SpecificBox{" +
+                "fscod=" + fscod +
+                ", bsid=" + bsid +
+                ", bsmod=" + bsmod +
+                ", acmod=" + acmod +
+                ", lfeon=" + lfeon +
+                ", bitRateCode=" + bitRateCode +
+                ", reserved=" + reserved +
+                '}';
+    }
+}
diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/boxes/AbstractSampleEncryptionBox.java b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/AbstractSampleEncryptionBox.java
new file mode 100644
index 0000000..7ac4bba
--- /dev/null
+++ b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/AbstractSampleEncryptionBox.java
@@ -0,0 +1,350 @@
+package com.googlecode.mp4parser.boxes;
+
+import com.coremedia.iso.Hex;
+import com.coremedia.iso.IsoTypeReader;
+import com.coremedia.iso.IsoTypeWriter;
+import com.coremedia.iso.boxes.Box;
+import com.coremedia.iso.boxes.TrackHeaderBox;
+import com.coremedia.iso.boxes.fragment.TrackFragmentHeaderBox;
+import com.googlecode.mp4parser.AbstractFullBox;
+import com.googlecode.mp4parser.boxes.basemediaformat.TrackEncryptionBox;
+import com.googlecode.mp4parser.util.Path;
+
+import java.io.IOException;
+import java.math.BigInteger;
+import java.nio.ByteBuffer;
+import java.nio.channels.WritableByteChannel;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.LinkedList;
+import java.util.List;
+
+
+public abstract class AbstractSampleEncryptionBox extends AbstractFullBox {
+    int algorithmId = -1;
+    int ivSize = -1;
+    byte[] kid = new byte[]{-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1};
+    List<Entry> entries = new LinkedList<Entry>();
+
+    protected AbstractSampleEncryptionBox(String type) {
+        super(type);
+    }
+
+    public int getOffsetToFirstIV() {
+        int offset = (getSize() > (1l << 32) ? 16 : 8);
+        offset += isOverrideTrackEncryptionBoxParameters() ? 20 : 0;
+        offset += 4; //num entries
+        return offset;
+    }
+
+    @Override
+    public void _parseDetails(ByteBuffer content) {
+        parseVersionAndFlags(content);
+        int useThisIvSize = -1;
+        if ((getFlags() & 0x1) > 0) {
+            algorithmId = IsoTypeReader.readUInt24(content);
+            ivSize = IsoTypeReader.readUInt8(content);
+            useThisIvSize = ivSize;
+            kid = new byte[16];
+            content.get(kid);
+        } else {
+            List<Box> tkhds = Path.getPaths(this, "/moov[0]/trak/tkhd");
+            for (Box tkhd : tkhds) {
+                if (((TrackHeaderBox) tkhd).getTrackId() == this.getParent().getBoxes(TrackFragmentHeaderBox.class).get(0).getTrackId()) {
+                    AbstractTrackEncryptionBox tenc = (AbstractTrackEncryptionBox) Path.getPath(tkhd, "../mdia[0]/minf[0]/stbl[0]/stsd[0]/enc.[0]/sinf[0]/schi[0]/tenc[0]");
+                    if (tenc == null) {
+                        tenc = (AbstractTrackEncryptionBox) Path.getPath(tkhd, "../mdia[0]/minf[0]/stbl[0]/stsd[0]/enc.[0]/sinf[0]/schi[0]/uuid[0]");
+                    }
+                    useThisIvSize = tenc.getDefaultIvSize();
+                }
+            }
+        }
+        long numOfEntries = IsoTypeReader.readUInt32(content);
+
+        while (numOfEntries-- > 0) {
+            Entry e = new Entry();
+            e.iv = new byte[useThisIvSize < 0 ? 8 : useThisIvSize];  // default to 8
+            content.get(e.iv);
+            if ((getFlags() & 0x2) > 0) {
+                int numOfPairs = IsoTypeReader.readUInt16(content);
+                e.pairs = new LinkedList<Entry.Pair>();
+                while (numOfPairs-- > 0) {
+                    e.pairs.add(e.createPair(IsoTypeReader.readUInt16(content), IsoTypeReader.readUInt32(content)));
+                }
+            }
+            entries.add(e);
+
+        }
+    }
+
+
+    public int getSampleCount() {
+        return entries.size();
+    }
+
+    public List<Entry> getEntries() {
+        return entries;
+    }
+
+    public void setEntries(List<Entry> entries) {
+        this.entries = entries;
+    }
+
+    public int getAlgorithmId() {
+        return algorithmId;
+    }
+
+    public void setAlgorithmId(int algorithmId) {
+        this.algorithmId = algorithmId;
+    }
+
+    public int getIvSize() {
+        return ivSize;
+    }
+
+    public void setIvSize(int ivSize) {
+        this.ivSize = ivSize;
+    }
+
+    public byte[] getKid() {
+        return kid;
+    }
+
+    public void setKid(byte[] kid) {
+        this.kid = kid;
+    }
+
+
+    public boolean isSubSampleEncryption() {
+        return (getFlags() & 0x2) > 0;
+    }
+
+    public boolean isOverrideTrackEncryptionBoxParameters() {
+        return (getFlags() & 0x1) > 0;
+    }
+
+    public void setSubSampleEncryption(boolean b) {
+        if (b) {
+            setFlags(getFlags() | 0x2);
+        } else {
+            setFlags(getFlags() & (0xffffff ^ 0x2));
+        }
+    }
+
+    public void setOverrideTrackEncryptionBoxParameters(boolean b) {
+        if (b) {
+            setFlags(getFlags() | 0x1);
+        } else {
+            setFlags(getFlags() & (0xffffff ^ 0x1));
+        }
+    }
+
+
+    @Override
+    protected void getContent(ByteBuffer byteBuffer) {
+        writeVersionAndFlags(byteBuffer);
+        if (isOverrideTrackEncryptionBoxParameters()) {
+            IsoTypeWriter.writeUInt24(byteBuffer, algorithmId);
+            IsoTypeWriter.writeUInt8(byteBuffer, ivSize);
+            byteBuffer.put(kid);
+        }
+        IsoTypeWriter.writeUInt32(byteBuffer, entries.size());
+        for (Entry entry : entries) {
+            if (isOverrideTrackEncryptionBoxParameters()) {
+                byte[] ivFull = new byte[ivSize];
+                System.arraycopy(entry.iv, 0, ivFull, ivSize - entry.iv.length, entry.iv.length);
+                byteBuffer.put(ivFull);
+            } else {
+                // just put the iv - i don't know any better
+                byteBuffer.put(entry.iv);
+            }
+            if (isSubSampleEncryption()) {
+                IsoTypeWriter.writeUInt16(byteBuffer, entry.pairs.size());
+                for (Entry.Pair pair : entry.pairs) {
+                    IsoTypeWriter.writeUInt16(byteBuffer, pair.clear);
+                    IsoTypeWriter.writeUInt32(byteBuffer, pair.encrypted);
+                }
+            }
+        }
+    }
+
+    @Override
+    protected long getContentSize() {
+        long contentSize = 4;
+        if (isOverrideTrackEncryptionBoxParameters()) {
+            contentSize += 4;
+            contentSize += kid.length;
+        }
+        contentSize += 4;
+        for (Entry entry : entries) {
+            contentSize += entry.getSize();
+        }
+        return contentSize;
+    }
+
+    @Override
+    public void getBox(WritableByteChannel os) throws IOException {
+        super.getBox(os);
+    }
+
+    public Entry createEntry() {
+        return new Entry();
+    }
+
+    public class Entry {
+        public byte[] iv;
+        public List<Pair> pairs = new LinkedList<Pair>();
+
+        public int getSize() {
+            int size = 0;
+            if (isOverrideTrackEncryptionBoxParameters()) {
+                size = ivSize;
+            } else {
+                size = iv.length;
+            }
+
+
+            if (isSubSampleEncryption()) {
+                size += 2;
+                for (Entry.Pair pair : pairs) {
+                    size += 6;
+                }
+            }
+            return size;
+        }
+
+        public Pair createPair(int clear, long encrypted) {
+            return new Pair(clear, encrypted);
+        }
+
+
+        public class Pair {
+            public int clear;
+            public long encrypted;
+
+            public Pair(int clear, long encrypted) {
+                this.clear = clear;
+                this.encrypted = encrypted;
+            }
+
+            @Override
+            public boolean equals(Object o) {
+                if (this == o) {
+                    return true;
+                }
+                if (o == null || getClass() != o.getClass()) {
+                    return false;
+                }
+
+                Pair pair = (Pair) o;
+
+                if (clear != pair.clear) {
+                    return false;
+                }
+                if (encrypted != pair.encrypted) {
+                    return false;
+                }
+
+                return true;
+            }
+
+            @Override
+            public int hashCode() {
+                int result = clear;
+                result = 31 * result + (int) (encrypted ^ (encrypted >>> 32));
+                return result;
+            }
+
+            @Override
+            public String toString() {
+                return "clr:" + clear + " enc:" + encrypted;
+            }
+        }
+
+
+        @Override
+        public boolean equals(Object o) {
+            if (this == o) {
+                return true;
+            }
+            if (o == null || getClass() != o.getClass()) {
+                return false;
+            }
+
+            Entry entry = (Entry) o;
+
+            if (!new BigInteger(iv).equals(new BigInteger(entry.iv))) {
+                return false;
+            }
+            if (pairs != null ? !pairs.equals(entry.pairs) : entry.pairs != null) {
+                return false;
+            }
+
+            return true;
+        }
+
+        @Override
+        public int hashCode() {
+            int result = iv != null ? Arrays.hashCode(iv) : 0;
+            result = 31 * result + (pairs != null ? pairs.hashCode() : 0);
+            return result;
+        }
+
+        @Override
+        public String toString() {
+            return "Entry{" +
+                    "iv=" + Hex.encodeHex(iv) +
+                    ", pairs=" + pairs +
+                    '}';
+        }
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) {
+            return true;
+        }
+        if (o == null || getClass() != o.getClass()) {
+            return false;
+        }
+
+        AbstractSampleEncryptionBox that = (AbstractSampleEncryptionBox) o;
+
+        if (algorithmId != that.algorithmId) {
+            return false;
+        }
+        if (ivSize != that.ivSize) {
+            return false;
+        }
+        if (entries != null ? !entries.equals(that.entries) : that.entries != null) {
+            return false;
+        }
+        if (!Arrays.equals(kid, that.kid)) {
+            return false;
+        }
+
+        return true;
+    }
+
+    @Override
+    public int hashCode() {
+        int result = algorithmId;
+        result = 31 * result + ivSize;
+        result = 31 * result + (kid != null ? Arrays.hashCode(kid) : 0);
+        result = 31 * result + (entries != null ? entries.hashCode() : 0);
+        return result;
+    }
+
+    public List<Short> getEntrySizes() {
+        List<Short> entrySizes = new ArrayList<Short>(entries.size());
+        for (Entry entry : entries) {
+            short size = (short) entry.iv.length;
+            if (isSubSampleEncryption()) {
+                size += 2; //numPairs
+                size += entry.pairs.size() * 6;
+            }
+            entrySizes.add(size);
+        }
+        return entrySizes;
+    }
+}
diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/boxes/AbstractTrackEncryptionBox.java b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/AbstractTrackEncryptionBox.java
new file mode 100644
index 0000000..fe35fde
--- /dev/null
+++ b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/AbstractTrackEncryptionBox.java
@@ -0,0 +1,93 @@
+package com.googlecode.mp4parser.boxes;
+
+import com.coremedia.iso.IsoTypeReader;
+import com.coremedia.iso.IsoTypeWriter;
+import com.googlecode.mp4parser.AbstractFullBox;
+
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.util.Arrays;
+import java.util.UUID;
+
+/**
+ *
+ */
+public abstract class AbstractTrackEncryptionBox extends AbstractFullBox {
+    int defaultAlgorithmId;
+    int defaultIvSize;
+    byte[] default_KID;
+
+    protected AbstractTrackEncryptionBox(String type) {
+        super(type);
+    }
+
+    public int getDefaultAlgorithmId() {
+        return defaultAlgorithmId;
+    }
+
+    public void setDefaultAlgorithmId(int defaultAlgorithmId) {
+        this.defaultAlgorithmId = defaultAlgorithmId;
+    }
+
+    public int getDefaultIvSize() {
+        return defaultIvSize;
+    }
+
+    public void setDefaultIvSize(int defaultIvSize) {
+        this.defaultIvSize = defaultIvSize;
+    }
+
+    public String getDefault_KID() {
+        ByteBuffer b = ByteBuffer.wrap(default_KID);
+        b.order(ByteOrder.BIG_ENDIAN);
+        return new UUID(b.getLong(), b.getLong()).toString();
+    }
+
+    public void setDefault_KID(byte[] default_KID) {
+        this.default_KID = default_KID;
+    }
+
+    @Override
+    public void _parseDetails(ByteBuffer content) {
+        parseVersionAndFlags(content);
+        defaultAlgorithmId = IsoTypeReader.readUInt24(content);
+        defaultIvSize = IsoTypeReader.readUInt8(content);
+        default_KID = new byte[16];
+        content.get(default_KID);
+    }
+
+    @Override
+    protected void getContent(ByteBuffer byteBuffer) {
+        writeVersionAndFlags(byteBuffer);
+        IsoTypeWriter.writeUInt24(byteBuffer, defaultAlgorithmId);
+        IsoTypeWriter.writeUInt8(byteBuffer, defaultIvSize);
+        byteBuffer.put(default_KID);
+    }
+
+    @Override
+    protected long getContentSize() {
+        return 24;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (o == null || getClass() != o.getClass()) return false;
+
+        AbstractTrackEncryptionBox that = (AbstractTrackEncryptionBox) o;
+
+        if (defaultAlgorithmId != that.defaultAlgorithmId) return false;
+        if (defaultIvSize != that.defaultIvSize) return false;
+        if (!Arrays.equals(default_KID, that.default_KID)) return false;
+
+        return true;
+    }
+
+    @Override
+    public int hashCode() {
+        int result = defaultAlgorithmId;
+        result = 31 * result + defaultIvSize;
+        result = 31 * result + (default_KID != null ? Arrays.hashCode(default_KID) : 0);
+        return result;
+    }
+}
diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/boxes/DTSSpecificBox.java b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/DTSSpecificBox.java
new file mode 100644
index 0000000..a4cb346
--- /dev/null
+++ b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/DTSSpecificBox.java
@@ -0,0 +1,217 @@
+package com.googlecode.mp4parser.boxes;
+
+import com.coremedia.iso.IsoTypeReader;
+import com.coremedia.iso.IsoTypeWriter;
+import com.googlecode.mp4parser.AbstractBox;
+import com.googlecode.mp4parser.boxes.mp4.objectdescriptors.BitReaderBuffer;
+import com.googlecode.mp4parser.boxes.mp4.objectdescriptors.BitWriterBuffer;
+
+import java.nio.ByteBuffer;
+
+/**
+ * Created by IntelliJ IDEA.
+ * User: magnus
+ * Date: 2012-03-09
+ * Time: 16:11
+ * To change this template use File | Settings | File Templates.
+ */
+public class DTSSpecificBox extends AbstractBox {
+    
+    long DTSSamplingFrequency;
+    long maxBitRate;
+    long avgBitRate;
+    int pcmSampleDepth;
+    int frameDuration;
+    int streamConstruction;
+    int coreLFEPresent;
+    int coreLayout;
+    int coreSize;
+    int stereoDownmix;
+    int representationType;
+    int channelLayout;
+    int multiAssetFlag;
+    int LBRDurationMod;
+    int reservedBoxPresent;
+    int reserved;
+
+    public DTSSpecificBox() {
+        super("ddts");
+    }
+
+    @Override
+    protected long getContentSize() {
+        return 20;
+    }
+
+    @Override
+    public void _parseDetails(ByteBuffer content) {
+        DTSSamplingFrequency = IsoTypeReader.readUInt32(content);
+        maxBitRate = IsoTypeReader.readUInt32(content);
+        avgBitRate = IsoTypeReader.readUInt32(content);
+        pcmSampleDepth = IsoTypeReader.readUInt8(content);
+        BitReaderBuffer brb = new BitReaderBuffer(content);
+        frameDuration = brb.readBits(2);
+        streamConstruction = brb.readBits(5);
+        coreLFEPresent = brb.readBits(1);
+        coreLayout = brb.readBits(6);
+        coreSize = brb.readBits(14);
+        stereoDownmix = brb.readBits(1);
+        representationType = brb.readBits(3);
+        channelLayout = brb.readBits(16);
+        multiAssetFlag = brb.readBits(1);
+        LBRDurationMod = brb.readBits(1);
+        reservedBoxPresent = brb.readBits(1);
+        reserved = brb.readBits(5);
+
+    }
+
+    @Override
+    protected void getContent(ByteBuffer byteBuffer) {
+        IsoTypeWriter.writeUInt32(byteBuffer, DTSSamplingFrequency);
+        IsoTypeWriter.writeUInt32(byteBuffer, maxBitRate);
+        IsoTypeWriter.writeUInt32(byteBuffer, avgBitRate);
+        IsoTypeWriter.writeUInt8(byteBuffer, pcmSampleDepth);
+        BitWriterBuffer bwb = new BitWriterBuffer(byteBuffer);
+        bwb.writeBits(frameDuration, 2);
+        bwb.writeBits(streamConstruction, 5);
+        bwb.writeBits(coreLFEPresent, 1);
+        bwb.writeBits(coreLayout, 6);
+        bwb.writeBits(coreSize, 14);
+        bwb.writeBits(stereoDownmix, 1);
+        bwb.writeBits(representationType, 3);
+        bwb.writeBits(channelLayout, 16);
+        bwb.writeBits(multiAssetFlag, 1);
+        bwb.writeBits(LBRDurationMod, 1);
+        bwb.writeBits(reservedBoxPresent, 1);
+        bwb.writeBits(reserved, 5);
+
+    }
+
+    public long getAvgBitRate() {
+        return avgBitRate;
+    }
+
+    public void setAvgBitRate(long avgBitRate) {
+        this.avgBitRate = avgBitRate;
+    }
+
+    public long getDTSSamplingFrequency() {
+        return DTSSamplingFrequency;
+    }
+
+    public void setDTSSamplingFrequency(long DTSSamplingFrequency) {
+        this.DTSSamplingFrequency = DTSSamplingFrequency;
+    }
+
+    public long getMaxBitRate() {
+        return maxBitRate;
+    }
+
+    public void setMaxBitRate(long maxBitRate) {
+        this.maxBitRate = maxBitRate;
+    }
+
+    public int getPcmSampleDepth() {
+        return pcmSampleDepth;
+    }
+
+    public void setPcmSampleDepth(int pcmSampleDepth) {
+        this.pcmSampleDepth = pcmSampleDepth;
+    }
+
+    public int getFrameDuration() {
+        return frameDuration;
+    }
+
+    public void setFrameDuration(int frameDuration) {
+        this.frameDuration = frameDuration;
+    }
+
+    public int getStreamConstruction() {
+        return streamConstruction;
+    }
+
+    public void setStreamConstruction(int streamConstruction) {
+        this.streamConstruction = streamConstruction;
+    }
+
+    public int getCoreLFEPresent() {
+        return coreLFEPresent;
+    }
+
+    public void setCoreLFEPresent(int coreLFEPresent) {
+        this.coreLFEPresent = coreLFEPresent;
+    }
+
+    public int getCoreLayout() {
+        return coreLayout;
+    }
+
+    public void setCoreLayout(int coreLayout) {
+        this.coreLayout = coreLayout;
+    }
+
+    public int getCoreSize() {
+        return coreSize;
+    }
+
+    public void setCoreSize(int coreSize) {
+        this.coreSize = coreSize;
+    }
+
+    public int getStereoDownmix() {
+        return stereoDownmix;
+    }
+
+    public void setStereoDownmix(int stereoDownmix) {
+        this.stereoDownmix = stereoDownmix;
+    }
+
+    public int getRepresentationType() {
+        return representationType;
+    }
+
+    public void setRepresentationType(int representationType) {
+        this.representationType = representationType;
+    }
+
+    public int getChannelLayout() {
+        return channelLayout;
+    }
+
+    public void setChannelLayout(int channelLayout) {
+        this.channelLayout = channelLayout;
+    }
+
+    public int getMultiAssetFlag() {
+        return multiAssetFlag;
+    }
+
+    public void setMultiAssetFlag(int multiAssetFlag) {
+        this.multiAssetFlag = multiAssetFlag;
+    }
+
+    public int getLBRDurationMod() {
+        return LBRDurationMod;
+    }
+
+    public void setLBRDurationMod(int LBRDurationMod) {
+        this.LBRDurationMod = LBRDurationMod;
+    }
+
+    public int getReserved() {
+        return reserved;
+    }
+
+    public void setReserved(int reserved) {
+        this.reserved = reserved;
+    }
+
+    public int getReservedBoxPresent() {
+        return reservedBoxPresent;
+    }
+
+    public void setReservedBoxPresent(int reservedBoxPresent) {
+        this.reservedBoxPresent = reservedBoxPresent;
+    }
+}
diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/boxes/EC3SpecificBox.java b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/EC3SpecificBox.java
new file mode 100644
index 0000000..412db04
--- /dev/null
+++ b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/EC3SpecificBox.java
@@ -0,0 +1,140 @@
+package com.googlecode.mp4parser.boxes;
+
+import com.googlecode.mp4parser.AbstractBox;
+import com.googlecode.mp4parser.boxes.mp4.objectdescriptors.BitReaderBuffer;
+import com.googlecode.mp4parser.boxes.mp4.objectdescriptors.BitWriterBuffer;
+
+import java.nio.ByteBuffer;
+import java.util.LinkedList;
+import java.util.List;
+
+/**
+ *
+ */
+public class EC3SpecificBox extends AbstractBox {
+    List<Entry> entries = new LinkedList<Entry>();
+    int dataRate;
+    int numIndSub;
+
+    public EC3SpecificBox() {
+        super("dec3");
+    }
+
+    @Override
+    public long getContentSize() {
+        long size = 2;
+        for (Entry entry : entries) {
+            if (entry.num_dep_sub > 0) {
+                size += 4;
+            } else {
+                size += 3;
+            }
+        }
+        return size;
+    }
+
+    @Override
+    public void _parseDetails(ByteBuffer content) {
+        BitReaderBuffer brb = new BitReaderBuffer(content);
+        dataRate = brb.readBits(13);
+        numIndSub = brb.readBits(3) + 1;
+        // This field indicates the number of independent substreams that are present in the Enhanced AC-3 bitstream. The value
+        // of this field is one less than the number of independent substreams present.
+
+
+        for (int i = 0; i < numIndSub; i++) {
+            Entry e = new Entry();
+            e.fscod = brb.readBits(2);
+            e.bsid = brb.readBits(5);
+            e.bsmod = brb.readBits(5);
+            e.acmod = brb.readBits(3);
+            e.lfeon = brb.readBits(1);
+            e.reserved = brb.readBits(3);
+            e.num_dep_sub = brb.readBits(4);
+            if (e.num_dep_sub > 0) {
+                e.chan_loc = brb.readBits(9);
+            } else {
+                e.reserved2 = brb.readBits(1);
+            }
+            entries.add(e);
+        }
+    }
+
+    @Override
+    public void getContent(ByteBuffer byteBuffer) {
+        BitWriterBuffer bwb = new BitWriterBuffer(byteBuffer);
+        bwb.writeBits(dataRate, 13);
+        bwb.writeBits(entries.size() - 1, 3);
+        for (Entry e : entries) {
+            bwb.writeBits(e.fscod, 2);
+            bwb.writeBits(e.bsid, 5);
+            bwb.writeBits(e.bsmod, 5);
+            bwb.writeBits(e.acmod, 3);
+            bwb.writeBits(e.lfeon, 1);
+            bwb.writeBits(e.reserved, 3);
+            bwb.writeBits(e.num_dep_sub, 4);
+            if (e.num_dep_sub > 0) {
+                bwb.writeBits(e.chan_loc, 9);
+            } else {
+                bwb.writeBits(e.reserved2, 1);
+            }
+        }
+    }
+
+
+    public List<Entry> getEntries() {
+        return entries;
+    }
+
+    public void setEntries(List<Entry> entries) {
+        this.entries = entries;
+    }
+
+    public void addEntry(Entry entry) {
+        this.entries.add(entry);
+    }
+
+    public int getDataRate() {
+        return dataRate;
+    }
+
+    public void setDataRate(int dataRate) {
+        this.dataRate = dataRate;
+    }
+
+    public int getNumIndSub() {
+        return numIndSub;
+    }
+
+    public void setNumIndSub(int numIndSub) {
+        this.numIndSub = numIndSub;
+    }
+
+    public static class Entry {
+        public int fscod;
+        public int bsid;
+        public int bsmod;
+        public int acmod;
+        public int lfeon;
+        public int reserved;
+        public int num_dep_sub;
+        public int chan_loc;
+        public int reserved2;
+
+
+        @Override
+        public String toString() {
+            return "Entry{" +
+                    "fscod=" + fscod +
+                    ", bsid=" + bsid +
+                    ", bsmod=" + bsmod +
+                    ", acmod=" + acmod +
+                    ", lfeon=" + lfeon +
+                    ", reserved=" + reserved +
+                    ", num_dep_sub=" + num_dep_sub +
+                    ", chan_loc=" + chan_loc +
+                    ", reserved2=" + reserved2 +
+                    '}';
+        }
+    }
+}
diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/boxes/MLPSpecificBox.java b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/MLPSpecificBox.java
new file mode 100644
index 0000000..fe6f0d8
--- /dev/null
+++ b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/MLPSpecificBox.java
@@ -0,0 +1,76 @@
+package com.googlecode.mp4parser.boxes;
+
+import com.googlecode.mp4parser.AbstractBox;
+import com.googlecode.mp4parser.boxes.mp4.objectdescriptors.BitReaderBuffer;
+import com.googlecode.mp4parser.boxes.mp4.objectdescriptors.BitWriterBuffer;
+
+import java.nio.ByteBuffer;
+
+
+public class MLPSpecificBox extends AbstractBox {
+
+    int format_info;
+    int peak_data_rate;
+    int reserved;
+    int reserved2;
+
+    public MLPSpecificBox() {
+        super("dmlp");
+    }
+
+    @Override
+    protected long getContentSize() {
+        return 10;
+    }
+
+    @Override
+    public void _parseDetails(ByteBuffer content) {
+        BitReaderBuffer brb = new BitReaderBuffer(content);
+        format_info = brb.readBits(32);
+        peak_data_rate = brb.readBits(15);
+        reserved = brb.readBits(1);
+        reserved2 = brb.readBits(32);
+    }
+
+    @Override
+    protected void getContent(ByteBuffer byteBuffer) {
+        BitWriterBuffer bwb = new BitWriterBuffer(byteBuffer);
+        bwb.writeBits(format_info, 32);
+        bwb.writeBits(peak_data_rate, 15);
+        bwb.writeBits(reserved, 1);
+        bwb.writeBits(reserved2, 32);
+        //To change body of implemented methods use File | Settings | File Templates.
+    }
+
+    public int getFormat_info() {
+        return format_info;
+    }
+
+    public void setFormat_info(int format_info) {
+        this.format_info = format_info;
+    }
+
+    public int getPeak_data_rate() {
+        return peak_data_rate;
+    }
+
+    public void setPeak_data_rate(int peak_data_rate) {
+        this.peak_data_rate = peak_data_rate;
+    }
+
+    public int getReserved() {
+        return reserved;
+    }
+
+    public void setReserved(int reserved) {
+        this.reserved = reserved;
+    }
+
+    public int getReserved2() {
+        return reserved2;
+    }
+
+    public void setReserved2(int reserved2) {
+        this.reserved2 = reserved2;
+    }
+}
diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/boxes/adobe/.svn/all-wcprops b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/adobe/.svn/all-wcprops
new file mode 100644
index 0000000..d4678d2
--- /dev/null
+++ b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/adobe/.svn/all-wcprops
@@ -0,0 +1,11 @@
+K 25
+svn:wc:ra_dav:version-url
+V 84
+/svn/!svn/ver/507/trunk/isoparser/src/main/java/com/googlecode/mp4parser/boxes/adobe
+END
+ActionMessageFormat0SampleEntryBox.java
+K 25
+svn:wc:ra_dav:version-url
+V 124
+/svn/!svn/ver/507/trunk/isoparser/src/main/java/com/googlecode/mp4parser/boxes/adobe/ActionMessageFormat0SampleEntryBox.java
+END
diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/boxes/adobe/.svn/entries b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/adobe/.svn/entries
new file mode 100644
index 0000000..c291f28
--- /dev/null
+++ b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/adobe/.svn/entries
@@ -0,0 +1,62 @@
+10
+
+dir
+778
+http://mp4parser.googlecode.com/svn/trunk/isoparser/src/main/java/com/googlecode/mp4parser/boxes/adobe
+http://mp4parser.googlecode.com/svn
+
+
+
+2012-04-21T22:05:38.425329Z
+507
+Sebastian.Annies@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+7decde4b-c250-0410-a0da-51896bc88be6
+
+ActionMessageFormat0SampleEntryBox.java
+file
+
+
+
+
+2012-09-14T17:27:51.297230Z
+cf327bd01b68a2d3801d58c67ba3a500
+2012-04-21T22:05:38.425329Z
+507
+Sebastian.Annies@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+901
+
diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/boxes/adobe/.svn/text-base/ActionMessageFormat0SampleEntryBox.java.svn-base b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/adobe/.svn/text-base/ActionMessageFormat0SampleEntryBox.java.svn-base
new file mode 100644
index 0000000..483dd8f
--- /dev/null
+++ b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/adobe/.svn/text-base/ActionMessageFormat0SampleEntryBox.java.svn-base
@@ -0,0 +1,38 @@
+package com.googlecode.mp4parser.boxes.adobe;
+
+import com.coremedia.iso.boxes.Box;
+import com.coremedia.iso.boxes.sampleentry.SampleEntry;
+
+import java.nio.ByteBuffer;
+
+/**
+ * Sample Entry as used for Action Message Format tracks.
+ */
+public class ActionMessageFormat0SampleEntryBox extends SampleEntry {
+    public ActionMessageFormat0SampleEntryBox() {
+        super("amf0");
+    }
+
+    @Override
+    protected long getContentSize() {
+        long size = 8;
+        for (Box box : boxes) {
+            size += box.getSize();
+        }
+
+        return size;
+    }
+
+
+    @Override
+    public void _parseDetails(ByteBuffer content) {
+        _parseReservedAndDataReferenceIndex(content);
+        _parseChildBoxes(content);
+    }
+
+    @Override
+    protected void getContent(ByteBuffer byteBuffer) {
+        _writeReservedAndDataReferenceIndex(byteBuffer);
+        _writeChildBoxes(byteBuffer);
+    }
+}
diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/boxes/adobe/ActionMessageFormat0SampleEntryBox.java b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/adobe/ActionMessageFormat0SampleEntryBox.java
new file mode 100644
index 0000000..483dd8f
--- /dev/null
+++ b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/adobe/ActionMessageFormat0SampleEntryBox.java
@@ -0,0 +1,38 @@
+package com.googlecode.mp4parser.boxes.adobe;
+
+import com.coremedia.iso.boxes.Box;
+import com.coremedia.iso.boxes.sampleentry.SampleEntry;
+
+import java.nio.ByteBuffer;
+
+/**
+ * Sample Entry as used for Action Message Format tracks.
+ */
+public class ActionMessageFormat0SampleEntryBox extends SampleEntry {
+    public ActionMessageFormat0SampleEntryBox() {
+        super("amf0");
+    }
+
+    @Override
+    protected long getContentSize() {
+        long size = 8;
+        for (Box box : boxes) {
+            size += box.getSize();
+        }
+
+        return size;
+    }
+
+
+    @Override
+    public void _parseDetails(ByteBuffer content) {
+        _parseReservedAndDataReferenceIndex(content);
+        _parseChildBoxes(content);
+    }
+
+    @Override
+    protected void getContent(ByteBuffer byteBuffer) {
+        _writeReservedAndDataReferenceIndex(byteBuffer);
+        _writeChildBoxes(byteBuffer);
+    }
+}
diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/boxes/apple/.svn/all-wcprops b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/apple/.svn/all-wcprops
new file mode 100644
index 0000000..458d104
--- /dev/null
+++ b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/apple/.svn/all-wcprops
@@ -0,0 +1,41 @@
+K 25
+svn:wc:ra_dav:version-url
+V 84
+/svn/!svn/ver/727/trunk/isoparser/src/main/java/com/googlecode/mp4parser/boxes/apple
+END
+TimeCodeBox.java
+K 25
+svn:wc:ra_dav:version-url
+V 101
+/svn/!svn/ver/684/trunk/isoparser/src/main/java/com/googlecode/mp4parser/boxes/apple/TimeCodeBox.java
+END
+QuicktimeTextSampleEntry.java
+K 25
+svn:wc:ra_dav:version-url
+V 114
+/svn/!svn/ver/690/trunk/isoparser/src/main/java/com/googlecode/mp4parser/boxes/apple/QuicktimeTextSampleEntry.java
+END
+GenericMediaHeaderAtom.java
+K 25
+svn:wc:ra_dav:version-url
+V 112
+/svn/!svn/ver/684/trunk/isoparser/src/main/java/com/googlecode/mp4parser/boxes/apple/GenericMediaHeaderAtom.java
+END
+BaseMediaInfoAtom.java
+K 25
+svn:wc:ra_dav:version-url
+V 107
+/svn/!svn/ver/687/trunk/isoparser/src/main/java/com/googlecode/mp4parser/boxes/apple/BaseMediaInfoAtom.java
+END
+TaptAtom.java
+K 25
+svn:wc:ra_dav:version-url
+V 98
+/svn/!svn/ver/727/trunk/isoparser/src/main/java/com/googlecode/mp4parser/boxes/apple/TaptAtom.java
+END
+GenericMediaHeaderTextAtom.java
+K 25
+svn:wc:ra_dav:version-url
+V 116
+/svn/!svn/ver/685/trunk/isoparser/src/main/java/com/googlecode/mp4parser/boxes/apple/GenericMediaHeaderTextAtom.java
+END
diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/boxes/apple/.svn/entries b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/apple/.svn/entries
new file mode 100644
index 0000000..ad474c2
--- /dev/null
+++ b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/apple/.svn/entries
@@ -0,0 +1,232 @@
+10
+
+dir
+778
+http://mp4parser.googlecode.com/svn/trunk/isoparser/src/main/java/com/googlecode/mp4parser/boxes/apple
+http://mp4parser.googlecode.com/svn
+
+
+
+2012-08-08T07:05:08.133759Z
+727
+Sebastian.Annies@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+7decde4b-c250-0410-a0da-51896bc88be6
+
+TimeCodeBox.java
+file
+
+
+
+
+2012-09-14T17:27:51.197229Z
+c584657a6b97bbddc67e006ea6425bb6
+2012-06-24T14:45:45.932648Z
+684
+Sebastian.Annies@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+1498
+
+QuicktimeTextSampleEntry.java
+file
+
+
+
+
+2012-09-14T17:27:51.197229Z
+9fb53b7189ae88149477c073fb987599
+2012-06-24T21:27:52.519961Z
+690
+Sebastian.Annies@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+6202
+
+GenericMediaHeaderAtom.java
+file
+
+
+
+
+2012-09-14T17:27:51.207229Z
+2eba5114788056352adb0e5e7d8cee33
+2012-06-24T14:45:45.932648Z
+684
+Sebastian.Annies@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+890
+
+BaseMediaInfoAtom.java
+file
+
+
+
+
+2012-09-14T17:27:51.207229Z
+6119ba316b09d48ed85824b96f2b68b1
+2012-06-24T19:53:06.650023Z
+687
+Sebastian.Annies@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+2695
+
+TaptAtom.java
+file
+
+
+
+
+2012-09-14T17:27:51.207229Z
+9eed1655d1a9f0c187071c0bf6ff61bc
+2012-08-08T07:05:08.133759Z
+727
+Sebastian.Annies@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+327
+
+GenericMediaHeaderTextAtom.java
+file
+
+
+
+
+2012-09-14T17:27:51.207229Z
+b06b279065c7b8475ade9558fa8227c9
+2012-06-24T15:08:14.651658Z
+685
+Sebastian.Annies@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+2866
+
diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/boxes/apple/.svn/text-base/BaseMediaInfoAtom.java.svn-base b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/apple/.svn/text-base/BaseMediaInfoAtom.java.svn-base
new file mode 100644
index 0000000..706569e
--- /dev/null
+++ b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/apple/.svn/text-base/BaseMediaInfoAtom.java.svn-base
@@ -0,0 +1,110 @@
+package com.googlecode.mp4parser.boxes.apple;
+
+import com.coremedia.iso.IsoTypeReader;
+import com.coremedia.iso.IsoTypeWriter;
+import com.googlecode.mp4parser.AbstractFullBox;
+
+import java.nio.ByteBuffer;
+
+public class BaseMediaInfoAtom extends AbstractFullBox {
+    public static final String TYPE = "gmin";
+
+    short graphicsMode = 64;
+    int opColorR = 32768;
+    int opColorG = 32768;
+    int opColorB = 32768;
+    short balance;
+    short reserved;
+
+    public BaseMediaInfoAtom() {
+        super(TYPE);
+    }
+
+    @Override
+    protected long getContentSize() {
+        return 16;
+    }
+
+    @Override
+    protected void getContent(ByteBuffer byteBuffer) {
+        writeVersionAndFlags(byteBuffer);
+        byteBuffer.putShort(graphicsMode);
+        IsoTypeWriter.writeUInt16(byteBuffer, opColorR);
+        IsoTypeWriter.writeUInt16(byteBuffer,opColorG );
+        IsoTypeWriter.writeUInt16(byteBuffer,opColorB );
+        byteBuffer.putShort(balance);
+        byteBuffer.putShort(reserved);
+    }
+
+    @Override
+    protected void _parseDetails(ByteBuffer content) {
+        parseVersionAndFlags(content);
+        graphicsMode = content.getShort();
+        opColorR = IsoTypeReader.readUInt16(content);
+        opColorG = IsoTypeReader.readUInt16(content);
+        opColorB = IsoTypeReader.readUInt16(content);
+        balance = content.getShort();
+        reserved = content.getShort();
+
+    }
+
+    public short getGraphicsMode() {
+        return graphicsMode;
+    }
+
+    public void setGraphicsMode(short graphicsMode) {
+        this.graphicsMode = graphicsMode;
+    }
+
+    public int getOpColorR() {
+        return opColorR;
+    }
+
+    public void setOpColorR(int opColorR) {
+        this.opColorR = opColorR;
+    }
+
+    public int getOpColorG() {
+        return opColorG;
+    }
+
+    public void setOpColorG(int opColorG) {
+        this.opColorG = opColorG;
+    }
+
+    public int getOpColorB() {
+        return opColorB;
+    }
+
+    public void setOpColorB(int opColorB) {
+        this.opColorB = opColorB;
+    }
+
+    public short getBalance() {
+        return balance;
+    }
+
+    public void setBalance(short balance) {
+        this.balance = balance;
+    }
+
+    public short getReserved() {
+        return reserved;
+    }
+
+    public void setReserved(short reserved) {
+        this.reserved = reserved;
+    }
+
+    @Override
+    public String toString() {
+        return "BaseMediaInfoAtom{" +
+                "graphicsMode=" + graphicsMode +
+                ", opColorR=" + opColorR +
+                ", opColorG=" + opColorG +
+                ", opColorB=" + opColorB +
+                ", balance=" + balance +
+                ", reserved=" + reserved +
+                '}';
+    }
+}
diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/boxes/apple/.svn/text-base/GenericMediaHeaderAtom.java.svn-base b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/apple/.svn/text-base/GenericMediaHeaderAtom.java.svn-base
new file mode 100644
index 0000000..ac2033f
--- /dev/null
+++ b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/apple/.svn/text-base/GenericMediaHeaderAtom.java.svn-base
@@ -0,0 +1,28 @@
+/*
+ * Copyright 2012 Sebastian Annies, Hamburg
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.googlecode.mp4parser.boxes.apple;
+
+import com.googlecode.mp4parser.AbstractContainerBox;
+
+public class GenericMediaHeaderAtom extends AbstractContainerBox {
+
+    public static final String TYPE = "gmhd";
+
+    public GenericMediaHeaderAtom() {
+        super(TYPE);
+    }
+
+}
diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/boxes/apple/.svn/text-base/GenericMediaHeaderTextAtom.java.svn-base b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/apple/.svn/text-base/GenericMediaHeaderTextAtom.java.svn-base
new file mode 100644
index 0000000..fd52dc9
--- /dev/null
+++ b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/apple/.svn/text-base/GenericMediaHeaderTextAtom.java.svn-base
@@ -0,0 +1,130 @@
+package com.googlecode.mp4parser.boxes.apple;
+
+import com.googlecode.mp4parser.AbstractBox;
+
+import java.nio.ByteBuffer;
+
+/**
+ * Undocumented atom in the gmhd atom of text tracks.
+ */
+public class GenericMediaHeaderTextAtom extends AbstractBox {
+
+    public static final String TYPE = "text";
+
+    int unknown_1 = 65536;
+    int unknown_2;
+    int unknown_3;
+    int unknown_4;
+    int unknown_5 = 65536;
+    int unknown_6;
+    int unknown_7;
+    int unknown_8;
+    int unknown_9 = 1073741824;
+
+    public GenericMediaHeaderTextAtom() {
+        super(TYPE);
+    }
+
+    @Override
+    protected long getContentSize() {
+        return 36;
+    }
+
+    @Override
+    protected void getContent(ByteBuffer byteBuffer) {
+        byteBuffer.putInt(unknown_1);
+        byteBuffer.putInt(unknown_2);
+        byteBuffer.putInt(unknown_3);
+        byteBuffer.putInt(unknown_4);
+        byteBuffer.putInt(unknown_5);
+        byteBuffer.putInt(unknown_6);
+        byteBuffer.putInt(unknown_7);
+        byteBuffer.putInt(unknown_8);
+        byteBuffer.putInt(unknown_9);
+    }
+
+    @Override
+    protected void _parseDetails(ByteBuffer content) {
+        unknown_1 = content.getInt();
+        unknown_2 = content.getInt();
+        unknown_3 = content.getInt();
+        unknown_4 = content.getInt();
+        unknown_5 = content.getInt();
+        unknown_6 = content.getInt();
+        unknown_7 = content.getInt();
+        unknown_8 = content.getInt();
+        unknown_9 = content.getInt();
+    }
+
+    public int getUnknown_1() {
+        return unknown_1;
+    }
+
+    public void setUnknown_1(int unknown_1) {
+        this.unknown_1 = unknown_1;
+    }
+
+    public int getUnknown_2() {
+        return unknown_2;
+    }
+
+    public void setUnknown_2(int unknown_2) {
+        this.unknown_2 = unknown_2;
+    }
+
+    public int getUnknown_3() {
+        return unknown_3;
+    }
+
+    public void setUnknown_3(int unknown_3) {
+        this.unknown_3 = unknown_3;
+    }
+
+    public int getUnknown_4() {
+        return unknown_4;
+    }
+
+    public void setUnknown_4(int unknown_4) {
+        this.unknown_4 = unknown_4;
+    }
+
+    public int getUnknown_5() {
+        return unknown_5;
+    }
+
+    public void setUnknown_5(int unknown_5) {
+        this.unknown_5 = unknown_5;
+    }
+
+    public int getUnknown_6() {
+        return unknown_6;
+    }
+
+    public void setUnknown_6(int unknown_6) {
+        this.unknown_6 = unknown_6;
+    }
+
+    public int getUnknown_7() {
+        return unknown_7;
+    }
+
+    public void setUnknown_7(int unknown_7) {
+        this.unknown_7 = unknown_7;
+    }
+
+    public int getUnknown_8() {
+        return unknown_8;
+    }
+
+    public void setUnknown_8(int unknown_8) {
+        this.unknown_8 = unknown_8;
+    }
+
+    public int getUnknown_9() {
+        return unknown_9;
+    }
+
+    public void setUnknown_9(int unknown_9) {
+        this.unknown_9 = unknown_9;
+    }
+}
diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/boxes/apple/.svn/text-base/QuicktimeTextSampleEntry.java.svn-base b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/apple/.svn/text-base/QuicktimeTextSampleEntry.java.svn-base
new file mode 100644
index 0000000..8784fc6
--- /dev/null
+++ b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/apple/.svn/text-base/QuicktimeTextSampleEntry.java.svn-base
@@ -0,0 +1,237 @@
+/*
+ * Copyright 2012 Sebastian Annies, Hamburg
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.googlecode.mp4parser.boxes.apple;
+
+import com.coremedia.iso.IsoTypeReader;
+import com.coremedia.iso.IsoTypeWriter;
+import com.coremedia.iso.boxes.sampleentry.SampleEntry;
+
+import java.nio.ByteBuffer;
+
+/**
+ * Entry type for timed text samples defined in the timed text specification (ISO/IEC 14496-17).
+ */
+public class QuicktimeTextSampleEntry extends SampleEntry {
+
+    public static final String TYPE = "text";
+
+    int displayFlags;
+    int textJustification;
+
+    int backgroundR;
+    int backgroundG;
+    int backgroundB;
+
+    long defaultTextBox;
+    long reserved1;
+
+    short fontNumber;
+    short fontFace;
+    byte reserved2;
+    short reserved3;
+
+    int foregroundR = 65535;
+    int foregroundG = 65535;
+    int foregroundB = 65535;
+
+    String fontName = "";
+
+    public QuicktimeTextSampleEntry() {
+        super(TYPE);
+    }
+
+    @Override
+    public void _parseDetails(ByteBuffer content) {
+        _parseReservedAndDataReferenceIndex(content);
+
+        displayFlags = content.getInt();
+        textJustification = content.getInt();
+        backgroundR = IsoTypeReader.readUInt16(content);
+        backgroundG = IsoTypeReader.readUInt16(content);
+        backgroundB = IsoTypeReader.readUInt16(content);
+        defaultTextBox = IsoTypeReader.readUInt64(content);
+        reserved1 = IsoTypeReader.readUInt64(content);
+        fontNumber = content.getShort();
+        fontFace = content.getShort();
+        reserved2 = content.get();
+        reserved3 = content.getShort();
+        foregroundR = IsoTypeReader.readUInt16(content);
+        foregroundG = IsoTypeReader.readUInt16(content);
+        foregroundB = IsoTypeReader.readUInt16(content);
+
+        if (content.remaining() > 0) {
+            int length = IsoTypeReader.readUInt8(content);
+            byte[] myFontName = new byte[length];
+            content.get(myFontName);
+            fontName = new String(myFontName);
+        } else {
+            fontName = null;
+        }
+    }
+
+
+    protected long getContentSize() {
+        return 52 + (fontName != null ? fontName.length() : 0);
+    }
+
+
+    public int getDisplayFlags() {
+        return displayFlags;
+    }
+
+    public void setDisplayFlags(int displayFlags) {
+        this.displayFlags = displayFlags;
+    }
+
+    public int getTextJustification() {
+        return textJustification;
+    }
+
+    public void setTextJustification(int textJustification) {
+        this.textJustification = textJustification;
+    }
+
+    public int getBackgroundR() {
+        return backgroundR;
+    }
+
+    public void setBackgroundR(int backgroundR) {
+        this.backgroundR = backgroundR;
+    }
+
+    public int getBackgroundG() {
+        return backgroundG;
+    }
+
+    public void setBackgroundG(int backgroundG) {
+        this.backgroundG = backgroundG;
+    }
+
+    public int getBackgroundB() {
+        return backgroundB;
+    }
+
+    public void setBackgroundB(int backgroundB) {
+        this.backgroundB = backgroundB;
+    }
+
+    public long getDefaultTextBox() {
+        return defaultTextBox;
+    }
+
+    public void setDefaultTextBox(long defaultTextBox) {
+        this.defaultTextBox = defaultTextBox;
+    }
+
+    public long getReserved1() {
+        return reserved1;
+    }
+
+    public void setReserved1(long reserved1) {
+        this.reserved1 = reserved1;
+    }
+
+    public short getFontNumber() {
+        return fontNumber;
+    }
+
+    public void setFontNumber(short fontNumber) {
+        this.fontNumber = fontNumber;
+    }
+
+    public short getFontFace() {
+        return fontFace;
+    }
+
+    public void setFontFace(short fontFace) {
+        this.fontFace = fontFace;
+    }
+
+    public byte getReserved2() {
+        return reserved2;
+    }
+
+    public void setReserved2(byte reserved2) {
+        this.reserved2 = reserved2;
+    }
+
+    public short getReserved3() {
+        return reserved3;
+    }
+
+    public void setReserved3(short reserved3) {
+        this.reserved3 = reserved3;
+    }
+
+    public int getForegroundR() {
+        return foregroundR;
+    }
+
+    public void setForegroundR(int foregroundR) {
+        this.foregroundR = foregroundR;
+    }
+
+    public int getForegroundG() {
+        return foregroundG;
+    }
+
+    public void setForegroundG(int foregroundG) {
+        this.foregroundG = foregroundG;
+    }
+
+    public int getForegroundB() {
+        return foregroundB;
+    }
+
+    public void setForegroundB(int foregroundB) {
+        this.foregroundB = foregroundB;
+    }
+
+    public String getFontName() {
+        return fontName;
+    }
+
+    public void setFontName(String fontName) {
+        this.fontName = fontName;
+    }
+
+    @Override
+    protected void getContent(ByteBuffer byteBuffer) {
+        _writeReservedAndDataReferenceIndex(byteBuffer);
+        byteBuffer.putInt(displayFlags);
+        byteBuffer.putInt(textJustification);
+        IsoTypeWriter.writeUInt16(byteBuffer, backgroundR);
+        IsoTypeWriter.writeUInt16(byteBuffer, backgroundG);
+        IsoTypeWriter.writeUInt16(byteBuffer, backgroundB);
+        IsoTypeWriter.writeUInt64(byteBuffer, defaultTextBox);
+        IsoTypeWriter.writeUInt64(byteBuffer, reserved1);
+        byteBuffer.putShort(fontNumber);
+        byteBuffer.putShort(fontFace);
+        byteBuffer.put(reserved2);
+        byteBuffer.putShort(reserved3);
+
+        IsoTypeWriter.writeUInt16(byteBuffer, foregroundR);
+        IsoTypeWriter.writeUInt16(byteBuffer, foregroundG);
+        IsoTypeWriter.writeUInt16(byteBuffer, foregroundB);
+        if (fontName != null) {
+            IsoTypeWriter.writeUInt8(byteBuffer, fontName.length());
+            byteBuffer.put(fontName.getBytes());
+        }
+
+    }
+
+
+}
diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/boxes/apple/.svn/text-base/TaptAtom.java.svn-base b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/apple/.svn/text-base/TaptAtom.java.svn-base
new file mode 100644
index 0000000..4fcea56
--- /dev/null
+++ b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/apple/.svn/text-base/TaptAtom.java.svn-base
@@ -0,0 +1,16 @@
+package com.googlecode.mp4parser.boxes.apple;
+
+import com.googlecode.mp4parser.AbstractContainerBox;
+
+/**
+ * Don't know what it is but it is obviously a container box.
+ */
+public class TaptAtom extends AbstractContainerBox {
+    public static final String TYPE = "tapt";
+
+    public TaptAtom() {
+        super(TYPE);
+    }
+
+
+}
diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/boxes/apple/.svn/text-base/TimeCodeBox.java.svn-base b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/apple/.svn/text-base/TimeCodeBox.java.svn-base
new file mode 100644
index 0000000..e15c9f0
--- /dev/null
+++ b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/apple/.svn/text-base/TimeCodeBox.java.svn-base
@@ -0,0 +1,54 @@
+/*
+ * Copyright 2012 Sebastian Annies, Hamburg
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.googlecode.mp4parser.boxes.apple;
+
+import com.coremedia.iso.boxes.Box;
+import com.coremedia.iso.boxes.sampleentry.SampleEntry;
+
+import java.nio.ByteBuffer;
+
+public class TimeCodeBox extends SampleEntry {
+    byte[] data;
+
+
+    public TimeCodeBox() {
+        super("tmcd");
+    }
+
+    @Override
+    protected long getContentSize() {
+        long size = 26;
+        for (Box box : boxes) {
+            size += box.getSize();
+        }
+        return size;
+    }
+
+    @Override
+    public void _parseDetails(ByteBuffer content) {
+        _parseReservedAndDataReferenceIndex(content);
+        data = new byte[18];
+        content.get(data);
+        _parseChildBoxes(content);
+    }
+
+    @Override
+    protected void getContent(ByteBuffer byteBuffer) {
+        _writeReservedAndDataReferenceIndex(byteBuffer);
+        byteBuffer.put(data);
+        _writeChildBoxes(byteBuffer);
+    }
+}
diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/boxes/apple/BaseMediaInfoAtom.java b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/apple/BaseMediaInfoAtom.java
new file mode 100644
index 0000000..706569e
--- /dev/null
+++ b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/apple/BaseMediaInfoAtom.java
@@ -0,0 +1,110 @@
+package com.googlecode.mp4parser.boxes.apple;
+
+import com.coremedia.iso.IsoTypeReader;
+import com.coremedia.iso.IsoTypeWriter;
+import com.googlecode.mp4parser.AbstractFullBox;
+
+import java.nio.ByteBuffer;
+
+public class BaseMediaInfoAtom extends AbstractFullBox {
+    public static final String TYPE = "gmin";
+
+    short graphicsMode = 64;
+    int opColorR = 32768;
+    int opColorG = 32768;
+    int opColorB = 32768;
+    short balance;
+    short reserved;
+
+    public BaseMediaInfoAtom() {
+        super(TYPE);
+    }
+
+    @Override
+    protected long getContentSize() {
+        return 16;
+    }
+
+    @Override
+    protected void getContent(ByteBuffer byteBuffer) {
+        writeVersionAndFlags(byteBuffer);
+        byteBuffer.putShort(graphicsMode);
+        IsoTypeWriter.writeUInt16(byteBuffer, opColorR);
+        IsoTypeWriter.writeUInt16(byteBuffer,opColorG );
+        IsoTypeWriter.writeUInt16(byteBuffer,opColorB );
+        byteBuffer.putShort(balance);
+        byteBuffer.putShort(reserved);
+    }
+
+    @Override
+    protected void _parseDetails(ByteBuffer content) {
+        parseVersionAndFlags(content);
+        graphicsMode = content.getShort();
+        opColorR = IsoTypeReader.readUInt16(content);
+        opColorG = IsoTypeReader.readUInt16(content);
+        opColorB = IsoTypeReader.readUInt16(content);
+        balance = content.getShort();
+        reserved = content.getShort();
+
+    }
+
+    public short getGraphicsMode() {
+        return graphicsMode;
+    }
+
+    public void setGraphicsMode(short graphicsMode) {
+        this.graphicsMode = graphicsMode;
+    }
+
+    public int getOpColorR() {
+        return opColorR;
+    }
+
+    public void setOpColorR(int opColorR) {
+        this.opColorR = opColorR;
+    }
+
+    public int getOpColorG() {
+        return opColorG;
+    }
+
+    public void setOpColorG(int opColorG) {
+        this.opColorG = opColorG;
+    }
+
+    public int getOpColorB() {
+        return opColorB;
+    }
+
+    public void setOpColorB(int opColorB) {
+        this.opColorB = opColorB;
+    }
+
+    public short getBalance() {
+        return balance;
+    }
+
+    public void setBalance(short balance) {
+        this.balance = balance;
+    }
+
+    public short getReserved() {
+        return reserved;
+    }
+
+    public void setReserved(short reserved) {
+        this.reserved = reserved;
+    }
+
+    @Override
+    public String toString() {
+        return "BaseMediaInfoAtom{" +
+                "graphicsMode=" + graphicsMode +
+                ", opColorR=" + opColorR +
+                ", opColorG=" + opColorG +
+                ", opColorB=" + opColorB +
+                ", balance=" + balance +
+                ", reserved=" + reserved +
+                '}';
+    }
+}
diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/boxes/apple/GenericMediaHeaderAtom.java b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/apple/GenericMediaHeaderAtom.java
new file mode 100644
index 0000000..ac2033f
--- /dev/null
+++ b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/apple/GenericMediaHeaderAtom.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright 2012 Sebastian Annies, Hamburg
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.googlecode.mp4parser.boxes.apple;
+
+import com.googlecode.mp4parser.AbstractContainerBox;
+
+public class GenericMediaHeaderAtom extends AbstractContainerBox {
+
+    public static final String TYPE = "gmhd";
+
+    public GenericMediaHeaderAtom() {
+        super(TYPE);
+    }
+
+}
diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/boxes/apple/GenericMediaHeaderTextAtom.java b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/apple/GenericMediaHeaderTextAtom.java
new file mode 100644
index 0000000..fd52dc9
--- /dev/null
+++ b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/apple/GenericMediaHeaderTextAtom.java
@@ -0,0 +1,130 @@
+package com.googlecode.mp4parser.boxes.apple;
+
+import com.googlecode.mp4parser.AbstractBox;
+
+import java.nio.ByteBuffer;
+
+/**
+ * Undocumented atom in the gmhd atom of text tracks.
+ */
+public class GenericMediaHeaderTextAtom extends AbstractBox {
+
+    public static final String TYPE = "text";
+
+    int unknown_1 = 65536;
+    int unknown_2;
+    int unknown_3;
+    int unknown_4;
+    int unknown_5 = 65536;
+    int unknown_6;
+    int unknown_7;
+    int unknown_8;
+    int unknown_9 = 1073741824;
+
+    public GenericMediaHeaderTextAtom() {
+        super(TYPE);
+    }
+
+    @Override
+    protected long getContentSize() {
+        return 36;
+    }
+
+    @Override
+    protected void getContent(ByteBuffer byteBuffer) {
+        byteBuffer.putInt(unknown_1);
+        byteBuffer.putInt(unknown_2);
+        byteBuffer.putInt(unknown_3);
+        byteBuffer.putInt(unknown_4);
+        byteBuffer.putInt(unknown_5);
+        byteBuffer.putInt(unknown_6);
+        byteBuffer.putInt(unknown_7);
+        byteBuffer.putInt(unknown_8);
+        byteBuffer.putInt(unknown_9);
+    }
+
+    @Override
+    protected void _parseDetails(ByteBuffer content) {
+        unknown_1 = content.getInt();
+        unknown_2 = content.getInt();
+        unknown_3 = content.getInt();
+        unknown_4 = content.getInt();
+        unknown_5 = content.getInt();
+        unknown_6 = content.getInt();
+        unknown_7 = content.getInt();
+        unknown_8 = content.getInt();
+        unknown_9 = content.getInt();
+    }
+
+    public int getUnknown_1() {
+        return unknown_1;
+    }
+
+    public void setUnknown_1(int unknown_1) {
+        this.unknown_1 = unknown_1;
+    }
+
+    public int getUnknown_2() {
+        return unknown_2;
+    }
+
+    public void setUnknown_2(int unknown_2) {
+        this.unknown_2 = unknown_2;
+    }
+
+    public int getUnknown_3() {
+        return unknown_3;
+    }
+
+    public void setUnknown_3(int unknown_3) {
+        this.unknown_3 = unknown_3;
+    }
+
+    public int getUnknown_4() {
+        return unknown_4;
+    }
+
+    public void setUnknown_4(int unknown_4) {
+        this.unknown_4 = unknown_4;
+    }
+
+    public int getUnknown_5() {
+        return unknown_5;
+    }
+
+    public void setUnknown_5(int unknown_5) {
+        this.unknown_5 = unknown_5;
+    }
+
+    public int getUnknown_6() {
+        return unknown_6;
+    }
+
+    public void setUnknown_6(int unknown_6) {
+        this.unknown_6 = unknown_6;
+    }
+
+    public int getUnknown_7() {
+        return unknown_7;
+    }
+
+    public void setUnknown_7(int unknown_7) {
+        this.unknown_7 = unknown_7;
+    }
+
+    public int getUnknown_8() {
+        return unknown_8;
+    }
+
+    public void setUnknown_8(int unknown_8) {
+        this.unknown_8 = unknown_8;
+    }
+
+    public int getUnknown_9() {
+        return unknown_9;
+    }
+
+    public void setUnknown_9(int unknown_9) {
+        this.unknown_9 = unknown_9;
+    }
+}
diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/boxes/apple/QuicktimeTextSampleEntry.java b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/apple/QuicktimeTextSampleEntry.java
new file mode 100644
index 0000000..8784fc6
--- /dev/null
+++ b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/apple/QuicktimeTextSampleEntry.java
@@ -0,0 +1,237 @@
+/*
+ * Copyright 2012 Sebastian Annies, Hamburg
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.googlecode.mp4parser.boxes.apple;
+
+import com.coremedia.iso.IsoTypeReader;
+import com.coremedia.iso.IsoTypeWriter;
+import com.coremedia.iso.boxes.sampleentry.SampleEntry;
+
+import java.nio.ByteBuffer;
+
+/**
+ * Entry type for timed text samples defined in the timed text specification (ISO/IEC 14496-17).
+ */
+public class QuicktimeTextSampleEntry extends SampleEntry {
+
+    public static final String TYPE = "text";
+
+    int displayFlags;
+    int textJustification;
+
+    int backgroundR;
+    int backgroundG;
+    int backgroundB;
+
+    long defaultTextBox;
+    long reserved1;
+
+    short fontNumber;
+    short fontFace;
+    byte reserved2;
+    short reserved3;
+
+    int foregroundR = 65535;
+    int foregroundG = 65535;
+    int foregroundB = 65535;
+
+    String fontName = "";
+
+    public QuicktimeTextSampleEntry() {
+        super(TYPE);
+    }
+
+    @Override
+    public void _parseDetails(ByteBuffer content) {
+        _parseReservedAndDataReferenceIndex(content);
+
+        displayFlags = content.getInt();
+        textJustification = content.getInt();
+        backgroundR = IsoTypeReader.readUInt16(content);
+        backgroundG = IsoTypeReader.readUInt16(content);
+        backgroundB = IsoTypeReader.readUInt16(content);
+        defaultTextBox = IsoTypeReader.readUInt64(content);
+        reserved1 = IsoTypeReader.readUInt64(content);
+        fontNumber = content.getShort();
+        fontFace = content.getShort();
+        reserved2 = content.get();
+        reserved3 = content.getShort();
+        foregroundR = IsoTypeReader.readUInt16(content);
+        foregroundG = IsoTypeReader.readUInt16(content);
+        foregroundB = IsoTypeReader.readUInt16(content);
+
+        if (content.remaining() > 0) {
+            int length = IsoTypeReader.readUInt8(content);
+            byte[] myFontName = new byte[length];
+            content.get(myFontName);
+            fontName = new String(myFontName);
+        } else {
+            fontName = null;
+        }
+    }
+
+
+    protected long getContentSize() {
+        return 52 + (fontName != null ? fontName.length() : 0);
+    }
+
+
+    public int getDisplayFlags() {
+        return displayFlags;
+    }
+
+    public void setDisplayFlags(int displayFlags) {
+        this.displayFlags = displayFlags;
+    }
+
+    public int getTextJustification() {
+        return textJustification;
+    }
+
+    public void setTextJustification(int textJustification) {
+        this.textJustification = textJustification;
+    }
+
+    public int getBackgroundR() {
+        return backgroundR;
+    }
+
+    public void setBackgroundR(int backgroundR) {
+        this.backgroundR = backgroundR;
+    }
+
+    public int getBackgroundG() {
+        return backgroundG;
+    }
+
+    public void setBackgroundG(int backgroundG) {
+        this.backgroundG = backgroundG;
+    }
+
+    public int getBackgroundB() {
+        return backgroundB;
+    }
+
+    public void setBackgroundB(int backgroundB) {
+        this.backgroundB = backgroundB;
+    }
+
+    public long getDefaultTextBox() {
+        return defaultTextBox;
+    }
+
+    public void setDefaultTextBox(long defaultTextBox) {
+        this.defaultTextBox = defaultTextBox;
+    }
+
+    public long getReserved1() {
+        return reserved1;
+    }
+
+    public void setReserved1(long reserved1) {
+        this.reserved1 = reserved1;
+    }
+
+    public short getFontNumber() {
+        return fontNumber;
+    }
+
+    public void setFontNumber(short fontNumber) {
+        this.fontNumber = fontNumber;
+    }
+
+    public short getFontFace() {
+        return fontFace;
+    }
+
+    public void setFontFace(short fontFace) {
+        this.fontFace = fontFace;
+    }
+
+    public byte getReserved2() {
+        return reserved2;
+    }
+
+    public void setReserved2(byte reserved2) {
+        this.reserved2 = reserved2;
+    }
+
+    public short getReserved3() {
+        return reserved3;
+    }
+
+    public void setReserved3(short reserved3) {
+        this.reserved3 = reserved3;
+    }
+
+    public int getForegroundR() {
+        return foregroundR;
+    }
+
+    public void setForegroundR(int foregroundR) {
+        this.foregroundR = foregroundR;
+    }
+
+    public int getForegroundG() {
+        return foregroundG;
+    }
+
+    public void setForegroundG(int foregroundG) {
+        this.foregroundG = foregroundG;
+    }
+
+    public int getForegroundB() {
+        return foregroundB;
+    }
+
+    public void setForegroundB(int foregroundB) {
+        this.foregroundB = foregroundB;
+    }
+
+    public String getFontName() {
+        return fontName;
+    }
+
+    public void setFontName(String fontName) {
+        this.fontName = fontName;
+    }
+
+    @Override
+    protected void getContent(ByteBuffer byteBuffer) {
+        _writeReservedAndDataReferenceIndex(byteBuffer);
+        byteBuffer.putInt(displayFlags);
+        byteBuffer.putInt(textJustification);
+        IsoTypeWriter.writeUInt16(byteBuffer, backgroundR);
+        IsoTypeWriter.writeUInt16(byteBuffer, backgroundG);
+        IsoTypeWriter.writeUInt16(byteBuffer, backgroundB);
+        IsoTypeWriter.writeUInt64(byteBuffer, defaultTextBox);
+        IsoTypeWriter.writeUInt64(byteBuffer, reserved1);
+        byteBuffer.putShort(fontNumber);
+        byteBuffer.putShort(fontFace);
+        byteBuffer.put(reserved2);
+        byteBuffer.putShort(reserved3);
+
+        IsoTypeWriter.writeUInt16(byteBuffer, foregroundR);
+        IsoTypeWriter.writeUInt16(byteBuffer, foregroundG);
+        IsoTypeWriter.writeUInt16(byteBuffer, foregroundB);
+        if (fontName != null) {
+            IsoTypeWriter.writeUInt8(byteBuffer, fontName.length());
+            byteBuffer.put(fontName.getBytes());
+        }
+
+    }
+
+
+}
diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/boxes/apple/TaptAtom.java b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/apple/TaptAtom.java
new file mode 100644
index 0000000..4fcea56
--- /dev/null
+++ b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/apple/TaptAtom.java
@@ -0,0 +1,16 @@
+package com.googlecode.mp4parser.boxes.apple;
+
+import com.googlecode.mp4parser.AbstractContainerBox;
+
+/**
+ * Don't know what it is but it is obviously a container box.
+ */
+public class TaptAtom extends AbstractContainerBox {
+    public static final String TYPE = "tapt";
+
+    public TaptAtom() {
+        super(TYPE);
+    }
+
+
+}
diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/boxes/apple/TimeCodeBox.java b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/apple/TimeCodeBox.java
new file mode 100644
index 0000000..e15c9f0
--- /dev/null
+++ b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/apple/TimeCodeBox.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright 2012 Sebastian Annies, Hamburg
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.googlecode.mp4parser.boxes.apple;
+
+import com.coremedia.iso.boxes.Box;
+import com.coremedia.iso.boxes.sampleentry.SampleEntry;
+
+import java.nio.ByteBuffer;
+
+public class TimeCodeBox extends SampleEntry {
+    byte[] data;
+
+
+    public TimeCodeBox() {
+        super("tmcd");
+    }
+
+    @Override
+    protected long getContentSize() {
+        long size = 26;
+        for (Box box : boxes) {
+            size += box.getSize();
+        }
+        return size;
+    }
+
+    @Override
+    public void _parseDetails(ByteBuffer content) {
+        _parseReservedAndDataReferenceIndex(content);
+        data = new byte[18];
+        content.get(data);
+        _parseChildBoxes(content);
+    }
+
+    @Override
+    protected void getContent(ByteBuffer byteBuffer) {
+        _writeReservedAndDataReferenceIndex(byteBuffer);
+        byteBuffer.put(data);
+        _writeChildBoxes(byteBuffer);
+    }
+}
diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/boxes/basemediaformat/.svn/all-wcprops b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/basemediaformat/.svn/all-wcprops
new file mode 100644
index 0000000..f4b1c1b
--- /dev/null
+++ b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/basemediaformat/.svn/all-wcprops
@@ -0,0 +1,23 @@
+K 25
+svn:wc:ra_dav:version-url
+V 94
+/svn/!svn/ver/671/trunk/isoparser/src/main/java/com/googlecode/mp4parser/boxes/basemediaformat
+END
+AvcNalUnitStorageBox.java
+K 25
+svn:wc:ra_dav:version-url
+V 120
+/svn/!svn/ver/671/trunk/isoparser/src/main/java/com/googlecode/mp4parser/boxes/basemediaformat/AvcNalUnitStorageBox.java
+END
+SampleEncryptionBox.java
+K 25
+svn:wc:ra_dav:version-url
+V 119
+/svn/!svn/ver/377/trunk/isoparser/src/main/java/com/googlecode/mp4parser/boxes/basemediaformat/SampleEncryptionBox.java
+END
+TrackEncryptionBox.java
+K 25
+svn:wc:ra_dav:version-url
+V 118
+/svn/!svn/ver/276/trunk/isoparser/src/main/java/com/googlecode/mp4parser/boxes/basemediaformat/TrackEncryptionBox.java
+END
diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/boxes/basemediaformat/.svn/entries b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/basemediaformat/.svn/entries
new file mode 100644
index 0000000..6af5ffa
--- /dev/null
+++ b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/basemediaformat/.svn/entries
@@ -0,0 +1,130 @@
+10
+
+dir
+778
+http://mp4parser.googlecode.com/svn/trunk/isoparser/src/main/java/com/googlecode/mp4parser/boxes/basemediaformat
+http://mp4parser.googlecode.com/svn
+
+
+
+2012-06-10T18:50:38.971172Z
+671
+michael.stattmann@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+7decde4b-c250-0410-a0da-51896bc88be6
+
+AvcNalUnitStorageBox.java
+file
+
+
+
+
+2012-09-14T17:27:50.667221Z
+fa9f9cda733943c6af5e690156163dcb
+2012-06-10T18:50:38.971172Z
+671
+michael.stattmann@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+3290
+
+SampleEncryptionBox.java
+file
+
+
+
+
+2012-09-14T17:27:50.667221Z
+b451a1521659345d7712cbb874eec98f
+2012-03-05T23:28:24.666173Z
+377
+Sebastian.Annies@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+618
+
+TrackEncryptionBox.java
+file
+
+
+
+
+2012-09-14T17:27:50.667221Z
+9ab827bee01e8abfe68167428df756dc
+2011-11-22T18:13:22.290919Z
+276
+Sebastian.Annies@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+269
+
diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/boxes/basemediaformat/.svn/text-base/AvcNalUnitStorageBox.java.svn-base b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/basemediaformat/.svn/text-base/AvcNalUnitStorageBox.java.svn-base
new file mode 100644
index 0000000..7182eca
--- /dev/null
+++ b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/basemediaformat/.svn/text-base/AvcNalUnitStorageBox.java.svn-base
@@ -0,0 +1,97 @@
+/*
+ * 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.basemediaformat;
+
+import com.googlecode.mp4parser.AbstractBox;
+import com.coremedia.iso.boxes.h264.AvcConfigurationBox;
+
+import java.io.ByteArrayOutputStream;
+import java.nio.ByteBuffer;
+import java.util.Arrays;
+import java.util.List;
+
+import static com.googlecode.mp4parser.util.CastUtils.l2i;
+
+/**
+ * The AVC NAL Unit Storage Box SHALL contain an AVCDecoderConfigurationRecord,
+ * as defined in section 5.2.4.1 of the ISO 14496-12.
+ */
+public class AvcNalUnitStorageBox extends AbstractBox {
+    AvcConfigurationBox.AVCDecoderConfigurationRecord avcDecoderConfigurationRecord;
+
+    public AvcNalUnitStorageBox() {
+        super("avcn");
+    }
+
+    public AvcNalUnitStorageBox(AvcConfigurationBox avcConfigurationBox) {
+        super("avcn");
+        this.avcDecoderConfigurationRecord = avcConfigurationBox.getavcDecoderConfigurationRecord();
+    }
+
+    public AvcConfigurationBox.AVCDecoderConfigurationRecord getAvcDecoderConfigurationRecord() {
+        return avcDecoderConfigurationRecord;
+    }
+
+    // just to display sps in isoviewer no practical use
+    public int getLengthSizeMinusOne() {
+        return avcDecoderConfigurationRecord.lengthSizeMinusOne;
+    }
+
+    public String[] getSPS() {
+        return avcDecoderConfigurationRecord.getSPS();
+    }
+
+    public String[] getPPS() {
+        return avcDecoderConfigurationRecord.getPPS();
+    }
+
+    public List<String> getSequenceParameterSetsAsStrings() {
+        return avcDecoderConfigurationRecord.getSequenceParameterSetsAsStrings();
+    }
+
+    public List<String> getSequenceParameterSetExtsAsStrings() {
+        return avcDecoderConfigurationRecord.getSequenceParameterSetExtsAsStrings();
+    }
+
+    public List<String> getPictureParameterSetsAsStrings() {
+        return avcDecoderConfigurationRecord.getPictureParameterSetsAsStrings();
+    }
+
+    @Override
+    protected long getContentSize() {
+        return avcDecoderConfigurationRecord.getContentSize();
+    }
+
+    @Override
+    public void _parseDetails(ByteBuffer content) {
+        this.avcDecoderConfigurationRecord = new AvcConfigurationBox.AVCDecoderConfigurationRecord(content);
+    }
+
+    @Override
+    protected void getContent(ByteBuffer byteBuffer) {
+        this.avcDecoderConfigurationRecord.getContent(byteBuffer);
+    }
+
+    @Override
+    public String toString() {
+        return "AvcNalUnitStorageBox{" +
+                "SPS=" + avcDecoderConfigurationRecord.getSequenceParameterSetsAsStrings() +
+                ",PPS=" + avcDecoderConfigurationRecord.getPictureParameterSetsAsStrings() +
+                ",lengthSize=" + (avcDecoderConfigurationRecord.lengthSizeMinusOne + 1) +
+                '}';
+    }
+}
diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/boxes/basemediaformat/.svn/text-base/SampleEncryptionBox.java.svn-base b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/basemediaformat/.svn/text-base/SampleEncryptionBox.java.svn-base
new file mode 100644
index 0000000..3430818
--- /dev/null
+++ b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/basemediaformat/.svn/text-base/SampleEncryptionBox.java.svn-base
@@ -0,0 +1,24 @@
+package com.googlecode.mp4parser.boxes.basemediaformat;
+
+import com.googlecode.mp4parser.boxes.AbstractSampleEncryptionBox;
+
+/**
+ * aligned(8) class AbstractSampleEncryptionBox extends FullBox(‘uuid’, extended_type= 0xA2394F52-5A9B-4f14-A244-6C427C648DF4, version=0, flags=0)
+ * {
+ * <p/>
+ * unsigned int (32) sample_count;
+ * {
+ * unsigned int(16) InitializationVector;
+ * }[ sample_count ]
+ * }
+ */
+public class SampleEncryptionBox extends AbstractSampleEncryptionBox {
+
+    /**
+     * Creates a SampleEncryptionBox for non-h264 tracks.
+     */
+    public SampleEncryptionBox() {
+        super("senc");
+
+    }
+}
diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/boxes/basemediaformat/.svn/text-base/TrackEncryptionBox.java.svn-base b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/basemediaformat/.svn/text-base/TrackEncryptionBox.java.svn-base
new file mode 100644
index 0000000..dd93a12
--- /dev/null
+++ b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/basemediaformat/.svn/text-base/TrackEncryptionBox.java.svn-base
@@ -0,0 +1,12 @@
+package com.googlecode.mp4parser.boxes.basemediaformat;
+
+import com.googlecode.mp4parser.boxes.AbstractTrackEncryptionBox;
+
+/**
+ *
+ */
+public class TrackEncryptionBox extends AbstractTrackEncryptionBox {
+    public TrackEncryptionBox() {
+        super("tenc");
+    }
+}
diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/boxes/basemediaformat/AvcNalUnitStorageBox.java b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/basemediaformat/AvcNalUnitStorageBox.java
new file mode 100644
index 0000000..7182eca
--- /dev/null
+++ b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/basemediaformat/AvcNalUnitStorageBox.java
@@ -0,0 +1,97 @@
+/*
+ * 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.basemediaformat;
+
+import com.googlecode.mp4parser.AbstractBox;
+import com.coremedia.iso.boxes.h264.AvcConfigurationBox;
+
+import java.io.ByteArrayOutputStream;
+import java.nio.ByteBuffer;
+import java.util.Arrays;
+import java.util.List;
+
+import static com.googlecode.mp4parser.util.CastUtils.l2i;
+
+/**
+ * The AVC NAL Unit Storage Box SHALL contain an AVCDecoderConfigurationRecord,
+ * as defined in section 5.2.4.1 of the ISO 14496-12.
+ */
+public class AvcNalUnitStorageBox extends AbstractBox {
+    AvcConfigurationBox.AVCDecoderConfigurationRecord avcDecoderConfigurationRecord;
+
+    public AvcNalUnitStorageBox() {
+        super("avcn");
+    }
+
+    public AvcNalUnitStorageBox(AvcConfigurationBox avcConfigurationBox) {
+        super("avcn");
+        this.avcDecoderConfigurationRecord = avcConfigurationBox.getavcDecoderConfigurationRecord();
+    }
+
+    public AvcConfigurationBox.AVCDecoderConfigurationRecord getAvcDecoderConfigurationRecord() {
+        return avcDecoderConfigurationRecord;
+    }
+
+    // just to display sps in isoviewer no practical use
+    public int getLengthSizeMinusOne() {
+        return avcDecoderConfigurationRecord.lengthSizeMinusOne;
+    }
+
+    public String[] getSPS() {
+        return avcDecoderConfigurationRecord.getSPS();
+    }
+
+    public String[] getPPS() {
+        return avcDecoderConfigurationRecord.getPPS();
+    }
+
+    public List<String> getSequenceParameterSetsAsStrings() {
+        return avcDecoderConfigurationRecord.getSequenceParameterSetsAsStrings();
+    }
+
+    public List<String> getSequenceParameterSetExtsAsStrings() {
+        return avcDecoderConfigurationRecord.getSequenceParameterSetExtsAsStrings();
+    }
+
+    public List<String> getPictureParameterSetsAsStrings() {
+        return avcDecoderConfigurationRecord.getPictureParameterSetsAsStrings();
+    }
+
+    @Override
+    protected long getContentSize() {
+        return avcDecoderConfigurationRecord.getContentSize();
+    }
+
+    @Override
+    public void _parseDetails(ByteBuffer content) {
+        this.avcDecoderConfigurationRecord = new AvcConfigurationBox.AVCDecoderConfigurationRecord(content);
+    }
+
+    @Override
+    protected void getContent(ByteBuffer byteBuffer) {
+        this.avcDecoderConfigurationRecord.getContent(byteBuffer);
+    }
+
+    @Override
+    public String toString() {
+        return "AvcNalUnitStorageBox{" +
+                "SPS=" + avcDecoderConfigurationRecord.getSequenceParameterSetsAsStrings() +
+                ",PPS=" + avcDecoderConfigurationRecord.getPictureParameterSetsAsStrings() +
+                ",lengthSize=" + (avcDecoderConfigurationRecord.lengthSizeMinusOne + 1) +
+                '}';
+    }
+}
diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/boxes/basemediaformat/SampleEncryptionBox.java b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/basemediaformat/SampleEncryptionBox.java
new file mode 100644
index 0000000..3430818
--- /dev/null
+++ b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/basemediaformat/SampleEncryptionBox.java
@@ -0,0 +1,24 @@
+package com.googlecode.mp4parser.boxes.basemediaformat;
+
+import com.googlecode.mp4parser.boxes.AbstractSampleEncryptionBox;
+
+/**
+ * aligned(8) class AbstractSampleEncryptionBox extends FullBox(‘uuid’, extended_type= 0xA2394F52-5A9B-4f14-A244-6C427C648DF4, version=0, flags=0)
+ * {
+ * <p/>
+ * unsigned int (32) sample_count;
+ * {
+ * unsigned int(16) InitializationVector;
+ * }[ sample_count ]
+ * }
+ */
+public class SampleEncryptionBox extends AbstractSampleEncryptionBox {
+
+    /**
+     * Creates a SampleEncryptionBox for non-h264 tracks.
+     */
+    public SampleEncryptionBox() {
+        super("senc");
+
+    }
+}
diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/boxes/basemediaformat/TrackEncryptionBox.java b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/basemediaformat/TrackEncryptionBox.java
new file mode 100644
index 0000000..dd93a12
--- /dev/null
+++ b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/basemediaformat/TrackEncryptionBox.java
@@ -0,0 +1,12 @@
+package com.googlecode.mp4parser.boxes.basemediaformat;
+
+import com.googlecode.mp4parser.boxes.AbstractTrackEncryptionBox;
+
+/**
+ *
+ */
+public class TrackEncryptionBox extends AbstractTrackEncryptionBox {
+    public TrackEncryptionBox() {
+        super("tenc");
+    }
+}
diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/boxes/cenc/.svn/all-wcprops b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/cenc/.svn/all-wcprops
new file mode 100644
index 0000000..54b03df
--- /dev/null
+++ b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/cenc/.svn/all-wcprops
@@ -0,0 +1,11 @@
+K 25
+svn:wc:ra_dav:version-url
+V 83
+/svn/!svn/ver/728/trunk/isoparser/src/main/java/com/googlecode/mp4parser/boxes/cenc
+END
+ProtectionSystemSpecificHeaderBox.java
+K 25
+svn:wc:ra_dav:version-url
+V 122
+/svn/!svn/ver/728/trunk/isoparser/src/main/java/com/googlecode/mp4parser/boxes/cenc/ProtectionSystemSpecificHeaderBox.java
+END
diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/boxes/cenc/.svn/entries b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/cenc/.svn/entries
new file mode 100644
index 0000000..c96b178
--- /dev/null
+++ b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/cenc/.svn/entries
@@ -0,0 +1,62 @@
+10
+
+dir
+778
+http://mp4parser.googlecode.com/svn/trunk/isoparser/src/main/java/com/googlecode/mp4parser/boxes/cenc
+http://mp4parser.googlecode.com/svn
+
+
+
+2012-08-08T11:39:22.997932Z
+728
+Sebastian.Annies@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+7decde4b-c250-0410-a0da-51896bc88be6
+
+ProtectionSystemSpecificHeaderBox.java
+file
+
+
+
+
+2012-09-14T17:27:51.237229Z
+5722926350b47a524ba4c38adeafe5bd
+2012-08-08T11:39:22.997932Z
+728
+Sebastian.Annies@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+3203
+
diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/boxes/cenc/.svn/text-base/ProtectionSystemSpecificHeaderBox.java.svn-base b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/cenc/.svn/text-base/ProtectionSystemSpecificHeaderBox.java.svn-base
new file mode 100644
index 0000000..d6b653c
--- /dev/null
+++ b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/cenc/.svn/text-base/ProtectionSystemSpecificHeaderBox.java.svn-base
@@ -0,0 +1,89 @@
+package com.googlecode.mp4parser.boxes.cenc;
+
+import com.coremedia.iso.BoxParser;
+import com.coremedia.iso.IsoFile;
+import com.coremedia.iso.IsoTypeReader;
+import com.coremedia.iso.IsoTypeWriter;
+import com.coremedia.iso.boxes.Box;
+import com.googlecode.mp4parser.AbstractFullBox;
+import com.googlecode.mp4parser.util.UUIDConverter;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.util.UUID;
+
+
+
+/**
+ * This box contains information needed by a Content Protection System to play back the content. The
+ * data format is specified by the system identified by the ‘pssh’ parameter SystemID, and is considered
+ * opaque for the purposes of this specification.
+ * <p/>
+ * The data encapsulated in the Data field may be read by the identified Content Protection System to
+ * enable decryption key acquisition and decryption of media data. For license/rights-based systems, the
+ * header information may include data such as the URL of license server(s) or rights issuer(s) used,
+ * embedded licenses/rights, and/or other protection system specific metadata.
+ * <p/>
+ * A single file may be constructed to be playable by multiple key and digital rights management (DRM)
+ * systems, by including one Protection System-Specific Header box for each system supported. Readers
+ * that process such presentations must match the SystemID field in this box to the SystemID(s) of the
+ * DRM System(s) they support, and select or create the matching Protection System-Specific Header
+ * box(es) for storage and retrieval of Protection-Specific information interpreted or created by that DRM
+ * system.
+ */
+public class ProtectionSystemSpecificHeaderBox extends AbstractFullBox {
+    public static final String TYPE = "pssh";
+
+    public static byte[] OMA2_SYSTEM_ID = UUIDConverter.convert(UUID.fromString("A2B55680-6F43-11E0-9A3F-0002A5D5C51B"));
+    public static byte[] PLAYREADY_SYSTEM_ID = UUIDConverter.convert(UUID.fromString("9A04F079-9840-4286-AB92-E65BE0885F95"));
+
+    byte[] content;
+    byte[] systemId;
+
+
+    public byte[] getSystemId() {
+        return systemId;
+    }
+
+    public void setSystemId(byte[] systemId) {
+        assert systemId.length == 16;
+        this.systemId = systemId;
+    }
+
+    public byte[] getContent() {
+        return content;
+    }
+
+    public void setContent(byte[] content) {
+        this.content = content;
+    }
+
+    public ProtectionSystemSpecificHeaderBox() {
+        super(TYPE);
+    }
+
+    @Override
+    protected long getContentSize() {
+        return 24 + content.length;
+    }
+
+    @Override
+    protected void getContent(ByteBuffer byteBuffer) {
+        writeVersionAndFlags(byteBuffer);
+        assert systemId.length == 16;
+        byteBuffer.put(systemId, 0, 16);
+        IsoTypeWriter.writeUInt32(byteBuffer, content.length);
+        byteBuffer.put(content);
+    }
+
+    @Override
+    protected void _parseDetails(ByteBuffer content) {
+        parseVersionAndFlags(content);
+        systemId = new byte[16];
+        content.get(systemId);
+        long length = IsoTypeReader.readUInt32(content);
+        this.content = new byte[content.remaining()];
+        content.get(this.content);
+        assert length == this.content.length;
+    }
+}
diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/boxes/cenc/ProtectionSystemSpecificHeaderBox.java b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/cenc/ProtectionSystemSpecificHeaderBox.java
new file mode 100644
index 0000000..d6b653c
--- /dev/null
+++ b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/cenc/ProtectionSystemSpecificHeaderBox.java
@@ -0,0 +1,89 @@
+package com.googlecode.mp4parser.boxes.cenc;
+
+import com.coremedia.iso.BoxParser;
+import com.coremedia.iso.IsoFile;
+import com.coremedia.iso.IsoTypeReader;
+import com.coremedia.iso.IsoTypeWriter;
+import com.coremedia.iso.boxes.Box;
+import com.googlecode.mp4parser.AbstractFullBox;
+import com.googlecode.mp4parser.util.UUIDConverter;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.util.UUID;
+
+
+
+/**
+ * This box contains information needed by a Content Protection System to play back the content. The
+ * data format is specified by the system identified by the ‘pssh’ parameter SystemID, and is considered
+ * opaque for the purposes of this specification.
+ * <p/>
+ * The data encapsulated in the Data field may be read by the identified Content Protection System to
+ * enable decryption key acquisition and decryption of media data. For license/rights-based systems, the
+ * header information may include data such as the URL of license server(s) or rights issuer(s) used,
+ * embedded licenses/rights, and/or other protection system specific metadata.
+ * <p/>
+ * A single file may be constructed to be playable by multiple key and digital rights management (DRM)
+ * systems, by including one Protection System-Specific Header box for each system supported. Readers
+ * that process such presentations must match the SystemID field in this box to the SystemID(s) of the
+ * DRM System(s) they support, and select or create the matching Protection System-Specific Header
+ * box(es) for storage and retrieval of Protection-Specific information interpreted or created by that DRM
+ * system.
+ */
+public class ProtectionSystemSpecificHeaderBox extends AbstractFullBox {
+    public static final String TYPE = "pssh";
+
+    public static byte[] OMA2_SYSTEM_ID = UUIDConverter.convert(UUID.fromString("A2B55680-6F43-11E0-9A3F-0002A5D5C51B"));
+    public static byte[] PLAYREADY_SYSTEM_ID = UUIDConverter.convert(UUID.fromString("9A04F079-9840-4286-AB92-E65BE0885F95"));
+
+    byte[] content;
+    byte[] systemId;
+
+
+    public byte[] getSystemId() {
+        return systemId;
+    }
+
+    public void setSystemId(byte[] systemId) {
+        assert systemId.length == 16;
+        this.systemId = systemId;
+    }
+
+    public byte[] getContent() {
+        return content;
+    }
+
+    public void setContent(byte[] content) {
+        this.content = content;
+    }
+
+    public ProtectionSystemSpecificHeaderBox() {
+        super(TYPE);
+    }
+
+    @Override
+    protected long getContentSize() {
+        return 24 + content.length;
+    }
+
+    @Override
+    protected void getContent(ByteBuffer byteBuffer) {
+        writeVersionAndFlags(byteBuffer);
+        assert systemId.length == 16;
+        byteBuffer.put(systemId, 0, 16);
+        IsoTypeWriter.writeUInt32(byteBuffer, content.length);
+        byteBuffer.put(content);
+    }
+
+    @Override
+    protected void _parseDetails(ByteBuffer content) {
+        parseVersionAndFlags(content);
+        systemId = new byte[16];
+        content.get(systemId);
+        long length = IsoTypeReader.readUInt32(content);
+        this.content = new byte[content.remaining()];
+        content.get(this.content);
+        assert length == this.content.length;
+    }
+}
diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/boxes/mp4-boxes.zip b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/mp4-boxes.zip
new file mode 100644
index 0000000..c9bcf8b
--- /dev/null
+++ b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/mp4-boxes.zip
Binary files differ
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();
+    }
+}
diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/boxes/piff/.svn/all-wcprops b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/piff/.svn/all-wcprops
new file mode 100644
index 0000000..73d7e4e
--- /dev/null
+++ b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/piff/.svn/all-wcprops
@@ -0,0 +1,47 @@
+K 25
+svn:wc:ra_dav:version-url
+V 83
+/svn/!svn/ver/616/trunk/isoparser/src/main/java/com/googlecode/mp4parser/boxes/piff
+END
+PlayReadyHeader.java
+K 25
+svn:wc:ra_dav:version-url
+V 104
+/svn/!svn/ver/525/trunk/isoparser/src/main/java/com/googlecode/mp4parser/boxes/piff/PlayReadyHeader.java
+END
+ProtectionSpecificHeader.java
+K 25
+svn:wc:ra_dav:version-url
+V 113
+/svn/!svn/ver/527/trunk/isoparser/src/main/java/com/googlecode/mp4parser/boxes/piff/ProtectionSpecificHeader.java
+END
+UuidBasedProtectionSystemSpecificHeaderBox.java
+K 25
+svn:wc:ra_dav:version-url
+V 131
+/svn/!svn/ver/616/trunk/isoparser/src/main/java/com/googlecode/mp4parser/boxes/piff/UuidBasedProtectionSystemSpecificHeaderBox.java
+END
+PiffSampleEncryptionBox.java
+K 25
+svn:wc:ra_dav:version-url
+V 112
+/svn/!svn/ver/377/trunk/isoparser/src/main/java/com/googlecode/mp4parser/boxes/piff/PiffSampleEncryptionBox.java
+END
+TfrfBox.java
+K 25
+svn:wc:ra_dav:version-url
+V 96
+/svn/!svn/ver/507/trunk/isoparser/src/main/java/com/googlecode/mp4parser/boxes/piff/TfrfBox.java
+END
+PiffTrackEncryptionBox.java
+K 25
+svn:wc:ra_dav:version-url
+V 111
+/svn/!svn/ver/377/trunk/isoparser/src/main/java/com/googlecode/mp4parser/boxes/piff/PiffTrackEncryptionBox.java
+END
+TfxdBox.java
+K 25
+svn:wc:ra_dav:version-url
+V 96
+/svn/!svn/ver/507/trunk/isoparser/src/main/java/com/googlecode/mp4parser/boxes/piff/TfxdBox.java
+END
diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/boxes/piff/.svn/entries b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/piff/.svn/entries
new file mode 100644
index 0000000..f869342
--- /dev/null
+++ b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/piff/.svn/entries
@@ -0,0 +1,266 @@
+10
+
+dir
+778
+http://mp4parser.googlecode.com/svn/trunk/isoparser/src/main/java/com/googlecode/mp4parser/boxes/piff
+http://mp4parser.googlecode.com/svn
+
+
+
+2012-05-17T09:04:15.805545Z
+616
+Sebastian.Annies@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+7decde4b-c250-0410-a0da-51896bc88be6
+
+PlayReadyHeader.java
+file
+
+
+
+
+2012-09-14T17:27:50.797223Z
+414299d2fe72802bfdba588cd197cc8d
+2012-04-25T19:24:04.485529Z
+525
+Sebastian.Annies@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+8099
+
+ProtectionSpecificHeader.java
+file
+
+
+
+
+2012-09-14T17:27:50.797223Z
+206bcc330dd14e88a9b36dbdab4b5676
+2012-04-25T23:16:14.370289Z
+527
+Sebastian.Annies@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+2339
+
+UuidBasedProtectionSystemSpecificHeaderBox.java
+file
+
+
+
+
+2012-09-14T17:27:50.797223Z
+bee6a83aa218637d445d55bb317bf1f0
+2012-05-17T09:04:15.805545Z
+616
+Sebastian.Annies@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+3419
+
+PiffSampleEncryptionBox.java
+file
+
+
+
+
+2012-09-14T17:27:50.797223Z
+e8e29f48bf61c02cd75f62b654664a1d
+2012-03-05T23:28:24.666173Z
+377
+Sebastian.Annies@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+1187
+
+TfrfBox.java
+file
+
+
+
+
+2012-09-14T17:27:50.797223Z
+87a71e91a262d3294bb9b1e4959b0b99
+2012-04-21T22:05:38.425329Z
+507
+Sebastian.Annies@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+4379
+
+PiffTrackEncryptionBox.java
+file
+
+
+
+
+2012-09-14T17:27:50.797223Z
+f412ae4506ee42fea327a2b274c0602d
+2012-03-05T23:28:24.666173Z
+377
+Sebastian.Annies@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+854
+
+TfxdBox.java
+file
+
+
+
+
+2012-09-14T17:27:50.807223Z
+d98ba32db0ee574c4130985dee95179a
+2012-04-21T22:05:38.425329Z
+507
+Sebastian.Annies@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+2998
+
diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/boxes/piff/.svn/text-base/PiffSampleEncryptionBox.java.svn-base b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/piff/.svn/text-base/PiffSampleEncryptionBox.java.svn-base
new file mode 100644
index 0000000..da3512d
--- /dev/null
+++ b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/piff/.svn/text-base/PiffSampleEncryptionBox.java.svn-base
@@ -0,0 +1,45 @@
+package com.googlecode.mp4parser.boxes.piff;
+
+import com.googlecode.mp4parser.boxes.AbstractSampleEncryptionBox;
+
+/**
+ * <pre>
+ * aligned(8) class SampleEncryptionBox extends FullBox(‘uuid’, extended_type= 0xA2394F52-5A9B-4f14-A244-6C427C648DF4, version=0, flags=0)
+ * {
+ *  if (flags & 0x000001)
+ *  {
+ *   unsigned int(24) AlgorithmID;
+ *   unsigned int(8) IV_size;
+ *   unsigned int(8)[16] KID;
+ *  }
+ *  unsigned int (32) sample_count;
+ *  {
+ *   unsigned int(IV_size) InitializationVector;
+ *   if (flags & 0x000002)
+ *   {
+ *    unsigned int(16) NumberOfEntries;
+ *    {
+ *     unsigned int(16) BytesOfClearData;
+ *     unsigned int(32) BytesOfEncryptedData;
+ *    } [ NumberOfEntries]
+ *   }
+ *  }[ sample_count ]
+ * }
+ * </pre>
+ */
+public class PiffSampleEncryptionBox extends AbstractSampleEncryptionBox {
+
+    /**
+     * Creates a AbstractSampleEncryptionBox for non-h264 tracks.
+     */
+    public PiffSampleEncryptionBox() {
+        super("uuid");
+
+    }
+
+    @Override
+    public byte[] getUserType() {
+        return new byte[]{(byte) 0xA2, 0x39, 0x4F, 0x52, 0x5A, (byte) 0x9B, 0x4f, 0x14, (byte) 0xA2, 0x44, 0x6C, 0x42, 0x7C, 0x64, (byte) 0x8D, (byte) 0xF4};
+    }
+
+}
diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/boxes/piff/.svn/text-base/PiffTrackEncryptionBox.java.svn-base b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/piff/.svn/text-base/PiffTrackEncryptionBox.java.svn-base
new file mode 100644
index 0000000..f92c0f3
--- /dev/null
+++ b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/piff/.svn/text-base/PiffTrackEncryptionBox.java.svn-base
@@ -0,0 +1,34 @@
+package com.googlecode.mp4parser.boxes.piff;
+
+import com.googlecode.mp4parser.boxes.AbstractTrackEncryptionBox;
+
+/**
+ * aligned(8) class TrackEncryptionBox extends FullBox(‘uuid’,
+ * extended_type=0x8974dbce-7be7-4c51-84f9-7148f9882554, version=0,
+ * flags=0)
+ * {
+ * unsigned int(24) default_AlgorithmID;
+ * unsigned int(8) default_IV_size;
+ * unsigned int(8)[16] default_KID;
+ * }
+ */
+public class PiffTrackEncryptionBox extends AbstractTrackEncryptionBox {
+
+
+    public PiffTrackEncryptionBox() {
+        super("uuid");
+    }
+
+    @Override
+    public byte[] getUserType() {
+        return new byte[]{(byte) 0x89, 0x74, (byte) 0xdb, (byte) 0xce, 0x7b, (byte) 0xe7, 0x4c, 0x51,
+                (byte) 0x84, (byte) 0xf9, 0x71, 0x48, (byte) 0xf9, (byte) 0x88, 0x25, 0x54};
+    }
+
+    @Override
+    public int getFlags() {
+        return 0;
+    }
+
+
+}
diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/boxes/piff/.svn/text-base/PlayReadyHeader.java.svn-base b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/piff/.svn/text-base/PlayReadyHeader.java.svn-base
new file mode 100644
index 0000000..74246d0
--- /dev/null
+++ b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/piff/.svn/text-base/PlayReadyHeader.java.svn-base
@@ -0,0 +1,253 @@
+package com.googlecode.mp4parser.boxes.piff;
+
+import com.coremedia.iso.IsoFile;
+import com.coremedia.iso.IsoTypeReader;
+import com.coremedia.iso.IsoTypeWriter;
+import com.googlecode.mp4parser.util.Path;
+
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.UnsupportedEncodingException;
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * Specifications > Microsoft PlayReady Format Specification > 2. PlayReady Media Format > 2.7. ASF GUIDs
+ * <p/>
+ * <p/>
+ * ASF_Protection_System_Identifier_Object
+ * 9A04F079-9840-4286-AB92E65BE0885F95
+ * <p/>
+ * ASF_Content_Protection_System_Microsoft_PlayReady
+ * F4637010-03C3-42CD-B932B48ADF3A6A54
+ * <p/>
+ * ASF_StreamType_PlayReady_Encrypted_Command_Media
+ * 8683973A-6639-463A-ABD764F1CE3EEAE0
+ * <p/>
+ * <p/>
+ * Specifications > Microsoft PlayReady Format Specification > 2. PlayReady Media Format > 2.5. Data Objects > 2.5.1. Payload Extension for AES in Counter Mode
+ * <p/>
+ * The sample Id is used as the IV in CTR mode. Block offset, starting at 0 and incremented by 1 after every 16 bytes, from the beginning of the sample is used as the Counter.
+ * <p/>
+ * The sample ID for each sample (media object) is stored as an ASF payload extension system with the ID of ASF_Payload_Extension_Encryption_SampleID = {6698B84E-0AFA-4330-AEB2-1C0A98D7A44D}. The payload extension can be stored as a fixed size extension of 8 bytes.
+ * <p/>
+ * The sample ID is always stored in big-endian byte order.
+ */
+public class PlayReadyHeader extends ProtectionSpecificHeader {
+    private long length;
+    private List<PlayReadyRecord> records;
+
+    public PlayReadyHeader() {
+
+    }
+
+    @Override
+    public void parse(ByteBuffer byteBuffer) {
+        /*
+   Length DWORD 32
+
+   PlayReady Record Count WORD 16
+
+   PlayReady Records See Text Varies
+
+        */
+
+        length = IsoTypeReader.readUInt32BE(byteBuffer);
+        int recordCount = IsoTypeReader.readUInt16BE(byteBuffer);
+
+        records = PlayReadyRecord.createFor(byteBuffer, recordCount);
+    }
+
+    @Override
+    public ByteBuffer getData() {
+
+        int size = 4 + 2;
+        for (PlayReadyRecord record : records) {
+            size += 2 + 2;
+            size += record.getValue().rewind().limit();
+        }
+        ByteBuffer byteBuffer = ByteBuffer.allocate(size);
+
+        IsoTypeWriter.writeUInt32BE(byteBuffer, size);
+        IsoTypeWriter.writeUInt16BE(byteBuffer, records.size());
+        for (PlayReadyRecord record : records) {
+            IsoTypeWriter.writeUInt16BE(byteBuffer, record.type);
+            IsoTypeWriter.writeUInt16BE(byteBuffer, record.getValue().limit());
+            ByteBuffer tmp4debug = record.getValue();
+            byteBuffer.put(tmp4debug);
+        }
+
+        return byteBuffer;
+    }
+
+    public void setRecords(List<PlayReadyRecord> records) {
+        this.records = records;
+    }
+
+    public List<PlayReadyRecord> getRecords() {
+        return Collections.unmodifiableList(records);
+    }
+
+    @Override
+    public String toString() {
+        final StringBuilder sb = new StringBuilder();
+        sb.append("PlayReadyHeader");
+        sb.append("{length=").append(length);
+        sb.append(", recordCount=").append(records.size());
+        sb.append(", records=").append(records);
+        sb.append('}');
+        return sb.toString();
+    }
+
+    public static abstract class PlayReadyRecord {
+        int type;
+
+
+        public PlayReadyRecord(int type) {
+            this.type = type;
+        }
+
+        public static List<PlayReadyRecord> createFor(ByteBuffer byteBuffer, int recordCount) {
+            List<PlayReadyRecord> records = new ArrayList<PlayReadyRecord>(recordCount);
+
+            for (int i = 0; i < recordCount; i++) {
+                PlayReadyRecord record;
+                int type = IsoTypeReader.readUInt16BE(byteBuffer);
+                int length = IsoTypeReader.readUInt16BE(byteBuffer);
+                switch (type) {
+                    case 0x1:
+                        record = new RMHeader();
+                        break;
+                    case 0x2:
+                        record = new DefaulPlayReadyRecord(0x02);
+                        break;
+                    case 0x3:
+                        record = new EmeddedLicenseStore();
+                        break;
+                    default:
+                        record = new DefaulPlayReadyRecord(type);
+                }
+                record.parse((ByteBuffer) byteBuffer.slice().limit(length));
+                byteBuffer.position(byteBuffer.position() + length);
+                records.add(record);
+            }
+
+            return records;
+        }
+
+        public abstract void parse(ByteBuffer bytes);
+
+        @Override
+        public String toString() {
+            final StringBuilder sb = new StringBuilder();
+            sb.append("PlayReadyRecord");
+            sb.append("{type=").append(type);
+            sb.append(", length=").append(getValue().limit());
+//            sb.append(", value=").append(Hex.encodeHex(getValue())).append('\'');
+            sb.append('}');
+            return sb.toString();
+        }
+
+        public abstract ByteBuffer getValue();
+
+        public static class RMHeader extends PlayReadyRecord {
+            String header;
+
+            public RMHeader() {
+                super(0x01);
+            }
+
+            @Override
+            public void parse(ByteBuffer bytes) {
+                try {
+                    byte[] str = new byte[bytes.slice().limit()];
+                    bytes.get(str);
+                    header = new String(str, "UTF-16LE");
+                } catch (UnsupportedEncodingException e) {
+                    throw new RuntimeException(e);
+                }
+            }
+
+            @Override
+            public ByteBuffer getValue() {
+                byte[] headerBytes;
+                try {
+                    headerBytes = header.getBytes("UTF-16LE");
+                } catch (UnsupportedEncodingException e) {
+                    throw new RuntimeException(e);
+                }
+                return ByteBuffer.wrap(headerBytes);
+            }
+
+            public void setHeader(String header) {
+                this.header = header;
+            }
+
+            public String getHeader() {
+                return header;
+            }
+
+            @Override
+            public String toString() {
+                final StringBuilder sb = new StringBuilder();
+                sb.append("RMHeader");
+                sb.append("{length=").append(getValue().limit());
+                sb.append(", header='").append(header).append('\'');
+                sb.append('}');
+                return sb.toString();
+            }
+        }
+
+        public static class EmeddedLicenseStore extends PlayReadyRecord {
+            ByteBuffer value;
+
+            public EmeddedLicenseStore() {
+                super(0x03);
+            }
+
+            @Override
+            public void parse(ByteBuffer bytes) {
+                this.value = bytes.duplicate();
+            }
+
+            @Override
+            public ByteBuffer getValue() {
+                return value;
+            }
+
+            @Override
+            public String toString() {
+                final StringBuilder sb = new StringBuilder();
+                sb.append("EmeddedLicenseStore");
+                sb.append("{length=").append(getValue().limit());
+                //sb.append(", value='").append(Hex.encodeHex(getValue())).append('\'');
+                sb.append('}');
+                return sb.toString();
+            }
+        }
+
+        public static class DefaulPlayReadyRecord extends PlayReadyRecord {
+            ByteBuffer value;
+
+            public DefaulPlayReadyRecord(int type) {
+                super(type);
+            }
+
+            @Override
+            public void parse(ByteBuffer bytes) {
+                this.value = bytes.duplicate();
+            }
+
+            @Override
+            public ByteBuffer getValue() {
+                return value;
+            }
+
+        }
+
+    }
+
+}
diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/boxes/piff/.svn/text-base/ProtectionSpecificHeader.java.svn-base b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/piff/.svn/text-base/ProtectionSpecificHeader.java.svn-base
new file mode 100644
index 0000000..0d2f344
--- /dev/null
+++ b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/piff/.svn/text-base/ProtectionSpecificHeader.java.svn-base
@@ -0,0 +1,79 @@
+package com.googlecode.mp4parser.boxes.piff;
+
+
+import com.coremedia.iso.Hex;
+
+import java.lang.Class;
+import java.lang.IllegalAccessException;
+import java.lang.InstantiationException;
+import java.lang.Object;
+import java.lang.Override;
+import java.lang.RuntimeException;
+import java.lang.String;
+import java.lang.StringBuilder;
+import java.nio.ByteBuffer;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.UUID;
+
+
+public class ProtectionSpecificHeader {
+    protected static Map<UUID, Class<? extends ProtectionSpecificHeader>> uuidRegistry = new HashMap<UUID, Class<? extends ProtectionSpecificHeader>>();
+    ByteBuffer data;
+
+    static {
+        uuidRegistry.put(UUID.fromString("9A04F079-9840-4286-AB92-E65BE0885F95"), PlayReadyHeader.class);
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (obj instanceof ProtectionSpecificHeader) {
+            if (this.getClass().equals(obj.getClass())) {
+                return data.equals(((ProtectionSpecificHeader) obj).data);
+            }
+        }
+        return false;
+    }
+
+    public static ProtectionSpecificHeader createFor(UUID systemId, ByteBuffer bufferWrapper) {
+        final Class<? extends ProtectionSpecificHeader> aClass = uuidRegistry.get(systemId);
+
+        ProtectionSpecificHeader protectionSpecificHeader = new ProtectionSpecificHeader();
+        if (aClass != null) {
+            try {
+                protectionSpecificHeader = aClass.newInstance();
+
+            } catch (InstantiationException e) {
+                throw new RuntimeException(e);
+            } catch (IllegalAccessException e) {
+                throw new RuntimeException(e);
+            }
+        }
+        protectionSpecificHeader.parse(bufferWrapper);
+        return protectionSpecificHeader;
+
+    }
+
+    public void parse(ByteBuffer buffer) {
+        data = buffer;
+
+    }
+
+    public ByteBuffer getData() {
+        return data;
+    }
+
+    @Override
+    public String toString() {
+        final StringBuilder sb = new StringBuilder();
+        sb.append("ProtectionSpecificHeader");
+        sb.append("{data=");
+        ByteBuffer data = getData().duplicate();
+        data.rewind();
+        byte[] bytes = new byte[data.limit()];
+        data.get(bytes);
+        sb.append(Hex.encodeHex(bytes));
+        sb.append('}');
+        return sb.toString();
+    }
+}
diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/boxes/piff/.svn/text-base/TfrfBox.java.svn-base b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/piff/.svn/text-base/TfrfBox.java.svn-base
new file mode 100644
index 0000000..1e862e9
--- /dev/null
+++ b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/piff/.svn/text-base/TfrfBox.java.svn-base
@@ -0,0 +1,129 @@
+package com.googlecode.mp4parser.boxes.piff;

+

+import com.coremedia.iso.IsoTypeReader;

+import com.coremedia.iso.IsoTypeWriter;

+import com.googlecode.mp4parser.AbstractFullBox;

+

+import java.nio.ByteBuffer;

+import java.util.ArrayList;

+import java.util.List;

+

+/**

+ * The syntax of the fields defined in this section, specified in ABNF [RFC5234], is as follows:

+ * TfrfBox = TfrfBoxLength TfrfBoxType [TfrfBoxLongLength] TfrfBoxUUID TfrfBoxFields

+ * TfrfBoxChildren

+ * TfrfBoxType = "u" "u" "i" "d"

+ * TfrfBoxLength = BoxLength

+ * TfrfBoxLongLength = LongBoxLength

+ * TfrfBoxUUID = %xD4 %x80 %x7E %xF2 %xCA %x39 %x46 %x95

+ * %x8E %x54 %x26 %xCB %x9E %x46 %xA7 %x9F

+ * TfrfBoxFields = TfrfBoxVersion

+ * TfrfBoxFlags

+ * FragmentCount

+ * (1* TfrfBoxDataFields32) / (1* TfrfBoxDataFields64)

+ * TfrfBoxVersion = %x00 / %x01

+ * TfrfBoxFlags = 24*24 RESERVED_BIT

+ * FragmentCount = UINT8

+ * TfrfBoxDataFields32 = FragmentAbsoluteTime32

+ * FragmentDuration32

+ * TfrfBoxDataFields64 = FragmentAbsoluteTime64

+ * FragmentDuration64

+ * FragmentAbsoluteTime64 = UNSIGNED_INT32

+ * FragmentDuration64 = UNSIGNED_INT32

+ * FragmentAbsoluteTime64 = UNSIGNED_INT64

+ * FragmentDuration64 = UNSIGNED_INT64

+ * TfrfBoxChildren = *( VendorExtensionUUIDBox )

+ */

+public class TfrfBox extends AbstractFullBox {

+    public List<Entry> entries = new ArrayList<Entry>();

+

+    public TfrfBox() {

+        super("uuid");

+    }

+

+    @Override

+    public byte[] getUserType() {

+        return new byte[]{(byte) 0xd4, (byte) 0x80, (byte) 0x7e, (byte) 0xf2, (byte) 0xca, (byte) 0x39, (byte) 0x46,

+                (byte) 0x95, (byte) 0x8e, (byte) 0x54, 0x26, (byte) 0xcb, (byte) 0x9e, (byte) 0x46, (byte) 0xa7, (byte) 0x9f};

+    }

+

+    @Override

+    protected long getContentSize() {

+        return 5 + entries.size() * (getVersion() == 0x01 ? 16 : 8);

+    }

+

+    @Override

+    protected void getContent(ByteBuffer byteBuffer) {

+        writeVersionAndFlags(byteBuffer);

+        IsoTypeWriter.writeUInt8(byteBuffer, entries.size());

+

+        for (Entry entry : entries) {

+            if (getVersion() == 0x01) {

+                IsoTypeWriter.writeUInt64(byteBuffer, entry.fragmentAbsoluteTime);

+                IsoTypeWriter.writeUInt64(byteBuffer, entry.fragmentAbsoluteDuration);

+            } else {

+                IsoTypeWriter.writeUInt32(byteBuffer, entry.fragmentAbsoluteTime);

+                IsoTypeWriter.writeUInt32(byteBuffer, entry.fragmentAbsoluteDuration);

+            }

+        }

+    }

+

+    @Override

+    public void _parseDetails(ByteBuffer content) {

+        parseVersionAndFlags(content);

+        int fragmentCount = IsoTypeReader.readUInt8(content);

+

+        for (int i = 0; i < fragmentCount; i++) {

+            Entry entry = new Entry();

+            if (getVersion() == 0x01) {

+                entry.fragmentAbsoluteTime = IsoTypeReader.readUInt64(content);

+                entry.fragmentAbsoluteDuration = IsoTypeReader.readUInt64(content);

+            } else {

+                entry.fragmentAbsoluteTime = IsoTypeReader.readUInt32(content);

+                entry.fragmentAbsoluteDuration = IsoTypeReader.readUInt32(content);

+            }

+            entries.add(entry);

+        }

+    }

+

+

+    public long getFragmentCount() {

+        return entries.size();

+    }

+

+    public List<Entry> getEntries() {

+        return entries;

+    }

+

+    @Override

+    public String toString() {

+        final StringBuilder sb = new StringBuilder();

+        sb.append("TfrfBox");

+        sb.append("{entries=").append(entries);

+        sb.append('}');

+        return sb.toString();

+    }

+

+    public class Entry {

+        long fragmentAbsoluteTime;

+        long fragmentAbsoluteDuration;

+

+        public long getFragmentAbsoluteTime() {

+            return fragmentAbsoluteTime;

+        }

+

+        public long getFragmentAbsoluteDuration() {

+            return fragmentAbsoluteDuration;

+        }

+

+        @Override

+        public String toString() {

+            final StringBuilder sb = new StringBuilder();

+            sb.append("Entry");

+            sb.append("{fragmentAbsoluteTime=").append(fragmentAbsoluteTime);

+            sb.append(", fragmentAbsoluteDuration=").append(fragmentAbsoluteDuration);

+            sb.append('}');

+            return sb.toString();

+        }

+    }

+}

diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/boxes/piff/.svn/text-base/TfxdBox.java.svn-base b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/piff/.svn/text-base/TfxdBox.java.svn-base
new file mode 100644
index 0000000..52e8e87
--- /dev/null
+++ b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/piff/.svn/text-base/TfxdBox.java.svn-base
@@ -0,0 +1,85 @@
+package com.googlecode.mp4parser.boxes.piff;

+

+import com.coremedia.iso.IsoTypeReader;

+import com.coremedia.iso.IsoTypeWriter;

+import com.googlecode.mp4parser.AbstractFullBox;

+

+import java.nio.ByteBuffer;

+

+/**

+ * The syntax of the fields defined in this section, specified in ABNF [RFC5234], is as follows:

+ * TfxdBox = TfxdBoxLength TfxdBoxType [TfxdBoxLongLength] TfxdBoxUUID TfxdBoxFields

+ * TfxdBoxChildren

+ * TfxdBoxType = "u" "u" "i" "d"

+ * TfxdBoxLength = BoxLength

+ * TfxdBoxLongLength = LongBoxLength

+ * TfxdBoxUUID = %x6D %x1D %x9B %x05 %x42 %xD5 %x44 %xE6

+ * %x80 %xE2 %x14 %x1D %xAF %xF7 %x57 %xB2

+ * TfxdBoxFields = TfxdBoxVersion

+ * TfxdBoxFlags

+ * TfxdBoxDataFields32 / TfxdBoxDataFields64

+ * TfxdBoxVersion = %x00 / %x01

+ * TfxdBoxFlags = 24*24 RESERVED_BIT

+ * TfxdBoxDataFields32 = FragmentAbsoluteTime32

+ * FragmentDuration32

+ * TfxdBoxDataFields64 = FragmentAbsoluteTime64

+ * FragmentDuration64

+ * FragmentAbsoluteTime64 = UNSIGNED_INT32

+ * FragmentDuration64 = UNSIGNED_INT32

+ * FragmentAbsoluteTime64 = UNSIGNED_INT64

+ * FragmentDuration64 = UNSIGNED_INT64

+ * TfxdBoxChildren = *( VendorExtensionUUIDBox )

+ */

+//@ExtendedUserType(uuid = "6d1d9b05-42d5-44e6-80e2-141daff757b2")

+public class TfxdBox extends AbstractFullBox {

+    public long fragmentAbsoluteTime;

+    public long fragmentAbsoluteDuration;

+

+    public TfxdBox() {

+        super("uuid");

+    }

+

+    @Override

+    public byte[] getUserType() {

+        return new byte[]{(byte) 0x6d, (byte) 0x1d, (byte) 0x9b, (byte) 0x05, (byte) 0x42, (byte) 0xd5, (byte) 0x44,

+                (byte) 0xe6, (byte) 0x80, (byte) 0xe2, 0x14, (byte) 0x1d, (byte) 0xaf, (byte) 0xf7, (byte) 0x57, (byte) 0xb2};

+    }

+

+    @Override

+    protected long getContentSize() {

+        return getVersion() == 0x01 ? 20 : 12;

+    }

+

+    @Override

+    public void _parseDetails(ByteBuffer content) {

+        parseVersionAndFlags(content);

+

+        if (getVersion() == 0x01) {

+            fragmentAbsoluteTime = IsoTypeReader.readUInt64(content);

+            fragmentAbsoluteDuration = IsoTypeReader.readUInt64(content);

+        } else {

+            fragmentAbsoluteTime = IsoTypeReader.readUInt32(content);

+            fragmentAbsoluteDuration = IsoTypeReader.readUInt32(content);

+        }

+    }

+

+    @Override

+    protected void getContent(ByteBuffer byteBuffer) {

+        writeVersionAndFlags(byteBuffer);

+        if (getVersion() == 0x01) {

+            IsoTypeWriter.writeUInt64(byteBuffer, fragmentAbsoluteTime);

+            IsoTypeWriter.writeUInt64(byteBuffer, fragmentAbsoluteDuration);

+        } else {

+            IsoTypeWriter.writeUInt32(byteBuffer, fragmentAbsoluteTime);

+            IsoTypeWriter.writeUInt32(byteBuffer, fragmentAbsoluteDuration);

+        }

+    }

+

+    public long getFragmentAbsoluteTime() {

+        return fragmentAbsoluteTime;

+    }

+

+    public long getFragmentAbsoluteDuration() {

+        return fragmentAbsoluteDuration;

+    }

+}

diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/boxes/piff/.svn/text-base/UuidBasedProtectionSystemSpecificHeaderBox.java.svn-base b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/piff/.svn/text-base/UuidBasedProtectionSystemSpecificHeaderBox.java.svn-base
new file mode 100644
index 0000000..b147398
--- /dev/null
+++ b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/piff/.svn/text-base/UuidBasedProtectionSystemSpecificHeaderBox.java.svn-base
@@ -0,0 +1,106 @@
+package com.googlecode.mp4parser.boxes.piff;
+
+import com.coremedia.iso.IsoFile;
+import com.coremedia.iso.IsoTypeReader;
+import com.coremedia.iso.IsoTypeWriter;
+import com.googlecode.mp4parser.AbstractFullBox;
+import com.googlecode.mp4parser.util.Path;
+import com.googlecode.mp4parser.util.UUIDConverter;
+
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.lang.Override;import java.lang.String;import java.lang.StringBuilder;import java.nio.ByteBuffer;
+import java.util.UUID;
+
+import static com.googlecode.mp4parser.util.CastUtils.l2i;
+
+/**
+ * aligned(8) class UuidBasedProtectionSystemSpecificHeaderBox extends FullBox(‘uuid’,
+ * extended_type=0xd08a4f18-10f3-4a82-b6c8-32d8aba183d3,
+ * version=0, flags=0)
+ * {
+ * unsigned int(8)[16] SystemID;
+ * unsigned int(32) DataSize;
+ * unsigned int(8)[DataSize] Data;
+ * }
+ */
+public class UuidBasedProtectionSystemSpecificHeaderBox extends AbstractFullBox {
+    public static byte[] USER_TYPE = new byte[]{(byte) 0xd0, (byte) 0x8a, 0x4f, 0x18, 0x10, (byte) 0xf3, 0x4a, (byte) 0x82,
+                (byte) 0xb6, (byte) 0xc8, 0x32, (byte) 0xd8, (byte) 0xab, (byte) 0xa1, (byte) 0x83, (byte) 0xd3};
+
+    UUID systemId;
+
+    ProtectionSpecificHeader protectionSpecificHeader;
+
+    public UuidBasedProtectionSystemSpecificHeaderBox() {
+        super("uuid", USER_TYPE);
+    }
+
+    @Override
+    protected long getContentSize() {
+        return 24 + protectionSpecificHeader.getData().limit();
+    }
+
+    @Override
+    public byte[] getUserType() {
+        return USER_TYPE;
+    }
+
+    @Override
+    protected void getContent(ByteBuffer byteBuffer) {
+        writeVersionAndFlags(byteBuffer);
+        IsoTypeWriter.writeUInt64(byteBuffer, systemId.getMostSignificantBits());
+        IsoTypeWriter.writeUInt64(byteBuffer, systemId.getLeastSignificantBits());
+        ByteBuffer data = protectionSpecificHeader.getData();
+        data.rewind();
+        IsoTypeWriter.writeUInt32(byteBuffer, data.limit());
+        byteBuffer.put(data);
+    }
+
+    @Override
+    protected void _parseDetails(ByteBuffer content) {
+        parseVersionAndFlags(content);
+        byte[] systemIdBytes = new byte[16];
+        content.get(systemIdBytes);
+        systemId = UUIDConverter.convert(systemIdBytes);
+        int dataSize = l2i(IsoTypeReader.readUInt32(content));
+        protectionSpecificHeader = ProtectionSpecificHeader.createFor(systemId, content);
+    }
+
+    public UUID getSystemId() {
+        return systemId;
+    }
+
+    public void setSystemId(UUID systemId) {
+        this.systemId = systemId;
+    }
+
+    public String getSystemIdString() {
+        return systemId.toString();
+    }
+
+    public ProtectionSpecificHeader getProtectionSpecificHeader() {
+        return protectionSpecificHeader;
+    }
+
+    public String getProtectionSpecificHeaderString() {
+        return protectionSpecificHeader.toString();
+    }
+
+    public void setProtectionSpecificHeader(ProtectionSpecificHeader protectionSpecificHeader) {
+        this.protectionSpecificHeader = protectionSpecificHeader;
+    }
+
+    @Override
+    public String toString() {
+        final StringBuilder sb = new StringBuilder();
+        sb.append("UuidBasedProtectionSystemSpecificHeaderBox");
+        sb.append("{systemId=").append(systemId.toString());
+        sb.append(", dataSize=").append(protectionSpecificHeader.getData().limit());
+        sb.append('}');
+        return sb.toString();
+    }
+
+
+
+}
diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/boxes/piff/PiffSampleEncryptionBox.java b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/piff/PiffSampleEncryptionBox.java
new file mode 100644
index 0000000..da3512d
--- /dev/null
+++ b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/piff/PiffSampleEncryptionBox.java
@@ -0,0 +1,45 @@
+package com.googlecode.mp4parser.boxes.piff;
+
+import com.googlecode.mp4parser.boxes.AbstractSampleEncryptionBox;
+
+/**
+ * <pre>
+ * aligned(8) class SampleEncryptionBox extends FullBox(‘uuid’, extended_type= 0xA2394F52-5A9B-4f14-A244-6C427C648DF4, version=0, flags=0)
+ * {
+ *  if (flags & 0x000001)
+ *  {
+ *   unsigned int(24) AlgorithmID;
+ *   unsigned int(8) IV_size;
+ *   unsigned int(8)[16] KID;
+ *  }
+ *  unsigned int (32) sample_count;
+ *  {
+ *   unsigned int(IV_size) InitializationVector;
+ *   if (flags & 0x000002)
+ *   {
+ *    unsigned int(16) NumberOfEntries;
+ *    {
+ *     unsigned int(16) BytesOfClearData;
+ *     unsigned int(32) BytesOfEncryptedData;
+ *    } [ NumberOfEntries]
+ *   }
+ *  }[ sample_count ]
+ * }
+ * </pre>
+ */
+public class PiffSampleEncryptionBox extends AbstractSampleEncryptionBox {
+
+    /**
+     * Creates a AbstractSampleEncryptionBox for non-h264 tracks.
+     */
+    public PiffSampleEncryptionBox() {
+        super("uuid");
+
+    }
+
+    @Override
+    public byte[] getUserType() {
+        return new byte[]{(byte) 0xA2, 0x39, 0x4F, 0x52, 0x5A, (byte) 0x9B, 0x4f, 0x14, (byte) 0xA2, 0x44, 0x6C, 0x42, 0x7C, 0x64, (byte) 0x8D, (byte) 0xF4};
+    }
+
+}
diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/boxes/piff/PiffTrackEncryptionBox.java b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/piff/PiffTrackEncryptionBox.java
new file mode 100644
index 0000000..f92c0f3
--- /dev/null
+++ b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/piff/PiffTrackEncryptionBox.java
@@ -0,0 +1,34 @@
+package com.googlecode.mp4parser.boxes.piff;
+
+import com.googlecode.mp4parser.boxes.AbstractTrackEncryptionBox;
+
+/**
+ * aligned(8) class TrackEncryptionBox extends FullBox(‘uuid’,
+ * extended_type=0x8974dbce-7be7-4c51-84f9-7148f9882554, version=0,
+ * flags=0)
+ * {
+ * unsigned int(24) default_AlgorithmID;
+ * unsigned int(8) default_IV_size;
+ * unsigned int(8)[16] default_KID;
+ * }
+ */
+public class PiffTrackEncryptionBox extends AbstractTrackEncryptionBox {
+
+
+    public PiffTrackEncryptionBox() {
+        super("uuid");
+    }
+
+    @Override
+    public byte[] getUserType() {
+        return new byte[]{(byte) 0x89, 0x74, (byte) 0xdb, (byte) 0xce, 0x7b, (byte) 0xe7, 0x4c, 0x51,
+                (byte) 0x84, (byte) 0xf9, 0x71, 0x48, (byte) 0xf9, (byte) 0x88, 0x25, 0x54};
+    }
+
+    @Override
+    public int getFlags() {
+        return 0;
+    }
+
+
+}
diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/boxes/piff/PlayReadyHeader.java b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/piff/PlayReadyHeader.java
new file mode 100644
index 0000000..74246d0
--- /dev/null
+++ b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/piff/PlayReadyHeader.java
@@ -0,0 +1,253 @@
+package com.googlecode.mp4parser.boxes.piff;
+
+import com.coremedia.iso.IsoFile;
+import com.coremedia.iso.IsoTypeReader;
+import com.coremedia.iso.IsoTypeWriter;
+import com.googlecode.mp4parser.util.Path;
+
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.UnsupportedEncodingException;
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * Specifications > Microsoft PlayReady Format Specification > 2. PlayReady Media Format > 2.7. ASF GUIDs
+ * <p/>
+ * <p/>
+ * ASF_Protection_System_Identifier_Object
+ * 9A04F079-9840-4286-AB92E65BE0885F95
+ * <p/>
+ * ASF_Content_Protection_System_Microsoft_PlayReady
+ * F4637010-03C3-42CD-B932B48ADF3A6A54
+ * <p/>
+ * ASF_StreamType_PlayReady_Encrypted_Command_Media
+ * 8683973A-6639-463A-ABD764F1CE3EEAE0
+ * <p/>
+ * <p/>
+ * Specifications > Microsoft PlayReady Format Specification > 2. PlayReady Media Format > 2.5. Data Objects > 2.5.1. Payload Extension for AES in Counter Mode
+ * <p/>
+ * The sample Id is used as the IV in CTR mode. Block offset, starting at 0 and incremented by 1 after every 16 bytes, from the beginning of the sample is used as the Counter.
+ * <p/>
+ * The sample ID for each sample (media object) is stored as an ASF payload extension system with the ID of ASF_Payload_Extension_Encryption_SampleID = {6698B84E-0AFA-4330-AEB2-1C0A98D7A44D}. The payload extension can be stored as a fixed size extension of 8 bytes.
+ * <p/>
+ * The sample ID is always stored in big-endian byte order.
+ */
+public class PlayReadyHeader extends ProtectionSpecificHeader {
+    private long length;
+    private List<PlayReadyRecord> records;
+
+    public PlayReadyHeader() {
+
+    }
+
+    @Override
+    public void parse(ByteBuffer byteBuffer) {
+        /*
+   Length DWORD 32
+
+   PlayReady Record Count WORD 16
+
+   PlayReady Records See Text Varies
+
+        */
+
+        length = IsoTypeReader.readUInt32BE(byteBuffer);
+        int recordCount = IsoTypeReader.readUInt16BE(byteBuffer);
+
+        records = PlayReadyRecord.createFor(byteBuffer, recordCount);
+    }
+
+    @Override
+    public ByteBuffer getData() {
+
+        int size = 4 + 2;
+        for (PlayReadyRecord record : records) {
+            size += 2 + 2;
+            size += record.getValue().rewind().limit();
+        }
+        ByteBuffer byteBuffer = ByteBuffer.allocate(size);
+
+        IsoTypeWriter.writeUInt32BE(byteBuffer, size);
+        IsoTypeWriter.writeUInt16BE(byteBuffer, records.size());
+        for (PlayReadyRecord record : records) {
+            IsoTypeWriter.writeUInt16BE(byteBuffer, record.type);
+            IsoTypeWriter.writeUInt16BE(byteBuffer, record.getValue().limit());
+            ByteBuffer tmp4debug = record.getValue();
+            byteBuffer.put(tmp4debug);
+        }
+
+        return byteBuffer;
+    }
+
+    public void setRecords(List<PlayReadyRecord> records) {
+        this.records = records;
+    }
+
+    public List<PlayReadyRecord> getRecords() {
+        return Collections.unmodifiableList(records);
+    }
+
+    @Override
+    public String toString() {
+        final StringBuilder sb = new StringBuilder();
+        sb.append("PlayReadyHeader");
+        sb.append("{length=").append(length);
+        sb.append(", recordCount=").append(records.size());
+        sb.append(", records=").append(records);
+        sb.append('}');
+        return sb.toString();
+    }
+
+    public static abstract class PlayReadyRecord {
+        int type;
+
+
+        public PlayReadyRecord(int type) {
+            this.type = type;
+        }
+
+        public static List<PlayReadyRecord> createFor(ByteBuffer byteBuffer, int recordCount) {
+            List<PlayReadyRecord> records = new ArrayList<PlayReadyRecord>(recordCount);
+
+            for (int i = 0; i < recordCount; i++) {
+                PlayReadyRecord record;
+                int type = IsoTypeReader.readUInt16BE(byteBuffer);
+                int length = IsoTypeReader.readUInt16BE(byteBuffer);
+                switch (type) {
+                    case 0x1:
+                        record = new RMHeader();
+                        break;
+                    case 0x2:
+                        record = new DefaulPlayReadyRecord(0x02);
+                        break;
+                    case 0x3:
+                        record = new EmeddedLicenseStore();
+                        break;
+                    default:
+                        record = new DefaulPlayReadyRecord(type);
+                }
+                record.parse((ByteBuffer) byteBuffer.slice().limit(length));
+                byteBuffer.position(byteBuffer.position() + length);
+                records.add(record);
+            }
+
+            return records;
+        }
+
+        public abstract void parse(ByteBuffer bytes);
+
+        @Override
+        public String toString() {
+            final StringBuilder sb = new StringBuilder();
+            sb.append("PlayReadyRecord");
+            sb.append("{type=").append(type);
+            sb.append(", length=").append(getValue().limit());
+//            sb.append(", value=").append(Hex.encodeHex(getValue())).append('\'');
+            sb.append('}');
+            return sb.toString();
+        }
+
+        public abstract ByteBuffer getValue();
+
+        public static class RMHeader extends PlayReadyRecord {
+            String header;
+
+            public RMHeader() {
+                super(0x01);
+            }
+
+            @Override
+            public void parse(ByteBuffer bytes) {
+                try {
+                    byte[] str = new byte[bytes.slice().limit()];
+                    bytes.get(str);
+                    header = new String(str, "UTF-16LE");
+                } catch (UnsupportedEncodingException e) {
+                    throw new RuntimeException(e);
+                }
+            }
+
+            @Override
+            public ByteBuffer getValue() {
+                byte[] headerBytes;
+                try {
+                    headerBytes = header.getBytes("UTF-16LE");
+                } catch (UnsupportedEncodingException e) {
+                    throw new RuntimeException(e);
+                }
+                return ByteBuffer.wrap(headerBytes);
+            }
+
+            public void setHeader(String header) {
+                this.header = header;
+            }
+
+            public String getHeader() {
+                return header;
+            }
+
+            @Override
+            public String toString() {
+                final StringBuilder sb = new StringBuilder();
+                sb.append("RMHeader");
+                sb.append("{length=").append(getValue().limit());
+                sb.append(", header='").append(header).append('\'');
+                sb.append('}');
+                return sb.toString();
+            }
+        }
+
+        public static class EmeddedLicenseStore extends PlayReadyRecord {
+            ByteBuffer value;
+
+            public EmeddedLicenseStore() {
+                super(0x03);
+            }
+
+            @Override
+            public void parse(ByteBuffer bytes) {
+                this.value = bytes.duplicate();
+            }
+
+            @Override
+            public ByteBuffer getValue() {
+                return value;
+            }
+
+            @Override
+            public String toString() {
+                final StringBuilder sb = new StringBuilder();
+                sb.append("EmeddedLicenseStore");
+                sb.append("{length=").append(getValue().limit());
+                //sb.append(", value='").append(Hex.encodeHex(getValue())).append('\'');
+                sb.append('}');
+                return sb.toString();
+            }
+        }
+
+        public static class DefaulPlayReadyRecord extends PlayReadyRecord {
+            ByteBuffer value;
+
+            public DefaulPlayReadyRecord(int type) {
+                super(type);
+            }
+
+            @Override
+            public void parse(ByteBuffer bytes) {
+                this.value = bytes.duplicate();
+            }
+
+            @Override
+            public ByteBuffer getValue() {
+                return value;
+            }
+
+        }
+
+    }
+
+}
diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/boxes/piff/ProtectionSpecificHeader.java b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/piff/ProtectionSpecificHeader.java
new file mode 100644
index 0000000..0d2f344
--- /dev/null
+++ b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/piff/ProtectionSpecificHeader.java
@@ -0,0 +1,79 @@
+package com.googlecode.mp4parser.boxes.piff;
+
+
+import com.coremedia.iso.Hex;
+
+import java.lang.Class;
+import java.lang.IllegalAccessException;
+import java.lang.InstantiationException;
+import java.lang.Object;
+import java.lang.Override;
+import java.lang.RuntimeException;
+import java.lang.String;
+import java.lang.StringBuilder;
+import java.nio.ByteBuffer;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.UUID;
+
+
+public class ProtectionSpecificHeader {
+    protected static Map<UUID, Class<? extends ProtectionSpecificHeader>> uuidRegistry = new HashMap<UUID, Class<? extends ProtectionSpecificHeader>>();
+    ByteBuffer data;
+
+    static {
+        uuidRegistry.put(UUID.fromString("9A04F079-9840-4286-AB92-E65BE0885F95"), PlayReadyHeader.class);
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (obj instanceof ProtectionSpecificHeader) {
+            if (this.getClass().equals(obj.getClass())) {
+                return data.equals(((ProtectionSpecificHeader) obj).data);
+            }
+        }
+        return false;
+    }
+
+    public static ProtectionSpecificHeader createFor(UUID systemId, ByteBuffer bufferWrapper) {
+        final Class<? extends ProtectionSpecificHeader> aClass = uuidRegistry.get(systemId);
+
+        ProtectionSpecificHeader protectionSpecificHeader = new ProtectionSpecificHeader();
+        if (aClass != null) {
+            try {
+                protectionSpecificHeader = aClass.newInstance();
+
+            } catch (InstantiationException e) {
+                throw new RuntimeException(e);
+            } catch (IllegalAccessException e) {
+                throw new RuntimeException(e);
+            }
+        }
+        protectionSpecificHeader.parse(bufferWrapper);
+        return protectionSpecificHeader;
+
+    }
+
+    public void parse(ByteBuffer buffer) {
+        data = buffer;
+
+    }
+
+    public ByteBuffer getData() {
+        return data;
+    }
+
+    @Override
+    public String toString() {
+        final StringBuilder sb = new StringBuilder();
+        sb.append("ProtectionSpecificHeader");
+        sb.append("{data=");
+        ByteBuffer data = getData().duplicate();
+        data.rewind();
+        byte[] bytes = new byte[data.limit()];
+        data.get(bytes);
+        sb.append(Hex.encodeHex(bytes));
+        sb.append('}');
+        return sb.toString();
+    }
+}
diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/boxes/piff/TfrfBox.java b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/piff/TfrfBox.java
new file mode 100644
index 0000000..1e862e9
--- /dev/null
+++ b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/piff/TfrfBox.java
@@ -0,0 +1,129 @@
+package com.googlecode.mp4parser.boxes.piff;

+

+import com.coremedia.iso.IsoTypeReader;

+import com.coremedia.iso.IsoTypeWriter;

+import com.googlecode.mp4parser.AbstractFullBox;

+

+import java.nio.ByteBuffer;

+import java.util.ArrayList;

+import java.util.List;

+

+/**

+ * The syntax of the fields defined in this section, specified in ABNF [RFC5234], is as follows:

+ * TfrfBox = TfrfBoxLength TfrfBoxType [TfrfBoxLongLength] TfrfBoxUUID TfrfBoxFields

+ * TfrfBoxChildren

+ * TfrfBoxType = "u" "u" "i" "d"

+ * TfrfBoxLength = BoxLength

+ * TfrfBoxLongLength = LongBoxLength

+ * TfrfBoxUUID = %xD4 %x80 %x7E %xF2 %xCA %x39 %x46 %x95

+ * %x8E %x54 %x26 %xCB %x9E %x46 %xA7 %x9F

+ * TfrfBoxFields = TfrfBoxVersion

+ * TfrfBoxFlags

+ * FragmentCount

+ * (1* TfrfBoxDataFields32) / (1* TfrfBoxDataFields64)

+ * TfrfBoxVersion = %x00 / %x01

+ * TfrfBoxFlags = 24*24 RESERVED_BIT

+ * FragmentCount = UINT8

+ * TfrfBoxDataFields32 = FragmentAbsoluteTime32

+ * FragmentDuration32

+ * TfrfBoxDataFields64 = FragmentAbsoluteTime64

+ * FragmentDuration64

+ * FragmentAbsoluteTime64 = UNSIGNED_INT32

+ * FragmentDuration64 = UNSIGNED_INT32

+ * FragmentAbsoluteTime64 = UNSIGNED_INT64

+ * FragmentDuration64 = UNSIGNED_INT64

+ * TfrfBoxChildren = *( VendorExtensionUUIDBox )

+ */

+public class TfrfBox extends AbstractFullBox {

+    public List<Entry> entries = new ArrayList<Entry>();

+

+    public TfrfBox() {

+        super("uuid");

+    }

+

+    @Override

+    public byte[] getUserType() {

+        return new byte[]{(byte) 0xd4, (byte) 0x80, (byte) 0x7e, (byte) 0xf2, (byte) 0xca, (byte) 0x39, (byte) 0x46,

+                (byte) 0x95, (byte) 0x8e, (byte) 0x54, 0x26, (byte) 0xcb, (byte) 0x9e, (byte) 0x46, (byte) 0xa7, (byte) 0x9f};

+    }

+

+    @Override

+    protected long getContentSize() {

+        return 5 + entries.size() * (getVersion() == 0x01 ? 16 : 8);

+    }

+

+    @Override

+    protected void getContent(ByteBuffer byteBuffer) {

+        writeVersionAndFlags(byteBuffer);

+        IsoTypeWriter.writeUInt8(byteBuffer, entries.size());

+

+        for (Entry entry : entries) {

+            if (getVersion() == 0x01) {

+                IsoTypeWriter.writeUInt64(byteBuffer, entry.fragmentAbsoluteTime);

+                IsoTypeWriter.writeUInt64(byteBuffer, entry.fragmentAbsoluteDuration);

+            } else {

+                IsoTypeWriter.writeUInt32(byteBuffer, entry.fragmentAbsoluteTime);

+                IsoTypeWriter.writeUInt32(byteBuffer, entry.fragmentAbsoluteDuration);

+            }

+        }

+    }

+

+    @Override

+    public void _parseDetails(ByteBuffer content) {

+        parseVersionAndFlags(content);

+        int fragmentCount = IsoTypeReader.readUInt8(content);

+

+        for (int i = 0; i < fragmentCount; i++) {

+            Entry entry = new Entry();

+            if (getVersion() == 0x01) {

+                entry.fragmentAbsoluteTime = IsoTypeReader.readUInt64(content);

+                entry.fragmentAbsoluteDuration = IsoTypeReader.readUInt64(content);

+            } else {

+                entry.fragmentAbsoluteTime = IsoTypeReader.readUInt32(content);

+                entry.fragmentAbsoluteDuration = IsoTypeReader.readUInt32(content);

+            }

+            entries.add(entry);

+        }

+    }

+

+

+    public long getFragmentCount() {

+        return entries.size();

+    }

+

+    public List<Entry> getEntries() {

+        return entries;

+    }

+

+    @Override

+    public String toString() {

+        final StringBuilder sb = new StringBuilder();

+        sb.append("TfrfBox");

+        sb.append("{entries=").append(entries);

+        sb.append('}');

+        return sb.toString();

+    }

+

+    public class Entry {

+        long fragmentAbsoluteTime;

+        long fragmentAbsoluteDuration;

+

+        public long getFragmentAbsoluteTime() {

+            return fragmentAbsoluteTime;

+        }

+

+        public long getFragmentAbsoluteDuration() {

+            return fragmentAbsoluteDuration;

+        }

+

+        @Override

+        public String toString() {

+            final StringBuilder sb = new StringBuilder();

+            sb.append("Entry");

+            sb.append("{fragmentAbsoluteTime=").append(fragmentAbsoluteTime);

+            sb.append(", fragmentAbsoluteDuration=").append(fragmentAbsoluteDuration);

+            sb.append('}');

+            return sb.toString();

+        }

+    }

+}

diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/boxes/piff/TfxdBox.java b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/piff/TfxdBox.java
new file mode 100644
index 0000000..52e8e87
--- /dev/null
+++ b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/piff/TfxdBox.java
@@ -0,0 +1,85 @@
+package com.googlecode.mp4parser.boxes.piff;

+

+import com.coremedia.iso.IsoTypeReader;

+import com.coremedia.iso.IsoTypeWriter;

+import com.googlecode.mp4parser.AbstractFullBox;

+

+import java.nio.ByteBuffer;

+

+/**

+ * The syntax of the fields defined in this section, specified in ABNF [RFC5234], is as follows:

+ * TfxdBox = TfxdBoxLength TfxdBoxType [TfxdBoxLongLength] TfxdBoxUUID TfxdBoxFields

+ * TfxdBoxChildren

+ * TfxdBoxType = "u" "u" "i" "d"

+ * TfxdBoxLength = BoxLength

+ * TfxdBoxLongLength = LongBoxLength

+ * TfxdBoxUUID = %x6D %x1D %x9B %x05 %x42 %xD5 %x44 %xE6

+ * %x80 %xE2 %x14 %x1D %xAF %xF7 %x57 %xB2

+ * TfxdBoxFields = TfxdBoxVersion

+ * TfxdBoxFlags

+ * TfxdBoxDataFields32 / TfxdBoxDataFields64

+ * TfxdBoxVersion = %x00 / %x01

+ * TfxdBoxFlags = 24*24 RESERVED_BIT

+ * TfxdBoxDataFields32 = FragmentAbsoluteTime32

+ * FragmentDuration32

+ * TfxdBoxDataFields64 = FragmentAbsoluteTime64

+ * FragmentDuration64

+ * FragmentAbsoluteTime64 = UNSIGNED_INT32

+ * FragmentDuration64 = UNSIGNED_INT32

+ * FragmentAbsoluteTime64 = UNSIGNED_INT64

+ * FragmentDuration64 = UNSIGNED_INT64

+ * TfxdBoxChildren = *( VendorExtensionUUIDBox )

+ */

+//@ExtendedUserType(uuid = "6d1d9b05-42d5-44e6-80e2-141daff757b2")

+public class TfxdBox extends AbstractFullBox {

+    public long fragmentAbsoluteTime;

+    public long fragmentAbsoluteDuration;

+

+    public TfxdBox() {

+        super("uuid");

+    }

+

+    @Override

+    public byte[] getUserType() {

+        return new byte[]{(byte) 0x6d, (byte) 0x1d, (byte) 0x9b, (byte) 0x05, (byte) 0x42, (byte) 0xd5, (byte) 0x44,

+                (byte) 0xe6, (byte) 0x80, (byte) 0xe2, 0x14, (byte) 0x1d, (byte) 0xaf, (byte) 0xf7, (byte) 0x57, (byte) 0xb2};

+    }

+

+    @Override

+    protected long getContentSize() {

+        return getVersion() == 0x01 ? 20 : 12;

+    }

+

+    @Override

+    public void _parseDetails(ByteBuffer content) {

+        parseVersionAndFlags(content);

+

+        if (getVersion() == 0x01) {

+            fragmentAbsoluteTime = IsoTypeReader.readUInt64(content);

+            fragmentAbsoluteDuration = IsoTypeReader.readUInt64(content);

+        } else {

+            fragmentAbsoluteTime = IsoTypeReader.readUInt32(content);

+            fragmentAbsoluteDuration = IsoTypeReader.readUInt32(content);

+        }

+    }

+

+    @Override

+    protected void getContent(ByteBuffer byteBuffer) {

+        writeVersionAndFlags(byteBuffer);

+        if (getVersion() == 0x01) {

+            IsoTypeWriter.writeUInt64(byteBuffer, fragmentAbsoluteTime);

+            IsoTypeWriter.writeUInt64(byteBuffer, fragmentAbsoluteDuration);

+        } else {

+            IsoTypeWriter.writeUInt32(byteBuffer, fragmentAbsoluteTime);

+            IsoTypeWriter.writeUInt32(byteBuffer, fragmentAbsoluteDuration);

+        }

+    }

+

+    public long getFragmentAbsoluteTime() {

+        return fragmentAbsoluteTime;

+    }

+

+    public long getFragmentAbsoluteDuration() {

+        return fragmentAbsoluteDuration;

+    }

+}

diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/boxes/piff/UuidBasedProtectionSystemSpecificHeaderBox.java b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/piff/UuidBasedProtectionSystemSpecificHeaderBox.java
new file mode 100644
index 0000000..b147398
--- /dev/null
+++ b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/piff/UuidBasedProtectionSystemSpecificHeaderBox.java
@@ -0,0 +1,106 @@
+package com.googlecode.mp4parser.boxes.piff;
+
+import com.coremedia.iso.IsoFile;
+import com.coremedia.iso.IsoTypeReader;
+import com.coremedia.iso.IsoTypeWriter;
+import com.googlecode.mp4parser.AbstractFullBox;
+import com.googlecode.mp4parser.util.Path;
+import com.googlecode.mp4parser.util.UUIDConverter;
+
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.lang.Override;import java.lang.String;import java.lang.StringBuilder;import java.nio.ByteBuffer;
+import java.util.UUID;
+
+import static com.googlecode.mp4parser.util.CastUtils.l2i;
+
+/**
+ * aligned(8) class UuidBasedProtectionSystemSpecificHeaderBox extends FullBox(‘uuid’,
+ * extended_type=0xd08a4f18-10f3-4a82-b6c8-32d8aba183d3,
+ * version=0, flags=0)
+ * {
+ * unsigned int(8)[16] SystemID;
+ * unsigned int(32) DataSize;
+ * unsigned int(8)[DataSize] Data;
+ * }
+ */
+public class UuidBasedProtectionSystemSpecificHeaderBox extends AbstractFullBox {
+    public static byte[] USER_TYPE = new byte[]{(byte) 0xd0, (byte) 0x8a, 0x4f, 0x18, 0x10, (byte) 0xf3, 0x4a, (byte) 0x82,
+                (byte) 0xb6, (byte) 0xc8, 0x32, (byte) 0xd8, (byte) 0xab, (byte) 0xa1, (byte) 0x83, (byte) 0xd3};
+
+    UUID systemId;
+
+    ProtectionSpecificHeader protectionSpecificHeader;
+
+    public UuidBasedProtectionSystemSpecificHeaderBox() {
+        super("uuid", USER_TYPE);
+    }
+
+    @Override
+    protected long getContentSize() {
+        return 24 + protectionSpecificHeader.getData().limit();
+    }
+
+    @Override
+    public byte[] getUserType() {
+        return USER_TYPE;
+    }
+
+    @Override
+    protected void getContent(ByteBuffer byteBuffer) {
+        writeVersionAndFlags(byteBuffer);
+        IsoTypeWriter.writeUInt64(byteBuffer, systemId.getMostSignificantBits());
+        IsoTypeWriter.writeUInt64(byteBuffer, systemId.getLeastSignificantBits());
+        ByteBuffer data = protectionSpecificHeader.getData();
+        data.rewind();
+        IsoTypeWriter.writeUInt32(byteBuffer, data.limit());
+        byteBuffer.put(data);
+    }
+
+    @Override
+    protected void _parseDetails(ByteBuffer content) {
+        parseVersionAndFlags(content);
+        byte[] systemIdBytes = new byte[16];
+        content.get(systemIdBytes);
+        systemId = UUIDConverter.convert(systemIdBytes);
+        int dataSize = l2i(IsoTypeReader.readUInt32(content));
+        protectionSpecificHeader = ProtectionSpecificHeader.createFor(systemId, content);
+    }
+
+    public UUID getSystemId() {
+        return systemId;
+    }
+
+    public void setSystemId(UUID systemId) {
+        this.systemId = systemId;
+    }
+
+    public String getSystemIdString() {
+        return systemId.toString();
+    }
+
+    public ProtectionSpecificHeader getProtectionSpecificHeader() {
+        return protectionSpecificHeader;
+    }
+
+    public String getProtectionSpecificHeaderString() {
+        return protectionSpecificHeader.toString();
+    }
+
+    public void setProtectionSpecificHeader(ProtectionSpecificHeader protectionSpecificHeader) {
+        this.protectionSpecificHeader = protectionSpecificHeader;
+    }
+
+    @Override
+    public String toString() {
+        final StringBuilder sb = new StringBuilder();
+        sb.append("UuidBasedProtectionSystemSpecificHeaderBox");
+        sb.append("{systemId=").append(systemId.toString());
+        sb.append(", dataSize=").append(protectionSpecificHeader.getData().limit());
+        sb.append('}');
+        return sb.toString();
+    }
+
+
+
+}
diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/boxes/threegpp26244/.svn/all-wcprops b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/threegpp26244/.svn/all-wcprops
new file mode 100644
index 0000000..1f9ed7a
--- /dev/null
+++ b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/threegpp26244/.svn/all-wcprops
@@ -0,0 +1,11 @@
+K 25
+svn:wc:ra_dav:version-url
+V 92
+/svn/!svn/ver/683/trunk/isoparser/src/main/java/com/googlecode/mp4parser/boxes/threegpp26244
+END
+SegmentIndexBox.java
+K 25
+svn:wc:ra_dav:version-url
+V 113
+/svn/!svn/ver/683/trunk/isoparser/src/main/java/com/googlecode/mp4parser/boxes/threegpp26244/SegmentIndexBox.java
+END
diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/boxes/threegpp26244/.svn/entries b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/threegpp26244/.svn/entries
new file mode 100644
index 0000000..954a06a
--- /dev/null
+++ b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/threegpp26244/.svn/entries
@@ -0,0 +1,62 @@
+10
+
+dir
+778
+http://mp4parser.googlecode.com/svn/trunk/isoparser/src/main/java/com/googlecode/mp4parser/boxes/threegpp26244
+http://mp4parser.googlecode.com/svn
+
+
+
+2012-06-23T08:51:59.024275Z
+683
+Sebastian.Annies@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+7decde4b-c250-0410-a0da-51896bc88be6
+
+SegmentIndexBox.java
+file
+
+
+
+
+2012-09-14T17:27:50.567220Z
+1d0e3a16184ab4820e3c6dc9ebdcea87
+2012-06-23T08:51:59.024275Z
+683
+Sebastian.Annies@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+8722
+
diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/boxes/threegpp26244/.svn/text-base/SegmentIndexBox.java.svn-base b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/threegpp26244/.svn/text-base/SegmentIndexBox.java.svn-base
new file mode 100644
index 0000000..638a87b
--- /dev/null
+++ b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/threegpp26244/.svn/text-base/SegmentIndexBox.java.svn-base
@@ -0,0 +1,283 @@
+package com.googlecode.mp4parser.boxes.threegpp26244;
+
+import com.coremedia.iso.IsoTypeReader;
+import com.coremedia.iso.IsoTypeWriter;
+import com.googlecode.mp4parser.AbstractFullBox;
+import com.googlecode.mp4parser.boxes.mp4.objectdescriptors.BitReaderBuffer;
+import com.googlecode.mp4parser.boxes.mp4.objectdescriptors.BitWriterBuffer;
+
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * <pre>
+ * aligned(8) class SegmentIndexBox extends FullBox(‘sidx’, version, 0) {
+ *  unsigned int(32) reference_ID;
+ *  unsigned int(32) timescale;
+ *  if (version==0)
+ *  {
+ *   unsigned int(32) earliest_presentation_time;
+ *   unsigned int(32) first_offset;
+ *  }
+ *  else
+ *  {
+ *   unsigned int(64) earliest_presentation_time;
+ *   unsigned int(64) first_offset;
+ *  }
+ *  unsigned int(16) reserved = 0;
+ *  unsigned int(16) reference_count;
+ *  for(i=1; i <= reference_count; i++)
+ *  {
+ *   bit (1)            reference_type;
+ *   unsigned int(31)   referenced_size;
+ *   unsigned int(32)   subsegment_duration;
+ *   bit(1)             starts_with_SAP;
+ *   unsigned int(3)    SAP_type;
+ *   unsigned int(28)   SAP_delta_time;
+ *  }
+ * }
+ * </pre>
+ */
+public class SegmentIndexBox extends AbstractFullBox {
+    public static final String TYPE = "sidx";
+    List<Entry> entries = new ArrayList<Entry>();
+
+    long referenceId;
+    long timeScale;
+    long earliestPresentationTime;
+    long firstOffset;
+    int reserved;
+
+
+    public SegmentIndexBox() {
+        super(TYPE);
+    }
+
+    @Override
+    protected long getContentSize() {
+        long size = 4;
+        size += 4;
+        size += 4;
+        size += getVersion() == 0 ? 8 : 16;
+        size += 2; // reserved
+        size += 2; // reference count
+
+        size += entries.size() * 12;
+
+        return size;
+    }
+
+    @Override
+    protected void getContent(ByteBuffer byteBuffer) {
+        writeVersionAndFlags(byteBuffer);
+        IsoTypeWriter.writeUInt32(byteBuffer, referenceId);
+        IsoTypeWriter.writeUInt32(byteBuffer, timeScale);
+        if (getVersion() == 0) {
+            IsoTypeWriter.writeUInt32(byteBuffer, earliestPresentationTime);
+            IsoTypeWriter.writeUInt32(byteBuffer, firstOffset);
+        } else {
+            IsoTypeWriter.writeUInt64(byteBuffer, earliestPresentationTime);
+            IsoTypeWriter.writeUInt64(byteBuffer, firstOffset);
+        }
+        IsoTypeWriter.writeUInt16(byteBuffer, reserved);
+        IsoTypeWriter.writeUInt16(byteBuffer, entries.size());
+        for (Entry entry : entries) {
+            BitWriterBuffer b = new BitWriterBuffer(byteBuffer);
+            b.writeBits(entry.getReferenceType(), 1);
+            b.writeBits(entry.getReferencedSize(), 31);
+            IsoTypeWriter.writeUInt32(byteBuffer, entry.getSubsegmentDuration());
+            b = new BitWriterBuffer(byteBuffer);
+            b.writeBits(entry.getStartsWithSap(), 1);
+            b.writeBits(entry.getSapType(), 3);
+            b.writeBits(entry.getSapDeltaTime(), 28);
+        }
+
+    }
+
+    @Override
+    protected void _parseDetails(ByteBuffer content) {
+        parseVersionAndFlags(content);
+        referenceId = IsoTypeReader.readUInt32(content);
+        timeScale = IsoTypeReader.readUInt32(content);
+        if (getVersion() == 0) {
+            earliestPresentationTime = IsoTypeReader.readUInt32(content);
+            firstOffset = IsoTypeReader.readUInt32(content);
+        } else {
+            earliestPresentationTime = IsoTypeReader.readUInt64(content);
+            firstOffset = IsoTypeReader.readUInt64(content);
+        }
+        reserved = IsoTypeReader.readUInt16(content);
+        int numEntries = IsoTypeReader.readUInt16(content);
+        for (int i = 0; i < numEntries; i++) {
+            BitReaderBuffer b = new BitReaderBuffer(content);
+            Entry e = new Entry();
+            e.setReferenceType((byte) b.readBits(1));
+            e.setReferencedSize(b.readBits(31));
+            e.setSubsegmentDuration(IsoTypeReader.readUInt32(content));
+            b = new BitReaderBuffer(content);
+            e.setStartsWithSap((byte) b.readBits(1));
+            e.setSapType((byte) b.readBits(3));
+            e.setSapDeltaTime(b.readBits(28));
+            entries.add(e);
+        }
+    }
+
+
+    public List<Entry> getEntries() {
+        return entries;
+    }
+
+    public void setEntries(List<Entry> entries) {
+        this.entries = entries;
+    }
+
+    public long getReferenceId() {
+        return referenceId;
+    }
+
+    public void setReferenceId(long referenceId) {
+        this.referenceId = referenceId;
+    }
+
+    public long getTimeScale() {
+        return timeScale;
+    }
+
+    public void setTimeScale(long timeScale) {
+        this.timeScale = timeScale;
+    }
+
+    public long getEarliestPresentationTime() {
+        return earliestPresentationTime;
+    }
+
+    public void setEarliestPresentationTime(long earliestPresentationTime) {
+        this.earliestPresentationTime = earliestPresentationTime;
+    }
+
+    public long getFirstOffset() {
+        return firstOffset;
+    }
+
+    public void setFirstOffset(long firstOffset) {
+        this.firstOffset = firstOffset;
+    }
+
+    public int getReserved() {
+        return reserved;
+    }
+
+    public void setReserved(int reserved) {
+        this.reserved = reserved;
+    }
+
+    public static class Entry {
+        byte referenceType;
+        int referencedSize;
+        long subsegmentDuration;
+        byte startsWithSap;
+        byte sapType;
+        int sapDeltaTime;
+
+        public Entry() {
+        }
+
+        public Entry(byte referenceType, int referencedSize, long subsegmentDuration, byte startsWithSap, byte sapType, int sapDeltaTime) {
+            this.referenceType = referenceType;
+            this.referencedSize = referencedSize;
+            this.subsegmentDuration = subsegmentDuration;
+            this.startsWithSap = startsWithSap;
+            this.sapType = sapType;
+            this.sapDeltaTime = sapDeltaTime;
+        }
+
+        public byte getReferenceType() {
+            return referenceType;
+        }
+
+        public void setReferenceType(byte referenceType) {
+            this.referenceType = referenceType;
+        }
+
+        public int getReferencedSize() {
+            return referencedSize;
+        }
+
+        public void setReferencedSize(int referencedSize) {
+            this.referencedSize = referencedSize;
+        }
+
+        public long getSubsegmentDuration() {
+            return subsegmentDuration;
+        }
+
+        public void setSubsegmentDuration(long subsegmentDuration) {
+            this.subsegmentDuration = subsegmentDuration;
+        }
+
+        public byte getStartsWithSap() {
+            return startsWithSap;
+        }
+
+        public void setStartsWithSap(byte startsWithSap) {
+            this.startsWithSap = startsWithSap;
+        }
+
+        public byte getSapType() {
+            return sapType;
+        }
+
+        public void setSapType(byte sapType) {
+            this.sapType = sapType;
+        }
+
+        public int getSapDeltaTime() {
+            return sapDeltaTime;
+        }
+
+        public void setSapDeltaTime(int sapDeltaTime) {
+            this.sapDeltaTime = sapDeltaTime;
+        }
+
+        @Override
+        public String toString() {
+            return "Entry{" +
+                    "referenceType=" + referenceType +
+                    ", referencedSize=" + referencedSize +
+                    ", subsegmentDuration=" + subsegmentDuration +
+                    ", startsWithSap=" + startsWithSap +
+                    ", sapType=" + sapType +
+                    ", sapDeltaTime=" + sapDeltaTime +
+                    '}';
+        }
+
+        @Override
+        public boolean equals(Object o) {
+            if (this == o) return true;
+            if (o == null || getClass() != o.getClass()) return false;
+
+            Entry entry = (Entry) o;
+
+            if (referenceType != entry.referenceType) return false;
+            if (referencedSize != entry.referencedSize) return false;
+            if (sapDeltaTime != entry.sapDeltaTime) return false;
+            if (sapType != entry.sapType) return false;
+            if (startsWithSap != entry.startsWithSap) return false;
+            if (subsegmentDuration != entry.subsegmentDuration) return false;
+
+            return true;
+        }
+
+        @Override
+        public int hashCode() {
+            int result = (int) referenceType;
+            result = 31 * result + referencedSize;
+            result = 31 * result + (int) (subsegmentDuration ^ (subsegmentDuration >>> 32));
+            result = 31 * result + (int) startsWithSap;
+            result = 31 * result + (int) sapType;
+            result = 31 * result + sapDeltaTime;
+            return result;
+        }
+    }
+}
diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/boxes/threegpp26244/SegmentIndexBox.java b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/threegpp26244/SegmentIndexBox.java
new file mode 100644
index 0000000..638a87b
--- /dev/null
+++ b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/threegpp26244/SegmentIndexBox.java
@@ -0,0 +1,283 @@
+package com.googlecode.mp4parser.boxes.threegpp26244;
+
+import com.coremedia.iso.IsoTypeReader;
+import com.coremedia.iso.IsoTypeWriter;
+import com.googlecode.mp4parser.AbstractFullBox;
+import com.googlecode.mp4parser.boxes.mp4.objectdescriptors.BitReaderBuffer;
+import com.googlecode.mp4parser.boxes.mp4.objectdescriptors.BitWriterBuffer;
+
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * <pre>
+ * aligned(8) class SegmentIndexBox extends FullBox(‘sidx’, version, 0) {
+ *  unsigned int(32) reference_ID;
+ *  unsigned int(32) timescale;
+ *  if (version==0)
+ *  {
+ *   unsigned int(32) earliest_presentation_time;
+ *   unsigned int(32) first_offset;
+ *  }
+ *  else
+ *  {
+ *   unsigned int(64) earliest_presentation_time;
+ *   unsigned int(64) first_offset;
+ *  }
+ *  unsigned int(16) reserved = 0;
+ *  unsigned int(16) reference_count;
+ *  for(i=1; i <= reference_count; i++)
+ *  {
+ *   bit (1)            reference_type;
+ *   unsigned int(31)   referenced_size;
+ *   unsigned int(32)   subsegment_duration;
+ *   bit(1)             starts_with_SAP;
+ *   unsigned int(3)    SAP_type;
+ *   unsigned int(28)   SAP_delta_time;
+ *  }
+ * }
+ * </pre>
+ */
+public class SegmentIndexBox extends AbstractFullBox {
+    public static final String TYPE = "sidx";
+    List<Entry> entries = new ArrayList<Entry>();
+
+    long referenceId;
+    long timeScale;
+    long earliestPresentationTime;
+    long firstOffset;
+    int reserved;
+
+
+    public SegmentIndexBox() {
+        super(TYPE);
+    }
+
+    @Override
+    protected long getContentSize() {
+        long size = 4;
+        size += 4;
+        size += 4;
+        size += getVersion() == 0 ? 8 : 16;
+        size += 2; // reserved
+        size += 2; // reference count
+
+        size += entries.size() * 12;
+
+        return size;
+    }
+
+    @Override
+    protected void getContent(ByteBuffer byteBuffer) {
+        writeVersionAndFlags(byteBuffer);
+        IsoTypeWriter.writeUInt32(byteBuffer, referenceId);
+        IsoTypeWriter.writeUInt32(byteBuffer, timeScale);
+        if (getVersion() == 0) {
+            IsoTypeWriter.writeUInt32(byteBuffer, earliestPresentationTime);
+            IsoTypeWriter.writeUInt32(byteBuffer, firstOffset);
+        } else {
+            IsoTypeWriter.writeUInt64(byteBuffer, earliestPresentationTime);
+            IsoTypeWriter.writeUInt64(byteBuffer, firstOffset);
+        }
+        IsoTypeWriter.writeUInt16(byteBuffer, reserved);
+        IsoTypeWriter.writeUInt16(byteBuffer, entries.size());
+        for (Entry entry : entries) {
+            BitWriterBuffer b = new BitWriterBuffer(byteBuffer);
+            b.writeBits(entry.getReferenceType(), 1);
+            b.writeBits(entry.getReferencedSize(), 31);
+            IsoTypeWriter.writeUInt32(byteBuffer, entry.getSubsegmentDuration());
+            b = new BitWriterBuffer(byteBuffer);
+            b.writeBits(entry.getStartsWithSap(), 1);
+            b.writeBits(entry.getSapType(), 3);
+            b.writeBits(entry.getSapDeltaTime(), 28);
+        }
+
+    }
+
+    @Override
+    protected void _parseDetails(ByteBuffer content) {
+        parseVersionAndFlags(content);
+        referenceId = IsoTypeReader.readUInt32(content);
+        timeScale = IsoTypeReader.readUInt32(content);
+        if (getVersion() == 0) {
+            earliestPresentationTime = IsoTypeReader.readUInt32(content);
+            firstOffset = IsoTypeReader.readUInt32(content);
+        } else {
+            earliestPresentationTime = IsoTypeReader.readUInt64(content);
+            firstOffset = IsoTypeReader.readUInt64(content);
+        }
+        reserved = IsoTypeReader.readUInt16(content);
+        int numEntries = IsoTypeReader.readUInt16(content);
+        for (int i = 0; i < numEntries; i++) {
+            BitReaderBuffer b = new BitReaderBuffer(content);
+            Entry e = new Entry();
+            e.setReferenceType((byte) b.readBits(1));
+            e.setReferencedSize(b.readBits(31));
+            e.setSubsegmentDuration(IsoTypeReader.readUInt32(content));
+            b = new BitReaderBuffer(content);
+            e.setStartsWithSap((byte) b.readBits(1));
+            e.setSapType((byte) b.readBits(3));
+            e.setSapDeltaTime(b.readBits(28));
+            entries.add(e);
+        }
+    }
+
+
+    public List<Entry> getEntries() {
+        return entries;
+    }
+
+    public void setEntries(List<Entry> entries) {
+        this.entries = entries;
+    }
+
+    public long getReferenceId() {
+        return referenceId;
+    }
+
+    public void setReferenceId(long referenceId) {
+        this.referenceId = referenceId;
+    }
+
+    public long getTimeScale() {
+        return timeScale;
+    }
+
+    public void setTimeScale(long timeScale) {
+        this.timeScale = timeScale;
+    }
+
+    public long getEarliestPresentationTime() {
+        return earliestPresentationTime;
+    }
+
+    public void setEarliestPresentationTime(long earliestPresentationTime) {
+        this.earliestPresentationTime = earliestPresentationTime;
+    }
+
+    public long getFirstOffset() {
+        return firstOffset;
+    }
+
+    public void setFirstOffset(long firstOffset) {
+        this.firstOffset = firstOffset;
+    }
+
+    public int getReserved() {
+        return reserved;
+    }
+
+    public void setReserved(int reserved) {
+        this.reserved = reserved;
+    }
+
+    public static class Entry {
+        byte referenceType;
+        int referencedSize;
+        long subsegmentDuration;
+        byte startsWithSap;
+        byte sapType;
+        int sapDeltaTime;
+
+        public Entry() {
+        }
+
+        public Entry(byte referenceType, int referencedSize, long subsegmentDuration, byte startsWithSap, byte sapType, int sapDeltaTime) {
+            this.referenceType = referenceType;
+            this.referencedSize = referencedSize;
+            this.subsegmentDuration = subsegmentDuration;
+            this.startsWithSap = startsWithSap;
+            this.sapType = sapType;
+            this.sapDeltaTime = sapDeltaTime;
+        }
+
+        public byte getReferenceType() {
+            return referenceType;
+        }
+
+        public void setReferenceType(byte referenceType) {
+            this.referenceType = referenceType;
+        }
+
+        public int getReferencedSize() {
+            return referencedSize;
+        }
+
+        public void setReferencedSize(int referencedSize) {
+            this.referencedSize = referencedSize;
+        }
+
+        public long getSubsegmentDuration() {
+            return subsegmentDuration;
+        }
+
+        public void setSubsegmentDuration(long subsegmentDuration) {
+            this.subsegmentDuration = subsegmentDuration;
+        }
+
+        public byte getStartsWithSap() {
+            return startsWithSap;
+        }
+
+        public void setStartsWithSap(byte startsWithSap) {
+            this.startsWithSap = startsWithSap;
+        }
+
+        public byte getSapType() {
+            return sapType;
+        }
+
+        public void setSapType(byte sapType) {
+            this.sapType = sapType;
+        }
+
+        public int getSapDeltaTime() {
+            return sapDeltaTime;
+        }
+
+        public void setSapDeltaTime(int sapDeltaTime) {
+            this.sapDeltaTime = sapDeltaTime;
+        }
+
+        @Override
+        public String toString() {
+            return "Entry{" +
+                    "referenceType=" + referenceType +
+                    ", referencedSize=" + referencedSize +
+                    ", subsegmentDuration=" + subsegmentDuration +
+                    ", startsWithSap=" + startsWithSap +
+                    ", sapType=" + sapType +
+                    ", sapDeltaTime=" + sapDeltaTime +
+                    '}';
+        }
+
+        @Override
+        public boolean equals(Object o) {
+            if (this == o) return true;
+            if (o == null || getClass() != o.getClass()) return false;
+
+            Entry entry = (Entry) o;
+
+            if (referenceType != entry.referenceType) return false;
+            if (referencedSize != entry.referencedSize) return false;
+            if (sapDeltaTime != entry.sapDeltaTime) return false;
+            if (sapType != entry.sapType) return false;
+            if (startsWithSap != entry.startsWithSap) return false;
+            if (subsegmentDuration != entry.subsegmentDuration) return false;
+
+            return true;
+        }
+
+        @Override
+        public int hashCode() {
+            int result = (int) referenceType;
+            result = 31 * result + referencedSize;
+            result = 31 * result + (int) (subsegmentDuration ^ (subsegmentDuration >>> 32));
+            result = 31 * result + (int) startsWithSap;
+            result = 31 * result + (int) sapType;
+            result = 31 * result + sapDeltaTime;
+            return result;
+        }
+    }
+}
diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/boxes/threegpp26245/.svn/all-wcprops b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/threegpp26245/.svn/all-wcprops
new file mode 100644
index 0000000..92aa246
--- /dev/null
+++ b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/threegpp26245/.svn/all-wcprops
@@ -0,0 +1,11 @@
+K 25
+svn:wc:ra_dav:version-url
+V 92
+/svn/!svn/ver/507/trunk/isoparser/src/main/java/com/googlecode/mp4parser/boxes/threegpp26245
+END
+FontTableBox.java
+K 25
+svn:wc:ra_dav:version-url
+V 110
+/svn/!svn/ver/507/trunk/isoparser/src/main/java/com/googlecode/mp4parser/boxes/threegpp26245/FontTableBox.java
+END
diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/boxes/threegpp26245/.svn/entries b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/threegpp26245/.svn/entries
new file mode 100644
index 0000000..a126e77
--- /dev/null
+++ b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/threegpp26245/.svn/entries
@@ -0,0 +1,62 @@
+10
+
+dir
+778
+http://mp4parser.googlecode.com/svn/trunk/isoparser/src/main/java/com/googlecode/mp4parser/boxes/threegpp26245
+http://mp4parser.googlecode.com/svn
+
+
+
+2012-04-21T22:05:38.425329Z
+507
+Sebastian.Annies@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+7decde4b-c250-0410-a0da-51896bc88be6
+
+FontTableBox.java
+file
+
+
+
+
+2012-09-14T17:27:50.567220Z
+edbb8c6ba22fb01c3b13ce20e34513b8
+2012-04-21T22:05:38.425329Z
+507
+Sebastian.Annies@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+2444
+
diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/boxes/threegpp26245/.svn/text-base/FontTableBox.java.svn-base b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/threegpp26245/.svn/text-base/FontTableBox.java.svn-base
new file mode 100644
index 0000000..2e3f640
--- /dev/null
+++ b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/threegpp26245/.svn/text-base/FontTableBox.java.svn-base
@@ -0,0 +1,95 @@
+package com.googlecode.mp4parser.boxes.threegpp26245;
+
+import com.coremedia.iso.IsoTypeReader;
+import com.coremedia.iso.IsoTypeWriter;
+import com.coremedia.iso.Utf8;
+import com.googlecode.mp4parser.AbstractBox;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.util.LinkedList;
+import java.util.List;
+
+/**
+ *
+ */
+public class FontTableBox extends AbstractBox {
+    List<FontRecord> entries = new LinkedList<FontRecord>();
+
+    public FontTableBox() {
+        super("ftab");
+    }
+
+    @Override
+    protected long getContentSize() {
+        int size = 2;
+        for (FontRecord fontRecord : entries) {
+            size += fontRecord.getSize();
+        }
+        return size;
+    }
+
+
+    @Override
+    public void _parseDetails(ByteBuffer content) {
+        int numberOfRecords = IsoTypeReader.readUInt16(content);
+        for (int i = 0; i < numberOfRecords; i++) {
+            FontRecord fr = new FontRecord();
+            fr.parse(content);
+            entries.add(fr);
+        }
+    }
+
+    @Override
+    protected void getContent(ByteBuffer byteBuffer) {
+        IsoTypeWriter.writeUInt16(byteBuffer, entries.size());
+        for (FontRecord record : entries) {
+            record.getContent(byteBuffer);
+        }
+    }
+
+    public List<FontRecord> getEntries() {
+        return entries;
+    }
+
+    public void setEntries(List<FontRecord> entries) {
+        this.entries = entries;
+    }
+
+    public static class FontRecord {
+        int fontId;
+        String fontname;
+
+        public FontRecord() {
+        }
+
+        public FontRecord(int fontId, String fontname) {
+            this.fontId = fontId;
+            this.fontname = fontname;
+        }
+
+        public void parse(ByteBuffer bb) {
+            fontId = IsoTypeReader.readUInt16(bb);
+            int length = IsoTypeReader.readUInt8(bb);
+            fontname = IsoTypeReader.readString(bb, length);
+        }
+
+        public void getContent(ByteBuffer bb) {
+            IsoTypeWriter.writeUInt16(bb, fontId);
+            IsoTypeWriter.writeUInt8(bb, fontname.length());
+            bb.put(Utf8.convert(fontname));
+        }
+
+        public int getSize() {
+            return Utf8.utf8StringLengthInBytes(fontname) + 3;
+        }
+
+        @Override
+        public String toString() {
+            return "FontRecord{" +
+                    "fontId=" + fontId +
+                    ", fontname='" + fontname + '\'' +
+                    '}';
+        }
+    }
+}
diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/boxes/threegpp26245/FontTableBox.java b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/threegpp26245/FontTableBox.java
new file mode 100644
index 0000000..2e3f640
--- /dev/null
+++ b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/threegpp26245/FontTableBox.java
@@ -0,0 +1,95 @@
+package com.googlecode.mp4parser.boxes.threegpp26245;
+
+import com.coremedia.iso.IsoTypeReader;
+import com.coremedia.iso.IsoTypeWriter;
+import com.coremedia.iso.Utf8;
+import com.googlecode.mp4parser.AbstractBox;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.util.LinkedList;
+import java.util.List;
+
+/**
+ *
+ */
+public class FontTableBox extends AbstractBox {
+    List<FontRecord> entries = new LinkedList<FontRecord>();
+
+    public FontTableBox() {
+        super("ftab");
+    }
+
+    @Override
+    protected long getContentSize() {
+        int size = 2;
+        for (FontRecord fontRecord : entries) {
+            size += fontRecord.getSize();
+        }
+        return size;
+    }
+
+
+    @Override
+    public void _parseDetails(ByteBuffer content) {
+        int numberOfRecords = IsoTypeReader.readUInt16(content);
+        for (int i = 0; i < numberOfRecords; i++) {
+            FontRecord fr = new FontRecord();
+            fr.parse(content);
+            entries.add(fr);
+        }
+    }
+
+    @Override
+    protected void getContent(ByteBuffer byteBuffer) {
+        IsoTypeWriter.writeUInt16(byteBuffer, entries.size());
+        for (FontRecord record : entries) {
+            record.getContent(byteBuffer);
+        }
+    }
+
+    public List<FontRecord> getEntries() {
+        return entries;
+    }
+
+    public void setEntries(List<FontRecord> entries) {
+        this.entries = entries;
+    }
+
+    public static class FontRecord {
+        int fontId;
+        String fontname;
+
+        public FontRecord() {
+        }
+
+        public FontRecord(int fontId, String fontname) {
+            this.fontId = fontId;
+            this.fontname = fontname;
+        }
+
+        public void parse(ByteBuffer bb) {
+            fontId = IsoTypeReader.readUInt16(bb);
+            int length = IsoTypeReader.readUInt8(bb);
+            fontname = IsoTypeReader.readString(bb, length);
+        }
+
+        public void getContent(ByteBuffer bb) {
+            IsoTypeWriter.writeUInt16(bb, fontId);
+            IsoTypeWriter.writeUInt8(bb, fontname.length());
+            bb.put(Utf8.convert(fontname));
+        }
+
+        public int getSize() {
+            return Utf8.utf8StringLengthInBytes(fontname) + 3;
+        }
+
+        @Override
+        public String toString() {
+            return "FontRecord{" +
+                    "fontId=" + fontId +
+                    ", fontname='" + fontname + '\'' +
+                    '}';
+        }
+    }
+}
diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/boxes/ultraviolet/.svn/all-wcprops b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/ultraviolet/.svn/all-wcprops
new file mode 100644
index 0000000..4e87a87
--- /dev/null
+++ b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/ultraviolet/.svn/all-wcprops
@@ -0,0 +1,17 @@
+K 25
+svn:wc:ra_dav:version-url
+V 90
+/svn/!svn/ver/507/trunk/isoparser/src/main/java/com/googlecode/mp4parser/boxes/ultraviolet
+END
+BaseLocationBox.java
+K 25
+svn:wc:ra_dav:version-url
+V 111
+/svn/!svn/ver/507/trunk/isoparser/src/main/java/com/googlecode/mp4parser/boxes/ultraviolet/BaseLocationBox.java
+END
+AssetInformationBox.java
+K 25
+svn:wc:ra_dav:version-url
+V 115
+/svn/!svn/ver/505/trunk/isoparser/src/main/java/com/googlecode/mp4parser/boxes/ultraviolet/AssetInformationBox.java
+END
diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/boxes/ultraviolet/.svn/entries b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/ultraviolet/.svn/entries
new file mode 100644
index 0000000..c7166b8
--- /dev/null
+++ b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/ultraviolet/.svn/entries
@@ -0,0 +1,96 @@
+10
+
+dir
+778
+http://mp4parser.googlecode.com/svn/trunk/isoparser/src/main/java/com/googlecode/mp4parser/boxes/ultraviolet
+http://mp4parser.googlecode.com/svn
+
+
+
+2012-04-21T22:05:38.425329Z
+507
+Sebastian.Annies@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+7decde4b-c250-0410-a0da-51896bc88be6
+
+BaseLocationBox.java
+file
+
+
+
+
+2012-09-14T17:27:51.307230Z
+40378a4f505496f720804c1f201fc542
+2012-04-21T22:05:38.425329Z
+507
+Sebastian.Annies@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+3319
+
+AssetInformationBox.java
+file
+
+
+
+
+2012-09-14T17:27:51.307230Z
+a43de0d08b7416e7a9034f0840cc2eeb
+2012-04-21T21:18:31.685061Z
+505
+Sebastian.Annies@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+2063
+
diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/boxes/ultraviolet/.svn/text-base/AssetInformationBox.java.svn-base b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/ultraviolet/.svn/text-base/AssetInformationBox.java.svn-base
new file mode 100644
index 0000000..a2a9e8a
--- /dev/null
+++ b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/ultraviolet/.svn/text-base/AssetInformationBox.java.svn-base
@@ -0,0 +1,75 @@
+/*
+ * 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.ultraviolet;
+
+import com.coremedia.iso.IsoTypeReader;
+import com.coremedia.iso.Utf8;
+import com.googlecode.mp4parser.AbstractFullBox;
+
+import java.nio.ByteBuffer;
+
+/**
+ * AssetInformationBox as defined Common File Format Spec.
+ */
+public class AssetInformationBox extends AbstractFullBox {
+    String apid = "";
+    String profileVersion = "0000";
+
+    public AssetInformationBox() {
+        super("ainf");
+    }
+
+    @Override
+    protected long getContentSize() {
+        return Utf8.utf8StringLengthInBytes(apid) + 9;
+    }
+
+
+    @Override
+    protected void getContent(ByteBuffer byteBuffer) {
+        writeVersionAndFlags(byteBuffer);
+        byteBuffer.put(Utf8.convert(profileVersion), 0, 4);
+        byteBuffer.put(Utf8.convert(apid));
+        byteBuffer.put((byte) 0);
+    }
+
+
+    @Override
+    public void _parseDetails(ByteBuffer content) {
+        parseVersionAndFlags(content);
+        profileVersion = IsoTypeReader.readString(content, 4);
+        apid = IsoTypeReader.readString(content);
+        content = null;
+    }
+
+    public String getApid() {
+        return apid;
+    }
+
+    public void setApid(String apid) {
+        this.apid = apid;
+    }
+
+    public String getProfileVersion() {
+        return profileVersion;
+    }
+
+    public void setProfileVersion(String profileVersion) {
+        assert profileVersion != null && profileVersion.length() == 4;
+        this.profileVersion = profileVersion;
+    }
+}
diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/boxes/ultraviolet/.svn/text-base/BaseLocationBox.java.svn-base b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/ultraviolet/.svn/text-base/BaseLocationBox.java.svn-base
new file mode 100644
index 0000000..1c63293
--- /dev/null
+++ b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/ultraviolet/.svn/text-base/BaseLocationBox.java.svn-base
@@ -0,0 +1,103 @@
+/*
+ * 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.ultraviolet;
+
+import com.coremedia.iso.IsoTypeReader;
+import com.coremedia.iso.Utf8;
+import com.googlecode.mp4parser.AbstractFullBox;
+
+import java.nio.ByteBuffer;
+
+/**
+ *
+ */
+public class BaseLocationBox extends AbstractFullBox {
+    String baseLocation = "";
+    String purchaseLocation = "";
+
+    public BaseLocationBox() {
+        super("bloc");
+    }
+
+    public BaseLocationBox(String baseLocation, String purchaseLocation) {
+        super("bloc");
+        this.baseLocation = baseLocation;
+        this.purchaseLocation = purchaseLocation;
+    }
+
+    public String getBaseLocation() {
+        return baseLocation;
+    }
+
+    public void setBaseLocation(String baseLocation) {
+        this.baseLocation = baseLocation;
+    }
+
+    public String getPurchaseLocation() {
+        return purchaseLocation;
+    }
+
+    public void setPurchaseLocation(String purchaseLocation) {
+        this.purchaseLocation = purchaseLocation;
+    }
+
+    @Override
+    protected long getContentSize() {
+        return 1028;
+    }
+
+    @Override
+    public void _parseDetails(ByteBuffer content) {
+        parseVersionAndFlags(content);
+        baseLocation = IsoTypeReader.readString(content);
+        content.get(new byte[256 - Utf8.utf8StringLengthInBytes(baseLocation) - 1]);
+        purchaseLocation = IsoTypeReader.readString(content);
+        content.get(new byte[256 - Utf8.utf8StringLengthInBytes(purchaseLocation) - 1]);
+        content.get(new byte[512]);
+    }
+
+    @Override
+    protected void getContent(ByteBuffer byteBuffer) {
+        writeVersionAndFlags(byteBuffer);
+        byteBuffer.put(Utf8.convert(baseLocation));
+        byteBuffer.put(new byte[256 - Utf8.utf8StringLengthInBytes(baseLocation)]); // string plus term zero
+        byteBuffer.put(Utf8.convert(purchaseLocation));
+        byteBuffer.put(new byte[256 - Utf8.utf8StringLengthInBytes(purchaseLocation)]); // string plus term zero
+        byteBuffer.put(new byte[512]);
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (o == null || getClass() != o.getClass()) return false;
+
+        BaseLocationBox that = (BaseLocationBox) o;
+
+        if (baseLocation != null ? !baseLocation.equals(that.baseLocation) : that.baseLocation != null) return false;
+        if (purchaseLocation != null ? !purchaseLocation.equals(that.purchaseLocation) : that.purchaseLocation != null)
+            return false;
+
+        return true;
+    }
+
+    @Override
+    public int hashCode() {
+        int result = baseLocation != null ? baseLocation.hashCode() : 0;
+        result = 31 * result + (purchaseLocation != null ? purchaseLocation.hashCode() : 0);
+        return result;
+    }
+}
diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/boxes/ultraviolet/AssetInformationBox.java b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/ultraviolet/AssetInformationBox.java
new file mode 100644
index 0000000..a2a9e8a
--- /dev/null
+++ b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/ultraviolet/AssetInformationBox.java
@@ -0,0 +1,75 @@
+/*
+ * 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.ultraviolet;
+
+import com.coremedia.iso.IsoTypeReader;
+import com.coremedia.iso.Utf8;
+import com.googlecode.mp4parser.AbstractFullBox;
+
+import java.nio.ByteBuffer;
+
+/**
+ * AssetInformationBox as defined Common File Format Spec.
+ */
+public class AssetInformationBox extends AbstractFullBox {
+    String apid = "";
+    String profileVersion = "0000";
+
+    public AssetInformationBox() {
+        super("ainf");
+    }
+
+    @Override
+    protected long getContentSize() {
+        return Utf8.utf8StringLengthInBytes(apid) + 9;
+    }
+
+
+    @Override
+    protected void getContent(ByteBuffer byteBuffer) {
+        writeVersionAndFlags(byteBuffer);
+        byteBuffer.put(Utf8.convert(profileVersion), 0, 4);
+        byteBuffer.put(Utf8.convert(apid));
+        byteBuffer.put((byte) 0);
+    }
+
+
+    @Override
+    public void _parseDetails(ByteBuffer content) {
+        parseVersionAndFlags(content);
+        profileVersion = IsoTypeReader.readString(content, 4);
+        apid = IsoTypeReader.readString(content);
+        content = null;
+    }
+
+    public String getApid() {
+        return apid;
+    }
+
+    public void setApid(String apid) {
+        this.apid = apid;
+    }
+
+    public String getProfileVersion() {
+        return profileVersion;
+    }
+
+    public void setProfileVersion(String profileVersion) {
+        assert profileVersion != null && profileVersion.length() == 4;
+        this.profileVersion = profileVersion;
+    }
+}
diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/boxes/ultraviolet/BaseLocationBox.java b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/ultraviolet/BaseLocationBox.java
new file mode 100644
index 0000000..1c63293
--- /dev/null
+++ b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/ultraviolet/BaseLocationBox.java
@@ -0,0 +1,103 @@
+/*
+ * 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.ultraviolet;
+
+import com.coremedia.iso.IsoTypeReader;
+import com.coremedia.iso.Utf8;
+import com.googlecode.mp4parser.AbstractFullBox;
+
+import java.nio.ByteBuffer;
+
+/**
+ *
+ */
+public class BaseLocationBox extends AbstractFullBox {
+    String baseLocation = "";
+    String purchaseLocation = "";
+
+    public BaseLocationBox() {
+        super("bloc");
+    }
+
+    public BaseLocationBox(String baseLocation, String purchaseLocation) {
+        super("bloc");
+        this.baseLocation = baseLocation;
+        this.purchaseLocation = purchaseLocation;
+    }
+
+    public String getBaseLocation() {
+        return baseLocation;
+    }
+
+    public void setBaseLocation(String baseLocation) {
+        this.baseLocation = baseLocation;
+    }
+
+    public String getPurchaseLocation() {
+        return purchaseLocation;
+    }
+
+    public void setPurchaseLocation(String purchaseLocation) {
+        this.purchaseLocation = purchaseLocation;
+    }
+
+    @Override
+    protected long getContentSize() {
+        return 1028;
+    }
+
+    @Override
+    public void _parseDetails(ByteBuffer content) {
+        parseVersionAndFlags(content);
+        baseLocation = IsoTypeReader.readString(content);
+        content.get(new byte[256 - Utf8.utf8StringLengthInBytes(baseLocation) - 1]);
+        purchaseLocation = IsoTypeReader.readString(content);
+        content.get(new byte[256 - Utf8.utf8StringLengthInBytes(purchaseLocation) - 1]);
+        content.get(new byte[512]);
+    }
+
+    @Override
+    protected void getContent(ByteBuffer byteBuffer) {
+        writeVersionAndFlags(byteBuffer);
+        byteBuffer.put(Utf8.convert(baseLocation));
+        byteBuffer.put(new byte[256 - Utf8.utf8StringLengthInBytes(baseLocation)]); // string plus term zero
+        byteBuffer.put(Utf8.convert(purchaseLocation));
+        byteBuffer.put(new byte[256 - Utf8.utf8StringLengthInBytes(purchaseLocation)]); // string plus term zero
+        byteBuffer.put(new byte[512]);
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (o == null || getClass() != o.getClass()) return false;
+
+        BaseLocationBox that = (BaseLocationBox) o;
+
+        if (baseLocation != null ? !baseLocation.equals(that.baseLocation) : that.baseLocation != null) return false;
+        if (purchaseLocation != null ? !purchaseLocation.equals(that.purchaseLocation) : that.purchaseLocation != null)
+            return false;
+
+        return true;
+    }
+
+    @Override
+    public int hashCode() {
+        int result = baseLocation != null ? baseLocation.hashCode() : 0;
+        result = 31 * result + (purchaseLocation != null ? purchaseLocation.hashCode() : 0);
+        return result;
+    }
+}
diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/h264/.svn/all-wcprops b/isoparser/src/main/java/com/googlecode/mp4parser/h264/.svn/all-wcprops
new file mode 100644
index 0000000..6a318ac
--- /dev/null
+++ b/isoparser/src/main/java/com/googlecode/mp4parser/h264/.svn/all-wcprops
@@ -0,0 +1,23 @@
+K 25
+svn:wc:ra_dav:version-url
+V 77
+/svn/!svn/ver/528/trunk/isoparser/src/main/java/com/googlecode/mp4parser/h264
+END
+CharCache.java
+K 25
+svn:wc:ra_dav:version-url
+V 92
+/svn/!svn/ver/236/trunk/isoparser/src/main/java/com/googlecode/mp4parser/h264/CharCache.java
+END
+BTree.java
+K 25
+svn:wc:ra_dav:version-url
+V 88
+/svn/!svn/ver/236/trunk/isoparser/src/main/java/com/googlecode/mp4parser/h264/BTree.java
+END
+Debug.java
+K 25
+svn:wc:ra_dav:version-url
+V 88
+/svn/!svn/ver/236/trunk/isoparser/src/main/java/com/googlecode/mp4parser/h264/Debug.java
+END
diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/h264/.svn/entries b/isoparser/src/main/java/com/googlecode/mp4parser/h264/.svn/entries
new file mode 100644
index 0000000..a6fb43e
--- /dev/null
+++ b/isoparser/src/main/java/com/googlecode/mp4parser/h264/.svn/entries
@@ -0,0 +1,139 @@
+10
+
+dir
+778
+http://mp4parser.googlecode.com/svn/trunk/isoparser/src/main/java/com/googlecode/mp4parser/h264
+http://mp4parser.googlecode.com/svn
+
+
+
+2012-04-26T13:35:04.700844Z
+528
+hoemmagnus@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+7decde4b-c250-0410-a0da-51896bc88be6
+
+model
+dir
+
+CharCache.java
+file
+
+
+
+
+2012-09-14T17:27:51.457232Z
+c3b2a16e50a2b43f07cc729ba83f6b84
+2011-09-20T18:03:23.375910Z
+236
+Sebastian.Annies@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+1868
+
+BTree.java
+file
+
+
+
+
+2012-09-14T17:27:51.457232Z
+3dd3d07d1bd0c3bdbcb2aeb45c375f1d
+2011-09-20T18:03:23.375910Z
+236
+Sebastian.Annies@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+2116
+
+Debug.java
+file
+
+
+
+
+2012-09-14T17:27:51.457232Z
+f136a4c416c039d97eedee9f96667284
+2011-09-20T18:03:23.375910Z
+236
+Sebastian.Annies@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+2796
+
+write
+dir
+
+read
+dir
+
diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/h264/.svn/text-base/BTree.java.svn-base b/isoparser/src/main/java/com/googlecode/mp4parser/h264/.svn/text-base/BTree.java.svn-base
new file mode 100644
index 0000000..57391ba
--- /dev/null
+++ b/isoparser/src/main/java/com/googlecode/mp4parser/h264/.svn/text-base/BTree.java.svn-base
@@ -0,0 +1,69 @@
+/*
+Copyright (c) 2011 Stanislav Vitvitskiy
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of this
+software and associated documentation files (the "Software"), to deal in the Software
+without restriction, including without limitation the rights to use, copy, modify,
+merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to the following
+conditions:
+
+The above copyright notice and this permission notice shall be included in all copies or
+substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
+INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
+FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
+OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+package com.googlecode.mp4parser.h264;
+
+
+/**
+ * Simple BTree implementation needed for haffman tables
+ *
+ * @author Stanislav Vitvitskiy
+ */
+public class BTree {
+    private BTree zero;
+    private BTree one;
+    private Object value;
+
+    /**
+     * Adds a leaf value to a binary path specified by path
+     *
+     * @param str
+     * @param value
+     */
+    public void addString(String path, Object value) {
+        if (path.length() == 0) {
+            this.value = value;
+            return;
+        }
+        char charAt = path.charAt(0);
+        BTree branch;
+        if (charAt == '0') {
+            if (zero == null)
+                zero = new BTree();
+            branch = zero;
+        } else {
+            if (one == null)
+                one = new BTree();
+            branch = one;
+        }
+        branch.addString(path.substring(1), value);
+    }
+
+    public BTree down(int b) {
+        if (b == 0)
+            return zero;
+        else
+            return one;
+    }
+
+    public Object getValue() {
+        return value;
+    }
+}
\ No newline at end of file
diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/h264/.svn/text-base/CharCache.java.svn-base b/isoparser/src/main/java/com/googlecode/mp4parser/h264/.svn/text-base/CharCache.java.svn-base
new file mode 100644
index 0000000..2fe8ead
--- /dev/null
+++ b/isoparser/src/main/java/com/googlecode/mp4parser/h264/.svn/text-base/CharCache.java.svn-base
@@ -0,0 +1,57 @@
+/*
+Copyright (c) 2011 Stanislav Vitvitskiy
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of this
+software and associated documentation files (the "Software"), to deal in the Software
+without restriction, including without limitation the rights to use, copy, modify,
+merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to the following
+conditions:
+
+The above copyright notice and this permission notice shall be included in all copies or
+substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
+INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
+FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
+OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+package com.googlecode.mp4parser.h264;
+
+public class CharCache {
+    private char[] cache;
+    private int pos;
+
+    public CharCache(int capacity) {
+        cache = new char[capacity];
+    }
+
+    public void append(String str) {
+        char[] chars = str.toCharArray();
+        int available = cache.length - pos;
+        int toWrite = chars.length < available ? chars.length : available;
+        System.arraycopy(chars, 0, cache, pos, toWrite);
+        pos += toWrite;
+    }
+
+    public String toString() {
+        return new String(cache, 0, pos);
+    }
+
+    public void clear() {
+        pos = 0;
+    }
+
+    public void append(char c) {
+        if (pos < cache.length - 1) {
+            cache[pos] = c;
+            pos++;
+        }
+    }
+
+    public int length() {
+        return pos;
+    }
+}
diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/h264/.svn/text-base/Debug.java.svn-base b/isoparser/src/main/java/com/googlecode/mp4parser/h264/.svn/text-base/Debug.java.svn-base
new file mode 100644
index 0000000..d0bea73
--- /dev/null
+++ b/isoparser/src/main/java/com/googlecode/mp4parser/h264/.svn/text-base/Debug.java.svn-base
@@ -0,0 +1,88 @@
+/*
+Copyright (c) 2011 Stanislav Vitvitskiy
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of this
+software and associated documentation files (the "Software"), to deal in the Software
+without restriction, including without limitation the rights to use, copy, modify,
+merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to the following
+conditions:
+
+The above copyright notice and this permission notice shall be included in all copies or
+substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
+INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
+FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
+OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+package com.googlecode.mp4parser.h264;
+
+import java.nio.ShortBuffer;
+
+public class Debug {
+    public final static void print8x8(int[] output) {
+        int i = 0;
+        for (int x = 0; x < 8; x++) {
+            for (int y = 0; y < 8; y++) {
+                System.out.printf("%3d, ", output[i]);
+                i++;
+            }
+            System.out.println();
+        }
+    }
+
+    public final static void print8x8(short[] output) {
+        int i = 0;
+        for (int x = 0; x < 8; x++) {
+            for (int y = 0; y < 8; y++) {
+                System.out.printf("%3d, ", output[i]);
+                i++;
+            }
+            System.out.println();
+        }
+    }
+
+    public final static void print8x8(ShortBuffer output) {
+        for (int x = 0; x < 8; x++) {
+            for (int y = 0; y < 8; y++) {
+                System.out.printf("%3d, ", output.get());
+            }
+            System.out.println();
+        }
+    }
+
+    public static void print(short[] table) {
+        int i = 0;
+        for (int x = 0; x < 8; x++) {
+            for (int y = 0; y < 8; y++) {
+                System.out.printf("%3d, ", table[i]);
+                i++;
+            }
+            System.out.println();
+        }
+    }
+
+    public static void trace(String format, Object... args) {
+        // System.out.printf("> " + format + "\n", args);
+    }
+
+    public final static boolean debug = false;
+
+    public static void print(int i) {
+        if (debug)
+            System.out.print(i);
+    }
+
+    public static void print(String string) {
+        if (debug)
+            System.out.print(string);
+    }
+
+    public static void println(String string) {
+        if (debug)
+            System.out.println(string);
+    }
+}
diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/h264/BTree.java b/isoparser/src/main/java/com/googlecode/mp4parser/h264/BTree.java
new file mode 100644
index 0000000..57391ba
--- /dev/null
+++ b/isoparser/src/main/java/com/googlecode/mp4parser/h264/BTree.java
@@ -0,0 +1,69 @@
+/*
+Copyright (c) 2011 Stanislav Vitvitskiy
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of this
+software and associated documentation files (the "Software"), to deal in the Software
+without restriction, including without limitation the rights to use, copy, modify,
+merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to the following
+conditions:
+
+The above copyright notice and this permission notice shall be included in all copies or
+substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
+INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
+FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
+OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+package com.googlecode.mp4parser.h264;
+
+
+/**
+ * Simple BTree implementation needed for haffman tables
+ *
+ * @author Stanislav Vitvitskiy
+ */
+public class BTree {
+    private BTree zero;
+    private BTree one;
+    private Object value;
+
+    /**
+     * Adds a leaf value to a binary path specified by path
+     *
+     * @param str
+     * @param value
+     */
+    public void addString(String path, Object value) {
+        if (path.length() == 0) {
+            this.value = value;
+            return;
+        }
+        char charAt = path.charAt(0);
+        BTree branch;
+        if (charAt == '0') {
+            if (zero == null)
+                zero = new BTree();
+            branch = zero;
+        } else {
+            if (one == null)
+                one = new BTree();
+            branch = one;
+        }
+        branch.addString(path.substring(1), value);
+    }
+
+    public BTree down(int b) {
+        if (b == 0)
+            return zero;
+        else
+            return one;
+    }
+
+    public Object getValue() {
+        return value;
+    }
+}
\ No newline at end of file
diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/h264/CharCache.java b/isoparser/src/main/java/com/googlecode/mp4parser/h264/CharCache.java
new file mode 100644
index 0000000..2fe8ead
--- /dev/null
+++ b/isoparser/src/main/java/com/googlecode/mp4parser/h264/CharCache.java
@@ -0,0 +1,57 @@
+/*
+Copyright (c) 2011 Stanislav Vitvitskiy
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of this
+software and associated documentation files (the "Software"), to deal in the Software
+without restriction, including without limitation the rights to use, copy, modify,
+merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to the following
+conditions:
+
+The above copyright notice and this permission notice shall be included in all copies or
+substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
+INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
+FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
+OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+package com.googlecode.mp4parser.h264;
+
+public class CharCache {
+    private char[] cache;
+    private int pos;
+
+    public CharCache(int capacity) {
+        cache = new char[capacity];
+    }
+
+    public void append(String str) {
+        char[] chars = str.toCharArray();
+        int available = cache.length - pos;
+        int toWrite = chars.length < available ? chars.length : available;
+        System.arraycopy(chars, 0, cache, pos, toWrite);
+        pos += toWrite;
+    }
+
+    public String toString() {
+        return new String(cache, 0, pos);
+    }
+
+    public void clear() {
+        pos = 0;
+    }
+
+    public void append(char c) {
+        if (pos < cache.length - 1) {
+            cache[pos] = c;
+            pos++;
+        }
+    }
+
+    public int length() {
+        return pos;
+    }
+}
diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/h264/Debug.java b/isoparser/src/main/java/com/googlecode/mp4parser/h264/Debug.java
new file mode 100644
index 0000000..d0bea73
--- /dev/null
+++ b/isoparser/src/main/java/com/googlecode/mp4parser/h264/Debug.java
@@ -0,0 +1,88 @@
+/*
+Copyright (c) 2011 Stanislav Vitvitskiy
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of this
+software and associated documentation files (the "Software"), to deal in the Software
+without restriction, including without limitation the rights to use, copy, modify,
+merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to the following
+conditions:
+
+The above copyright notice and this permission notice shall be included in all copies or
+substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
+INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
+FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
+OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+package com.googlecode.mp4parser.h264;
+
+import java.nio.ShortBuffer;
+
+public class Debug {
+    public final static void print8x8(int[] output) {
+        int i = 0;
+        for (int x = 0; x < 8; x++) {
+            for (int y = 0; y < 8; y++) {
+                System.out.printf("%3d, ", output[i]);
+                i++;
+            }
+            System.out.println();
+        }
+    }
+
+    public final static void print8x8(short[] output) {
+        int i = 0;
+        for (int x = 0; x < 8; x++) {
+            for (int y = 0; y < 8; y++) {
+                System.out.printf("%3d, ", output[i]);
+                i++;
+            }
+            System.out.println();
+        }
+    }
+
+    public final static void print8x8(ShortBuffer output) {
+        for (int x = 0; x < 8; x++) {
+            for (int y = 0; y < 8; y++) {
+                System.out.printf("%3d, ", output.get());
+            }
+            System.out.println();
+        }
+    }
+
+    public static void print(short[] table) {
+        int i = 0;
+        for (int x = 0; x < 8; x++) {
+            for (int y = 0; y < 8; y++) {
+                System.out.printf("%3d, ", table[i]);
+                i++;
+            }
+            System.out.println();
+        }
+    }
+
+    public static void trace(String format, Object... args) {
+        // System.out.printf("> " + format + "\n", args);
+    }
+
+    public final static boolean debug = false;
+
+    public static void print(int i) {
+        if (debug)
+            System.out.print(i);
+    }
+
+    public static void print(String string) {
+        if (debug)
+            System.out.print(string);
+    }
+
+    public static void println(String string) {
+        if (debug)
+            System.out.println(string);
+    }
+}
diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/h264/model/.svn/all-wcprops b/isoparser/src/main/java/com/googlecode/mp4parser/h264/model/.svn/all-wcprops
new file mode 100644
index 0000000..87c4f5d
--- /dev/null
+++ b/isoparser/src/main/java/com/googlecode/mp4parser/h264/model/.svn/all-wcprops
@@ -0,0 +1,59 @@
+K 25
+svn:wc:ra_dav:version-url
+V 83
+/svn/!svn/ver/528/trunk/isoparser/src/main/java/com/googlecode/mp4parser/h264/model
+END
+HRDParameters.java
+K 25
+svn:wc:ra_dav:version-url
+V 102
+/svn/!svn/ver/381/trunk/isoparser/src/main/java/com/googlecode/mp4parser/h264/model/HRDParameters.java
+END
+ChromaFormat.java
+K 25
+svn:wc:ra_dav:version-url
+V 101
+/svn/!svn/ver/244/trunk/isoparser/src/main/java/com/googlecode/mp4parser/h264/model/ChromaFormat.java
+END
+BitstreamElement.java
+K 25
+svn:wc:ra_dav:version-url
+V 105
+/svn/!svn/ver/236/trunk/isoparser/src/main/java/com/googlecode/mp4parser/h264/model/BitstreamElement.java
+END
+SeqParameterSet.java
+K 25
+svn:wc:ra_dav:version-url
+V 104
+/svn/!svn/ver/377/trunk/isoparser/src/main/java/com/googlecode/mp4parser/h264/model/SeqParameterSet.java
+END
+ScalingMatrix.java
+K 25
+svn:wc:ra_dav:version-url
+V 102
+/svn/!svn/ver/244/trunk/isoparser/src/main/java/com/googlecode/mp4parser/h264/model/ScalingMatrix.java
+END
+VUIParameters.java
+K 25
+svn:wc:ra_dav:version-url
+V 102
+/svn/!svn/ver/244/trunk/isoparser/src/main/java/com/googlecode/mp4parser/h264/model/VUIParameters.java
+END
+PictureParameterSet.java
+K 25
+svn:wc:ra_dav:version-url
+V 108
+/svn/!svn/ver/528/trunk/isoparser/src/main/java/com/googlecode/mp4parser/h264/model/PictureParameterSet.java
+END
+ScalingList.java
+K 25
+svn:wc:ra_dav:version-url
+V 100
+/svn/!svn/ver/244/trunk/isoparser/src/main/java/com/googlecode/mp4parser/h264/model/ScalingList.java
+END
+AspectRatio.java
+K 25
+svn:wc:ra_dav:version-url
+V 100
+/svn/!svn/ver/236/trunk/isoparser/src/main/java/com/googlecode/mp4parser/h264/model/AspectRatio.java
+END
diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/h264/model/.svn/entries b/isoparser/src/main/java/com/googlecode/mp4parser/h264/model/.svn/entries
new file mode 100644
index 0000000..57346e5
--- /dev/null
+++ b/isoparser/src/main/java/com/googlecode/mp4parser/h264/model/.svn/entries
@@ -0,0 +1,334 @@
+10
+
+dir
+778
+http://mp4parser.googlecode.com/svn/trunk/isoparser/src/main/java/com/googlecode/mp4parser/h264/model
+http://mp4parser.googlecode.com/svn
+
+
+
+2012-04-26T13:35:04.700844Z
+528
+hoemmagnus@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+7decde4b-c250-0410-a0da-51896bc88be6
+
+HRDParameters.java
+file
+
+
+
+
+2012-09-14T17:27:51.377231Z
+b975fc17f18909ecfd3e15a29d8fb70e
+2012-03-06T23:45:39.821994Z
+381
+Sebastian.Annies@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+2410
+
+ChromaFormat.java
+file
+
+
+
+
+2012-09-14T17:27:51.377231Z
+55075c51ac229ada06e17133f52fbc2b
+2011-10-15T21:12:03.008630Z
+244
+Sebastian.Annies@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+2498
+
+BitstreamElement.java
+file
+
+
+
+
+2012-09-14T17:27:51.377231Z
+36a082110b2e0d7feab53e78bd5447e9
+2011-09-20T18:03:23.375910Z
+236
+Sebastian.Annies@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+1287
+
+SeqParameterSet.java
+file
+
+
+
+
+2012-09-14T17:27:51.377231Z
+f5f16b7f8e3609e73614f978009d472a
+2012-03-05T23:28:24.666173Z
+377
+Sebastian.Annies@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+28600
+
+ScalingMatrix.java
+file
+
+
+
+
+2012-09-14T17:27:51.377231Z
+d7e4473348da54dc5434b84745704e62
+2011-10-15T21:12:03.008630Z
+244
+Sebastian.Annies@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+1582
+
+VUIParameters.java
+file
+
+
+
+
+2012-09-14T17:27:51.377231Z
+c39f83d225178ec9873004550130700b
+2011-10-15T21:12:03.008630Z
+244
+Sebastian.Annies@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+4563
+
+PictureParameterSet.java
+file
+
+
+
+
+2012-09-14T17:27:51.377231Z
+bfe87344433e296b0c8b953ddad5e78f
+2012-04-26T13:35:04.700844Z
+528
+hoemmagnus@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+19980
+
+ScalingList.java
+file
+
+
+
+
+2012-09-14T17:27:51.377231Z
+6f3a11866f0bcd61a9868f949a3c5c27
+2011-10-15T21:12:03.008630Z
+244
+Sebastian.Annies@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+2945
+
+AspectRatio.java
+file
+
+
+
+
+2012-09-14T17:27:51.377231Z
+4471abf932d16399567945fce05d656c
+2011-09-20T18:03:23.375910Z
+236
+Sebastian.Annies@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+1640
+
diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/h264/model/.svn/text-base/AspectRatio.java.svn-base b/isoparser/src/main/java/com/googlecode/mp4parser/h264/model/.svn/text-base/AspectRatio.java.svn-base
new file mode 100644
index 0000000..bc66b1a
--- /dev/null
+++ b/isoparser/src/main/java/com/googlecode/mp4parser/h264/model/.svn/text-base/AspectRatio.java.svn-base
@@ -0,0 +1,50 @@
+/*
+Copyright (c) 2011 Stanislav Vitvitskiy
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of this
+software and associated documentation files (the "Software"), to deal in the Software
+without restriction, including without limitation the rights to use, copy, modify,
+merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to the following
+conditions:
+
+The above copyright notice and this permission notice shall be included in all copies or
+substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
+INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
+FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
+OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+package com.googlecode.mp4parser.h264.model;
+
+/**
+ * Aspect ratio
+ * <p/>
+ * dynamic enum
+ *
+ * @author Stanislav Vitvitskiy
+ */
+public class AspectRatio {
+
+    public static final AspectRatio Extended_SAR = new AspectRatio(255);
+
+    private int value;
+
+    private AspectRatio(int value) {
+        this.value = value;
+    }
+
+    public static AspectRatio fromValue(int value) {
+        if (value == Extended_SAR.value) {
+            return Extended_SAR;
+        }
+        return new AspectRatio(value);
+    }
+
+    public int getValue() {
+        return value;
+    }
+}
diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/h264/model/.svn/text-base/BitstreamElement.java.svn-base b/isoparser/src/main/java/com/googlecode/mp4parser/h264/model/.svn/text-base/BitstreamElement.java.svn-base
new file mode 100644
index 0000000..f16c5e9
--- /dev/null
+++ b/isoparser/src/main/java/com/googlecode/mp4parser/h264/model/.svn/text-base/BitstreamElement.java.svn-base
@@ -0,0 +1,29 @@
+/*
+Copyright (c) 2011 Stanislav Vitvitskiy
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of this
+software and associated documentation files (the "Software"), to deal in the Software
+without restriction, including without limitation the rights to use, copy, modify,
+merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to the following
+conditions:
+
+The above copyright notice and this permission notice shall be included in all copies or
+substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
+INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
+FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
+OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+package com.googlecode.mp4parser.h264.model;
+
+import java.io.IOException;
+import java.io.OutputStream;
+
+public abstract class BitstreamElement {
+
+    public abstract void write(OutputStream out) throws IOException;
+}
diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/h264/model/.svn/text-base/ChromaFormat.java.svn-base b/isoparser/src/main/java/com/googlecode/mp4parser/h264/model/.svn/text-base/ChromaFormat.java.svn-base
new file mode 100644
index 0000000..2af2966
--- /dev/null
+++ b/isoparser/src/main/java/com/googlecode/mp4parser/h264/model/.svn/text-base/ChromaFormat.java.svn-base
@@ -0,0 +1,77 @@
+/*
+Copyright (c) 2011 Stanislav Vitvitskiy
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of this
+software and associated documentation files (the "Software"), to deal in the Software
+without restriction, including without limitation the rights to use, copy, modify,
+merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to the following
+conditions:
+
+The above copyright notice and this permission notice shall be included in all copies or
+substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
+INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
+FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
+OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+package com.googlecode.mp4parser.h264.model;
+
+/**
+ * Chroma format enum
+ *
+ * @author Stanislav Vitvitskiy
+ */
+public class ChromaFormat {
+    public static ChromaFormat MONOCHROME = new ChromaFormat(0, 0, 0);
+    public static ChromaFormat YUV_420 = new ChromaFormat(1, 2, 2);
+    public static ChromaFormat YUV_422 = new ChromaFormat(2, 2, 1);
+    public static ChromaFormat YUV_444 = new ChromaFormat(3, 1, 1);
+
+    private int id;
+    private int subWidth;
+    private int subHeight;
+
+    public ChromaFormat(int id, int subWidth, int subHeight) {
+        this.id = id;
+        this.subWidth = subWidth;
+        this.subHeight = subHeight;
+    }
+
+    public static ChromaFormat fromId(int id) {
+        if (id == MONOCHROME.id) {
+            return MONOCHROME;
+        } else if (id == YUV_420.id) {
+            return YUV_420;
+        } else if (id == YUV_422.id) {
+            return YUV_422;
+        } else if (id == YUV_444.id) {
+            return YUV_444;
+        }
+        return null;
+    }
+
+    public int getId() {
+        return id;
+    }
+
+    public int getSubWidth() {
+        return subWidth;
+    }
+
+    public int getSubHeight() {
+        return subHeight;
+    }
+
+    @Override
+    public String toString() {
+        return "ChromaFormat{" + "\n" +
+                "id=" + id + ",\n" +
+                " subWidth=" + subWidth + ",\n" +
+                " subHeight=" + subHeight +
+                '}';
+    }
+}
diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/h264/model/.svn/text-base/HRDParameters.java.svn-base b/isoparser/src/main/java/com/googlecode/mp4parser/h264/model/.svn/text-base/HRDParameters.java.svn-base
new file mode 100644
index 0000000..f713ab2
--- /dev/null
+++ b/isoparser/src/main/java/com/googlecode/mp4parser/h264/model/.svn/text-base/HRDParameters.java.svn-base
@@ -0,0 +1,53 @@
+/*
+Copyright (c) 2011 Stanislav Vitvitskiy
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of this
+software and associated documentation files (the "Software"), to deal in the Software
+without restriction, including without limitation the rights to use, copy, modify,
+merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to the following
+conditions:
+
+The above copyright notice and this permission notice shall be included in all copies or
+substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
+INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
+FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
+OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+package com.googlecode.mp4parser.h264.model;
+
+import java.util.Arrays;
+
+public class HRDParameters {
+
+    public int cpb_cnt_minus1;
+    public int bit_rate_scale;
+    public int cpb_size_scale;
+    public int[] bit_rate_value_minus1;
+    public int[] cpb_size_value_minus1;
+    public boolean[] cbr_flag;
+    public int initial_cpb_removal_delay_length_minus1;
+    public int cpb_removal_delay_length_minus1;
+    public int dpb_output_delay_length_minus1;
+    public int time_offset_length;
+
+    @Override
+    public String toString() {
+        return "HRDParameters{" +
+                "cpb_cnt_minus1=" + cpb_cnt_minus1 +
+                ", bit_rate_scale=" + bit_rate_scale +
+                ", cpb_size_scale=" + cpb_size_scale +
+                ", bit_rate_value_minus1=" + Arrays.toString(bit_rate_value_minus1) +
+                ", cpb_size_value_minus1=" + Arrays.toString(cpb_size_value_minus1) +
+                ", cbr_flag=" + Arrays.toString(cbr_flag) +
+                ", initial_cpb_removal_delay_length_minus1=" + initial_cpb_removal_delay_length_minus1 +
+                ", cpb_removal_delay_length_minus1=" + cpb_removal_delay_length_minus1 +
+                ", dpb_output_delay_length_minus1=" + dpb_output_delay_length_minus1 +
+                ", time_offset_length=" + time_offset_length +
+                '}';
+    }
+}
diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/h264/model/.svn/text-base/PictureParameterSet.java.svn-base b/isoparser/src/main/java/com/googlecode/mp4parser/h264/model/.svn/text-base/PictureParameterSet.java.svn-base
new file mode 100644
index 0000000..9154c38
--- /dev/null
+++ b/isoparser/src/main/java/com/googlecode/mp4parser/h264/model/.svn/text-base/PictureParameterSet.java.svn-base
@@ -0,0 +1,406 @@
+/*
+Copyright (c) 2011 Stanislav Vitvitskiy
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of this
+software and associated documentation files (the "Software"), to deal in the Software
+without restriction, including without limitation the rights to use, copy, modify,
+merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to the following
+conditions:
+
+The above copyright notice and this permission notice shall be included in all copies or
+substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
+INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
+FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
+OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+package com.googlecode.mp4parser.h264.model;
+
+import com.googlecode.mp4parser.h264.read.CAVLCReader;
+import com.googlecode.mp4parser.h264.write.CAVLCWriter;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.Arrays;
+
+/**
+ * Picture Parameter Set entity of H264 bitstream
+ * <p/>
+ * capable to serialize / deserialize with CAVLC bitstream
+ *
+ * @author Stanislav Vitvitskiy
+ */
+public class PictureParameterSet extends BitstreamElement {
+
+    public static class PPSExt {
+        public boolean transform_8x8_mode_flag;
+        public ScalingMatrix scalindMatrix = new ScalingMatrix();
+        public int second_chroma_qp_index_offset;
+        public boolean[] pic_scaling_list_present_flag;
+
+        @Override
+        public String toString() {
+            return "PPSExt{" +
+                    "transform_8x8_mode_flag=" + transform_8x8_mode_flag +
+                    ", scalindMatrix=" + scalindMatrix +
+                    ", second_chroma_qp_index_offset=" + second_chroma_qp_index_offset +
+                    ", pic_scaling_list_present_flag=" + pic_scaling_list_present_flag +
+                    '}';
+        }
+    }
+
+    public boolean entropy_coding_mode_flag;
+    public int num_ref_idx_l0_active_minus1;
+    public int num_ref_idx_l1_active_minus1;
+    public int slice_group_change_rate_minus1;
+    public int pic_parameter_set_id;
+    public int seq_parameter_set_id;
+    public boolean pic_order_present_flag;
+    public int num_slice_groups_minus1;
+    public int slice_group_map_type;
+    public boolean weighted_pred_flag;
+    public int weighted_bipred_idc;
+    public int pic_init_qp_minus26;
+    public int pic_init_qs_minus26;
+    public int chroma_qp_index_offset;
+    public boolean deblocking_filter_control_present_flag;
+    public boolean constrained_intra_pred_flag;
+    public boolean redundant_pic_cnt_present_flag;
+    public int[] top_left;
+    public int[] bottom_right;
+    public int[] run_length_minus1;
+    public boolean slice_group_change_direction_flag;
+    public int[] slice_group_id;
+    public PPSExt extended;
+
+    public static PictureParameterSet read(byte[] b) throws IOException {
+        return read(new ByteArrayInputStream(b));
+    }
+
+    public static PictureParameterSet read(InputStream is) throws IOException {
+        CAVLCReader reader = new CAVLCReader(is);
+        PictureParameterSet pps = new PictureParameterSet();
+
+        pps.pic_parameter_set_id = reader.readUE("PPS: pic_parameter_set_id");
+        pps.seq_parameter_set_id = reader.readUE("PPS: seq_parameter_set_id");
+        pps.entropy_coding_mode_flag = reader
+                .readBool("PPS: entropy_coding_mode_flag");
+        pps.pic_order_present_flag = reader
+                .readBool("PPS: pic_order_present_flag");
+        pps.num_slice_groups_minus1 = reader
+                .readUE("PPS: num_slice_groups_minus1");
+        if (pps.num_slice_groups_minus1 > 0) {
+            pps.slice_group_map_type = reader
+                    .readUE("PPS: slice_group_map_type");
+            pps.top_left = new int[pps.num_slice_groups_minus1 + 1];
+            pps.bottom_right = new int[pps.num_slice_groups_minus1 + 1];
+            pps.run_length_minus1 = new int[pps.num_slice_groups_minus1 + 1];
+            if (pps.slice_group_map_type == 0)
+                for (int iGroup = 0; iGroup <= pps.num_slice_groups_minus1; iGroup++)
+                    pps.run_length_minus1[iGroup] = reader
+                            .readUE("PPS: run_length_minus1");
+            else if (pps.slice_group_map_type == 2)
+                for (int iGroup = 0; iGroup < pps.num_slice_groups_minus1; iGroup++) {
+                    pps.top_left[iGroup] = reader.readUE("PPS: top_left");
+                    pps.bottom_right[iGroup] = reader
+                            .readUE("PPS: bottom_right");
+                }
+            else if (pps.slice_group_map_type == 3
+                    || pps.slice_group_map_type == 4
+                    || pps.slice_group_map_type == 5) {
+                pps.slice_group_change_direction_flag = reader
+                        .readBool("PPS: slice_group_change_direction_flag");
+                pps.slice_group_change_rate_minus1 = reader
+                        .readUE("PPS: slice_group_change_rate_minus1");
+            } else if (pps.slice_group_map_type == 6) {
+                int NumberBitsPerSliceGroupId;
+                if (pps.num_slice_groups_minus1 + 1 > 4)
+                    NumberBitsPerSliceGroupId = 3;
+                else if (pps.num_slice_groups_minus1 + 1 > 2)
+                    NumberBitsPerSliceGroupId = 2;
+                else
+                    NumberBitsPerSliceGroupId = 1;
+                int pic_size_in_map_units_minus1 = reader
+                        .readUE("PPS: pic_size_in_map_units_minus1");
+                pps.slice_group_id = new int[pic_size_in_map_units_minus1 + 1];
+                for (int i = 0; i <= pic_size_in_map_units_minus1; i++) {
+                    pps.slice_group_id[i] = reader.readU(
+                            NumberBitsPerSliceGroupId, "PPS: slice_group_id ["
+                            + i + "]f");
+                }
+            }
+        }
+        pps.num_ref_idx_l0_active_minus1 = reader
+                .readUE("PPS: num_ref_idx_l0_active_minus1");
+        pps.num_ref_idx_l1_active_minus1 = reader
+                .readUE("PPS: num_ref_idx_l1_active_minus1");
+        pps.weighted_pred_flag = reader.readBool("PPS: weighted_pred_flag");
+        pps.weighted_bipred_idc = (int) reader.readNBit(2,
+                "PPS: weighted_bipred_idc");
+        pps.pic_init_qp_minus26 = reader.readSE("PPS: pic_init_qp_minus26");
+        pps.pic_init_qs_minus26 = reader.readSE("PPS: pic_init_qs_minus26");
+        pps.chroma_qp_index_offset = reader
+                .readSE("PPS: chroma_qp_index_offset");
+        pps.deblocking_filter_control_present_flag = reader
+                .readBool("PPS: deblocking_filter_control_present_flag");
+        pps.constrained_intra_pred_flag = reader
+                .readBool("PPS: constrained_intra_pred_flag");
+        pps.redundant_pic_cnt_present_flag = reader
+                .readBool("PPS: redundant_pic_cnt_present_flag");
+        if (reader.moreRBSPData()) {
+            pps.extended = new PictureParameterSet.PPSExt();
+            pps.extended.transform_8x8_mode_flag = reader
+                    .readBool("PPS: transform_8x8_mode_flag");
+            boolean pic_scaling_matrix_present_flag = reader
+                    .readBool("PPS: pic_scaling_matrix_present_flag");
+            if (pic_scaling_matrix_present_flag) {
+                for (int i = 0; i < 6 + 2 * (pps.extended.transform_8x8_mode_flag ? 1
+                        : 0); i++) {
+                    boolean pic_scaling_list_present_flag = reader
+                            .readBool("PPS: pic_scaling_list_present_flag");
+                    if (pic_scaling_list_present_flag) {
+                        pps.extended.scalindMatrix.ScalingList4x4 = new ScalingList[8];
+                        pps.extended.scalindMatrix.ScalingList8x8 = new ScalingList[8];
+                        if (i < 6) {
+                            pps.extended.scalindMatrix.ScalingList4x4[i] = ScalingList
+                                    .read(reader, 16);
+                        } else {
+                            pps.extended.scalindMatrix.ScalingList8x8[i - 6] = ScalingList
+                                    .read(reader, 64);
+                        }
+                    }
+                }
+            }
+            pps.extended.second_chroma_qp_index_offset = reader
+                    .readSE("PPS: second_chroma_qp_index_offset");
+        }
+
+        reader.readTrailingBits();
+
+        return pps;
+    }
+
+    public void write(OutputStream out) throws IOException {
+        CAVLCWriter writer = new CAVLCWriter(out);
+
+        writer.writeUE(pic_parameter_set_id, "PPS: pic_parameter_set_id");
+        writer.writeUE(seq_parameter_set_id, "PPS: seq_parameter_set_id");
+        writer.writeBool(entropy_coding_mode_flag,
+                "PPS: entropy_coding_mode_flag");
+        writer.writeBool(pic_order_present_flag, "PPS: pic_order_present_flag");
+        writer.writeUE(num_slice_groups_minus1, "PPS: num_slice_groups_minus1");
+        if (num_slice_groups_minus1 > 0) {
+            writer.writeUE(slice_group_map_type, "PPS: slice_group_map_type");
+            int[] top_left = new int[1];
+            int[] bottom_right = new int[1];
+            int[] run_length_minus1 = new int[1];
+            if (slice_group_map_type == 0) {
+                for (int iGroup = 0; iGroup <= num_slice_groups_minus1; iGroup++) {
+                    writer.writeUE(run_length_minus1[iGroup], "PPS: ");
+                }
+            } else if (slice_group_map_type == 2) {
+                for (int iGroup = 0; iGroup < num_slice_groups_minus1; iGroup++) {
+                    writer.writeUE(top_left[iGroup], "PPS: ");
+                    writer.writeUE(bottom_right[iGroup], "PPS: ");
+                }
+            } else if (slice_group_map_type == 3 || slice_group_map_type == 4
+                    || slice_group_map_type == 5) {
+                writer.writeBool(slice_group_change_direction_flag,
+                        "PPS: slice_group_change_direction_flag");
+                writer.writeUE(slice_group_change_rate_minus1,
+                        "PPS: slice_group_change_rate_minus1");
+            } else if (slice_group_map_type == 6) {
+                int NumberBitsPerSliceGroupId;
+                if (num_slice_groups_minus1 + 1 > 4)
+                    NumberBitsPerSliceGroupId = 3;
+                else if (num_slice_groups_minus1 + 1 > 2)
+                    NumberBitsPerSliceGroupId = 2;
+                else
+                    NumberBitsPerSliceGroupId = 1;
+                writer.writeUE(slice_group_id.length, "PPS: ");
+                for (int i = 0; i <= slice_group_id.length; i++) {
+                    writer.writeU(slice_group_id[i], NumberBitsPerSliceGroupId);
+                }
+            }
+        }
+        writer.writeUE(num_ref_idx_l0_active_minus1,
+                "PPS: num_ref_idx_l0_active_minus1");
+        writer.writeUE(num_ref_idx_l1_active_minus1,
+                "PPS: num_ref_idx_l1_active_minus1");
+        writer.writeBool(weighted_pred_flag, "PPS: weighted_pred_flag");
+        writer.writeNBit(weighted_bipred_idc, 2, "PPS: weighted_bipred_idc");
+        writer.writeSE(pic_init_qp_minus26, "PPS: pic_init_qp_minus26");
+        writer.writeSE(pic_init_qs_minus26, "PPS: pic_init_qs_minus26");
+        writer.writeSE(chroma_qp_index_offset, "PPS: chroma_qp_index_offset");
+        writer.writeBool(deblocking_filter_control_present_flag,
+                "PPS: deblocking_filter_control_present_flag");
+        writer.writeBool(constrained_intra_pred_flag,
+                "PPS: constrained_intra_pred_flag");
+        writer.writeBool(redundant_pic_cnt_present_flag,
+                "PPS: redundant_pic_cnt_present_flag");
+        if (extended != null) {
+            writer.writeBool(extended.transform_8x8_mode_flag,
+                    "PPS: transform_8x8_mode_flag");
+            writer.writeBool(extended.scalindMatrix != null,
+                    "PPS: scalindMatrix");
+            if (extended.scalindMatrix != null) {
+                for (int i = 0; i < 6 + 2 * (extended.transform_8x8_mode_flag ? 1
+                        : 0); i++) {
+                    if (i < 6) {
+                        writer
+                                .writeBool(
+                                        extended.scalindMatrix.ScalingList4x4[i] != null,
+                                        "PPS: ");
+                        if (extended.scalindMatrix.ScalingList4x4[i] != null) {
+                            extended.scalindMatrix.ScalingList4x4[i]
+                                    .write(writer);
+                        }
+
+                    } else {
+                        writer
+                                .writeBool(
+                                        extended.scalindMatrix.ScalingList8x8[i - 6] != null,
+                                        "PPS: ");
+                        if (extended.scalindMatrix.ScalingList8x8[i - 6] != null) {
+                            extended.scalindMatrix.ScalingList8x8[i - 6]
+                                    .write(writer);
+                        }
+                    }
+                }
+            }
+            writer.writeSE(extended.second_chroma_qp_index_offset, "PPS: ");
+        }
+
+        writer.writeTrailingBits();
+    }
+
+    @Override
+    public int hashCode() {
+        final int prime = 31;
+        int result = 1;
+        result = prime * result + Arrays.hashCode(bottom_right);
+        result = prime * result + chroma_qp_index_offset;
+        result = prime * result + (constrained_intra_pred_flag ? 1231 : 1237);
+        result = prime * result
+                + (deblocking_filter_control_present_flag ? 1231 : 1237);
+        result = prime * result + (entropy_coding_mode_flag ? 1231 : 1237);
+        result = prime * result
+                + ((extended == null) ? 0 : extended.hashCode());
+        result = prime * result + num_ref_idx_l0_active_minus1;
+        result = prime * result + num_ref_idx_l1_active_minus1;
+        result = prime * result + num_slice_groups_minus1;
+        result = prime * result + pic_init_qp_minus26;
+        result = prime * result + pic_init_qs_minus26;
+        result = prime * result + (pic_order_present_flag ? 1231 : 1237);
+        result = prime * result + pic_parameter_set_id;
+        result = prime * result
+                + (redundant_pic_cnt_present_flag ? 1231 : 1237);
+        result = prime * result + Arrays.hashCode(run_length_minus1);
+        result = prime * result + seq_parameter_set_id;
+        result = prime * result
+                + (slice_group_change_direction_flag ? 1231 : 1237);
+        result = prime * result + slice_group_change_rate_minus1;
+        result = prime * result + Arrays.hashCode(slice_group_id);
+        result = prime * result + slice_group_map_type;
+        result = prime * result + Arrays.hashCode(top_left);
+        result = prime * result + weighted_bipred_idc;
+        result = prime * result + (weighted_pred_flag ? 1231 : 1237);
+        return result;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj)
+            return true;
+        if (obj == null)
+            return false;
+        if (getClass() != obj.getClass())
+            return false;
+        PictureParameterSet other = (PictureParameterSet) obj;
+        if (!Arrays.equals(bottom_right, other.bottom_right))
+            return false;
+        if (chroma_qp_index_offset != other.chroma_qp_index_offset)
+            return false;
+        if (constrained_intra_pred_flag != other.constrained_intra_pred_flag)
+            return false;
+        if (deblocking_filter_control_present_flag != other.deblocking_filter_control_present_flag)
+            return false;
+        if (entropy_coding_mode_flag != other.entropy_coding_mode_flag)
+            return false;
+        if (extended == null) {
+            if (other.extended != null)
+                return false;
+        } else if (!extended.equals(other.extended))
+            return false;
+        if (num_ref_idx_l0_active_minus1 != other.num_ref_idx_l0_active_minus1)
+            return false;
+        if (num_ref_idx_l1_active_minus1 != other.num_ref_idx_l1_active_minus1)
+            return false;
+        if (num_slice_groups_minus1 != other.num_slice_groups_minus1)
+            return false;
+        if (pic_init_qp_minus26 != other.pic_init_qp_minus26)
+            return false;
+        if (pic_init_qs_minus26 != other.pic_init_qs_minus26)
+            return false;
+        if (pic_order_present_flag != other.pic_order_present_flag)
+            return false;
+        if (pic_parameter_set_id != other.pic_parameter_set_id)
+            return false;
+        if (redundant_pic_cnt_present_flag != other.redundant_pic_cnt_present_flag)
+            return false;
+        if (!Arrays.equals(run_length_minus1, other.run_length_minus1))
+            return false;
+        if (seq_parameter_set_id != other.seq_parameter_set_id)
+            return false;
+        if (slice_group_change_direction_flag != other.slice_group_change_direction_flag)
+            return false;
+        if (slice_group_change_rate_minus1 != other.slice_group_change_rate_minus1)
+            return false;
+        if (!Arrays.equals(slice_group_id, other.slice_group_id))
+            return false;
+        if (slice_group_map_type != other.slice_group_map_type)
+            return false;
+        if (!Arrays.equals(top_left, other.top_left))
+            return false;
+        if (weighted_bipred_idc != other.weighted_bipred_idc)
+            return false;
+        if (weighted_pred_flag != other.weighted_pred_flag)
+            return false;
+        return true;
+    }
+
+    @Override
+    public String toString() {
+        return "PictureParameterSet{" +
+                "\n       entropy_coding_mode_flag=" + entropy_coding_mode_flag +
+                ",\n       num_ref_idx_l0_active_minus1=" + num_ref_idx_l0_active_minus1 +
+                ",\n       num_ref_idx_l1_active_minus1=" + num_ref_idx_l1_active_minus1 +
+                ",\n       slice_group_change_rate_minus1=" + slice_group_change_rate_minus1 +
+                ",\n       pic_parameter_set_id=" + pic_parameter_set_id +
+                ",\n       seq_parameter_set_id=" + seq_parameter_set_id +
+                ",\n       pic_order_present_flag=" + pic_order_present_flag +
+                ",\n       num_slice_groups_minus1=" + num_slice_groups_minus1 +
+                ",\n       slice_group_map_type=" + slice_group_map_type +
+                ",\n       weighted_pred_flag=" + weighted_pred_flag +
+                ",\n       weighted_bipred_idc=" + weighted_bipred_idc +
+                ",\n       pic_init_qp_minus26=" + pic_init_qp_minus26 +
+                ",\n       pic_init_qs_minus26=" + pic_init_qs_minus26 +
+                ",\n       chroma_qp_index_offset=" + chroma_qp_index_offset +
+                ",\n       deblocking_filter_control_present_flag=" + deblocking_filter_control_present_flag +
+                ",\n       constrained_intra_pred_flag=" + constrained_intra_pred_flag +
+                ",\n       redundant_pic_cnt_present_flag=" + redundant_pic_cnt_present_flag +
+                ",\n       top_left=" + top_left +
+                ",\n       bottom_right=" + bottom_right +
+                ",\n       run_length_minus1=" + run_length_minus1 +
+                ",\n       slice_group_change_direction_flag=" + slice_group_change_direction_flag +
+                ",\n       slice_group_id=" + slice_group_id +
+                ",\n       extended=" + extended +
+                '}';
+    }
+}
diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/h264/model/.svn/text-base/ScalingList.java.svn-base b/isoparser/src/main/java/com/googlecode/mp4parser/h264/model/.svn/text-base/ScalingList.java.svn-base
new file mode 100644
index 0000000..5d272bf
--- /dev/null
+++ b/isoparser/src/main/java/com/googlecode/mp4parser/h264/model/.svn/text-base/ScalingList.java.svn-base
@@ -0,0 +1,83 @@
+/*
+Copyright (c) 2011 Stanislav Vitvitskiy
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of this
+software and associated documentation files (the "Software"), to deal in the Software
+without restriction, including without limitation the rights to use, copy, modify,
+merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to the following
+conditions:
+
+The above copyright notice and this permission notice shall be included in all copies or
+substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
+INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
+FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
+OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+package com.googlecode.mp4parser.h264.model;
+
+import com.googlecode.mp4parser.h264.read.CAVLCReader;
+import com.googlecode.mp4parser.h264.write.CAVLCWriter;
+
+import java.io.IOException;
+
+/**
+ * Scaling list entity
+ * <p/>
+ * capable to serialize / deserialize with CAVLC bitstream
+ *
+ * @author Stanislav Vitvitskiy
+ */
+public class ScalingList {
+
+    public int[] scalingList;
+    public boolean useDefaultScalingMatrixFlag;
+
+    public void write(CAVLCWriter out) throws IOException {
+        if (useDefaultScalingMatrixFlag) {
+            out.writeSE(0, "SPS: ");
+            return;
+        }
+
+        int lastScale = 8;
+        int nextScale = 8;
+        for (int j = 0; j < scalingList.length; j++) {
+            if (nextScale != 0) {
+                int deltaScale = scalingList[j] - lastScale - 256;
+                out.writeSE(deltaScale, "SPS: ");
+            }
+            lastScale = scalingList[j];
+        }
+    }
+
+    public static ScalingList read(CAVLCReader is, int sizeOfScalingList)
+            throws IOException {
+
+        ScalingList sl = new ScalingList();
+        sl.scalingList = new int[sizeOfScalingList];
+        int lastScale = 8;
+        int nextScale = 8;
+        for (int j = 0; j < sizeOfScalingList; j++) {
+            if (nextScale != 0) {
+                int deltaScale = is.readSE("deltaScale");
+                nextScale = (lastScale + deltaScale + 256) % 256;
+                sl.useDefaultScalingMatrixFlag = (j == 0 && nextScale == 0);
+            }
+            sl.scalingList[j] = nextScale == 0 ? lastScale : nextScale;
+            lastScale = sl.scalingList[j];
+        }
+        return sl;
+    }
+
+    @Override
+    public String toString() {
+        return "ScalingList{" +
+                "scalingList=" + scalingList +
+                ", useDefaultScalingMatrixFlag=" + useDefaultScalingMatrixFlag +
+                '}';
+    }
+}
\ No newline at end of file
diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/h264/model/.svn/text-base/ScalingMatrix.java.svn-base b/isoparser/src/main/java/com/googlecode/mp4parser/h264/model/.svn/text-base/ScalingMatrix.java.svn-base
new file mode 100644
index 0000000..d04af8e
--- /dev/null
+++ b/isoparser/src/main/java/com/googlecode/mp4parser/h264/model/.svn/text-base/ScalingMatrix.java.svn-base
@@ -0,0 +1,37 @@
+/*
+Copyright (c) 2011 Stanislav Vitvitskiy
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of this
+software and associated documentation files (the "Software"), to deal in the Software
+without restriction, including without limitation the rights to use, copy, modify,
+merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to the following
+conditions:
+
+The above copyright notice and this permission notice shall be included in all copies or
+substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
+INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
+FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
+OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+package com.googlecode.mp4parser.h264.model;
+
+import java.util.Arrays;
+
+public class ScalingMatrix {
+
+    public ScalingList[] ScalingList4x4;
+    public ScalingList[] ScalingList8x8;
+
+    @Override
+    public String toString() {
+        return "ScalingMatrix{" +
+                "ScalingList4x4=" + (ScalingList4x4 == null ? null : Arrays.asList(ScalingList4x4)) + "\n" +
+                ", ScalingList8x8=" + (ScalingList8x8 == null ? null : Arrays.asList(ScalingList8x8)) + "\n" +
+                '}';
+    }
+}
\ No newline at end of file
diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/h264/model/.svn/text-base/SeqParameterSet.java.svn-base b/isoparser/src/main/java/com/googlecode/mp4parser/h264/model/.svn/text-base/SeqParameterSet.java.svn-base
new file mode 100644
index 0000000..4894df8
--- /dev/null
+++ b/isoparser/src/main/java/com/googlecode/mp4parser/h264/model/.svn/text-base/SeqParameterSet.java.svn-base
@@ -0,0 +1,556 @@
+/*
+Copyright (c) 2011 Stanislav Vitvitskiy
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of this
+software and associated documentation files (the "Software"), to deal in the Software
+without restriction, including without limitation the rights to use, copy, modify,
+merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to the following
+conditions:
+
+The above copyright notice and this permission notice shall be included in all copies or
+substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
+INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
+FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
+OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+package com.googlecode.mp4parser.h264.model;
+
+import com.googlecode.mp4parser.h264.read.CAVLCReader;
+import com.googlecode.mp4parser.h264.write.CAVLCWriter;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+/**
+ * Sequence Parameter Set structure of h264 bitstream
+ * <p/>
+ * capable to serialize and deserialize with CAVLC bitstream
+ *
+ * @author Stanislav Vitvitskiy
+ */
+public class SeqParameterSet extends BitstreamElement {
+    public int pic_order_cnt_type;
+    public boolean field_pic_flag;
+    public boolean delta_pic_order_always_zero_flag;
+    public boolean weighted_pred_flag;
+    public int weighted_bipred_idc;
+    public boolean entropy_coding_mode_flag;
+    public boolean mb_adaptive_frame_field_flag;
+    public boolean direct_8x8_inference_flag;
+    public ChromaFormat chroma_format_idc;
+    public int log2_max_frame_num_minus4;
+    public int log2_max_pic_order_cnt_lsb_minus4;
+    public int pic_height_in_map_units_minus1;
+    public int pic_width_in_mbs_minus1;
+    public int bit_depth_luma_minus8;
+    public int bit_depth_chroma_minus8;
+    public boolean qpprime_y_zero_transform_bypass_flag;
+    public int profile_idc;
+    public boolean constraint_set_0_flag;
+    public boolean constraint_set_1_flag;
+    public boolean constraint_set_2_flag;
+    public boolean constraint_set_3_flag;
+    public int level_idc;
+    public int seq_parameter_set_id;
+    public boolean residual_color_transform_flag;
+    public int offset_for_non_ref_pic;
+    public int offset_for_top_to_bottom_field;
+    public int num_ref_frames;
+    public boolean gaps_in_frame_num_value_allowed_flag;
+    public boolean frame_mbs_only_flag;
+    public boolean frame_cropping_flag;
+    public int frame_crop_left_offset;
+    public int frame_crop_right_offset;
+    public int frame_crop_top_offset;
+    public int frame_crop_bottom_offset;
+    public int[] offsetForRefFrame;
+    public VUIParameters vuiParams;
+    public ScalingMatrix scalingMatrix;
+    public int num_ref_frames_in_pic_order_cnt_cycle;
+
+    public static SeqParameterSet read(InputStream is) throws IOException {
+        CAVLCReader reader = new CAVLCReader(is);
+        SeqParameterSet sps = new SeqParameterSet();
+
+        sps.profile_idc = (int) reader.readNBit(8, "SPS: profile_idc");
+        sps.constraint_set_0_flag = reader
+                .readBool("SPS: constraint_set_0_flag");
+        sps.constraint_set_1_flag = reader
+                .readBool("SPS: constraint_set_1_flag");
+        sps.constraint_set_2_flag = reader
+                .readBool("SPS: constraint_set_2_flag");
+        sps.constraint_set_3_flag = reader
+                .readBool("SPS: constraint_set_3_flag");
+        reader.readNBit(4, "SPS: reserved_zero_4bits");
+        sps.level_idc = (int) reader.readNBit(8, "SPS: level_idc");
+        sps.seq_parameter_set_id = reader.readUE("SPS: seq_parameter_set_id");
+
+        if (sps.profile_idc == 100 || sps.profile_idc == 110
+                || sps.profile_idc == 122 || sps.profile_idc == 144) {
+            sps.chroma_format_idc = ChromaFormat.fromId(reader
+                    .readUE("SPS: chroma_format_idc"));
+            if (sps.chroma_format_idc == ChromaFormat.YUV_444) {
+                sps.residual_color_transform_flag = reader
+                        .readBool("SPS: residual_color_transform_flag");
+            }
+            sps.bit_depth_luma_minus8 = reader
+                    .readUE("SPS: bit_depth_luma_minus8");
+            sps.bit_depth_chroma_minus8 = reader
+                    .readUE("SPS: bit_depth_chroma_minus8");
+            sps.qpprime_y_zero_transform_bypass_flag = reader
+                    .readBool("SPS: qpprime_y_zero_transform_bypass_flag");
+            boolean seqScalingMatrixPresent = reader
+                    .readBool("SPS: seq_scaling_matrix_present_lag");
+            if (seqScalingMatrixPresent) {
+                readScalingListMatrix(reader, sps);
+            }
+        } else {
+            sps.chroma_format_idc = ChromaFormat.YUV_420;
+        }
+        sps.log2_max_frame_num_minus4 = reader
+                .readUE("SPS: log2_max_frame_num_minus4");
+        sps.pic_order_cnt_type = reader.readUE("SPS: pic_order_cnt_type");
+        if (sps.pic_order_cnt_type == 0) {
+            sps.log2_max_pic_order_cnt_lsb_minus4 = reader
+                    .readUE("SPS: log2_max_pic_order_cnt_lsb_minus4");
+        } else if (sps.pic_order_cnt_type == 1) {
+            sps.delta_pic_order_always_zero_flag = reader
+                    .readBool("SPS: delta_pic_order_always_zero_flag");
+            sps.offset_for_non_ref_pic = reader
+                    .readSE("SPS: offset_for_non_ref_pic");
+            sps.offset_for_top_to_bottom_field = reader
+                    .readSE("SPS: offset_for_top_to_bottom_field");
+            sps.num_ref_frames_in_pic_order_cnt_cycle = reader
+                    .readUE("SPS: num_ref_frames_in_pic_order_cnt_cycle");
+            sps.offsetForRefFrame = new int[sps.num_ref_frames_in_pic_order_cnt_cycle];
+            for (int i = 0; i < sps.num_ref_frames_in_pic_order_cnt_cycle; i++) {
+                sps.offsetForRefFrame[i] = reader
+                        .readSE("SPS: offsetForRefFrame [" + i + "]");
+            }
+        }
+        sps.num_ref_frames = reader.readUE("SPS: num_ref_frames");
+        sps.gaps_in_frame_num_value_allowed_flag = reader
+                .readBool("SPS: gaps_in_frame_num_value_allowed_flag");
+        sps.pic_width_in_mbs_minus1 = reader
+                .readUE("SPS: pic_width_in_mbs_minus1");
+        sps.pic_height_in_map_units_minus1 = reader
+                .readUE("SPS: pic_height_in_map_units_minus1");
+        sps.frame_mbs_only_flag = reader.readBool("SPS: frame_mbs_only_flag");
+        if (!sps.frame_mbs_only_flag) {
+            sps.mb_adaptive_frame_field_flag = reader
+                    .readBool("SPS: mb_adaptive_frame_field_flag");
+        }
+        sps.direct_8x8_inference_flag = reader
+                .readBool("SPS: direct_8x8_inference_flag");
+        sps.frame_cropping_flag = reader.readBool("SPS: frame_cropping_flag");
+        if (sps.frame_cropping_flag) {
+            sps.frame_crop_left_offset = reader
+                    .readUE("SPS: frame_crop_left_offset");
+            sps.frame_crop_right_offset = reader
+                    .readUE("SPS: frame_crop_right_offset");
+            sps.frame_crop_top_offset = reader
+                    .readUE("SPS: frame_crop_top_offset");
+            sps.frame_crop_bottom_offset = reader
+                    .readUE("SPS: frame_crop_bottom_offset");
+        }
+        boolean vui_parameters_present_flag = reader
+                .readBool("SPS: vui_parameters_present_flag");
+        if (vui_parameters_present_flag)
+            sps.vuiParams = ReadVUIParameters(reader);
+
+        reader.readTrailingBits();
+
+        return sps;
+    }
+
+    private static void readScalingListMatrix(CAVLCReader reader,
+                                              SeqParameterSet sps) throws IOException {
+        sps.scalingMatrix = new ScalingMatrix();
+        for (int i = 0; i < 8; i++) {
+            boolean seqScalingListPresentFlag = reader
+                    .readBool("SPS: seqScalingListPresentFlag");
+            if (seqScalingListPresentFlag) {
+                sps.scalingMatrix.ScalingList4x4 = new ScalingList[8];
+                sps.scalingMatrix.ScalingList8x8 = new ScalingList[8];
+                if (i < 6) {
+                    sps.scalingMatrix.ScalingList4x4[i] = ScalingList.read(
+                            reader, 16);
+                } else {
+                    sps.scalingMatrix.ScalingList8x8[i - 6] = ScalingList.read(
+                            reader, 64);
+                }
+            }
+        }
+    }
+
+    private static VUIParameters ReadVUIParameters(CAVLCReader reader)
+            throws IOException {
+        VUIParameters vuip = new VUIParameters();
+        vuip.aspect_ratio_info_present_flag = reader
+                .readBool("VUI: aspect_ratio_info_present_flag");
+        if (vuip.aspect_ratio_info_present_flag) {
+            vuip.aspect_ratio = AspectRatio.fromValue((int) reader.readNBit(8,
+                    "VUI: aspect_ratio"));
+            if (vuip.aspect_ratio == AspectRatio.Extended_SAR) {
+                vuip.sar_width = (int) reader.readNBit(16, "VUI: sar_width");
+                vuip.sar_height = (int) reader.readNBit(16, "VUI: sar_height");
+            }
+        }
+        vuip.overscan_info_present_flag = reader
+                .readBool("VUI: overscan_info_present_flag");
+        if (vuip.overscan_info_present_flag) {
+            vuip.overscan_appropriate_flag = reader
+                    .readBool("VUI: overscan_appropriate_flag");
+        }
+        vuip.video_signal_type_present_flag = reader
+                .readBool("VUI: video_signal_type_present_flag");
+        if (vuip.video_signal_type_present_flag) {
+            vuip.video_format = (int) reader.readNBit(3, "VUI: video_format");
+            vuip.video_full_range_flag = reader
+                    .readBool("VUI: video_full_range_flag");
+            vuip.colour_description_present_flag = reader
+                    .readBool("VUI: colour_description_present_flag");
+            if (vuip.colour_description_present_flag) {
+                vuip.colour_primaries = (int) reader.readNBit(8,
+                        "VUI: colour_primaries");
+                vuip.transfer_characteristics = (int) reader.readNBit(8,
+                        "VUI: transfer_characteristics");
+                vuip.matrix_coefficients = (int) reader.readNBit(8,
+                        "VUI: matrix_coefficients");
+            }
+        }
+        vuip.chroma_loc_info_present_flag = reader
+                .readBool("VUI: chroma_loc_info_present_flag");
+        if (vuip.chroma_loc_info_present_flag) {
+            vuip.chroma_sample_loc_type_top_field = reader
+                    .readUE("VUI chroma_sample_loc_type_top_field");
+            vuip.chroma_sample_loc_type_bottom_field = reader
+                    .readUE("VUI chroma_sample_loc_type_bottom_field");
+        }
+        vuip.timing_info_present_flag = reader
+                .readBool("VUI: timing_info_present_flag");
+        if (vuip.timing_info_present_flag) {
+            vuip.num_units_in_tick = (int) reader.readNBit(32,
+                    "VUI: num_units_in_tick");
+            vuip.time_scale = (int) reader.readNBit(32, "VUI: time_scale");
+            vuip.fixed_frame_rate_flag = reader
+                    .readBool("VUI: fixed_frame_rate_flag");
+        }
+        boolean nal_hrd_parameters_present_flag = reader
+                .readBool("VUI: nal_hrd_parameters_present_flag");
+        if (nal_hrd_parameters_present_flag)
+            vuip.nalHRDParams = readHRDParameters(reader);
+        boolean vcl_hrd_parameters_present_flag = reader
+                .readBool("VUI: vcl_hrd_parameters_present_flag");
+        if (vcl_hrd_parameters_present_flag)
+            vuip.vclHRDParams = readHRDParameters(reader);
+        if (nal_hrd_parameters_present_flag || vcl_hrd_parameters_present_flag) {
+            vuip.low_delay_hrd_flag = reader
+                    .readBool("VUI: low_delay_hrd_flag");
+        }
+        vuip.pic_struct_present_flag = reader
+                .readBool("VUI: pic_struct_present_flag");
+        boolean bitstream_restriction_flag = reader
+                .readBool("VUI: bitstream_restriction_flag");
+        if (bitstream_restriction_flag) {
+            vuip.bitstreamRestriction = new VUIParameters.BitstreamRestriction();
+            vuip.bitstreamRestriction.motion_vectors_over_pic_boundaries_flag = reader
+                    .readBool("VUI: motion_vectors_over_pic_boundaries_flag");
+            vuip.bitstreamRestriction.max_bytes_per_pic_denom = reader
+                    .readUE("VUI max_bytes_per_pic_denom");
+            vuip.bitstreamRestriction.max_bits_per_mb_denom = reader
+                    .readUE("VUI max_bits_per_mb_denom");
+            vuip.bitstreamRestriction.log2_max_mv_length_horizontal = reader
+                    .readUE("VUI log2_max_mv_length_horizontal");
+            vuip.bitstreamRestriction.log2_max_mv_length_vertical = reader
+                    .readUE("VUI log2_max_mv_length_vertical");
+            vuip.bitstreamRestriction.num_reorder_frames = reader
+                    .readUE("VUI num_reorder_frames");
+            vuip.bitstreamRestriction.max_dec_frame_buffering = reader
+                    .readUE("VUI max_dec_frame_buffering");
+        }
+
+        return vuip;
+    }
+
+    private static HRDParameters readHRDParameters(CAVLCReader reader)
+            throws IOException {
+        HRDParameters hrd = new HRDParameters();
+        hrd.cpb_cnt_minus1 = reader.readUE("SPS: cpb_cnt_minus1");
+        hrd.bit_rate_scale = (int) reader.readNBit(4, "HRD: bit_rate_scale");
+        hrd.cpb_size_scale = (int) reader.readNBit(4, "HRD: cpb_size_scale");
+        hrd.bit_rate_value_minus1 = new int[hrd.cpb_cnt_minus1 + 1];
+        hrd.cpb_size_value_minus1 = new int[hrd.cpb_cnt_minus1 + 1];
+        hrd.cbr_flag = new boolean[hrd.cpb_cnt_minus1 + 1];
+
+        for (int SchedSelIdx = 0; SchedSelIdx <= hrd.cpb_cnt_minus1; SchedSelIdx++) {
+            hrd.bit_rate_value_minus1[SchedSelIdx] = reader
+                    .readUE("HRD: bit_rate_value_minus1");
+            hrd.cpb_size_value_minus1[SchedSelIdx] = reader
+                    .readUE("HRD: cpb_size_value_minus1");
+            hrd.cbr_flag[SchedSelIdx] = reader.readBool("HRD: cbr_flag");
+        }
+        hrd.initial_cpb_removal_delay_length_minus1 = (int) reader.readNBit(5,
+                "HRD: initial_cpb_removal_delay_length_minus1");
+        hrd.cpb_removal_delay_length_minus1 = (int) reader.readNBit(5,
+                "HRD: cpb_removal_delay_length_minus1");
+        hrd.dpb_output_delay_length_minus1 = (int) reader.readNBit(5,
+                "HRD: dpb_output_delay_length_minus1");
+        hrd.time_offset_length = (int) reader.readNBit(5,
+                "HRD: time_offset_length");
+        return hrd;
+    }
+
+    public void write(OutputStream out) throws IOException {
+        CAVLCWriter writer = new CAVLCWriter(out);
+
+        writer.writeNBit(profile_idc, 8, "SPS: profile_idc");
+        writer.writeBool(constraint_set_0_flag, "SPS: constraint_set_0_flag");
+        writer.writeBool(constraint_set_1_flag, "SPS: constraint_set_1_flag");
+        writer.writeBool(constraint_set_2_flag, "SPS: constraint_set_2_flag");
+        writer.writeBool(constraint_set_3_flag, "SPS: constraint_set_3_flag");
+        writer.writeNBit(0, 4, "SPS: reserved");
+        writer.writeNBit(level_idc, 8, "SPS: level_idc");
+        writer.writeUE(seq_parameter_set_id, "SPS: seq_parameter_set_id");
+
+        if (profile_idc == 100 || profile_idc == 110 || profile_idc == 122
+                || profile_idc == 144) {
+            writer.writeUE(chroma_format_idc.getId(), "SPS: chroma_format_idc");
+            if (chroma_format_idc == ChromaFormat.YUV_444) {
+                writer.writeBool(residual_color_transform_flag,
+                        "SPS: residual_color_transform_flag");
+            }
+            writer.writeUE(bit_depth_luma_minus8, "SPS: ");
+            writer.writeUE(bit_depth_chroma_minus8, "SPS: ");
+            writer.writeBool(qpprime_y_zero_transform_bypass_flag,
+                    "SPS: qpprime_y_zero_transform_bypass_flag");
+            writer.writeBool(scalingMatrix != null, "SPS: ");
+            if (scalingMatrix != null) {
+                for (int i = 0; i < 8; i++) {
+                    if (i < 6) {
+                        writer.writeBool(
+                                scalingMatrix.ScalingList4x4[i] != null,
+                                "SPS: ");
+                        if (scalingMatrix.ScalingList4x4[i] != null) {
+                            scalingMatrix.ScalingList4x4[i].write(writer);
+                        }
+                    } else {
+                        writer.writeBool(
+                                scalingMatrix.ScalingList8x8[i - 6] != null,
+                                "SPS: ");
+                        if (scalingMatrix.ScalingList8x8[i - 6] != null) {
+                            scalingMatrix.ScalingList8x8[i - 6].write(writer);
+                        }
+                    }
+                }
+            }
+        }
+        writer.writeUE(log2_max_frame_num_minus4,
+                "SPS: log2_max_frame_num_minus4");
+        writer.writeUE(pic_order_cnt_type, "SPS: pic_order_cnt_type");
+        if (pic_order_cnt_type == 0) {
+            writer.writeUE(log2_max_pic_order_cnt_lsb_minus4,
+                    "SPS: log2_max_pic_order_cnt_lsb_minus4");
+        } else if (pic_order_cnt_type == 1) {
+            writer.writeBool(delta_pic_order_always_zero_flag,
+                    "SPS: delta_pic_order_always_zero_flag");
+            writer.writeSE(offset_for_non_ref_pic,
+                    "SPS: offset_for_non_ref_pic");
+            writer.writeSE(offset_for_top_to_bottom_field,
+                    "SPS: offset_for_top_to_bottom_field");
+            writer.writeUE(offsetForRefFrame.length, "SPS: ");
+            for (int i = 0; i < offsetForRefFrame.length; i++)
+                writer.writeSE(offsetForRefFrame[i], "SPS: ");
+        }
+        writer.writeUE(num_ref_frames, "SPS: num_ref_frames");
+        writer.writeBool(gaps_in_frame_num_value_allowed_flag,
+                "SPS: gaps_in_frame_num_value_allowed_flag");
+        writer.writeUE(pic_width_in_mbs_minus1, "SPS: pic_width_in_mbs_minus1");
+        writer.writeUE(pic_height_in_map_units_minus1,
+                "SPS: pic_height_in_map_units_minus1");
+        writer.writeBool(frame_mbs_only_flag, "SPS: frame_mbs_only_flag");
+        if (!frame_mbs_only_flag) {
+            writer.writeBool(mb_adaptive_frame_field_flag,
+                    "SPS: mb_adaptive_frame_field_flag");
+        }
+        writer.writeBool(direct_8x8_inference_flag,
+                "SPS: direct_8x8_inference_flag");
+        writer.writeBool(frame_cropping_flag, "SPS: frame_cropping_flag");
+        if (frame_cropping_flag) {
+            writer.writeUE(frame_crop_left_offset,
+                    "SPS: frame_crop_left_offset");
+            writer.writeUE(frame_crop_right_offset,
+                    "SPS: frame_crop_right_offset");
+            writer.writeUE(frame_crop_top_offset, "SPS: frame_crop_top_offset");
+            writer.writeUE(frame_crop_bottom_offset,
+                    "SPS: frame_crop_bottom_offset");
+        }
+        writer.writeBool(vuiParams != null, "SPS: ");
+        if (vuiParams != null)
+            writeVUIParameters(vuiParams, writer);
+
+        writer.writeTrailingBits();
+    }
+
+    private void writeVUIParameters(VUIParameters vuip, CAVLCWriter writer)
+            throws IOException {
+        writer.writeBool(vuip.aspect_ratio_info_present_flag,
+                "VUI: aspect_ratio_info_present_flag");
+        if (vuip.aspect_ratio_info_present_flag) {
+            writer.writeNBit(vuip.aspect_ratio.getValue(), 8,
+                    "VUI: aspect_ratio");
+            if (vuip.aspect_ratio == AspectRatio.Extended_SAR) {
+                writer.writeNBit(vuip.sar_width, 16, "VUI: sar_width");
+                writer.writeNBit(vuip.sar_height, 16, "VUI: sar_height");
+            }
+        }
+        writer.writeBool(vuip.overscan_info_present_flag,
+                "VUI: overscan_info_present_flag");
+        if (vuip.overscan_info_present_flag) {
+            writer.writeBool(vuip.overscan_appropriate_flag,
+                    "VUI: overscan_appropriate_flag");
+        }
+        writer.writeBool(vuip.video_signal_type_present_flag,
+                "VUI: video_signal_type_present_flag");
+        if (vuip.video_signal_type_present_flag) {
+            writer.writeNBit(vuip.video_format, 3, "VUI: video_format");
+            writer.writeBool(vuip.video_full_range_flag,
+                    "VUI: video_full_range_flag");
+            writer.writeBool(vuip.colour_description_present_flag,
+                    "VUI: colour_description_present_flag");
+            if (vuip.colour_description_present_flag) {
+                writer.writeNBit(vuip.colour_primaries, 8,
+                        "VUI: colour_primaries");
+                writer.writeNBit(vuip.transfer_characteristics, 8,
+                        "VUI: transfer_characteristics");
+                writer.writeNBit(vuip.matrix_coefficients, 8,
+                        "VUI: matrix_coefficients");
+            }
+        }
+        writer.writeBool(vuip.chroma_loc_info_present_flag,
+                "VUI: chroma_loc_info_present_flag");
+        if (vuip.chroma_loc_info_present_flag) {
+            writer.writeUE(vuip.chroma_sample_loc_type_top_field,
+                    "VUI: chroma_sample_loc_type_top_field");
+            writer.writeUE(vuip.chroma_sample_loc_type_bottom_field,
+                    "VUI: chroma_sample_loc_type_bottom_field");
+        }
+        writer.writeBool(vuip.timing_info_present_flag,
+                "VUI: timing_info_present_flag");
+        if (vuip.timing_info_present_flag) {
+            writer.writeNBit(vuip.num_units_in_tick, 32,
+                    "VUI: num_units_in_tick");
+            writer.writeNBit(vuip.time_scale, 32, "VUI: time_scale");
+            writer.writeBool(vuip.fixed_frame_rate_flag,
+                    "VUI: fixed_frame_rate_flag");
+        }
+        writer.writeBool(vuip.nalHRDParams != null, "VUI: ");
+        if (vuip.nalHRDParams != null) {
+            writeHRDParameters(vuip.nalHRDParams, writer);
+        }
+        writer.writeBool(vuip.vclHRDParams != null, "VUI: ");
+        if (vuip.vclHRDParams != null) {
+            writeHRDParameters(vuip.vclHRDParams, writer);
+        }
+
+        if (vuip.nalHRDParams != null || vuip.vclHRDParams != null) {
+            writer
+                    .writeBool(vuip.low_delay_hrd_flag,
+                            "VUI: low_delay_hrd_flag");
+        }
+        writer.writeBool(vuip.pic_struct_present_flag,
+                "VUI: pic_struct_present_flag");
+        writer.writeBool(vuip.bitstreamRestriction != null, "VUI: ");
+        if (vuip.bitstreamRestriction != null) {
+            writer
+                    .writeBool(
+                            vuip.bitstreamRestriction.motion_vectors_over_pic_boundaries_flag,
+                            "VUI: motion_vectors_over_pic_boundaries_flag");
+            writer.writeUE(vuip.bitstreamRestriction.max_bytes_per_pic_denom,
+                    "VUI: max_bytes_per_pic_denom");
+            writer.writeUE(vuip.bitstreamRestriction.max_bits_per_mb_denom,
+                    "VUI: max_bits_per_mb_denom");
+            writer.writeUE(
+                    vuip.bitstreamRestriction.log2_max_mv_length_horizontal,
+                    "VUI: log2_max_mv_length_horizontal");
+            writer.writeUE(
+                    vuip.bitstreamRestriction.log2_max_mv_length_vertical,
+                    "VUI: log2_max_mv_length_vertical");
+            writer.writeUE(vuip.bitstreamRestriction.num_reorder_frames,
+                    "VUI: num_reorder_frames");
+            writer.writeUE(vuip.bitstreamRestriction.max_dec_frame_buffering,
+                    "VUI: max_dec_frame_buffering");
+        }
+
+    }
+
+    private void writeHRDParameters(HRDParameters hrd, CAVLCWriter writer)
+            throws IOException {
+        writer.writeUE(hrd.cpb_cnt_minus1, "HRD: cpb_cnt_minus1");
+        writer.writeNBit(hrd.bit_rate_scale, 4, "HRD: bit_rate_scale");
+        writer.writeNBit(hrd.cpb_size_scale, 4, "HRD: cpb_size_scale");
+
+        for (int SchedSelIdx = 0; SchedSelIdx <= hrd.cpb_cnt_minus1; SchedSelIdx++) {
+            writer.writeUE(hrd.bit_rate_value_minus1[SchedSelIdx], "HRD: ");
+            writer.writeUE(hrd.cpb_size_value_minus1[SchedSelIdx], "HRD: ");
+            writer.writeBool(hrd.cbr_flag[SchedSelIdx], "HRD: ");
+        }
+        writer.writeNBit(hrd.initial_cpb_removal_delay_length_minus1, 5,
+                "HRD: initial_cpb_removal_delay_length_minus1");
+        writer.writeNBit(hrd.cpb_removal_delay_length_minus1, 5,
+                "HRD: cpb_removal_delay_length_minus1");
+        writer.writeNBit(hrd.dpb_output_delay_length_minus1, 5,
+                "HRD: dpb_output_delay_length_minus1");
+        writer.writeNBit(hrd.time_offset_length, 5, "HRD: time_offset_length");
+    }
+
+    @Override
+    public String toString() {
+        return "SeqParameterSet{ " +
+                "\n        pic_order_cnt_type=" + pic_order_cnt_type +
+                ", \n        field_pic_flag=" + field_pic_flag +
+                ", \n        delta_pic_order_always_zero_flag=" + delta_pic_order_always_zero_flag +
+                ", \n        weighted_pred_flag=" + weighted_pred_flag +
+                ", \n        weighted_bipred_idc=" + weighted_bipred_idc +
+                ", \n        entropy_coding_mode_flag=" + entropy_coding_mode_flag +
+                ", \n        mb_adaptive_frame_field_flag=" + mb_adaptive_frame_field_flag +
+                ", \n        direct_8x8_inference_flag=" + direct_8x8_inference_flag +
+                ", \n        chroma_format_idc=" + chroma_format_idc +
+                ", \n        log2_max_frame_num_minus4=" + log2_max_frame_num_minus4 +
+                ", \n        log2_max_pic_order_cnt_lsb_minus4=" + log2_max_pic_order_cnt_lsb_minus4 +
+                ", \n        pic_height_in_map_units_minus1=" + pic_height_in_map_units_minus1 +
+                ", \n        pic_width_in_mbs_minus1=" + pic_width_in_mbs_minus1 +
+                ", \n        bit_depth_luma_minus8=" + bit_depth_luma_minus8 +
+                ", \n        bit_depth_chroma_minus8=" + bit_depth_chroma_minus8 +
+                ", \n        qpprime_y_zero_transform_bypass_flag=" + qpprime_y_zero_transform_bypass_flag +
+                ", \n        profile_idc=" + profile_idc +
+                ", \n        constraint_set_0_flag=" + constraint_set_0_flag +
+                ", \n        constraint_set_1_flag=" + constraint_set_1_flag +
+                ", \n        constraint_set_2_flag=" + constraint_set_2_flag +
+                ", \n        constraint_set_3_flag=" + constraint_set_3_flag +
+                ", \n        level_idc=" + level_idc +
+                ", \n        seq_parameter_set_id=" + seq_parameter_set_id +
+                ", \n        residual_color_transform_flag=" + residual_color_transform_flag +
+                ", \n        offset_for_non_ref_pic=" + offset_for_non_ref_pic +
+                ", \n        offset_for_top_to_bottom_field=" + offset_for_top_to_bottom_field +
+                ", \n        num_ref_frames=" + num_ref_frames +
+                ", \n        gaps_in_frame_num_value_allowed_flag=" + gaps_in_frame_num_value_allowed_flag +
+                ", \n        frame_mbs_only_flag=" + frame_mbs_only_flag +
+                ", \n        frame_cropping_flag=" + frame_cropping_flag +
+                ", \n        frame_crop_left_offset=" + frame_crop_left_offset +
+                ", \n        frame_crop_right_offset=" + frame_crop_right_offset +
+                ", \n        frame_crop_top_offset=" + frame_crop_top_offset +
+                ", \n        frame_crop_bottom_offset=" + frame_crop_bottom_offset +
+                ", \n        offsetForRefFrame=" + offsetForRefFrame +
+                ", \n        vuiParams=" + vuiParams +
+                ", \n        scalingMatrix=" + scalingMatrix +
+                ", \n        num_ref_frames_in_pic_order_cnt_cycle=" + num_ref_frames_in_pic_order_cnt_cycle +
+                '}';
+    }
+}
\ No newline at end of file
diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/h264/model/.svn/text-base/VUIParameters.java.svn-base b/isoparser/src/main/java/com/googlecode/mp4parser/h264/model/.svn/text-base/VUIParameters.java.svn-base
new file mode 100644
index 0000000..eec7880
--- /dev/null
+++ b/isoparser/src/main/java/com/googlecode/mp4parser/h264/model/.svn/text-base/VUIParameters.java.svn-base
@@ -0,0 +1,94 @@
+/*
+Copyright (c) 2011 Stanislav Vitvitskiy
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of this
+software and associated documentation files (the "Software"), to deal in the Software
+without restriction, including without limitation the rights to use, copy, modify,
+merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to the following
+conditions:
+
+The above copyright notice and this permission notice shall be included in all copies or
+substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
+INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
+FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
+OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+package com.googlecode.mp4parser.h264.model;
+
+public class VUIParameters {
+
+    public static class BitstreamRestriction {
+
+        public boolean motion_vectors_over_pic_boundaries_flag;
+        public int max_bytes_per_pic_denom;
+        public int max_bits_per_mb_denom;
+        public int log2_max_mv_length_horizontal;
+        public int log2_max_mv_length_vertical;
+        public int num_reorder_frames;
+        public int max_dec_frame_buffering;
+
+    }
+
+    public boolean aspect_ratio_info_present_flag;
+    public int sar_width;
+    public int sar_height;
+    public boolean overscan_info_present_flag;
+    public boolean overscan_appropriate_flag;
+    public boolean video_signal_type_present_flag;
+    public int video_format;
+    public boolean video_full_range_flag;
+    public boolean colour_description_present_flag;
+    public int colour_primaries;
+    public int transfer_characteristics;
+    public int matrix_coefficients;
+    public boolean chroma_loc_info_present_flag;
+    public int chroma_sample_loc_type_top_field;
+    public int chroma_sample_loc_type_bottom_field;
+    public boolean timing_info_present_flag;
+    public int num_units_in_tick;
+    public int time_scale;
+    public boolean fixed_frame_rate_flag;
+    public boolean low_delay_hrd_flag;
+    public boolean pic_struct_present_flag;
+    public HRDParameters nalHRDParams;
+    public HRDParameters vclHRDParams;
+
+    public BitstreamRestriction bitstreamRestriction;
+    public AspectRatio aspect_ratio;
+
+    @Override
+    public String toString() {
+        return "VUIParameters{" + "\n" +
+                "aspect_ratio_info_present_flag=" + aspect_ratio_info_present_flag + "\n" +
+                ", sar_width=" + sar_width + "\n" +
+                ", sar_height=" + sar_height + "\n" +
+                ", overscan_info_present_flag=" + overscan_info_present_flag + "\n" +
+                ", overscan_appropriate_flag=" + overscan_appropriate_flag + "\n" +
+                ", video_signal_type_present_flag=" + video_signal_type_present_flag + "\n" +
+                ", video_format=" + video_format + "\n" +
+                ", video_full_range_flag=" + video_full_range_flag + "\n" +
+                ", colour_description_present_flag=" + colour_description_present_flag + "\n" +
+                ", colour_primaries=" + colour_primaries + "\n" +
+                ", transfer_characteristics=" + transfer_characteristics + "\n" +
+                ", matrix_coefficients=" + matrix_coefficients + "\n" +
+                ", chroma_loc_info_present_flag=" + chroma_loc_info_present_flag + "\n" +
+                ", chroma_sample_loc_type_top_field=" + chroma_sample_loc_type_top_field + "\n" +
+                ", chroma_sample_loc_type_bottom_field=" + chroma_sample_loc_type_bottom_field + "\n" +
+                ", timing_info_present_flag=" + timing_info_present_flag + "\n" +
+                ", num_units_in_tick=" + num_units_in_tick + "\n" +
+                ", time_scale=" + time_scale + "\n" +
+                ", fixed_frame_rate_flag=" + fixed_frame_rate_flag + "\n" +
+                ", low_delay_hrd_flag=" + low_delay_hrd_flag + "\n" +
+                ", pic_struct_present_flag=" + pic_struct_present_flag + "\n" +
+                ", nalHRDParams=" + nalHRDParams + "\n" +
+                ", vclHRDParams=" + vclHRDParams + "\n" +
+                ", bitstreamRestriction=" + bitstreamRestriction + "\n" +
+                ", aspect_ratio=" + aspect_ratio + "\n" +
+                '}';
+    }
+}
diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/h264/model/AspectRatio.java b/isoparser/src/main/java/com/googlecode/mp4parser/h264/model/AspectRatio.java
new file mode 100644
index 0000000..bc66b1a
--- /dev/null
+++ b/isoparser/src/main/java/com/googlecode/mp4parser/h264/model/AspectRatio.java
@@ -0,0 +1,50 @@
+/*
+Copyright (c) 2011 Stanislav Vitvitskiy
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of this
+software and associated documentation files (the "Software"), to deal in the Software
+without restriction, including without limitation the rights to use, copy, modify,
+merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to the following
+conditions:
+
+The above copyright notice and this permission notice shall be included in all copies or
+substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
+INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
+FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
+OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+package com.googlecode.mp4parser.h264.model;
+
+/**
+ * Aspect ratio
+ * <p/>
+ * dynamic enum
+ *
+ * @author Stanislav Vitvitskiy
+ */
+public class AspectRatio {
+
+    public static final AspectRatio Extended_SAR = new AspectRatio(255);
+
+    private int value;
+
+    private AspectRatio(int value) {
+        this.value = value;
+    }
+
+    public static AspectRatio fromValue(int value) {
+        if (value == Extended_SAR.value) {
+            return Extended_SAR;
+        }
+        return new AspectRatio(value);
+    }
+
+    public int getValue() {
+        return value;
+    }
+}
diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/h264/model/BitstreamElement.java b/isoparser/src/main/java/com/googlecode/mp4parser/h264/model/BitstreamElement.java
new file mode 100644
index 0000000..f16c5e9
--- /dev/null
+++ b/isoparser/src/main/java/com/googlecode/mp4parser/h264/model/BitstreamElement.java
@@ -0,0 +1,29 @@
+/*
+Copyright (c) 2011 Stanislav Vitvitskiy
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of this
+software and associated documentation files (the "Software"), to deal in the Software
+without restriction, including without limitation the rights to use, copy, modify,
+merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to the following
+conditions:
+
+The above copyright notice and this permission notice shall be included in all copies or
+substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
+INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
+FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
+OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+package com.googlecode.mp4parser.h264.model;
+
+import java.io.IOException;
+import java.io.OutputStream;
+
+public abstract class BitstreamElement {
+
+    public abstract void write(OutputStream out) throws IOException;
+}
diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/h264/model/ChromaFormat.java b/isoparser/src/main/java/com/googlecode/mp4parser/h264/model/ChromaFormat.java
new file mode 100644
index 0000000..2af2966
--- /dev/null
+++ b/isoparser/src/main/java/com/googlecode/mp4parser/h264/model/ChromaFormat.java
@@ -0,0 +1,77 @@
+/*
+Copyright (c) 2011 Stanislav Vitvitskiy
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of this
+software and associated documentation files (the "Software"), to deal in the Software
+without restriction, including without limitation the rights to use, copy, modify,
+merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to the following
+conditions:
+
+The above copyright notice and this permission notice shall be included in all copies or
+substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
+INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
+FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
+OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+package com.googlecode.mp4parser.h264.model;
+
+/**
+ * Chroma format enum
+ *
+ * @author Stanislav Vitvitskiy
+ */
+public class ChromaFormat {
+    public static ChromaFormat MONOCHROME = new ChromaFormat(0, 0, 0);
+    public static ChromaFormat YUV_420 = new ChromaFormat(1, 2, 2);
+    public static ChromaFormat YUV_422 = new ChromaFormat(2, 2, 1);
+    public static ChromaFormat YUV_444 = new ChromaFormat(3, 1, 1);
+
+    private int id;
+    private int subWidth;
+    private int subHeight;
+
+    public ChromaFormat(int id, int subWidth, int subHeight) {
+        this.id = id;
+        this.subWidth = subWidth;
+        this.subHeight = subHeight;
+    }
+
+    public static ChromaFormat fromId(int id) {
+        if (id == MONOCHROME.id) {
+            return MONOCHROME;
+        } else if (id == YUV_420.id) {
+            return YUV_420;
+        } else if (id == YUV_422.id) {
+            return YUV_422;
+        } else if (id == YUV_444.id) {
+            return YUV_444;
+        }
+        return null;
+    }
+
+    public int getId() {
+        return id;
+    }
+
+    public int getSubWidth() {
+        return subWidth;
+    }
+
+    public int getSubHeight() {
+        return subHeight;
+    }
+
+    @Override
+    public String toString() {
+        return "ChromaFormat{" + "\n" +
+                "id=" + id + ",\n" +
+                " subWidth=" + subWidth + ",\n" +
+                " subHeight=" + subHeight +
+                '}';
+    }
+}
diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/h264/model/HRDParameters.java b/isoparser/src/main/java/com/googlecode/mp4parser/h264/model/HRDParameters.java
new file mode 100644
index 0000000..f713ab2
--- /dev/null
+++ b/isoparser/src/main/java/com/googlecode/mp4parser/h264/model/HRDParameters.java
@@ -0,0 +1,53 @@
+/*
+Copyright (c) 2011 Stanislav Vitvitskiy
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of this
+software and associated documentation files (the "Software"), to deal in the Software
+without restriction, including without limitation the rights to use, copy, modify,
+merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to the following
+conditions:
+
+The above copyright notice and this permission notice shall be included in all copies or
+substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
+INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
+FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
+OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+package com.googlecode.mp4parser.h264.model;
+
+import java.util.Arrays;
+
+public class HRDParameters {
+
+    public int cpb_cnt_minus1;
+    public int bit_rate_scale;
+    public int cpb_size_scale;
+    public int[] bit_rate_value_minus1;
+    public int[] cpb_size_value_minus1;
+    public boolean[] cbr_flag;
+    public int initial_cpb_removal_delay_length_minus1;
+    public int cpb_removal_delay_length_minus1;
+    public int dpb_output_delay_length_minus1;
+    public int time_offset_length;
+
+    @Override
+    public String toString() {
+        return "HRDParameters{" +
+                "cpb_cnt_minus1=" + cpb_cnt_minus1 +
+                ", bit_rate_scale=" + bit_rate_scale +
+                ", cpb_size_scale=" + cpb_size_scale +
+                ", bit_rate_value_minus1=" + Arrays.toString(bit_rate_value_minus1) +
+                ", cpb_size_value_minus1=" + Arrays.toString(cpb_size_value_minus1) +
+                ", cbr_flag=" + Arrays.toString(cbr_flag) +
+                ", initial_cpb_removal_delay_length_minus1=" + initial_cpb_removal_delay_length_minus1 +
+                ", cpb_removal_delay_length_minus1=" + cpb_removal_delay_length_minus1 +
+                ", dpb_output_delay_length_minus1=" + dpb_output_delay_length_minus1 +
+                ", time_offset_length=" + time_offset_length +
+                '}';
+    }
+}
diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/h264/model/PictureParameterSet.java b/isoparser/src/main/java/com/googlecode/mp4parser/h264/model/PictureParameterSet.java
new file mode 100644
index 0000000..9154c38
--- /dev/null
+++ b/isoparser/src/main/java/com/googlecode/mp4parser/h264/model/PictureParameterSet.java
@@ -0,0 +1,406 @@
+/*
+Copyright (c) 2011 Stanislav Vitvitskiy
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of this
+software and associated documentation files (the "Software"), to deal in the Software
+without restriction, including without limitation the rights to use, copy, modify,
+merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to the following
+conditions:
+
+The above copyright notice and this permission notice shall be included in all copies or
+substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
+INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
+FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
+OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+package com.googlecode.mp4parser.h264.model;
+
+import com.googlecode.mp4parser.h264.read.CAVLCReader;
+import com.googlecode.mp4parser.h264.write.CAVLCWriter;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.Arrays;
+
+/**
+ * Picture Parameter Set entity of H264 bitstream
+ * <p/>
+ * capable to serialize / deserialize with CAVLC bitstream
+ *
+ * @author Stanislav Vitvitskiy
+ */
+public class PictureParameterSet extends BitstreamElement {
+
+    public static class PPSExt {
+        public boolean transform_8x8_mode_flag;
+        public ScalingMatrix scalindMatrix = new ScalingMatrix();
+        public int second_chroma_qp_index_offset;
+        public boolean[] pic_scaling_list_present_flag;
+
+        @Override
+        public String toString() {
+            return "PPSExt{" +
+                    "transform_8x8_mode_flag=" + transform_8x8_mode_flag +
+                    ", scalindMatrix=" + scalindMatrix +
+                    ", second_chroma_qp_index_offset=" + second_chroma_qp_index_offset +
+                    ", pic_scaling_list_present_flag=" + pic_scaling_list_present_flag +
+                    '}';
+        }
+    }
+
+    public boolean entropy_coding_mode_flag;
+    public int num_ref_idx_l0_active_minus1;
+    public int num_ref_idx_l1_active_minus1;
+    public int slice_group_change_rate_minus1;
+    public int pic_parameter_set_id;
+    public int seq_parameter_set_id;
+    public boolean pic_order_present_flag;
+    public int num_slice_groups_minus1;
+    public int slice_group_map_type;
+    public boolean weighted_pred_flag;
+    public int weighted_bipred_idc;
+    public int pic_init_qp_minus26;
+    public int pic_init_qs_minus26;
+    public int chroma_qp_index_offset;
+    public boolean deblocking_filter_control_present_flag;
+    public boolean constrained_intra_pred_flag;
+    public boolean redundant_pic_cnt_present_flag;
+    public int[] top_left;
+    public int[] bottom_right;
+    public int[] run_length_minus1;
+    public boolean slice_group_change_direction_flag;
+    public int[] slice_group_id;
+    public PPSExt extended;
+
+    public static PictureParameterSet read(byte[] b) throws IOException {
+        return read(new ByteArrayInputStream(b));
+    }
+
+    public static PictureParameterSet read(InputStream is) throws IOException {
+        CAVLCReader reader = new CAVLCReader(is);
+        PictureParameterSet pps = new PictureParameterSet();
+
+        pps.pic_parameter_set_id = reader.readUE("PPS: pic_parameter_set_id");
+        pps.seq_parameter_set_id = reader.readUE("PPS: seq_parameter_set_id");
+        pps.entropy_coding_mode_flag = reader
+                .readBool("PPS: entropy_coding_mode_flag");
+        pps.pic_order_present_flag = reader
+                .readBool("PPS: pic_order_present_flag");
+        pps.num_slice_groups_minus1 = reader
+                .readUE("PPS: num_slice_groups_minus1");
+        if (pps.num_slice_groups_minus1 > 0) {
+            pps.slice_group_map_type = reader
+                    .readUE("PPS: slice_group_map_type");
+            pps.top_left = new int[pps.num_slice_groups_minus1 + 1];
+            pps.bottom_right = new int[pps.num_slice_groups_minus1 + 1];
+            pps.run_length_minus1 = new int[pps.num_slice_groups_minus1 + 1];
+            if (pps.slice_group_map_type == 0)
+                for (int iGroup = 0; iGroup <= pps.num_slice_groups_minus1; iGroup++)
+                    pps.run_length_minus1[iGroup] = reader
+                            .readUE("PPS: run_length_minus1");
+            else if (pps.slice_group_map_type == 2)
+                for (int iGroup = 0; iGroup < pps.num_slice_groups_minus1; iGroup++) {
+                    pps.top_left[iGroup] = reader.readUE("PPS: top_left");
+                    pps.bottom_right[iGroup] = reader
+                            .readUE("PPS: bottom_right");
+                }
+            else if (pps.slice_group_map_type == 3
+                    || pps.slice_group_map_type == 4
+                    || pps.slice_group_map_type == 5) {
+                pps.slice_group_change_direction_flag = reader
+                        .readBool("PPS: slice_group_change_direction_flag");
+                pps.slice_group_change_rate_minus1 = reader
+                        .readUE("PPS: slice_group_change_rate_minus1");
+            } else if (pps.slice_group_map_type == 6) {
+                int NumberBitsPerSliceGroupId;
+                if (pps.num_slice_groups_minus1 + 1 > 4)
+                    NumberBitsPerSliceGroupId = 3;
+                else if (pps.num_slice_groups_minus1 + 1 > 2)
+                    NumberBitsPerSliceGroupId = 2;
+                else
+                    NumberBitsPerSliceGroupId = 1;
+                int pic_size_in_map_units_minus1 = reader
+                        .readUE("PPS: pic_size_in_map_units_minus1");
+                pps.slice_group_id = new int[pic_size_in_map_units_minus1 + 1];
+                for (int i = 0; i <= pic_size_in_map_units_minus1; i++) {
+                    pps.slice_group_id[i] = reader.readU(
+                            NumberBitsPerSliceGroupId, "PPS: slice_group_id ["
+                            + i + "]f");
+                }
+            }
+        }
+        pps.num_ref_idx_l0_active_minus1 = reader
+                .readUE("PPS: num_ref_idx_l0_active_minus1");
+        pps.num_ref_idx_l1_active_minus1 = reader
+                .readUE("PPS: num_ref_idx_l1_active_minus1");
+        pps.weighted_pred_flag = reader.readBool("PPS: weighted_pred_flag");
+        pps.weighted_bipred_idc = (int) reader.readNBit(2,
+                "PPS: weighted_bipred_idc");
+        pps.pic_init_qp_minus26 = reader.readSE("PPS: pic_init_qp_minus26");
+        pps.pic_init_qs_minus26 = reader.readSE("PPS: pic_init_qs_minus26");
+        pps.chroma_qp_index_offset = reader
+                .readSE("PPS: chroma_qp_index_offset");
+        pps.deblocking_filter_control_present_flag = reader
+                .readBool("PPS: deblocking_filter_control_present_flag");
+        pps.constrained_intra_pred_flag = reader
+                .readBool("PPS: constrained_intra_pred_flag");
+        pps.redundant_pic_cnt_present_flag = reader
+                .readBool("PPS: redundant_pic_cnt_present_flag");
+        if (reader.moreRBSPData()) {
+            pps.extended = new PictureParameterSet.PPSExt();
+            pps.extended.transform_8x8_mode_flag = reader
+                    .readBool("PPS: transform_8x8_mode_flag");
+            boolean pic_scaling_matrix_present_flag = reader
+                    .readBool("PPS: pic_scaling_matrix_present_flag");
+            if (pic_scaling_matrix_present_flag) {
+                for (int i = 0; i < 6 + 2 * (pps.extended.transform_8x8_mode_flag ? 1
+                        : 0); i++) {
+                    boolean pic_scaling_list_present_flag = reader
+                            .readBool("PPS: pic_scaling_list_present_flag");
+                    if (pic_scaling_list_present_flag) {
+                        pps.extended.scalindMatrix.ScalingList4x4 = new ScalingList[8];
+                        pps.extended.scalindMatrix.ScalingList8x8 = new ScalingList[8];
+                        if (i < 6) {
+                            pps.extended.scalindMatrix.ScalingList4x4[i] = ScalingList
+                                    .read(reader, 16);
+                        } else {
+                            pps.extended.scalindMatrix.ScalingList8x8[i - 6] = ScalingList
+                                    .read(reader, 64);
+                        }
+                    }
+                }
+            }
+            pps.extended.second_chroma_qp_index_offset = reader
+                    .readSE("PPS: second_chroma_qp_index_offset");
+        }
+
+        reader.readTrailingBits();
+
+        return pps;
+    }
+
+    public void write(OutputStream out) throws IOException {
+        CAVLCWriter writer = new CAVLCWriter(out);
+
+        writer.writeUE(pic_parameter_set_id, "PPS: pic_parameter_set_id");
+        writer.writeUE(seq_parameter_set_id, "PPS: seq_parameter_set_id");
+        writer.writeBool(entropy_coding_mode_flag,
+                "PPS: entropy_coding_mode_flag");
+        writer.writeBool(pic_order_present_flag, "PPS: pic_order_present_flag");
+        writer.writeUE(num_slice_groups_minus1, "PPS: num_slice_groups_minus1");
+        if (num_slice_groups_minus1 > 0) {
+            writer.writeUE(slice_group_map_type, "PPS: slice_group_map_type");
+            int[] top_left = new int[1];
+            int[] bottom_right = new int[1];
+            int[] run_length_minus1 = new int[1];
+            if (slice_group_map_type == 0) {
+                for (int iGroup = 0; iGroup <= num_slice_groups_minus1; iGroup++) {
+                    writer.writeUE(run_length_minus1[iGroup], "PPS: ");
+                }
+            } else if (slice_group_map_type == 2) {
+                for (int iGroup = 0; iGroup < num_slice_groups_minus1; iGroup++) {
+                    writer.writeUE(top_left[iGroup], "PPS: ");
+                    writer.writeUE(bottom_right[iGroup], "PPS: ");
+                }
+            } else if (slice_group_map_type == 3 || slice_group_map_type == 4
+                    || slice_group_map_type == 5) {
+                writer.writeBool(slice_group_change_direction_flag,
+                        "PPS: slice_group_change_direction_flag");
+                writer.writeUE(slice_group_change_rate_minus1,
+                        "PPS: slice_group_change_rate_minus1");
+            } else if (slice_group_map_type == 6) {
+                int NumberBitsPerSliceGroupId;
+                if (num_slice_groups_minus1 + 1 > 4)
+                    NumberBitsPerSliceGroupId = 3;
+                else if (num_slice_groups_minus1 + 1 > 2)
+                    NumberBitsPerSliceGroupId = 2;
+                else
+                    NumberBitsPerSliceGroupId = 1;
+                writer.writeUE(slice_group_id.length, "PPS: ");
+                for (int i = 0; i <= slice_group_id.length; i++) {
+                    writer.writeU(slice_group_id[i], NumberBitsPerSliceGroupId);
+                }
+            }
+        }
+        writer.writeUE(num_ref_idx_l0_active_minus1,
+                "PPS: num_ref_idx_l0_active_minus1");
+        writer.writeUE(num_ref_idx_l1_active_minus1,
+                "PPS: num_ref_idx_l1_active_minus1");
+        writer.writeBool(weighted_pred_flag, "PPS: weighted_pred_flag");
+        writer.writeNBit(weighted_bipred_idc, 2, "PPS: weighted_bipred_idc");
+        writer.writeSE(pic_init_qp_minus26, "PPS: pic_init_qp_minus26");
+        writer.writeSE(pic_init_qs_minus26, "PPS: pic_init_qs_minus26");
+        writer.writeSE(chroma_qp_index_offset, "PPS: chroma_qp_index_offset");
+        writer.writeBool(deblocking_filter_control_present_flag,
+                "PPS: deblocking_filter_control_present_flag");
+        writer.writeBool(constrained_intra_pred_flag,
+                "PPS: constrained_intra_pred_flag");
+        writer.writeBool(redundant_pic_cnt_present_flag,
+                "PPS: redundant_pic_cnt_present_flag");
+        if (extended != null) {
+            writer.writeBool(extended.transform_8x8_mode_flag,
+                    "PPS: transform_8x8_mode_flag");
+            writer.writeBool(extended.scalindMatrix != null,
+                    "PPS: scalindMatrix");
+            if (extended.scalindMatrix != null) {
+                for (int i = 0; i < 6 + 2 * (extended.transform_8x8_mode_flag ? 1
+                        : 0); i++) {
+                    if (i < 6) {
+                        writer
+                                .writeBool(
+                                        extended.scalindMatrix.ScalingList4x4[i] != null,
+                                        "PPS: ");
+                        if (extended.scalindMatrix.ScalingList4x4[i] != null) {
+                            extended.scalindMatrix.ScalingList4x4[i]
+                                    .write(writer);
+                        }
+
+                    } else {
+                        writer
+                                .writeBool(
+                                        extended.scalindMatrix.ScalingList8x8[i - 6] != null,
+                                        "PPS: ");
+                        if (extended.scalindMatrix.ScalingList8x8[i - 6] != null) {
+                            extended.scalindMatrix.ScalingList8x8[i - 6]
+                                    .write(writer);
+                        }
+                    }
+                }
+            }
+            writer.writeSE(extended.second_chroma_qp_index_offset, "PPS: ");
+        }
+
+        writer.writeTrailingBits();
+    }
+
+    @Override
+    public int hashCode() {
+        final int prime = 31;
+        int result = 1;
+        result = prime * result + Arrays.hashCode(bottom_right);
+        result = prime * result + chroma_qp_index_offset;
+        result = prime * result + (constrained_intra_pred_flag ? 1231 : 1237);
+        result = prime * result
+                + (deblocking_filter_control_present_flag ? 1231 : 1237);
+        result = prime * result + (entropy_coding_mode_flag ? 1231 : 1237);
+        result = prime * result
+                + ((extended == null) ? 0 : extended.hashCode());
+        result = prime * result + num_ref_idx_l0_active_minus1;
+        result = prime * result + num_ref_idx_l1_active_minus1;
+        result = prime * result + num_slice_groups_minus1;
+        result = prime * result + pic_init_qp_minus26;
+        result = prime * result + pic_init_qs_minus26;
+        result = prime * result + (pic_order_present_flag ? 1231 : 1237);
+        result = prime * result + pic_parameter_set_id;
+        result = prime * result
+                + (redundant_pic_cnt_present_flag ? 1231 : 1237);
+        result = prime * result + Arrays.hashCode(run_length_minus1);
+        result = prime * result + seq_parameter_set_id;
+        result = prime * result
+                + (slice_group_change_direction_flag ? 1231 : 1237);
+        result = prime * result + slice_group_change_rate_minus1;
+        result = prime * result + Arrays.hashCode(slice_group_id);
+        result = prime * result + slice_group_map_type;
+        result = prime * result + Arrays.hashCode(top_left);
+        result = prime * result + weighted_bipred_idc;
+        result = prime * result + (weighted_pred_flag ? 1231 : 1237);
+        return result;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj)
+            return true;
+        if (obj == null)
+            return false;
+        if (getClass() != obj.getClass())
+            return false;
+        PictureParameterSet other = (PictureParameterSet) obj;
+        if (!Arrays.equals(bottom_right, other.bottom_right))
+            return false;
+        if (chroma_qp_index_offset != other.chroma_qp_index_offset)
+            return false;
+        if (constrained_intra_pred_flag != other.constrained_intra_pred_flag)
+            return false;
+        if (deblocking_filter_control_present_flag != other.deblocking_filter_control_present_flag)
+            return false;
+        if (entropy_coding_mode_flag != other.entropy_coding_mode_flag)
+            return false;
+        if (extended == null) {
+            if (other.extended != null)
+                return false;
+        } else if (!extended.equals(other.extended))
+            return false;
+        if (num_ref_idx_l0_active_minus1 != other.num_ref_idx_l0_active_minus1)
+            return false;
+        if (num_ref_idx_l1_active_minus1 != other.num_ref_idx_l1_active_minus1)
+            return false;
+        if (num_slice_groups_minus1 != other.num_slice_groups_minus1)
+            return false;
+        if (pic_init_qp_minus26 != other.pic_init_qp_minus26)
+            return false;
+        if (pic_init_qs_minus26 != other.pic_init_qs_minus26)
+            return false;
+        if (pic_order_present_flag != other.pic_order_present_flag)
+            return false;
+        if (pic_parameter_set_id != other.pic_parameter_set_id)
+            return false;
+        if (redundant_pic_cnt_present_flag != other.redundant_pic_cnt_present_flag)
+            return false;
+        if (!Arrays.equals(run_length_minus1, other.run_length_minus1))
+            return false;
+        if (seq_parameter_set_id != other.seq_parameter_set_id)
+            return false;
+        if (slice_group_change_direction_flag != other.slice_group_change_direction_flag)
+            return false;
+        if (slice_group_change_rate_minus1 != other.slice_group_change_rate_minus1)
+            return false;
+        if (!Arrays.equals(slice_group_id, other.slice_group_id))
+            return false;
+        if (slice_group_map_type != other.slice_group_map_type)
+            return false;
+        if (!Arrays.equals(top_left, other.top_left))
+            return false;
+        if (weighted_bipred_idc != other.weighted_bipred_idc)
+            return false;
+        if (weighted_pred_flag != other.weighted_pred_flag)
+            return false;
+        return true;
+    }
+
+    @Override
+    public String toString() {
+        return "PictureParameterSet{" +
+                "\n       entropy_coding_mode_flag=" + entropy_coding_mode_flag +
+                ",\n       num_ref_idx_l0_active_minus1=" + num_ref_idx_l0_active_minus1 +
+                ",\n       num_ref_idx_l1_active_minus1=" + num_ref_idx_l1_active_minus1 +
+                ",\n       slice_group_change_rate_minus1=" + slice_group_change_rate_minus1 +
+                ",\n       pic_parameter_set_id=" + pic_parameter_set_id +
+                ",\n       seq_parameter_set_id=" + seq_parameter_set_id +
+                ",\n       pic_order_present_flag=" + pic_order_present_flag +
+                ",\n       num_slice_groups_minus1=" + num_slice_groups_minus1 +
+                ",\n       slice_group_map_type=" + slice_group_map_type +
+                ",\n       weighted_pred_flag=" + weighted_pred_flag +
+                ",\n       weighted_bipred_idc=" + weighted_bipred_idc +
+                ",\n       pic_init_qp_minus26=" + pic_init_qp_minus26 +
+                ",\n       pic_init_qs_minus26=" + pic_init_qs_minus26 +
+                ",\n       chroma_qp_index_offset=" + chroma_qp_index_offset +
+                ",\n       deblocking_filter_control_present_flag=" + deblocking_filter_control_present_flag +
+                ",\n       constrained_intra_pred_flag=" + constrained_intra_pred_flag +
+                ",\n       redundant_pic_cnt_present_flag=" + redundant_pic_cnt_present_flag +
+                ",\n       top_left=" + top_left +
+                ",\n       bottom_right=" + bottom_right +
+                ",\n       run_length_minus1=" + run_length_minus1 +
+                ",\n       slice_group_change_direction_flag=" + slice_group_change_direction_flag +
+                ",\n       slice_group_id=" + slice_group_id +
+                ",\n       extended=" + extended +
+                '}';
+    }
+}
diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/h264/model/ScalingList.java b/isoparser/src/main/java/com/googlecode/mp4parser/h264/model/ScalingList.java
new file mode 100644
index 0000000..5d272bf
--- /dev/null
+++ b/isoparser/src/main/java/com/googlecode/mp4parser/h264/model/ScalingList.java
@@ -0,0 +1,83 @@
+/*
+Copyright (c) 2011 Stanislav Vitvitskiy
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of this
+software and associated documentation files (the "Software"), to deal in the Software
+without restriction, including without limitation the rights to use, copy, modify,
+merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to the following
+conditions:
+
+The above copyright notice and this permission notice shall be included in all copies or
+substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
+INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
+FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
+OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+package com.googlecode.mp4parser.h264.model;
+
+import com.googlecode.mp4parser.h264.read.CAVLCReader;
+import com.googlecode.mp4parser.h264.write.CAVLCWriter;
+
+import java.io.IOException;
+
+/**
+ * Scaling list entity
+ * <p/>
+ * capable to serialize / deserialize with CAVLC bitstream
+ *
+ * @author Stanislav Vitvitskiy
+ */
+public class ScalingList {
+
+    public int[] scalingList;
+    public boolean useDefaultScalingMatrixFlag;
+
+    public void write(CAVLCWriter out) throws IOException {
+        if (useDefaultScalingMatrixFlag) {
+            out.writeSE(0, "SPS: ");
+            return;
+        }
+
+        int lastScale = 8;
+        int nextScale = 8;
+        for (int j = 0; j < scalingList.length; j++) {
+            if (nextScale != 0) {
+                int deltaScale = scalingList[j] - lastScale - 256;
+                out.writeSE(deltaScale, "SPS: ");
+            }
+            lastScale = scalingList[j];
+        }
+    }
+
+    public static ScalingList read(CAVLCReader is, int sizeOfScalingList)
+            throws IOException {
+
+        ScalingList sl = new ScalingList();
+        sl.scalingList = new int[sizeOfScalingList];
+        int lastScale = 8;
+        int nextScale = 8;
+        for (int j = 0; j < sizeOfScalingList; j++) {
+            if (nextScale != 0) {
+                int deltaScale = is.readSE("deltaScale");
+                nextScale = (lastScale + deltaScale + 256) % 256;
+                sl.useDefaultScalingMatrixFlag = (j == 0 && nextScale == 0);
+            }
+            sl.scalingList[j] = nextScale == 0 ? lastScale : nextScale;
+            lastScale = sl.scalingList[j];
+        }
+        return sl;
+    }
+
+    @Override
+    public String toString() {
+        return "ScalingList{" +
+                "scalingList=" + scalingList +
+                ", useDefaultScalingMatrixFlag=" + useDefaultScalingMatrixFlag +
+                '}';
+    }
+}
\ No newline at end of file
diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/h264/model/ScalingMatrix.java b/isoparser/src/main/java/com/googlecode/mp4parser/h264/model/ScalingMatrix.java
new file mode 100644
index 0000000..d04af8e
--- /dev/null
+++ b/isoparser/src/main/java/com/googlecode/mp4parser/h264/model/ScalingMatrix.java
@@ -0,0 +1,37 @@
+/*
+Copyright (c) 2011 Stanislav Vitvitskiy
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of this
+software and associated documentation files (the "Software"), to deal in the Software
+without restriction, including without limitation the rights to use, copy, modify,
+merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to the following
+conditions:
+
+The above copyright notice and this permission notice shall be included in all copies or
+substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
+INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
+FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
+OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+package com.googlecode.mp4parser.h264.model;
+
+import java.util.Arrays;
+
+public class ScalingMatrix {
+
+    public ScalingList[] ScalingList4x4;
+    public ScalingList[] ScalingList8x8;
+
+    @Override
+    public String toString() {
+        return "ScalingMatrix{" +
+                "ScalingList4x4=" + (ScalingList4x4 == null ? null : Arrays.asList(ScalingList4x4)) + "\n" +
+                ", ScalingList8x8=" + (ScalingList8x8 == null ? null : Arrays.asList(ScalingList8x8)) + "\n" +
+                '}';
+    }
+}
\ No newline at end of file
diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/h264/model/SeqParameterSet.java b/isoparser/src/main/java/com/googlecode/mp4parser/h264/model/SeqParameterSet.java
new file mode 100644
index 0000000..4894df8
--- /dev/null
+++ b/isoparser/src/main/java/com/googlecode/mp4parser/h264/model/SeqParameterSet.java
@@ -0,0 +1,556 @@
+/*
+Copyright (c) 2011 Stanislav Vitvitskiy
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of this
+software and associated documentation files (the "Software"), to deal in the Software
+without restriction, including without limitation the rights to use, copy, modify,
+merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to the following
+conditions:
+
+The above copyright notice and this permission notice shall be included in all copies or
+substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
+INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
+FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
+OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+package com.googlecode.mp4parser.h264.model;
+
+import com.googlecode.mp4parser.h264.read.CAVLCReader;
+import com.googlecode.mp4parser.h264.write.CAVLCWriter;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+/**
+ * Sequence Parameter Set structure of h264 bitstream
+ * <p/>
+ * capable to serialize and deserialize with CAVLC bitstream
+ *
+ * @author Stanislav Vitvitskiy
+ */
+public class SeqParameterSet extends BitstreamElement {
+    public int pic_order_cnt_type;
+    public boolean field_pic_flag;
+    public boolean delta_pic_order_always_zero_flag;
+    public boolean weighted_pred_flag;
+    public int weighted_bipred_idc;
+    public boolean entropy_coding_mode_flag;
+    public boolean mb_adaptive_frame_field_flag;
+    public boolean direct_8x8_inference_flag;
+    public ChromaFormat chroma_format_idc;
+    public int log2_max_frame_num_minus4;
+    public int log2_max_pic_order_cnt_lsb_minus4;
+    public int pic_height_in_map_units_minus1;
+    public int pic_width_in_mbs_minus1;
+    public int bit_depth_luma_minus8;
+    public int bit_depth_chroma_minus8;
+    public boolean qpprime_y_zero_transform_bypass_flag;
+    public int profile_idc;
+    public boolean constraint_set_0_flag;
+    public boolean constraint_set_1_flag;
+    public boolean constraint_set_2_flag;
+    public boolean constraint_set_3_flag;
+    public int level_idc;
+    public int seq_parameter_set_id;
+    public boolean residual_color_transform_flag;
+    public int offset_for_non_ref_pic;
+    public int offset_for_top_to_bottom_field;
+    public int num_ref_frames;
+    public boolean gaps_in_frame_num_value_allowed_flag;
+    public boolean frame_mbs_only_flag;
+    public boolean frame_cropping_flag;
+    public int frame_crop_left_offset;
+    public int frame_crop_right_offset;
+    public int frame_crop_top_offset;
+    public int frame_crop_bottom_offset;
+    public int[] offsetForRefFrame;
+    public VUIParameters vuiParams;
+    public ScalingMatrix scalingMatrix;
+    public int num_ref_frames_in_pic_order_cnt_cycle;
+
+    public static SeqParameterSet read(InputStream is) throws IOException {
+        CAVLCReader reader = new CAVLCReader(is);
+        SeqParameterSet sps = new SeqParameterSet();
+
+        sps.profile_idc = (int) reader.readNBit(8, "SPS: profile_idc");
+        sps.constraint_set_0_flag = reader
+                .readBool("SPS: constraint_set_0_flag");
+        sps.constraint_set_1_flag = reader
+                .readBool("SPS: constraint_set_1_flag");
+        sps.constraint_set_2_flag = reader
+                .readBool("SPS: constraint_set_2_flag");
+        sps.constraint_set_3_flag = reader
+                .readBool("SPS: constraint_set_3_flag");
+        reader.readNBit(4, "SPS: reserved_zero_4bits");
+        sps.level_idc = (int) reader.readNBit(8, "SPS: level_idc");
+        sps.seq_parameter_set_id = reader.readUE("SPS: seq_parameter_set_id");
+
+        if (sps.profile_idc == 100 || sps.profile_idc == 110
+                || sps.profile_idc == 122 || sps.profile_idc == 144) {
+            sps.chroma_format_idc = ChromaFormat.fromId(reader
+                    .readUE("SPS: chroma_format_idc"));
+            if (sps.chroma_format_idc == ChromaFormat.YUV_444) {
+                sps.residual_color_transform_flag = reader
+                        .readBool("SPS: residual_color_transform_flag");
+            }
+            sps.bit_depth_luma_minus8 = reader
+                    .readUE("SPS: bit_depth_luma_minus8");
+            sps.bit_depth_chroma_minus8 = reader
+                    .readUE("SPS: bit_depth_chroma_minus8");
+            sps.qpprime_y_zero_transform_bypass_flag = reader
+                    .readBool("SPS: qpprime_y_zero_transform_bypass_flag");
+            boolean seqScalingMatrixPresent = reader
+                    .readBool("SPS: seq_scaling_matrix_present_lag");
+            if (seqScalingMatrixPresent) {
+                readScalingListMatrix(reader, sps);
+            }
+        } else {
+            sps.chroma_format_idc = ChromaFormat.YUV_420;
+        }
+        sps.log2_max_frame_num_minus4 = reader
+                .readUE("SPS: log2_max_frame_num_minus4");
+        sps.pic_order_cnt_type = reader.readUE("SPS: pic_order_cnt_type");
+        if (sps.pic_order_cnt_type == 0) {
+            sps.log2_max_pic_order_cnt_lsb_minus4 = reader
+                    .readUE("SPS: log2_max_pic_order_cnt_lsb_minus4");
+        } else if (sps.pic_order_cnt_type == 1) {
+            sps.delta_pic_order_always_zero_flag = reader
+                    .readBool("SPS: delta_pic_order_always_zero_flag");
+            sps.offset_for_non_ref_pic = reader
+                    .readSE("SPS: offset_for_non_ref_pic");
+            sps.offset_for_top_to_bottom_field = reader
+                    .readSE("SPS: offset_for_top_to_bottom_field");
+            sps.num_ref_frames_in_pic_order_cnt_cycle = reader
+                    .readUE("SPS: num_ref_frames_in_pic_order_cnt_cycle");
+            sps.offsetForRefFrame = new int[sps.num_ref_frames_in_pic_order_cnt_cycle];
+            for (int i = 0; i < sps.num_ref_frames_in_pic_order_cnt_cycle; i++) {
+                sps.offsetForRefFrame[i] = reader
+                        .readSE("SPS: offsetForRefFrame [" + i + "]");
+            }
+        }
+        sps.num_ref_frames = reader.readUE("SPS: num_ref_frames");
+        sps.gaps_in_frame_num_value_allowed_flag = reader
+                .readBool("SPS: gaps_in_frame_num_value_allowed_flag");
+        sps.pic_width_in_mbs_minus1 = reader
+                .readUE("SPS: pic_width_in_mbs_minus1");
+        sps.pic_height_in_map_units_minus1 = reader
+                .readUE("SPS: pic_height_in_map_units_minus1");
+        sps.frame_mbs_only_flag = reader.readBool("SPS: frame_mbs_only_flag");
+        if (!sps.frame_mbs_only_flag) {
+            sps.mb_adaptive_frame_field_flag = reader
+                    .readBool("SPS: mb_adaptive_frame_field_flag");
+        }
+        sps.direct_8x8_inference_flag = reader
+                .readBool("SPS: direct_8x8_inference_flag");
+        sps.frame_cropping_flag = reader.readBool("SPS: frame_cropping_flag");
+        if (sps.frame_cropping_flag) {
+            sps.frame_crop_left_offset = reader
+                    .readUE("SPS: frame_crop_left_offset");
+            sps.frame_crop_right_offset = reader
+                    .readUE("SPS: frame_crop_right_offset");
+            sps.frame_crop_top_offset = reader
+                    .readUE("SPS: frame_crop_top_offset");
+            sps.frame_crop_bottom_offset = reader
+                    .readUE("SPS: frame_crop_bottom_offset");
+        }
+        boolean vui_parameters_present_flag = reader
+                .readBool("SPS: vui_parameters_present_flag");
+        if (vui_parameters_present_flag)
+            sps.vuiParams = ReadVUIParameters(reader);
+
+        reader.readTrailingBits();
+
+        return sps;
+    }
+
+    private static void readScalingListMatrix(CAVLCReader reader,
+                                              SeqParameterSet sps) throws IOException {
+        sps.scalingMatrix = new ScalingMatrix();
+        for (int i = 0; i < 8; i++) {
+            boolean seqScalingListPresentFlag = reader
+                    .readBool("SPS: seqScalingListPresentFlag");
+            if (seqScalingListPresentFlag) {
+                sps.scalingMatrix.ScalingList4x4 = new ScalingList[8];
+                sps.scalingMatrix.ScalingList8x8 = new ScalingList[8];
+                if (i < 6) {
+                    sps.scalingMatrix.ScalingList4x4[i] = ScalingList.read(
+                            reader, 16);
+                } else {
+                    sps.scalingMatrix.ScalingList8x8[i - 6] = ScalingList.read(
+                            reader, 64);
+                }
+            }
+        }
+    }
+
+    private static VUIParameters ReadVUIParameters(CAVLCReader reader)
+            throws IOException {
+        VUIParameters vuip = new VUIParameters();
+        vuip.aspect_ratio_info_present_flag = reader
+                .readBool("VUI: aspect_ratio_info_present_flag");
+        if (vuip.aspect_ratio_info_present_flag) {
+            vuip.aspect_ratio = AspectRatio.fromValue((int) reader.readNBit(8,
+                    "VUI: aspect_ratio"));
+            if (vuip.aspect_ratio == AspectRatio.Extended_SAR) {
+                vuip.sar_width = (int) reader.readNBit(16, "VUI: sar_width");
+                vuip.sar_height = (int) reader.readNBit(16, "VUI: sar_height");
+            }
+        }
+        vuip.overscan_info_present_flag = reader
+                .readBool("VUI: overscan_info_present_flag");
+        if (vuip.overscan_info_present_flag) {
+            vuip.overscan_appropriate_flag = reader
+                    .readBool("VUI: overscan_appropriate_flag");
+        }
+        vuip.video_signal_type_present_flag = reader
+                .readBool("VUI: video_signal_type_present_flag");
+        if (vuip.video_signal_type_present_flag) {
+            vuip.video_format = (int) reader.readNBit(3, "VUI: video_format");
+            vuip.video_full_range_flag = reader
+                    .readBool("VUI: video_full_range_flag");
+            vuip.colour_description_present_flag = reader
+                    .readBool("VUI: colour_description_present_flag");
+            if (vuip.colour_description_present_flag) {
+                vuip.colour_primaries = (int) reader.readNBit(8,
+                        "VUI: colour_primaries");
+                vuip.transfer_characteristics = (int) reader.readNBit(8,
+                        "VUI: transfer_characteristics");
+                vuip.matrix_coefficients = (int) reader.readNBit(8,
+                        "VUI: matrix_coefficients");
+            }
+        }
+        vuip.chroma_loc_info_present_flag = reader
+                .readBool("VUI: chroma_loc_info_present_flag");
+        if (vuip.chroma_loc_info_present_flag) {
+            vuip.chroma_sample_loc_type_top_field = reader
+                    .readUE("VUI chroma_sample_loc_type_top_field");
+            vuip.chroma_sample_loc_type_bottom_field = reader
+                    .readUE("VUI chroma_sample_loc_type_bottom_field");
+        }
+        vuip.timing_info_present_flag = reader
+                .readBool("VUI: timing_info_present_flag");
+        if (vuip.timing_info_present_flag) {
+            vuip.num_units_in_tick = (int) reader.readNBit(32,
+                    "VUI: num_units_in_tick");
+            vuip.time_scale = (int) reader.readNBit(32, "VUI: time_scale");
+            vuip.fixed_frame_rate_flag = reader
+                    .readBool("VUI: fixed_frame_rate_flag");
+        }
+        boolean nal_hrd_parameters_present_flag = reader
+                .readBool("VUI: nal_hrd_parameters_present_flag");
+        if (nal_hrd_parameters_present_flag)
+            vuip.nalHRDParams = readHRDParameters(reader);
+        boolean vcl_hrd_parameters_present_flag = reader
+                .readBool("VUI: vcl_hrd_parameters_present_flag");
+        if (vcl_hrd_parameters_present_flag)
+            vuip.vclHRDParams = readHRDParameters(reader);
+        if (nal_hrd_parameters_present_flag || vcl_hrd_parameters_present_flag) {
+            vuip.low_delay_hrd_flag = reader
+                    .readBool("VUI: low_delay_hrd_flag");
+        }
+        vuip.pic_struct_present_flag = reader
+                .readBool("VUI: pic_struct_present_flag");
+        boolean bitstream_restriction_flag = reader
+                .readBool("VUI: bitstream_restriction_flag");
+        if (bitstream_restriction_flag) {
+            vuip.bitstreamRestriction = new VUIParameters.BitstreamRestriction();
+            vuip.bitstreamRestriction.motion_vectors_over_pic_boundaries_flag = reader
+                    .readBool("VUI: motion_vectors_over_pic_boundaries_flag");
+            vuip.bitstreamRestriction.max_bytes_per_pic_denom = reader
+                    .readUE("VUI max_bytes_per_pic_denom");
+            vuip.bitstreamRestriction.max_bits_per_mb_denom = reader
+                    .readUE("VUI max_bits_per_mb_denom");
+            vuip.bitstreamRestriction.log2_max_mv_length_horizontal = reader
+                    .readUE("VUI log2_max_mv_length_horizontal");
+            vuip.bitstreamRestriction.log2_max_mv_length_vertical = reader
+                    .readUE("VUI log2_max_mv_length_vertical");
+            vuip.bitstreamRestriction.num_reorder_frames = reader
+                    .readUE("VUI num_reorder_frames");
+            vuip.bitstreamRestriction.max_dec_frame_buffering = reader
+                    .readUE("VUI max_dec_frame_buffering");
+        }
+
+        return vuip;
+    }
+
+    private static HRDParameters readHRDParameters(CAVLCReader reader)
+            throws IOException {
+        HRDParameters hrd = new HRDParameters();
+        hrd.cpb_cnt_minus1 = reader.readUE("SPS: cpb_cnt_minus1");
+        hrd.bit_rate_scale = (int) reader.readNBit(4, "HRD: bit_rate_scale");
+        hrd.cpb_size_scale = (int) reader.readNBit(4, "HRD: cpb_size_scale");
+        hrd.bit_rate_value_minus1 = new int[hrd.cpb_cnt_minus1 + 1];
+        hrd.cpb_size_value_minus1 = new int[hrd.cpb_cnt_minus1 + 1];
+        hrd.cbr_flag = new boolean[hrd.cpb_cnt_minus1 + 1];
+
+        for (int SchedSelIdx = 0; SchedSelIdx <= hrd.cpb_cnt_minus1; SchedSelIdx++) {
+            hrd.bit_rate_value_minus1[SchedSelIdx] = reader
+                    .readUE("HRD: bit_rate_value_minus1");
+            hrd.cpb_size_value_minus1[SchedSelIdx] = reader
+                    .readUE("HRD: cpb_size_value_minus1");
+            hrd.cbr_flag[SchedSelIdx] = reader.readBool("HRD: cbr_flag");
+        }
+        hrd.initial_cpb_removal_delay_length_minus1 = (int) reader.readNBit(5,
+                "HRD: initial_cpb_removal_delay_length_minus1");
+        hrd.cpb_removal_delay_length_minus1 = (int) reader.readNBit(5,
+                "HRD: cpb_removal_delay_length_minus1");
+        hrd.dpb_output_delay_length_minus1 = (int) reader.readNBit(5,
+                "HRD: dpb_output_delay_length_minus1");
+        hrd.time_offset_length = (int) reader.readNBit(5,
+                "HRD: time_offset_length");
+        return hrd;
+    }
+
+    public void write(OutputStream out) throws IOException {
+        CAVLCWriter writer = new CAVLCWriter(out);
+
+        writer.writeNBit(profile_idc, 8, "SPS: profile_idc");
+        writer.writeBool(constraint_set_0_flag, "SPS: constraint_set_0_flag");
+        writer.writeBool(constraint_set_1_flag, "SPS: constraint_set_1_flag");
+        writer.writeBool(constraint_set_2_flag, "SPS: constraint_set_2_flag");
+        writer.writeBool(constraint_set_3_flag, "SPS: constraint_set_3_flag");
+        writer.writeNBit(0, 4, "SPS: reserved");
+        writer.writeNBit(level_idc, 8, "SPS: level_idc");
+        writer.writeUE(seq_parameter_set_id, "SPS: seq_parameter_set_id");
+
+        if (profile_idc == 100 || profile_idc == 110 || profile_idc == 122
+                || profile_idc == 144) {
+            writer.writeUE(chroma_format_idc.getId(), "SPS: chroma_format_idc");
+            if (chroma_format_idc == ChromaFormat.YUV_444) {
+                writer.writeBool(residual_color_transform_flag,
+                        "SPS: residual_color_transform_flag");
+            }
+            writer.writeUE(bit_depth_luma_minus8, "SPS: ");
+            writer.writeUE(bit_depth_chroma_minus8, "SPS: ");
+            writer.writeBool(qpprime_y_zero_transform_bypass_flag,
+                    "SPS: qpprime_y_zero_transform_bypass_flag");
+            writer.writeBool(scalingMatrix != null, "SPS: ");
+            if (scalingMatrix != null) {
+                for (int i = 0; i < 8; i++) {
+                    if (i < 6) {
+                        writer.writeBool(
+                                scalingMatrix.ScalingList4x4[i] != null,
+                                "SPS: ");
+                        if (scalingMatrix.ScalingList4x4[i] != null) {
+                            scalingMatrix.ScalingList4x4[i].write(writer);
+                        }
+                    } else {
+                        writer.writeBool(
+                                scalingMatrix.ScalingList8x8[i - 6] != null,
+                                "SPS: ");
+                        if (scalingMatrix.ScalingList8x8[i - 6] != null) {
+                            scalingMatrix.ScalingList8x8[i - 6].write(writer);
+                        }
+                    }
+                }
+            }
+        }
+        writer.writeUE(log2_max_frame_num_minus4,
+                "SPS: log2_max_frame_num_minus4");
+        writer.writeUE(pic_order_cnt_type, "SPS: pic_order_cnt_type");
+        if (pic_order_cnt_type == 0) {
+            writer.writeUE(log2_max_pic_order_cnt_lsb_minus4,
+                    "SPS: log2_max_pic_order_cnt_lsb_minus4");
+        } else if (pic_order_cnt_type == 1) {
+            writer.writeBool(delta_pic_order_always_zero_flag,
+                    "SPS: delta_pic_order_always_zero_flag");
+            writer.writeSE(offset_for_non_ref_pic,
+                    "SPS: offset_for_non_ref_pic");
+            writer.writeSE(offset_for_top_to_bottom_field,
+                    "SPS: offset_for_top_to_bottom_field");
+            writer.writeUE(offsetForRefFrame.length, "SPS: ");
+            for (int i = 0; i < offsetForRefFrame.length; i++)
+                writer.writeSE(offsetForRefFrame[i], "SPS: ");
+        }
+        writer.writeUE(num_ref_frames, "SPS: num_ref_frames");
+        writer.writeBool(gaps_in_frame_num_value_allowed_flag,
+                "SPS: gaps_in_frame_num_value_allowed_flag");
+        writer.writeUE(pic_width_in_mbs_minus1, "SPS: pic_width_in_mbs_minus1");
+        writer.writeUE(pic_height_in_map_units_minus1,
+                "SPS: pic_height_in_map_units_minus1");
+        writer.writeBool(frame_mbs_only_flag, "SPS: frame_mbs_only_flag");
+        if (!frame_mbs_only_flag) {
+            writer.writeBool(mb_adaptive_frame_field_flag,
+                    "SPS: mb_adaptive_frame_field_flag");
+        }
+        writer.writeBool(direct_8x8_inference_flag,
+                "SPS: direct_8x8_inference_flag");
+        writer.writeBool(frame_cropping_flag, "SPS: frame_cropping_flag");
+        if (frame_cropping_flag) {
+            writer.writeUE(frame_crop_left_offset,
+                    "SPS: frame_crop_left_offset");
+            writer.writeUE(frame_crop_right_offset,
+                    "SPS: frame_crop_right_offset");
+            writer.writeUE(frame_crop_top_offset, "SPS: frame_crop_top_offset");
+            writer.writeUE(frame_crop_bottom_offset,
+                    "SPS: frame_crop_bottom_offset");
+        }
+        writer.writeBool(vuiParams != null, "SPS: ");
+        if (vuiParams != null)
+            writeVUIParameters(vuiParams, writer);
+
+        writer.writeTrailingBits();
+    }
+
+    private void writeVUIParameters(VUIParameters vuip, CAVLCWriter writer)
+            throws IOException {
+        writer.writeBool(vuip.aspect_ratio_info_present_flag,
+                "VUI: aspect_ratio_info_present_flag");
+        if (vuip.aspect_ratio_info_present_flag) {
+            writer.writeNBit(vuip.aspect_ratio.getValue(), 8,
+                    "VUI: aspect_ratio");
+            if (vuip.aspect_ratio == AspectRatio.Extended_SAR) {
+                writer.writeNBit(vuip.sar_width, 16, "VUI: sar_width");
+                writer.writeNBit(vuip.sar_height, 16, "VUI: sar_height");
+            }
+        }
+        writer.writeBool(vuip.overscan_info_present_flag,
+                "VUI: overscan_info_present_flag");
+        if (vuip.overscan_info_present_flag) {
+            writer.writeBool(vuip.overscan_appropriate_flag,
+                    "VUI: overscan_appropriate_flag");
+        }
+        writer.writeBool(vuip.video_signal_type_present_flag,
+                "VUI: video_signal_type_present_flag");
+        if (vuip.video_signal_type_present_flag) {
+            writer.writeNBit(vuip.video_format, 3, "VUI: video_format");
+            writer.writeBool(vuip.video_full_range_flag,
+                    "VUI: video_full_range_flag");
+            writer.writeBool(vuip.colour_description_present_flag,
+                    "VUI: colour_description_present_flag");
+            if (vuip.colour_description_present_flag) {
+                writer.writeNBit(vuip.colour_primaries, 8,
+                        "VUI: colour_primaries");
+                writer.writeNBit(vuip.transfer_characteristics, 8,
+                        "VUI: transfer_characteristics");
+                writer.writeNBit(vuip.matrix_coefficients, 8,
+                        "VUI: matrix_coefficients");
+            }
+        }
+        writer.writeBool(vuip.chroma_loc_info_present_flag,
+                "VUI: chroma_loc_info_present_flag");
+        if (vuip.chroma_loc_info_present_flag) {
+            writer.writeUE(vuip.chroma_sample_loc_type_top_field,
+                    "VUI: chroma_sample_loc_type_top_field");
+            writer.writeUE(vuip.chroma_sample_loc_type_bottom_field,
+                    "VUI: chroma_sample_loc_type_bottom_field");
+        }
+        writer.writeBool(vuip.timing_info_present_flag,
+                "VUI: timing_info_present_flag");
+        if (vuip.timing_info_present_flag) {
+            writer.writeNBit(vuip.num_units_in_tick, 32,
+                    "VUI: num_units_in_tick");
+            writer.writeNBit(vuip.time_scale, 32, "VUI: time_scale");
+            writer.writeBool(vuip.fixed_frame_rate_flag,
+                    "VUI: fixed_frame_rate_flag");
+        }
+        writer.writeBool(vuip.nalHRDParams != null, "VUI: ");
+        if (vuip.nalHRDParams != null) {
+            writeHRDParameters(vuip.nalHRDParams, writer);
+        }
+        writer.writeBool(vuip.vclHRDParams != null, "VUI: ");
+        if (vuip.vclHRDParams != null) {
+            writeHRDParameters(vuip.vclHRDParams, writer);
+        }
+
+        if (vuip.nalHRDParams != null || vuip.vclHRDParams != null) {
+            writer
+                    .writeBool(vuip.low_delay_hrd_flag,
+                            "VUI: low_delay_hrd_flag");
+        }
+        writer.writeBool(vuip.pic_struct_present_flag,
+                "VUI: pic_struct_present_flag");
+        writer.writeBool(vuip.bitstreamRestriction != null, "VUI: ");
+        if (vuip.bitstreamRestriction != null) {
+            writer
+                    .writeBool(
+                            vuip.bitstreamRestriction.motion_vectors_over_pic_boundaries_flag,
+                            "VUI: motion_vectors_over_pic_boundaries_flag");
+            writer.writeUE(vuip.bitstreamRestriction.max_bytes_per_pic_denom,
+                    "VUI: max_bytes_per_pic_denom");
+            writer.writeUE(vuip.bitstreamRestriction.max_bits_per_mb_denom,
+                    "VUI: max_bits_per_mb_denom");
+            writer.writeUE(
+                    vuip.bitstreamRestriction.log2_max_mv_length_horizontal,
+                    "VUI: log2_max_mv_length_horizontal");
+            writer.writeUE(
+                    vuip.bitstreamRestriction.log2_max_mv_length_vertical,
+                    "VUI: log2_max_mv_length_vertical");
+            writer.writeUE(vuip.bitstreamRestriction.num_reorder_frames,
+                    "VUI: num_reorder_frames");
+            writer.writeUE(vuip.bitstreamRestriction.max_dec_frame_buffering,
+                    "VUI: max_dec_frame_buffering");
+        }
+
+    }
+
+    private void writeHRDParameters(HRDParameters hrd, CAVLCWriter writer)
+            throws IOException {
+        writer.writeUE(hrd.cpb_cnt_minus1, "HRD: cpb_cnt_minus1");
+        writer.writeNBit(hrd.bit_rate_scale, 4, "HRD: bit_rate_scale");
+        writer.writeNBit(hrd.cpb_size_scale, 4, "HRD: cpb_size_scale");
+
+        for (int SchedSelIdx = 0; SchedSelIdx <= hrd.cpb_cnt_minus1; SchedSelIdx++) {
+            writer.writeUE(hrd.bit_rate_value_minus1[SchedSelIdx], "HRD: ");
+            writer.writeUE(hrd.cpb_size_value_minus1[SchedSelIdx], "HRD: ");
+            writer.writeBool(hrd.cbr_flag[SchedSelIdx], "HRD: ");
+        }
+        writer.writeNBit(hrd.initial_cpb_removal_delay_length_minus1, 5,
+                "HRD: initial_cpb_removal_delay_length_minus1");
+        writer.writeNBit(hrd.cpb_removal_delay_length_minus1, 5,
+                "HRD: cpb_removal_delay_length_minus1");
+        writer.writeNBit(hrd.dpb_output_delay_length_minus1, 5,
+                "HRD: dpb_output_delay_length_minus1");
+        writer.writeNBit(hrd.time_offset_length, 5, "HRD: time_offset_length");
+    }
+
+    @Override
+    public String toString() {
+        return "SeqParameterSet{ " +
+                "\n        pic_order_cnt_type=" + pic_order_cnt_type +
+                ", \n        field_pic_flag=" + field_pic_flag +
+                ", \n        delta_pic_order_always_zero_flag=" + delta_pic_order_always_zero_flag +
+                ", \n        weighted_pred_flag=" + weighted_pred_flag +
+                ", \n        weighted_bipred_idc=" + weighted_bipred_idc +
+                ", \n        entropy_coding_mode_flag=" + entropy_coding_mode_flag +
+                ", \n        mb_adaptive_frame_field_flag=" + mb_adaptive_frame_field_flag +
+                ", \n        direct_8x8_inference_flag=" + direct_8x8_inference_flag +
+                ", \n        chroma_format_idc=" + chroma_format_idc +
+                ", \n        log2_max_frame_num_minus4=" + log2_max_frame_num_minus4 +
+                ", \n        log2_max_pic_order_cnt_lsb_minus4=" + log2_max_pic_order_cnt_lsb_minus4 +
+                ", \n        pic_height_in_map_units_minus1=" + pic_height_in_map_units_minus1 +
+                ", \n        pic_width_in_mbs_minus1=" + pic_width_in_mbs_minus1 +
+                ", \n        bit_depth_luma_minus8=" + bit_depth_luma_minus8 +
+                ", \n        bit_depth_chroma_minus8=" + bit_depth_chroma_minus8 +
+                ", \n        qpprime_y_zero_transform_bypass_flag=" + qpprime_y_zero_transform_bypass_flag +
+                ", \n        profile_idc=" + profile_idc +
+                ", \n        constraint_set_0_flag=" + constraint_set_0_flag +
+                ", \n        constraint_set_1_flag=" + constraint_set_1_flag +
+                ", \n        constraint_set_2_flag=" + constraint_set_2_flag +
+                ", \n        constraint_set_3_flag=" + constraint_set_3_flag +
+                ", \n        level_idc=" + level_idc +
+                ", \n        seq_parameter_set_id=" + seq_parameter_set_id +
+                ", \n        residual_color_transform_flag=" + residual_color_transform_flag +
+                ", \n        offset_for_non_ref_pic=" + offset_for_non_ref_pic +
+                ", \n        offset_for_top_to_bottom_field=" + offset_for_top_to_bottom_field +
+                ", \n        num_ref_frames=" + num_ref_frames +
+                ", \n        gaps_in_frame_num_value_allowed_flag=" + gaps_in_frame_num_value_allowed_flag +
+                ", \n        frame_mbs_only_flag=" + frame_mbs_only_flag +
+                ", \n        frame_cropping_flag=" + frame_cropping_flag +
+                ", \n        frame_crop_left_offset=" + frame_crop_left_offset +
+                ", \n        frame_crop_right_offset=" + frame_crop_right_offset +
+                ", \n        frame_crop_top_offset=" + frame_crop_top_offset +
+                ", \n        frame_crop_bottom_offset=" + frame_crop_bottom_offset +
+                ", \n        offsetForRefFrame=" + offsetForRefFrame +
+                ", \n        vuiParams=" + vuiParams +
+                ", \n        scalingMatrix=" + scalingMatrix +
+                ", \n        num_ref_frames_in_pic_order_cnt_cycle=" + num_ref_frames_in_pic_order_cnt_cycle +
+                '}';
+    }
+}
\ No newline at end of file
diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/h264/model/VUIParameters.java b/isoparser/src/main/java/com/googlecode/mp4parser/h264/model/VUIParameters.java
new file mode 100644
index 0000000..eec7880
--- /dev/null
+++ b/isoparser/src/main/java/com/googlecode/mp4parser/h264/model/VUIParameters.java
@@ -0,0 +1,94 @@
+/*
+Copyright (c) 2011 Stanislav Vitvitskiy
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of this
+software and associated documentation files (the "Software"), to deal in the Software
+without restriction, including without limitation the rights to use, copy, modify,
+merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to the following
+conditions:
+
+The above copyright notice and this permission notice shall be included in all copies or
+substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
+INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
+FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
+OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+package com.googlecode.mp4parser.h264.model;
+
+public class VUIParameters {
+
+    public static class BitstreamRestriction {
+
+        public boolean motion_vectors_over_pic_boundaries_flag;
+        public int max_bytes_per_pic_denom;
+        public int max_bits_per_mb_denom;
+        public int log2_max_mv_length_horizontal;
+        public int log2_max_mv_length_vertical;
+        public int num_reorder_frames;
+        public int max_dec_frame_buffering;
+
+    }
+
+    public boolean aspect_ratio_info_present_flag;
+    public int sar_width;
+    public int sar_height;
+    public boolean overscan_info_present_flag;
+    public boolean overscan_appropriate_flag;
+    public boolean video_signal_type_present_flag;
+    public int video_format;
+    public boolean video_full_range_flag;
+    public boolean colour_description_present_flag;
+    public int colour_primaries;
+    public int transfer_characteristics;
+    public int matrix_coefficients;
+    public boolean chroma_loc_info_present_flag;
+    public int chroma_sample_loc_type_top_field;
+    public int chroma_sample_loc_type_bottom_field;
+    public boolean timing_info_present_flag;
+    public int num_units_in_tick;
+    public int time_scale;
+    public boolean fixed_frame_rate_flag;
+    public boolean low_delay_hrd_flag;
+    public boolean pic_struct_present_flag;
+    public HRDParameters nalHRDParams;
+    public HRDParameters vclHRDParams;
+
+    public BitstreamRestriction bitstreamRestriction;
+    public AspectRatio aspect_ratio;
+
+    @Override
+    public String toString() {
+        return "VUIParameters{" + "\n" +
+                "aspect_ratio_info_present_flag=" + aspect_ratio_info_present_flag + "\n" +
+                ", sar_width=" + sar_width + "\n" +
+                ", sar_height=" + sar_height + "\n" +
+                ", overscan_info_present_flag=" + overscan_info_present_flag + "\n" +
+                ", overscan_appropriate_flag=" + overscan_appropriate_flag + "\n" +
+                ", video_signal_type_present_flag=" + video_signal_type_present_flag + "\n" +
+                ", video_format=" + video_format + "\n" +
+                ", video_full_range_flag=" + video_full_range_flag + "\n" +
+                ", colour_description_present_flag=" + colour_description_present_flag + "\n" +
+                ", colour_primaries=" + colour_primaries + "\n" +
+                ", transfer_characteristics=" + transfer_characteristics + "\n" +
+                ", matrix_coefficients=" + matrix_coefficients + "\n" +
+                ", chroma_loc_info_present_flag=" + chroma_loc_info_present_flag + "\n" +
+                ", chroma_sample_loc_type_top_field=" + chroma_sample_loc_type_top_field + "\n" +
+                ", chroma_sample_loc_type_bottom_field=" + chroma_sample_loc_type_bottom_field + "\n" +
+                ", timing_info_present_flag=" + timing_info_present_flag + "\n" +
+                ", num_units_in_tick=" + num_units_in_tick + "\n" +
+                ", time_scale=" + time_scale + "\n" +
+                ", fixed_frame_rate_flag=" + fixed_frame_rate_flag + "\n" +
+                ", low_delay_hrd_flag=" + low_delay_hrd_flag + "\n" +
+                ", pic_struct_present_flag=" + pic_struct_present_flag + "\n" +
+                ", nalHRDParams=" + nalHRDParams + "\n" +
+                ", vclHRDParams=" + vclHRDParams + "\n" +
+                ", bitstreamRestriction=" + bitstreamRestriction + "\n" +
+                ", aspect_ratio=" + aspect_ratio + "\n" +
+                '}';
+    }
+}
diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/h264/read/.svn/all-wcprops b/isoparser/src/main/java/com/googlecode/mp4parser/h264/read/.svn/all-wcprops
new file mode 100644
index 0000000..39f268a
--- /dev/null
+++ b/isoparser/src/main/java/com/googlecode/mp4parser/h264/read/.svn/all-wcprops
@@ -0,0 +1,17 @@
+K 25
+svn:wc:ra_dav:version-url
+V 82
+/svn/!svn/ver/377/trunk/isoparser/src/main/java/com/googlecode/mp4parser/h264/read
+END
+CAVLCReader.java
+K 25
+svn:wc:ra_dav:version-url
+V 99
+/svn/!svn/ver/377/trunk/isoparser/src/main/java/com/googlecode/mp4parser/h264/read/CAVLCReader.java
+END
+BitstreamReader.java
+K 25
+svn:wc:ra_dav:version-url
+V 103
+/svn/!svn/ver/377/trunk/isoparser/src/main/java/com/googlecode/mp4parser/h264/read/BitstreamReader.java
+END
diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/h264/read/.svn/entries b/isoparser/src/main/java/com/googlecode/mp4parser/h264/read/.svn/entries
new file mode 100644
index 0000000..f0111dc
--- /dev/null
+++ b/isoparser/src/main/java/com/googlecode/mp4parser/h264/read/.svn/entries
@@ -0,0 +1,96 @@
+10
+
+dir
+778
+http://mp4parser.googlecode.com/svn/trunk/isoparser/src/main/java/com/googlecode/mp4parser/h264/read
+http://mp4parser.googlecode.com/svn
+
+
+
+2012-03-05T23:28:24.666173Z
+377
+Sebastian.Annies@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+7decde4b-c250-0410-a0da-51896bc88be6
+
+CAVLCReader.java
+file
+
+
+
+
+2012-09-14T17:27:51.457232Z
+bcd623b178982adc4723a481ed9ee8c8
+2012-03-05T23:28:24.666173Z
+377
+Sebastian.Annies@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+5069
+
+BitstreamReader.java
+file
+
+
+
+
+2012-09-14T17:27:51.457232Z
+0a82a1920e98d55c972bc7e536bfb158
+2012-03-05T23:28:24.666173Z
+377
+Sebastian.Annies@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+4982
+
diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/h264/read/.svn/text-base/BitstreamReader.java.svn-base b/isoparser/src/main/java/com/googlecode/mp4parser/h264/read/.svn/text-base/BitstreamReader.java.svn-base
new file mode 100644
index 0000000..816af6a
--- /dev/null
+++ b/isoparser/src/main/java/com/googlecode/mp4parser/h264/read/.svn/text-base/BitstreamReader.java.svn-base
@@ -0,0 +1,194 @@
+/*
+Copyright (c) 2011 Stanislav Vitvitskiy
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of this
+software and associated documentation files (the "Software"), to deal in the Software
+without restriction, including without limitation the rights to use, copy, modify,
+merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to the following
+conditions:
+
+The above copyright notice and this permission notice shall be included in all copies or
+substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
+INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
+FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
+OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+package com.googlecode.mp4parser.h264.read;
+
+import com.googlecode.mp4parser.h264.CharCache;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+/**
+ * A dummy implementation of H264 RBSP reading
+ *
+ * @author Stanislav Vitvitskiy
+ */
+public class BitstreamReader {
+    private InputStream is;
+    private int curByte;
+    private int nextByte;
+    int nBit;
+    protected static int bitsRead;
+
+    protected CharCache debugBits = new CharCache(50);
+
+    public BitstreamReader(InputStream is) throws IOException {
+        this.is = is;
+        curByte = is.read();
+        nextByte = is.read();
+    }
+
+    /*
+      * (non-Javadoc)
+      *
+      * @see ua.org.jplayer.javcodec.h264.RBSPInputStream#read1Bit()
+      */
+    public int read1Bit() throws IOException {
+        if (nBit == 8) {
+            advance();
+            if (curByte == -1) {
+                return -1;
+            }
+        }
+        int res = (curByte >> (7 - nBit)) & 1;
+        nBit++;
+
+        debugBits.append(res == 0 ? '0' : '1');
+        ++bitsRead;
+
+        return res;
+    }
+
+    /*
+      * (non-Javadoc)
+      *
+      * @see ua.org.jplayer.javcodec.h264.RBSPInputStream#readNBit(int)
+      */
+    public long readNBit(int n) throws IOException {
+        if (n > 64)
+            throw new IllegalArgumentException("Can not readByte more then 64 bit");
+
+        long val = 0;
+
+        for (int i = 0; i < n; i++) {
+            val <<= 1;
+            val |= read1Bit();
+        }
+
+        return val;
+    }
+
+    private void advance() throws IOException {
+        curByte = nextByte;
+        nextByte = is.read();
+        nBit = 0;
+    }
+
+    /*
+      * (non-Javadoc)
+      *
+      * @see ua.org.jplayer.javcodec.h264.RBSPInputStream#readByte()
+      */
+    public int readByte() throws IOException {
+        if (nBit > 0) {
+            advance();
+        }
+
+        int res = curByte;
+
+        advance();
+
+        return res;
+    }
+
+    /*
+      * (non-Javadoc)
+      *
+      * @see ua.org.jplayer.javcodec.h264.RBSPInputStream#moreRBSPData()
+      */
+    public boolean moreRBSPData() throws IOException {
+        if (nBit == 8) {
+            advance();
+        }
+        int tail = 1 << (8 - nBit - 1);
+        int mask = ((tail << 1) - 1);
+        boolean hasTail = (curByte & mask) == tail;
+
+        return !(curByte == -1 || (nextByte == -1 && hasTail));
+    }
+
+    public long getBitPosition() {
+        return (bitsRead * 8 + (nBit % 8));
+    }
+
+    /*
+      * (non-Javadoc)
+      *
+      * @see ua.org.jplayer.javcodec.h264.RBSPInputStream#readRemainingByte()
+      */
+    public long readRemainingByte() throws IOException {
+        return readNBit(8 - nBit);
+    }
+
+    /*
+      * (non-Javadoc)
+      *
+      * @see ua.org.jplayer.javcodec.h264.RBSPInputStream#next_bits(int)
+      */
+    public int peakNextBits(int n) throws IOException {
+        if (n > 8)
+            throw new IllegalArgumentException("N should be less then 8");
+        if (nBit == 8) {
+            advance();
+            if (curByte == -1) {
+                return -1;
+            }
+        }
+        int[] bits = new int[16 - nBit];
+
+        int cnt = 0;
+        for (int i = nBit; i < 8; i++) {
+            bits[cnt++] = (curByte >> (7 - i)) & 0x1;
+        }
+
+        for (int i = 0; i < 8; i++) {
+            bits[cnt++] = (nextByte >> (7 - i)) & 0x1;
+        }
+
+        int result = 0;
+        for (int i = 0; i < n; i++) {
+            result <<= 1;
+            result |= bits[i];
+        }
+
+        return result;
+    }
+
+    /*
+      * (non-Javadoc)
+      *
+      * @see ua.org.jplayer.javcodec.h264.RBSPInputStream#byte_aligned()
+      */
+    public boolean isByteAligned() {
+        return (nBit % 8) == 0;
+    }
+
+    /*
+      * (non-Javadoc)
+      *
+      * @see ua.org.jplayer.javcodec.h264.RBSPInputStream#close()
+      */
+    public void close() throws IOException {
+    }
+
+    public int getCurBit() {
+        return nBit;
+    }
+}
\ No newline at end of file
diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/h264/read/.svn/text-base/CAVLCReader.java.svn-base b/isoparser/src/main/java/com/googlecode/mp4parser/h264/read/.svn/text-base/CAVLCReader.java.svn-base
new file mode 100644
index 0000000..07c7f71
--- /dev/null
+++ b/isoparser/src/main/java/com/googlecode/mp4parser/h264/read/.svn/text-base/CAVLCReader.java.svn-base
@@ -0,0 +1,185 @@
+/*
+Copyright (c) 2011 Stanislav Vitvitskiy
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of this
+software and associated documentation files (the "Software"), to deal in the Software
+without restriction, including without limitation the rights to use, copy, modify,
+merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to the following
+conditions:
+
+The above copyright notice and this permission notice shall be included in all copies or
+substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
+INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
+FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
+OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+package com.googlecode.mp4parser.h264.read;
+
+
+import com.googlecode.mp4parser.h264.BTree;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+import static com.googlecode.mp4parser.h264.Debug.println;
+
+
+public class CAVLCReader extends BitstreamReader {
+
+    public CAVLCReader(InputStream is) throws IOException {
+        super(is);
+    }
+
+    public long readNBit(int n, String message) throws IOException {
+        long val = readNBit(n);
+
+        trace(message, String.valueOf(val));
+
+        return val;
+    }
+
+    /**
+     * Read unsigned exp-golomb code
+     *
+     * @return
+     * @throws java.io.IOException
+     * @throws java.io.IOException
+     */
+    private int readUE() throws IOException {
+        int cnt = 0;
+        while (read1Bit() == 0)
+            cnt++;
+
+        int res = 0;
+        if (cnt > 0) {
+            long val = readNBit(cnt);
+
+            res = (int) ((1 << cnt) - 1 + val);
+        }
+
+        return res;
+    }
+
+    /*
+      * (non-Javadoc)
+      *
+      * @see
+      * ua.org.jplayer.javcodec.h264.H264BitInputStream#readUE(java.lang.String)
+      */
+    public int readUE(String message) throws IOException {
+        int res = readUE();
+
+        trace(message, String.valueOf(res));
+
+        return res;
+    }
+
+    public int readSE(String message) throws IOException {
+        int val = readUE();
+
+        int sign = ((val & 0x1) << 1) - 1;
+        val = ((val >> 1) + (val & 0x1)) * sign;
+
+        trace(message, String.valueOf(val));
+
+        return val;
+    }
+
+    public boolean readBool(String message) throws IOException {
+
+        boolean res = read1Bit() == 0 ? false : true;
+
+        trace(message, res ? "1" : "0");
+
+        return res;
+    }
+
+    public int readU(int i, String string) throws IOException {
+        return (int) readNBit(i, string);
+    }
+
+    public byte[] read(int payloadSize) throws IOException {
+        byte[] result = new byte[payloadSize];
+        for (int i = 0; i < payloadSize; i++) {
+            result[i] = (byte) readByte();
+        }
+        return result;
+    }
+
+    public boolean readAE() {
+        // TODO: do it!!
+        throw new UnsupportedOperationException("Stan");
+    }
+
+    public int readTE(int max) throws IOException {
+        if (max > 1)
+            return readUE();
+        return ~read1Bit() & 0x1;
+    }
+
+    public int readAEI() {
+        // TODO: do it!!
+        throw new UnsupportedOperationException("Stan");
+    }
+
+    public int readME(String string) throws IOException {
+        return readUE(string);
+    }
+
+    public Object readCE(BTree bt, String message) throws IOException {
+        while (true) {
+            int bit = read1Bit();
+            bt = bt.down(bit);
+            if (bt == null) {
+                throw new RuntimeException("Illegal code");
+            }
+            Object i = bt.getValue();
+            if (i != null) {
+                trace(message, i.toString());
+                return i;
+            }
+        }
+    }
+
+    public int readZeroBitCount(String message) throws IOException {
+        int count = 0;
+        while (read1Bit() == 0)
+            count++;
+
+        trace(message, String.valueOf(count));
+
+        return count;
+    }
+
+    public void readTrailingBits() throws IOException {
+        read1Bit();
+        readRemainingByte();
+    }
+
+    private void trace(String message, String val) {
+        StringBuilder traceBuilder = new StringBuilder();
+        int spaces;
+        String pos = String.valueOf(bitsRead - debugBits.length());
+        spaces = 8 - pos.length();
+
+        traceBuilder.append("@" + pos);
+
+        for (int i = 0; i < spaces; i++)
+            traceBuilder.append(' ');
+
+        traceBuilder.append(message);
+        spaces = 100 - traceBuilder.length() - debugBits.length();
+        for (int i = 0; i < spaces; i++)
+            traceBuilder.append(' ');
+        traceBuilder.append(debugBits);
+        traceBuilder.append(" (" + val + ")");
+        debugBits.clear();
+
+        println(traceBuilder.toString());
+    }
+}
\ No newline at end of file
diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/h264/read/BitstreamReader.java b/isoparser/src/main/java/com/googlecode/mp4parser/h264/read/BitstreamReader.java
new file mode 100644
index 0000000..816af6a
--- /dev/null
+++ b/isoparser/src/main/java/com/googlecode/mp4parser/h264/read/BitstreamReader.java
@@ -0,0 +1,194 @@
+/*
+Copyright (c) 2011 Stanislav Vitvitskiy
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of this
+software and associated documentation files (the "Software"), to deal in the Software
+without restriction, including without limitation the rights to use, copy, modify,
+merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to the following
+conditions:
+
+The above copyright notice and this permission notice shall be included in all copies or
+substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
+INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
+FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
+OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+package com.googlecode.mp4parser.h264.read;
+
+import com.googlecode.mp4parser.h264.CharCache;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+/**
+ * A dummy implementation of H264 RBSP reading
+ *
+ * @author Stanislav Vitvitskiy
+ */
+public class BitstreamReader {
+    private InputStream is;
+    private int curByte;
+    private int nextByte;
+    int nBit;
+    protected static int bitsRead;
+
+    protected CharCache debugBits = new CharCache(50);
+
+    public BitstreamReader(InputStream is) throws IOException {
+        this.is = is;
+        curByte = is.read();
+        nextByte = is.read();
+    }
+
+    /*
+      * (non-Javadoc)
+      *
+      * @see ua.org.jplayer.javcodec.h264.RBSPInputStream#read1Bit()
+      */
+    public int read1Bit() throws IOException {
+        if (nBit == 8) {
+            advance();
+            if (curByte == -1) {
+                return -1;
+            }
+        }
+        int res = (curByte >> (7 - nBit)) & 1;
+        nBit++;
+
+        debugBits.append(res == 0 ? '0' : '1');
+        ++bitsRead;
+
+        return res;
+    }
+
+    /*
+      * (non-Javadoc)
+      *
+      * @see ua.org.jplayer.javcodec.h264.RBSPInputStream#readNBit(int)
+      */
+    public long readNBit(int n) throws IOException {
+        if (n > 64)
+            throw new IllegalArgumentException("Can not readByte more then 64 bit");
+
+        long val = 0;
+
+        for (int i = 0; i < n; i++) {
+            val <<= 1;
+            val |= read1Bit();
+        }
+
+        return val;
+    }
+
+    private void advance() throws IOException {
+        curByte = nextByte;
+        nextByte = is.read();
+        nBit = 0;
+    }
+
+    /*
+      * (non-Javadoc)
+      *
+      * @see ua.org.jplayer.javcodec.h264.RBSPInputStream#readByte()
+      */
+    public int readByte() throws IOException {
+        if (nBit > 0) {
+            advance();
+        }
+
+        int res = curByte;
+
+        advance();
+
+        return res;
+    }
+
+    /*
+      * (non-Javadoc)
+      *
+      * @see ua.org.jplayer.javcodec.h264.RBSPInputStream#moreRBSPData()
+      */
+    public boolean moreRBSPData() throws IOException {
+        if (nBit == 8) {
+            advance();
+        }
+        int tail = 1 << (8 - nBit - 1);
+        int mask = ((tail << 1) - 1);
+        boolean hasTail = (curByte & mask) == tail;
+
+        return !(curByte == -1 || (nextByte == -1 && hasTail));
+    }
+
+    public long getBitPosition() {
+        return (bitsRead * 8 + (nBit % 8));
+    }
+
+    /*
+      * (non-Javadoc)
+      *
+      * @see ua.org.jplayer.javcodec.h264.RBSPInputStream#readRemainingByte()
+      */
+    public long readRemainingByte() throws IOException {
+        return readNBit(8 - nBit);
+    }
+
+    /*
+      * (non-Javadoc)
+      *
+      * @see ua.org.jplayer.javcodec.h264.RBSPInputStream#next_bits(int)
+      */
+    public int peakNextBits(int n) throws IOException {
+        if (n > 8)
+            throw new IllegalArgumentException("N should be less then 8");
+        if (nBit == 8) {
+            advance();
+            if (curByte == -1) {
+                return -1;
+            }
+        }
+        int[] bits = new int[16 - nBit];
+
+        int cnt = 0;
+        for (int i = nBit; i < 8; i++) {
+            bits[cnt++] = (curByte >> (7 - i)) & 0x1;
+        }
+
+        for (int i = 0; i < 8; i++) {
+            bits[cnt++] = (nextByte >> (7 - i)) & 0x1;
+        }
+
+        int result = 0;
+        for (int i = 0; i < n; i++) {
+            result <<= 1;
+            result |= bits[i];
+        }
+
+        return result;
+    }
+
+    /*
+      * (non-Javadoc)
+      *
+      * @see ua.org.jplayer.javcodec.h264.RBSPInputStream#byte_aligned()
+      */
+    public boolean isByteAligned() {
+        return (nBit % 8) == 0;
+    }
+
+    /*
+      * (non-Javadoc)
+      *
+      * @see ua.org.jplayer.javcodec.h264.RBSPInputStream#close()
+      */
+    public void close() throws IOException {
+    }
+
+    public int getCurBit() {
+        return nBit;
+    }
+}
\ No newline at end of file
diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/h264/read/CAVLCReader.java b/isoparser/src/main/java/com/googlecode/mp4parser/h264/read/CAVLCReader.java
new file mode 100644
index 0000000..07c7f71
--- /dev/null
+++ b/isoparser/src/main/java/com/googlecode/mp4parser/h264/read/CAVLCReader.java
@@ -0,0 +1,185 @@
+/*
+Copyright (c) 2011 Stanislav Vitvitskiy
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of this
+software and associated documentation files (the "Software"), to deal in the Software
+without restriction, including without limitation the rights to use, copy, modify,
+merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to the following
+conditions:
+
+The above copyright notice and this permission notice shall be included in all copies or
+substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
+INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
+FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
+OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+package com.googlecode.mp4parser.h264.read;
+
+
+import com.googlecode.mp4parser.h264.BTree;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+import static com.googlecode.mp4parser.h264.Debug.println;
+
+
+public class CAVLCReader extends BitstreamReader {
+
+    public CAVLCReader(InputStream is) throws IOException {
+        super(is);
+    }
+
+    public long readNBit(int n, String message) throws IOException {
+        long val = readNBit(n);
+
+        trace(message, String.valueOf(val));
+
+        return val;
+    }
+
+    /**
+     * Read unsigned exp-golomb code
+     *
+     * @return
+     * @throws java.io.IOException
+     * @throws java.io.IOException
+     */
+    private int readUE() throws IOException {
+        int cnt = 0;
+        while (read1Bit() == 0)
+            cnt++;
+
+        int res = 0;
+        if (cnt > 0) {
+            long val = readNBit(cnt);
+
+            res = (int) ((1 << cnt) - 1 + val);
+        }
+
+        return res;
+    }
+
+    /*
+      * (non-Javadoc)
+      *
+      * @see
+      * ua.org.jplayer.javcodec.h264.H264BitInputStream#readUE(java.lang.String)
+      */
+    public int readUE(String message) throws IOException {
+        int res = readUE();
+
+        trace(message, String.valueOf(res));
+
+        return res;
+    }
+
+    public int readSE(String message) throws IOException {
+        int val = readUE();
+
+        int sign = ((val & 0x1) << 1) - 1;
+        val = ((val >> 1) + (val & 0x1)) * sign;
+
+        trace(message, String.valueOf(val));
+
+        return val;
+    }
+
+    public boolean readBool(String message) throws IOException {
+
+        boolean res = read1Bit() == 0 ? false : true;
+
+        trace(message, res ? "1" : "0");
+
+        return res;
+    }
+
+    public int readU(int i, String string) throws IOException {
+        return (int) readNBit(i, string);
+    }
+
+    public byte[] read(int payloadSize) throws IOException {
+        byte[] result = new byte[payloadSize];
+        for (int i = 0; i < payloadSize; i++) {
+            result[i] = (byte) readByte();
+        }
+        return result;
+    }
+
+    public boolean readAE() {
+        // TODO: do it!!
+        throw new UnsupportedOperationException("Stan");
+    }
+
+    public int readTE(int max) throws IOException {
+        if (max > 1)
+            return readUE();
+        return ~read1Bit() & 0x1;
+    }
+
+    public int readAEI() {
+        // TODO: do it!!
+        throw new UnsupportedOperationException("Stan");
+    }
+
+    public int readME(String string) throws IOException {
+        return readUE(string);
+    }
+
+    public Object readCE(BTree bt, String message) throws IOException {
+        while (true) {
+            int bit = read1Bit();
+            bt = bt.down(bit);
+            if (bt == null) {
+                throw new RuntimeException("Illegal code");
+            }
+            Object i = bt.getValue();
+            if (i != null) {
+                trace(message, i.toString());
+                return i;
+            }
+        }
+    }
+
+    public int readZeroBitCount(String message) throws IOException {
+        int count = 0;
+        while (read1Bit() == 0)
+            count++;
+
+        trace(message, String.valueOf(count));
+
+        return count;
+    }
+
+    public void readTrailingBits() throws IOException {
+        read1Bit();
+        readRemainingByte();
+    }
+
+    private void trace(String message, String val) {
+        StringBuilder traceBuilder = new StringBuilder();
+        int spaces;
+        String pos = String.valueOf(bitsRead - debugBits.length());
+        spaces = 8 - pos.length();
+
+        traceBuilder.append("@" + pos);
+
+        for (int i = 0; i < spaces; i++)
+            traceBuilder.append(' ');
+
+        traceBuilder.append(message);
+        spaces = 100 - traceBuilder.length() - debugBits.length();
+        for (int i = 0; i < spaces; i++)
+            traceBuilder.append(' ');
+        traceBuilder.append(debugBits);
+        traceBuilder.append(" (" + val + ")");
+        debugBits.clear();
+
+        println(traceBuilder.toString());
+    }
+}
\ No newline at end of file
diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/h264/write/.svn/all-wcprops b/isoparser/src/main/java/com/googlecode/mp4parser/h264/write/.svn/all-wcprops
new file mode 100644
index 0000000..eb9d014
--- /dev/null
+++ b/isoparser/src/main/java/com/googlecode/mp4parser/h264/write/.svn/all-wcprops
@@ -0,0 +1,17 @@
+K 25
+svn:wc:ra_dav:version-url
+V 83
+/svn/!svn/ver/236/trunk/isoparser/src/main/java/com/googlecode/mp4parser/h264/write
+END
+CAVLCWriter.java
+K 25
+svn:wc:ra_dav:version-url
+V 100
+/svn/!svn/ver/236/trunk/isoparser/src/main/java/com/googlecode/mp4parser/h264/write/CAVLCWriter.java
+END
+BitstreamWriter.java
+K 25
+svn:wc:ra_dav:version-url
+V 104
+/svn/!svn/ver/236/trunk/isoparser/src/main/java/com/googlecode/mp4parser/h264/write/BitstreamWriter.java
+END
diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/h264/write/.svn/entries b/isoparser/src/main/java/com/googlecode/mp4parser/h264/write/.svn/entries
new file mode 100644
index 0000000..17c897c
--- /dev/null
+++ b/isoparser/src/main/java/com/googlecode/mp4parser/h264/write/.svn/entries
@@ -0,0 +1,96 @@
+10
+
+dir
+778
+http://mp4parser.googlecode.com/svn/trunk/isoparser/src/main/java/com/googlecode/mp4parser/h264/write
+http://mp4parser.googlecode.com/svn
+
+
+
+2011-09-20T18:03:23.375910Z
+236
+Sebastian.Annies@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+7decde4b-c250-0410-a0da-51896bc88be6
+
+CAVLCWriter.java
+file
+
+
+
+
+2012-09-14T17:27:51.397232Z
+466f7fb1a81ac3195414706a32abdee2
+2011-09-20T18:03:23.375910Z
+236
+Sebastian.Annies@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+3214
+
+BitstreamWriter.java
+file
+
+
+
+
+2012-09-14T17:27:51.397232Z
+816b2b532d6ccee0eda214f86cde8ebc
+2011-09-20T18:03:23.375910Z
+236
+Sebastian.Annies@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+3192
+
diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/h264/write/.svn/text-base/BitstreamWriter.java.svn-base b/isoparser/src/main/java/com/googlecode/mp4parser/h264/write/.svn/text-base/BitstreamWriter.java.svn-base
new file mode 100644
index 0000000..b382400
--- /dev/null
+++ b/isoparser/src/main/java/com/googlecode/mp4parser/h264/write/.svn/text-base/BitstreamWriter.java.svn-base
@@ -0,0 +1,108 @@
+/*
+Copyright (c) 2011 Stanislav Vitvitskiy
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of this
+software and associated documentation files (the "Software"), to deal in the Software
+without restriction, including without limitation the rights to use, copy, modify,
+merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to the following
+conditions:
+
+The above copyright notice and this permission notice shall be included in all copies or
+substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
+INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
+FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
+OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+package com.googlecode.mp4parser.h264.write;
+
+import com.googlecode.mp4parser.h264.Debug;
+
+import java.io.IOException;
+import java.io.OutputStream;
+
+/**
+ * A dummy implementation of H264 RBSP output stream
+ *
+ * @author Stanislav Vitvitskiy
+ */
+public class BitstreamWriter {
+
+    private final OutputStream os;
+    private int[] curByte = new int[8];
+    private int curBit;
+
+    public BitstreamWriter(OutputStream out) {
+        this.os = out;
+    }
+
+    /*
+     * (non-Javadoc)
+     * 
+     * @see ua.org.jplayer.javcodec.h264.H264BitOutputStream#flush()
+     */
+    public void flush() throws IOException {
+        for (int i = curBit; i < 8; i++) {
+            curByte[i] = 0;
+        }
+        curBit = 0;
+        writeCurByte();
+    }
+
+    private void writeCurByte() throws IOException {
+        int toWrite = (curByte[0] << 7) | (curByte[1] << 6) | (curByte[2] << 5)
+                | (curByte[3] << 4) | (curByte[4] << 3) | (curByte[5] << 2)
+                | (curByte[6] << 1) | curByte[7];
+        os.write(toWrite);
+    }
+
+    /*
+     * (non-Javadoc)
+     * 
+     * @see ua.org.jplayer.javcodec.h264.H264BitOutputStream#write1Bit(int)
+     */
+    public void write1Bit(int value) throws IOException {
+        Debug.print(value);
+        if (curBit == 8) {
+            curBit = 0;
+            writeCurByte();
+        }
+        curByte[curBit++] = value;
+    }
+
+    /*
+     * (non-Javadoc)
+     * 
+     * @see ua.org.jplayer.javcodec.h264.H264BitOutputStream#writeNBit(long,
+     * int)
+     */
+    public void writeNBit(long value, int n) throws IOException {
+        for (int i = 0; i < n; i++) {
+            write1Bit((int) (value >> (n - i - 1)) & 0x1);
+        }
+    }
+
+    /*
+     * (non-Javadoc)
+     * 
+     * @see
+     * ua.org.jplayer.javcodec.h264.H264BitOutputStream#writeRemainingZero()
+     */
+    public void writeRemainingZero() throws IOException {
+        writeNBit(0, 8 - curBit);
+    }
+
+    /*
+     * (non-Javadoc)
+     * 
+     * @see ua.org.jplayer.javcodec.h264.H264BitOutputStream#writeByte(int)
+     */
+    public void writeByte(int b) throws IOException {
+        os.write(b);
+
+    }
+}
\ No newline at end of file
diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/h264/write/.svn/text-base/CAVLCWriter.java.svn-base b/isoparser/src/main/java/com/googlecode/mp4parser/h264/write/.svn/text-base/CAVLCWriter.java.svn-base
new file mode 100644
index 0000000..c4e0026
--- /dev/null
+++ b/isoparser/src/main/java/com/googlecode/mp4parser/h264/write/.svn/text-base/CAVLCWriter.java.svn-base
@@ -0,0 +1,100 @@
+/*
+Copyright (c) 2011 Stanislav Vitvitskiy
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of this
+software and associated documentation files (the "Software"), to deal in the Software
+without restriction, including without limitation the rights to use, copy, modify,
+merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to the following
+conditions:
+
+The above copyright notice and this permission notice shall be included in all copies or
+substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
+INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
+FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
+OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+package com.googlecode.mp4parser.h264.write;
+
+import com.googlecode.mp4parser.h264.Debug;
+
+import java.io.IOException;
+import java.io.OutputStream;
+
+
+/**
+ * A class responsible for outputting exp-Golumb values into binary stream
+ *
+ * @author Stanislav Vitvitskiy
+ */
+public class CAVLCWriter extends BitstreamWriter {
+
+    public CAVLCWriter(OutputStream out) {
+        super(out);
+    }
+
+    public void writeU(int value, int n, String string) throws IOException {
+        Debug.print(string + "\t");
+        writeNBit(value, n);
+        Debug.println("\t" + value);
+    }
+
+    public void writeUE(int value) throws IOException {
+        int bits = 0;
+        int cumul = 0;
+        for (int i = 0; i < 15; i++) {
+            if (value < cumul + (1 << i)) {
+                bits = i;
+                break;
+            }
+            cumul += (1 << i);
+        }
+        writeNBit(0, bits);
+        write1Bit(1);
+        writeNBit(value - cumul, bits);
+    }
+
+    public void writeUE(int value, String string) throws IOException {
+        Debug.print(string + "\t");
+        writeUE(value);
+        Debug.println("\t" + value);
+    }
+
+    public void writeSE(int value, String string) throws IOException {
+        Debug.print(string + "\t");
+        writeUE((value << 1) * (value < 0 ? -1 : 1) + (value > 0 ? 1 : 0));
+        Debug.println("\t" + value);
+    }
+
+    public void writeBool(boolean value, String string) throws IOException {
+        Debug.print(string + "\t");
+        write1Bit(value ? 1 : 0);
+        Debug.println("\t" + value);
+    }
+
+    public void writeU(int i, int n) throws IOException {
+        writeNBit(i, n);
+    }
+
+    public void writeNBit(long value, int n, String string) throws IOException {
+        Debug.print(string + "\t");
+        for (int i = 0; i < n; i++) {
+            write1Bit((int) (value >> (n - i - 1)) & 0x1);
+        }
+        Debug.println("\t" + value);
+    }
+
+    public void writeTrailingBits() throws IOException {
+        write1Bit(1);
+        writeRemainingZero();
+        flush();
+    }
+
+    public void writeSliceTrailingBits() {
+        throw new IllegalStateException("todo");
+    }
+}
\ No newline at end of file
diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/h264/write/BitstreamWriter.java b/isoparser/src/main/java/com/googlecode/mp4parser/h264/write/BitstreamWriter.java
new file mode 100644
index 0000000..b382400
--- /dev/null
+++ b/isoparser/src/main/java/com/googlecode/mp4parser/h264/write/BitstreamWriter.java
@@ -0,0 +1,108 @@
+/*
+Copyright (c) 2011 Stanislav Vitvitskiy
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of this
+software and associated documentation files (the "Software"), to deal in the Software
+without restriction, including without limitation the rights to use, copy, modify,
+merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to the following
+conditions:
+
+The above copyright notice and this permission notice shall be included in all copies or
+substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
+INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
+FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
+OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+package com.googlecode.mp4parser.h264.write;
+
+import com.googlecode.mp4parser.h264.Debug;
+
+import java.io.IOException;
+import java.io.OutputStream;
+
+/**
+ * A dummy implementation of H264 RBSP output stream
+ *
+ * @author Stanislav Vitvitskiy
+ */
+public class BitstreamWriter {
+
+    private final OutputStream os;
+    private int[] curByte = new int[8];
+    private int curBit;
+
+    public BitstreamWriter(OutputStream out) {
+        this.os = out;
+    }
+
+    /*
+     * (non-Javadoc)
+     * 
+     * @see ua.org.jplayer.javcodec.h264.H264BitOutputStream#flush()
+     */
+    public void flush() throws IOException {
+        for (int i = curBit; i < 8; i++) {
+            curByte[i] = 0;
+        }
+        curBit = 0;
+        writeCurByte();
+    }
+
+    private void writeCurByte() throws IOException {
+        int toWrite = (curByte[0] << 7) | (curByte[1] << 6) | (curByte[2] << 5)
+                | (curByte[3] << 4) | (curByte[4] << 3) | (curByte[5] << 2)
+                | (curByte[6] << 1) | curByte[7];
+        os.write(toWrite);
+    }
+
+    /*
+     * (non-Javadoc)
+     * 
+     * @see ua.org.jplayer.javcodec.h264.H264BitOutputStream#write1Bit(int)
+     */
+    public void write1Bit(int value) throws IOException {
+        Debug.print(value);
+        if (curBit == 8) {
+            curBit = 0;
+            writeCurByte();
+        }
+        curByte[curBit++] = value;
+    }
+
+    /*
+     * (non-Javadoc)
+     * 
+     * @see ua.org.jplayer.javcodec.h264.H264BitOutputStream#writeNBit(long,
+     * int)
+     */
+    public void writeNBit(long value, int n) throws IOException {
+        for (int i = 0; i < n; i++) {
+            write1Bit((int) (value >> (n - i - 1)) & 0x1);
+        }
+    }
+
+    /*
+     * (non-Javadoc)
+     * 
+     * @see
+     * ua.org.jplayer.javcodec.h264.H264BitOutputStream#writeRemainingZero()
+     */
+    public void writeRemainingZero() throws IOException {
+        writeNBit(0, 8 - curBit);
+    }
+
+    /*
+     * (non-Javadoc)
+     * 
+     * @see ua.org.jplayer.javcodec.h264.H264BitOutputStream#writeByte(int)
+     */
+    public void writeByte(int b) throws IOException {
+        os.write(b);
+
+    }
+}
\ No newline at end of file
diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/h264/write/CAVLCWriter.java b/isoparser/src/main/java/com/googlecode/mp4parser/h264/write/CAVLCWriter.java
new file mode 100644
index 0000000..c4e0026
--- /dev/null
+++ b/isoparser/src/main/java/com/googlecode/mp4parser/h264/write/CAVLCWriter.java
@@ -0,0 +1,100 @@
+/*
+Copyright (c) 2011 Stanislav Vitvitskiy
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of this
+software and associated documentation files (the "Software"), to deal in the Software
+without restriction, including without limitation the rights to use, copy, modify,
+merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to the following
+conditions:
+
+The above copyright notice and this permission notice shall be included in all copies or
+substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
+INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
+FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
+OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+package com.googlecode.mp4parser.h264.write;
+
+import com.googlecode.mp4parser.h264.Debug;
+
+import java.io.IOException;
+import java.io.OutputStream;
+
+
+/**
+ * A class responsible for outputting exp-Golumb values into binary stream
+ *
+ * @author Stanislav Vitvitskiy
+ */
+public class CAVLCWriter extends BitstreamWriter {
+
+    public CAVLCWriter(OutputStream out) {
+        super(out);
+    }
+
+    public void writeU(int value, int n, String string) throws IOException {
+        Debug.print(string + "\t");
+        writeNBit(value, n);
+        Debug.println("\t" + value);
+    }
+
+    public void writeUE(int value) throws IOException {
+        int bits = 0;
+        int cumul = 0;
+        for (int i = 0; i < 15; i++) {
+            if (value < cumul + (1 << i)) {
+                bits = i;
+                break;
+            }
+            cumul += (1 << i);
+        }
+        writeNBit(0, bits);
+        write1Bit(1);
+        writeNBit(value - cumul, bits);
+    }
+
+    public void writeUE(int value, String string) throws IOException {
+        Debug.print(string + "\t");
+        writeUE(value);
+        Debug.println("\t" + value);
+    }
+
+    public void writeSE(int value, String string) throws IOException {
+        Debug.print(string + "\t");
+        writeUE((value << 1) * (value < 0 ? -1 : 1) + (value > 0 ? 1 : 0));
+        Debug.println("\t" + value);
+    }
+
+    public void writeBool(boolean value, String string) throws IOException {
+        Debug.print(string + "\t");
+        write1Bit(value ? 1 : 0);
+        Debug.println("\t" + value);
+    }
+
+    public void writeU(int i, int n) throws IOException {
+        writeNBit(i, n);
+    }
+
+    public void writeNBit(long value, int n, String string) throws IOException {
+        Debug.print(string + "\t");
+        for (int i = 0; i < n; i++) {
+            write1Bit((int) (value >> (n - i - 1)) & 0x1);
+        }
+        Debug.println("\t" + value);
+    }
+
+    public void writeTrailingBits() throws IOException {
+        write1Bit(1);
+        writeRemainingZero();
+        flush();
+    }
+
+    public void writeSliceTrailingBits() {
+        throw new IllegalStateException("todo");
+    }
+}
\ No newline at end of file
diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/srt/.svn/all-wcprops b/isoparser/src/main/java/com/googlecode/mp4parser/srt/.svn/all-wcprops
new file mode 100644
index 0000000..47e82bc
--- /dev/null
+++ b/isoparser/src/main/java/com/googlecode/mp4parser/srt/.svn/all-wcprops
@@ -0,0 +1,11 @@
+K 25
+svn:wc:ra_dav:version-url
+V 76
+/svn/!svn/ver/242/trunk/isoparser/src/main/java/com/googlecode/mp4parser/srt
+END
+SrtParser.java
+K 25
+svn:wc:ra_dav:version-url
+V 91
+/svn/!svn/ver/242/trunk/isoparser/src/main/java/com/googlecode/mp4parser/srt/SrtParser.java
+END
diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/srt/.svn/entries b/isoparser/src/main/java/com/googlecode/mp4parser/srt/.svn/entries
new file mode 100644
index 0000000..9f98b72
--- /dev/null
+++ b/isoparser/src/main/java/com/googlecode/mp4parser/srt/.svn/entries
@@ -0,0 +1,62 @@
+10
+
+dir
+778
+http://mp4parser.googlecode.com/svn/trunk/isoparser/src/main/java/com/googlecode/mp4parser/srt
+http://mp4parser.googlecode.com/svn
+
+
+
+2011-10-15T21:10:20.063570Z
+242
+Sebastian.Annies@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+7decde4b-c250-0410-a0da-51896bc88be6
+
+SrtParser.java
+file
+
+
+
+
+2012-09-14T17:27:51.527233Z
+fc7724dd7559c66f7843417fcdea2d12
+2011-10-15T21:10:20.063570Z
+242
+Sebastian.Annies@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+2127
+
diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/srt/.svn/text-base/SrtParser.java.svn-base b/isoparser/src/main/java/com/googlecode/mp4parser/srt/.svn/text-base/SrtParser.java.svn-base
new file mode 100644
index 0000000..3e3a3b9
--- /dev/null
+++ b/isoparser/src/main/java/com/googlecode/mp4parser/srt/.svn/text-base/SrtParser.java.svn-base
@@ -0,0 +1,59 @@
+/*
+ * 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.srt;
+
+import com.googlecode.mp4parser.authoring.tracks.TextTrackImpl;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.LineNumberReader;
+
+/**
+ * Parses a .srt file and creates a Track for it.
+ */
+public class SrtParser {
+    public static TextTrackImpl parse(InputStream is) throws IOException {
+        LineNumberReader r = new LineNumberReader(new InputStreamReader(is, "UTF-8"));
+        TextTrackImpl track = new TextTrackImpl();
+        String numberString;
+        while ((numberString = r.readLine()) != null) {
+            String timeString = r.readLine();
+            String lineString = "";
+            String s;
+            while (!((s = r.readLine()) == null || s.trim().equals(""))) {
+                lineString += s + "\n";
+            }
+
+            long startTime = parse(timeString.split("-->")[0]);
+            long endTime = parse(timeString.split("-->")[1]);
+
+            track.getSubs().add(new TextTrackImpl.Line(startTime, endTime, lineString));
+
+        }
+        return track;
+    }
+
+    private static long parse(String in) {
+        long hours = Long.parseLong(in.split(":")[0].trim());
+        long minutes = Long.parseLong(in.split(":")[1].trim());
+        long seconds = Long.parseLong(in.split(":")[2].split(",")[0].trim());
+        long millies = Long.parseLong(in.split(":")[2].split(",")[1].trim());
+
+        return hours * 60 * 60 * 1000 + minutes * 60 * 1000 + seconds * 1000 + millies;
+
+    }
+}
diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/srt/SrtParser.java b/isoparser/src/main/java/com/googlecode/mp4parser/srt/SrtParser.java
new file mode 100644
index 0000000..3e3a3b9
--- /dev/null
+++ b/isoparser/src/main/java/com/googlecode/mp4parser/srt/SrtParser.java
@@ -0,0 +1,59 @@
+/*
+ * 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.srt;
+
+import com.googlecode.mp4parser.authoring.tracks.TextTrackImpl;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.LineNumberReader;
+
+/**
+ * Parses a .srt file and creates a Track for it.
+ */
+public class SrtParser {
+    public static TextTrackImpl parse(InputStream is) throws IOException {
+        LineNumberReader r = new LineNumberReader(new InputStreamReader(is, "UTF-8"));
+        TextTrackImpl track = new TextTrackImpl();
+        String numberString;
+        while ((numberString = r.readLine()) != null) {
+            String timeString = r.readLine();
+            String lineString = "";
+            String s;
+            while (!((s = r.readLine()) == null || s.trim().equals(""))) {
+                lineString += s + "\n";
+            }
+
+            long startTime = parse(timeString.split("-->")[0]);
+            long endTime = parse(timeString.split("-->")[1]);
+
+            track.getSubs().add(new TextTrackImpl.Line(startTime, endTime, lineString));
+
+        }
+        return track;
+    }
+
+    private static long parse(String in) {
+        long hours = Long.parseLong(in.split(":")[0].trim());
+        long minutes = Long.parseLong(in.split(":")[1].trim());
+        long seconds = Long.parseLong(in.split(":")[2].split(",")[0].trim());
+        long millies = Long.parseLong(in.split(":")[2].split(",")[1].trim());
+
+        return hours * 60 * 60 * 1000 + minutes * 60 * 1000 + seconds * 1000 + millies;
+
+    }
+}
diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/util/.svn/all-wcprops b/isoparser/src/main/java/com/googlecode/mp4parser/util/.svn/all-wcprops
new file mode 100644
index 0000000..6decd2f
--- /dev/null
+++ b/isoparser/src/main/java/com/googlecode/mp4parser/util/.svn/all-wcprops
@@ -0,0 +1,35 @@
+K 25
+svn:wc:ra_dav:version-url
+V 77
+/svn/!svn/ver/647/trunk/isoparser/src/main/java/com/googlecode/mp4parser/util
+END
+Math.java
+K 25
+svn:wc:ra_dav:version-url
+V 87
+/svn/!svn/ver/591/trunk/isoparser/src/main/java/com/googlecode/mp4parser/util/Math.java
+END
+ByteBufferByteChannel.java
+K 25
+svn:wc:ra_dav:version-url
+V 104
+/svn/!svn/ver/505/trunk/isoparser/src/main/java/com/googlecode/mp4parser/util/ByteBufferByteChannel.java
+END
+CastUtils.java
+K 25
+svn:wc:ra_dav:version-url
+V 92
+/svn/!svn/ver/505/trunk/isoparser/src/main/java/com/googlecode/mp4parser/util/CastUtils.java
+END
+Path.java
+K 25
+svn:wc:ra_dav:version-url
+V 87
+/svn/!svn/ver/647/trunk/isoparser/src/main/java/com/googlecode/mp4parser/util/Path.java
+END
+UUIDConverter.java
+K 25
+svn:wc:ra_dav:version-url
+V 96
+/svn/!svn/ver/418/trunk/isoparser/src/main/java/com/googlecode/mp4parser/util/UUIDConverter.java
+END
diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/util/.svn/entries b/isoparser/src/main/java/com/googlecode/mp4parser/util/.svn/entries
new file mode 100644
index 0000000..df7f2b0
--- /dev/null
+++ b/isoparser/src/main/java/com/googlecode/mp4parser/util/.svn/entries
@@ -0,0 +1,198 @@
+10
+
+dir
+778
+http://mp4parser.googlecode.com/svn/trunk/isoparser/src/main/java/com/googlecode/mp4parser/util
+http://mp4parser.googlecode.com/svn
+
+
+
+2012-05-27T05:36:06.980381Z
+647
+Sebastian.Annies@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+7decde4b-c250-0410-a0da-51896bc88be6
+
+Math.java
+file
+
+
+
+
+2012-09-14T17:27:51.667235Z
+be07b5a338a5ad8f6491ffec0f4d5e11
+2012-05-07T16:21:15.288279Z
+591
+Sebastian.Annies@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+619
+
+ByteBufferByteChannel.java
+file
+
+
+
+
+2012-09-14T17:27:51.667235Z
+8e8bdec08e05ef5d4dbeb46b7e1d35c2
+2012-04-21T21:18:31.685061Z
+505
+Sebastian.Annies@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+1654
+
+CastUtils.java
+file
+
+
+
+
+2012-09-14T17:27:51.667235Z
+8cda078221f55ca06cf0cdc49e2cbbba
+2012-04-21T21:18:31.685061Z
+505
+Sebastian.Annies@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+1326
+
+Path.java
+file
+
+
+
+
+2012-09-14T17:27:51.667235Z
+f0ae3de018d1fb2645b0eb2beefeeb01
+2012-05-27T05:36:06.980381Z
+647
+Sebastian.Annies@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+3884
+
+UUIDConverter.java
+file
+
+
+
+
+2012-09-14T17:27:51.667235Z
+d9d8f271318ba9ee779efd10904d7ad3
+2012-03-11T20:54:45.638478Z
+418
+Sebastian.Annies@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+1413
+
diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/util/.svn/text-base/ByteBufferByteChannel.java.svn-base b/isoparser/src/main/java/com/googlecode/mp4parser/util/.svn/text-base/ByteBufferByteChannel.java.svn-base
new file mode 100644
index 0000000..9f3264b
--- /dev/null
+++ b/isoparser/src/main/java/com/googlecode/mp4parser/util/.svn/text-base/ByteBufferByteChannel.java.svn-base
@@ -0,0 +1,56 @@
+/*
+ * Copyright 2012 Sebastian Annies, Hamburg
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.googlecode.mp4parser.util;
+
+import java.io.EOFException;
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.nio.channels.ByteChannel;
+
+/**
+ * Creates a <code>ReadableByteChannel</code> that is backed by a <code>ByteBuffer</code>.
+ */
+public class ByteBufferByteChannel implements ByteChannel {
+    ByteBuffer byteBuffer;
+
+    public ByteBufferByteChannel(ByteBuffer byteBuffer) {
+        this.byteBuffer = byteBuffer;
+    }
+
+    public int read(ByteBuffer dst) throws IOException {
+        byte[] b = dst.array();
+        int r = dst.remaining();
+        if (byteBuffer.remaining() >= r) {
+            byteBuffer.get(b, dst.position(), r);
+            return r;
+        } else {
+            throw new EOFException("Reading beyond end of stream");
+        }
+    }
+
+    public boolean isOpen() {
+        return true;
+    }
+
+    public void close() throws IOException {
+    }
+
+    public int write(ByteBuffer src) throws IOException {
+        int r = src.remaining();
+        byteBuffer.put(src);
+        return r;
+    }
+}
diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/util/.svn/text-base/CastUtils.java.svn-base b/isoparser/src/main/java/com/googlecode/mp4parser/util/.svn/text-base/CastUtils.java.svn-base
new file mode 100644
index 0000000..2dd011a
--- /dev/null
+++ b/isoparser/src/main/java/com/googlecode/mp4parser/util/.svn/text-base/CastUtils.java.svn-base
@@ -0,0 +1,34 @@
+/*
+ * Copyright 2012 Sebastian Annies, Hamburg
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.googlecode.mp4parser.util;
+
+
+public class CastUtils {
+    /**
+     * Casts a long to an int. In many cases I use a long for a UInt32 but this cannot be used to allocate
+     * ByteBuffers or arrays since they restricted to <code>Integer.MAX_VALUE</code> this cast-method will throw
+     * a RuntimeException if the cast would cause a loss of information.
+     *
+     * @param l the long value
+     * @return the long value as int
+     */
+    public static int l2i(long l) {
+        if (l > Integer.MAX_VALUE || l < Integer.MIN_VALUE) {
+            throw new RuntimeException("A cast to int has gone wrong. Please contact the mp4parser discussion group (" + l + ")");
+        }
+        return (int) l;
+    }
+}
diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/util/.svn/text-base/Math.java.svn-base b/isoparser/src/main/java/com/googlecode/mp4parser/util/.svn/text-base/Math.java.svn-base
new file mode 100644
index 0000000..27fd4b2
--- /dev/null
+++ b/isoparser/src/main/java/com/googlecode/mp4parser/util/.svn/text-base/Math.java.svn-base
@@ -0,0 +1,30 @@
+package com.googlecode.mp4parser.util;
+
+public class Math {
+    public static long gcd(long a, long b) {
+        while (b > 0) {
+            long temp = b;
+            b = a % b; // % is remainder
+            a = temp;
+        }
+        return a;
+    }
+
+    public static int gcd(int a, int b) {
+        while (b > 0) {
+            int temp = b;
+            b = a % b; // % is remainder
+            a = temp;
+        }
+        return a;
+    }
+
+    public static long lcm(long a, long b) {
+        return a * (b / gcd(a, b));
+    }
+
+    public static int lcm(int a, int b) {
+        return a * (b / gcd(a, b));
+    }
+
+}
diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/util/.svn/text-base/Path.java.svn-base b/isoparser/src/main/java/com/googlecode/mp4parser/util/.svn/text-base/Path.java.svn-base
new file mode 100644
index 0000000..a6066c8
--- /dev/null
+++ b/isoparser/src/main/java/com/googlecode/mp4parser/util/.svn/text-base/Path.java.svn-base
@@ -0,0 +1,115 @@
+/*
+ * Copyright 2012 Sebastian Annies, Hamburg
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.googlecode.mp4parser.util;
+
+
+import com.coremedia.iso.IsoFile;
+import com.coremedia.iso.boxes.Box;
+import com.coremedia.iso.boxes.ContainerBox;
+
+import java.util.Collections;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+public class Path {
+
+    private Path() {
+    }
+
+    static Pattern component = Pattern.compile("(....|\\.\\.)(\\[(.*)\\])?");
+
+    public static String createPath(Box box) {
+        return createPath(box, "");
+    }
+
+    private static String createPath(Box box, String path) {
+        if (box instanceof IsoFile) {
+            return path;
+        } else {
+            List<?> boxesOfBoxType = box.getParent().getBoxes(box.getClass());
+            int index = boxesOfBoxType.indexOf(box);
+            path = String.format("/%s[%d]", box.getType(), index) + path;
+
+            return createPath(box.getParent(), path);
+        }
+    }
+
+    public static Box getPath(Box box, String path) {
+        List<Box> all = getPaths(box, path);
+        return all.isEmpty() ? null : all.get(0);
+    }
+
+
+    public static List<Box> getPaths(Box box, String path) {
+        if (path.startsWith("/")) {
+            Box isoFile = box;
+            while (isoFile.getParent() != null) {
+                isoFile = isoFile.getParent();
+            }
+            assert isoFile instanceof IsoFile : isoFile.getType() + " has no parent";
+            return getPaths(isoFile, path.substring(1));
+        } else if (path.isEmpty()) {
+            return Collections.singletonList(box);
+        } else {
+            String later;
+            String now;
+            if (path.contains("/")) {
+                later = path.substring(path.indexOf('/') + 1);
+                now = path.substring(0, path.indexOf('/'));
+            } else {
+                now = path;
+                later = "";
+            }
+
+            Matcher m = component.matcher(now);
+            if (m.matches()) {
+                String type = m.group(1);
+                if ("..".equals(type)) {
+                    return getPaths(box.getParent(), later);
+                } else {
+                    int index = -1;
+                    if (m.group(2) != null) {
+                        // we have a specific index
+                        String indexString = m.group(3);
+                        index = Integer.parseInt(indexString);
+                    }
+                    List<Box> children = new LinkedList<Box>();
+                    int currentIndex = 0;
+                    for (Box box1 : ((ContainerBox) box).getBoxes()) {
+                        if (box1.getType().matches(type)) {
+                            if (index == -1 || index == currentIndex) {
+                                children.addAll(getPaths(box1, later));
+                            }
+                            currentIndex++;
+                        }
+                    }
+                    return children;
+                }
+            } else {
+                throw new RuntimeException(now + " is invalid path.");
+            }
+        }
+
+    }
+
+
+    public static boolean isContained(Box box, String path) {
+        assert path.startsWith("/") : "Absolute path required";
+        return getPaths(box, path).contains(box);
+    }
+}
diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/util/.svn/text-base/UUIDConverter.java.svn-base b/isoparser/src/main/java/com/googlecode/mp4parser/util/.svn/text-base/UUIDConverter.java.svn-base
new file mode 100644
index 0000000..635e4c1
--- /dev/null
+++ b/isoparser/src/main/java/com/googlecode/mp4parser/util/.svn/text-base/UUIDConverter.java.svn-base
@@ -0,0 +1,48 @@
+/*
+ * Copyright 2012 Sebastian Annies, Hamburg
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.googlecode.mp4parser.util;
+
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.util.UUID;
+
+/**
+ * UUID from/to byte array.
+ */
+public class UUIDConverter {
+    public static byte[] convert(UUID uuid) {
+
+        long msb = uuid.getMostSignificantBits();
+        long lsb = uuid.getLeastSignificantBits();
+        byte[] buffer = new byte[16];
+
+        for (int i = 0; i < 8; i++) {
+            buffer[i] = (byte) (msb >>> 8 * (7 - i));
+        }
+        for (int i = 8; i < 16; i++) {
+            buffer[i] = (byte) (lsb >>> 8 * (7 - i));
+        }
+
+        return buffer;
+
+    }
+
+    public static UUID convert(byte[] uuidBytes) {
+        ByteBuffer b = ByteBuffer.wrap(uuidBytes);
+        b.order(ByteOrder.BIG_ENDIAN);
+        return new UUID(b.getLong(), b.getLong());
+    }
+}
diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/util/ByteBufferByteChannel.java b/isoparser/src/main/java/com/googlecode/mp4parser/util/ByteBufferByteChannel.java
new file mode 100644
index 0000000..9f3264b
--- /dev/null
+++ b/isoparser/src/main/java/com/googlecode/mp4parser/util/ByteBufferByteChannel.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright 2012 Sebastian Annies, Hamburg
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.googlecode.mp4parser.util;
+
+import java.io.EOFException;
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.nio.channels.ByteChannel;
+
+/**
+ * Creates a <code>ReadableByteChannel</code> that is backed by a <code>ByteBuffer</code>.
+ */
+public class ByteBufferByteChannel implements ByteChannel {
+    ByteBuffer byteBuffer;
+
+    public ByteBufferByteChannel(ByteBuffer byteBuffer) {
+        this.byteBuffer = byteBuffer;
+    }
+
+    public int read(ByteBuffer dst) throws IOException {
+        byte[] b = dst.array();
+        int r = dst.remaining();
+        if (byteBuffer.remaining() >= r) {
+            byteBuffer.get(b, dst.position(), r);
+            return r;
+        } else {
+            throw new EOFException("Reading beyond end of stream");
+        }
+    }
+
+    public boolean isOpen() {
+        return true;
+    }
+
+    public void close() throws IOException {
+    }
+
+    public int write(ByteBuffer src) throws IOException {
+        int r = src.remaining();
+        byteBuffer.put(src);
+        return r;
+    }
+}
diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/util/CastUtils.java b/isoparser/src/main/java/com/googlecode/mp4parser/util/CastUtils.java
new file mode 100644
index 0000000..2dd011a
--- /dev/null
+++ b/isoparser/src/main/java/com/googlecode/mp4parser/util/CastUtils.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright 2012 Sebastian Annies, Hamburg
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.googlecode.mp4parser.util;
+
+
+public class CastUtils {
+    /**
+     * Casts a long to an int. In many cases I use a long for a UInt32 but this cannot be used to allocate
+     * ByteBuffers or arrays since they restricted to <code>Integer.MAX_VALUE</code> this cast-method will throw
+     * a RuntimeException if the cast would cause a loss of information.
+     *
+     * @param l the long value
+     * @return the long value as int
+     */
+    public static int l2i(long l) {
+        if (l > Integer.MAX_VALUE || l < Integer.MIN_VALUE) {
+            throw new RuntimeException("A cast to int has gone wrong. Please contact the mp4parser discussion group (" + l + ")");
+        }
+        return (int) l;
+    }
+}
diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/util/Math.java b/isoparser/src/main/java/com/googlecode/mp4parser/util/Math.java
new file mode 100644
index 0000000..27fd4b2
--- /dev/null
+++ b/isoparser/src/main/java/com/googlecode/mp4parser/util/Math.java
@@ -0,0 +1,30 @@
+package com.googlecode.mp4parser.util;
+
+public class Math {
+    public static long gcd(long a, long b) {
+        while (b > 0) {
+            long temp = b;
+            b = a % b; // % is remainder
+            a = temp;
+        }
+        return a;
+    }
+
+    public static int gcd(int a, int b) {
+        while (b > 0) {
+            int temp = b;
+            b = a % b; // % is remainder
+            a = temp;
+        }
+        return a;
+    }
+
+    public static long lcm(long a, long b) {
+        return a * (b / gcd(a, b));
+    }
+
+    public static int lcm(int a, int b) {
+        return a * (b / gcd(a, b));
+    }
+
+}
diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/util/Path.java b/isoparser/src/main/java/com/googlecode/mp4parser/util/Path.java
new file mode 100644
index 0000000..a6066c8
--- /dev/null
+++ b/isoparser/src/main/java/com/googlecode/mp4parser/util/Path.java
@@ -0,0 +1,115 @@
+/*
+ * Copyright 2012 Sebastian Annies, Hamburg
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.googlecode.mp4parser.util;
+
+
+import com.coremedia.iso.IsoFile;
+import com.coremedia.iso.boxes.Box;
+import com.coremedia.iso.boxes.ContainerBox;
+
+import java.util.Collections;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+public class Path {
+
+    private Path() {
+    }
+
+    static Pattern component = Pattern.compile("(....|\\.\\.)(\\[(.*)\\])?");
+
+    public static String createPath(Box box) {
+        return createPath(box, "");
+    }
+
+    private static String createPath(Box box, String path) {
+        if (box instanceof IsoFile) {
+            return path;
+        } else {
+            List<?> boxesOfBoxType = box.getParent().getBoxes(box.getClass());
+            int index = boxesOfBoxType.indexOf(box);
+            path = String.format("/%s[%d]", box.getType(), index) + path;
+
+            return createPath(box.getParent(), path);
+        }
+    }
+
+    public static Box getPath(Box box, String path) {
+        List<Box> all = getPaths(box, path);
+        return all.isEmpty() ? null : all.get(0);
+    }
+
+
+    public static List<Box> getPaths(Box box, String path) {
+        if (path.startsWith("/")) {
+            Box isoFile = box;
+            while (isoFile.getParent() != null) {
+                isoFile = isoFile.getParent();
+            }
+            assert isoFile instanceof IsoFile : isoFile.getType() + " has no parent";
+            return getPaths(isoFile, path.substring(1));
+        } else if (path.isEmpty()) {
+            return Collections.singletonList(box);
+        } else {
+            String later;
+            String now;
+            if (path.contains("/")) {
+                later = path.substring(path.indexOf('/') + 1);
+                now = path.substring(0, path.indexOf('/'));
+            } else {
+                now = path;
+                later = "";
+            }
+
+            Matcher m = component.matcher(now);
+            if (m.matches()) {
+                String type = m.group(1);
+                if ("..".equals(type)) {
+                    return getPaths(box.getParent(), later);
+                } else {
+                    int index = -1;
+                    if (m.group(2) != null) {
+                        // we have a specific index
+                        String indexString = m.group(3);
+                        index = Integer.parseInt(indexString);
+                    }
+                    List<Box> children = new LinkedList<Box>();
+                    int currentIndex = 0;
+                    for (Box box1 : ((ContainerBox) box).getBoxes()) {
+                        if (box1.getType().matches(type)) {
+                            if (index == -1 || index == currentIndex) {
+                                children.addAll(getPaths(box1, later));
+                            }
+                            currentIndex++;
+                        }
+                    }
+                    return children;
+                }
+            } else {
+                throw new RuntimeException(now + " is invalid path.");
+            }
+        }
+
+    }
+
+
+    public static boolean isContained(Box box, String path) {
+        assert path.startsWith("/") : "Absolute path required";
+        return getPaths(box, path).contains(box);
+    }
+}
diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/util/UUIDConverter.java b/isoparser/src/main/java/com/googlecode/mp4parser/util/UUIDConverter.java
new file mode 100644
index 0000000..635e4c1
--- /dev/null
+++ b/isoparser/src/main/java/com/googlecode/mp4parser/util/UUIDConverter.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright 2012 Sebastian Annies, Hamburg
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.googlecode.mp4parser.util;
+
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.util.UUID;
+
+/**
+ * UUID from/to byte array.
+ */
+public class UUIDConverter {
+    public static byte[] convert(UUID uuid) {
+
+        long msb = uuid.getMostSignificantBits();
+        long lsb = uuid.getLeastSignificantBits();
+        byte[] buffer = new byte[16];
+
+        for (int i = 0; i < 8; i++) {
+            buffer[i] = (byte) (msb >>> 8 * (7 - i));
+        }
+        for (int i = 8; i < 16; i++) {
+            buffer[i] = (byte) (lsb >>> 8 * (7 - i));
+        }
+
+        return buffer;
+
+    }
+
+    public static UUID convert(byte[] uuidBytes) {
+        ByteBuffer b = ByteBuffer.wrap(uuidBytes);
+        b.order(ByteOrder.BIG_ENDIAN);
+        return new UUID(b.getLong(), b.getLong());
+    }
+}
diff --git a/isoparser/src/main/resources/.svn/all-wcprops b/isoparser/src/main/resources/.svn/all-wcprops
new file mode 100644
index 0000000..bbb5562
--- /dev/null
+++ b/isoparser/src/main/resources/.svn/all-wcprops
@@ -0,0 +1,29 @@
+K 25
+svn:wc:ra_dav:version-url
+V 52
+/svn/!svn/ver/727/trunk/isoparser/src/main/resources
+END
+NOTICE.txt
+K 25
+svn:wc:ra_dav:version-url
+V 63
+/svn/!svn/ver/411/trunk/isoparser/src/main/resources/NOTICE.txt
+END
+LICENSE.txt
+K 25
+svn:wc:ra_dav:version-url
+V 64
+/svn/!svn/ver/218/trunk/isoparser/src/main/resources/LICENSE.txt
+END
+version.txt
+K 25
+svn:wc:ra_dav:version-url
+V 64
+/svn/!svn/ver/599/trunk/isoparser/src/main/resources/version.txt
+END
+isoparser-default.properties
+K 25
+svn:wc:ra_dav:version-url
+V 81
+/svn/!svn/ver/727/trunk/isoparser/src/main/resources/isoparser-default.properties
+END
diff --git a/isoparser/src/main/resources/.svn/entries b/isoparser/src/main/resources/.svn/entries
new file mode 100644
index 0000000..99bab1e
--- /dev/null
+++ b/isoparser/src/main/resources/.svn/entries
@@ -0,0 +1,164 @@
+10
+
+dir
+778
+http://mp4parser.googlecode.com/svn/trunk/isoparser/src/main/resources
+http://mp4parser.googlecode.com/svn
+
+
+
+2012-08-08T07:05:08.133759Z
+727
+Sebastian.Annies@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+7decde4b-c250-0410-a0da-51896bc88be6
+
+NOTICE.txt
+file
+
+
+
+
+2012-09-14T17:27:53.187257Z
+fff0059e2c9a4032e8859bdc2893e1ba
+2012-03-11T15:51:09.611460Z
+411
+Sebastian.Annies@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+1179
+
+LICENSE.txt
+file
+
+
+
+
+2012-09-14T17:27:53.187257Z
+d229da563da18fe5d58cd95a6467d584
+2011-09-02T11:20:19.650707Z
+218
+Sebastian.Annies@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+11558
+
+version.txt
+file
+
+
+
+
+2012-09-14T17:27:53.187257Z
+ad3f9bff6aff7eb4162a8329d720e21d
+2012-05-10T08:19:36.847188Z
+599
+Sebastian.Annies@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+40
+
+isoparser-default.properties
+file
+
+
+
+
+2012-09-14T17:27:53.187257Z
+1d05d9cf65f28048f74e13be23f1895c
+2012-08-08T07:05:08.133759Z
+727
+Sebastian.Annies@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+13118
+
diff --git a/isoparser/src/main/resources/.svn/text-base/LICENSE.txt.svn-base b/isoparser/src/main/resources/.svn/text-base/LICENSE.txt.svn-base
new file mode 100644
index 0000000..29f81d8
--- /dev/null
+++ b/isoparser/src/main/resources/.svn/text-base/LICENSE.txt.svn-base
@@ -0,0 +1,201 @@
+                                 Apache License

+                           Version 2.0, January 2004

+                        http://www.apache.org/licenses/

+

+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION

+

+   1. Definitions.

+

+      "License" shall mean the terms and conditions for use, reproduction,

+      and distribution as defined by Sections 1 through 9 of this document.

+

+      "Licensor" shall mean the copyright owner or entity authorized by

+      the copyright owner that is granting the License.

+

+      "Legal Entity" shall mean the union of the acting entity and all

+      other entities that control, are controlled by, or are under common

+      control with that entity. For the purposes of this definition,

+      "control" means (i) the power, direct or indirect, to cause the

+      direction or management of such entity, whether by contract or

+      otherwise, or (ii) ownership of fifty percent (50%) or more of the

+      outstanding shares, or (iii) beneficial ownership of such entity.

+

+      "You" (or "Your") shall mean an individual or Legal Entity

+      exercising permissions granted by this License.

+

+      "Source" form shall mean the preferred form for making modifications,

+      including but not limited to software source code, documentation

+      source, and configuration files.

+

+      "Object" form shall mean any form resulting from mechanical

+      transformation or translation of a Source form, including but

+      not limited to compiled object code, generated documentation,

+      and conversions to other media types.

+

+      "Work" shall mean the work of authorship, whether in Source or

+      Object form, made available under the License, as indicated by a

+      copyright notice that is included in or attached to the work

+      (an example is provided in the Appendix below).

+

+      "Derivative Works" shall mean any work, whether in Source or Object

+      form, that is based on (or derived from) the Work and for which the

+      editorial revisions, annotations, elaborations, or other modifications

+      represent, as a whole, an original work of authorship. For the purposes

+      of this License, Derivative Works shall not include works that remain

+      separable from, or merely link (or bind by name) to the interfaces of,

+      the Work and Derivative Works thereof.

+

+      "Contribution" shall mean any work of authorship, including

+      the original version of the Work and any modifications or additions

+      to that Work or Derivative Works thereof, that is intentionally

+      submitted to Licensor for inclusion in the Work by the copyright owner

+      or by an individual or Legal Entity authorized to submit on behalf of

+      the copyright owner. For the purposes of this definition, "submitted"

+      means any form of electronic, verbal, or written communication sent

+      to the Licensor or its representatives, including but not limited to

+      communication on electronic mailing lists, source code control systems,

+      and issue tracking systems that are managed by, or on behalf of, the

+      Licensor for the purpose of discussing and improving the Work, but

+      excluding communication that is conspicuously marked or otherwise

+      designated in writing by the copyright owner as "Not a Contribution."

+

+      "Contributor" shall mean Licensor and any individual or Legal Entity

+      on behalf of whom a Contribution has been received by Licensor and

+      subsequently incorporated within the Work.

+

+   2. Grant of Copyright License. Subject to the terms and conditions of

+      this License, each Contributor hereby grants to You a perpetual,

+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable

+      copyright license to reproduce, prepare Derivative Works of,

+      publicly display, publicly perform, sublicense, and distribute the

+      Work and such Derivative Works in Source or Object form.

+

+   3. Grant of Patent License. Subject to the terms and conditions of

+      this License, each Contributor hereby grants to You a perpetual,

+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable

+      (except as stated in this section) patent license to make, have made,

+      use, offer to sell, sell, import, and otherwise transfer the Work,

+      where such license applies only to those patent claims licensable

+      by such Contributor that are necessarily infringed by their

+      Contribution(s) alone or by combination of their Contribution(s)

+      with the Work to which such Contribution(s) was submitted. If You

+      institute patent litigation against any entity (including a

+      cross-claim or counterclaim in a lawsuit) alleging that the Work

+      or a Contribution incorporated within the Work constitutes direct

+      or contributory patent infringement, then any patent licenses

+      granted to You under this License for that Work shall terminate

+      as of the date such litigation is filed.

+

+   4. Redistribution. You may reproduce and distribute copies of the

+      Work or Derivative Works thereof in any medium, with or without

+      modifications, and in Source or Object form, provided that You

+      meet the following conditions:

+

+      (a) You must give any other recipients of the Work or

+          Derivative Works a copy of this License; and

+

+      (b) You must cause any modified files to carry prominent notices

+          stating that You changed the files; and

+

+      (c) You must retain, in the Source form of any Derivative Works

+          that You distribute, all copyright, patent, trademark, and

+          attribution notices from the Source form of the Work,

+          excluding those notices that do not pertain to any part of

+          the Derivative Works; and

+

+      (d) If the Work includes a "NOTICE" text file as part of its

+          distribution, then any Derivative Works that You distribute must

+          include a readable copy of the attribution notices contained

+          within such NOTICE file, excluding those notices that do not

+          pertain to any part of the Derivative Works, in at least one

+          of the following places: within a NOTICE text file distributed

+          as part of the Derivative Works; within the Source form or

+          documentation, if provided along with the Derivative Works; or,

+          within a display generated by the Derivative Works, if and

+          wherever such third-party notices normally appear. The contents

+          of the NOTICE file are for informational purposes only and

+          do not modify the License. You may add Your own attribution

+          notices within Derivative Works that You distribute, alongside

+          or as an addendum to the NOTICE text from the Work, provided

+          that such additional attribution notices cannot be construed

+          as modifying the License.

+

+      You may add Your own copyright statement to Your modifications and

+      may provide additional or different license terms and conditions

+      for use, reproduction, or distribution of Your modifications, or

+      for any such Derivative Works as a whole, provided Your use,

+      reproduction, and distribution of the Work otherwise complies with

+      the conditions stated in this License.

+

+   5. Submission of Contributions. Unless You explicitly state otherwise,

+      any Contribution intentionally submitted for inclusion in the Work

+      by You to the Licensor shall be under the terms and conditions of

+      this License, without any additional terms or conditions.

+      Notwithstanding the above, nothing herein shall supersede or modify

+      the terms of any separate license agreement you may have executed

+      with Licensor regarding such Contributions.

+

+   6. Trademarks. This License does not grant permission to use the trade

+      names, trademarks, service marks, or product names of the Licensor,

+      except as required for reasonable and customary use in describing the

+      origin of the Work and reproducing the content of the NOTICE file.

+

+   7. Disclaimer of Warranty. Unless required by applicable law or

+      agreed to in writing, Licensor provides the Work (and each

+      Contributor provides its Contributions) on an "AS IS" BASIS,

+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or

+      implied, including, without limitation, any warranties or conditions

+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A

+      PARTICULAR PURPOSE. You are solely responsible for determining the

+      appropriateness of using or redistributing the Work and assume any

+      risks associated with Your exercise of permissions under this License.

+

+   8. Limitation of Liability. In no event and under no legal theory,

+      whether in tort (including negligence), contract, or otherwise,

+      unless required by applicable law (such as deliberate and grossly

+      negligent acts) or agreed to in writing, shall any Contributor be

+      liable to You for damages, including any direct, indirect, special,

+      incidental, or consequential damages of any character arising as a

+      result of this License or out of the use or inability to use the

+      Work (including but not limited to damages for loss of goodwill,

+      work stoppage, computer failure or malfunction, or any and all

+      other commercial damages or losses), even if such Contributor

+      has been advised of the possibility of such damages.

+

+   9. Accepting Warranty or Additional Liability. While redistributing

+      the Work or Derivative Works thereof, You may choose to offer,

+      and charge a fee for, acceptance of support, warranty, indemnity,

+      or other liability obligations and/or rights consistent with this

+      License. However, in accepting such obligations, You may act only

+      on Your own behalf and on Your sole responsibility, not on behalf

+      of any other Contributor, and only if You agree to indemnify,

+      defend, and hold each Contributor harmless for any liability

+      incurred by, or claims asserted against, such Contributor by reason

+      of your accepting any such warranty or additional liability.

+

+   END OF TERMS AND CONDITIONS

+

+   APPENDIX: How to apply the Apache License to your work.

+

+      To apply the Apache License to your work, attach the following

+      boilerplate notice, with the fields enclosed by brackets "[]"

+      replaced with your own identifying information. (Don't include

+      the brackets!)  The text should be enclosed in the appropriate

+      comment syntax for the file format. We also recommend that a

+      file or class name and description of purpose be included on the

+      same "printed page" as the copyright notice for easier

+      identification within third-party archives.

+

+   Copyright [yyyy] [name of copyright owner]

+

+   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.

diff --git a/isoparser/src/main/resources/.svn/text-base/NOTICE.txt.svn-base b/isoparser/src/main/resources/.svn/text-base/NOTICE.txt.svn-base
new file mode 100644
index 0000000..a766aa1
--- /dev/null
+++ b/isoparser/src/main/resources/.svn/text-base/NOTICE.txt.svn-base
@@ -0,0 +1,29 @@
+   =========================================================================

+   ==  NOTICE file corresponding to the section 4 d of                    ==

+   ==  the Apache License, Version 2.0,                                   ==

+   ==  in this case for the Apache Maven distribution.                    ==

+   =========================================================================

+

+This product includes software developed by

+CoreMedia AG (http://www.coremedia.com/).

+

+This product includes software developed by

+castLabs GmbH (http://www.castlabs.com/).

+

+This product includes software developed by

+Sebastian Annies (Sebastian.Annies@gmail.com)

+

+This product includes software (Base64 Encoder extracted from commons-codec) developed by

+The Apache Software Foundation (http://www.apache.org/).

+

+This product includes software (Hex Encoder extracted from commons-codec) developed by

+The Apache Software Foundation (http://www.apache.org/).

+

+This product includes software (package com.googlecode.mp4parser.h264) developed by

+Stanislav Vitvitskiy and originally licensed under MIT license (http://www.opensource.org/licenses/mit-license.php)

+

+

+

+

+

+

diff --git a/isoparser/src/main/resources/.svn/text-base/isoparser-default.properties.svn-base b/isoparser/src/main/resources/.svn/text-base/isoparser-default.properties.svn-base
new file mode 100644
index 0000000..21e3910
--- /dev/null
+++ b/isoparser/src/main/resources/.svn/text-base/isoparser-default.properties.svn-base
@@ -0,0 +1,236 @@
+hint=com.coremedia.iso.boxes.TrackReferenceTypeBox(type)
+cdsc=com.coremedia.iso.boxes.TrackReferenceTypeBox(type)
+meta-ilst=com.coremedia.iso.boxes.apple.AppleItemListBox()
+-----name=com.coremedia.iso.boxes.apple.AppleNameBox()
+-----mean=com.coremedia.iso.boxes.apple.AppleMeanBox()
+-----data=com.coremedia.iso.boxes.apple.AppleDataBox()
+rmra=com.coremedia.iso.boxes.apple.AppleReferenceMovieBox()
+rmda=com.coremedia.iso.boxes.apple.AppleReferenceMovieDescriptorBox()
+rmdr=com.coremedia.iso.boxes.apple.AppleDataRateBox()
+rdrf=com.coremedia.iso.boxes.apple.AppleDataReferenceBox()
+ilst-cprt=com.coremedia.iso.boxes.apple.AppleCopyrightBox()
+ilst-\u00A9cmt=com.coremedia.iso.boxes.apple.AppleCommentBox()
+ilst-desc=com.coremedia.iso.boxes.apple.AppleDescriptionBox()
+ilst-covr=com.coremedia.iso.boxes.apple.AppleCoverBox()
+ilst-\u00A9alb=com.coremedia.iso.boxes.apple.AppleAlbumBox()
+ilst-\u00A9gen=com.coremedia.iso.boxes.apple.AppleCustomGenreBox()
+ilst-\u00A9grp=com.coremedia.iso.boxes.apple.AppleGroupingBox()
+ilst-\u00A9wrt=com.coremedia.iso.boxes.apple.AppleTrackAuthorBox()
+ilst-aART=com.coremedia.iso.boxes.apple.AppleAlbumArtistBox()
+ilst-tvsh=com.coremedia.iso.boxes.apple.AppleShowBox()
+ilst-stik=com.coremedia.iso.boxes.apple.AppleMediaTypeBox()
+ilst-pgap=com.coremedia.iso.boxes.apple.AppleGaplessPlaybackBox()
+ilst-tmpo=com.coremedia.iso.boxes.apple.AppleTempBox()
+ilst-\u00A9nam=com.coremedia.iso.boxes.apple.AppleTrackTitleBox()
+ilst-ldes=com.coremedia.iso.boxes.apple.AppleSynopsisBox()
+ilst-\u00A9ART=com.coremedia.iso.boxes.apple.AppleArtistBox()
+ilst-name=com.coremedia.iso.boxes.apple.AppleNameBox()
+ilst-cpil=com.coremedia.iso.boxes.apple.AppleCompilationBox()
+ilst-purd=com.coremedia.iso.boxes.apple.ApplePurchaseDateBox()
+ilst-\u00A9too=com.coremedia.iso.boxes.apple.AppleEncoderBox()
+ilst-sfID=com.coremedia.iso.boxes.apple.AppleStoreCountryCodeBox()
+ilst-gnre=com.coremedia.iso.boxes.apple.AppleStandardGenreBox()
+ilst-tves=com.coremedia.iso.boxes.apple.AppleTvEpisodeBox()
+ilst-ilst=com.coremedia.iso.boxes.apple.AppleItemListBox()
+ilst-data=com.coremedia.iso.boxes.apple.AppleDataBox()
+ilst-tvsn=com.coremedia.iso.boxes.apple.AppleTvSeasonBox()
+ilst-soal=com.coremedia.iso.boxes.apple.AppleSortAlbumBox()
+ilst-tven=com.coremedia.iso.boxes.apple.AppleTvEpisodeNumberBox()
+ilst-trkn=com.coremedia.iso.boxes.apple.AppleTrackNumberBox()
+ilst-\u00A9day=com.coremedia.iso.boxes.apple.AppleRecordingYearBox()
+ilst-----=com.coremedia.iso.boxes.apple.AppleGenericBox()
+ilst-akID=com.coremedia.iso.boxes.apple.AppleStoreAccountTypeBox()
+ilst-rtng=com.coremedia.iso.boxes.apple.AppleRatingBox()
+ilst-tvnn=com.coremedia.iso.boxes.apple.AppleNetworkBox()
+ilst-apID=com.coremedia.iso.boxes.apple.AppleIdBox()
+wave=com.coremedia.iso.boxes.apple.AppleWaveBox()
+
+udta-ccid=com.coremedia.iso.boxes.odf.OmaDrmContentIdBox()
+udta-yrrc=com.coremedia.iso.boxes.RecordingYearBox()
+udta-titl=com.coremedia.iso.boxes.TitleBox()
+udta-dscp=com.coremedia.iso.boxes.DescriptionBox()
+udta-icnu=com.coremedia.iso.boxes.odf.OmaDrmIconUriBox()
+udta-infu=com.coremedia.iso.boxes.odf.OmaDrmInfoUrlBox()
+udta-albm=com.coremedia.iso.boxes.AlbumBox()
+udta-cprt=com.coremedia.iso.boxes.CopyrightBox()
+udta-gnre=com.coremedia.iso.boxes.GenreBox()
+udta-perf=com.coremedia.iso.boxes.PerformerBox()
+udta-auth=com.coremedia.iso.boxes.AuthorBox()
+udta-kywd=com.coremedia.iso.boxes.KeywordsBox()
+udta-loci=com.coremedia.iso.boxes.threegpp26244.LocationInformationBox()
+udta-rtng=com.coremedia.iso.boxes.RatingBox()
+udta-clsf=com.coremedia.iso.boxes.ClassificationBox()
+udta-cdis=com.coremedia.iso.boxes.vodafone.ContentDistributorIdBox()
+udta-albr=com.coremedia.iso.boxes.vodafone.AlbumArtistBox()
+udta-cvru=com.coremedia.iso.boxes.odf.OmaDrmCoverUriBox()
+udta-lrcu=com.coremedia.iso.boxes.odf.OmaDrmLyricsUriBox()
+
+
+
+
+stsd-tx3g=com.coremedia.iso.boxes.sampleentry.TextSampleEntry(type)
+stsd-text=com.googlecode.mp4parser.boxes.apple.QuicktimeTextSampleEntry()
+stsd-enct=com.coremedia.iso.boxes.sampleentry.TextSampleEntry(type)
+stsd-samr=com.coremedia.iso.boxes.sampleentry.AudioSampleEntry(type)
+stsd-sawb=com.coremedia.iso.boxes.sampleentry.AudioSampleEntry(type)
+stsd-mp4a=com.coremedia.iso.boxes.sampleentry.AudioSampleEntry(type)
+stsd-drms=com.coremedia.iso.boxes.sampleentry.AudioSampleEntry(type)
+stsd-alac=com.coremedia.iso.boxes.sampleentry.AudioSampleEntry(type)
+stsd-mp4s=com.coremedia.iso.boxes.sampleentry.MpegSampleEntry(type)
+stsd-owma=com.coremedia.iso.boxes.sampleentry.AudioSampleEntry(type)
+stsd-ac-3=com.coremedia.iso.boxes.sampleentry.AudioSampleEntry(type)
+dac3=com.googlecode.mp4parser.boxes.AC3SpecificBox()
+stsd-ec-3=com.coremedia.iso.boxes.sampleentry.AudioSampleEntry(type)
+dec3=com.googlecode.mp4parser.boxes.EC3SpecificBox()
+stsd-lpcm=com.coremedia.iso.boxes.sampleentry.AudioSampleEntry(type)
+stsd-dtsc=com.coremedia.iso.boxes.sampleentry.AudioSampleEntry(type)
+stsd-dtsh=com.coremedia.iso.boxes.sampleentry.AudioSampleEntry(type)
+stsd-dtsl=com.coremedia.iso.boxes.sampleentry.AudioSampleEntry(type)
+ddts=com.googlecode.mp4parser.boxes.DTSSpecificBox()
+stsd-dtse=com.coremedia.iso.boxes.sampleentry.AudioSampleEntry(type)
+stsd-mlpa=com.coremedia.iso.boxes.sampleentry.AudioSampleEntry(type)
+dmlp=com.googlecode.mp4parser.boxes.MLPSpecificBox()
+stsd-enca=com.coremedia.iso.boxes.sampleentry.AudioSampleEntry(type)
+stsd-encv=com.coremedia.iso.boxes.sampleentry.VisualSampleEntry(type)
+stsd-mp4v=com.coremedia.iso.boxes.sampleentry.VisualSampleEntry(type)
+stsd-s263=com.coremedia.iso.boxes.sampleentry.VisualSampleEntry(type)
+stsd-avc1=com.coremedia.iso.boxes.sampleentry.VisualSampleEntry(type)
+stsd-ovc1=com.coremedia.iso.boxes.sampleentry.Ovc1VisualSampleEntryImpl()
+stsd-stpp=com.coremedia.iso.boxes.sampleentry.SubtitleSampleEntry(type)
+avcC=com.coremedia.iso.boxes.h264.AvcConfigurationBox()
+alac=com.coremedia.iso.boxes.apple.AppleLosslessSpecificBox()
+btrt=com.coremedia.iso.boxes.BitRateBox()
+ftyp=com.coremedia.iso.boxes.FileTypeBox()
+mdat=com.coremedia.iso.boxes.mdat.MediaDataBox()
+moov=com.coremedia.iso.boxes.MovieBox()
+mvhd=com.coremedia.iso.boxes.MovieHeaderBox()
+trak=com.coremedia.iso.boxes.TrackBox()
+tkhd=com.coremedia.iso.boxes.TrackHeaderBox()
+edts=com.coremedia.iso.boxes.EditBox()
+elst=com.coremedia.iso.boxes.EditListBox()
+mdia=com.coremedia.iso.boxes.MediaBox()
+mdhd=com.coremedia.iso.boxes.MediaHeaderBox()
+hdlr=com.coremedia.iso.boxes.HandlerBox()
+minf=com.coremedia.iso.boxes.MediaInformationBox()
+vmhd=com.coremedia.iso.boxes.VideoMediaHeaderBox()
+smhd=com.coremedia.iso.boxes.SoundMediaHeaderBox()
+sthd=com.coremedia.iso.boxes.SubtitleMediaHeaderBox()
+hmhd=com.coremedia.iso.boxes.HintMediaHeaderBox()
+dinf=com.coremedia.iso.boxes.DataInformationBox()
+dref=com.coremedia.iso.boxes.DataReferenceBox()
+url\ =com.coremedia.iso.boxes.DataEntryUrlBox()
+urn\ =com.coremedia.iso.boxes.DataEntryUrnBox()
+stbl=com.coremedia.iso.boxes.SampleTableBox()
+ctts=com.coremedia.iso.boxes.CompositionTimeToSample()
+stsd=com.coremedia.iso.boxes.SampleDescriptionBox()
+stts=com.coremedia.iso.boxes.TimeToSampleBox()
+stss=com.coremedia.iso.boxes.SyncSampleBox()
+stsc=com.coremedia.iso.boxes.SampleToChunkBox()
+stsz=com.coremedia.iso.boxes.SampleSizeBox()
+stco=com.coremedia.iso.boxes.StaticChunkOffsetBox()
+subs=com.coremedia.iso.boxes.SubSampleInformationBox()
+udta=com.coremedia.iso.boxes.UserDataBox()
+skip=com.coremedia.iso.boxes.FreeSpaceBox()
+tref=com.coremedia.iso.boxes.TrackReferenceBox()
+iloc=com.coremedia.iso.boxes.ItemLocationBox()
+idat=com.coremedia.iso.boxes.ItemDataBox()
+saio=com.coremedia.iso.boxes.SampleAuxiliaryInformationOffsetsBox()
+saiz=com.coremedia.iso.boxes.SampleAuxiliaryInformationSizesBox()
+damr=com.coremedia.iso.boxes.sampleentry.AmrSpecificBox()
+meta=com.coremedia.iso.boxes.MetaBox()
+ipro=com.coremedia.iso.boxes.ItemProtectionBox()
+sinf=com.coremedia.iso.boxes.ProtectionSchemeInformationBox()
+frma=com.coremedia.iso.boxes.OriginalFormatBox()
+schi=com.coremedia.iso.boxes.SchemeInformationBox()
+odkm=com.coremedia.iso.boxes.odf.OmaDrmKeyManagenentSystemBox()
+odaf=com.coremedia.iso.boxes.OmaDrmAccessUnitFormatBox()
+schm=com.coremedia.iso.boxes.SchemeTypeBox()
+uuid=com.coremedia.iso.boxes.UserBox(userType)
+free=com.coremedia.iso.boxes.FreeBox()
+styp=com.coremedia.iso.boxes.fragment.SegmentTypeBox()
+mvex=com.coremedia.iso.boxes.fragment.MovieExtendsBox()
+mehd=com.coremedia.iso.boxes.fragment.MovieExtendsHeaderBox()
+trex=com.coremedia.iso.boxes.fragment.TrackExtendsBox()
+
+moof=com.coremedia.iso.boxes.fragment.MovieFragmentBox()
+mfhd=com.coremedia.iso.boxes.fragment.MovieFragmentHeaderBox()
+traf=com.coremedia.iso.boxes.fragment.TrackFragmentBox()
+tfhd=com.coremedia.iso.boxes.fragment.TrackFragmentHeaderBox()
+trun=com.coremedia.iso.boxes.fragment.TrackRunBox()
+sdtp=com.coremedia.iso.boxes.SampleDependencyTypeBox()
+mfra=com.coremedia.iso.boxes.fragment.MovieFragmentRandomAccessBox()
+tfra=com.coremedia.iso.boxes.fragment.TrackFragmentRandomAccessBox()
+mfro=com.coremedia.iso.boxes.fragment.MovieFragmentRandomAccessOffsetBox()
+tfdt=com.coremedia.iso.boxes.fragment.TrackFragmentBaseMediaDecodeTimeBox()
+nmhd=com.coremedia.iso.boxes.NullMediaHeaderBox()
+gmhd=com.googlecode.mp4parser.boxes.apple.GenericMediaHeaderAtom()
+gmhd-text=com.googlecode.mp4parser.boxes.apple.GenericMediaHeaderTextAtom()
+gmin=com.googlecode.mp4parser.boxes.apple.BaseMediaInfoAtom()
+cslg=com.coremedia.iso.boxes.CompositionShiftLeastGreatestAtom()
+pdin=com.coremedia.iso.boxes.ProgressiveDownloadInformationBox()
+bloc=com.googlecode.mp4parser.boxes.ultraviolet.BaseLocationBox()
+ftab=com.googlecode.mp4parser.boxes.threegpp26245.FontTableBox()
+co64=com.coremedia.iso.boxes.ChunkOffset64BitBox()
+xml\ =com.coremedia.iso.boxes.XmlBox()
+avcn=com.googlecode.mp4parser.boxes.basemediaformat.AvcNalUnitStorageBox()
+ainf=com.googlecode.mp4parser.boxes.ultraviolet.AssetInformationBox()
+pssh=com.googlecode.mp4parser.boxes.cenc.ProtectionSystemSpecificHeaderBox()
+trik=com.coremedia.iso.boxes.dece.TrickPlayBox()
+uuid[A2394F525A9B4F14A2446C427C648DF4]=com.googlecode.mp4parser.boxes.piff.PiffSampleEncryptionBox()
+uuid[8974DBCE7BE74C5184F97148F9882554]=com.googlecode.mp4parser.boxes.piff.PiffTrackEncryptionBox()
+uuid[D4807EF2CA3946958E5426CB9E46A79F]=com.googlecode.mp4parser.boxes.piff.TfrfBox()
+uuid[6D1D9B0542D544E680E2141DAFF757B2]=com.googlecode.mp4parser.boxes.piff.TfxdBox()
+uuid[D08A4F1810F34A82B6C832D8ABA183D3]=com.googlecode.mp4parser.boxes.piff.UuidBasedProtectionSystemSpecificHeaderBox()
+senc=com.googlecode.mp4parser.boxes.basemediaformat.SampleEncryptionBox()
+tenc=com.googlecode.mp4parser.boxes.basemediaformat.TrackEncryptionBox()
+amf0=com.googlecode.mp4parser.boxes.adobe.ActionMessageFormat0SampleEntryBox()
+
+#iods=com.googlecode.mp4parser.boxes.mp4.ObjectDescriptorBox()
+esds=com.googlecode.mp4parser.boxes.mp4.ESDescriptorBox()
+
+tmcd=com.googlecode.mp4parser.boxes.apple.TimeCodeBox()
+sidx=com.googlecode.mp4parser.boxes.threegpp26244.SegmentIndexBox()
+
+sbgp=com.googlecode.mp4parser.boxes.mp4.samplegrouping.SampleToGroupBox()
+sgpd=com.googlecode.mp4parser.boxes.mp4.samplegrouping.SampleGroupDescriptionBox()
+
+tapt=com.googlecode.mp4parser.boxes.apple.TaptAtom()
+
+default=com.coremedia.iso.boxes.UnknownBox(type)
+
+
+
+#stsd-rtp\ =com.coremedia.iso.boxes.rtp.RtpHintSampleEntry(type)
+#udta-hnti=com.coremedia.iso.boxes.rtp.HintInformationBox()
+#udta-hinf=com.coremedia.iso.boxes.rtp.HintStatisticsBox()
+#hnti-sdp\ =com.coremedia.iso.boxes.rtp.RtpTrackSdpHintInformationBox()
+#hnti-rtp\ =com.coremedia.iso.boxes.rtp.RtpMovieHintInformationBox()
+#hinf-pmax=com.coremedia.iso.boxes.rtp.LargestHintPacketBox()
+#hinf-payt=com.coremedia.iso.boxes.rtp.PayloadTypeBox()
+#hinf-tmin=com.coremedia.iso.boxes.rtp.SmallestRelativeTransmissionTimeBox()
+#hinf-tmax=com.coremedia.iso.boxes.rtp.LargestRelativeTransmissionTimeBox()
+#hinf-maxr=com.coremedia.iso.boxes.rtp.MaximumDataRateBox()
+#hinf-dmax=com.coremedia.iso.boxes.rtp.LargestHintPacketDurationBox()
+#hinf-hnti=com.coremedia.iso.boxes.rtp.HintInformationBox()
+#hinf-tims=com.coremedia.iso.boxes.rtp.TimeScaleEntry()
+
+#hinf-nump=com.coremedia.iso.boxes.rtp.HintPacketsSentBox(type)
+#hinf-npck=com.coremedia.iso.boxes.rtp.HintPacketsSentBox(type)
+
+#hinf-trpy=com.coremedia.iso.boxes.rtp.HintStatisticBoxes(type)
+#hinf-totl=com.coremedia.iso.boxes.rtp.HintStatisticBoxes(type)
+#hinf-tpyl=com.coremedia.iso.boxes.rtp.HintStatisticBoxes(type)
+#hinf-tpay=com.coremedia.iso.boxes.rtp.HintStatisticBoxes(type)
+#hinf-dmed=com.coremedia.iso.boxes.rtp.HintStatisticBoxes(type)
+#hinf-dimm=com.coremedia.iso.boxes.rtp.HintStatisticBoxes(type)
+#hinf-drep=com.coremedia.iso.boxes.rtp.HintStatisticBoxes(type)
+#tims=com.coremedia.iso.boxes.rtp.TimeScaleEntry()
+
+#odrm=com.coremedia.iso.boxes.odf.OmaDrmContainerBox()
+#mdri=com.coremedia.iso.boxes.odf.MutableDrmInformationBox()
+#odtt=com.coremedia.iso.boxes.odf.OmaDrmTransactionTrackingBox()
+#odrb=com.coremedia.iso.boxes.odf.OmaDrmRightsObjectBox()
+#odhe=com.coremedia.iso.boxes.odf.OmaDrmDiscreteHeadersBox()
+#odda=com.coremedia.iso.boxes.odf.OmaDrmContentObjectBox()
+#ohdr=com.coremedia.iso.boxes.odf.OmaDrmCommonHeadersBox()
+#grpi=com.coremedia.iso.boxes.odf.OmaDrmGroupIdBox()
diff --git a/isoparser/src/main/resources/.svn/text-base/version.txt.svn-base b/isoparser/src/main/resources/.svn/text-base/version.txt.svn-base
new file mode 100644
index 0000000..c285390
--- /dev/null
+++ b/isoparser/src/main/resources/.svn/text-base/version.txt.svn-base
@@ -0,0 +1 @@
+${project.artifactId}-${project.version}
\ No newline at end of file
diff --git a/isoparser/src/main/resources/LICENSE.txt b/isoparser/src/main/resources/LICENSE.txt
new file mode 100644
index 0000000..29f81d8
--- /dev/null
+++ b/isoparser/src/main/resources/LICENSE.txt
@@ -0,0 +1,201 @@
+                                 Apache License

+                           Version 2.0, January 2004

+                        http://www.apache.org/licenses/

+

+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION

+

+   1. Definitions.

+

+      "License" shall mean the terms and conditions for use, reproduction,

+      and distribution as defined by Sections 1 through 9 of this document.

+

+      "Licensor" shall mean the copyright owner or entity authorized by

+      the copyright owner that is granting the License.

+

+      "Legal Entity" shall mean the union of the acting entity and all

+      other entities that control, are controlled by, or are under common

+      control with that entity. For the purposes of this definition,

+      "control" means (i) the power, direct or indirect, to cause the

+      direction or management of such entity, whether by contract or

+      otherwise, or (ii) ownership of fifty percent (50%) or more of the

+      outstanding shares, or (iii) beneficial ownership of such entity.

+

+      "You" (or "Your") shall mean an individual or Legal Entity

+      exercising permissions granted by this License.

+

+      "Source" form shall mean the preferred form for making modifications,

+      including but not limited to software source code, documentation

+      source, and configuration files.

+

+      "Object" form shall mean any form resulting from mechanical

+      transformation or translation of a Source form, including but

+      not limited to compiled object code, generated documentation,

+      and conversions to other media types.

+

+      "Work" shall mean the work of authorship, whether in Source or

+      Object form, made available under the License, as indicated by a

+      copyright notice that is included in or attached to the work

+      (an example is provided in the Appendix below).

+

+      "Derivative Works" shall mean any work, whether in Source or Object

+      form, that is based on (or derived from) the Work and for which the

+      editorial revisions, annotations, elaborations, or other modifications

+      represent, as a whole, an original work of authorship. For the purposes

+      of this License, Derivative Works shall not include works that remain

+      separable from, or merely link (or bind by name) to the interfaces of,

+      the Work and Derivative Works thereof.

+

+      "Contribution" shall mean any work of authorship, including

+      the original version of the Work and any modifications or additions

+      to that Work or Derivative Works thereof, that is intentionally

+      submitted to Licensor for inclusion in the Work by the copyright owner

+      or by an individual or Legal Entity authorized to submit on behalf of

+      the copyright owner. For the purposes of this definition, "submitted"

+      means any form of electronic, verbal, or written communication sent

+      to the Licensor or its representatives, including but not limited to

+      communication on electronic mailing lists, source code control systems,

+      and issue tracking systems that are managed by, or on behalf of, the

+      Licensor for the purpose of discussing and improving the Work, but

+      excluding communication that is conspicuously marked or otherwise

+      designated in writing by the copyright owner as "Not a Contribution."

+

+      "Contributor" shall mean Licensor and any individual or Legal Entity

+      on behalf of whom a Contribution has been received by Licensor and

+      subsequently incorporated within the Work.

+

+   2. Grant of Copyright License. Subject to the terms and conditions of

+      this License, each Contributor hereby grants to You a perpetual,

+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable

+      copyright license to reproduce, prepare Derivative Works of,

+      publicly display, publicly perform, sublicense, and distribute the

+      Work and such Derivative Works in Source or Object form.

+

+   3. Grant of Patent License. Subject to the terms and conditions of

+      this License, each Contributor hereby grants to You a perpetual,

+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable

+      (except as stated in this section) patent license to make, have made,

+      use, offer to sell, sell, import, and otherwise transfer the Work,

+      where such license applies only to those patent claims licensable

+      by such Contributor that are necessarily infringed by their

+      Contribution(s) alone or by combination of their Contribution(s)

+      with the Work to which such Contribution(s) was submitted. If You

+      institute patent litigation against any entity (including a

+      cross-claim or counterclaim in a lawsuit) alleging that the Work

+      or a Contribution incorporated within the Work constitutes direct

+      or contributory patent infringement, then any patent licenses

+      granted to You under this License for that Work shall terminate

+      as of the date such litigation is filed.

+

+   4. Redistribution. You may reproduce and distribute copies of the

+      Work or Derivative Works thereof in any medium, with or without

+      modifications, and in Source or Object form, provided that You

+      meet the following conditions:

+

+      (a) You must give any other recipients of the Work or

+          Derivative Works a copy of this License; and

+

+      (b) You must cause any modified files to carry prominent notices

+          stating that You changed the files; and

+

+      (c) You must retain, in the Source form of any Derivative Works

+          that You distribute, all copyright, patent, trademark, and

+          attribution notices from the Source form of the Work,

+          excluding those notices that do not pertain to any part of

+          the Derivative Works; and

+

+      (d) If the Work includes a "NOTICE" text file as part of its

+          distribution, then any Derivative Works that You distribute must

+          include a readable copy of the attribution notices contained

+          within such NOTICE file, excluding those notices that do not

+          pertain to any part of the Derivative Works, in at least one

+          of the following places: within a NOTICE text file distributed

+          as part of the Derivative Works; within the Source form or

+          documentation, if provided along with the Derivative Works; or,

+          within a display generated by the Derivative Works, if and

+          wherever such third-party notices normally appear. The contents

+          of the NOTICE file are for informational purposes only and

+          do not modify the License. You may add Your own attribution

+          notices within Derivative Works that You distribute, alongside

+          or as an addendum to the NOTICE text from the Work, provided

+          that such additional attribution notices cannot be construed

+          as modifying the License.

+

+      You may add Your own copyright statement to Your modifications and

+      may provide additional or different license terms and conditions

+      for use, reproduction, or distribution of Your modifications, or

+      for any such Derivative Works as a whole, provided Your use,

+      reproduction, and distribution of the Work otherwise complies with

+      the conditions stated in this License.

+

+   5. Submission of Contributions. Unless You explicitly state otherwise,

+      any Contribution intentionally submitted for inclusion in the Work

+      by You to the Licensor shall be under the terms and conditions of

+      this License, without any additional terms or conditions.

+      Notwithstanding the above, nothing herein shall supersede or modify

+      the terms of any separate license agreement you may have executed

+      with Licensor regarding such Contributions.

+

+   6. Trademarks. This License does not grant permission to use the trade

+      names, trademarks, service marks, or product names of the Licensor,

+      except as required for reasonable and customary use in describing the

+      origin of the Work and reproducing the content of the NOTICE file.

+

+   7. Disclaimer of Warranty. Unless required by applicable law or

+      agreed to in writing, Licensor provides the Work (and each

+      Contributor provides its Contributions) on an "AS IS" BASIS,

+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or

+      implied, including, without limitation, any warranties or conditions

+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A

+      PARTICULAR PURPOSE. You are solely responsible for determining the

+      appropriateness of using or redistributing the Work and assume any

+      risks associated with Your exercise of permissions under this License.

+

+   8. Limitation of Liability. In no event and under no legal theory,

+      whether in tort (including negligence), contract, or otherwise,

+      unless required by applicable law (such as deliberate and grossly

+      negligent acts) or agreed to in writing, shall any Contributor be

+      liable to You for damages, including any direct, indirect, special,

+      incidental, or consequential damages of any character arising as a

+      result of this License or out of the use or inability to use the

+      Work (including but not limited to damages for loss of goodwill,

+      work stoppage, computer failure or malfunction, or any and all

+      other commercial damages or losses), even if such Contributor

+      has been advised of the possibility of such damages.

+

+   9. Accepting Warranty or Additional Liability. While redistributing

+      the Work or Derivative Works thereof, You may choose to offer,

+      and charge a fee for, acceptance of support, warranty, indemnity,

+      or other liability obligations and/or rights consistent with this

+      License. However, in accepting such obligations, You may act only

+      on Your own behalf and on Your sole responsibility, not on behalf

+      of any other Contributor, and only if You agree to indemnify,

+      defend, and hold each Contributor harmless for any liability

+      incurred by, or claims asserted against, such Contributor by reason

+      of your accepting any such warranty or additional liability.

+

+   END OF TERMS AND CONDITIONS

+

+   APPENDIX: How to apply the Apache License to your work.

+

+      To apply the Apache License to your work, attach the following

+      boilerplate notice, with the fields enclosed by brackets "[]"

+      replaced with your own identifying information. (Don't include

+      the brackets!)  The text should be enclosed in the appropriate

+      comment syntax for the file format. We also recommend that a

+      file or class name and description of purpose be included on the

+      same "printed page" as the copyright notice for easier

+      identification within third-party archives.

+

+   Copyright [yyyy] [name of copyright owner]

+

+   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.

diff --git a/isoparser/src/main/resources/NOTICE.txt b/isoparser/src/main/resources/NOTICE.txt
new file mode 100644
index 0000000..a766aa1
--- /dev/null
+++ b/isoparser/src/main/resources/NOTICE.txt
@@ -0,0 +1,29 @@
+   =========================================================================

+   ==  NOTICE file corresponding to the section 4 d of                    ==

+   ==  the Apache License, Version 2.0,                                   ==

+   ==  in this case for the Apache Maven distribution.                    ==

+   =========================================================================

+

+This product includes software developed by

+CoreMedia AG (http://www.coremedia.com/).

+

+This product includes software developed by

+castLabs GmbH (http://www.castlabs.com/).

+

+This product includes software developed by

+Sebastian Annies (Sebastian.Annies@gmail.com)

+

+This product includes software (Base64 Encoder extracted from commons-codec) developed by

+The Apache Software Foundation (http://www.apache.org/).

+

+This product includes software (Hex Encoder extracted from commons-codec) developed by

+The Apache Software Foundation (http://www.apache.org/).

+

+This product includes software (package com.googlecode.mp4parser.h264) developed by

+Stanislav Vitvitskiy and originally licensed under MIT license (http://www.opensource.org/licenses/mit-license.php)

+

+

+

+

+

+

diff --git a/isoparser/src/main/resources/isoparser-default.properties b/isoparser/src/main/resources/isoparser-default.properties
new file mode 100644
index 0000000..21e3910
--- /dev/null
+++ b/isoparser/src/main/resources/isoparser-default.properties
@@ -0,0 +1,236 @@
+hint=com.coremedia.iso.boxes.TrackReferenceTypeBox(type)
+cdsc=com.coremedia.iso.boxes.TrackReferenceTypeBox(type)
+meta-ilst=com.coremedia.iso.boxes.apple.AppleItemListBox()
+-----name=com.coremedia.iso.boxes.apple.AppleNameBox()
+-----mean=com.coremedia.iso.boxes.apple.AppleMeanBox()
+-----data=com.coremedia.iso.boxes.apple.AppleDataBox()
+rmra=com.coremedia.iso.boxes.apple.AppleReferenceMovieBox()
+rmda=com.coremedia.iso.boxes.apple.AppleReferenceMovieDescriptorBox()
+rmdr=com.coremedia.iso.boxes.apple.AppleDataRateBox()
+rdrf=com.coremedia.iso.boxes.apple.AppleDataReferenceBox()
+ilst-cprt=com.coremedia.iso.boxes.apple.AppleCopyrightBox()
+ilst-\u00A9cmt=com.coremedia.iso.boxes.apple.AppleCommentBox()
+ilst-desc=com.coremedia.iso.boxes.apple.AppleDescriptionBox()
+ilst-covr=com.coremedia.iso.boxes.apple.AppleCoverBox()
+ilst-\u00A9alb=com.coremedia.iso.boxes.apple.AppleAlbumBox()
+ilst-\u00A9gen=com.coremedia.iso.boxes.apple.AppleCustomGenreBox()
+ilst-\u00A9grp=com.coremedia.iso.boxes.apple.AppleGroupingBox()
+ilst-\u00A9wrt=com.coremedia.iso.boxes.apple.AppleTrackAuthorBox()
+ilst-aART=com.coremedia.iso.boxes.apple.AppleAlbumArtistBox()
+ilst-tvsh=com.coremedia.iso.boxes.apple.AppleShowBox()
+ilst-stik=com.coremedia.iso.boxes.apple.AppleMediaTypeBox()
+ilst-pgap=com.coremedia.iso.boxes.apple.AppleGaplessPlaybackBox()
+ilst-tmpo=com.coremedia.iso.boxes.apple.AppleTempBox()
+ilst-\u00A9nam=com.coremedia.iso.boxes.apple.AppleTrackTitleBox()
+ilst-ldes=com.coremedia.iso.boxes.apple.AppleSynopsisBox()
+ilst-\u00A9ART=com.coremedia.iso.boxes.apple.AppleArtistBox()
+ilst-name=com.coremedia.iso.boxes.apple.AppleNameBox()
+ilst-cpil=com.coremedia.iso.boxes.apple.AppleCompilationBox()
+ilst-purd=com.coremedia.iso.boxes.apple.ApplePurchaseDateBox()
+ilst-\u00A9too=com.coremedia.iso.boxes.apple.AppleEncoderBox()
+ilst-sfID=com.coremedia.iso.boxes.apple.AppleStoreCountryCodeBox()
+ilst-gnre=com.coremedia.iso.boxes.apple.AppleStandardGenreBox()
+ilst-tves=com.coremedia.iso.boxes.apple.AppleTvEpisodeBox()
+ilst-ilst=com.coremedia.iso.boxes.apple.AppleItemListBox()
+ilst-data=com.coremedia.iso.boxes.apple.AppleDataBox()
+ilst-tvsn=com.coremedia.iso.boxes.apple.AppleTvSeasonBox()
+ilst-soal=com.coremedia.iso.boxes.apple.AppleSortAlbumBox()
+ilst-tven=com.coremedia.iso.boxes.apple.AppleTvEpisodeNumberBox()
+ilst-trkn=com.coremedia.iso.boxes.apple.AppleTrackNumberBox()
+ilst-\u00A9day=com.coremedia.iso.boxes.apple.AppleRecordingYearBox()
+ilst-----=com.coremedia.iso.boxes.apple.AppleGenericBox()
+ilst-akID=com.coremedia.iso.boxes.apple.AppleStoreAccountTypeBox()
+ilst-rtng=com.coremedia.iso.boxes.apple.AppleRatingBox()
+ilst-tvnn=com.coremedia.iso.boxes.apple.AppleNetworkBox()
+ilst-apID=com.coremedia.iso.boxes.apple.AppleIdBox()
+wave=com.coremedia.iso.boxes.apple.AppleWaveBox()
+
+udta-ccid=com.coremedia.iso.boxes.odf.OmaDrmContentIdBox()
+udta-yrrc=com.coremedia.iso.boxes.RecordingYearBox()
+udta-titl=com.coremedia.iso.boxes.TitleBox()
+udta-dscp=com.coremedia.iso.boxes.DescriptionBox()
+udta-icnu=com.coremedia.iso.boxes.odf.OmaDrmIconUriBox()
+udta-infu=com.coremedia.iso.boxes.odf.OmaDrmInfoUrlBox()
+udta-albm=com.coremedia.iso.boxes.AlbumBox()
+udta-cprt=com.coremedia.iso.boxes.CopyrightBox()
+udta-gnre=com.coremedia.iso.boxes.GenreBox()
+udta-perf=com.coremedia.iso.boxes.PerformerBox()
+udta-auth=com.coremedia.iso.boxes.AuthorBox()
+udta-kywd=com.coremedia.iso.boxes.KeywordsBox()
+udta-loci=com.coremedia.iso.boxes.threegpp26244.LocationInformationBox()
+udta-rtng=com.coremedia.iso.boxes.RatingBox()
+udta-clsf=com.coremedia.iso.boxes.ClassificationBox()
+udta-cdis=com.coremedia.iso.boxes.vodafone.ContentDistributorIdBox()
+udta-albr=com.coremedia.iso.boxes.vodafone.AlbumArtistBox()
+udta-cvru=com.coremedia.iso.boxes.odf.OmaDrmCoverUriBox()
+udta-lrcu=com.coremedia.iso.boxes.odf.OmaDrmLyricsUriBox()
+
+
+
+
+stsd-tx3g=com.coremedia.iso.boxes.sampleentry.TextSampleEntry(type)
+stsd-text=com.googlecode.mp4parser.boxes.apple.QuicktimeTextSampleEntry()
+stsd-enct=com.coremedia.iso.boxes.sampleentry.TextSampleEntry(type)
+stsd-samr=com.coremedia.iso.boxes.sampleentry.AudioSampleEntry(type)
+stsd-sawb=com.coremedia.iso.boxes.sampleentry.AudioSampleEntry(type)
+stsd-mp4a=com.coremedia.iso.boxes.sampleentry.AudioSampleEntry(type)
+stsd-drms=com.coremedia.iso.boxes.sampleentry.AudioSampleEntry(type)
+stsd-alac=com.coremedia.iso.boxes.sampleentry.AudioSampleEntry(type)
+stsd-mp4s=com.coremedia.iso.boxes.sampleentry.MpegSampleEntry(type)
+stsd-owma=com.coremedia.iso.boxes.sampleentry.AudioSampleEntry(type)
+stsd-ac-3=com.coremedia.iso.boxes.sampleentry.AudioSampleEntry(type)
+dac3=com.googlecode.mp4parser.boxes.AC3SpecificBox()
+stsd-ec-3=com.coremedia.iso.boxes.sampleentry.AudioSampleEntry(type)
+dec3=com.googlecode.mp4parser.boxes.EC3SpecificBox()
+stsd-lpcm=com.coremedia.iso.boxes.sampleentry.AudioSampleEntry(type)
+stsd-dtsc=com.coremedia.iso.boxes.sampleentry.AudioSampleEntry(type)
+stsd-dtsh=com.coremedia.iso.boxes.sampleentry.AudioSampleEntry(type)
+stsd-dtsl=com.coremedia.iso.boxes.sampleentry.AudioSampleEntry(type)
+ddts=com.googlecode.mp4parser.boxes.DTSSpecificBox()
+stsd-dtse=com.coremedia.iso.boxes.sampleentry.AudioSampleEntry(type)
+stsd-mlpa=com.coremedia.iso.boxes.sampleentry.AudioSampleEntry(type)
+dmlp=com.googlecode.mp4parser.boxes.MLPSpecificBox()
+stsd-enca=com.coremedia.iso.boxes.sampleentry.AudioSampleEntry(type)
+stsd-encv=com.coremedia.iso.boxes.sampleentry.VisualSampleEntry(type)
+stsd-mp4v=com.coremedia.iso.boxes.sampleentry.VisualSampleEntry(type)
+stsd-s263=com.coremedia.iso.boxes.sampleentry.VisualSampleEntry(type)
+stsd-avc1=com.coremedia.iso.boxes.sampleentry.VisualSampleEntry(type)
+stsd-ovc1=com.coremedia.iso.boxes.sampleentry.Ovc1VisualSampleEntryImpl()
+stsd-stpp=com.coremedia.iso.boxes.sampleentry.SubtitleSampleEntry(type)
+avcC=com.coremedia.iso.boxes.h264.AvcConfigurationBox()
+alac=com.coremedia.iso.boxes.apple.AppleLosslessSpecificBox()
+btrt=com.coremedia.iso.boxes.BitRateBox()
+ftyp=com.coremedia.iso.boxes.FileTypeBox()
+mdat=com.coremedia.iso.boxes.mdat.MediaDataBox()
+moov=com.coremedia.iso.boxes.MovieBox()
+mvhd=com.coremedia.iso.boxes.MovieHeaderBox()
+trak=com.coremedia.iso.boxes.TrackBox()
+tkhd=com.coremedia.iso.boxes.TrackHeaderBox()
+edts=com.coremedia.iso.boxes.EditBox()
+elst=com.coremedia.iso.boxes.EditListBox()
+mdia=com.coremedia.iso.boxes.MediaBox()
+mdhd=com.coremedia.iso.boxes.MediaHeaderBox()
+hdlr=com.coremedia.iso.boxes.HandlerBox()
+minf=com.coremedia.iso.boxes.MediaInformationBox()
+vmhd=com.coremedia.iso.boxes.VideoMediaHeaderBox()
+smhd=com.coremedia.iso.boxes.SoundMediaHeaderBox()
+sthd=com.coremedia.iso.boxes.SubtitleMediaHeaderBox()
+hmhd=com.coremedia.iso.boxes.HintMediaHeaderBox()
+dinf=com.coremedia.iso.boxes.DataInformationBox()
+dref=com.coremedia.iso.boxes.DataReferenceBox()
+url\ =com.coremedia.iso.boxes.DataEntryUrlBox()
+urn\ =com.coremedia.iso.boxes.DataEntryUrnBox()
+stbl=com.coremedia.iso.boxes.SampleTableBox()
+ctts=com.coremedia.iso.boxes.CompositionTimeToSample()
+stsd=com.coremedia.iso.boxes.SampleDescriptionBox()
+stts=com.coremedia.iso.boxes.TimeToSampleBox()
+stss=com.coremedia.iso.boxes.SyncSampleBox()
+stsc=com.coremedia.iso.boxes.SampleToChunkBox()
+stsz=com.coremedia.iso.boxes.SampleSizeBox()
+stco=com.coremedia.iso.boxes.StaticChunkOffsetBox()
+subs=com.coremedia.iso.boxes.SubSampleInformationBox()
+udta=com.coremedia.iso.boxes.UserDataBox()
+skip=com.coremedia.iso.boxes.FreeSpaceBox()
+tref=com.coremedia.iso.boxes.TrackReferenceBox()
+iloc=com.coremedia.iso.boxes.ItemLocationBox()
+idat=com.coremedia.iso.boxes.ItemDataBox()
+saio=com.coremedia.iso.boxes.SampleAuxiliaryInformationOffsetsBox()
+saiz=com.coremedia.iso.boxes.SampleAuxiliaryInformationSizesBox()
+damr=com.coremedia.iso.boxes.sampleentry.AmrSpecificBox()
+meta=com.coremedia.iso.boxes.MetaBox()
+ipro=com.coremedia.iso.boxes.ItemProtectionBox()
+sinf=com.coremedia.iso.boxes.ProtectionSchemeInformationBox()
+frma=com.coremedia.iso.boxes.OriginalFormatBox()
+schi=com.coremedia.iso.boxes.SchemeInformationBox()
+odkm=com.coremedia.iso.boxes.odf.OmaDrmKeyManagenentSystemBox()
+odaf=com.coremedia.iso.boxes.OmaDrmAccessUnitFormatBox()
+schm=com.coremedia.iso.boxes.SchemeTypeBox()
+uuid=com.coremedia.iso.boxes.UserBox(userType)
+free=com.coremedia.iso.boxes.FreeBox()
+styp=com.coremedia.iso.boxes.fragment.SegmentTypeBox()
+mvex=com.coremedia.iso.boxes.fragment.MovieExtendsBox()
+mehd=com.coremedia.iso.boxes.fragment.MovieExtendsHeaderBox()
+trex=com.coremedia.iso.boxes.fragment.TrackExtendsBox()
+
+moof=com.coremedia.iso.boxes.fragment.MovieFragmentBox()
+mfhd=com.coremedia.iso.boxes.fragment.MovieFragmentHeaderBox()
+traf=com.coremedia.iso.boxes.fragment.TrackFragmentBox()
+tfhd=com.coremedia.iso.boxes.fragment.TrackFragmentHeaderBox()
+trun=com.coremedia.iso.boxes.fragment.TrackRunBox()
+sdtp=com.coremedia.iso.boxes.SampleDependencyTypeBox()
+mfra=com.coremedia.iso.boxes.fragment.MovieFragmentRandomAccessBox()
+tfra=com.coremedia.iso.boxes.fragment.TrackFragmentRandomAccessBox()
+mfro=com.coremedia.iso.boxes.fragment.MovieFragmentRandomAccessOffsetBox()
+tfdt=com.coremedia.iso.boxes.fragment.TrackFragmentBaseMediaDecodeTimeBox()
+nmhd=com.coremedia.iso.boxes.NullMediaHeaderBox()
+gmhd=com.googlecode.mp4parser.boxes.apple.GenericMediaHeaderAtom()
+gmhd-text=com.googlecode.mp4parser.boxes.apple.GenericMediaHeaderTextAtom()
+gmin=com.googlecode.mp4parser.boxes.apple.BaseMediaInfoAtom()
+cslg=com.coremedia.iso.boxes.CompositionShiftLeastGreatestAtom()
+pdin=com.coremedia.iso.boxes.ProgressiveDownloadInformationBox()
+bloc=com.googlecode.mp4parser.boxes.ultraviolet.BaseLocationBox()
+ftab=com.googlecode.mp4parser.boxes.threegpp26245.FontTableBox()
+co64=com.coremedia.iso.boxes.ChunkOffset64BitBox()
+xml\ =com.coremedia.iso.boxes.XmlBox()
+avcn=com.googlecode.mp4parser.boxes.basemediaformat.AvcNalUnitStorageBox()
+ainf=com.googlecode.mp4parser.boxes.ultraviolet.AssetInformationBox()
+pssh=com.googlecode.mp4parser.boxes.cenc.ProtectionSystemSpecificHeaderBox()
+trik=com.coremedia.iso.boxes.dece.TrickPlayBox()
+uuid[A2394F525A9B4F14A2446C427C648DF4]=com.googlecode.mp4parser.boxes.piff.PiffSampleEncryptionBox()
+uuid[8974DBCE7BE74C5184F97148F9882554]=com.googlecode.mp4parser.boxes.piff.PiffTrackEncryptionBox()
+uuid[D4807EF2CA3946958E5426CB9E46A79F]=com.googlecode.mp4parser.boxes.piff.TfrfBox()
+uuid[6D1D9B0542D544E680E2141DAFF757B2]=com.googlecode.mp4parser.boxes.piff.TfxdBox()
+uuid[D08A4F1810F34A82B6C832D8ABA183D3]=com.googlecode.mp4parser.boxes.piff.UuidBasedProtectionSystemSpecificHeaderBox()
+senc=com.googlecode.mp4parser.boxes.basemediaformat.SampleEncryptionBox()
+tenc=com.googlecode.mp4parser.boxes.basemediaformat.TrackEncryptionBox()
+amf0=com.googlecode.mp4parser.boxes.adobe.ActionMessageFormat0SampleEntryBox()
+
+#iods=com.googlecode.mp4parser.boxes.mp4.ObjectDescriptorBox()
+esds=com.googlecode.mp4parser.boxes.mp4.ESDescriptorBox()
+
+tmcd=com.googlecode.mp4parser.boxes.apple.TimeCodeBox()
+sidx=com.googlecode.mp4parser.boxes.threegpp26244.SegmentIndexBox()
+
+sbgp=com.googlecode.mp4parser.boxes.mp4.samplegrouping.SampleToGroupBox()
+sgpd=com.googlecode.mp4parser.boxes.mp4.samplegrouping.SampleGroupDescriptionBox()
+
+tapt=com.googlecode.mp4parser.boxes.apple.TaptAtom()
+
+default=com.coremedia.iso.boxes.UnknownBox(type)
+
+
+
+#stsd-rtp\ =com.coremedia.iso.boxes.rtp.RtpHintSampleEntry(type)
+#udta-hnti=com.coremedia.iso.boxes.rtp.HintInformationBox()
+#udta-hinf=com.coremedia.iso.boxes.rtp.HintStatisticsBox()
+#hnti-sdp\ =com.coremedia.iso.boxes.rtp.RtpTrackSdpHintInformationBox()
+#hnti-rtp\ =com.coremedia.iso.boxes.rtp.RtpMovieHintInformationBox()
+#hinf-pmax=com.coremedia.iso.boxes.rtp.LargestHintPacketBox()
+#hinf-payt=com.coremedia.iso.boxes.rtp.PayloadTypeBox()
+#hinf-tmin=com.coremedia.iso.boxes.rtp.SmallestRelativeTransmissionTimeBox()
+#hinf-tmax=com.coremedia.iso.boxes.rtp.LargestRelativeTransmissionTimeBox()
+#hinf-maxr=com.coremedia.iso.boxes.rtp.MaximumDataRateBox()
+#hinf-dmax=com.coremedia.iso.boxes.rtp.LargestHintPacketDurationBox()
+#hinf-hnti=com.coremedia.iso.boxes.rtp.HintInformationBox()
+#hinf-tims=com.coremedia.iso.boxes.rtp.TimeScaleEntry()
+
+#hinf-nump=com.coremedia.iso.boxes.rtp.HintPacketsSentBox(type)
+#hinf-npck=com.coremedia.iso.boxes.rtp.HintPacketsSentBox(type)
+
+#hinf-trpy=com.coremedia.iso.boxes.rtp.HintStatisticBoxes(type)
+#hinf-totl=com.coremedia.iso.boxes.rtp.HintStatisticBoxes(type)
+#hinf-tpyl=com.coremedia.iso.boxes.rtp.HintStatisticBoxes(type)
+#hinf-tpay=com.coremedia.iso.boxes.rtp.HintStatisticBoxes(type)
+#hinf-dmed=com.coremedia.iso.boxes.rtp.HintStatisticBoxes(type)
+#hinf-dimm=com.coremedia.iso.boxes.rtp.HintStatisticBoxes(type)
+#hinf-drep=com.coremedia.iso.boxes.rtp.HintStatisticBoxes(type)
+#tims=com.coremedia.iso.boxes.rtp.TimeScaleEntry()
+
+#odrm=com.coremedia.iso.boxes.odf.OmaDrmContainerBox()
+#mdri=com.coremedia.iso.boxes.odf.MutableDrmInformationBox()
+#odtt=com.coremedia.iso.boxes.odf.OmaDrmTransactionTrackingBox()
+#odrb=com.coremedia.iso.boxes.odf.OmaDrmRightsObjectBox()
+#odhe=com.coremedia.iso.boxes.odf.OmaDrmDiscreteHeadersBox()
+#odda=com.coremedia.iso.boxes.odf.OmaDrmContentObjectBox()
+#ohdr=com.coremedia.iso.boxes.odf.OmaDrmCommonHeadersBox()
+#grpi=com.coremedia.iso.boxes.odf.OmaDrmGroupIdBox()
diff --git a/isoparser/src/main/resources/version.txt b/isoparser/src/main/resources/version.txt
new file mode 100644
index 0000000..c285390
--- /dev/null
+++ b/isoparser/src/main/resources/version.txt
@@ -0,0 +1 @@
+${project.artifactId}-${project.version}
\ No newline at end of file