diff --git a/libraries/common/src/main/java/androidx/media3/common/C.java b/libraries/common/src/main/java/androidx/media3/common/C.java index df6736b80a..f1264fb560 100644 --- a/libraries/common/src/main/java/androidx/media3/common/C.java +++ b/libraries/common/src/main/java/androidx/media3/common/C.java @@ -1,3 +1,28 @@ +/*************************************************************************** + +Fraunhofer hereby grants to Google free of charge a worldwide, perpetual, +irrevocable, non-exclusive copyright license with the right to sublicense +through multiple tiers to use, copy, distribute, modify and create +derivative works of the Software Patches for Exoplayer in source code form +and/or object code versions of the software. For the avoidance of doubt, +this license does not include any license to any Fraunhofer patents or any +third-party patents. Since the license is granted without any charge, +Fraunhofer provides the Software Patches for Exoplayer, in accordance with +the laws of the Federal Republic of Germany, on an “as is” basis, WITHOUT +WARRANTIES or conditions of any kind, either express or implied, including, +without limitation, any warranties or conditions of title, non-infringement, +merchantability, or fitness for a particular purpose. + +For the purpose of clarity, the provision of the Software Patches for +Exoplayer by Fraunhofer and the use of the same by Google shall be subject +solely to the license stated above. + +This file was originally licensed under the Apache 2.0 license (see license +note below). Fraunhofer has modified this files and provides its copyright +in the modifications to Google under the above terms, which shall not be +considered a contribution under the Apache 2.0 license. + +***************************************************************************/ /* * Copyright (C) 2016 The Android Open Source Project * @@ -1608,4 +1633,51 @@ public final class C { int mediaDrmErrorCode) { return Util.getErrorCodeForMediaDrmErrorCode(mediaDrmErrorCode); } + + @Documented + @Retention(RetentionPolicy.SOURCE) + @IntDef({ + Format.NO_VALUE, + MPEGH_PROFILE_MAIN_L1, + MPEGH_PROFILE_MAIN_L2, + MPEGH_PROFILE_MAIN_L3, + MPEGH_PROFILE_MAIN_L4, + MPEGH_PROFILE_MAIN_L5, + MPEGH_PROFILE_HIGH_L1, + MPEGH_PROFILE_HIGH_L2, + MPEGH_PROFILE_HIGH_L3, + MPEGH_PROFILE_HIGH_L4, + MPEGH_PROFILE_HIGH_L5, + MPEGH_PROFILE_LC_L1, + MPEGH_PROFILE_LC_L2, + MPEGH_PROFILE_LC_L3, + MPEGH_PROFILE_LC_L4, + MPEGH_PROFILE_LC_L5, + MPEGH_PROFILE_BL_L1, + MPEGH_PROFILE_BL_L2, + MPEGH_PROFILE_BL_L3, + MPEGH_PROFILE_BL_L4, + MPEGH_PROFILE_BL_L5 + }) + public @interface MpeghProfileLevelIndication {} + public static final int MPEGH_PROFILE_MAIN_L1 = 1; + public static final int MPEGH_PROFILE_MAIN_L2 = 2; + public static final int MPEGH_PROFILE_MAIN_L3 = 3; + public static final int MPEGH_PROFILE_MAIN_L4 = 4; + public static final int MPEGH_PROFILE_MAIN_L5 = 5; + public static final int MPEGH_PROFILE_HIGH_L1 = 6; + public static final int MPEGH_PROFILE_HIGH_L2 = 7; + public static final int MPEGH_PROFILE_HIGH_L3 = 8; + public static final int MPEGH_PROFILE_HIGH_L4 = 9; + public static final int MPEGH_PROFILE_HIGH_L5 = 10; + public static final int MPEGH_PROFILE_LC_L1 = 11; + public static final int MPEGH_PROFILE_LC_L2 = 12; + public static final int MPEGH_PROFILE_LC_L3 = 13; + public static final int MPEGH_PROFILE_LC_L4 = 14; + public static final int MPEGH_PROFILE_LC_L5 = 15; + public static final int MPEGH_PROFILE_BL_L1 = 16; + public static final int MPEGH_PROFILE_BL_L2 = 17; + public static final int MPEGH_PROFILE_BL_L3 = 18; + public static final int MPEGH_PROFILE_BL_L4 = 19; + public static final int MPEGH_PROFILE_BL_L5 = 20; } diff --git a/libraries/common/src/main/java/androidx/media3/common/Format.java b/libraries/common/src/main/java/androidx/media3/common/Format.java index 5795a1437b..df3d2a080b 100644 --- a/libraries/common/src/main/java/androidx/media3/common/Format.java +++ b/libraries/common/src/main/java/androidx/media3/common/Format.java @@ -1,3 +1,28 @@ +/*************************************************************************** + +Fraunhofer hereby grants to Google free of charge a worldwide, perpetual, +irrevocable, non-exclusive copyright license with the right to sublicense +through multiple tiers to use, copy, distribute, modify and create +derivative works of the Software Patches for Exoplayer in source code form +and/or object code versions of the software. For the avoidance of doubt, +this license does not include any license to any Fraunhofer patents or any +third-party patents. Since the license is granted without any charge, +Fraunhofer provides the Software Patches for Exoplayer, in accordance with +the laws of the Federal Republic of Germany, on an “as is” basis, WITHOUT +WARRANTIES or conditions of any kind, either express or implied, including, +without limitation, any warranties or conditions of title, non-infringement, +merchantability, or fitness for a particular purpose. + +For the purpose of clarity, the provision of the Software Patches for +Exoplayer by Fraunhofer and the use of the same by Google shall be subject +solely to the license stated above. + +This file was originally licensed under the Apache 2.0 license (see license +note below). Fraunhofer has modified this files and provides its copyright +in the modifications to Google under the above terms, which shall not be +considered a contribution under the Apache 2.0 license. + +***************************************************************************/ /* * Copyright (C) 2016 The Android Open Source Project * @@ -176,6 +201,10 @@ public final class Format implements Bundleable { private int encoderDelay; private int encoderPadding; + @C.MpeghProfileLevelIndication private int mpeghProfileLevelIndication; + private int mpeghReferenceChannelLayout; + @Nullable @C.MpeghProfileLevelIndication private int[] mpeghCompatibleProfileLevelSet; + // Text specific. private int accessibilityChannel; @@ -207,6 +236,8 @@ public final class Format implements Bundleable { channelCount = NO_VALUE; sampleRate = NO_VALUE; pcmEncoding = NO_VALUE; + mpeghProfileLevelIndication = NO_VALUE; + mpeghReferenceChannelLayout = NO_VALUE; // Text specific. accessibilityChannel = NO_VALUE; cueReplacementBehavior = CUE_REPLACEMENT_BEHAVIOR_MERGE; @@ -255,6 +286,9 @@ public final class Format implements Bundleable { this.pcmEncoding = format.pcmEncoding; this.encoderDelay = format.encoderDelay; this.encoderPadding = format.encoderPadding; + this.mpeghReferenceChannelLayout = format.mpeghReferenceChannelLayout; + this.mpeghProfileLevelIndication = format.mpeghProfileLevelIndication; + this.mpeghCompatibleProfileLevelSet = format.mpeghCompatibleProfileLevelSet; // Text specific. this.accessibilityChannel = format.accessibilityChannel; this.cueReplacementBehavior = format.cueReplacementBehavior; @@ -622,6 +656,19 @@ public final class Format implements Bundleable { return this; } + public Builder setMpeghProfileLevelIndication(@C.MpeghProfileLevelIndication int mpeghProfileLevelIndication) { + this.mpeghProfileLevelIndication = mpeghProfileLevelIndication; + return this; + } + public Builder setMpeghReferenceChannelLayout(int mpeghReferenceChannelLayout) { + this.mpeghReferenceChannelLayout = mpeghReferenceChannelLayout; + return this; + } + public Builder setMpeghCompatibleProfileLevelSet(@Nullable @C.MpeghProfileLevelIndication int[] mpeghCompatibleProfileLevelSet) { + this.mpeghCompatibleProfileLevelSet = mpeghCompatibleProfileLevelSet; + return this; + } + // Text specific. /** @@ -895,6 +942,10 @@ public final class Format implements Bundleable { */ @UnstableApi public final int encoderPadding; + @C.MpeghProfileLevelIndication public final int mpeghProfileLevelIndication; + public final int mpeghReferenceChannelLayout; + @Nullable @C.MpeghProfileLevelIndication public final int[] mpeghCompatibleProfileLevelSet; + // Text specific. /** The Accessibility channel, or {@link #NO_VALUE} if not known or applicable. */ @@ -965,6 +1016,9 @@ public final class Format implements Bundleable { pcmEncoding = builder.pcmEncoding; encoderDelay = builder.encoderDelay == NO_VALUE ? 0 : builder.encoderDelay; encoderPadding = builder.encoderPadding == NO_VALUE ? 0 : builder.encoderPadding; + mpeghProfileLevelIndication = builder.mpeghProfileLevelIndication; + mpeghReferenceChannelLayout = builder.mpeghReferenceChannelLayout; + mpeghCompatibleProfileLevelSet = builder.mpeghCompatibleProfileLevelSet; // Text specific. accessibilityChannel = builder.accessibilityChannel; cueReplacementBehavior = builder.cueReplacementBehavior; @@ -1138,6 +1192,9 @@ public final class Format implements Bundleable { result = 31 * result + pcmEncoding; result = 31 * result + encoderDelay; result = 31 * result + encoderPadding; + result = 31 * result + mpeghProfileLevelIndication; + result = 31 * result + mpeghReferenceChannelLayout; + // [Omitted] mpeghCompatibleProfileLevelSet. // Text specific. result = 31 * result + accessibilityChannel; // Image specific. @@ -1178,6 +1235,9 @@ public final class Format implements Bundleable { && pcmEncoding == other.pcmEncoding && encoderDelay == other.encoderDelay && encoderPadding == other.encoderPadding + && mpeghReferenceChannelLayout == other.mpeghReferenceChannelLayout + && mpeghProfileLevelIndication == other.mpeghProfileLevelIndication + && Util.areEqual(mpeghCompatibleProfileLevelSet, other.mpeghCompatibleProfileLevelSet) && accessibilityChannel == other.accessibilityChannel && tileCountHorizontal == other.tileCountHorizontal && tileCountVertical == other.tileCountVertical @@ -1382,6 +1442,9 @@ public final class Format implements Bundleable { private static final String FIELD_CRYPTO_TYPE = Util.intToStringMaxRadix(29); private static final String FIELD_TILE_COUNT_HORIZONTAL = Util.intToStringMaxRadix(30); private static final String FIELD_TILE_COUNT_VERTICAL = Util.intToStringMaxRadix(31); + private static final String FIELD_MPEGH_PROFILE_LEVEL_INDICATION = Util.intToStringMaxRadix(32); + private static final String FIELD_MPEGH_REFERENCE_CHANNEL_LAYOUT = Util.intToStringMaxRadix(33); + private static final String FIELD_MPEGH_COMPATIBLE_PROFILE_LEVEL_SET = Util.intToStringMaxRadix(34); @UnstableApi @Override @@ -1437,6 +1500,9 @@ public final class Format implements Bundleable { bundle.putInt(FIELD_PCM_ENCODING, pcmEncoding); bundle.putInt(FIELD_ENCODER_DELAY, encoderDelay); bundle.putInt(FIELD_ENCODER_PADDING, encoderPadding); + bundle.putInt(FIELD_MPEGH_PROFILE_LEVEL_INDICATION, mpeghProfileLevelIndication); + bundle.putInt(FIELD_MPEGH_REFERENCE_CHANNEL_LAYOUT, mpeghReferenceChannelLayout); + bundle.putIntArray(FIELD_MPEGH_COMPATIBLE_PROFILE_LEVEL_SET, mpeghCompatibleProfileLevelSet); // Text specific. bundle.putInt(FIELD_ACCESSIBILITY_CHANNEL, accessibilityChannel); // Image specific. @@ -1512,6 +1578,12 @@ public final class Format implements Bundleable { .setPcmEncoding(bundle.getInt(FIELD_PCM_ENCODING, DEFAULT.pcmEncoding)) .setEncoderDelay(bundle.getInt(FIELD_ENCODER_DELAY, DEFAULT.encoderDelay)) .setEncoderPadding(bundle.getInt(FIELD_ENCODER_PADDING, DEFAULT.encoderPadding)) + .setMpeghProfileLevelIndication( + bundle.getInt(FIELD_MPEGH_PROFILE_LEVEL_INDICATION, DEFAULT.mpeghProfileLevelIndication)) + .setMpeghReferenceChannelLayout( + bundle.getInt(FIELD_MPEGH_REFERENCE_CHANNEL_LAYOUT, DEFAULT.mpeghReferenceChannelLayout)) + .setMpeghCompatibleProfileLevelSet( + bundle.getIntArray(FIELD_MPEGH_COMPATIBLE_PROFILE_LEVEL_SET)) // Text specific. .setAccessibilityChannel( bundle.getInt(FIELD_ACCESSIBILITY_CHANNEL, DEFAULT.accessibilityChannel)) diff --git a/libraries/extractor/src/main/java/androidx/media3/extractor/mp4/Atom.java b/libraries/extractor/src/main/java/androidx/media3/extractor/mp4/Atom.java index 91d2a1dc6f..d9e5bdb292 100644 --- a/libraries/extractor/src/main/java/androidx/media3/extractor/mp4/Atom.java +++ b/libraries/extractor/src/main/java/androidx/media3/extractor/mp4/Atom.java @@ -1,3 +1,28 @@ +/*************************************************************************** + +Fraunhofer hereby grants to Google free of charge a worldwide, perpetual, +irrevocable, non-exclusive copyright license with the right to sublicense +through multiple tiers to use, copy, distribute, modify and create +derivative works of the Software Patches for Exoplayer in source code form +and/or object code versions of the software. For the avoidance of doubt, +this license does not include any license to any Fraunhofer patents or any +third-party patents. Since the license is granted without any charge, +Fraunhofer provides the Software Patches for Exoplayer, in accordance with +the laws of the Federal Republic of Germany, on an “as is” basis, WITHOUT +WARRANTIES or conditions of any kind, either express or implied, including, +without limitation, any warranties or conditions of title, non-infringement, +merchantability, or fitness for a particular purpose. + +For the purpose of clarity, the provision of the Software Patches for +Exoplayer by Fraunhofer and the use of the same by Google shall be subject +solely to the license stated above. + +This file was originally licensed under the Apache 2.0 license (see license +note below). Fraunhofer has modified this files and provides its copyright +in the modifications to Google under the above terms, which shall not be +considered a contribution under the Apache 2.0 license. + +***************************************************************************/ /* * Copyright (C) 2016 The Android Open Source Project * @@ -125,6 +150,9 @@ import java.util.List; @SuppressWarnings("ConstantCaseForConstants") public static final int TYPE_mhaC = 0x6d686143; + @SuppressWarnings("ConstantCaseForConstants") + public static final int TYPE_mhaP = 0x6d686150; + @SuppressWarnings("ConstantCaseForConstants") public static final int TYPE_wave = 0x77617665; 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 9f0638ceae..2f4e581c1f 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 @@ -1,3 +1,28 @@ +/*************************************************************************** + +Fraunhofer hereby grants to Google free of charge a worldwide, perpetual, +irrevocable, non-exclusive copyright license with the right to sublicense +through multiple tiers to use, copy, distribute, modify and create +derivative works of the Software Patches for Exoplayer in source code form +and/or object code versions of the software. For the avoidance of doubt, +this license does not include any license to any Fraunhofer patents or any +third-party patents. Since the license is granted without any charge, +Fraunhofer provides the Software Patches for Exoplayer, in accordance with +the laws of the Federal Republic of Germany, on an “as is” basis, WITHOUT +WARRANTIES or conditions of any kind, either express or implied, including, +without limitation, any warranties or conditions of title, non-infringement, +merchantability, or fitness for a particular purpose. + +For the purpose of clarity, the provision of the Software Patches for +Exoplayer by Fraunhofer and the use of the same by Google shall be subject +solely to the license stated above. + +This file was originally licensed under the Apache 2.0 license (see license +note below). Fraunhofer has modified this files and provides its copyright +in the modifications to Google under the above terms, which shall not be +considered a contribution under the Apache 2.0 license. + +***************************************************************************/ /* * Copyright (C) 2016 The Android Open Source Project * @@ -1598,6 +1623,9 @@ import java.util.List; int sampleRateMlp = 0; @C.PcmEncoding int pcmEncoding = Format.NO_VALUE; @Nullable String codecs = null; + @C.MpeghProfileLevelIndication int mpeghProfileLevelIndication = Format.NO_VALUE; + int mpeghReferenceChannelLayout = Format.NO_VALUE; + @Nullable @C.MpeghProfileLevelIndication int[] mpeghCompatibleProfileLevelSet = null; @Nullable EsdsData esdsData = null; if (quickTimeSoundDescriptionVersion == 0 || quickTimeSoundDescriptionVersion == 1) { @@ -1720,15 +1748,35 @@ import java.util.List; ExtractorUtil.checkContainerInput(childAtomSize > 0, "childAtomSize must be positive"); int childAtomType = parent.readInt(); if (childAtomType == Atom.TYPE_mhaC) { - // See ISO_IEC_23008-3;2019 MHADecoderConfigurationRecord + // See ISO_IEC_23008-3;2022 MHADecoderConfigurationRecord // The header consists of: size (4), boxtype 'mhaC' (4), configurationVersion (1), // mpegh3daProfileLevelIndication (1), referenceChannelLayout (1), mpegh3daConfigLength (2). int mhacHeaderSize = 13; - int childAtomBodySize = childAtomSize - mhacHeaderSize; - byte[] initializationDataBytes = new byte[childAtomBodySize]; - parent.setPosition(childPosition + mhacHeaderSize); - parent.readBytes(initializationDataBytes, 0, childAtomBodySize); + parent.setPosition(childPosition + Atom.HEADER_SIZE); + int configurationVersion = parent.readUnsignedByte(); + mpeghProfileLevelIndication = parent.readUnsignedByte(); + mpeghReferenceChannelLayout = parent.readUnsignedByte(); + if (mimeType.equals(MimeTypes.AUDIO_MPEGH_MHM1)) { + codecs = String.format("mhm1.0x%02X", mpeghProfileLevelIndication); + } else { + codecs = String.format("mha1.0x%02X", mpeghProfileLevelIndication); + } + int mpegh3daConfigLength = parent.readUnsignedShort(); + byte[] initializationDataBytes = new byte[mpegh3daConfigLength]; + parent.readBytes(initializationDataBytes, 0, mpegh3daConfigLength); initializationData = ImmutableList.of(initializationDataBytes); + } else if (childAtomType == Atom.TYPE_mhaP) { + // See ISO_IEC_23008-3;2022 MHAProfileAndLevelCompatibilitySetBox + // The header consists of: size (4), boxtype 'mhaP' (4), numCompatibleSets (1). + int mhapHeaderSize = 9; + parent.setPosition(childPosition + Atom.HEADER_SIZE); + int numCompatibleSets = parent.readUnsignedByte(); + if (numCompatibleSets > 0) { + mpeghCompatibleProfileLevelSet = new int[numCompatibleSets]; + for (int i = 0; i < numCompatibleSets; i++) { + mpeghCompatibleProfileLevelSet[i] = parent.readUnsignedByte(); + } + } } else if (childAtomType == Atom.TYPE_esds || (isQuickTime && childAtomType == Atom.TYPE_wave)) { int esdsAtomPosition = @@ -1835,6 +1883,9 @@ import java.util.List; .setPcmEncoding(pcmEncoding) .setInitializationData(initializationData) .setDrmInitData(drmInitData) + .setMpeghProfileLevelIndication(mpeghProfileLevelIndication) + .setMpeghReferenceChannelLayout(mpeghReferenceChannelLayout) + .setMpeghCompatibleProfileLevelSet(mpeghCompatibleProfileLevelSet) .setLanguage(language); if (esdsData != null) {