Consider udta box as leaf

The MP4 standard considers the udta box as a regular container box. Quicktime, however,
considers it as a container (of only leaf atoms) that can have a terminating 32 bit
integer with value 0. Since this breaks the principle of not having content in container
boxes, this CL considers the udta box as a leaf box that contains other boxes and does
the parsing manually.

Issue: #1315
-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=117237255
This commit is contained in:
olly 2016-03-15 07:28:17 -07:00 committed by Oliver Woodman
parent bbceb459fd
commit f5b7ea676d
2 changed files with 31 additions and 13 deletions

View File

@ -335,28 +335,46 @@ import java.util.List;
* Parses a udta atom. * Parses a udta atom.
* *
* @param udtaAtom The udta (user data) atom to parse. * @param udtaAtom The udta (user data) atom to parse.
* @param isQuickTime True for QuickTime media. False otherwise.
* @return Gapless playback information stored in the user data, or {@code null} if not present. * @return Gapless playback information stored in the user data, or {@code null} if not present.
*/ */
public static GaplessInfo parseUdta(Atom.ContainerAtom udtaAtom) { public static GaplessInfo parseUdta(Atom.LeafAtom udtaAtom, boolean isQuickTime) {
Atom.LeafAtom metaAtom = udtaAtom.getLeafAtomOfType(Atom.TYPE_meta); if (isQuickTime) {
if (metaAtom == null) { // Meta boxes are regular boxes rather than full boxes in QuickTime. For now, don't try and
// parse one.
return null; return null;
} }
ParsableByteArray data = metaAtom.data; ParsableByteArray udtaData = udtaAtom.data;
data.setPosition(Atom.FULL_HEADER_SIZE); udtaData.setPosition(Atom.HEADER_SIZE);
while (udtaData.bytesLeft() >= Atom.HEADER_SIZE) {
int atomSize = udtaData.readInt();
int atomType = udtaData.readInt();
if (atomType == Atom.TYPE_meta) {
udtaData.setPosition(udtaData.getPosition() - Atom.HEADER_SIZE);
udtaData.setLimit(udtaData.getPosition() + atomSize);
return parseMetaAtom(udtaData);
} else {
udtaData.skipBytes(atomSize - Atom.HEADER_SIZE);
}
}
return null;
}
private static GaplessInfo parseMetaAtom(ParsableByteArray data) {
data.skipBytes(Atom.FULL_HEADER_SIZE);
ParsableByteArray ilst = new ParsableByteArray(); ParsableByteArray ilst = new ParsableByteArray();
while (data.bytesLeft() > 0) { while (data.bytesLeft() >= Atom.HEADER_SIZE) {
int length = data.readInt() - Atom.HEADER_SIZE; int payloadSize = data.readInt() - Atom.HEADER_SIZE;
int type = data.readInt(); int atomType = data.readInt();
if (type == Atom.TYPE_ilst) { if (atomType == Atom.TYPE_ilst) {
ilst.reset(data.data, data.getPosition() + length); ilst.reset(data.data, data.getPosition() + payloadSize);
ilst.setPosition(data.getPosition()); ilst.setPosition(data.getPosition());
GaplessInfo gaplessInfo = parseIlst(ilst); GaplessInfo gaplessInfo = parseIlst(ilst);
if (gaplessInfo != null) { if (gaplessInfo != null) {
return gaplessInfo; return gaplessInfo;
} }
} }
data.skipBytes(length); data.skipBytes(payloadSize);
} }
return null; return null;
} }

View File

@ -293,9 +293,9 @@ public final class Mp4Extractor implements Extractor, SeekMap {
List<Mp4Track> tracks = new ArrayList<>(); List<Mp4Track> tracks = new ArrayList<>();
long earliestSampleOffset = Long.MAX_VALUE; long earliestSampleOffset = Long.MAX_VALUE;
GaplessInfo gaplessInfo = null; GaplessInfo gaplessInfo = null;
Atom.ContainerAtom udta = moov.getContainerAtomOfType(Atom.TYPE_udta); Atom.LeafAtom udta = moov.getLeafAtomOfType(Atom.TYPE_udta);
if (udta != null) { if (udta != null) {
gaplessInfo = AtomParsers.parseUdta(udta); gaplessInfo = AtomParsers.parseUdta(udta, isQuickTime);
} }
for (int i = 0; i < moov.containerChildren.size(); i++) { for (int i = 0; i < moov.containerChildren.size(); i++) {
Atom.ContainerAtom atom = moov.containerChildren.get(i); Atom.ContainerAtom atom = moov.containerChildren.get(i);