diff --git a/libraries/extractor/src/main/java/androidx/media3/extractor/MpeghUtil.java b/libraries/extractor/src/main/java/androidx/media3/extractor/MpeghUtil.java index 8992dafde1..c1b9a099c8 100644 --- a/libraries/extractor/src/main/java/androidx/media3/extractor/MpeghUtil.java +++ b/libraries/extractor/src/main/java/androidx/media3/extractor/MpeghUtil.java @@ -24,6 +24,8 @@ import static java.lang.annotation.ElementType.TYPE_USE; import androidx.annotation.IntDef; import androidx.annotation.Nullable; +import androidx.media3.common.C; +import androidx.media3.common.Format; import androidx.media3.common.util.ParsableBitArray; import androidx.media3.common.util.ParsableByteArray; import androidx.media3.common.util.UnstableApi; @@ -33,13 +35,12 @@ import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; import java.util.Arrays; -import org.checkerframework.checker.nullness.qual.NonNull; /** Utility methods for parsing MPEG-H frames, which are access units in MPEG-H bitstreams. */ @UnstableApi public final class MpeghUtil { - /** See ISO_IEC_23003-3;2020, 6.1.1.1, Table 72 */ + /** See ISO_IEC_23003-3;2020, 6.1.1.1, Table 72. */ private static final int[] SAMPLING_RATE_TABLE = new int[]{ 96000, 88200, 64000, 48000, 44100, 32000, 24000, 22050, 16000, 12000, 11025, 8000, 7350, @@ -47,24 +48,31 @@ public final class MpeghUtil { 9600, 0, 0, 0, 0 }; - /** See ISO_IEC_23003-3;2020, 6.1.1.1, Table 75 */ + /** See ISO_IEC_23003-3;2020, 6.1.1.1, Table 75. */ private static final int[] OUTPUT_FRAMELENGTH_TABLE = new int[]{ 768, 1024, 2048, 2048, 4096, 0, 0, 0 }; - /** See ISO_IEC_23003-3;2020, 6.1.1.1, Table 75 */ + /** See ISO_IEC_23003-3;2020, 6.1.1.1, Table 75. */ private static final int[] SBR_RATIO_INDEX_TABLE = new int[]{ 0, 0, 2, 3, 1 }; + /** See ISO_IEC_23003-8;2022, 14.4.4. */ private static final int MHAS_SYNCPACKET = 0xC001A5; /** - * Enumeration of the MHAS packet types. - * See ISO_IEC_23008-3;2022, 14.3.1, Table 226 + * MHAS packet types. See ISO_IEC_23008-3;2022, 14.3.1, Table 226. + * One of {@link #PACTYP_FILLDATA}, {@link #PACTYP_MPEGH3DACFG}, {@link #PACTYP_MPEGH3DAFRAME}, + * {@link #PACTYP_AUDIOSCENEINFO}, {@link #PACTYP_SYNC}, {@link #PACTYP_SYNCGAP}, + * {@link #PACTYP_MARKER}, {@link #PACTYP_CRC16}, {@link #PACTYP_CRC32}, + * {@link #PACTYP_DESCRIPTOR}, {@link #PACTYP_USERINTERACTION}, {@link #PACTYP_LOUDNESS_DRC}, + * {@link #PACTYP_BUFFERINFO}, {@link #PACTYP_GLOBAL_CRC16}, {@link #PACTYP_GLOBAL_CRC32}, + * {@link #PACTYP_AUDIOTRUNCATION}, {@link #PACTYP_GENDATA}, {@link #PACTYPE_EARCON}, + * {@link #PACTYPE_PCMCONFIG}, {@link #PACTYPE_PCMDATA}, {@link #PACTYP_LOUDNESS}. */ @Documented @Retention(RetentionPolicy.SOURCE) @@ -117,35 +125,48 @@ public final class MpeghUtil { private static final int PACTYP_LOUDNESS = 22; + /** + * Represents the parsing state. One of {@link #STATE_END_OUTPUT}, + * {@link #STATE_PARSE_ERROR}, {@link #STATE_SUBSTREAM_UNSUPPORTED}. + */ @Documented @Retention(RetentionPolicy.SOURCE) @Target(TYPE_USE) @IntDef({ - END_OUTPUT, - PARSE_ERROR, - SUBSTREAM_UNSUPPORTED + STATE_END_OUTPUT, + STATE_PARSE_ERROR, + STATE_SUBSTREAM_UNSUPPORTED }) - private @interface ParseState {} + private @interface State {} - private static final int END_OUTPUT = 0; - private static final int PARSE_ERROR = 1; - private static final int SUBSTREAM_UNSUPPORTED = 2; + private static final int STATE_END_OUTPUT = 0; + private static final int STATE_PARSE_ERROR = 1; + private static final int STATE_SUBSTREAM_UNSUPPORTED = 2; public static class FrameInfo { - public boolean containsConfig = false; - public boolean configChanged = false; - public int standardFrameSamples = 0; - public int samplingRate = 0; - public int frameSamples = 0; - public int frameBytes = 0; - public long mainStreamLabel = -1; + public boolean containsConfig; + public boolean configChanged; + public int standardFrameSamples; + public int samplingRate; + public int frameSamples; + public int frameBytes; + public long mainStreamLabel; - public int mpegh3daProfileLevelIndication = -1; - public byte[] compatibleSetIndication = new byte[0]; + public int mpegh3daProfileLevelIndication; + public byte[] compatibleSetIndication; public FrameInfo() { + this.containsConfig = false; + this.configChanged = false; + this.standardFrameSamples = Format.NO_VALUE; + this.samplingRate = Format.NO_VALUE; + this.frameSamples = Format.NO_VALUE; + this.frameBytes = Format.NO_VALUE; + this.mainStreamLabel = Format.NO_VALUE; + this.mpegh3daProfileLevelIndication = Format.NO_VALUE; + this.compatibleSetIndication = new byte[0]; } public FrameInfo(boolean containsConfig, boolean configChanged, int standardFrameSamples, @@ -168,24 +189,24 @@ public final class MpeghUtil { public void reset() { containsConfig = false; configChanged = false; - standardFrameSamples = 0; - samplingRate = 0; - frameBytes = 0; - frameSamples = 0; - mainStreamLabel = -1; - mpegh3daProfileLevelIndication = -1; + standardFrameSamples = Format.NO_VALUE; + samplingRate = Format.NO_VALUE; + frameBytes = Format.NO_VALUE; + frameSamples = Format.NO_VALUE; + mainStreamLabel = Format.NO_VALUE; + mpegh3daProfileLevelIndication = Format.NO_VALUE; compatibleSetIndication = new byte[0]; } } /** - * This function is used to check if the provided number of bits is available in the bit array. + * Validates that the provided number of bits is available in the bit array. * * @param data The byte array to parse. * @param numBits The number of bits to check for. - * @throws ParseException If not enough bits are available. + * @throws {@link ParseException} if not enough bits are available. */ - public static void checkBitsAvailable(ParsableBitArray data, int numBits) + public static void validateBitsAvailability(ParsableBitArray data, int numBits) throws ParseException { if (data.bitsLeft() < numBits) { throw ParseException.createForNotEnoughData(); @@ -193,15 +214,15 @@ public final class MpeghUtil { } /** - * This function is used to find the start position of the MHAS sync packet in the provided data - * buffer. See ISO_IEC_23008-3;2022, 14.4.4 + * Finds the start position of the MHAS sync packet in the provided data buffer. + * See ISO_IEC_23008-3;2022, 14.4.4. * * @param data The byte array to parse. - * @return byte position in data of the MHAS sync packet on success, negative value on failure. + * @return Byte index in data of the MHAS sync packet on success, {@link C#INDEX_UNSET} on failure. */ public static int findSyncPacket(ParsableByteArray data) { int startPos = data.getPosition(); - int syncPacketBytePos = -1; + int syncPacketBytePos = C.INDEX_UNSET; while (data.bytesLeft() >= 3) { int syncword = data.readUnsignedInt24(); if (syncword == MHAS_SYNCPACKET) { @@ -216,8 +237,8 @@ public final class MpeghUtil { } /** - * This function is used to check if a complete MHAS frame could be parsed by calculating if - * enough data is available in the provided ParsableBitArray. + * Checks if a complete MHAS frame could be parsed by calculating if enough data is available + * in the provided ParsableBitArray. * * @param data The bit array to parse. * @return Whether a complete MHAS frame could be parsed. @@ -262,12 +283,12 @@ public final class MpeghUtil { } /** - * This function is used to parse an MHAS packet header. - * See ISO_IEC_23008-3;2022, 14.2.1, Table 222 + * Parses an MHAS packet header. + * See ISO_IEC_23008-3;2022, 14.2.1, Table 222. * * @param data The bit array to parse. * @return MHASPacketHeader The MHAS packet header info. - * @throws ParseException If parsing failed, i.e. there is not enough data available. + * @throws {@link ParseException} if parsing failed, i.e. there is not enough data available. */ private static MHASPacketHeader parseMhasPacketHeader(ParsableBitArray data) throws ParseException { @MHASPacketType int packetType = (int) readEscapedValue(data, 3, 8, 8); @@ -277,14 +298,14 @@ public final class MpeghUtil { } /** - * This function is used to parse one MPEG-H frame into the FrameInfo structure. + * Parses the necessary info of an MPEG-H frame into the FrameInfo structure. * * @param data The bit array to parse, positioned at the start of the MHAS frame. * @param prevFrameInfo A previously obtained FrameInfo. * @return FrameInfo of the current frame. - * @throws ParseException If parsing failed. + * @throws {@link ParseException} if parsing failed. */ - public static FrameInfo parseFrame(ParsableBitArray data, @NonNull FrameInfo prevFrameInfo) + public static FrameInfo parseFrame(ParsableBitArray data, FrameInfo prevFrameInfo) throws ParseException { int nBitsIns; int standardFrameSamples = prevFrameInfo.standardFrameSamples; @@ -293,8 +314,8 @@ public final class MpeghUtil { boolean configFound = false; boolean configChanged = false; int truncationSamples = 0; - long mainStreamLabel = -1; - int mpegh3daProfileLevelIndication = -1; + long mainStreamLabel = Format.NO_VALUE; + int mpegh3daProfileLevelIndication = Format.NO_VALUE; byte[] compatibleSetIndication = new byte[0]; nBitsIns = data.bitsLeft(); @@ -315,7 +336,7 @@ public final class MpeghUtil { } // check if the complete packet could be parsed - checkBitsAvailable(data, packetHeader.packetLength * 8); + validateBitsAvailability(data, packetHeader.packetLength * 8); int dataPos = data.getPosition(); switch (packetHeader.packetType) { @@ -416,21 +437,21 @@ public final class MpeghUtil { } /** - * This function is used to obtain the sampling rate of the current MPEG-H frame. + * Obtains the sampling rate of the current MPEG-H frame. * * @param data The bit array holding the bits to be parsed. * @return The sampling frequency. - * @throws ParseException If sampling frequency could not be obtained. + * @throws {@link ParseException} if sampling frequency could not be obtained. */ public static int getSamplingFrequency(ParsableBitArray data) throws ParseException { int sampleRate; int idx; - checkBitsAvailable(data, 5); + validateBitsAvailability(data, 5); idx = data.readBits(5); if (idx == 0x1F) { - checkBitsAvailable(data, 24); + validateBitsAvailability(data, 24); sampleRate = data.readBits(24); } else { sampleRate = SAMPLING_RATE_TABLE[idx]; @@ -439,31 +460,31 @@ public final class MpeghUtil { } /** - * This function is used to obtain an escaped value from an MPEG-H bit stream. - * See ISO_IEC_23003-3;2020, 5.2, Table 19 + * Obtains an escaped value from an MPEG-H bit stream. + * See ISO_IEC_23003-3;2020, 5.2, Table 19. * * @param data The bit array to be parsed. * @param bits1 number of bits to be parsed. * @param bits2 number of bits to be parsed. * @param bits3 number of bits to be parsed. * @return The escaped value. - * @throws ParseException If parsing failed. + * @throws {@link ParseException} if parsing failed. */ public static long readEscapedValue(ParsableBitArray data, int bits1, int bits2, int bits3) throws ParseException { long value; long valueAdd; - checkBitsAvailable(data, bits1); + validateBitsAvailability(data, bits1); value = data.readBitsToLong(bits1); if (value == (1L << bits1) - 1) { - checkBitsAvailable(data, bits2); + validateBitsAvailability(data, bits2); valueAdd = data.readBitsToLong(bits2); value += valueAdd; if (valueAdd == (1L << bits2) - 1) { - checkBitsAvailable(data, bits3); + validateBitsAvailability(data, bits3); valueAdd = data.readBitsToLong(bits3); value += valueAdd; } @@ -473,29 +494,37 @@ public final class MpeghUtil { private static class Mpegh3daConfig { - int mpegh3daProfileLevelIndication = 0; - int samplingFrequency = 0; - int standardFrameSamples = 0; + int mpegh3daProfileLevelIndication; + int samplingFrequency; + int standardFrameSamples; @Nullable - byte[] compatibleProfileLevelSet = null; + byte[] compatibleProfileLevelSet; + + private Mpegh3daConfig() { + this.mpegh3daProfileLevelIndication = Format.NO_VALUE; + this.samplingFrequency = Format.NO_VALUE; + this.standardFrameSamples = Format.NO_VALUE; + this.compatibleProfileLevelSet = null; + } } + /** - * This function is used to obtain the necessary info of the Mpegh3daConfig from an MPEG-H bit - * stream. See ISO_IEC_23008-3;2022, 5.2.2.1, Table 15 + * Obtains the necessary info of the Mpegh3daConfig from an MPEG-H bit stream. + * See ISO_IEC_23008-3;2022, 5.2.2.1, Table 15. * * @param data The bit array to be parsed. * @return The Mpegh3daConfig. - * @throws ParseException If parsing failed. + * @throws {@link ParseException} if parsing failed. */ private static Mpegh3daConfig parseMpegh3daConfig(ParsableBitArray data) throws ParseException { Mpegh3daConfig mpegh3daConfig = new Mpegh3daConfig(); - checkBitsAvailable(data, 8); + validateBitsAvailability(data, 8); mpegh3daConfig.mpegh3daProfileLevelIndication = data.readBits(8); int usacSamplingFrequency = getSamplingFrequency(data); - checkBitsAvailable(data, 5); + validateBitsAvailability(data, 5); int coreSbrFrameLengthIndex = data.readBits(3); data.skipBits(2); // cfg_reserved(1), receiverDelayCompensation(1) @@ -506,7 +535,7 @@ public final class MpeghUtil { int numSignals = parseSignals3d(data); // frameworkConfig3d parseMpegh3daDecoderConfig(data, numSignals, sbrRatioIndex); // decoderConfig - checkBitsAvailable(data, 1); + validateBitsAvailability(data, 1); if (data.readBit()) { // usacConfigExtensionPresent // Mpegh3daConfigExtension int numConfigExtensions = (int) readEscapedValue(data, 2, 4, 8) + 1; @@ -515,16 +544,16 @@ public final class MpeghUtil { int usacConfigExtLength = (int) readEscapedValue(data, 4, 8, 16); if (usacConfigExtType == 7 /*ID_CONFIG_EXT_COMPATIBLE_PROFILELVL_SET*/) { - checkBitsAvailable(data, 8); + validateBitsAvailability(data, 8); int numCompatibleSets = data.readBits(4) + 1; data.skipBits(4); // reserved mpegh3daConfig.compatibleProfileLevelSet = new byte[numCompatibleSets]; for (int idx = 0; idx < numCompatibleSets; idx++) { - checkBitsAvailable(data, 8); + validateBitsAvailability(data, 8); mpegh3daConfig.compatibleProfileLevelSet[idx] = (byte) data.readBits(8); } } else { - checkBitsAvailable(data, 8 * usacConfigExtLength); + validateBitsAvailability(data, 8 * usacConfigExtLength); data.skipBits(8 * usacConfigExtLength); } } @@ -566,16 +595,16 @@ public final class MpeghUtil { /** - * This function is used to obtain the number of truncated samples of the AudioTruncationInfo from - * an MPEG-H bit stream. See ISO_IEC_23008-3;2022, 14.2.2, Table 225 + * Obtains the number of truncated samples of the AudioTruncationInfo from an MPEG-H bit stream. + * See ISO_IEC_23008-3;2022, 14.2.2, Table 225. * * @param data The bit array to be parsed. * @return The number of truncated samples. - * @throws ParseException If parsing failed. + * @throws {@link ParseException} if parsing failed. */ private static int parseAudioTruncationInfo(ParsableBitArray data) throws ParseException { int truncationSamples = 0; - checkBitsAvailable(data, 16); + validateBitsAvailability(data, 16); boolean isActive = data.readBit(); data.skipBits(2); // reserved(1), truncFromBegin(1) int trunc = data.readBits(13); @@ -587,26 +616,26 @@ public final class MpeghUtil { /** - * This function is used to parse the SpeakerConfig3d from an MPEG-H bit stream. - * See ISO_IEC_23008-3;2022, 5.2.2.2, Table 18 + * Parses the SpeakerConfig3d from an MPEG-H bit stream. + * See ISO_IEC_23008-3;2022, 5.2.2.2, Table 18. * * @param data The bit array to be parsed. - * @throws ParseException If parsing failed. + * @throws {@link ParseException} if parsing failed. */ private static void parseSpeakerConfig3d(ParsableBitArray data) throws ParseException { - checkBitsAvailable(data, 2); + validateBitsAvailability(data, 2); int speakerLayoutType = data.readBits(2); if (speakerLayoutType == 0) { - checkBitsAvailable(data, 6); + validateBitsAvailability(data, 6); data.skipBits(6); // cicpSpeakerLayoutIdx } else { int numSpeakers = (int) readEscapedValue(data, 5, 8, 16) + 1; if (speakerLayoutType == 1) { - checkBitsAvailable(data, 7 * numSpeakers); + validateBitsAvailability(data, 7 * numSpeakers); data.skipBits(7 * numSpeakers); // cicpSpeakerIdx per speaker } if (speakerLayoutType == 2) { - checkBitsAvailable(data, 1); + validateBitsAvailability(data, 1); boolean angularPrecision = data.readBit(); int angularPrecisionDegrees = angularPrecision ? 1 : 5; int elevationAngleBits = angularPrecision ? 7 : 5; @@ -615,35 +644,35 @@ public final class MpeghUtil { // Mpegh3daSpeakerDescription array for (int i = 0; i < numSpeakers; i++) { int azimuthAngle = 0; - checkBitsAvailable(data, 1); + validateBitsAvailability(data, 1); if (data.readBit()) { // isCICPspeakerIdx - checkBitsAvailable(data, 7); + validateBitsAvailability(data, 7); data.skipBits(7); // cicpSpeakerIdx } else { - checkBitsAvailable(data, 2); + validateBitsAvailability(data, 2); int elevationClass = data.readBits(2); if (elevationClass == 3) { - checkBitsAvailable(data, elevationAngleBits); + validateBitsAvailability(data, elevationAngleBits); int elevationAngleIdx = data.readBits(elevationAngleBits); int elevationAngle = elevationAngleIdx * angularPrecisionDegrees; if (elevationAngle != 0) { - checkBitsAvailable(data, 1); + validateBitsAvailability(data, 1); data.skipBit(); // elevationDirection } } - checkBitsAvailable(data, azimuthAngleBits); + validateBitsAvailability(data, azimuthAngleBits); int azimuthAngleIdx = data.readBits(azimuthAngleBits); azimuthAngle = azimuthAngleIdx * angularPrecisionDegrees; if ((azimuthAngle != 0) && (azimuthAngle != 180)) { - checkBitsAvailable(data, 1); + validateBitsAvailability(data, 1); data.skipBit(); // azimuthDirection } - checkBitsAvailable(data, 1); + validateBitsAvailability(data, 1); data.skipBit(); // isLFE } if ((azimuthAngle != 0) && (azimuthAngle != 180)) { - checkBitsAvailable(data, 1); + validateBitsAvailability(data, 1); if (data.readBit()) { // alsoAddSymmetricPair i++; } @@ -654,28 +683,28 @@ public final class MpeghUtil { } /** - * This function is used to obtain the necessary info of Signals3d from an MPEG-H bit stream. - * See ISO_IEC_23008-3;2022, 5.2.2.1, Table 17 + * Obtains the necessary info of Signals3d from an MPEG-H bit stream. + * See ISO_IEC_23008-3;2022, 5.2.2.1, Table 17. * * @param data The bit array to be parsed. * @return The number of overall signals in the bit stream. - * @throws ParseException If parsing failed. + * @throws {@link ParseException} if parsing failed. */ private static int parseSignals3d(ParsableBitArray data) throws ParseException { int numSignals = 0; - checkBitsAvailable(data, 5); + validateBitsAvailability(data, 5); int bsNumSignalGroups = data.readBits(5); for (int grp = 0; grp < bsNumSignalGroups + 1; grp++) { - checkBitsAvailable(data, 3); + validateBitsAvailability(data, 3); int signalGroupType = data.readBits(3); int bsNumberOfSignals = (int) readEscapedValue(data, 5, 8, 16); numSignals += bsNumberOfSignals + 1; if (signalGroupType == 0 /*SignalGroupTypeChannels*/ || signalGroupType == 2 /*SignalGroupTypeSAOC*/) { - checkBitsAvailable(data, 1); + validateBitsAvailability(data, 1); if (data.readBit()) { // differsFromReferenceLayout OR saocDmxLayoutPresent parseSpeakerConfig3d(data); // audioChannelLayout[grp] OR saocDmxChannelLayout } @@ -685,24 +714,24 @@ public final class MpeghUtil { } /** - * This function is used to parse the Mpegh3daDecoderConfig from an MPEG-H bit stream. - * See ISO_IEC_23008-3;2022, 5.2.2.3, Table 21 + * Parses the Mpegh3daDecoderConfig from an MPEG-H bit stream. + * See ISO_IEC_23008-3;2022, 5.2.2.3, Table 21. * * @param data The bit array to be parsed. * @param numSignals The number of overall signals. * @param sbrRatioIndex The SBR ration index. - * @throws ParseException If parsing failed. + * @throws {@link ParseException} if parsing failed. */ private static void parseMpegh3daDecoderConfig(ParsableBitArray data, int numSignals, int sbrRatioIndex) throws ParseException { int numElements = (int) readEscapedValue(data, 4, 8, 16) + 1; - checkBitsAvailable(data, 1); + validateBitsAvailability(data, 1); data.skipBit(); // elementLengthPresent for (int elemIdx = 0; elemIdx < numElements; elemIdx++) { - checkBitsAvailable(data, 2); + validateBitsAvailability(data, 2); int usacElementType = data.readBits(2); switch (usacElementType) { @@ -715,53 +744,53 @@ public final class MpeghUtil { case 1 /*ID_USAC_CPE*/: boolean enhancedNoiseFilling = parseMpegh3daCoreConfig(data); // coreConfig if (enhancedNoiseFilling) { - checkBitsAvailable(data, 1); + validateBitsAvailability(data, 1); data.skipBit(); // igfIndependentTiling } int stereoConfigIndex = 0; if (sbrRatioIndex > 0) { parseSbrConfig(data); // sbrConfig - checkBitsAvailable(data, 2); + validateBitsAvailability(data, 2); stereoConfigIndex = data.readBits(2); } if (stereoConfigIndex > 0) { // mps212Config - checkBitsAvailable(data, 13); + validateBitsAvailability(data, 13); data.skipBits(6); // bsFreqRes(3), bsFixedGainDMX(3), int bsTempShapeConfig = data.readBits(2); data.skipBits(4);// bsDecorrConfig(2), bsHighRateMode(1), bsPhaseCoding(1) if (data.readBit()) { // bsOttBandsPhasePresent - checkBitsAvailable(data, 5); + validateBitsAvailability(data, 5); data.skipBits(5); // bsOttBandsPhase } if (stereoConfigIndex == 2 || stereoConfigIndex == 3) { - checkBitsAvailable(data, 6); + validateBitsAvailability(data, 6); data.skipBits(6); // bsResidualBands(5), bsPseudoLr(1) } if (bsTempShapeConfig == 2) { - checkBitsAvailable(data, 1); + validateBitsAvailability(data, 1); data.skipBit(); // bsEnvQuantMode } } int nBits = (int) Math.floor(Math.log(numSignals - 1) / Math.log(2.0)) + 1; - checkBitsAvailable(data, 2); + validateBitsAvailability(data, 2); int qceIndex = data.readBits(2); if (qceIndex > 0) { - checkBitsAvailable(data, 1); + validateBitsAvailability(data, 1); if (data.readBit()) { // shiftIndex0 - checkBitsAvailable(data, nBits); + validateBitsAvailability(data, nBits); data.skipBits(nBits); // shiftChannel0 } } - checkBitsAvailable(data, 1); + validateBitsAvailability(data, 1); if (data.readBit()) { // shiftIndex1 - checkBitsAvailable(data, nBits); + validateBitsAvailability(data, nBits); data.skipBits(nBits); // shiftChannel1 } if (sbrRatioIndex == 0 && qceIndex == 0) { - checkBitsAvailable(data, 1); + validateBitsAvailability(data, 1); data.skipBit(); // lpdStereoIndex } break; @@ -769,15 +798,15 @@ public final class MpeghUtil { readEscapedValue(data, 4, 8, 16); // usacExtElementType int usacExtElementConfigLength = (int) readEscapedValue(data, 4, 8, 16); - checkBitsAvailable(data, 1); + validateBitsAvailability(data, 1); if (data.readBit()) { // usacExtElementDefaultLengthPresent readEscapedValue(data, 8, 16, 0)/*+1*/; // usacExtElementDefaultLength } - checkBitsAvailable(data, 1); + validateBitsAvailability(data, 1); data.skipBit(); // usacExtElementPayloadFrag if (usacExtElementConfigLength > 0) { - checkBitsAvailable(data, 8 * usacExtElementConfigLength); + validateBitsAvailability(data, 8 * usacExtElementConfigLength); data.skipBits(8 * usacExtElementConfigLength); } break; @@ -788,46 +817,46 @@ public final class MpeghUtil { } /** - * This function is used to obtain the necessary info of the Mpegh3daCoreConfig from an MPEG-H - * bit stream. See ISO_IEC_23008-3;2022, 5.2.2.3, Table 24 + * Obtains the necessary info of the Mpegh3daCoreConfig from an MPEG-H bit stream. + * See ISO_IEC_23008-3;2022, 5.2.2.3, Table 24. * * @param data The bit array to be parsed. * @return The enhanced noise filling flag. - * @throws ParseException If parsing failed. + * @throws {@link ParseException} if parsing failed. */ private static boolean parseMpegh3daCoreConfig(ParsableBitArray data) throws ParseException { - checkBitsAvailable(data, 4); + validateBitsAvailability(data, 4); data.skipBits(3); // tw_mdct(1), fullbandLpd(1), noiseFilling(1) boolean enhancedNoiseFilling = data.readBit(); if (enhancedNoiseFilling) { - checkBitsAvailable(data, 13); + validateBitsAvailability(data, 13); data.skipBits(13); // igfUseEnf(1), igfUseHighRes(1), igfUseWhitening(1), igfAfterTnsSynth(1), igfStartIndex(5), igfStopIndex(4) } return enhancedNoiseFilling; } /** - * This function is used to parse the SbrConfig from an MPEG-H bit stream. - * See ISO_IEC_23003-3;2020, 5.2, Table 14 + * Parses the SbrConfig from an MPEG-H bit stream. + * See ISO_IEC_23003-3;2020, 5.2, Table 14. * * @param data The bit array to be parsed. - * @throws ParseException If parsing failed. + * @throws {@link ParseException} if parsing failed. */ private static void parseSbrConfig(ParsableBitArray data) throws ParseException { - checkBitsAvailable(data, 3); + validateBitsAvailability(data, 3); data.skipBits(3); // harmonicSBR(1), bs_interTes(1), bs_pvc(1) - checkBitsAvailable(data, 10); + validateBitsAvailability(data, 10); data.skipBits(8); // dflt_start_freq(4), dflt_stop_freq(4) boolean dflt_header_extra1 = data.readBit(); boolean dflt_header_extra2 = data.readBit(); if (dflt_header_extra1) { - checkBitsAvailable(data, 5); + validateBitsAvailability(data, 5); data.skipBits(5); // dflt_freq_scale(2), dflt_alter_scale(1), dflt_noise_bands(2) } if (dflt_header_extra2) { - checkBitsAvailable(data, 6); + validateBitsAvailability(data, 6); data.skipBits(6); // dflt_limiter_bands(2), dflt_limiter_gains(2), dflt_interpol_freq(1), dflt_smoothing_mode(1) } } @@ -838,24 +867,24 @@ public final class MpeghUtil { public static class ParseException extends IOException { - public final @ParseState int parseState; + public final @State int parseState; public static ParseException createForNotEnoughData() { - return new ParseException(null, null, END_OUTPUT); + return new ParseException(null, null, STATE_END_OUTPUT); } public static ParseException createForUnsupportedSubstream(@Nullable String message) { - return new ParseException(message, null, SUBSTREAM_UNSUPPORTED); + return new ParseException(message, null, STATE_SUBSTREAM_UNSUPPORTED); } public static ParseException createForParsingError(@Nullable String message) { - return new ParseException(message, null, PARSE_ERROR); + return new ParseException(message, null, STATE_PARSE_ERROR); } protected ParseException( @Nullable String message, @Nullable Throwable cause, - @ParseState int parseState) { + @State int parseState) { super(message, cause); this.parseState = parseState; } diff --git a/libraries/extractor/src/main/java/androidx/media3/extractor/ts/MpeghReader.java b/libraries/extractor/src/main/java/androidx/media3/extractor/ts/MpeghReader.java index 695c1161c1..3f67d41662 100644 --- a/libraries/extractor/src/main/java/androidx/media3/extractor/ts/MpeghReader.java +++ b/libraries/extractor/src/main/java/androidx/media3/extractor/ts/MpeghReader.java @@ -25,7 +25,6 @@ import static androidx.media3.extractor.ts.TsPayloadReader.FLAG_RANDOM_ACCESS_IN import android.util.Log; -import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.media3.common.C; @@ -33,6 +32,7 @@ import androidx.media3.common.Format; import androidx.media3.common.MimeTypes; import androidx.media3.common.util.ParsableBitArray; import androidx.media3.common.util.ParsableByteArray; +import androidx.media3.common.util.UnstableApi; import androidx.media3.extractor.ExtractorOutput; import androidx.media3.extractor.MpeghUtil; import androidx.media3.extractor.TrackOutput; @@ -44,6 +44,7 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull; /** * Parses a continuous MPEG-H audio byte stream and extracts MPEG-H frames. */ +@UnstableApi public final class MpeghReader implements ElementaryStreamReader { private static final String TAG = MpeghReader.class.getSimpleName(); @@ -107,7 +108,7 @@ public final class MpeghReader implements ElementaryStreamReader { } @Override - public void consume(@NonNull ParsableByteArray data) { + public void consume(ParsableByteArray data) { // write the PES payload to a data buffer until the packet is complete appendToDataBuffer(data); }