/*
* Copyright (C) 2014 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.
*/
package com.google.android.exoplayer.extractor.mp4;
import com.google.android.exoplayer.util.ParsableByteArray;
import com.google.android.exoplayer.util.Util;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
/* package*/ abstract class Atom {
/**
* Size of an atom header, in bytes.
*/
public static final int HEADER_SIZE = 8;
/**
* Size of a full atom header, in bytes.
*/
public static final int FULL_HEADER_SIZE = 12;
/**
* Size of a long atom header, in bytes.
*/
public static final int LONG_HEADER_SIZE = 16;
/**
* Value for the first 32 bits of atomSize when the atom size is actually a long value.
*/
public static final int LONG_SIZE_PREFIX = 1;
public static final int TYPE_ftyp = Util.getIntegerCodeForString("ftyp");
public static final int TYPE_avc1 = Util.getIntegerCodeForString("avc1");
public static final int TYPE_avc3 = Util.getIntegerCodeForString("avc3");
public static final int TYPE_hvc1 = Util.getIntegerCodeForString("hvc1");
public static final int TYPE_hev1 = Util.getIntegerCodeForString("hev1");
public static final int TYPE_s263 = Util.getIntegerCodeForString("s263");
public static final int TYPE_d263 = Util.getIntegerCodeForString("d263");
public static final int TYPE_mdat = Util.getIntegerCodeForString("mdat");
public static final int TYPE_mp4a = Util.getIntegerCodeForString("mp4a");
public static final int TYPE_ac_3 = Util.getIntegerCodeForString("ac-3");
public static final int TYPE_dac3 = Util.getIntegerCodeForString("dac3");
public static final int TYPE_ec_3 = Util.getIntegerCodeForString("ec-3");
public static final int TYPE_dec3 = Util.getIntegerCodeForString("dec3");
public static final int TYPE_dtsc = Util.getIntegerCodeForString("dtsc");
public static final int TYPE_dtsh = Util.getIntegerCodeForString("dtsh");
public static final int TYPE_dtsl = Util.getIntegerCodeForString("dtsl");
public static final int TYPE_dtse = Util.getIntegerCodeForString("dtse");
public static final int TYPE_ddts = Util.getIntegerCodeForString("ddts");
public static final int TYPE_tfdt = Util.getIntegerCodeForString("tfdt");
public static final int TYPE_tfhd = Util.getIntegerCodeForString("tfhd");
public static final int TYPE_trex = Util.getIntegerCodeForString("trex");
public static final int TYPE_trun = Util.getIntegerCodeForString("trun");
public static final int TYPE_sidx = Util.getIntegerCodeForString("sidx");
public static final int TYPE_moov = Util.getIntegerCodeForString("moov");
public static final int TYPE_mvhd = Util.getIntegerCodeForString("mvhd");
public static final int TYPE_trak = Util.getIntegerCodeForString("trak");
public static final int TYPE_mdia = Util.getIntegerCodeForString("mdia");
public static final int TYPE_minf = Util.getIntegerCodeForString("minf");
public static final int TYPE_stbl = Util.getIntegerCodeForString("stbl");
public static final int TYPE_avcC = Util.getIntegerCodeForString("avcC");
public static final int TYPE_hvcC = Util.getIntegerCodeForString("hvcC");
public static final int TYPE_esds = Util.getIntegerCodeForString("esds");
public static final int TYPE_moof = Util.getIntegerCodeForString("moof");
public static final int TYPE_traf = Util.getIntegerCodeForString("traf");
public static final int TYPE_mvex = Util.getIntegerCodeForString("mvex");
public static final int TYPE_tkhd = Util.getIntegerCodeForString("tkhd");
public static final int TYPE_mdhd = Util.getIntegerCodeForString("mdhd");
public static final int TYPE_hdlr = Util.getIntegerCodeForString("hdlr");
public static final int TYPE_stsd = Util.getIntegerCodeForString("stsd");
public static final int TYPE_pssh = Util.getIntegerCodeForString("pssh");
public static final int TYPE_sinf = Util.getIntegerCodeForString("sinf");
public static final int TYPE_schm = Util.getIntegerCodeForString("schm");
public static final int TYPE_schi = Util.getIntegerCodeForString("schi");
public static final int TYPE_tenc = Util.getIntegerCodeForString("tenc");
public static final int TYPE_encv = Util.getIntegerCodeForString("encv");
public static final int TYPE_enca = Util.getIntegerCodeForString("enca");
public static final int TYPE_frma = Util.getIntegerCodeForString("frma");
public static final int TYPE_saiz = Util.getIntegerCodeForString("saiz");
public static final int TYPE_uuid = Util.getIntegerCodeForString("uuid");
public static final int TYPE_senc = Util.getIntegerCodeForString("senc");
public static final int TYPE_pasp = Util.getIntegerCodeForString("pasp");
public static final int TYPE_TTML = Util.getIntegerCodeForString("TTML");
public static final int TYPE_vmhd = Util.getIntegerCodeForString("vmhd");
public static final int TYPE_smhd = Util.getIntegerCodeForString("smhd");
public static final int TYPE_mp4v = Util.getIntegerCodeForString("mp4v");
public static final int TYPE_stts = Util.getIntegerCodeForString("stts");
public static final int TYPE_stss = Util.getIntegerCodeForString("stss");
public static final int TYPE_ctts = Util.getIntegerCodeForString("ctts");
public static final int TYPE_stsc = Util.getIntegerCodeForString("stsc");
public static final int TYPE_stsz = Util.getIntegerCodeForString("stsz");
public static final int TYPE_stco = Util.getIntegerCodeForString("stco");
public static final int TYPE_co64 = Util.getIntegerCodeForString("co64");
public static final int TYPE_tx3g = Util.getIntegerCodeForString("tx3g");
public static final int TYPE_stpp = Util.getIntegerCodeForString("stpp");
public final int type;
public Atom(int type) {
this.type = type;
}
@Override
public String toString() {
return getAtomTypeString(type);
}
/**
* An MP4 atom that is a leaf.
*/
/* package */ static final class LeafAtom extends Atom {
/**
* The atom data.
*/
public final ParsableByteArray data;
/**
* @param type The type of the atom.
* @param data The atom data.
*/
public LeafAtom(int type, ParsableByteArray data) {
super(type);
this.data = data;
}
}
/**
* An MP4 atom that has child atoms.
*/
/* package */ static final class ContainerAtom extends Atom {
public final long endPosition;
public final List<LeafAtom> leafChildren;
public final List<ContainerAtom> containerChildren;
/**
* @param type The type of the atom.
* @param endPosition The position of the first byte after the end of the atom.
*/
public ContainerAtom(int type, long endPosition) {
super(type);
this.endPosition = endPosition;
leafChildren = new ArrayList<>();
containerChildren = new ArrayList<>();
}
/**
* Adds a child leaf to this container.
*
* @param atom The child to add.
*/
public void add(LeafAtom atom) {
leafChildren.add(atom);
}
/**
* Adds a child container to this container.
*
* @param atom The child to add.
*/
public void add(ContainerAtom atom) {
containerChildren.add(atom);
}
/**
* Gets the child leaf of the given type.
* <p>
* If no child exists with the given type then null is returned. If multiple children exist with
* the given type then the first one to have been added is returned.
*
* @param type The leaf type.
* @return The child leaf of the given type, or null if no such child exists.
*/
public LeafAtom getLeafAtomOfType(int type) {
int childrenSize = leafChildren.size();
for (int i = 0; i < childrenSize; i++) {
LeafAtom atom = leafChildren.get(i);
if (atom.type == type) {
return atom;
}
}
return null;
}
/**
* Gets the child container of the given type.
* <p>
* If no child exists with the given type then null is returned. If multiple children exist with
* the given type then the first one to have been added is returned.
*
* @param type The container type.
* @return The child container of the given type, or null if no such child exists.
*/
public ContainerAtom getContainerAtomOfType(int type) {
int childrenSize = containerChildren.size();
for (int i = 0; i < childrenSize; i++) {
ContainerAtom atom = containerChildren.get(i);
if (atom.type == type) {
return atom;
}
}
return null;
}
@Override
public String toString() {
return getAtomTypeString(type)
+ " leaves: " + Arrays.toString(leafChildren.toArray(new LeafAtom[0]))
+ " containers: " + Arrays.toString(containerChildren.toArray(new ContainerAtom[0]));
}
}
/**
* Parses the version number out of the additional integer component of a full atom.
*/
public static int parseFullAtomVersion(int fullAtomInt) {
return 0x000000FF & (fullAtomInt >> 24);
}
/**
* Parses the atom flags out of the additional integer component of a full atom.
*/
public static int parseFullAtomFlags(int fullAtomInt) {
return 0x00FFFFFF & fullAtomInt;
}
/**
* Converts a numeric atom type to the corresponding four character string.
*
* @param type The numeric atom type.
* @return The corresponding four character string.
*/
public static String getAtomTypeString(int type) {
return "" + (char) (type >> 24)
+ (char) ((type >> 16) & 0xFF)
+ (char) ((type >> 8) & 0xFF)
+ (char) (type & 0xFF);
}
}