From 0b5443c4505452718711b1858b74792444578fcb Mon Sep 17 00:00:00 2001 From: Colin Kho Date: Fri, 9 Aug 2024 15:16:18 -0700 Subject: [PATCH 1/6] Make Extractor/Mp4 Atom Parsing code reusable by external custom mp4 extractors --- .../java/androidx/media3/extractor/mp4/AtomParsers.java | 6 +++--- .../main/java/androidx/media3/extractor/mp4/Sniffer.java | 2 +- .../androidx/media3/extractor/mp4/TrackSampleTable.java | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) 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 2cec2512fb..887d318406 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 @@ -62,7 +62,7 @@ import java.util.Objects; /** Utility methods for parsing MP4 format atom payloads according to ISO/IEC 14496-12. */ @SuppressWarnings("ConstantField") -/* package */ final class AtomParsers { +public final class AtomParsers { private static final String TAG = "AtomParsers"; @@ -317,7 +317,7 @@ import java.util.Objects; * @throws ParserException Thrown if the trak atom can't be parsed. */ @Nullable - private static Track parseTrak( + public static Track parseTrak( Mp4Box.ContainerBox trak, LeafBox mvhd, long duration, @@ -401,7 +401,7 @@ import java.util.Objects; * @return Sample table described by the stbl atom. * @throws ParserException Thrown if the stbl atom can't be parsed. */ - private static TrackSampleTable parseStbl( + public static TrackSampleTable parseStbl( Track track, Mp4Box.ContainerBox stblAtom, GaplessInfoHolder gaplessInfoHolder) throws ParserException { SampleSizeBox sampleSizeBox; 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 58f427e0b2..0fd3fc41ed 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 @@ -27,7 +27,7 @@ import java.io.IOException; * Provides methods that peek data from an {@link ExtractorInput} and return whether the input * appears to be in MP4 format. */ -/* package */ final class Sniffer { +public final class Sniffer { /** Brand stored in the ftyp atom for QuickTime media. */ public static final int BRAND_QUICKTIME = 0x71742020; diff --git a/libraries/extractor/src/main/java/androidx/media3/extractor/mp4/TrackSampleTable.java b/libraries/extractor/src/main/java/androidx/media3/extractor/mp4/TrackSampleTable.java index 7f2c046865..59b84a8b50 100644 --- a/libraries/extractor/src/main/java/androidx/media3/extractor/mp4/TrackSampleTable.java +++ b/libraries/extractor/src/main/java/androidx/media3/extractor/mp4/TrackSampleTable.java @@ -20,7 +20,7 @@ import androidx.media3.common.util.Assertions; import androidx.media3.common.util.Util; /** Sample table for a track in an MP4 file. */ -/* package */ final class TrackSampleTable { +public final class TrackSampleTable { /** The track corresponding to this sample table. */ public final Track track; From 6ba9c9ff9e10879abfd9d65d684c9ab71d6f2fd6 Mon Sep 17 00:00:00 2001 From: Colin Kho Date: Thu, 15 Aug 2024 10:45:21 -0700 Subject: [PATCH 2/6] Rename AtomParsers to BoxParsers --- .../mp4/{AtomParsers.java => BoxParsers.java} | 4 +-- .../extractor/mp4/FragmentedMp4Extractor.java | 26 +++++++++---------- .../media3/extractor/mp4/MetadataUtil.java | 2 +- .../media3/extractor/mp4/Mp4Extractor.java | 10 +++---- .../media3/extractor/mp4/PsshAtomUtil.java | 2 +- ...omParsersTest.java => BoxParsersTest.java} | 14 +++++----- .../extractor/mp4/PsshAtomUtilTest.java | 4 +-- 7 files changed, 31 insertions(+), 31 deletions(-) rename libraries/extractor/src/main/java/androidx/media3/extractor/mp4/{AtomParsers.java => BoxParsers.java} (99%) rename libraries/extractor/src/test/java/androidx/media3/extractor/mp4/{AtomParsersTest.java => BoxParsersTest.java} (94%) diff --git a/libraries/extractor/src/main/java/androidx/media3/extractor/mp4/AtomParsers.java b/libraries/extractor/src/main/java/androidx/media3/extractor/mp4/BoxParsers.java similarity index 99% rename from libraries/extractor/src/main/java/androidx/media3/extractor/mp4/AtomParsers.java rename to libraries/extractor/src/main/java/androidx/media3/extractor/mp4/BoxParsers.java index 887d318406..c556c7f294 100644 --- a/libraries/extractor/src/main/java/androidx/media3/extractor/mp4/AtomParsers.java +++ b/libraries/extractor/src/main/java/androidx/media3/extractor/mp4/BoxParsers.java @@ -62,7 +62,7 @@ import java.util.Objects; /** Utility methods for parsing MP4 format atom payloads according to ISO/IEC 14496-12. */ @SuppressWarnings("ConstantField") -public final class AtomParsers { +public final class BoxParsers { private static final String TAG = "AtomParsers"; @@ -2274,7 +2274,7 @@ public final class AtomParsers { && editEndTime <= duration; } - private AtomParsers() { + private BoxParsers() { // Prevent instantiation. } 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 39c0be79df..13660ec930 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 @@ -19,7 +19,7 @@ import static androidx.media3.common.util.Assertions.checkNotNull; import static androidx.media3.common.util.Assertions.checkState; import static androidx.media3.common.util.Util.castNonNull; import static androidx.media3.common.util.Util.nullSafeArrayCopy; -import static androidx.media3.extractor.mp4.AtomParsers.parseTraks; +import static androidx.media3.extractor.mp4.BoxParsers.parseTraks; import static java.lang.Math.max; import static java.lang.annotation.ElementType.TYPE_USE; @@ -778,7 +778,7 @@ public class FragmentedMp4Extractor implements Extractor { } atom.setPosition(Mp4Box.HEADER_SIZE); int fullAtom = atom.readInt(); - int version = AtomParsers.parseFullAtomVersion(fullAtom); + int version = BoxParsers.parseFullAtomVersion(fullAtom); String schemeIdUri; String value; long timescale; @@ -884,7 +884,7 @@ public class FragmentedMp4Extractor implements Extractor { private static long parseMehd(ParsableByteArray mehd) { mehd.setPosition(Mp4Box.HEADER_SIZE); int fullAtom = mehd.readInt(); - int version = AtomParsers.parseFullAtomVersion(fullAtom); + int version = BoxParsers.parseFullAtomVersion(fullAtom); return version == 0 ? mehd.readUnsignedInt() : mehd.readUnsignedLongToLong(); } @@ -1006,7 +1006,7 @@ public class FragmentedMp4Extractor implements Extractor { int vectorSize = encryptionBox.perSampleIvSize; saiz.setPosition(Mp4Box.HEADER_SIZE); int fullAtom = saiz.readInt(); - int flags = AtomParsers.parseFullAtomFlags(fullAtom); + int flags = BoxParsers.parseFullAtomFlags(fullAtom); if ((flags & 0x01) == 1) { saiz.skipBytes(8); } @@ -1050,7 +1050,7 @@ public class FragmentedMp4Extractor implements Extractor { private static void parseSaio(ParsableByteArray saio, TrackFragment out) throws ParserException { saio.setPosition(Mp4Box.HEADER_SIZE); int fullAtom = saio.readInt(); - int flags = AtomParsers.parseFullAtomFlags(fullAtom); + int flags = BoxParsers.parseFullAtomFlags(fullAtom); if ((flags & 0x01) == 1) { saio.skipBytes(8); } @@ -1062,7 +1062,7 @@ public class FragmentedMp4Extractor implements Extractor { "Unexpected saio entry count: " + entryCount, /* cause= */ null); } - int version = AtomParsers.parseFullAtomVersion(fullAtom); + int version = BoxParsers.parseFullAtomVersion(fullAtom); out.auxiliaryDataPosition += version == 0 ? saio.readUnsignedInt() : saio.readUnsignedLongToLong(); } @@ -1084,7 +1084,7 @@ public class FragmentedMp4Extractor implements Extractor { ParsableByteArray tfhd, SparseArray trackBundles, boolean haveSideloadedTrack) { tfhd.setPosition(Mp4Box.HEADER_SIZE); int fullAtom = tfhd.readInt(); - int atomFlags = AtomParsers.parseFullAtomFlags(fullAtom); + int atomFlags = BoxParsers.parseFullAtomFlags(fullAtom); int trackId = tfhd.readInt(); @Nullable TrackBundle trackBundle = @@ -1133,7 +1133,7 @@ public class FragmentedMp4Extractor implements Extractor { private static long parseTfdt(ParsableByteArray tfdt) { tfdt.setPosition(Mp4Box.HEADER_SIZE); int fullAtom = tfdt.readInt(); - int version = AtomParsers.parseFullAtomVersion(fullAtom); + int version = BoxParsers.parseFullAtomVersion(fullAtom); return version == 1 ? tfdt.readUnsignedLongToLong() : tfdt.readUnsignedInt(); } @@ -1176,7 +1176,7 @@ public class FragmentedMp4Extractor implements Extractor { throws ParserException { trun.setPosition(Mp4Box.HEADER_SIZE); int fullAtom = trun.readInt(); - int atomFlags = AtomParsers.parseFullAtomFlags(fullAtom); + int atomFlags = BoxParsers.parseFullAtomFlags(fullAtom); Track track = trackBundle.moovSampleTable.track; TrackFragment fragment = trackBundle.fragment; @@ -1287,7 +1287,7 @@ public class FragmentedMp4Extractor implements Extractor { throws ParserException { senc.setPosition(Mp4Box.HEADER_SIZE + offset); int fullAtom = senc.readInt(); - int flags = AtomParsers.parseFullAtomFlags(fullAtom); + int flags = BoxParsers.parseFullAtomFlags(fullAtom); if ((flags & 0x01 /* override_track_encryption_box_parameters */) != 0) { // TODO: Implement this. @@ -1340,7 +1340,7 @@ public class FragmentedMp4Extractor implements Extractor { } sbgp.setPosition(Mp4Box.HEADER_SIZE); - int sbgpVersion = AtomParsers.parseFullAtomVersion(sbgp.readInt()); + int sbgpVersion = BoxParsers.parseFullAtomVersion(sbgp.readInt()); sbgp.skipBytes(4); // grouping_type == seig. if (sbgpVersion == 1) { sbgp.skipBytes(4); // grouping_type_parameter. @@ -1351,7 +1351,7 @@ public class FragmentedMp4Extractor implements Extractor { } sgpd.setPosition(Mp4Box.HEADER_SIZE); - int sgpdVersion = AtomParsers.parseFullAtomVersion(sgpd.readInt()); + int sgpdVersion = BoxParsers.parseFullAtomVersion(sgpd.readInt()); sgpd.skipBytes(4); // grouping_type == seig. if (sgpdVersion == 1) { if (sgpd.readUnsignedInt() == 0) { @@ -1408,7 +1408,7 @@ public class FragmentedMp4Extractor implements Extractor { throws ParserException { atom.setPosition(Mp4Box.HEADER_SIZE); int fullAtom = atom.readInt(); - int version = AtomParsers.parseFullAtomVersion(fullAtom); + int version = BoxParsers.parseFullAtomVersion(fullAtom); atom.skipBytes(4); long timescale = atom.readUnsignedInt(); 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 86eccb1367..bf4b790df5 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 @@ -372,7 +372,7 @@ import com.google.common.collect.ImmutableList; int atomType = data.readInt(); if (atomType == Mp4Box.TYPE_data) { int fullVersionInt = data.readInt(); - int flags = AtomParsers.parseFullAtomFlags(fullVersionInt); + int flags = BoxParsers.parseFullAtomFlags(fullVersionInt); @Nullable String mimeType = flags == 13 ? "image/jpeg" : flags == 14 ? "image/png" : null; if (mimeType == null) { Log.w(TAG, "Unrecognized cover art flags: " + flags); 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 fe64215925..2888a11078 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 @@ -28,7 +28,7 @@ import static androidx.media3.container.Mp4Util.EDITABLE_TRACK_TYPE_DEPTH_INVERS import static androidx.media3.container.Mp4Util.EDITABLE_TRACK_TYPE_DEPTH_LINEAR; import static androidx.media3.container.Mp4Util.EDITABLE_TRACK_TYPE_DEPTH_METADATA; import static androidx.media3.container.Mp4Util.EDITABLE_TRACK_TYPE_SHARP; -import static androidx.media3.extractor.mp4.AtomParsers.parseTraks; +import static androidx.media3.extractor.mp4.BoxParsers.parseTraks; import static androidx.media3.extractor.mp4.MetadataUtil.findMdtaMetadataEntryWithKey; import static androidx.media3.extractor.mp4.Sniffer.BRAND_HEIC; import static androidx.media3.extractor.mp4.Sniffer.BRAND_QUICKTIME; @@ -657,7 +657,7 @@ public final class Mp4Extractor implements Extractor, SeekMap { List<@C.AuxiliaryTrackType Integer> auxiliaryTrackTypesForEditableVideoTracks = new ArrayList<>(); if (meta != null) { - mdtaMetadata = AtomParsers.parseMdtaFromMeta(meta); + mdtaMetadata = BoxParsers.parseMdtaFromMeta(meta); if (readingEditableVideoTracks) { checkStateNotNull(mdtaMetadata); maybeSetDefaultSampleOffsetForEditableVideoTracks(mdtaMetadata); @@ -678,13 +678,13 @@ public final class Mp4Extractor implements Extractor, SeekMap { @Nullable Metadata udtaMetadata = null; @Nullable Mp4Box.LeafBox udta = moov.getLeafBoxOfType(Mp4Box.TYPE_udta); if (udta != null) { - udtaMetadata = AtomParsers.parseUdta(udta); + udtaMetadata = BoxParsers.parseUdta(udta); gaplessInfoHolder.setFromMetadata(udtaMetadata); } Metadata mvhdMetadata = new Metadata( - AtomParsers.parseMvhd(checkNotNull(moov.getLeafBoxOfType(Mp4Box.TYPE_mvhd)).data)); + BoxParsers.parseMvhd(checkNotNull(moov.getLeafBoxOfType(Mp4Box.TYPE_mvhd)).data)); boolean ignoreEditLists = (flags & FLAG_WORKAROUND_IGNORE_EDIT_LISTS) != 0; List trackSampleTables = @@ -1056,7 +1056,7 @@ public final class Mp4Extractor implements Extractor, SeekMap { private void maybeSkipRemainingMetaAtomHeaderBytes(ExtractorInput input) throws IOException { scratch.reset(8); input.peekFully(scratch.getData(), 0, 8); - AtomParsers.maybeSkipRemainingMetaAtomHeaderBytes(scratch); + BoxParsers.maybeSkipRemainingMetaAtomHeaderBytes(scratch); input.skipFully(scratch.getPosition()); input.resetPeekPosition(); } 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 748822e295..87c23edad6 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 @@ -176,7 +176,7 @@ public final class PsshAtomUtil { Log.w(TAG, "Atom type is not pssh: " + atomType); return null; } - int atomVersion = AtomParsers.parseFullAtomVersion(atomData.readInt()); + int atomVersion = BoxParsers.parseFullAtomVersion(atomData.readInt()); if (atomVersion > 1) { Log.w(TAG, "Unsupported pssh version: " + atomVersion); return null; diff --git a/libraries/extractor/src/test/java/androidx/media3/extractor/mp4/AtomParsersTest.java b/libraries/extractor/src/test/java/androidx/media3/extractor/mp4/BoxParsersTest.java similarity index 94% rename from libraries/extractor/src/test/java/androidx/media3/extractor/mp4/AtomParsersTest.java rename to libraries/extractor/src/test/java/androidx/media3/extractor/mp4/BoxParsersTest.java index 404e20b196..023d2c08be 100644 --- a/libraries/extractor/src/test/java/androidx/media3/extractor/mp4/AtomParsersTest.java +++ b/libraries/extractor/src/test/java/androidx/media3/extractor/mp4/BoxParsersTest.java @@ -26,9 +26,9 @@ import androidx.test.ext.junit.runners.AndroidJUnit4; import org.junit.Test; import org.junit.runner.RunWith; -/** Tests for {@link AtomParsers}. */ +/** Tests for {@link BoxParsers}. */ @RunWith(AndroidJUnit4.class) -public final class AtomParsersTest { +public final class BoxParsersTest { private static final String ATOM_HEADER = "000000000000000000000000"; private static final String SAMPLE_COUNT = "00000004"; @@ -248,7 +248,7 @@ public final class AtomParsersTest { 0, 0, 0, 0, 88, 88, 88, 88 }; // version (1), flags (3), 'xxxx' (4) assertThat( - AtomParsers.parseCommonEncryptionSinfFromParent( + BoxParsers.parseCommonEncryptionSinfFromParent( new ParsableByteArray(cencSinf), 0, cencSinf.length)) .isNull(); } @@ -271,17 +271,17 @@ public final class AtomParsersTest { @Test public void vexuParsings() throws ParserException { - AtomParsers.VexuData vexuData = null; + BoxParsers.VexuData vexuData = null; assertThat( vexuData = - AtomParsers.parseVideoExtendedUsageBox( + BoxParsers.parseVideoExtendedUsageBox( new ParsableByteArray(VEXU_DATA0), 0, VEXU_DATA0.length)) .isNotNull(); assertThat(vexuData).isNotNull(); assertThat(vexuData.hasBothEyeViews()).isTrue(); assertThat( vexuData = - AtomParsers.parseVideoExtendedUsageBox( + BoxParsers.parseVideoExtendedUsageBox( new ParsableByteArray(VEXU_DATA1), 0, VEXU_DATA1.length)) .isNotNull(); assertThat(vexuData).isNotNull(); @@ -289,7 +289,7 @@ public final class AtomParsersTest { } private static void verifyStz2Parsing(Mp4Box.LeafBox stz2Atom) { - AtomParsers.Stz2SampleSizeBox box = new AtomParsers.Stz2SampleSizeBox(stz2Atom); + BoxParsers.Stz2SampleSizeBox box = new BoxParsers.Stz2SampleSizeBox(stz2Atom); assertThat(box.getSampleCount()).isEqualTo(4); assertThat(box.getFixedSampleSize()).isEqualTo(C.LENGTH_UNSET); for (int i = 0; i < box.getSampleCount(); i++) { 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 717158a1a5..2d857556a4 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 @@ -17,8 +17,8 @@ package androidx.media3.extractor.mp4; import static androidx.media3.common.C.WIDEVINE_UUID; 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 androidx.media3.extractor.mp4.BoxParsers.parseFullAtomFlags; +import static androidx.media3.extractor.mp4.BoxParsers.parseFullAtomVersion; import static com.google.common.truth.Truth.assertThat; import androidx.media3.common.C; From 3a95b24afcc48a471f50bba81ff29112f8b87f73 Mon Sep 17 00:00:00 2001 From: Colin Kho Date: Thu, 15 Aug 2024 12:31:37 -0700 Subject: [PATCH 3/6] Rename BoxParsers tag from AtomParsers to BoxParsers --- .../src/main/java/androidx/media3/extractor/mp4/BoxParsers.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/extractor/src/main/java/androidx/media3/extractor/mp4/BoxParsers.java b/libraries/extractor/src/main/java/androidx/media3/extractor/mp4/BoxParsers.java index c556c7f294..4bf7d6c796 100644 --- a/libraries/extractor/src/main/java/androidx/media3/extractor/mp4/BoxParsers.java +++ b/libraries/extractor/src/main/java/androidx/media3/extractor/mp4/BoxParsers.java @@ -64,7 +64,7 @@ import java.util.Objects; @SuppressWarnings("ConstantField") public final class BoxParsers { - private static final String TAG = "AtomParsers"; + private static final String TAG = "BoxParsers"; @SuppressWarnings("ConstantCaseForConstants") private static final int TYPE_clcp = 0x636c6370; From 2dd6794ba05b88ba924fb3471e44fa7e6f7f5185 Mon Sep 17 00:00:00 2001 From: Ian Baker Date: Fri, 16 Aug 2024 14:04:21 +0100 Subject: [PATCH 4/6] More atom -> box updates in public API surface --- .../media3/extractor/mp4/BoxParsers.java | 98 +++++++++---------- .../extractor/mp4/FragmentedMp4Extractor.java | 24 ++--- .../media3/extractor/mp4/MetadataUtil.java | 2 +- .../media3/extractor/mp4/Mp4Extractor.java | 2 +- .../media3/extractor/mp4/PsshAtomUtil.java | 2 +- .../extractor/mp4/PsshAtomUtilTest.java | 12 +-- 6 files changed, 70 insertions(+), 70 deletions(-) diff --git a/libraries/extractor/src/main/java/androidx/media3/extractor/mp4/BoxParsers.java b/libraries/extractor/src/main/java/androidx/media3/extractor/mp4/BoxParsers.java index 4bf7d6c796..d0790b86be 100644 --- a/libraries/extractor/src/main/java/androidx/media3/extractor/mp4/BoxParsers.java +++ b/libraries/extractor/src/main/java/androidx/media3/extractor/mp4/BoxParsers.java @@ -60,7 +60,7 @@ import java.util.Arrays; import java.util.List; import java.util.Objects; -/** Utility methods for parsing MP4 format atom payloads according to ISO/IEC 14496-12. */ +/** Utility methods for parsing MP4 format box payloads according to ISO/IEC 14496-12. */ @SuppressWarnings("ConstantField") public final class BoxParsers { @@ -105,29 +105,29 @@ public final class BoxParsers { /** The magic signature for an Opus Identification header, as defined in RFC-7845. */ private static final byte[] opusMagic = Util.getUtf8Bytes("OpusHead"); - /** Parses the version number out of the additional integer component of a full atom. */ - public static int parseFullAtomVersion(int fullAtomInt) { - return 0x000000FF & (fullAtomInt >> 24); + /** Parses the version number out of the additional integer component of a full box. */ + public static int parseFullBoxVersion(int fullBoxInt) { + return 0x000000FF & (fullBoxInt >> 24); } - /** Parses the atom flags out of the additional integer component of a full atom. */ - public static int parseFullAtomFlags(int fullAtomInt) { - return 0x00FFFFFF & fullAtomInt; + /** Parses the box flags out of the additional integer component of a full box. */ + public static int parseFullBoxFlags(int fullBoxInt) { + return 0x00FFFFFF & fullBoxInt; } /** - * Parse the trak atoms in a moov atom (defined in ISO/IEC 14496-12). + * Parse the trak boxes in a moov box (defined in ISO/IEC 14496-12). * - * @param moov Moov atom to decode. + * @param moov Moov box to decode. * @param gaplessInfoHolder Holder to populate with gapless playback information. - * @param duration The duration in units of the timescale declared in the mvhd atom, or {@link - * C#TIME_UNSET} if the duration should be parsed from the tkhd atom. + * @param duration The duration in units of the timescale declared in the mvhd box, or {@link + * C#TIME_UNSET} if the duration should be parsed from the tkhd box. * @param drmInitData {@link DrmInitData} to be included in the format, or {@code null}. * @param ignoreEditLists Whether to ignore any edit lists in the trak boxes. * @param isQuickTime True for QuickTime media. False otherwise. * @param modifyTrackFunction A function to apply to the {@link Track Tracks} in the result. * @return A list of {@link TrackSampleTable} instances. - * @throws ParserException Thrown if the trak atoms can't be parsed. + * @throws ParserException Thrown if the trak boxes can't be parsed. */ public static List parseTraks( Mp4Box.ContainerBox moov, @@ -170,13 +170,13 @@ public final class BoxParsers { } /** - * Parses a udta atom. + * Parses a udta box. * - * @param udtaAtom The udta (user data) atom to decode. + * @param udtaBox The udta (user data) box to decode. * @return Parsed metadata. */ - public static Metadata parseUdta(LeafBox udtaAtom) { - ParsableByteArray udtaData = udtaAtom.data; + public static Metadata parseUdta(LeafBox udtaBox) { + ParsableByteArray udtaData = udtaBox.data; udtaData.setPosition(Mp4Box.HEADER_SIZE); Metadata metadata = new Metadata(); while (udtaData.bytesLeft() >= Mp4Box.HEADER_SIZE) { @@ -201,15 +201,15 @@ public final class BoxParsers { } /** - * Parses an mvhd atom (defined in ISO/IEC 14496-12). + * Parses an mvhd box (defined in ISO/IEC 14496-12). * - * @param mvhd Contents of the mvhd atom to be parsed. + * @param mvhd Contents of the mvhd box to be parsed. * @return An object containing the parsed data. */ public static Mp4TimestampData parseMvhd(ParsableByteArray mvhd) { mvhd.setPosition(Mp4Box.HEADER_SIZE); int fullAtom = mvhd.readInt(); - int version = parseFullAtomVersion(fullAtom); + int version = parseFullBoxVersion(fullAtom); long creationTimestampSeconds; long modificationTimestampSeconds; if (version == 0) { @@ -225,9 +225,9 @@ public final class BoxParsers { } /** - * Parses a metadata meta atom if it contains metadata with handler 'mdta'. + * Parses a metadata meta box if it contains metadata with handler 'mdta'. * - * @param meta The metadata atom to decode. + * @param meta The metadata box to decode. * @return Parsed metadata, or null. */ @Nullable @@ -280,17 +280,17 @@ public final class BoxParsers { } /** - * Possibly skips the version and flags fields (1+3 byte) of a full meta atom. + * Possibly skips the version and flags fields (1+3 byte) of a full meta box. * - *

Atoms of type {@link Mp4Box#TYPE_meta} are defined to be full atoms which have four + *

Boxes of type {@link Mp4Box#TYPE_meta} are defined to be full boxes 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. + * @param meta The 8 or more bytes following the meta box size and type. */ - public static void maybeSkipRemainingMetaAtomHeaderBytes(ParsableByteArray meta) { + public static void maybeSkipRemainingMetaBoxHeaderBytes(ParsableByteArray meta) { int endPosition = meta.getPosition(); // The next 8 bytes can be either: // (iso) [1 byte version + 3 bytes flags][4 byte size of next atom] @@ -304,17 +304,17 @@ public final class BoxParsers { } /** - * Parses a trak atom (defined in ISO/IEC 14496-12). + * Parses a trak box (defined in ISO/IEC 14496-12). * - * @param trak Atom to decode. - * @param mvhd Movie header atom, used to get the timescale. - * @param duration The duration in units of the timescale declared in the mvhd atom, or {@link - * C#TIME_UNSET} if the duration should be parsed from the tkhd atom. + * @param trak Box to decode. + * @param mvhd Movie header box, used to get the timescale. + * @param duration The duration in units of the timescale declared in the mvhd box, or {@link + * C#TIME_UNSET} if the duration should be parsed from the tkhd box. * @param drmInitData {@link DrmInitData} to be included in the format, or {@code null}. * @param ignoreEditLists Whether to ignore any edit lists in the trak box. * @param isQuickTime True for QuickTime media. False otherwise. * @return A {@link Track} instance, or {@code null} if the track's type isn't supported. - * @throws ParserException Thrown if the trak atom can't be parsed. + * @throws ParserException Thrown if the trak box can't be parsed. */ @Nullable public static Track parseTrak( @@ -393,23 +393,23 @@ public final class BoxParsers { } /** - * Parses an stbl atom (defined in ISO/IEC 14496-12). + * Parses an stbl box (defined in ISO/IEC 14496-12). * * @param track Track to which this sample table corresponds. - * @param stblAtom stbl (sample table) atom to decode. + * @param stblBox stbl (sample table) box to decode. * @param gaplessInfoHolder Holder to populate with gapless playback information. - * @return Sample table described by the stbl atom. - * @throws ParserException Thrown if the stbl atom can't be parsed. + * @return Sample table described by the stbl box. + * @throws ParserException Thrown if the stbl box can't be parsed. */ public static TrackSampleTable parseStbl( - Track track, Mp4Box.ContainerBox stblAtom, GaplessInfoHolder gaplessInfoHolder) + Track track, Mp4Box.ContainerBox stblBox, GaplessInfoHolder gaplessInfoHolder) throws ParserException { SampleSizeBox sampleSizeBox; - @Nullable LeafBox stszAtom = stblAtom.getLeafBoxOfType(Mp4Box.TYPE_stsz); + @Nullable LeafBox stszAtom = stblBox.getLeafBoxOfType(Mp4Box.TYPE_stsz); if (stszAtom != null) { sampleSizeBox = new StszSampleSizeBox(stszAtom, track.format); } else { - @Nullable LeafBox stz2Atom = stblAtom.getLeafBoxOfType(Mp4Box.TYPE_stz2); + @Nullable LeafBox stz2Atom = stblBox.getLeafBoxOfType(Mp4Box.TYPE_stz2); if (stz2Atom == null) { throw ParserException.createForMalformedContainer( "Track has no sample table size information", /* cause= */ null); @@ -431,21 +431,21 @@ public final class BoxParsers { // Entries are byte offsets of chunks. boolean chunkOffsetsAreLongs = false; - @Nullable LeafBox chunkOffsetsAtom = stblAtom.getLeafBoxOfType(Mp4Box.TYPE_stco); + @Nullable LeafBox chunkOffsetsAtom = stblBox.getLeafBoxOfType(Mp4Box.TYPE_stco); if (chunkOffsetsAtom == null) { chunkOffsetsAreLongs = true; - chunkOffsetsAtom = checkNotNull(stblAtom.getLeafBoxOfType(Mp4Box.TYPE_co64)); + chunkOffsetsAtom = checkNotNull(stblBox.getLeafBoxOfType(Mp4Box.TYPE_co64)); } ParsableByteArray chunkOffsets = chunkOffsetsAtom.data; // Entries are (chunk number, number of samples per chunk, sample description index). - ParsableByteArray stsc = checkNotNull(stblAtom.getLeafBoxOfType(Mp4Box.TYPE_stsc)).data; + ParsableByteArray stsc = checkNotNull(stblBox.getLeafBoxOfType(Mp4Box.TYPE_stsc)).data; // Entries are (number of samples, timestamp delta between those samples). - ParsableByteArray stts = checkNotNull(stblAtom.getLeafBoxOfType(Mp4Box.TYPE_stts)).data; + ParsableByteArray stts = checkNotNull(stblBox.getLeafBoxOfType(Mp4Box.TYPE_stts)).data; // Entries are the indices of samples that are synchronization samples. - @Nullable LeafBox stssAtom = stblAtom.getLeafBoxOfType(Mp4Box.TYPE_stss); + @Nullable LeafBox stssAtom = stblBox.getLeafBoxOfType(Mp4Box.TYPE_stss); @Nullable ParsableByteArray stss = stssAtom != null ? stssAtom.data : null; // Entries are (number of samples, timestamp offset). - @Nullable LeafBox cttsAtom = stblAtom.getLeafBoxOfType(Mp4Box.TYPE_ctts); + @Nullable LeafBox cttsAtom = stblBox.getLeafBoxOfType(Mp4Box.TYPE_ctts); @Nullable ParsableByteArray ctts = cttsAtom != null ? cttsAtom.data : null; // Prepare to read chunk information. @@ -794,7 +794,7 @@ public final class BoxParsers { @Nullable private static Metadata parseUdtaMeta(ParsableByteArray meta, int limit) { meta.skipBytes(Mp4Box.HEADER_SIZE); - maybeSkipRemainingMetaAtomHeaderBytes(meta); + maybeSkipRemainingMetaBoxHeaderBytes(meta); while (meta.getPosition() < limit) { int atomPosition = meta.getPosition(); int atomSize = meta.readInt(); @@ -851,7 +851,7 @@ public final class BoxParsers { private static TkhdData parseTkhd(ParsableByteArray tkhd) { tkhd.setPosition(Mp4Box.HEADER_SIZE); int fullAtom = tkhd.readInt(); - int version = parseFullAtomVersion(fullAtom); + int version = parseFullBoxVersion(fullAtom); tkhd.skipBytes(version == 0 ? 8 : 16); int trackId = tkhd.readInt(); @@ -938,7 +938,7 @@ public final class BoxParsers { private static Pair parseMdhd(ParsableByteArray mdhd) { mdhd.setPosition(Mp4Box.HEADER_SIZE); int fullAtom = mdhd.readInt(); - int version = parseFullAtomVersion(fullAtom); + int version = parseFullBoxVersion(fullAtom); mdhd.skipBytes(version == 0 ? 8 : 16); long timescale = mdhd.readUnsignedInt(); mdhd.skipBytes(version == 0 ? 4 : 8); @@ -1647,7 +1647,7 @@ public final class BoxParsers { ParsableByteArray elstData = elstAtom.data; elstData.setPosition(Mp4Box.HEADER_SIZE); int fullAtom = elstData.readInt(); - int version = parseFullAtomVersion(fullAtom); + int version = parseFullBoxVersion(fullAtom); int entryCount = elstData.readUnsignedIntToInt(); long[] editListDurations = new long[entryCount]; long[] editListMediaTimes = new long[entryCount]; @@ -2199,7 +2199,7 @@ public final class BoxParsers { int childAtomType = parent.readInt(); if (childAtomType == Mp4Box.TYPE_tenc) { int fullAtom = parent.readInt(); - int version = parseFullAtomVersion(fullAtom); + int version = parseFullBoxVersion(fullAtom); parent.skipBytes(1); // reserved = 0. int defaultCryptByteBlock = 0; int defaultSkipByteBlock = 0; 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 13660ec930..a4b25cbcdd 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 @@ -778,7 +778,7 @@ public class FragmentedMp4Extractor implements Extractor { } atom.setPosition(Mp4Box.HEADER_SIZE); int fullAtom = atom.readInt(); - int version = BoxParsers.parseFullAtomVersion(fullAtom); + int version = BoxParsers.parseFullBoxVersion(fullAtom); String schemeIdUri; String value; long timescale; @@ -884,7 +884,7 @@ public class FragmentedMp4Extractor implements Extractor { private static long parseMehd(ParsableByteArray mehd) { mehd.setPosition(Mp4Box.HEADER_SIZE); int fullAtom = mehd.readInt(); - int version = BoxParsers.parseFullAtomVersion(fullAtom); + int version = BoxParsers.parseFullBoxVersion(fullAtom); return version == 0 ? mehd.readUnsignedInt() : mehd.readUnsignedLongToLong(); } @@ -1006,7 +1006,7 @@ public class FragmentedMp4Extractor implements Extractor { int vectorSize = encryptionBox.perSampleIvSize; saiz.setPosition(Mp4Box.HEADER_SIZE); int fullAtom = saiz.readInt(); - int flags = BoxParsers.parseFullAtomFlags(fullAtom); + int flags = BoxParsers.parseFullBoxFlags(fullAtom); if ((flags & 0x01) == 1) { saiz.skipBytes(8); } @@ -1050,7 +1050,7 @@ public class FragmentedMp4Extractor implements Extractor { private static void parseSaio(ParsableByteArray saio, TrackFragment out) throws ParserException { saio.setPosition(Mp4Box.HEADER_SIZE); int fullAtom = saio.readInt(); - int flags = BoxParsers.parseFullAtomFlags(fullAtom); + int flags = BoxParsers.parseFullBoxFlags(fullAtom); if ((flags & 0x01) == 1) { saio.skipBytes(8); } @@ -1062,7 +1062,7 @@ public class FragmentedMp4Extractor implements Extractor { "Unexpected saio entry count: " + entryCount, /* cause= */ null); } - int version = BoxParsers.parseFullAtomVersion(fullAtom); + int version = BoxParsers.parseFullBoxVersion(fullAtom); out.auxiliaryDataPosition += version == 0 ? saio.readUnsignedInt() : saio.readUnsignedLongToLong(); } @@ -1084,7 +1084,7 @@ public class FragmentedMp4Extractor implements Extractor { ParsableByteArray tfhd, SparseArray trackBundles, boolean haveSideloadedTrack) { tfhd.setPosition(Mp4Box.HEADER_SIZE); int fullAtom = tfhd.readInt(); - int atomFlags = BoxParsers.parseFullAtomFlags(fullAtom); + int atomFlags = BoxParsers.parseFullBoxFlags(fullAtom); int trackId = tfhd.readInt(); @Nullable TrackBundle trackBundle = @@ -1133,7 +1133,7 @@ public class FragmentedMp4Extractor implements Extractor { private static long parseTfdt(ParsableByteArray tfdt) { tfdt.setPosition(Mp4Box.HEADER_SIZE); int fullAtom = tfdt.readInt(); - int version = BoxParsers.parseFullAtomVersion(fullAtom); + int version = BoxParsers.parseFullBoxVersion(fullAtom); return version == 1 ? tfdt.readUnsignedLongToLong() : tfdt.readUnsignedInt(); } @@ -1176,7 +1176,7 @@ public class FragmentedMp4Extractor implements Extractor { throws ParserException { trun.setPosition(Mp4Box.HEADER_SIZE); int fullAtom = trun.readInt(); - int atomFlags = BoxParsers.parseFullAtomFlags(fullAtom); + int atomFlags = BoxParsers.parseFullBoxFlags(fullAtom); Track track = trackBundle.moovSampleTable.track; TrackFragment fragment = trackBundle.fragment; @@ -1287,7 +1287,7 @@ public class FragmentedMp4Extractor implements Extractor { throws ParserException { senc.setPosition(Mp4Box.HEADER_SIZE + offset); int fullAtom = senc.readInt(); - int flags = BoxParsers.parseFullAtomFlags(fullAtom); + int flags = BoxParsers.parseFullBoxFlags(fullAtom); if ((flags & 0x01 /* override_track_encryption_box_parameters */) != 0) { // TODO: Implement this. @@ -1340,7 +1340,7 @@ public class FragmentedMp4Extractor implements Extractor { } sbgp.setPosition(Mp4Box.HEADER_SIZE); - int sbgpVersion = BoxParsers.parseFullAtomVersion(sbgp.readInt()); + int sbgpVersion = BoxParsers.parseFullBoxVersion(sbgp.readInt()); sbgp.skipBytes(4); // grouping_type == seig. if (sbgpVersion == 1) { sbgp.skipBytes(4); // grouping_type_parameter. @@ -1351,7 +1351,7 @@ public class FragmentedMp4Extractor implements Extractor { } sgpd.setPosition(Mp4Box.HEADER_SIZE); - int sgpdVersion = BoxParsers.parseFullAtomVersion(sgpd.readInt()); + int sgpdVersion = BoxParsers.parseFullBoxVersion(sgpd.readInt()); sgpd.skipBytes(4); // grouping_type == seig. if (sgpdVersion == 1) { if (sgpd.readUnsignedInt() == 0) { @@ -1408,7 +1408,7 @@ public class FragmentedMp4Extractor implements Extractor { throws ParserException { atom.setPosition(Mp4Box.HEADER_SIZE); int fullAtom = atom.readInt(); - int version = BoxParsers.parseFullAtomVersion(fullAtom); + int version = BoxParsers.parseFullBoxVersion(fullAtom); atom.skipBytes(4); long timescale = atom.readUnsignedInt(); 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 bf4b790df5..ac024aa5af 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 @@ -372,7 +372,7 @@ import com.google.common.collect.ImmutableList; int atomType = data.readInt(); if (atomType == Mp4Box.TYPE_data) { int fullVersionInt = data.readInt(); - int flags = BoxParsers.parseFullAtomFlags(fullVersionInt); + int flags = BoxParsers.parseFullBoxFlags(fullVersionInt); @Nullable String mimeType = flags == 13 ? "image/jpeg" : flags == 14 ? "image/png" : null; if (mimeType == null) { Log.w(TAG, "Unrecognized cover art flags: " + flags); 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 2888a11078..ca0836378a 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 @@ -1056,7 +1056,7 @@ public final class Mp4Extractor implements Extractor, SeekMap { private void maybeSkipRemainingMetaAtomHeaderBytes(ExtractorInput input) throws IOException { scratch.reset(8); input.peekFully(scratch.getData(), 0, 8); - BoxParsers.maybeSkipRemainingMetaAtomHeaderBytes(scratch); + BoxParsers.maybeSkipRemainingMetaBoxHeaderBytes(scratch); input.skipFully(scratch.getPosition()); input.resetPeekPosition(); } 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 87c23edad6..00157ff533 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 @@ -176,7 +176,7 @@ public final class PsshAtomUtil { Log.w(TAG, "Atom type is not pssh: " + atomType); return null; } - int atomVersion = BoxParsers.parseFullAtomVersion(atomData.readInt()); + int atomVersion = BoxParsers.parseFullBoxVersion(atomData.readInt()); if (atomVersion > 1) { Log.w(TAG, "Unsupported pssh version: " + atomVersion); return null; 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 2d857556a4..a46adfabee 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 @@ -17,8 +17,8 @@ package androidx.media3.extractor.mp4; import static androidx.media3.common.C.WIDEVINE_UUID; import static androidx.media3.container.Mp4Box.TYPE_pssh; -import static androidx.media3.extractor.mp4.BoxParsers.parseFullAtomFlags; -import static androidx.media3.extractor.mp4.BoxParsers.parseFullAtomVersion; +import static androidx.media3.extractor.mp4.BoxParsers.parseFullBoxFlags; +import static androidx.media3.extractor.mp4.BoxParsers.parseFullBoxVersion; import static com.google.common.truth.Truth.assertThat; import androidx.media3.common.C; @@ -42,8 +42,8 @@ public final class PsshAtomUtilTest { assertThat(parsablePsshAtom.readUnsignedIntToInt()).isEqualTo(psshAtom.length); // length assertThat(parsablePsshAtom.readInt()).isEqualTo(TYPE_pssh); // type int fullAtomInt = parsablePsshAtom.readInt(); // version + flags - assertThat(parseFullAtomVersion(fullAtomInt)).isEqualTo(0); - assertThat(parseFullAtomFlags(fullAtomInt)).isEqualTo(0); + assertThat(parseFullBoxVersion(fullAtomInt)).isEqualTo(0); + assertThat(parseFullBoxFlags(fullAtomInt)).isEqualTo(0); UUID systemId = new UUID(parsablePsshAtom.readLong(), parsablePsshAtom.readLong()); assertThat(systemId).isEqualTo(WIDEVINE_UUID); assertThat(parsablePsshAtom.readUnsignedIntToInt()).isEqualTo(schemeData.length); @@ -65,8 +65,8 @@ public final class PsshAtomUtilTest { assertThat(parsablePsshAtom.readUnsignedIntToInt()).isEqualTo(psshAtom.length); assertThat(parsablePsshAtom.readInt()).isEqualTo(TYPE_pssh); // type int fullAtomInt = parsablePsshAtom.readInt(); // version + flags - assertThat(parseFullAtomVersion(fullAtomInt)).isEqualTo(1); - assertThat(parseFullAtomFlags(fullAtomInt)).isEqualTo(0); + assertThat(parseFullBoxVersion(fullAtomInt)).isEqualTo(1); + assertThat(parseFullBoxFlags(fullAtomInt)).isEqualTo(0); UUID systemId = new UUID(parsablePsshAtom.readLong(), parsablePsshAtom.readLong()); assertThat(systemId).isEqualTo(WIDEVINE_UUID); assertThat(parsablePsshAtom.readUnsignedIntToInt()).isEqualTo(2); From 77f3ef9b25c60b226fa3f04ca78d8cfa7616aa57 Mon Sep 17 00:00:00 2001 From: Ian Baker Date: Fri, 16 Aug 2024 14:47:38 +0100 Subject: [PATCH 5/6] Add @UnstableApi annotation --- .../src/main/java/androidx/media3/extractor/mp4/BoxParsers.java | 2 ++ .../src/main/java/androidx/media3/extractor/mp4/Sniffer.java | 2 ++ .../java/androidx/media3/extractor/mp4/TrackSampleTable.java | 2 ++ 3 files changed, 6 insertions(+) diff --git a/libraries/extractor/src/main/java/androidx/media3/extractor/mp4/BoxParsers.java b/libraries/extractor/src/main/java/androidx/media3/extractor/mp4/BoxParsers.java index d0790b86be..029fb299b7 100644 --- a/libraries/extractor/src/main/java/androidx/media3/extractor/mp4/BoxParsers.java +++ b/libraries/extractor/src/main/java/androidx/media3/extractor/mp4/BoxParsers.java @@ -34,6 +34,7 @@ import androidx.media3.common.util.Log; import androidx.media3.common.util.NullableType; import androidx.media3.common.util.ParsableBitArray; import androidx.media3.common.util.ParsableByteArray; +import androidx.media3.common.util.UnstableApi; import androidx.media3.common.util.Util; import androidx.media3.container.Mp4Box; import androidx.media3.container.Mp4Box.LeafBox; @@ -62,6 +63,7 @@ import java.util.Objects; /** Utility methods for parsing MP4 format box payloads according to ISO/IEC 14496-12. */ @SuppressWarnings("ConstantField") +@UnstableApi public final class BoxParsers { private static final String TAG = "BoxParsers"; 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 0fd3fc41ed..fa7ff35bd3 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.common.util.UnstableApi; import androidx.media3.container.Mp4Box; import androidx.media3.extractor.ExtractorInput; import androidx.media3.extractor.SniffFailure; @@ -27,6 +28,7 @@ import java.io.IOException; * Provides methods that peek data from an {@link ExtractorInput} and return whether the input * appears to be in MP4 format. */ +@UnstableApi public final class Sniffer { /** Brand stored in the ftyp atom for QuickTime media. */ diff --git a/libraries/extractor/src/main/java/androidx/media3/extractor/mp4/TrackSampleTable.java b/libraries/extractor/src/main/java/androidx/media3/extractor/mp4/TrackSampleTable.java index 59b84a8b50..15c73b8e65 100644 --- a/libraries/extractor/src/main/java/androidx/media3/extractor/mp4/TrackSampleTable.java +++ b/libraries/extractor/src/main/java/androidx/media3/extractor/mp4/TrackSampleTable.java @@ -17,9 +17,11 @@ package androidx.media3.extractor.mp4; import androidx.media3.common.C; import androidx.media3.common.util.Assertions; +import androidx.media3.common.util.UnstableApi; import androidx.media3.common.util.Util; /** Sample table for a track in an MP4 file. */ +@UnstableApi public final class TrackSampleTable { /** The track corresponding to this sample table. */ From 2e49e91c84fdce4b3ee50cead179df7378f6584a Mon Sep 17 00:00:00 2001 From: Ian Baker Date: Tue, 20 Aug 2024 11:11:14 +0100 Subject: [PATCH 6/6] Rename to singular BoxParser for consistency with other types like ColorParser --- .../mp4/{BoxParsers.java => BoxParser.java} | 4 +-- .../extractor/mp4/FragmentedMp4Extractor.java | 26 +++++++++---------- .../media3/extractor/mp4/MetadataUtil.java | 2 +- .../media3/extractor/mp4/Mp4Extractor.java | 10 +++---- .../media3/extractor/mp4/PsshAtomUtil.java | 2 +- ...BoxParsersTest.java => BoxParserTest.java} | 14 +++++----- .../extractor/mp4/PsshAtomUtilTest.java | 4 +-- 7 files changed, 31 insertions(+), 31 deletions(-) rename libraries/extractor/src/main/java/androidx/media3/extractor/mp4/{BoxParsers.java => BoxParser.java} (99%) rename libraries/extractor/src/test/java/androidx/media3/extractor/mp4/{BoxParsersTest.java => BoxParserTest.java} (94%) diff --git a/libraries/extractor/src/main/java/androidx/media3/extractor/mp4/BoxParsers.java b/libraries/extractor/src/main/java/androidx/media3/extractor/mp4/BoxParser.java similarity index 99% rename from libraries/extractor/src/main/java/androidx/media3/extractor/mp4/BoxParsers.java rename to libraries/extractor/src/main/java/androidx/media3/extractor/mp4/BoxParser.java index 029fb299b7..a4eb4b5adb 100644 --- a/libraries/extractor/src/main/java/androidx/media3/extractor/mp4/BoxParsers.java +++ b/libraries/extractor/src/main/java/androidx/media3/extractor/mp4/BoxParser.java @@ -64,7 +64,7 @@ import java.util.Objects; /** Utility methods for parsing MP4 format box payloads according to ISO/IEC 14496-12. */ @SuppressWarnings("ConstantField") @UnstableApi -public final class BoxParsers { +public final class BoxParser { private static final String TAG = "BoxParsers"; @@ -2276,7 +2276,7 @@ public final class BoxParsers { && editEndTime <= duration; } - private BoxParsers() { + private BoxParser() { // Prevent instantiation. } 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 a4b25cbcdd..3a556970ba 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 @@ -19,7 +19,7 @@ import static androidx.media3.common.util.Assertions.checkNotNull; import static androidx.media3.common.util.Assertions.checkState; import static androidx.media3.common.util.Util.castNonNull; import static androidx.media3.common.util.Util.nullSafeArrayCopy; -import static androidx.media3.extractor.mp4.BoxParsers.parseTraks; +import static androidx.media3.extractor.mp4.BoxParser.parseTraks; import static java.lang.Math.max; import static java.lang.annotation.ElementType.TYPE_USE; @@ -778,7 +778,7 @@ public class FragmentedMp4Extractor implements Extractor { } atom.setPosition(Mp4Box.HEADER_SIZE); int fullAtom = atom.readInt(); - int version = BoxParsers.parseFullBoxVersion(fullAtom); + int version = BoxParser.parseFullBoxVersion(fullAtom); String schemeIdUri; String value; long timescale; @@ -884,7 +884,7 @@ public class FragmentedMp4Extractor implements Extractor { private static long parseMehd(ParsableByteArray mehd) { mehd.setPosition(Mp4Box.HEADER_SIZE); int fullAtom = mehd.readInt(); - int version = BoxParsers.parseFullBoxVersion(fullAtom); + int version = BoxParser.parseFullBoxVersion(fullAtom); return version == 0 ? mehd.readUnsignedInt() : mehd.readUnsignedLongToLong(); } @@ -1006,7 +1006,7 @@ public class FragmentedMp4Extractor implements Extractor { int vectorSize = encryptionBox.perSampleIvSize; saiz.setPosition(Mp4Box.HEADER_SIZE); int fullAtom = saiz.readInt(); - int flags = BoxParsers.parseFullBoxFlags(fullAtom); + int flags = BoxParser.parseFullBoxFlags(fullAtom); if ((flags & 0x01) == 1) { saiz.skipBytes(8); } @@ -1050,7 +1050,7 @@ public class FragmentedMp4Extractor implements Extractor { private static void parseSaio(ParsableByteArray saio, TrackFragment out) throws ParserException { saio.setPosition(Mp4Box.HEADER_SIZE); int fullAtom = saio.readInt(); - int flags = BoxParsers.parseFullBoxFlags(fullAtom); + int flags = BoxParser.parseFullBoxFlags(fullAtom); if ((flags & 0x01) == 1) { saio.skipBytes(8); } @@ -1062,7 +1062,7 @@ public class FragmentedMp4Extractor implements Extractor { "Unexpected saio entry count: " + entryCount, /* cause= */ null); } - int version = BoxParsers.parseFullBoxVersion(fullAtom); + int version = BoxParser.parseFullBoxVersion(fullAtom); out.auxiliaryDataPosition += version == 0 ? saio.readUnsignedInt() : saio.readUnsignedLongToLong(); } @@ -1084,7 +1084,7 @@ public class FragmentedMp4Extractor implements Extractor { ParsableByteArray tfhd, SparseArray trackBundles, boolean haveSideloadedTrack) { tfhd.setPosition(Mp4Box.HEADER_SIZE); int fullAtom = tfhd.readInt(); - int atomFlags = BoxParsers.parseFullBoxFlags(fullAtom); + int atomFlags = BoxParser.parseFullBoxFlags(fullAtom); int trackId = tfhd.readInt(); @Nullable TrackBundle trackBundle = @@ -1133,7 +1133,7 @@ public class FragmentedMp4Extractor implements Extractor { private static long parseTfdt(ParsableByteArray tfdt) { tfdt.setPosition(Mp4Box.HEADER_SIZE); int fullAtom = tfdt.readInt(); - int version = BoxParsers.parseFullBoxVersion(fullAtom); + int version = BoxParser.parseFullBoxVersion(fullAtom); return version == 1 ? tfdt.readUnsignedLongToLong() : tfdt.readUnsignedInt(); } @@ -1176,7 +1176,7 @@ public class FragmentedMp4Extractor implements Extractor { throws ParserException { trun.setPosition(Mp4Box.HEADER_SIZE); int fullAtom = trun.readInt(); - int atomFlags = BoxParsers.parseFullBoxFlags(fullAtom); + int atomFlags = BoxParser.parseFullBoxFlags(fullAtom); Track track = trackBundle.moovSampleTable.track; TrackFragment fragment = trackBundle.fragment; @@ -1287,7 +1287,7 @@ public class FragmentedMp4Extractor implements Extractor { throws ParserException { senc.setPosition(Mp4Box.HEADER_SIZE + offset); int fullAtom = senc.readInt(); - int flags = BoxParsers.parseFullBoxFlags(fullAtom); + int flags = BoxParser.parseFullBoxFlags(fullAtom); if ((flags & 0x01 /* override_track_encryption_box_parameters */) != 0) { // TODO: Implement this. @@ -1340,7 +1340,7 @@ public class FragmentedMp4Extractor implements Extractor { } sbgp.setPosition(Mp4Box.HEADER_SIZE); - int sbgpVersion = BoxParsers.parseFullBoxVersion(sbgp.readInt()); + int sbgpVersion = BoxParser.parseFullBoxVersion(sbgp.readInt()); sbgp.skipBytes(4); // grouping_type == seig. if (sbgpVersion == 1) { sbgp.skipBytes(4); // grouping_type_parameter. @@ -1351,7 +1351,7 @@ public class FragmentedMp4Extractor implements Extractor { } sgpd.setPosition(Mp4Box.HEADER_SIZE); - int sgpdVersion = BoxParsers.parseFullBoxVersion(sgpd.readInt()); + int sgpdVersion = BoxParser.parseFullBoxVersion(sgpd.readInt()); sgpd.skipBytes(4); // grouping_type == seig. if (sgpdVersion == 1) { if (sgpd.readUnsignedInt() == 0) { @@ -1408,7 +1408,7 @@ public class FragmentedMp4Extractor implements Extractor { throws ParserException { atom.setPosition(Mp4Box.HEADER_SIZE); int fullAtom = atom.readInt(); - int version = BoxParsers.parseFullBoxVersion(fullAtom); + int version = BoxParser.parseFullBoxVersion(fullAtom); atom.skipBytes(4); long timescale = atom.readUnsignedInt(); 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 ac024aa5af..9d3f13bb66 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 @@ -372,7 +372,7 @@ import com.google.common.collect.ImmutableList; int atomType = data.readInt(); if (atomType == Mp4Box.TYPE_data) { int fullVersionInt = data.readInt(); - int flags = BoxParsers.parseFullBoxFlags(fullVersionInt); + int flags = BoxParser.parseFullBoxFlags(fullVersionInt); @Nullable String mimeType = flags == 13 ? "image/jpeg" : flags == 14 ? "image/png" : null; if (mimeType == null) { Log.w(TAG, "Unrecognized cover art flags: " + flags); 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 ca0836378a..3593c4cba9 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 @@ -28,7 +28,7 @@ import static androidx.media3.container.Mp4Util.EDITABLE_TRACK_TYPE_DEPTH_INVERS import static androidx.media3.container.Mp4Util.EDITABLE_TRACK_TYPE_DEPTH_LINEAR; import static androidx.media3.container.Mp4Util.EDITABLE_TRACK_TYPE_DEPTH_METADATA; import static androidx.media3.container.Mp4Util.EDITABLE_TRACK_TYPE_SHARP; -import static androidx.media3.extractor.mp4.BoxParsers.parseTraks; +import static androidx.media3.extractor.mp4.BoxParser.parseTraks; import static androidx.media3.extractor.mp4.MetadataUtil.findMdtaMetadataEntryWithKey; import static androidx.media3.extractor.mp4.Sniffer.BRAND_HEIC; import static androidx.media3.extractor.mp4.Sniffer.BRAND_QUICKTIME; @@ -657,7 +657,7 @@ public final class Mp4Extractor implements Extractor, SeekMap { List<@C.AuxiliaryTrackType Integer> auxiliaryTrackTypesForEditableVideoTracks = new ArrayList<>(); if (meta != null) { - mdtaMetadata = BoxParsers.parseMdtaFromMeta(meta); + mdtaMetadata = BoxParser.parseMdtaFromMeta(meta); if (readingEditableVideoTracks) { checkStateNotNull(mdtaMetadata); maybeSetDefaultSampleOffsetForEditableVideoTracks(mdtaMetadata); @@ -678,13 +678,13 @@ public final class Mp4Extractor implements Extractor, SeekMap { @Nullable Metadata udtaMetadata = null; @Nullable Mp4Box.LeafBox udta = moov.getLeafBoxOfType(Mp4Box.TYPE_udta); if (udta != null) { - udtaMetadata = BoxParsers.parseUdta(udta); + udtaMetadata = BoxParser.parseUdta(udta); gaplessInfoHolder.setFromMetadata(udtaMetadata); } Metadata mvhdMetadata = new Metadata( - BoxParsers.parseMvhd(checkNotNull(moov.getLeafBoxOfType(Mp4Box.TYPE_mvhd)).data)); + BoxParser.parseMvhd(checkNotNull(moov.getLeafBoxOfType(Mp4Box.TYPE_mvhd)).data)); boolean ignoreEditLists = (flags & FLAG_WORKAROUND_IGNORE_EDIT_LISTS) != 0; List trackSampleTables = @@ -1056,7 +1056,7 @@ public final class Mp4Extractor implements Extractor, SeekMap { private void maybeSkipRemainingMetaAtomHeaderBytes(ExtractorInput input) throws IOException { scratch.reset(8); input.peekFully(scratch.getData(), 0, 8); - BoxParsers.maybeSkipRemainingMetaBoxHeaderBytes(scratch); + BoxParser.maybeSkipRemainingMetaBoxHeaderBytes(scratch); input.skipFully(scratch.getPosition()); input.resetPeekPosition(); } 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 00157ff533..fc4f24ce67 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 @@ -176,7 +176,7 @@ public final class PsshAtomUtil { Log.w(TAG, "Atom type is not pssh: " + atomType); return null; } - int atomVersion = BoxParsers.parseFullBoxVersion(atomData.readInt()); + int atomVersion = BoxParser.parseFullBoxVersion(atomData.readInt()); if (atomVersion > 1) { Log.w(TAG, "Unsupported pssh version: " + atomVersion); return null; diff --git a/libraries/extractor/src/test/java/androidx/media3/extractor/mp4/BoxParsersTest.java b/libraries/extractor/src/test/java/androidx/media3/extractor/mp4/BoxParserTest.java similarity index 94% rename from libraries/extractor/src/test/java/androidx/media3/extractor/mp4/BoxParsersTest.java rename to libraries/extractor/src/test/java/androidx/media3/extractor/mp4/BoxParserTest.java index 023d2c08be..5a0c694058 100644 --- a/libraries/extractor/src/test/java/androidx/media3/extractor/mp4/BoxParsersTest.java +++ b/libraries/extractor/src/test/java/androidx/media3/extractor/mp4/BoxParserTest.java @@ -26,9 +26,9 @@ import androidx.test.ext.junit.runners.AndroidJUnit4; import org.junit.Test; import org.junit.runner.RunWith; -/** Tests for {@link BoxParsers}. */ +/** Tests for {@link BoxParser}. */ @RunWith(AndroidJUnit4.class) -public final class BoxParsersTest { +public final class BoxParserTest { private static final String ATOM_HEADER = "000000000000000000000000"; private static final String SAMPLE_COUNT = "00000004"; @@ -248,7 +248,7 @@ public final class BoxParsersTest { 0, 0, 0, 0, 88, 88, 88, 88 }; // version (1), flags (3), 'xxxx' (4) assertThat( - BoxParsers.parseCommonEncryptionSinfFromParent( + BoxParser.parseCommonEncryptionSinfFromParent( new ParsableByteArray(cencSinf), 0, cencSinf.length)) .isNull(); } @@ -271,17 +271,17 @@ public final class BoxParsersTest { @Test public void vexuParsings() throws ParserException { - BoxParsers.VexuData vexuData = null; + BoxParser.VexuData vexuData = null; assertThat( vexuData = - BoxParsers.parseVideoExtendedUsageBox( + BoxParser.parseVideoExtendedUsageBox( new ParsableByteArray(VEXU_DATA0), 0, VEXU_DATA0.length)) .isNotNull(); assertThat(vexuData).isNotNull(); assertThat(vexuData.hasBothEyeViews()).isTrue(); assertThat( vexuData = - BoxParsers.parseVideoExtendedUsageBox( + BoxParser.parseVideoExtendedUsageBox( new ParsableByteArray(VEXU_DATA1), 0, VEXU_DATA1.length)) .isNotNull(); assertThat(vexuData).isNotNull(); @@ -289,7 +289,7 @@ public final class BoxParsersTest { } private static void verifyStz2Parsing(Mp4Box.LeafBox stz2Atom) { - BoxParsers.Stz2SampleSizeBox box = new BoxParsers.Stz2SampleSizeBox(stz2Atom); + BoxParser.Stz2SampleSizeBox box = new BoxParser.Stz2SampleSizeBox(stz2Atom); assertThat(box.getSampleCount()).isEqualTo(4); assertThat(box.getFixedSampleSize()).isEqualTo(C.LENGTH_UNSET); for (int i = 0; i < box.getSampleCount(); i++) { 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 a46adfabee..593151607e 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 @@ -17,8 +17,8 @@ package androidx.media3.extractor.mp4; import static androidx.media3.common.C.WIDEVINE_UUID; import static androidx.media3.container.Mp4Box.TYPE_pssh; -import static androidx.media3.extractor.mp4.BoxParsers.parseFullBoxFlags; -import static androidx.media3.extractor.mp4.BoxParsers.parseFullBoxVersion; +import static androidx.media3.extractor.mp4.BoxParser.parseFullBoxFlags; +import static androidx.media3.extractor.mp4.BoxParser.parseFullBoxVersion; import static com.google.common.truth.Truth.assertThat; import androidx.media3.common.C;