diff --git a/libraries/extractor/src/main/java/androidx/media3/extractor/mp4/Atom.java b/libraries/container/src/main/java/androidx/media3/container/Mp4Box.java similarity index 89% rename from libraries/extractor/src/main/java/androidx/media3/extractor/mp4/Atom.java rename to libraries/container/src/main/java/androidx/media3/container/Mp4Box.java index ddae52aa83..a410436205 100644 --- a/libraries/extractor/src/main/java/androidx/media3/extractor/mp4/Atom.java +++ b/libraries/container/src/main/java/androidx/media3/container/Mp4Box.java @@ -13,30 +13,33 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package androidx.media3.extractor.mp4; +package androidx.media3.container; import androidx.annotation.Nullable; import androidx.media3.common.util.ParsableByteArray; +import androidx.media3.common.util.UnstableApi; import java.util.ArrayList; import java.util.Arrays; import java.util.List; +/** A representation of an MP4 box (aka atom). */ @SuppressWarnings("ConstantField") -/* package */ abstract class Atom { +@UnstableApi +public abstract class Mp4Box { - /** Size of an atom header, in bytes. */ + /** Size of a box header, in bytes. */ public static final int HEADER_SIZE = 8; - /** Size of a full atom header, in bytes. */ + /** Size of a full box header, in bytes. */ public static final int FULL_HEADER_SIZE = 12; - /** Size of a long atom header, in bytes. */ + /** Size of a long box header, in bytes. */ public static final int LONG_HEADER_SIZE = 16; - /** Value for the size field in an atom that defines its size in the largesize field. */ + /** Value for the size field in a box that defines its size in the largesize field. */ public static final int DEFINES_LARGE_SIZE = 1; - /** Value for the size field in an atom that extends to the end of the file. */ + /** Value for the size field in a box that extends to the end of the file. */ public static final int EXTENDS_TO_END_SIZE = 0; @SuppressWarnings("ConstantCaseForConstants") @@ -451,43 +454,44 @@ import java.util.List; public final int type; - public Atom(int type) { + // private to only allow sub-classing from within this file. + private Mp4Box(int type) { this.type = type; } @Override public String toString() { - return getAtomTypeString(type); + return getBoxTypeString(type); } - /** An MP4 atom that is a leaf. */ - /* package */ static final class LeafAtom extends Atom { + /** An MP4 box that is a leaf. */ + public static final class LeafBox extends Mp4Box { - /** The atom data. */ + /** The box data. */ public final ParsableByteArray data; /** - * @param type The type of the atom. - * @param data The atom data. + * @param type The type of the box. + * @param data The box data. */ - public LeafAtom(int type, ParsableByteArray data) { + public LeafBox(int type, ParsableByteArray data) { super(type); this.data = data; } } - /** An MP4 atom that has child atoms. */ - /* package */ static final class ContainerAtom extends Atom { + /** An MP4 box that has child boxes. */ + public static final class ContainerBox extends Mp4Box { public final long endPosition; - public final List leafChildren; - public final List containerChildren; + public final List leafChildren; + public final List containerChildren; /** - * @param type The type of the atom. - * @param endPosition The position of the first byte after the end of the atom. + * @param type The type of the box. + * @param endPosition The position of the first byte after the end of the box. */ - public ContainerAtom(int type, long endPosition) { + public ContainerBox(int type, long endPosition) { super(type); this.endPosition = endPosition; leafChildren = new ArrayList<>(); @@ -497,19 +501,19 @@ import java.util.List; /** * Adds a child leaf to this container. * - * @param atom The child to add. + * @param box The child to add. */ - public void add(LeafAtom atom) { - leafChildren.add(atom); + public void add(LeafBox box) { + leafChildren.add(box); } /** * Adds a child container to this container. * - * @param atom The child to add. + * @param box The child to add. */ - public void add(ContainerAtom atom) { - containerChildren.add(atom); + public void add(ContainerBox box) { + containerChildren.add(box); } /** @@ -522,12 +526,12 @@ import java.util.List; * @return The child leaf of the given type, or null if no such child exists. */ @Nullable - public LeafAtom getLeafAtomOfType(int type) { + public LeafBox getLeafBoxOfType(int type) { int childrenSize = leafChildren.size(); for (int i = 0; i < childrenSize; i++) { - LeafAtom atom = leafChildren.get(i); - if (atom.type == type) { - return atom; + LeafBox box = leafChildren.get(i); + if (box.type == type) { + return box; } } return null; @@ -543,12 +547,12 @@ import java.util.List; * @return The child container of the given type, or null if no such child exists. */ @Nullable - public ContainerAtom getContainerAtomOfType(int type) { + public ContainerBox getContainerBoxOfType(int type) { int childrenSize = containerChildren.size(); for (int i = 0; i < childrenSize; i++) { - ContainerAtom atom = containerChildren.get(i); - if (atom.type == type) { - return atom; + ContainerBox box = containerChildren.get(i); + if (box.type == type) { + return box; } } return null; @@ -556,7 +560,7 @@ import java.util.List; @Override public String toString() { - return getAtomTypeString(type) + return getBoxTypeString(type) + " leaves: " + Arrays.toString(leafChildren.toArray()) + " containers: " @@ -565,12 +569,12 @@ import java.util.List; } /** - * Converts a numeric atom type to the corresponding four character string. + * Converts a numeric box type to the corresponding four character string. * - * @param type The numeric atom type. + * @param type The numeric box type. * @return The corresponding four character string. */ - public static String getAtomTypeString(int type) { + public static String getBoxTypeString(int type) { return "" + (char) ((type >> 24) & 0xFF) + (char) ((type >> 16) & 0xFF) diff --git a/libraries/extractor/src/main/java/androidx/media3/extractor/mp4/AtomParsers.java b/libraries/extractor/src/main/java/androidx/media3/extractor/mp4/AtomParsers.java index 2a93dd8297..2cec2512fb 100644 --- a/libraries/extractor/src/main/java/androidx/media3/extractor/mp4/AtomParsers.java +++ b/libraries/extractor/src/main/java/androidx/media3/extractor/mp4/AtomParsers.java @@ -35,6 +35,8 @@ import androidx.media3.common.util.NullableType; import androidx.media3.common.util.ParsableBitArray; import androidx.media3.common.util.ParsableByteArray; import androidx.media3.common.util.Util; +import androidx.media3.container.Mp4Box; +import androidx.media3.container.Mp4Box.LeafBox; import androidx.media3.container.Mp4LocationData; import androidx.media3.container.Mp4TimestampData; import androidx.media3.container.NalUnitUtil; @@ -48,7 +50,6 @@ import androidx.media3.extractor.GaplessInfoHolder; import androidx.media3.extractor.HevcConfig; import androidx.media3.extractor.OpusUtil; import androidx.media3.extractor.VorbisUtil; -import androidx.media3.extractor.mp4.Atom.LeafAtom; import com.google.common.base.Function; import com.google.common.collect.ImmutableList; import com.google.common.primitives.Ints; @@ -129,7 +130,7 @@ import java.util.Objects; * @throws ParserException Thrown if the trak atoms can't be parsed. */ public static List parseTraks( - Atom.ContainerAtom moov, + Mp4Box.ContainerBox moov, GaplessInfoHolder gaplessInfoHolder, long duration, @Nullable DrmInitData drmInitData, @@ -139,8 +140,8 @@ import java.util.Objects; throws ParserException { List trackSampleTables = new ArrayList<>(); for (int i = 0; i < moov.containerChildren.size(); i++) { - Atom.ContainerAtom atom = moov.containerChildren.get(i); - if (atom.type != Atom.TYPE_trak) { + Mp4Box.ContainerBox atom = moov.containerChildren.get(i); + if (atom.type != Mp4Box.TYPE_trak) { continue; } @Nullable @@ -148,7 +149,7 @@ import java.util.Objects; modifyTrackFunction.apply( parseTrak( atom, - checkNotNull(moov.getLeafAtomOfType(Atom.TYPE_mvhd)), + checkNotNull(moov.getLeafBoxOfType(Mp4Box.TYPE_mvhd)), duration, drmInitData, ignoreEditLists, @@ -156,12 +157,12 @@ import java.util.Objects; if (track == null) { continue; } - Atom.ContainerAtom stblAtom = + Mp4Box.ContainerBox stblAtom = checkNotNull( checkNotNull( - checkNotNull(atom.getContainerAtomOfType(Atom.TYPE_mdia)) - .getContainerAtomOfType(Atom.TYPE_minf)) - .getContainerAtomOfType(Atom.TYPE_stbl)); + checkNotNull(atom.getContainerBoxOfType(Mp4Box.TYPE_mdia)) + .getContainerBoxOfType(Mp4Box.TYPE_minf)) + .getContainerBoxOfType(Mp4Box.TYPE_stbl)); TrackSampleTable trackSampleTable = parseStbl(track, stblAtom, gaplessInfoHolder); trackSampleTables.add(trackSampleTable); } @@ -174,24 +175,24 @@ import java.util.Objects; * @param udtaAtom The udta (user data) atom to decode. * @return Parsed metadata. */ - public static Metadata parseUdta(Atom.LeafAtom udtaAtom) { + public static Metadata parseUdta(LeafBox udtaAtom) { ParsableByteArray udtaData = udtaAtom.data; - udtaData.setPosition(Atom.HEADER_SIZE); + udtaData.setPosition(Mp4Box.HEADER_SIZE); Metadata metadata = new Metadata(); - while (udtaData.bytesLeft() >= Atom.HEADER_SIZE) { + while (udtaData.bytesLeft() >= Mp4Box.HEADER_SIZE) { int atomPosition = udtaData.getPosition(); int atomSize = udtaData.readInt(); int atomType = udtaData.readInt(); - if (atomType == Atom.TYPE_meta) { + if (atomType == Mp4Box.TYPE_meta) { udtaData.setPosition(atomPosition); metadata = metadata.copyWithAppendedEntriesFrom(parseUdtaMeta(udtaData, atomPosition + atomSize)); - } else if (atomType == Atom.TYPE_smta) { + } else if (atomType == Mp4Box.TYPE_smta) { udtaData.setPosition(atomPosition); metadata = metadata.copyWithAppendedEntriesFrom( SmtaAtomUtil.parseSmta(udtaData, atomPosition + atomSize)); - } else if (atomType == Atom.TYPE_xyz) { + } else if (atomType == Mp4Box.TYPE_xyz) { metadata = metadata.copyWithAppendedEntriesFrom(parseXyz(udtaData)); } udtaData.setPosition(atomPosition + atomSize); @@ -206,7 +207,7 @@ import java.util.Objects; * @return An object containing the parsed data. */ public static Mp4TimestampData parseMvhd(ParsableByteArray mvhd) { - mvhd.setPosition(Atom.HEADER_SIZE); + mvhd.setPosition(Mp4Box.HEADER_SIZE); int fullAtom = mvhd.readInt(); int version = parseFullAtomVersion(fullAtom); long creationTimestampSeconds; @@ -230,10 +231,10 @@ import java.util.Objects; * @return Parsed metadata, or null. */ @Nullable - public static Metadata parseMdtaFromMeta(Atom.ContainerAtom meta) { - @Nullable Atom.LeafAtom hdlrAtom = meta.getLeafAtomOfType(Atom.TYPE_hdlr); - @Nullable Atom.LeafAtom keysAtom = meta.getLeafAtomOfType(Atom.TYPE_keys); - @Nullable Atom.LeafAtom ilstAtom = meta.getLeafAtomOfType(Atom.TYPE_ilst); + public static Metadata parseMdtaFromMeta(Mp4Box.ContainerBox meta) { + @Nullable LeafBox hdlrAtom = meta.getLeafBoxOfType(Mp4Box.TYPE_hdlr); + @Nullable LeafBox keysAtom = meta.getLeafBoxOfType(Mp4Box.TYPE_keys); + @Nullable LeafBox ilstAtom = meta.getLeafBoxOfType(Mp4Box.TYPE_ilst); if (hdlrAtom == null || keysAtom == null || ilstAtom == null @@ -244,7 +245,7 @@ import java.util.Objects; // Parse metadata keys. ParsableByteArray keys = keysAtom.data; - keys.setPosition(Atom.FULL_HEADER_SIZE); + keys.setPosition(Mp4Box.FULL_HEADER_SIZE); int entryCount = keys.readInt(); String[] keyNames = new String[entryCount]; for (int i = 0; i < entryCount; i++) { @@ -256,9 +257,9 @@ import java.util.Objects; // Parse metadata items. ParsableByteArray ilst = ilstAtom.data; - ilst.setPosition(Atom.HEADER_SIZE); + ilst.setPosition(Mp4Box.HEADER_SIZE); ArrayList entries = new ArrayList<>(); - while (ilst.bytesLeft() > Atom.HEADER_SIZE) { + while (ilst.bytesLeft() > Mp4Box.HEADER_SIZE) { int atomPosition = ilst.getPosition(); int atomSize = ilst.readInt(); int keyIndex = ilst.readInt() - 1; @@ -281,11 +282,11 @@ import java.util.Objects; /** * Possibly skips the version and flags fields (1+3 byte) of a full meta atom. * - *

Atoms of type {@link Atom#TYPE_meta} are defined to be full atoms which have four additional - * bytes for a version and a flags field (see 4.2 'Object Structure' in ISO/IEC 14496-12:2005). - * QuickTime do not have such a full box structure. Since some of these files are encoded wrongly, - * we can't rely on the file type though. Instead we must check the 8 bytes after the common - * header bytes ourselves. + *

Atoms of type {@link Mp4Box#TYPE_meta} are defined to be full atoms which have four + * additional bytes for a version and a flags field (see 4.2 'Object Structure' in ISO/IEC + * 14496-12:2005). QuickTime do not have such a full box structure. Since some of these files are + * encoded wrongly, we can't rely on the file type though. Instead we must check the 8 bytes after + * the common header bytes ourselves. * * @param meta The 8 or more bytes following the meta atom size and type. */ @@ -296,7 +297,7 @@ import java.util.Objects; // (qt) [4 byte size of next atom ][4 byte hdlr atom type ] // In case of (iso) we need to skip the next 4 bytes. meta.skipBytes(4); - if (meta.readInt() != Atom.TYPE_hdlr) { + if (meta.readInt() != Mp4Box.TYPE_hdlr) { endPosition += 4; } meta.setPosition(endPosition); @@ -317,22 +318,22 @@ import java.util.Objects; */ @Nullable private static Track parseTrak( - Atom.ContainerAtom trak, - Atom.LeafAtom mvhd, + Mp4Box.ContainerBox trak, + LeafBox mvhd, long duration, @Nullable DrmInitData drmInitData, boolean ignoreEditLists, boolean isQuickTime) throws ParserException { - Atom.ContainerAtom mdia = checkNotNull(trak.getContainerAtomOfType(Atom.TYPE_mdia)); + Mp4Box.ContainerBox mdia = checkNotNull(trak.getContainerBoxOfType(Mp4Box.TYPE_mdia)); @C.TrackType int trackType = - getTrackTypeForHdlr(parseHdlr(checkNotNull(mdia.getLeafAtomOfType(Atom.TYPE_hdlr)).data)); + getTrackTypeForHdlr(parseHdlr(checkNotNull(mdia.getLeafBoxOfType(Mp4Box.TYPE_hdlr)).data)); if (trackType == C.TRACK_TYPE_UNKNOWN) { return null; } - TkhdData tkhdData = parseTkhd(checkNotNull(trak.getLeafAtomOfType(Atom.TYPE_tkhd)).data); + TkhdData tkhdData = parseTkhd(checkNotNull(trak.getLeafBoxOfType(Mp4Box.TYPE_tkhd)).data); if (duration == C.TIME_UNSET) { duration = tkhdData.duration; } @@ -343,14 +344,14 @@ import java.util.Objects; } else { durationUs = Util.scaleLargeTimestamp(duration, C.MICROS_PER_SECOND, movieTimescale); } - Atom.ContainerAtom stbl = + Mp4Box.ContainerBox stbl = checkNotNull( - checkNotNull(mdia.getContainerAtomOfType(Atom.TYPE_minf)) - .getContainerAtomOfType(Atom.TYPE_stbl)); + checkNotNull(mdia.getContainerBoxOfType(Mp4Box.TYPE_minf)) + .getContainerBoxOfType(Mp4Box.TYPE_stbl)); Pair mdhdData = - parseMdhd(checkNotNull(mdia.getLeafAtomOfType(Atom.TYPE_mdhd)).data); - LeafAtom stsd = stbl.getLeafAtomOfType(Atom.TYPE_stsd); + parseMdhd(checkNotNull(mdia.getLeafBoxOfType(Mp4Box.TYPE_mdhd)).data); + LeafBox stsd = stbl.getLeafBoxOfType(Mp4Box.TYPE_stsd); if (stsd == null) { throw ParserException.createForMalformedContainer( "Malformed sample table (stbl) missing sample description (stsd)", /* cause= */ null); @@ -366,7 +367,7 @@ import java.util.Objects; @Nullable long[] editListDurations = null; @Nullable long[] editListMediaTimes = null; if (!ignoreEditLists) { - @Nullable Atom.ContainerAtom edtsAtom = trak.getContainerAtomOfType(Atom.TYPE_edts); + @Nullable Mp4Box.ContainerBox edtsAtom = trak.getContainerBoxOfType(Mp4Box.TYPE_edts); if (edtsAtom != null) { @Nullable Pair edtsData = parseEdts(edtsAtom); if (edtsData != null) { @@ -401,14 +402,14 @@ import java.util.Objects; * @throws ParserException Thrown if the stbl atom can't be parsed. */ private static TrackSampleTable parseStbl( - Track track, Atom.ContainerAtom stblAtom, GaplessInfoHolder gaplessInfoHolder) + Track track, Mp4Box.ContainerBox stblAtom, GaplessInfoHolder gaplessInfoHolder) throws ParserException { SampleSizeBox sampleSizeBox; - @Nullable Atom.LeafAtom stszAtom = stblAtom.getLeafAtomOfType(Atom.TYPE_stsz); + @Nullable LeafBox stszAtom = stblAtom.getLeafBoxOfType(Mp4Box.TYPE_stsz); if (stszAtom != null) { sampleSizeBox = new StszSampleSizeBox(stszAtom, track.format); } else { - @Nullable Atom.LeafAtom stz2Atom = stblAtom.getLeafAtomOfType(Atom.TYPE_stz2); + @Nullable LeafBox stz2Atom = stblAtom.getLeafBoxOfType(Mp4Box.TYPE_stz2); if (stz2Atom == null) { throw ParserException.createForMalformedContainer( "Track has no sample table size information", /* cause= */ null); @@ -430,28 +431,28 @@ import java.util.Objects; // Entries are byte offsets of chunks. boolean chunkOffsetsAreLongs = false; - @Nullable Atom.LeafAtom chunkOffsetsAtom = stblAtom.getLeafAtomOfType(Atom.TYPE_stco); + @Nullable LeafBox chunkOffsetsAtom = stblAtom.getLeafBoxOfType(Mp4Box.TYPE_stco); if (chunkOffsetsAtom == null) { chunkOffsetsAreLongs = true; - chunkOffsetsAtom = checkNotNull(stblAtom.getLeafAtomOfType(Atom.TYPE_co64)); + chunkOffsetsAtom = checkNotNull(stblAtom.getLeafBoxOfType(Mp4Box.TYPE_co64)); } ParsableByteArray chunkOffsets = chunkOffsetsAtom.data; // Entries are (chunk number, number of samples per chunk, sample description index). - ParsableByteArray stsc = checkNotNull(stblAtom.getLeafAtomOfType(Atom.TYPE_stsc)).data; + ParsableByteArray stsc = checkNotNull(stblAtom.getLeafBoxOfType(Mp4Box.TYPE_stsc)).data; // Entries are (number of samples, timestamp delta between those samples). - ParsableByteArray stts = checkNotNull(stblAtom.getLeafAtomOfType(Atom.TYPE_stts)).data; + ParsableByteArray stts = checkNotNull(stblAtom.getLeafBoxOfType(Mp4Box.TYPE_stts)).data; // Entries are the indices of samples that are synchronization samples. - @Nullable Atom.LeafAtom stssAtom = stblAtom.getLeafAtomOfType(Atom.TYPE_stss); + @Nullable LeafBox stssAtom = stblAtom.getLeafBoxOfType(Mp4Box.TYPE_stss); @Nullable ParsableByteArray stss = stssAtom != null ? stssAtom.data : null; // Entries are (number of samples, timestamp offset). - @Nullable Atom.LeafAtom cttsAtom = stblAtom.getLeafAtomOfType(Atom.TYPE_ctts); + @Nullable LeafBox cttsAtom = stblAtom.getLeafBoxOfType(Mp4Box.TYPE_ctts); @Nullable ParsableByteArray ctts = cttsAtom != null ? cttsAtom.data : null; // Prepare to read chunk information. ChunkIterator chunkIterator = new ChunkIterator(stsc, chunkOffsets, chunkOffsetsAreLongs); // Prepare to read sample timestamps. - stts.setPosition(Atom.FULL_HEADER_SIZE); + stts.setPosition(Mp4Box.FULL_HEADER_SIZE); int remainingTimestampDeltaChanges = stts.readUnsignedIntToInt() - 1; int remainingSamplesAtTimestampDelta = stts.readUnsignedIntToInt(); int timestampDeltaInTimeUnits = stts.readUnsignedIntToInt(); @@ -461,14 +462,14 @@ import java.util.Objects; int remainingTimestampOffsetChanges = 0; int timestampOffset = 0; if (ctts != null) { - ctts.setPosition(Atom.FULL_HEADER_SIZE); + ctts.setPosition(Mp4Box.FULL_HEADER_SIZE); remainingTimestampOffsetChanges = ctts.readUnsignedIntToInt(); } int nextSynchronizationSampleIndex = C.INDEX_UNSET; int remainingSynchronizationSamples = 0; if (stss != null) { - stss.setPosition(Atom.FULL_HEADER_SIZE); + stss.setPosition(Mp4Box.FULL_HEADER_SIZE); remainingSynchronizationSamples = stss.readUnsignedIntToInt(); if (remainingSynchronizationSamples > 0) { nextSynchronizationSampleIndex = stss.readUnsignedIntToInt() - 1; @@ -792,13 +793,13 @@ import java.util.Objects; @Nullable private static Metadata parseUdtaMeta(ParsableByteArray meta, int limit) { - meta.skipBytes(Atom.HEADER_SIZE); + meta.skipBytes(Mp4Box.HEADER_SIZE); maybeSkipRemainingMetaAtomHeaderBytes(meta); while (meta.getPosition() < limit) { int atomPosition = meta.getPosition(); int atomSize = meta.readInt(); int atomType = meta.readInt(); - if (atomType == Atom.TYPE_ilst) { + if (atomType == Mp4Box.TYPE_ilst) { meta.setPosition(atomPosition); return parseIlst(meta, atomPosition + atomSize); } @@ -809,7 +810,7 @@ import java.util.Objects; @Nullable private static Metadata parseIlst(ParsableByteArray ilst, int limit) { - ilst.skipBytes(Atom.HEADER_SIZE); + ilst.skipBytes(Mp4Box.HEADER_SIZE); ArrayList entries = new ArrayList<>(); while (ilst.getPosition() < limit) { @Nullable Metadata.Entry entry = MetadataUtil.parseIlstElement(ilst); @@ -848,7 +849,7 @@ import java.util.Objects; * @return An object containing the parsed data. */ private static TkhdData parseTkhd(ParsableByteArray tkhd) { - tkhd.setPosition(Atom.HEADER_SIZE); + tkhd.setPosition(Mp4Box.HEADER_SIZE); int fullAtom = tkhd.readInt(); int version = parseFullAtomVersion(fullAtom); @@ -908,7 +909,7 @@ import java.util.Objects; * @return The handler value. */ private static int parseHdlr(ParsableByteArray hdlr) { - hdlr.setPosition(Atom.FULL_HEADER_SIZE + 4); + hdlr.setPosition(Mp4Box.FULL_HEADER_SIZE + 4); return hdlr.readInt(); } @@ -935,7 +936,7 @@ import java.util.Objects; * in one second, and the language code. */ private static Pair parseMdhd(ParsableByteArray mdhd) { - mdhd.setPosition(Atom.HEADER_SIZE); + mdhd.setPosition(Mp4Box.HEADER_SIZE); int fullAtom = mdhd.readInt(); int version = parseFullAtomVersion(fullAtom); mdhd.skipBytes(version == 0 ? 8 : 16); @@ -969,7 +970,7 @@ import java.util.Objects; @Nullable DrmInitData drmInitData, boolean isQuickTime) throws ParserException { - stsd.setPosition(Atom.FULL_HEADER_SIZE); + stsd.setPosition(Mp4Box.FULL_HEADER_SIZE); int numberOfEntries = stsd.readInt(); StsdData out = new StsdData(numberOfEntries); for (int i = 0; i < numberOfEntries; i++) { @@ -977,22 +978,22 @@ import java.util.Objects; int childAtomSize = stsd.readInt(); ExtractorUtil.checkContainerInput(childAtomSize > 0, "childAtomSize must be positive"); int childAtomType = stsd.readInt(); - if (childAtomType == Atom.TYPE_avc1 - || childAtomType == Atom.TYPE_avc3 - || childAtomType == Atom.TYPE_encv - || childAtomType == Atom.TYPE_m1v_ - || childAtomType == Atom.TYPE_mp4v - || childAtomType == Atom.TYPE_hvc1 - || childAtomType == Atom.TYPE_hev1 - || childAtomType == Atom.TYPE_s263 - || childAtomType == Atom.TYPE_H263 - || childAtomType == Atom.TYPE_vp08 - || childAtomType == Atom.TYPE_vp09 - || childAtomType == Atom.TYPE_av01 - || childAtomType == Atom.TYPE_dvav - || childAtomType == Atom.TYPE_dva1 - || childAtomType == Atom.TYPE_dvhe - || childAtomType == Atom.TYPE_dvh1) { + if (childAtomType == Mp4Box.TYPE_avc1 + || childAtomType == Mp4Box.TYPE_avc3 + || childAtomType == Mp4Box.TYPE_encv + || childAtomType == Mp4Box.TYPE_m1v_ + || childAtomType == Mp4Box.TYPE_mp4v + || childAtomType == Mp4Box.TYPE_hvc1 + || childAtomType == Mp4Box.TYPE_hev1 + || childAtomType == Mp4Box.TYPE_s263 + || childAtomType == Mp4Box.TYPE_H263 + || childAtomType == Mp4Box.TYPE_vp08 + || childAtomType == Mp4Box.TYPE_vp09 + || childAtomType == Mp4Box.TYPE_av01 + || childAtomType == Mp4Box.TYPE_dvav + || childAtomType == Mp4Box.TYPE_dva1 + || childAtomType == Mp4Box.TYPE_dvhe + || childAtomType == Mp4Box.TYPE_dvh1) { parseVideoSampleEntry( stsd, childAtomType, @@ -1003,32 +1004,32 @@ import java.util.Objects; drmInitData, out, i); - } else if (childAtomType == Atom.TYPE_mp4a - || childAtomType == Atom.TYPE_enca - || childAtomType == Atom.TYPE_ac_3 - || childAtomType == Atom.TYPE_ec_3 - || childAtomType == Atom.TYPE_ac_4 - || childAtomType == Atom.TYPE_mlpa - || childAtomType == Atom.TYPE_dtsc - || childAtomType == Atom.TYPE_dtse - || childAtomType == Atom.TYPE_dtsh - || childAtomType == Atom.TYPE_dtsl - || childAtomType == Atom.TYPE_dtsx - || childAtomType == Atom.TYPE_samr - || childAtomType == Atom.TYPE_sawb - || childAtomType == Atom.TYPE_lpcm - || childAtomType == Atom.TYPE_sowt - || childAtomType == Atom.TYPE_twos - || childAtomType == Atom.TYPE__mp2 - || childAtomType == Atom.TYPE__mp3 - || childAtomType == Atom.TYPE_mha1 - || childAtomType == Atom.TYPE_mhm1 - || childAtomType == Atom.TYPE_alac - || childAtomType == Atom.TYPE_alaw - || childAtomType == Atom.TYPE_ulaw - || childAtomType == Atom.TYPE_Opus - || childAtomType == Atom.TYPE_fLaC - || childAtomType == Atom.TYPE_iamf) { + } else if (childAtomType == Mp4Box.TYPE_mp4a + || childAtomType == Mp4Box.TYPE_enca + || childAtomType == Mp4Box.TYPE_ac_3 + || childAtomType == Mp4Box.TYPE_ec_3 + || childAtomType == Mp4Box.TYPE_ac_4 + || childAtomType == Mp4Box.TYPE_mlpa + || childAtomType == Mp4Box.TYPE_dtsc + || childAtomType == Mp4Box.TYPE_dtse + || childAtomType == Mp4Box.TYPE_dtsh + || childAtomType == Mp4Box.TYPE_dtsl + || childAtomType == Mp4Box.TYPE_dtsx + || childAtomType == Mp4Box.TYPE_samr + || childAtomType == Mp4Box.TYPE_sawb + || childAtomType == Mp4Box.TYPE_lpcm + || childAtomType == Mp4Box.TYPE_sowt + || childAtomType == Mp4Box.TYPE_twos + || childAtomType == Mp4Box.TYPE__mp2 + || childAtomType == Mp4Box.TYPE__mp3 + || childAtomType == Mp4Box.TYPE_mha1 + || childAtomType == Mp4Box.TYPE_mhm1 + || childAtomType == Mp4Box.TYPE_alac + || childAtomType == Mp4Box.TYPE_alaw + || childAtomType == Mp4Box.TYPE_ulaw + || childAtomType == Mp4Box.TYPE_Opus + || childAtomType == Mp4Box.TYPE_fLaC + || childAtomType == Mp4Box.TYPE_iamf) { parseAudioSampleEntry( stsd, childAtomType, @@ -1040,16 +1041,16 @@ import java.util.Objects; drmInitData, out, i); - } else if (childAtomType == Atom.TYPE_TTML - || childAtomType == Atom.TYPE_tx3g - || childAtomType == Atom.TYPE_wvtt - || childAtomType == Atom.TYPE_stpp - || childAtomType == Atom.TYPE_c608) { + } else if (childAtomType == Mp4Box.TYPE_TTML + || childAtomType == Mp4Box.TYPE_tx3g + || childAtomType == Mp4Box.TYPE_wvtt + || childAtomType == Mp4Box.TYPE_stpp + || childAtomType == Mp4Box.TYPE_c608) { parseTextSampleEntry( stsd, childAtomType, childStartPosition, childAtomSize, trackId, language, out); - } else if (childAtomType == Atom.TYPE_mett) { + } else if (childAtomType == Mp4Box.TYPE_mett) { parseMetaDataSampleEntry(stsd, childAtomType, childStartPosition, trackId, out); - } else if (childAtomType == Atom.TYPE_camm) { + } else if (childAtomType == Mp4Box.TYPE_camm) { out.format = new Format.Builder() .setId(trackId) @@ -1069,27 +1070,27 @@ import java.util.Objects; int trackId, String language, StsdData out) { - parent.setPosition(position + Atom.HEADER_SIZE + StsdData.STSD_HEADER_SIZE); + parent.setPosition(position + Mp4Box.HEADER_SIZE + StsdData.STSD_HEADER_SIZE); // Default values. @Nullable ImmutableList initializationData = null; long subsampleOffsetUs = Format.OFFSET_SAMPLE_RELATIVE; String mimeType; - if (atomType == Atom.TYPE_TTML) { + if (atomType == Mp4Box.TYPE_TTML) { mimeType = MimeTypes.APPLICATION_TTML; - } else if (atomType == Atom.TYPE_tx3g) { + } else if (atomType == Mp4Box.TYPE_tx3g) { mimeType = MimeTypes.APPLICATION_TX3G; - int sampleDescriptionLength = atomSize - Atom.HEADER_SIZE - 8; + int sampleDescriptionLength = atomSize - Mp4Box.HEADER_SIZE - 8; byte[] sampleDescriptionData = new byte[sampleDescriptionLength]; parent.readBytes(sampleDescriptionData, 0, sampleDescriptionLength); initializationData = ImmutableList.of(sampleDescriptionData); - } else if (atomType == Atom.TYPE_wvtt) { + } else if (atomType == Mp4Box.TYPE_wvtt) { mimeType = MimeTypes.APPLICATION_MP4VTT; - } else if (atomType == Atom.TYPE_stpp) { + } else if (atomType == Mp4Box.TYPE_stpp) { mimeType = MimeTypes.APPLICATION_TTML; subsampleOffsetUs = 0; // Subsample timing is absolute. - } else if (atomType == Atom.TYPE_c608) { + } else if (atomType == Mp4Box.TYPE_c608) { // Defined by the QuickTime File Format specification. mimeType = MimeTypes.APPLICATION_MP4CEA608; out.requiredSampleTransformation = Track.TRANSFORMATION_CEA608_CDAT; @@ -1121,7 +1122,7 @@ import java.util.Objects; StsdData out, int entryIndex) throws ParserException { - parent.setPosition(position + Atom.HEADER_SIZE + StsdData.STSD_HEADER_SIZE); + parent.setPosition(position + Mp4Box.HEADER_SIZE + StsdData.STSD_HEADER_SIZE); parent.skipBytes(16); int width = parent.readUnsignedShort(); @@ -1134,7 +1135,7 @@ import java.util.Objects; parent.skipBytes(50); int childPosition = parent.getPosition(); - if (atomType == Atom.TYPE_encv) { + if (atomType == Mp4Box.TYPE_encv) { @Nullable Pair sampleEntryEncryptionData = parseSampleEntryEncryptionData(parent, position, size); @@ -1154,9 +1155,9 @@ import java.util.Objects; // } @Nullable String mimeType = null; - if (atomType == Atom.TYPE_m1v_) { + if (atomType == Mp4Box.TYPE_m1v_) { mimeType = MimeTypes.VIDEO_MPEG; - } else if (atomType == Atom.TYPE_H263) { + } else if (atomType == Mp4Box.TYPE_H263) { mimeType = MimeTypes.VIDEO_H263; } @@ -1185,10 +1186,10 @@ import java.util.Objects; } ExtractorUtil.checkContainerInput(childAtomSize > 0, "childAtomSize must be positive"); int childAtomType = parent.readInt(); - if (childAtomType == Atom.TYPE_avcC) { + if (childAtomType == Mp4Box.TYPE_avcC) { ExtractorUtil.checkContainerInput(mimeType == null, /* message= */ null); mimeType = MimeTypes.VIDEO_H264; - parent.setPosition(childStartPosition + Atom.HEADER_SIZE); + parent.setPosition(childStartPosition + Mp4Box.HEADER_SIZE); AvcConfig avcConfig = AvcConfig.parse(parent); initializationData = avcConfig.initializationData; out.nalUnitLengthFieldLength = avcConfig.nalUnitLengthFieldLength; @@ -1202,10 +1203,10 @@ import java.util.Objects; colorTransfer = avcConfig.colorTransfer; bitdepthLuma = avcConfig.bitdepthLuma; bitdepthChroma = avcConfig.bitdepthChroma; - } else if (childAtomType == Atom.TYPE_hvcC) { + } else if (childAtomType == Mp4Box.TYPE_hvcC) { ExtractorUtil.checkContainerInput(mimeType == null, /* message= */ null); mimeType = MimeTypes.VIDEO_H265; - parent.setPosition(childStartPosition + Atom.HEADER_SIZE); + parent.setPosition(childStartPosition + Mp4Box.HEADER_SIZE); HevcConfig hevcConfig = HevcConfig.parse(parent); initializationData = hevcConfig.initializationData; out.nalUnitLengthFieldLength = hevcConfig.nalUnitLengthFieldLength; @@ -1224,14 +1225,14 @@ import java.util.Objects; bitdepthLuma = hevcConfig.bitdepthLuma; bitdepthChroma = hevcConfig.bitdepthChroma; vpsData = hevcConfig.vpsData; - } else if (childAtomType == Atom.TYPE_lhvC) { + } else if (childAtomType == Mp4Box.TYPE_lhvC) { // The lhvC atom must follow the hvcC atom; so the media type must be already set. ExtractorUtil.checkContainerInput( MimeTypes.VIDEO_H265.equals(mimeType), "lhvC must follow hvcC atom"); ExtractorUtil.checkContainerInput( vpsData != null && vpsData.layerInfos.size() >= 2, "must have at least two layers"); - parent.setPosition(childStartPosition + Atom.HEADER_SIZE); + parent.setPosition(childStartPosition + Mp4Box.HEADER_SIZE); HevcConfig lhevcConfig = HevcConfig.parseLayered(parent, checkNotNull(vpsData)); ExtractorUtil.checkContainerInput( out.nalUnitLengthFieldLength == lhevcConfig.nalUnitLengthFieldLength, @@ -1271,7 +1272,7 @@ import java.util.Objects; false, "initializationData must be already set from hvcC atom"); } codecs = lhevcConfig.codecs; - } else if (childAtomType == Atom.TYPE_vexu) { + } else if (childAtomType == Mp4Box.TYPE_vexu) { VexuData vexuData = parseVideoExtendedUsageBox(parent, childStartPosition, childAtomSize); if (vexuData != null && vexuData.eyesData != null) { if (vpsData != null && vpsData.layerInfos.size() >= 2) { @@ -1292,16 +1293,16 @@ import java.util.Objects; : C.STEREO_MODE_INTERLEAVED_LEFT_PRIMARY; } } - } else if (childAtomType == Atom.TYPE_dvcC || childAtomType == Atom.TYPE_dvvC) { + } else if (childAtomType == Mp4Box.TYPE_dvcC || childAtomType == Mp4Box.TYPE_dvvC) { @Nullable DolbyVisionConfig dolbyVisionConfig = DolbyVisionConfig.parse(parent); if (dolbyVisionConfig != null) { codecs = dolbyVisionConfig.codecs; mimeType = MimeTypes.VIDEO_DOLBY_VISION; } - } else if (childAtomType == Atom.TYPE_vpcC) { + } else if (childAtomType == Mp4Box.TYPE_vpcC) { ExtractorUtil.checkContainerInput(mimeType == null, /* message= */ null); - mimeType = (atomType == Atom.TYPE_vp08) ? MimeTypes.VIDEO_VP8 : MimeTypes.VIDEO_VP9; - parent.setPosition(childStartPosition + Atom.FULL_HEADER_SIZE); + mimeType = (atomType == Mp4Box.TYPE_vp08) ? MimeTypes.VIDEO_VP8 : MimeTypes.VIDEO_VP9; + parent.setPosition(childStartPosition + Mp4Box.FULL_HEADER_SIZE); // See vpcC atom syntax: https://www.webmproject.org/vp9/mp4/#syntax_1 parent.skipBytes(2); // profile(8), level(8) int byte3 = parent.readUnsignedByte(); @@ -1314,15 +1315,15 @@ import java.util.Objects; colorRange = fullRangeFlag ? C.COLOR_RANGE_FULL : C.COLOR_RANGE_LIMITED; colorTransfer = ColorInfo.isoTransferCharacteristicsToColorTransfer(transferCharacteristics); - } else if (childAtomType == Atom.TYPE_av1C) { + } else if (childAtomType == Mp4Box.TYPE_av1C) { mimeType = MimeTypes.VIDEO_AV1; - int childAtomBodySize = childAtomSize - Atom.HEADER_SIZE; + int childAtomBodySize = childAtomSize - Mp4Box.HEADER_SIZE; byte[] initializationDataChunk = new byte[childAtomBodySize]; parent.readBytes(initializationDataChunk, /* offset= */ 0, childAtomBodySize); initializationData = ImmutableList.of(initializationDataChunk); - parent.setPosition(childStartPosition + Atom.HEADER_SIZE); + parent.setPosition(childStartPosition + Mp4Box.HEADER_SIZE); ColorInfo colorInfo = parseAv1c(parent); bitdepthLuma = colorInfo.lumaBitdepth; @@ -1330,7 +1331,7 @@ import java.util.Objects; colorSpace = colorInfo.colorSpace; colorRange = colorInfo.colorRange; colorTransfer = colorInfo.colorTransfer; - } else if (childAtomType == Atom.TYPE_clli) { + } else if (childAtomType == Mp4Box.TYPE_clli) { if (hdrStaticInfo == null) { hdrStaticInfo = allocateHdrStaticInfo(); } @@ -1339,7 +1340,7 @@ import java.util.Objects; hdrStaticInfo.position(21); hdrStaticInfo.putShort(parent.readShort()); // max_content_light_level. hdrStaticInfo.putShort(parent.readShort()); // max_pic_average_light_level. - } else if (childAtomType == Atom.TYPE_mdcv) { + } else if (childAtomType == Mp4Box.TYPE_mdcv) { if (hdrStaticInfo == null) { hdrStaticInfo = allocateHdrStaticInfo(); } @@ -1367,10 +1368,10 @@ import java.util.Objects; hdrStaticInfo.putShort(whitePointY); hdrStaticInfo.putShort((short) (maxDisplayMasteringLuminance / 10000)); hdrStaticInfo.putShort((short) (minDisplayMasteringLuminance / 10000)); - } else if (childAtomType == Atom.TYPE_d263) { + } else if (childAtomType == Mp4Box.TYPE_d263) { ExtractorUtil.checkContainerInput(mimeType == null, /* message= */ null); mimeType = MimeTypes.VIDEO_H263; - } else if (childAtomType == Atom.TYPE_esds) { + } else if (childAtomType == Mp4Box.TYPE_esds) { ExtractorUtil.checkContainerInput(mimeType == null, /* message= */ null); esdsData = parseEsdsFromParent(parent, childStartPosition); mimeType = esdsData.mimeType; @@ -1378,12 +1379,12 @@ import java.util.Objects; if (initializationDataBytes != null) { initializationData = ImmutableList.of(initializationDataBytes); } - } else if (childAtomType == Atom.TYPE_pasp) { + } else if (childAtomType == Mp4Box.TYPE_pasp) { pixelWidthHeightRatio = parsePaspFromParent(parent, childStartPosition); pixelWidthHeightRatioFromPasp = true; - } else if (childAtomType == Atom.TYPE_sv3d) { + } else if (childAtomType == Mp4Box.TYPE_sv3d) { projectionData = parseProjFromParent(parent, childStartPosition, childAtomSize); - } else if (childAtomType == Atom.TYPE_st3d) { + } else if (childAtomType == Mp4Box.TYPE_st3d) { int version = parent.readUnsignedByte(); parent.skipBytes(3); // Flags. if (version == 0) { @@ -1405,7 +1406,7 @@ import java.util.Objects; break; } } - } else if (childAtomType == Atom.TYPE_colr) { + } else if (childAtomType == Mp4Box.TYPE_colr) { // Only modify these values if 'colorSpace' and 'colorTransfer' have not been previously // established by the bitstream. The absence of color descriptors ('colorSpace' and // 'colorTransfer') does not necessarily mean that 'colorRange' has default values, hence it @@ -1432,7 +1433,7 @@ import java.util.Objects; colorTransfer = ColorInfo.isoTransferCharacteristicsToColorTransfer(transferCharacteristics); } else { - Log.w(TAG, "Unsupported color type: " + Atom.getAtomTypeString(colorType)); + Log.w(TAG, "Unsupported color type: " + Mp4Box.getBoxTypeString(colorType)); } } } @@ -1620,8 +1621,8 @@ import java.util.Objects; private static void parseMetaDataSampleEntry( ParsableByteArray parent, int atomType, int position, int trackId, StsdData out) { - parent.setPosition(position + Atom.HEADER_SIZE + StsdData.STSD_HEADER_SIZE); - if (atomType == Atom.TYPE_mett) { + parent.setPosition(position + Mp4Box.HEADER_SIZE + StsdData.STSD_HEADER_SIZE); + if (atomType == Mp4Box.TYPE_mett) { parent.readNullTerminatedString(); // Skip optional content_encoding @Nullable String mimeType = parent.readNullTerminatedString(); if (mimeType != null) { @@ -1638,13 +1639,13 @@ import java.util.Objects; * present. */ @Nullable - private static Pair parseEdts(Atom.ContainerAtom edtsAtom) { - @Nullable Atom.LeafAtom elstAtom = edtsAtom.getLeafAtomOfType(Atom.TYPE_elst); + private static Pair parseEdts(Mp4Box.ContainerBox edtsAtom) { + @Nullable LeafBox elstAtom = edtsAtom.getLeafBoxOfType(Mp4Box.TYPE_elst); if (elstAtom == null) { return null; } ParsableByteArray elstData = elstAtom.data; - elstData.setPosition(Atom.HEADER_SIZE); + elstData.setPosition(Mp4Box.HEADER_SIZE); int fullAtom = elstData.readInt(); int version = parseFullAtomVersion(fullAtom); int entryCount = elstData.readUnsignedIntToInt(); @@ -1665,7 +1666,7 @@ import java.util.Objects; } private static float parsePaspFromParent(ParsableByteArray parent, int position) { - parent.setPosition(position + Atom.HEADER_SIZE); + parent.setPosition(position + Mp4Box.HEADER_SIZE); int hSpacing = parent.readUnsignedIntToInt(); int vSpacing = parent.readUnsignedIntToInt(); return (float) hSpacing / vSpacing; @@ -1683,7 +1684,7 @@ import java.util.Objects; StsdData out, int entryIndex) throws ParserException { - parent.setPosition(position + Atom.HEADER_SIZE + StsdData.STSD_HEADER_SIZE); + parent.setPosition(position + Mp4Box.HEADER_SIZE + StsdData.STSD_HEADER_SIZE); int quickTimeSoundDescriptionVersion = 0; if (isQuickTime) { @@ -1743,7 +1744,7 @@ import java.util.Objects; } int childPosition = parent.getPosition(); - if (atomType == Atom.TYPE_enca) { + if (atomType == Mp4Box.TYPE_enca) { @Nullable Pair sampleEntryEncryptionData = parseSampleEntryEncryptionData(parent, position, size); @@ -1764,54 +1765,54 @@ import java.util.Objects; // If the atom type determines a MIME type, set it immediately. @Nullable String mimeType = null; - if (atomType == Atom.TYPE_ac_3) { + if (atomType == Mp4Box.TYPE_ac_3) { mimeType = MimeTypes.AUDIO_AC3; - } else if (atomType == Atom.TYPE_ec_3) { + } else if (atomType == Mp4Box.TYPE_ec_3) { mimeType = MimeTypes.AUDIO_E_AC3; - } else if (atomType == Atom.TYPE_ac_4) { + } else if (atomType == Mp4Box.TYPE_ac_4) { mimeType = MimeTypes.AUDIO_AC4; - } else if (atomType == Atom.TYPE_dtsc) { + } else if (atomType == Mp4Box.TYPE_dtsc) { mimeType = MimeTypes.AUDIO_DTS; - } else if (atomType == Atom.TYPE_dtsh || atomType == Atom.TYPE_dtsl) { + } else if (atomType == Mp4Box.TYPE_dtsh || atomType == Mp4Box.TYPE_dtsl) { mimeType = MimeTypes.AUDIO_DTS_HD; - } else if (atomType == Atom.TYPE_dtse) { + } else if (atomType == Mp4Box.TYPE_dtse) { mimeType = MimeTypes.AUDIO_DTS_EXPRESS; - } else if (atomType == Atom.TYPE_dtsx) { + } else if (atomType == Mp4Box.TYPE_dtsx) { mimeType = MimeTypes.AUDIO_DTS_X; - } else if (atomType == Atom.TYPE_samr) { + } else if (atomType == Mp4Box.TYPE_samr) { mimeType = MimeTypes.AUDIO_AMR_NB; - } else if (atomType == Atom.TYPE_sawb) { + } else if (atomType == Mp4Box.TYPE_sawb) { mimeType = MimeTypes.AUDIO_AMR_WB; - } else if (atomType == Atom.TYPE_sowt) { + } else if (atomType == Mp4Box.TYPE_sowt) { mimeType = MimeTypes.AUDIO_RAW; pcmEncoding = C.ENCODING_PCM_16BIT; - } else if (atomType == Atom.TYPE_twos) { + } else if (atomType == Mp4Box.TYPE_twos) { mimeType = MimeTypes.AUDIO_RAW; pcmEncoding = C.ENCODING_PCM_16BIT_BIG_ENDIAN; - } else if (atomType == Atom.TYPE_lpcm) { + } else if (atomType == Mp4Box.TYPE_lpcm) { mimeType = MimeTypes.AUDIO_RAW; if (pcmEncoding == Format.NO_VALUE) { pcmEncoding = C.ENCODING_PCM_16BIT; } - } else if (atomType == Atom.TYPE__mp2 || atomType == Atom.TYPE__mp3) { + } else if (atomType == Mp4Box.TYPE__mp2 || atomType == Mp4Box.TYPE__mp3) { mimeType = MimeTypes.AUDIO_MPEG; - } else if (atomType == Atom.TYPE_mha1) { + } else if (atomType == Mp4Box.TYPE_mha1) { mimeType = MimeTypes.AUDIO_MPEGH_MHA1; - } else if (atomType == Atom.TYPE_mhm1) { + } else if (atomType == Mp4Box.TYPE_mhm1) { mimeType = MimeTypes.AUDIO_MPEGH_MHM1; - } else if (atomType == Atom.TYPE_alac) { + } else if (atomType == Mp4Box.TYPE_alac) { mimeType = MimeTypes.AUDIO_ALAC; - } else if (atomType == Atom.TYPE_alaw) { + } else if (atomType == Mp4Box.TYPE_alaw) { mimeType = MimeTypes.AUDIO_ALAW; - } else if (atomType == Atom.TYPE_ulaw) { + } else if (atomType == Mp4Box.TYPE_ulaw) { mimeType = MimeTypes.AUDIO_MLAW; - } else if (atomType == Atom.TYPE_Opus) { + } else if (atomType == Mp4Box.TYPE_Opus) { mimeType = MimeTypes.AUDIO_OPUS; - } else if (atomType == Atom.TYPE_fLaC) { + } else if (atomType == Mp4Box.TYPE_fLaC) { mimeType = MimeTypes.AUDIO_FLAC; - } else if (atomType == Atom.TYPE_mlpa) { + } else if (atomType == Mp4Box.TYPE_mlpa) { mimeType = MimeTypes.AUDIO_TRUEHD; - } else if (atomType == Atom.TYPE_iamf) { + } else if (atomType == Mp4Box.TYPE_iamf) { mimeType = MimeTypes.AUDIO_IAMF; } @@ -1821,11 +1822,11 @@ import java.util.Objects; int childAtomSize = parent.readInt(); ExtractorUtil.checkContainerInput(childAtomSize > 0, "childAtomSize must be positive"); int childAtomType = parent.readInt(); - if (childAtomType == Atom.TYPE_mhaC) { + if (childAtomType == Mp4Box.TYPE_mhaC) { // See ISO_IEC_23008-3;2022 MHADecoderConfigurationRecord // The header consists of: size (4), boxtype 'mhaC' (4), configurationVersion (1), // mpegh3daProfileLevelIndication (1), referenceChannelLayout (1), mpegh3daConfigLength (2). - parent.setPosition(childPosition + Atom.HEADER_SIZE); + parent.setPosition(childPosition + Mp4Box.HEADER_SIZE); parent.skipBytes(1); // configurationVersion int mpeghProfileLevelIndication = parent.readUnsignedByte(); parent.skipBytes(1); // mpeghReferenceChannelLayout @@ -1844,10 +1845,10 @@ import java.util.Objects; // level sets as the second entry. initializationData = ImmutableList.of(initializationDataBytes, initializationData.get(0)); } - } else if (childAtomType == Atom.TYPE_mhaP) { + } else if (childAtomType == Mp4Box.TYPE_mhaP) { // See ISO_IEC_23008-3;2022 MHAProfileAndLevelCompatibilitySetBox // The header consists of: size (4), boxtype 'mhaP' (4), numCompatibleSets (1). - parent.setPosition(childPosition + Atom.HEADER_SIZE); + parent.setPosition(childPosition + Mp4Box.HEADER_SIZE); int numCompatibleSets = parent.readUnsignedByte(); if (numCompatibleSets > 0) { byte[] mpeghCompatibleProfileLevelSet = new byte[numCompatibleSets]; @@ -1861,12 +1862,12 @@ import java.util.Objects; ImmutableList.of(initializationData.get(0), mpeghCompatibleProfileLevelSet); } } - } else if (childAtomType == Atom.TYPE_esds - || (isQuickTime && childAtomType == Atom.TYPE_wave)) { + } else if (childAtomType == Mp4Box.TYPE_esds + || (isQuickTime && childAtomType == Mp4Box.TYPE_wave)) { int esdsAtomPosition = - childAtomType == Atom.TYPE_esds + childAtomType == Mp4Box.TYPE_esds ? childPosition - : findBoxPosition(parent, Atom.TYPE_esds, childPosition, childAtomSize); + : findBoxPosition(parent, Mp4Box.TYPE_esds, childPosition, childAtomSize); if (esdsAtomPosition != C.INDEX_UNSET) { esdsData = parseEsdsFromParent(parent, esdsAtomPosition); mimeType = esdsData.mimeType; @@ -1889,19 +1890,19 @@ import java.util.Objects; } } } - } else if (childAtomType == Atom.TYPE_dac3) { - parent.setPosition(Atom.HEADER_SIZE + childPosition); + } else if (childAtomType == Mp4Box.TYPE_dac3) { + parent.setPosition(Mp4Box.HEADER_SIZE + childPosition); out.format = Ac3Util.parseAc3AnnexFFormat(parent, Integer.toString(trackId), language, drmInitData); - } else if (childAtomType == Atom.TYPE_dec3) { - parent.setPosition(Atom.HEADER_SIZE + childPosition); + } else if (childAtomType == Mp4Box.TYPE_dec3) { + parent.setPosition(Mp4Box.HEADER_SIZE + childPosition); out.format = Ac3Util.parseEAc3AnnexFFormat(parent, Integer.toString(trackId), language, drmInitData); - } else if (childAtomType == Atom.TYPE_dac4) { - parent.setPosition(Atom.HEADER_SIZE + childPosition); + } else if (childAtomType == Mp4Box.TYPE_dac4) { + parent.setPosition(Mp4Box.HEADER_SIZE + childPosition); out.format = Ac4Util.parseAc4AnnexEFormat(parent, Integer.toString(trackId), language, drmInitData); - } else if (childAtomType == Atom.TYPE_dmlp) { + } else if (childAtomType == Mp4Box.TYPE_dmlp) { if (sampleRateMlp <= 0) { throw ParserException.createForMalformedContainer( "Invalid sample rate for Dolby TrueHD MLP stream: " + sampleRateMlp, @@ -1912,7 +1913,7 @@ import java.util.Objects; // because these streams can carry simultaneously multiple representations of the same // audio. Use stereo by default. channelCount = 2; - } else if (childAtomType == Atom.TYPE_ddts || childAtomType == Atom.TYPE_udts) { + } else if (childAtomType == Mp4Box.TYPE_ddts || childAtomType == Mp4Box.TYPE_udts) { out.format = new Format.Builder() .setId(trackId) @@ -1922,28 +1923,28 @@ import java.util.Objects; .setDrmInitData(drmInitData) .setLanguage(language) .build(); - } else if (childAtomType == Atom.TYPE_dOps) { + } else if (childAtomType == Mp4Box.TYPE_dOps) { // Build an Opus Identification Header (defined in RFC-7845) by concatenating the Opus Magic // Signature and the body of the dOps atom. - int childAtomBodySize = childAtomSize - Atom.HEADER_SIZE; + int childAtomBodySize = childAtomSize - Mp4Box.HEADER_SIZE; byte[] headerBytes = Arrays.copyOf(opusMagic, opusMagic.length + childAtomBodySize); - parent.setPosition(childPosition + Atom.HEADER_SIZE); + parent.setPosition(childPosition + Mp4Box.HEADER_SIZE); parent.readBytes(headerBytes, opusMagic.length, childAtomBodySize); initializationData = OpusUtil.buildInitializationData(headerBytes); - } else if (childAtomType == Atom.TYPE_dfLa) { - int childAtomBodySize = childAtomSize - Atom.FULL_HEADER_SIZE; + } else if (childAtomType == Mp4Box.TYPE_dfLa) { + int childAtomBodySize = childAtomSize - Mp4Box.FULL_HEADER_SIZE; byte[] initializationDataBytes = new byte[4 + childAtomBodySize]; initializationDataBytes[0] = 0x66; // f initializationDataBytes[1] = 0x4C; // L initializationDataBytes[2] = 0x61; // a initializationDataBytes[3] = 0x43; // C - parent.setPosition(childPosition + Atom.FULL_HEADER_SIZE); + parent.setPosition(childPosition + Mp4Box.FULL_HEADER_SIZE); parent.readBytes(initializationDataBytes, /* offset= */ 4, childAtomBodySize); initializationData = ImmutableList.of(initializationDataBytes); - } else if (childAtomType == Atom.TYPE_alac) { - int childAtomBodySize = childAtomSize - Atom.FULL_HEADER_SIZE; + } else if (childAtomType == Mp4Box.TYPE_alac) { + int childAtomBodySize = childAtomSize - Mp4Box.FULL_HEADER_SIZE; byte[] initializationDataBytes = new byte[childAtomBodySize]; - parent.setPosition(childPosition + Atom.FULL_HEADER_SIZE); + parent.setPosition(childPosition + Mp4Box.FULL_HEADER_SIZE); parent.readBytes(initializationDataBytes, /* offset= */ 0, childAtomBodySize); // Update sampleRate and channelCount from the AudioSpecificConfig initialization data, // which is more reliable. See https://github.com/google/ExoPlayer/pull/6629. @@ -1952,9 +1953,9 @@ import java.util.Objects; sampleRate = audioSpecificConfig.first; channelCount = audioSpecificConfig.second; initializationData = ImmutableList.of(initializationDataBytes); - } else if (childAtomType == Atom.TYPE_iacb) { + } else if (childAtomType == Mp4Box.TYPE_iacb) { parent.setPosition( - childPosition + Atom.HEADER_SIZE + 1); // header and configuration version + childPosition + Mp4Box.HEADER_SIZE + 1); // header and configuration version int configObusSize = parent.readUnsignedLeb128ToInt(); byte[] initializationDataBytes = new byte[configObusSize]; parent.readBytes(initializationDataBytes, /* offset= */ 0, configObusSize); @@ -2018,7 +2019,7 @@ import java.util.Objects; /** Returns codec-specific initialization data contained in an esds box. */ private static EsdsData parseEsdsFromParent(ParsableByteArray parent, int position) { - parent.setPosition(position + Atom.HEADER_SIZE + 4); + parent.setPosition(position + Mp4Box.HEADER_SIZE + 4); // Start of the ES_Descriptor (defined in ISO/IEC 14496-1) parent.skipBytes(1); // ES_Descriptor tag parseExpandableClassSize(parent); @@ -2077,7 +2078,7 @@ import java.util.Objects; @Nullable /* package */ static VexuData parseVideoExtendedUsageBox( ParsableByteArray parent, int position, int size) throws ParserException { - parent.setPosition(position + Atom.HEADER_SIZE); + parent.setPosition(position + Mp4Box.HEADER_SIZE); int childPosition = parent.getPosition(); @Nullable EyesData eyesData = null; while (childPosition - position < size) { @@ -2085,7 +2086,7 @@ import java.util.Objects; int childAtomSize = parent.readInt(); ExtractorUtil.checkContainerInput(childAtomSize > 0, "childAtomSize must be positive"); int childAtomType = parent.readInt(); - if (childAtomType == Atom.TYPE_eyes) { + if (childAtomType == Mp4Box.TYPE_eyes) { eyesData = parseStereoViewBox(parent, childPosition, childAtomSize); } childPosition += childAtomSize; @@ -2096,13 +2097,13 @@ import java.util.Objects; @Nullable private static EyesData parseStereoViewBox(ParsableByteArray parent, int position, int size) throws ParserException { - parent.setPosition(position + Atom.HEADER_SIZE); + parent.setPosition(position + Mp4Box.HEADER_SIZE); int childPosition = parent.getPosition(); while (childPosition - position < size) { parent.setPosition(childPosition); int childAtomSize = parent.readInt(); ExtractorUtil.checkContainerInput(childAtomSize > 0, "childAtomSize must be positive"); - if (parent.readInt() == Atom.TYPE_stri) { + if (parent.readInt() == Mp4Box.TYPE_stri) { // The stri box extends FullBox that includes version (8 bits) and flags (24 bits). parent.skipBytes(4); int striInfo = parent.readUnsignedByte() & 0x0F; @@ -2132,7 +2133,7 @@ import java.util.Objects; int childAtomSize = parent.readInt(); ExtractorUtil.checkContainerInput(childAtomSize > 0, "childAtomSize must be positive"); int childAtomType = parent.readInt(); - if (childAtomType == Atom.TYPE_sinf) { + if (childAtomType == Mp4Box.TYPE_sinf) { @Nullable Pair result = parseCommonEncryptionSinfFromParent(parent, childPosition, childAtomSize); @@ -2148,7 +2149,7 @@ import java.util.Objects; @Nullable /* package */ static Pair parseCommonEncryptionSinfFromParent( ParsableByteArray parent, int position, int size) throws ParserException { - int childPosition = position + Atom.HEADER_SIZE; + int childPosition = position + Mp4Box.HEADER_SIZE; int schemeInformationBoxPosition = C.INDEX_UNSET; int schemeInformationBoxSize = 0; @Nullable String schemeType = null; @@ -2157,13 +2158,13 @@ import java.util.Objects; parent.setPosition(childPosition); int childAtomSize = parent.readInt(); int childAtomType = parent.readInt(); - if (childAtomType == Atom.TYPE_frma) { + if (childAtomType == Mp4Box.TYPE_frma) { dataFormat = parent.readInt(); - } else if (childAtomType == Atom.TYPE_schm) { + } else if (childAtomType == Mp4Box.TYPE_schm) { parent.skipBytes(4); // Common encryption scheme_type values are defined in ISO/IEC 23001-7:2016, section 4.1. schemeType = parent.readString(4); - } else if (childAtomType == Atom.TYPE_schi) { + } else if (childAtomType == Mp4Box.TYPE_schi) { schemeInformationBoxPosition = childPosition; schemeInformationBoxSize = childAtomSize; } @@ -2191,12 +2192,12 @@ import java.util.Objects; @Nullable private static TrackEncryptionBox parseSchiFromParent( ParsableByteArray parent, int position, int size, String schemeType) { - int childPosition = position + Atom.HEADER_SIZE; + int childPosition = position + Mp4Box.HEADER_SIZE; while (childPosition - position < size) { parent.setPosition(childPosition); int childAtomSize = parent.readInt(); int childAtomType = parent.readInt(); - if (childAtomType == Atom.TYPE_tenc) { + if (childAtomType == Mp4Box.TYPE_tenc) { int fullAtom = parent.readInt(); int version = parseFullAtomVersion(fullAtom); parent.skipBytes(1); // reserved = 0. @@ -2236,12 +2237,12 @@ import java.util.Objects; /** Parses the proj box from sv3d box, as specified by https://github.com/google/spatial-media. */ @Nullable private static byte[] parseProjFromParent(ParsableByteArray parent, int position, int size) { - int childPosition = position + Atom.HEADER_SIZE; + int childPosition = position + Mp4Box.HEADER_SIZE; while (childPosition - position < size) { parent.setPosition(childPosition); int childAtomSize = parent.readInt(); int childAtomType = parent.readInt(); - if (childAtomType == Atom.TYPE_proj) { + if (childAtomType == Mp4Box.TYPE_proj) { return Arrays.copyOfRange(parent.getData(), childPosition, childPosition + childAtomSize); } childPosition += childAtomSize; @@ -2298,9 +2299,9 @@ import java.util.Objects; this.stsc = stsc; this.chunkOffsets = chunkOffsets; this.chunkOffsetsAreLongs = chunkOffsetsAreLongs; - chunkOffsets.setPosition(Atom.FULL_HEADER_SIZE); + chunkOffsets.setPosition(Mp4Box.FULL_HEADER_SIZE); length = chunkOffsets.readUnsignedIntToInt(); - stsc.setPosition(Atom.FULL_HEADER_SIZE); + stsc.setPosition(Mp4Box.FULL_HEADER_SIZE); remainingSamplesPerChunkChanges = stsc.readUnsignedIntToInt(); ExtractorUtil.checkContainerInput(stsc.readInt() == 1, "first_chunk must be 1"); index = -1; @@ -2439,9 +2440,9 @@ import java.util.Objects; private final int sampleCount; private final ParsableByteArray data; - public StszSampleSizeBox(Atom.LeafAtom stszAtom, Format trackFormat) { + public StszSampleSizeBox(LeafBox stszAtom, Format trackFormat) { data = stszAtom.data; - data.setPosition(Atom.FULL_HEADER_SIZE); + data.setPosition(Mp4Box.FULL_HEADER_SIZE); int fixedSampleSize = data.readUnsignedIntToInt(); if (MimeTypes.AUDIO_RAW.equals(trackFormat.sampleMimeType)) { int pcmFrameSize = Util.getPcmFrameSize(trackFormat.pcmEncoding, trackFormat.channelCount); @@ -2489,9 +2490,9 @@ import java.util.Objects; private int sampleIndex; private int currentByte; - public Stz2SampleSizeBox(Atom.LeafAtom stz2Atom) { + public Stz2SampleSizeBox(LeafBox stz2Atom) { data = stz2Atom.data; - data.setPosition(Atom.FULL_HEADER_SIZE); + data.setPosition(Mp4Box.FULL_HEADER_SIZE); fieldSize = data.readUnsignedIntToInt() & 0x000000FF; sampleCount = data.readUnsignedIntToInt(); } diff --git a/libraries/extractor/src/main/java/androidx/media3/extractor/mp4/FragmentedMp4Extractor.java b/libraries/extractor/src/main/java/androidx/media3/extractor/mp4/FragmentedMp4Extractor.java index 04203a3597..39c0be79df 100644 --- a/libraries/extractor/src/main/java/androidx/media3/extractor/mp4/FragmentedMp4Extractor.java +++ b/libraries/extractor/src/main/java/androidx/media3/extractor/mp4/FragmentedMp4Extractor.java @@ -38,6 +38,9 @@ import androidx.media3.common.util.ParsableByteArray; import androidx.media3.common.util.TimestampAdjuster; import androidx.media3.common.util.UnstableApi; import androidx.media3.common.util.Util; +import androidx.media3.container.Mp4Box; +import androidx.media3.container.Mp4Box.ContainerBox; +import androidx.media3.container.Mp4Box.LeafBox; import androidx.media3.container.NalUnitUtil; import androidx.media3.container.ReorderingSeiMessageQueue; import androidx.media3.extractor.Ac4Util; @@ -54,8 +57,6 @@ import androidx.media3.extractor.SniffFailure; import androidx.media3.extractor.TrackOutput; import androidx.media3.extractor.metadata.emsg.EventMessage; import androidx.media3.extractor.metadata.emsg.EventMessageEncoder; -import androidx.media3.extractor.mp4.Atom.ContainerAtom; -import androidx.media3.extractor.mp4.Atom.LeafAtom; import androidx.media3.extractor.text.SubtitleParser; import androidx.media3.extractor.text.SubtitleTranscodingExtractorOutput; import com.google.common.collect.ImmutableList; @@ -208,7 +209,7 @@ public class FragmentedMp4Extractor implements Extractor { // Parser state. private final ParsableByteArray atomHeader; - private final ArrayDeque containerAtoms; + private final ArrayDeque containerAtoms; private final ArrayDeque pendingMetadataSampleInfos; private final ReorderingSeiMessageQueue reorderingSeiMessageQueue; @Nullable private final TrackOutput additionalEmsgTrackOutput; @@ -402,7 +403,7 @@ public class FragmentedMp4Extractor implements Extractor { this.closedCaptionFormats = Collections.unmodifiableList(closedCaptionFormats); this.additionalEmsgTrackOutput = additionalEmsgTrackOutput; eventMessageEncoder = new EventMessageEncoder(); - atomHeader = new ParsableByteArray(Atom.LONG_HEADER_SIZE); + atomHeader = new ParsableByteArray(Mp4Box.LONG_HEADER_SIZE); nalStartCode = new ParsableByteArray(NalUnitUtil.NAL_START_CODE); nalPrefix = new ParsableByteArray(5); nalBuffer = new ParsableByteArray(); @@ -517,22 +518,22 @@ public class FragmentedMp4Extractor implements Extractor { private boolean readAtomHeader(ExtractorInput input) throws IOException { if (atomHeaderBytesRead == 0) { // Read the standard length atom header. - if (!input.readFully(atomHeader.getData(), 0, Atom.HEADER_SIZE, true)) { + if (!input.readFully(atomHeader.getData(), 0, Mp4Box.HEADER_SIZE, true)) { return false; } - atomHeaderBytesRead = Atom.HEADER_SIZE; + atomHeaderBytesRead = Mp4Box.HEADER_SIZE; atomHeader.setPosition(0); atomSize = atomHeader.readUnsignedInt(); atomType = atomHeader.readInt(); } - if (atomSize == Atom.DEFINES_LARGE_SIZE) { + if (atomSize == Mp4Box.DEFINES_LARGE_SIZE) { // Read the large size. - int headerBytesRemaining = Atom.LONG_HEADER_SIZE - Atom.HEADER_SIZE; - input.readFully(atomHeader.getData(), Atom.HEADER_SIZE, headerBytesRemaining); + int headerBytesRemaining = Mp4Box.LONG_HEADER_SIZE - Mp4Box.HEADER_SIZE; + input.readFully(atomHeader.getData(), Mp4Box.HEADER_SIZE, headerBytesRemaining); atomHeaderBytesRead += headerBytesRemaining; atomSize = atomHeader.readUnsignedLongToLong(); - } else if (atomSize == Atom.EXTENDS_TO_END_SIZE) { + } else if (atomSize == Mp4Box.EXTENDS_TO_END_SIZE) { // The atom extends to the end of the file. Note that if the atom is within a container we can // work out its size even if the input length is unknown. long endPosition = input.getLength(); @@ -550,7 +551,7 @@ public class FragmentedMp4Extractor implements Extractor { } long atomPosition = input.getPosition() - atomHeaderBytesRead; - if (atomType == Atom.TYPE_moof || atomType == Atom.TYPE_mdat) { + if (atomType == Mp4Box.TYPE_moof || atomType == Mp4Box.TYPE_mdat) { if (!haveOutputSeekMap) { // This must be the first moof or mdat in the stream. extractorOutput.seekMap(new SeekMap.Unseekable(durationUs, atomPosition)); @@ -558,7 +559,7 @@ public class FragmentedMp4Extractor implements Extractor { } } - if (atomType == Atom.TYPE_moof) { + if (atomType == Mp4Box.TYPE_moof) { // The data positions may be updated when parsing the tfhd/trun. int trackCount = trackBundles.size(); for (int i = 0; i < trackCount; i++) { @@ -569,7 +570,7 @@ public class FragmentedMp4Extractor implements Extractor { } } - if (atomType == Atom.TYPE_mdat) { + if (atomType == Mp4Box.TYPE_mdat) { currentTrackBundle = null; endOfMdatPosition = atomPosition + atomSize; parserState = STATE_READING_ENCRYPTION_DATA; @@ -577,8 +578,8 @@ public class FragmentedMp4Extractor implements Extractor { } if (shouldParseContainerAtom(atomType)) { - long endPosition = input.getPosition() + atomSize - Atom.HEADER_SIZE; - containerAtoms.push(new ContainerAtom(atomType, endPosition)); + long endPosition = input.getPosition() + atomSize - Mp4Box.HEADER_SIZE; + containerAtoms.push(new ContainerBox(atomType, endPosition)); if (atomSize == atomHeaderBytesRead) { processAtomEnded(endPosition); } else { @@ -586,7 +587,7 @@ public class FragmentedMp4Extractor implements Extractor { enterReadingAtomHeaderState(); } } else if (shouldParseLeafAtom(atomType)) { - if (atomHeaderBytesRead != Atom.HEADER_SIZE) { + if (atomHeaderBytesRead != Mp4Box.HEADER_SIZE) { throw ParserException.createForUnsupportedContainerFeature( "Leaf atom defines extended atom size (unsupported)."); } @@ -595,7 +596,7 @@ public class FragmentedMp4Extractor implements Extractor { "Leaf atom with length > 2147483647 (unsupported)."); } ParsableByteArray atomData = new ParsableByteArray((int) atomSize); - System.arraycopy(atomHeader.getData(), 0, atomData.getData(), 0, Atom.HEADER_SIZE); + System.arraycopy(atomHeader.getData(), 0, atomData.getData(), 0, Mp4Box.HEADER_SIZE); this.atomData = atomData; parserState = STATE_READING_ATOM_PAYLOAD; } else { @@ -614,8 +615,8 @@ public class FragmentedMp4Extractor implements Extractor { int atomPayloadSize = (int) atomSize - atomHeaderBytesRead; @Nullable ParsableByteArray atomData = this.atomData; if (atomData != null) { - input.readFully(atomData.getData(), Atom.HEADER_SIZE, atomPayloadSize); - onLeafAtomRead(new LeafAtom(atomType, atomData), input.getPosition()); + input.readFully(atomData.getData(), Mp4Box.HEADER_SIZE, atomPayloadSize); + onLeafAtomRead(new LeafBox(atomType, atomData), input.getPosition()); } else { input.skipFully(atomPayloadSize); } @@ -629,45 +630,45 @@ public class FragmentedMp4Extractor implements Extractor { enterReadingAtomHeaderState(); } - private void onLeafAtomRead(LeafAtom leaf, long inputPosition) throws ParserException { + private void onLeafAtomRead(LeafBox leaf, long inputPosition) throws ParserException { if (!containerAtoms.isEmpty()) { containerAtoms.peek().add(leaf); - } else if (leaf.type == Atom.TYPE_sidx) { + } else if (leaf.type == Mp4Box.TYPE_sidx) { Pair result = parseSidx(leaf.data, inputPosition); segmentIndexEarliestPresentationTimeUs = result.first; extractorOutput.seekMap(result.second); haveOutputSeekMap = true; - } else if (leaf.type == Atom.TYPE_emsg) { + } else if (leaf.type == Mp4Box.TYPE_emsg) { onEmsgLeafAtomRead(leaf.data); } } - private void onContainerAtomRead(ContainerAtom container) throws ParserException { - if (container.type == Atom.TYPE_moov) { + private void onContainerAtomRead(ContainerBox container) throws ParserException { + if (container.type == Mp4Box.TYPE_moov) { onMoovContainerAtomRead(container); - } else if (container.type == Atom.TYPE_moof) { + } else if (container.type == Mp4Box.TYPE_moof) { onMoofContainerAtomRead(container); } else if (!containerAtoms.isEmpty()) { containerAtoms.peek().add(container); } } - private void onMoovContainerAtomRead(ContainerAtom moov) throws ParserException { + private void onMoovContainerAtomRead(ContainerBox moov) throws ParserException { checkState(sideloadedTrack == null, "Unexpected moov box."); @Nullable DrmInitData drmInitData = getDrmInitDataFromAtoms(moov.leafChildren); // Read declaration of track fragments in the moov box. - ContainerAtom mvex = checkNotNull(moov.getContainerAtomOfType(Atom.TYPE_mvex)); + ContainerBox mvex = checkNotNull(moov.getContainerBoxOfType(Mp4Box.TYPE_mvex)); SparseArray defaultSampleValuesArray = new SparseArray<>(); long duration = C.TIME_UNSET; int mvexChildrenSize = mvex.leafChildren.size(); for (int i = 0; i < mvexChildrenSize; i++) { - Atom.LeafAtom atom = mvex.leafChildren.get(i); - if (atom.type == Atom.TYPE_trex) { + LeafBox atom = mvex.leafChildren.get(i); + if (atom.type == Mp4Box.TYPE_trex) { Pair trexData = parseTrex(atom.data); defaultSampleValuesArray.put(trexData.first, trexData.second); - } else if (atom.type == Atom.TYPE_mehd) { + } else if (atom.type == Mp4Box.TYPE_mehd) { duration = parseMehd(atom.data); } } @@ -725,7 +726,7 @@ public class FragmentedMp4Extractor implements Extractor { return checkNotNull(defaultSampleValuesArray.get(trackId)); } - private void onMoofContainerAtomRead(ContainerAtom moof) throws ParserException { + private void onMoofContainerAtomRead(ContainerBox moof) throws ParserException { parseMoof(moof, trackBundles, sideloadedTrack != null, flags, scratchBytes); @Nullable DrmInitData drmInitData = getDrmInitDataFromAtoms(moof.leafChildren); @@ -775,7 +776,7 @@ public class FragmentedMp4Extractor implements Extractor { if (emsgTrackOutputs.length == 0) { return; } - atom.setPosition(Atom.HEADER_SIZE); + atom.setPosition(Mp4Box.HEADER_SIZE); int fullAtom = atom.readInt(); int version = AtomParsers.parseFullAtomVersion(fullAtom); String schemeIdUri; @@ -863,7 +864,7 @@ public class FragmentedMp4Extractor implements Extractor { /** Parses a trex atom (defined in 14496-12). */ private static Pair parseTrex(ParsableByteArray trex) { - trex.setPosition(Atom.FULL_HEADER_SIZE); + trex.setPosition(Mp4Box.FULL_HEADER_SIZE); int trackId = trex.readInt(); int defaultSampleDescriptionIndex = trex.readInt() - 1; int defaultSampleDuration = trex.readInt(); @@ -881,14 +882,14 @@ public class FragmentedMp4Extractor implements Extractor { /** Parses an mehd atom (defined in 14496-12). */ private static long parseMehd(ParsableByteArray mehd) { - mehd.setPosition(Atom.HEADER_SIZE); + mehd.setPosition(Mp4Box.HEADER_SIZE); int fullAtom = mehd.readInt(); int version = AtomParsers.parseFullAtomVersion(fullAtom); return version == 0 ? mehd.readUnsignedInt() : mehd.readUnsignedLongToLong(); } private static void parseMoof( - ContainerAtom moof, + ContainerBox moof, SparseArray trackBundles, boolean haveSideloadedTrack, @Flags int flags, @@ -896,9 +897,9 @@ public class FragmentedMp4Extractor implements Extractor { throws ParserException { int moofContainerChildrenSize = moof.containerChildren.size(); for (int i = 0; i < moofContainerChildrenSize; i++) { - Atom.ContainerAtom child = moof.containerChildren.get(i); + ContainerBox child = moof.containerChildren.get(i); // TODO: Support multiple traf boxes per track in a single moof. - if (child.type == Atom.TYPE_traf) { + if (child.type == Mp4Box.TYPE_traf) { parseTraf(child, trackBundles, haveSideloadedTrack, flags, extendedTypeScratch); } } @@ -906,13 +907,13 @@ public class FragmentedMp4Extractor implements Extractor { /** Parses a traf atom (defined in 14496-12). */ private static void parseTraf( - ContainerAtom traf, + ContainerBox traf, SparseArray trackBundles, boolean haveSideloadedTrack, @Flags int flags, byte[] extendedTypeScratch) throws ParserException { - LeafAtom tfhd = checkNotNull(traf.getLeafAtomOfType(Atom.TYPE_tfhd)); + LeafBox tfhd = checkNotNull(traf.getLeafBoxOfType(Mp4Box.TYPE_tfhd)); @Nullable TrackBundle trackBundle = parseTfhd(tfhd.data, trackBundles, haveSideloadedTrack); if (trackBundle == null) { return; @@ -923,7 +924,7 @@ public class FragmentedMp4Extractor implements Extractor { boolean fragmentDecodeTimeIncludesMoov = fragment.nextFragmentDecodeTimeIncludesMoov; trackBundle.resetFragmentInfo(); trackBundle.currentlyInFragment = true; - @Nullable LeafAtom tfdtAtom = traf.getLeafAtomOfType(Atom.TYPE_tfdt); + @Nullable LeafBox tfdtAtom = traf.getLeafBoxOfType(Mp4Box.TYPE_tfdt); if (tfdtAtom != null && (flags & FLAG_WORKAROUND_IGNORE_TFDT_BOX) == 0) { fragment.nextFragmentDecodeTime = parseTfdt(tfdtAtom.data); fragment.nextFragmentDecodeTimeIncludesMoov = true; @@ -939,17 +940,17 @@ public class FragmentedMp4Extractor implements Extractor { trackBundle.moovSampleTable.track.getSampleDescriptionEncryptionBox( checkNotNull(fragment.header).sampleDescriptionIndex); - @Nullable LeafAtom saiz = traf.getLeafAtomOfType(Atom.TYPE_saiz); + @Nullable LeafBox saiz = traf.getLeafBoxOfType(Mp4Box.TYPE_saiz); if (saiz != null) { parseSaiz(checkNotNull(encryptionBox), saiz.data, fragment); } - @Nullable LeafAtom saio = traf.getLeafAtomOfType(Atom.TYPE_saio); + @Nullable LeafBox saio = traf.getLeafBoxOfType(Mp4Box.TYPE_saio); if (saio != null) { parseSaio(saio.data, fragment); } - @Nullable LeafAtom senc = traf.getLeafAtomOfType(Atom.TYPE_senc); + @Nullable LeafBox senc = traf.getLeafBoxOfType(Mp4Box.TYPE_senc); if (senc != null) { parseSenc(senc.data, fragment); } @@ -958,24 +959,24 @@ public class FragmentedMp4Extractor implements Extractor { int leafChildrenSize = traf.leafChildren.size(); for (int i = 0; i < leafChildrenSize; i++) { - LeafAtom atom = traf.leafChildren.get(i); - if (atom.type == Atom.TYPE_uuid) { + LeafBox atom = traf.leafChildren.get(i); + if (atom.type == Mp4Box.TYPE_uuid) { parseUuid(atom.data, fragment, extendedTypeScratch); } } } - private static void parseTruns(ContainerAtom traf, TrackBundle trackBundle, @Flags int flags) + private static void parseTruns(ContainerBox traf, TrackBundle trackBundle, @Flags int flags) throws ParserException { int trunCount = 0; int totalSampleCount = 0; - List leafChildren = traf.leafChildren; + List leafChildren = traf.leafChildren; int leafChildrenSize = leafChildren.size(); for (int i = 0; i < leafChildrenSize; i++) { - LeafAtom atom = leafChildren.get(i); - if (atom.type == Atom.TYPE_trun) { + LeafBox atom = leafChildren.get(i); + if (atom.type == Mp4Box.TYPE_trun) { ParsableByteArray trunData = atom.data; - trunData.setPosition(Atom.FULL_HEADER_SIZE); + trunData.setPosition(Mp4Box.FULL_HEADER_SIZE); int trunSampleCount = trunData.readUnsignedIntToInt(); if (trunSampleCount > 0) { totalSampleCount += trunSampleCount; @@ -991,8 +992,8 @@ public class FragmentedMp4Extractor implements Extractor { int trunIndex = 0; int trunStartPosition = 0; for (int i = 0; i < leafChildrenSize; i++) { - LeafAtom trun = leafChildren.get(i); - if (trun.type == Atom.TYPE_trun) { + LeafBox trun = leafChildren.get(i); + if (trun.type == Mp4Box.TYPE_trun) { trunStartPosition = parseTrun(trackBundle, trunIndex++, flags, trun.data, trunStartPosition); } @@ -1003,7 +1004,7 @@ public class FragmentedMp4Extractor implements Extractor { TrackEncryptionBox encryptionBox, ParsableByteArray saiz, TrackFragment out) throws ParserException { int vectorSize = encryptionBox.perSampleIvSize; - saiz.setPosition(Atom.HEADER_SIZE); + saiz.setPosition(Mp4Box.HEADER_SIZE); int fullAtom = saiz.readInt(); int flags = AtomParsers.parseFullAtomFlags(fullAtom); if ((flags & 0x01) == 1) { @@ -1047,7 +1048,7 @@ public class FragmentedMp4Extractor implements Extractor { * @param out The {@link TrackFragment} to populate with data from the saio atom. */ private static void parseSaio(ParsableByteArray saio, TrackFragment out) throws ParserException { - saio.setPosition(Atom.HEADER_SIZE); + saio.setPosition(Mp4Box.HEADER_SIZE); int fullAtom = saio.readInt(); int flags = AtomParsers.parseFullAtomFlags(fullAtom); if ((flags & 0x01) == 1) { @@ -1081,7 +1082,7 @@ public class FragmentedMp4Extractor implements Extractor { @Nullable private static TrackBundle parseTfhd( ParsableByteArray tfhd, SparseArray trackBundles, boolean haveSideloadedTrack) { - tfhd.setPosition(Atom.HEADER_SIZE); + tfhd.setPosition(Mp4Box.HEADER_SIZE); int fullAtom = tfhd.readInt(); int atomFlags = AtomParsers.parseFullAtomFlags(fullAtom); int trackId = tfhd.readInt(); @@ -1130,7 +1131,7 @@ public class FragmentedMp4Extractor implements Extractor { * media, expressed in the media's timescale. */ private static long parseTfdt(ParsableByteArray tfdt) { - tfdt.setPosition(Atom.HEADER_SIZE); + tfdt.setPosition(Mp4Box.HEADER_SIZE); int fullAtom = tfdt.readInt(); int version = AtomParsers.parseFullAtomVersion(fullAtom); return version == 1 ? tfdt.readUnsignedLongToLong() : tfdt.readUnsignedInt(); @@ -1173,7 +1174,7 @@ public class FragmentedMp4Extractor implements Extractor { ParsableByteArray trun, int trackRunStart) throws ParserException { - trun.setPosition(Atom.HEADER_SIZE); + trun.setPosition(Mp4Box.HEADER_SIZE); int fullAtom = trun.readInt(); int atomFlags = AtomParsers.parseFullAtomFlags(fullAtom); @@ -1264,7 +1265,7 @@ public class FragmentedMp4Extractor implements Extractor { private static void parseUuid( ParsableByteArray uuid, TrackFragment out, byte[] extendedTypeScratch) throws ParserException { - uuid.setPosition(Atom.HEADER_SIZE); + uuid.setPosition(Mp4Box.HEADER_SIZE); uuid.readBytes(extendedTypeScratch, 0, 16); // Currently this parser only supports Microsoft's PIFF SampleEncryptionBox. @@ -1284,7 +1285,7 @@ public class FragmentedMp4Extractor implements Extractor { private static void parseSenc(ParsableByteArray senc, int offset, TrackFragment out) throws ParserException { - senc.setPosition(Atom.HEADER_SIZE + offset); + senc.setPosition(Mp4Box.HEADER_SIZE + offset); int fullAtom = senc.readInt(); int flags = AtomParsers.parseFullAtomFlags(fullAtom); @@ -1315,20 +1316,20 @@ public class FragmentedMp4Extractor implements Extractor { } private static void parseSampleGroups( - ContainerAtom traf, @Nullable String schemeType, TrackFragment out) throws ParserException { + ContainerBox traf, @Nullable String schemeType, TrackFragment out) throws ParserException { // Find sbgp and sgpd boxes with grouping_type == seig. @Nullable ParsableByteArray sbgp = null; @Nullable ParsableByteArray sgpd = null; for (int i = 0; i < traf.leafChildren.size(); i++) { - LeafAtom leafAtom = traf.leafChildren.get(i); + LeafBox leafAtom = traf.leafChildren.get(i); ParsableByteArray leafAtomData = leafAtom.data; - if (leafAtom.type == Atom.TYPE_sbgp) { - leafAtomData.setPosition(Atom.FULL_HEADER_SIZE); + if (leafAtom.type == Mp4Box.TYPE_sbgp) { + leafAtomData.setPosition(Mp4Box.FULL_HEADER_SIZE); if (leafAtomData.readInt() == SAMPLE_GROUP_TYPE_seig) { sbgp = leafAtomData; } - } else if (leafAtom.type == Atom.TYPE_sgpd) { - leafAtomData.setPosition(Atom.FULL_HEADER_SIZE); + } else if (leafAtom.type == Mp4Box.TYPE_sgpd) { + leafAtomData.setPosition(Mp4Box.FULL_HEADER_SIZE); if (leafAtomData.readInt() == SAMPLE_GROUP_TYPE_seig) { sgpd = leafAtomData; } @@ -1338,7 +1339,7 @@ public class FragmentedMp4Extractor implements Extractor { return; } - sbgp.setPosition(Atom.HEADER_SIZE); + sbgp.setPosition(Mp4Box.HEADER_SIZE); int sbgpVersion = AtomParsers.parseFullAtomVersion(sbgp.readInt()); sbgp.skipBytes(4); // grouping_type == seig. if (sbgpVersion == 1) { @@ -1349,7 +1350,7 @@ public class FragmentedMp4Extractor implements Extractor { "Entry count in sbgp != 1 (unsupported)."); } - sgpd.setPosition(Atom.HEADER_SIZE); + sgpd.setPosition(Mp4Box.HEADER_SIZE); int sgpdVersion = AtomParsers.parseFullAtomVersion(sgpd.readInt()); sgpd.skipBytes(4); // grouping_type == seig. if (sgpdVersion == 1) { @@ -1405,7 +1406,7 @@ public class FragmentedMp4Extractor implements Extractor { */ private static Pair parseSidx(ParsableByteArray atom, long inputPosition) throws ParserException { - atom.setPosition(Atom.HEADER_SIZE); + atom.setPosition(Mp4Box.HEADER_SIZE); int fullAtom = atom.readInt(); int version = AtomParsers.parseFullAtomVersion(fullAtom); @@ -1551,8 +1552,8 @@ public class FragmentedMp4Extractor implements Extractor { if (trackBundle.moovSampleTable.track.sampleTransformation == Track.TRANSFORMATION_CEA608_CDAT) { - sampleSize -= Atom.HEADER_SIZE; - input.skipFully(Atom.HEADER_SIZE); + sampleSize -= Mp4Box.HEADER_SIZE; + input.skipFully(Mp4Box.HEADER_SIZE); } if (MimeTypes.AUDIO_AC4.equals(trackBundle.moovSampleTable.track.format.sampleMimeType)) { @@ -1742,12 +1743,12 @@ public class FragmentedMp4Extractor implements Extractor { /** Returns DrmInitData from leaf atoms. */ @Nullable - private static DrmInitData getDrmInitDataFromAtoms(List leafChildren) { + private static DrmInitData getDrmInitDataFromAtoms(List leafChildren) { @Nullable ArrayList schemeDatas = null; int leafChildrenSize = leafChildren.size(); for (int i = 0; i < leafChildrenSize; i++) { - LeafAtom child = leafChildren.get(i); - if (child.type == Atom.TYPE_pssh) { + LeafBox child = leafChildren.get(i); + if (child.type == Mp4Box.TYPE_pssh) { if (schemeDatas == null) { schemeDatas = new ArrayList<>(); } @@ -1765,47 +1766,47 @@ public class FragmentedMp4Extractor implements Extractor { /** Returns whether the extractor should decode a leaf atom with type {@code atom}. */ private static boolean shouldParseLeafAtom(int atom) { - return atom == Atom.TYPE_hdlr - || atom == Atom.TYPE_mdhd - || atom == Atom.TYPE_mvhd - || atom == Atom.TYPE_sidx - || atom == Atom.TYPE_stsd - || atom == Atom.TYPE_stts - || atom == Atom.TYPE_ctts - || atom == Atom.TYPE_stsc - || atom == Atom.TYPE_stsz - || atom == Atom.TYPE_stz2 - || atom == Atom.TYPE_stco - || atom == Atom.TYPE_co64 - || atom == Atom.TYPE_stss - || atom == Atom.TYPE_tfdt - || atom == Atom.TYPE_tfhd - || atom == Atom.TYPE_tkhd - || atom == Atom.TYPE_trex - || atom == Atom.TYPE_trun - || atom == Atom.TYPE_pssh - || atom == Atom.TYPE_saiz - || atom == Atom.TYPE_saio - || atom == Atom.TYPE_senc - || atom == Atom.TYPE_uuid - || atom == Atom.TYPE_sbgp - || atom == Atom.TYPE_sgpd - || atom == Atom.TYPE_elst - || atom == Atom.TYPE_mehd - || atom == Atom.TYPE_emsg; + return atom == Mp4Box.TYPE_hdlr + || atom == Mp4Box.TYPE_mdhd + || atom == Mp4Box.TYPE_mvhd + || atom == Mp4Box.TYPE_sidx + || atom == Mp4Box.TYPE_stsd + || atom == Mp4Box.TYPE_stts + || atom == Mp4Box.TYPE_ctts + || atom == Mp4Box.TYPE_stsc + || atom == Mp4Box.TYPE_stsz + || atom == Mp4Box.TYPE_stz2 + || atom == Mp4Box.TYPE_stco + || atom == Mp4Box.TYPE_co64 + || atom == Mp4Box.TYPE_stss + || atom == Mp4Box.TYPE_tfdt + || atom == Mp4Box.TYPE_tfhd + || atom == Mp4Box.TYPE_tkhd + || atom == Mp4Box.TYPE_trex + || atom == Mp4Box.TYPE_trun + || atom == Mp4Box.TYPE_pssh + || atom == Mp4Box.TYPE_saiz + || atom == Mp4Box.TYPE_saio + || atom == Mp4Box.TYPE_senc + || atom == Mp4Box.TYPE_uuid + || atom == Mp4Box.TYPE_sbgp + || atom == Mp4Box.TYPE_sgpd + || atom == Mp4Box.TYPE_elst + || atom == Mp4Box.TYPE_mehd + || atom == Mp4Box.TYPE_emsg; } /** Returns whether the extractor should decode a container atom with type {@code atom}. */ private static boolean shouldParseContainerAtom(int atom) { - return atom == Atom.TYPE_moov - || atom == Atom.TYPE_trak - || atom == Atom.TYPE_mdia - || atom == Atom.TYPE_minf - || atom == Atom.TYPE_stbl - || atom == Atom.TYPE_moof - || atom == Atom.TYPE_traf - || atom == Atom.TYPE_mvex - || atom == Atom.TYPE_edts; + return atom == Mp4Box.TYPE_moov + || atom == Mp4Box.TYPE_trak + || atom == Mp4Box.TYPE_mdia + || atom == Mp4Box.TYPE_minf + || atom == Mp4Box.TYPE_stbl + || atom == Mp4Box.TYPE_moof + || atom == Mp4Box.TYPE_traf + || atom == Mp4Box.TYPE_mvex + || atom == Mp4Box.TYPE_edts; } /** Holds data corresponding to a metadata sample. */ diff --git a/libraries/extractor/src/main/java/androidx/media3/extractor/mp4/MetadataUtil.java b/libraries/extractor/src/main/java/androidx/media3/extractor/mp4/MetadataUtil.java index f015a184d5..86eccb1367 100644 --- a/libraries/extractor/src/main/java/androidx/media3/extractor/mp4/MetadataUtil.java +++ b/libraries/extractor/src/main/java/androidx/media3/extractor/mp4/MetadataUtil.java @@ -25,6 +25,7 @@ import androidx.media3.common.util.Log; import androidx.media3.common.util.NullableType; import androidx.media3.common.util.ParsableByteArray; import androidx.media3.container.MdtaMetadataEntry; +import androidx.media3.container.Mp4Box; import androidx.media3.extractor.GaplessInfoHolder; import androidx.media3.extractor.metadata.id3.ApicFrame; import androidx.media3.extractor.metadata.id3.CommentFrame; @@ -203,7 +204,7 @@ import com.google.common.collect.ImmutableList; } else if (type == TYPE_INTERNAL) { return parseInternalAttribute(ilst, endPosition); } - Log.d(TAG, "Skipped unknown metadata entry: " + Atom.getAtomTypeString(type)); + Log.d(TAG, "Skipped unknown metadata entry: " + Mp4Box.getBoxTypeString(type)); return null; } finally { ilst.setPosition(endPosition); @@ -225,7 +226,7 @@ import com.google.common.collect.ImmutableList; while ((atomPosition = ilst.getPosition()) < endPosition) { int atomSize = ilst.readInt(); int atomType = ilst.readInt(); - if (atomType == Atom.TYPE_data) { + if (atomType == Mp4Box.TYPE_data) { int typeIndicator = ilst.readInt(); int localeIndicator = ilst.readInt(); int dataSize = atomSize - 16; @@ -264,12 +265,12 @@ import com.google.common.collect.ImmutableList; int type, String id, ParsableByteArray data) { int atomSize = data.readInt(); int atomType = data.readInt(); - if (atomType == Atom.TYPE_data) { + if (atomType == Mp4Box.TYPE_data) { data.skipBytes(8); // version (1), flags (3), empty (4) String value = data.readNullTerminatedString(atomSize - 16); return new TextInformationFrame(id, /* description= */ null, ImmutableList.of(value)); } - Log.w(TAG, "Failed to parse text attribute: " + Atom.getAtomTypeString(type)); + Log.w(TAG, "Failed to parse text attribute: " + Mp4Box.getBoxTypeString(type)); return null; } @@ -277,12 +278,12 @@ import com.google.common.collect.ImmutableList; private static CommentFrame parseCommentAttribute(int type, ParsableByteArray data) { int atomSize = data.readInt(); int atomType = data.readInt(); - if (atomType == Atom.TYPE_data) { + if (atomType == Mp4Box.TYPE_data) { data.skipBytes(8); // version (1), flags (3), empty (4) String value = data.readNullTerminatedString(atomSize - 16); return new CommentFrame(C.LANGUAGE_UNDETERMINED, value, value); } - Log.w(TAG, "Failed to parse comment attribute: " + Atom.getAtomTypeString(type)); + Log.w(TAG, "Failed to parse comment attribute: " + Mp4Box.getBoxTypeString(type)); return null; } @@ -303,14 +304,14 @@ import com.google.common.collect.ImmutableList; id, /* description= */ null, ImmutableList.of(Integer.toString(value))) : new CommentFrame(C.LANGUAGE_UNDETERMINED, id, Integer.toString(value)); } - Log.w(TAG, "Failed to parse uint8 attribute: " + Atom.getAtomTypeString(type)); + Log.w(TAG, "Failed to parse uint8 attribute: " + Mp4Box.getBoxTypeString(type)); return null; } private static int parseIntegerAttribute(ParsableByteArray data) { int atomSize = data.readInt(); int atomType = data.readInt(); - if (atomType == Atom.TYPE_data) { + if (atomType == Mp4Box.TYPE_data) { data.skipBytes(8); // version (1), flags (3), empty (4) switch (atomSize - 16) { case 1: @@ -334,7 +335,7 @@ import com.google.common.collect.ImmutableList; int type, String attributeName, ParsableByteArray data) { int atomSize = data.readInt(); int atomType = data.readInt(); - if (atomType == Atom.TYPE_data && atomSize >= 22) { + if (atomType == Mp4Box.TYPE_data && atomSize >= 22) { data.skipBytes(10); // version (1), flags (3), empty (4), empty (2) int index = data.readUnsignedShort(); if (index > 0) { @@ -347,7 +348,7 @@ import com.google.common.collect.ImmutableList; attributeName, /* description= */ null, ImmutableList.of(value)); } } - Log.w(TAG, "Failed to parse index/count attribute: " + Atom.getAtomTypeString(type)); + Log.w(TAG, "Failed to parse index/count attribute: " + Mp4Box.getBoxTypeString(type)); return null; } @@ -369,7 +370,7 @@ import com.google.common.collect.ImmutableList; private static ApicFrame parseCoverArt(ParsableByteArray data) { int atomSize = data.readInt(); int atomType = data.readInt(); - if (atomType == Atom.TYPE_data) { + if (atomType == Mp4Box.TYPE_data) { int fullVersionInt = data.readInt(); int flags = AtomParsers.parseFullAtomFlags(fullVersionInt); @Nullable String mimeType = flags == 13 ? "image/jpeg" : flags == 14 ? "image/png" : null; @@ -401,12 +402,12 @@ import com.google.common.collect.ImmutableList; int atomSize = data.readInt(); int atomType = data.readInt(); data.skipBytes(4); // version (1), flags (3) - if (atomType == Atom.TYPE_mean) { + if (atomType == Mp4Box.TYPE_mean) { domain = data.readNullTerminatedString(atomSize - 12); - } else if (atomType == Atom.TYPE_name) { + } else if (atomType == Mp4Box.TYPE_name) { name = data.readNullTerminatedString(atomSize - 12); } else { - if (atomType == Atom.TYPE_data) { + if (atomType == Mp4Box.TYPE_data) { dataAtomPosition = atomPosition; dataAtomSize = atomSize; } diff --git a/libraries/extractor/src/main/java/androidx/media3/extractor/mp4/Mp4Extractor.java b/libraries/extractor/src/main/java/androidx/media3/extractor/mp4/Mp4Extractor.java index 53ee27c70a..dd96df587f 100644 --- a/libraries/extractor/src/main/java/androidx/media3/extractor/mp4/Mp4Extractor.java +++ b/libraries/extractor/src/main/java/androidx/media3/extractor/mp4/Mp4Extractor.java @@ -47,6 +47,8 @@ import androidx.media3.common.util.Assertions; import androidx.media3.common.util.ParsableByteArray; import androidx.media3.common.util.UnstableApi; import androidx.media3.container.MdtaMetadataEntry; +import androidx.media3.container.Mp4Box; +import androidx.media3.container.Mp4Box.ContainerBox; import androidx.media3.container.NalUnitUtil; import androidx.media3.extractor.Ac3Util; import androidx.media3.extractor.Ac4Util; @@ -63,7 +65,6 @@ import androidx.media3.extractor.TrackOutput; import androidx.media3.extractor.TrueHdSampleRechunker; import androidx.media3.extractor.metadata.mp4.MotionPhotoMetadata; import androidx.media3.extractor.metadata.mp4.SlowMotionData; -import androidx.media3.extractor.mp4.Atom.ContainerAtom; import androidx.media3.extractor.text.SubtitleParser; import androidx.media3.extractor.text.SubtitleTranscodingExtractorOutput; import com.google.common.collect.ImmutableList; @@ -229,7 +230,7 @@ public final class Mp4Extractor implements Extractor, SeekMap { private final ParsableByteArray scratch; private final ParsableByteArray atomHeader; - private final ArrayDeque containerAtoms; + private final ArrayDeque containerAtoms; private final SefReader sefReader; private final List slowMotionMetadataEntries; @@ -305,7 +306,7 @@ public final class Mp4Extractor implements Extractor, SeekMap { ((flags & FLAG_READ_SEF_DATA) != 0) ? STATE_READING_SEF : STATE_READING_ATOM_HEADER; sefReader = new SefReader(); slowMotionMetadataEntries = new ArrayList<>(); - atomHeader = new ParsableByteArray(Atom.LONG_HEADER_SIZE); + atomHeader = new ParsableByteArray(Mp4Box.LONG_HEADER_SIZE); containerAtoms = new ArrayDeque<>(); nalStartCode = new ParsableByteArray(NalUnitUtil.NAL_START_CODE); nalPrefix = new ParsableByteArray(5); @@ -493,28 +494,28 @@ public final class Mp4Extractor implements Extractor, SeekMap { private boolean readAtomHeader(ExtractorInput input) throws IOException { if (atomHeaderBytesRead == 0) { // Read the standard length atom header. - if (!input.readFully(atomHeader.getData(), 0, Atom.HEADER_SIZE, true)) { + if (!input.readFully(atomHeader.getData(), 0, Mp4Box.HEADER_SIZE, true)) { processEndOfStreamReadingAtomHeader(); return false; } - atomHeaderBytesRead = Atom.HEADER_SIZE; + atomHeaderBytesRead = Mp4Box.HEADER_SIZE; atomHeader.setPosition(0); atomSize = atomHeader.readUnsignedInt(); atomType = atomHeader.readInt(); } - if (atomSize == Atom.DEFINES_LARGE_SIZE) { + if (atomSize == Mp4Box.DEFINES_LARGE_SIZE) { // Read the large size. - int headerBytesRemaining = Atom.LONG_HEADER_SIZE - Atom.HEADER_SIZE; - input.readFully(atomHeader.getData(), Atom.HEADER_SIZE, headerBytesRemaining); + int headerBytesRemaining = Mp4Box.LONG_HEADER_SIZE - Mp4Box.HEADER_SIZE; + input.readFully(atomHeader.getData(), Mp4Box.HEADER_SIZE, headerBytesRemaining); atomHeaderBytesRead += headerBytesRemaining; atomSize = atomHeader.readUnsignedLongToLong(); - } else if (atomSize == Atom.EXTENDS_TO_END_SIZE) { + } else if (atomSize == Mp4Box.EXTENDS_TO_END_SIZE) { // The atom extends to the end of the file. Note that if the atom is within a container we can // work out its size even if the input length is unknown. long endPosition = input.getLength(); if (endPosition == C.LENGTH_UNSET) { - @Nullable ContainerAtom containerAtom = containerAtoms.peek(); + @Nullable ContainerBox containerAtom = containerAtoms.peek(); if (containerAtom != null) { endPosition = containerAtom.endPosition; } @@ -531,10 +532,10 @@ public final class Mp4Extractor implements Extractor, SeekMap { if (shouldParseContainerAtom(atomType)) { long endPosition = input.getPosition() + atomSize - atomHeaderBytesRead; - if (atomSize != atomHeaderBytesRead && atomType == Atom.TYPE_meta) { + if (atomSize != atomHeaderBytesRead && atomType == Mp4Box.TYPE_meta) { maybeSkipRemainingMetaAtomHeaderBytes(input); } - containerAtoms.push(new ContainerAtom(atomType, endPosition)); + containerAtoms.push(new ContainerBox(atomType, endPosition)); if (atomSize == atomHeaderBytesRead) { processAtomEnded(endPosition); } else { @@ -544,10 +545,10 @@ public final class Mp4Extractor implements Extractor, SeekMap { } else if (shouldParseLeafAtom(atomType)) { // We don't support parsing of leaf atoms that define extended atom sizes, or that have // lengths greater than Integer.MAX_VALUE. - Assertions.checkState(atomHeaderBytesRead == Atom.HEADER_SIZE); + Assertions.checkState(atomHeaderBytesRead == Mp4Box.HEADER_SIZE); Assertions.checkState(atomSize <= Integer.MAX_VALUE); ParsableByteArray atomData = new ParsableByteArray((int) atomSize); - System.arraycopy(atomHeader.getData(), 0, atomData.getData(), 0, Atom.HEADER_SIZE); + System.arraycopy(atomHeader.getData(), 0, atomData.getData(), 0, Mp4Box.HEADER_SIZE); this.atomData = atomData; parserState = STATE_READING_ATOM_PAYLOAD; } else { @@ -573,14 +574,14 @@ public final class Mp4Extractor implements Extractor, SeekMap { @Nullable ParsableByteArray atomData = this.atomData; if (atomData != null) { input.readFully(atomData.getData(), atomHeaderBytesRead, (int) atomPayloadSize); - if (atomType == Atom.TYPE_ftyp) { + if (atomType == Mp4Box.TYPE_ftyp) { seenFtypAtom = true; fileType = processFtypAtom(atomData); } else if (!containerAtoms.isEmpty()) { - containerAtoms.peek().add(new Atom.LeafAtom(atomType, atomData)); + containerAtoms.peek().add(new Mp4Box.LeafBox(atomType, atomData)); } } else { - if (!seenFtypAtom && atomType == Atom.TYPE_mdat) { + if (!seenFtypAtom && atomType == Mp4Box.TYPE_mdat) { // The original QuickTime specification did not require files to begin with the ftyp atom. // See https://developer.apple.com/standards/qtff-2001.pdf. fileType = FILE_TYPE_QUICKTIME; @@ -614,8 +615,8 @@ public final class Mp4Extractor implements Extractor, SeekMap { private void processAtomEnded(long atomEndPosition) throws ParserException { while (!containerAtoms.isEmpty() && containerAtoms.peek().endPosition == atomEndPosition) { - Atom.ContainerAtom containerAtom = containerAtoms.pop(); - if (containerAtom.type == Atom.TYPE_moov) { + ContainerBox containerAtom = containerAtoms.pop(); + if (containerAtom.type == Mp4Box.TYPE_moov) { // We've reached the end of the moov atom. Process it and prepare to read samples. processMoovAtom(containerAtom); containerAtoms.clear(); @@ -636,10 +637,10 @@ public final class Mp4Extractor implements Extractor, SeekMap { * *

The processing is aborted if the edvd.moov atom needs to be processed instead. */ - private void processMoovAtom(ContainerAtom moov) throws ParserException { + private void processMoovAtom(ContainerBox moov) throws ParserException { // Process metadata first to determine whether to abort processing and seek to the edvd atom. @Nullable Metadata mdtaMetadata = null; - @Nullable Atom.ContainerAtom meta = moov.getContainerAtomOfType(Atom.TYPE_meta); + @Nullable Mp4Box.ContainerBox meta = moov.getContainerBoxOfType(Mp4Box.TYPE_meta); List<@C.AuxiliaryTrackType Integer> auxiliaryTrackTypesForEditableVideoTracks = new ArrayList<>(); if (meta != null) { @@ -654,7 +655,6 @@ public final class Mp4Extractor implements Extractor, SeekMap { return; } } - int firstVideoTrackIndex = C.INDEX_UNSET; long durationUs = C.TIME_UNSET; List tracks = new ArrayList<>(); @@ -663,7 +663,7 @@ public final class Mp4Extractor implements Extractor, SeekMap { boolean isQuickTime = fileType == FILE_TYPE_QUICKTIME; GaplessInfoHolder gaplessInfoHolder = new GaplessInfoHolder(); @Nullable Metadata udtaMetadata = null; - @Nullable Atom.LeafAtom udta = moov.getLeafAtomOfType(Atom.TYPE_udta); + @Nullable Mp4Box.LeafBox udta = moov.getLeafBoxOfType(Mp4Box.TYPE_udta); if (udta != null) { udtaMetadata = AtomParsers.parseUdta(udta); gaplessInfoHolder.setFromMetadata(udtaMetadata); @@ -671,7 +671,7 @@ public final class Mp4Extractor implements Extractor, SeekMap { Metadata mvhdMetadata = new Metadata( - AtomParsers.parseMvhd(checkNotNull(moov.getLeafAtomOfType(Atom.TYPE_mvhd)).data)); + AtomParsers.parseMvhd(checkNotNull(moov.getLeafBoxOfType(Mp4Box.TYPE_mvhd)).data)); boolean ignoreEditLists = (flags & FLAG_WORKAROUND_IGNORE_EDIT_LISTS) != 0; List trackSampleTables = @@ -863,8 +863,8 @@ public final class Mp4Extractor implements Extractor, SeekMap { if (track.track.sampleTransformation == Track.TRANSFORMATION_CEA608_CDAT) { // The sample information is contained in a cdat atom. The header must be discarded for // committing. - skipAmount += Atom.HEADER_SIZE; - sampleSize -= Atom.HEADER_SIZE; + skipAmount += Mp4Box.HEADER_SIZE; + sampleSize -= Mp4Box.HEADER_SIZE; } input.skipFully((int) skipAmount); // Treat all samples in non-H.264 codecs as depended on. @@ -1050,7 +1050,7 @@ public final class Mp4Extractor implements Extractor, SeekMap { /** Processes an atom whose payload does not need to be parsed. */ private void processUnparsedAtom(long atomStartPosition) { - if (atomType == Atom.TYPE_mpvd) { + if (atomType == Mp4Box.TYPE_mpvd) { // The input is an HEIC motion photo following the Google Photos Motion Photo File Format // V1.1. motionPhotoMetadata = @@ -1148,7 +1148,7 @@ public final class Mp4Extractor implements Extractor, SeekMap { * @return The {@link FileType}. */ private static @FileType int processFtypAtom(ParsableByteArray atomData) { - atomData.setPosition(Atom.HEADER_SIZE); + atomData.setPosition(Mp4Box.HEADER_SIZE); int majorBrand = atomData.readInt(); @FileType int fileType = brandToFileType(majorBrand); if (fileType != FILE_TYPE_MP4) { @@ -1177,36 +1177,36 @@ public final class Mp4Extractor implements Extractor, SeekMap { /** Returns whether the extractor should decode a leaf atom with type {@code atom}. */ private static boolean shouldParseLeafAtom(int atom) { - return atom == Atom.TYPE_mdhd - || atom == Atom.TYPE_mvhd - || atom == Atom.TYPE_hdlr - || atom == Atom.TYPE_stsd - || atom == Atom.TYPE_stts - || atom == Atom.TYPE_stss - || atom == Atom.TYPE_ctts - || atom == Atom.TYPE_elst - || atom == Atom.TYPE_stsc - || atom == Atom.TYPE_stsz - || atom == Atom.TYPE_stz2 - || atom == Atom.TYPE_stco - || atom == Atom.TYPE_co64 - || atom == Atom.TYPE_tkhd - || atom == Atom.TYPE_ftyp - || atom == Atom.TYPE_udta - || atom == Atom.TYPE_keys - || atom == Atom.TYPE_ilst; + return atom == Mp4Box.TYPE_mdhd + || atom == Mp4Box.TYPE_mvhd + || atom == Mp4Box.TYPE_hdlr + || atom == Mp4Box.TYPE_stsd + || atom == Mp4Box.TYPE_stts + || atom == Mp4Box.TYPE_stss + || atom == Mp4Box.TYPE_ctts + || atom == Mp4Box.TYPE_elst + || atom == Mp4Box.TYPE_stsc + || atom == Mp4Box.TYPE_stsz + || atom == Mp4Box.TYPE_stz2 + || atom == Mp4Box.TYPE_stco + || atom == Mp4Box.TYPE_co64 + || atom == Mp4Box.TYPE_tkhd + || atom == Mp4Box.TYPE_ftyp + || atom == Mp4Box.TYPE_udta + || atom == Mp4Box.TYPE_keys + || atom == Mp4Box.TYPE_ilst; } /** Returns whether the extractor should decode a container atom with type {@code atom}. */ private static boolean shouldParseContainerAtom(int atom) { - return atom == Atom.TYPE_moov - || atom == Atom.TYPE_trak - || atom == Atom.TYPE_mdia - || atom == Atom.TYPE_minf - || atom == Atom.TYPE_stbl - || atom == Atom.TYPE_edts - || atom == Atom.TYPE_meta - || atom == Atom.TYPE_edvd; + return atom == Mp4Box.TYPE_moov + || atom == Mp4Box.TYPE_trak + || atom == Mp4Box.TYPE_mdia + || atom == Mp4Box.TYPE_minf + || atom == Mp4Box.TYPE_stbl + || atom == Mp4Box.TYPE_edts + || atom == Mp4Box.TYPE_meta + || atom == Mp4Box.TYPE_edvd; } private static final class Mp4Track { diff --git a/libraries/extractor/src/main/java/androidx/media3/extractor/mp4/PsshAtomUtil.java b/libraries/extractor/src/main/java/androidx/media3/extractor/mp4/PsshAtomUtil.java index 7abf61eaf9..748822e295 100644 --- a/libraries/extractor/src/main/java/androidx/media3/extractor/mp4/PsshAtomUtil.java +++ b/libraries/extractor/src/main/java/androidx/media3/extractor/mp4/PsshAtomUtil.java @@ -19,6 +19,7 @@ import androidx.annotation.Nullable; import androidx.media3.common.util.Log; import androidx.media3.common.util.ParsableByteArray; import androidx.media3.common.util.UnstableApi; +import androidx.media3.container.Mp4Box; import java.nio.ByteBuffer; import java.util.UUID; @@ -52,13 +53,13 @@ public final class PsshAtomUtil { public static byte[] buildPsshAtom( UUID systemId, @Nullable UUID[] keyIds, @Nullable byte[] data) { int dataLength = data != null ? data.length : 0; - int psshBoxLength = Atom.FULL_HEADER_SIZE + 16 /* SystemId */ + 4 /* DataSize */ + dataLength; + int psshBoxLength = Mp4Box.FULL_HEADER_SIZE + 16 /* SystemId */ + 4 /* DataSize */ + dataLength; if (keyIds != null) { psshBoxLength += 4 /* KID_count */ + (keyIds.length * 16) /* KIDs */; } ByteBuffer psshBox = ByteBuffer.allocate(psshBoxLength); psshBox.putInt(psshBoxLength); - psshBox.putInt(Atom.TYPE_pssh); + psshBox.putInt(Mp4Box.TYPE_pssh); psshBox.putInt(keyIds != null ? 0x01000000 : 0 /* version=(buildV1Atom ? 1 : 0), flags=0 */); psshBox.putLong(systemId.getMostSignificantBits()); psshBox.putLong(systemId.getLeastSignificantBits()); @@ -157,7 +158,7 @@ public final class PsshAtomUtil { @Nullable public static PsshAtom parsePsshAtom(byte[] atom) { ParsableByteArray atomData = new ParsableByteArray(atom); - if (atomData.limit() < Atom.FULL_HEADER_SIZE + 16 /* UUID */ + 4 /* DataSize */) { + if (atomData.limit() < Mp4Box.FULL_HEADER_SIZE + 16 /* UUID */ + 4 /* DataSize */) { // Data too short. return null; } @@ -171,7 +172,7 @@ public final class PsshAtomUtil { return null; } int atomType = atomData.readInt(); - if (atomType != Atom.TYPE_pssh) { + if (atomType != Mp4Box.TYPE_pssh) { Log.w(TAG, "Atom type is not pssh: " + atomType); return null; } diff --git a/libraries/extractor/src/main/java/androidx/media3/extractor/mp4/SmtaAtomUtil.java b/libraries/extractor/src/main/java/androidx/media3/extractor/mp4/SmtaAtomUtil.java index e2493b7c04..d1d8ff8436 100644 --- a/libraries/extractor/src/main/java/androidx/media3/extractor/mp4/SmtaAtomUtil.java +++ b/libraries/extractor/src/main/java/androidx/media3/extractor/mp4/SmtaAtomUtil.java @@ -23,6 +23,7 @@ import androidx.media3.common.C; import androidx.media3.common.Metadata; import androidx.media3.common.util.ParsableByteArray; import androidx.media3.common.util.UnstableApi; +import androidx.media3.container.Mp4Box; import androidx.media3.extractor.metadata.mp4.SmtaMetadataEntry; import java.lang.annotation.Documented; import java.lang.annotation.Retention; @@ -70,12 +71,12 @@ public final class SmtaAtomUtil { /** Parses metadata from a Samsung smta atom. */ @Nullable public static Metadata parseSmta(ParsableByteArray smta, int limit) { - smta.skipBytes(Atom.FULL_HEADER_SIZE); + smta.skipBytes(Mp4Box.FULL_HEADER_SIZE); while (smta.getPosition() < limit) { int atomPosition = smta.getPosition(); int atomSize = smta.readInt(); int atomType = smta.readInt(); - if (atomType == Atom.TYPE_saut) { + if (atomType == Mp4Box.TYPE_saut) { // Size (4), Type (4), Author (4), Recording mode (2), SVC layer count (2). if (atomSize < 16) { return null; @@ -126,13 +127,13 @@ public final class SmtaAtomUtil { return C.RATE_UNSET_INT; } - if (smta.bytesLeft() < Atom.HEADER_SIZE || smta.getPosition() + Atom.HEADER_SIZE > limit) { + if (smta.bytesLeft() < Mp4Box.HEADER_SIZE || smta.getPosition() + Mp4Box.HEADER_SIZE > limit) { return C.RATE_UNSET_INT; } int atomSize = smta.readInt(); int atomType = smta.readInt(); - if (atomSize < 12 || atomType != Atom.TYPE_srfr) { + if (atomSize < 12 || atomType != Mp4Box.TYPE_srfr) { return C.RATE_UNSET_INT; } // Capture frame rate is in Q16 format. diff --git a/libraries/extractor/src/main/java/androidx/media3/extractor/mp4/Sniffer.java b/libraries/extractor/src/main/java/androidx/media3/extractor/mp4/Sniffer.java index cb2c16b948..58f427e0b2 100644 --- a/libraries/extractor/src/main/java/androidx/media3/extractor/mp4/Sniffer.java +++ b/libraries/extractor/src/main/java/androidx/media3/extractor/mp4/Sniffer.java @@ -18,6 +18,7 @@ package androidx.media3.extractor.mp4; import androidx.annotation.Nullable; import androidx.media3.common.C; import androidx.media3.common.util.ParsableByteArray; +import androidx.media3.container.Mp4Box; import androidx.media3.extractor.ExtractorInput; import androidx.media3.extractor.SniffFailure; import java.io.IOException; @@ -118,7 +119,7 @@ import java.io.IOException; boolean isFragmented = false; while (bytesSearched < bytesToSearch) { // Read an atom header. - int headerSize = Atom.HEADER_SIZE; + int headerSize = Mp4Box.HEADER_SIZE; buffer.reset(headerSize); boolean success = input.peekFully(buffer.getData(), 0, headerSize, /* allowEndOfInput= */ true); @@ -128,14 +129,14 @@ import java.io.IOException; } long atomSize = buffer.readUnsignedInt(); int atomType = buffer.readInt(); - if (atomSize == Atom.DEFINES_LARGE_SIZE) { + if (atomSize == Mp4Box.DEFINES_LARGE_SIZE) { // Read the large atom size. - headerSize = Atom.LONG_HEADER_SIZE; + headerSize = Mp4Box.LONG_HEADER_SIZE; input.peekFully( - buffer.getData(), Atom.HEADER_SIZE, Atom.LONG_HEADER_SIZE - Atom.HEADER_SIZE); - buffer.setLimit(Atom.LONG_HEADER_SIZE); + buffer.getData(), Mp4Box.HEADER_SIZE, Mp4Box.LONG_HEADER_SIZE - Mp4Box.HEADER_SIZE); + buffer.setLimit(Mp4Box.LONG_HEADER_SIZE); atomSize = buffer.readLong(); - } else if (atomSize == Atom.EXTENDS_TO_END_SIZE) { + } else if (atomSize == Mp4Box.EXTENDS_TO_END_SIZE) { // The atom extends to the end of the file. long fileEndPosition = input.getLength(); if (fileEndPosition != C.LENGTH_UNSET) { @@ -149,7 +150,7 @@ import java.io.IOException; } bytesSearched += headerSize; - if (atomType == Atom.TYPE_moov) { + if (atomType == Mp4Box.TYPE_moov) { // We have seen the moov atom. We increase the search size to make sure we don't miss an // mvex atom because the moov's size exceeds the search length. bytesToSearch += (int) atomSize; @@ -161,13 +162,13 @@ import java.io.IOException; continue; } - if (atomType == Atom.TYPE_moof || atomType == Atom.TYPE_mvex) { + if (atomType == Mp4Box.TYPE_moof || atomType == Mp4Box.TYPE_mvex) { // The movie is fragmented. Stop searching as we must have read any ftyp atom already. isFragmented = true; break; } - if (atomType == Atom.TYPE_mdat) { + if (atomType == Mp4Box.TYPE_mdat) { // The original QuickTime specification did not require files to begin with the ftyp atom. // See https://developer.apple.com/standards/qtff-2001.pdf. foundGoodFileType = true; @@ -180,7 +181,7 @@ import java.io.IOException; int atomDataSize = (int) (atomSize - headerSize); bytesSearched += atomDataSize; - if (atomType == Atom.TYPE_ftyp) { + if (atomType == Mp4Box.TYPE_ftyp) { // Parse the atom and check the file type/brand is compatible with the extractors. if (atomDataSize < 8) { return new AtomSizeTooSmallSniffFailure(atomType, atomDataSize, 8); diff --git a/libraries/extractor/src/test/java/androidx/media3/extractor/mp4/AtomParsersTest.java b/libraries/extractor/src/test/java/androidx/media3/extractor/mp4/AtomParsersTest.java index 935e957a5f..404e20b196 100644 --- a/libraries/extractor/src/test/java/androidx/media3/extractor/mp4/AtomParsersTest.java +++ b/libraries/extractor/src/test/java/androidx/media3/extractor/mp4/AtomParsersTest.java @@ -21,6 +21,7 @@ import androidx.media3.common.C; import androidx.media3.common.ParserException; import androidx.media3.common.util.ParsableByteArray; import androidx.media3.common.util.Util; +import androidx.media3.container.Mp4Box; import androidx.test.ext.junit.runners.AndroidJUnit4; import org.junit.Test; import org.junit.runner.RunWith; @@ -254,17 +255,18 @@ public final class AtomParsersTest { @Test public void stz2Parsing4BitFieldSize() { - verifyStz2Parsing(new Atom.LeafAtom(Atom.TYPE_stsz, new ParsableByteArray(FOUR_BIT_STZ2))); + verifyStz2Parsing(new Mp4Box.LeafBox(Mp4Box.TYPE_stsz, new ParsableByteArray(FOUR_BIT_STZ2))); } @Test public void stz2Parsing8BitFieldSize() { - verifyStz2Parsing(new Atom.LeafAtom(Atom.TYPE_stsz, new ParsableByteArray(EIGHT_BIT_STZ2))); + verifyStz2Parsing(new Mp4Box.LeafBox(Mp4Box.TYPE_stsz, new ParsableByteArray(EIGHT_BIT_STZ2))); } @Test public void stz2Parsing16BitFieldSize() { - verifyStz2Parsing(new Atom.LeafAtom(Atom.TYPE_stsz, new ParsableByteArray(SIXTEEN_BIT_STZ2))); + verifyStz2Parsing( + new Mp4Box.LeafBox(Mp4Box.TYPE_stsz, new ParsableByteArray(SIXTEEN_BIT_STZ2))); } @Test @@ -286,7 +288,7 @@ public final class AtomParsersTest { assertThat(vexuData.hasBothEyeViews()).isTrue(); } - private static void verifyStz2Parsing(Atom.LeafAtom stz2Atom) { + private static void verifyStz2Parsing(Mp4Box.LeafBox stz2Atom) { AtomParsers.Stz2SampleSizeBox box = new AtomParsers.Stz2SampleSizeBox(stz2Atom); assertThat(box.getSampleCount()).isEqualTo(4); assertThat(box.getFixedSampleSize()).isEqualTo(C.LENGTH_UNSET); diff --git a/libraries/extractor/src/test/java/androidx/media3/extractor/mp4/PsshAtomUtilTest.java b/libraries/extractor/src/test/java/androidx/media3/extractor/mp4/PsshAtomUtilTest.java index f103d9fabe..717158a1a5 100644 --- a/libraries/extractor/src/test/java/androidx/media3/extractor/mp4/PsshAtomUtilTest.java +++ b/libraries/extractor/src/test/java/androidx/media3/extractor/mp4/PsshAtomUtilTest.java @@ -16,7 +16,7 @@ package androidx.media3.extractor.mp4; import static androidx.media3.common.C.WIDEVINE_UUID; -import static androidx.media3.extractor.mp4.Atom.TYPE_pssh; +import static androidx.media3.container.Mp4Box.TYPE_pssh; import static androidx.media3.extractor.mp4.AtomParsers.parseFullAtomFlags; import static androidx.media3.extractor.mp4.AtomParsers.parseFullAtomVersion; import static com.google.common.truth.Truth.assertThat;