Skip to content
Commits on Source (46)
......@@ -4,3 +4,11 @@
*.jar
*.war
*.ear
.idea
*.iml
examples/target
isoparser/target
isoparser/aac-sample.mp4
isoparser/ac3-sample.mp4
<component name="libraryTable">
<library name="Maven: commons-collections:commons-collections:3.2.1">
<CLASSES>
<root url="jar://$MAVEN_REPOSITORY$/commons-collections/commons-collections/3.2.1/commons-collections-3.2.1.jar!/" />
</CLASSES>
<JAVADOC>
<root url="jar://$MAVEN_REPOSITORY$/commons-collections/commons-collections/3.2.1/commons-collections-3.2.1-javadoc.jar!/" />
</JAVADOC>
<SOURCES>
<root url="jar://$MAVEN_REPOSITORY$/commons-collections/commons-collections/3.2.1/commons-collections-3.2.1-sources.jar!/" />
</SOURCES>
</library>
</component>
\ No newline at end of file
language: java
\ No newline at end of file
* Build status: [![Build Status](https://travis-ci.org/sannies/mp4parser.svg?branch=master)](https://travis-ci.org/sannies/mp4parser)
* Current central released version: [![Maven Central](https://maven-badges.herokuapp.com/maven-central/com.googlecode.mp4parser/isoparser/badge.svg)](https://maven-badges.herokuapp.com/maven-central/com.googlecode.mp4parser/isoparser)
Java MP4 Parser
====================
......@@ -8,6 +12,14 @@ Using the library
The library is published to Maven repositories. Each release is pushed to a staging repository which is published on the release page. On request specific releases can be pushed to maven central.
```
<dependency>
<groupId>com.googlecode.mp4parser</groupId>
<artifactId>isoparser</artifactId>
<version>1.1.7</version>
</dependency>
```
For projects that do not use a dependency management tool each release's artifacts (jar, javadoc-jar, source-jar) are attached to the release page. Please be aware that the project requires the aspectj-rt.jar library.
......@@ -19,10 +31,10 @@ Typical tasks for the MP4 Parser are:
- Muxing audio/video into an MP4 file
- Append recordings that use same encode settings
- Adding/Changing metadata
- Shorten recordings by ommiting frames.
- Shorten recordings by omitting frames
My examples will all use H264 and AAC as these to codecs are most typical for MP4 files. AC-3 is also not uncommon as the codec is well known from DVD.
There are also MP4 files with H263/MPEG-2 video tracks but they are no longer used widespread as most android phones You can also
My examples will all use H264 and AAC as these two codecs are most typical for MP4 files. AC-3 is also not uncommon as the codec is well known from DVD.
There are also MP4 files with H263/MPEG-2 video tracks but they are no longer used widespread as most android phones. You can also
Muxing Audio/Video
--------------------
......@@ -30,25 +42,29 @@ Muxing Audio/Video
The API and the process is straight-forward:
1. You wrap each raw format file into an appropriate Track object.
```java
H264TrackImpl h264Track = new H264TrackImpl(new FileDataSourceImpl("video.h264"));
AACTrackImpl aacTrack = new AACTrackImpl(new FileDataSourceImpl("audio.aac"));
```
2. These Track object are then added to a Movie object
```java
Movie movie = new Movie();
movie.addTrack(h264Track);
movie.addTrack(aacTrack);
```
3. The Movie object is fed into an MP4Builder to create the container.
```java
Container mp4file = new DefaultMp4Builder().build(movie);
```
4. Write the container to an appropriate sink.
```java
FileChannel fc = new FileOutputStream(new File("output.mp4")).getChannel();
mp4file.writeContainer(fc);
fc.close();
```
There are cases where the frame rate is signalled out of band or is known in advance so that the H264 doesn't contain it literally.
In this case you will have to supply it to the constructor.
......@@ -63,12 +79,12 @@ There are Track implementations for the following formats:
and additionally two subtitle tracks that do not directly wrap a raw format but they are conceptually similar.
Typical Issues
~~~~~~~~~~~~~~~
--------------------
Audio and video are not in sync. Whenever there are problems with timing possible make sure to start
Audio starts before video
~~~~~~~~~~~~~~~~~~~~~~~~~
--------------------
In AAC there are always samplerate/1024 sample/s so each sample's duration is 1000 * 1024 / samplerate milliseconds.
......@@ -80,11 +96,11 @@ to match audio and video exactly with that but the human perception is more sens
Remember: If someone is only 10 meters away the delay between audio and video is >30ms. The brain is used to that!
{code}
```java
AACTrackImpl aacTrackOriginal = new AACTrackImpl(new FileDataSourceImpl("audio.aac"));
// removes the first sample and shortens the AAC track by ~22ms
CroppedTrack aacTrackShort = new CroppedTrack(aacTrackOriginal, 1, aacTrack.getSamples().size());
{code}
```
......@@ -97,9 +113,6 @@ It is important to emphasize that you cannot append any two tracks with:
* Different resolutions
* Different frame-rates
as this leads to d
What can't you do?
--------------------
......
<?xml version="1.0" encoding="utf-8"?>
<tt xmlns="http://www.w3.org/ns/ttml" xmlns:ttm="http://www.w3.org/ns/ttml#metadata"
xmlns:tts="http://www.w3.org/ns/ttml#styling" xml:lang="en">
<head>
<metadata>
<ttm:title></ttm:title>
<ttm:desc></ttm:desc>
<ttm:copyright></ttm:copyright>
</metadata>
<styling>
<style xml:id="backgroundStyle" tts:backgroundColor="rgba(0,0,0,100)" tts:displayAlign="center"
tts:extent="80% 10%" tts:fontFamily="proportionalSansSerif" tts:fontSize="16px" tts:origin="10% 85%"
tts:textAlign="center"/>
<style style="backgroundStyle" xml:id="speakerStyle" tts:backgroundColor="transparent" tts:color="white"/>
</styling>
<layout>
<region style="speakerStyle" xml:id="speaker" tts:zIndex="1"/>
<region style="backgroundStyle" xml:id="background" tts:zIndex="0"/>
</layout>
</head>
<body>
<div style="default" xml:lang="en">
<p begin="00:00:01.000" end="00:00:03.000" region="speaker">This is pretty freaky.</p>
<p begin="00:00:57.000" end="00:00:59.000" region="speaker">Shouldn&apos;t you be down there?</p>
</div>
</body>
</tt>
\ No newline at end of file
......@@ -18,7 +18,7 @@
<dependency>
<groupId>com.googlecode.mp4parser</groupId>
<artifactId>isoparser</artifactId>
<version>1.0-RC-23-SNAPSHOT</version>
<version>1.0.4.2</version>
</dependency>
</dependencies>
<build>
......@@ -29,7 +29,7 @@
<plugin>
<groupId>com.jayway.maven.plugins.android.generation2</groupId>
<artifactId>android-maven-plugin</artifactId>
<version>3.4.0</version>
<version>4.0.0-rc.2</version>
<extensions>true</extensions>
</plugin>
</plugins>
......
mp4parser (1.1.18-1) unstable; urgency=medium
* New upstream release
- New build dependency on the maven-shade-plugin
* Removed the Maven 2 compatibility patch
* Build with DH sequencer instead of CDBS
* Standards-Version updated to 4.3.0
* Switch to debhelper level 11
* Use salsa.debian.org Vcs-* URLs
* Removed the debian/orig-tar.sh script
* Updated the Homepage field
-- Emmanuel Bourg <ebourg@apache.org> Fri, 18 Jan 2019 18:22:49 +0100
mp4parser (1.0.4.2-1) unstable; urgency=medium
* Initial release (Closes: #712972)
......
......@@ -3,18 +3,19 @@ Section: java
Priority: optional
Maintainer: Debian Java Maintainers <pkg-java-maintainers@lists.alioth.debian.org>
Uploaders: Emmanuel Bourg <ebourg@apache.org>
Build-Depends: cdbs,
debhelper (>= 9),
Build-Depends:
debhelper (>= 11),
default-jdk,
junit4,
libaspectj-maven-plugin-java,
libcommons-codec-java,
libcommons-io-java,
maven-debian-helper (>= 1.5)
Standards-Version: 3.9.6
Vcs-Git: git://anonscm.debian.org/pkg-java/mp4parser.git
Vcs-Browser: https://anonscm.debian.org/cgit/pkg-java/mp4parser.git
Homepage: http://code.google.com/p/mp4parser/
libmaven-shade-plugin-java,
maven-debian-helper (>= 2.0)
Standards-Version: 4.3.0
Vcs-Git: https://salsa.debian.org/java-team/mp4parser.git
Vcs-Browser: https://salsa.debian.org/java-team/mp4parser
Homepage: https://github.com/sannies/mp4parser
Package: libisoparser-java
Architecture: all
......
Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
Upstream-Name: MP4 Parser Project
Upstream-Contact: Sebastian Annies
Source: http://code.google.com/p/mp4parser/
Source: https://github.com/sannies/mp4parser
Files-Excluded: examples/src
androidtest/src
*/src/test/resources/*
Files: *
Copyright: 2008, CoreMedia AG
......
#!/bin/sh
VERSION=$2
TAR=../mp4parser_$VERSION.orig.tar.xz
DIR=mp4parser-$VERSION
mkdir $DIR
tar -xf $3 --strip-components=1 -C $DIR
rm $3
XZ_OPT=--best tar -c -v -J -f $TAR \
--exclude='examples/src' \
--exclude='androidtest/src' \
--exclude='*.3gp' \
--exclude='*.aac' \
--exclude='*.ac3' \
--exclude='*.f4v' \
--exclude='*.m4a' \
--exclude='*.m4p' \
--exclude='*.m4s' \
--exclude='*.mp4' \
--exclude='*.mp4f' \
--exclude='*.h264' \
--exclude='*.srt' \
--exclude='*.odf' \
$DIR
rm -Rf $DIR
Description: Remove the prerequisites on Maven 3
Author: Emmanuel Bourg <ebourg@apache.org>
Forwarded: not-needed
diff --git a/pom.xml b/pom.xml
index 1d080c9..6863889 100644
--- a/pom.xml
+++ b/pom.xml
@@ -16,9 +16,6 @@
<module>isoparser</module>
<module>examples</module>
</modules>
- <prerequisites>
- <maven>3.0</maven>
- </prerequisites>
<profiles>
<profile>
<id>android</id>
01-maven2-compatibility.patch
02-disable-android-logger.patch
#!/usr/bin/make -f
include /usr/share/cdbs/1/rules/debhelper.mk
include /usr/share/cdbs/1/class/maven.mk
JAVA_HOME := /usr/lib/jvm/default-java
DEB_MAVEN_ARGS := -DtoolsjarSystemPath=$(JAVA_HOME)/lib/tools.jar
get-orig-source:
uscan --download-current-version --force-download --no-symlink
%:
dh $@
version=3
https://github.com/sannies/mp4parser/tags .*/mp4parser-project-(.*).tar.gz debian debian/orig-tar.sh
version=4
opts="mode=git,repack,compression=xz" \
https://github.com/sannies/mp4parser refs/tags/mp4parser-project-(.*)
......@@ -5,17 +5,17 @@
<artifactId>examples</artifactId>
<name>ISO Parser Examples</name>
<version>1.0.4.2</version>
<version>1.1.18</version>
<parent>
<groupId>com.googlecode.mp4parser</groupId>
<artifactId>mp4parser-project</artifactId>
<version>1.0.4.2</version>
<version>1.1.18</version>
</parent>
<dependencies>
<dependency>
<groupId>com.googlecode.mp4parser</groupId>
<artifactId>isoparser</artifactId>
<version>1.0.4.2</version>
<version>1.1.18</version>
</dependency>
<dependency>
<groupId>xom</groupId>
......@@ -42,6 +42,11 @@
<artifactId>jetty-server</artifactId>
<version>8.1.7.v20120910</version>
</dependency>
<dependency>
<groupId>commons-collections</groupId>
<artifactId>commons-collections</artifactId>
<version>3.2.1</version>
</dependency>
</dependencies>
......@@ -74,7 +79,7 @@
<scm>
<url>http://code.google.com/p/mp4parser/source/browse/</url>
<connection>scm:svn:https://mp4parser.googlecode.com/svn/trunk/examples</connection>
<tag>mp4parser-project-1.0.4.2-2</tag>
<tag> mp4parser-project-1.1.18</tag>
</scm>
<repositories>
<repository>
......
......@@ -7,7 +7,7 @@
<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.4.2</version>
<version>1.1.18</version>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
......@@ -22,41 +22,6 @@
</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>
......@@ -84,6 +49,11 @@
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
<version>2.4</version>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-resources-plugin</artifactId>
......@@ -99,29 +69,26 @@
</configuration>
</plugin>
<plugin>
<inherited>true</inherited>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
<version>2.1.2</version>
<artifactId>maven-shade-plugin</artifactId>
<version>2.4.1</version>
<executions>
<execution>
<id>attach-sources</id>
<phase>verify</phase>
<goals>
<goal>jar</goal>
<goal>shade</goal>
</goals>
</execution>
</executions>
<configuration>
<createSourcesJar>true</createSourcesJar>
<relocations>
<relocation>
<pattern>org.aspectj</pattern>
<shadedPattern>org.mp4parser.aspectj</shadedPattern>
</relocation>
</relocations>
</configuration>
</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>
......@@ -167,19 +134,6 @@
</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>
......@@ -193,6 +147,7 @@
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
......@@ -211,8 +166,8 @@
</mailingLists>
<issueManagement>
<system>google-code</system>
<url>http://code.google.com/p/mp4parser/issues/list</url>
<system>github</system>
<url>https://github.com/sannies/mp4parser/issues</url>
</issueManagement>
<developers>
......@@ -226,7 +181,7 @@
<snapshotRepository>
<id>release</id>
<name>Sonatype Nexus Snapshots</name>
<url>https://repository.castlabs.com/content/repositories/snapshots/</url>
<url>http://repository.castlabs.com/content/repositories/snapshots/</url>
</snapshotRepository>
<repository>
<id>sonatype-nexus-staging</id>
......@@ -242,12 +197,12 @@
<scm>
<url>https://github.com/sannies/mp4parser</url>
<tag>mp4parser-project-1.0.4.2-2</tag>
<tag> mp4parser-project-1.1.18</tag>
</scm>
<licenses>
<license>
<name>Apache 2</name>
<name>Apache Software License - Version 2.0</name>
<url>http://www.apache.org/licenses/LICENSE-2.0.txt</url>
<distribution>repo</distribution>
<comments>A business-friendly OSS license</comments>
......
......@@ -101,7 +101,7 @@ public abstract class AbstractBoxParser implements BoxParser {
Box box = createBox(type, usertype, (parent instanceof Box) ? ((Box) parent).getType() : "");
box.setParent(parent);
//LOG.finest("Parsing " + box.getType());
// System.out.println("parsing " + Arrays.toString(box.getType()) + " " + box.getClass().getName() + " size=" + size);
// System.out.println("parsing " + Mp4Arrays.toString(box.getType()) + " " + box.getClass().getName() + " size=" + size);
header.get().rewind();
box.parse(byteChannel, header.get(), contentSize, this);
......
......@@ -156,30 +156,17 @@ public final class IsoTypeReader {
}
private static IntHashMap codeCache = new IntHashMap();
private static byte[] codeBytes = new byte[4];
public static String read4cc(ByteBuffer bb) {
byte[] codeBytes = new byte[4];
bb.get(codeBytes);
int result = ((codeBytes[0] << 24) & 0xFF000000);
result |= ((codeBytes[1] << 16) & 0xFF0000);
result |= ((codeBytes[2] << 8) & 0xFF00);
result |= ((codeBytes[3]) & 0xFF);
String code;
if ((code = (String) codeCache.get(result)) != null) {
return code;
} else {
try {
code = new String(codeBytes, "ISO-8859-1");
codeCache.put(result, code);
return code;
return new String(codeBytes, "ISO-8859-1");
} catch (UnsupportedEncodingException e) {
throw new RuntimeException(e);
}
}
}
public static long readUInt48(ByteBuffer byteBuffer) {
......
......@@ -81,9 +81,9 @@ public class PropertyBoxParserImpl extends AbstractBoxParser {
public Box createBox(String type, byte[] userType, String parent) {
invoke(type, userType, parent);
String[] param = this.param.get();
try {
Class<Box> clazz = (Class<Box>) Class.forName(clazzName);
Class<Box> clazz = (Class<Box>) Class.forName(clazzName.get());
if (param.length > 0) {
Class[] constructorArgsClazz = new Class[param.length];
Object[] constructorArgs = new Object[param.length];
......@@ -123,8 +123,8 @@ public class PropertyBoxParserImpl extends AbstractBoxParser {
StringBuilder buildLookupStrings = new StringBuilder();
String clazzName;
String param[];
ThreadLocal<String> clazzName = new ThreadLocal<String>();
ThreadLocal<String[]> param = new ThreadLocal<String[]>();
static String[] EMPTY_STRING_ARRAY = new String[0];
public void invoke(String type, byte[] userType, String parent) {
......@@ -156,19 +156,19 @@ public class PropertyBoxParserImpl extends AbstractBoxParser {
throw new RuntimeException("No box object found for " + type);
}
if (!constructor.endsWith(")")) {
param = EMPTY_STRING_ARRAY;
clazzName = constructor;
param.set( EMPTY_STRING_ARRAY);
clazzName.set(constructor);
} else {
Matcher m = constuctorPattern.matcher(constructor);
boolean matches = m.matches();
if (!matches) {
throw new RuntimeException("Cannot work with that constructor: " + constructor);
}
clazzName = m.group(1);
clazzName.set( m.group(1));
if (m.group(2).length() == 0) {
param = EMPTY_STRING_ARRAY;
param.set(EMPTY_STRING_ARRAY);
} else {
param = m.group(2).length() > 0 ? m.group(2).split(",") : new String[]{};
param.set(m.group(2).length() > 0 ? m.group(2).split(",") : new String[]{});
}
}
......