diff --git a/library/common/src/main/java/com/google/android/exoplayer2/util/MimeTypes.java b/library/common/src/main/java/com/google/android/exoplayer2/util/MimeTypes.java index 2847dda685..cf86be8c46 100644 --- a/library/common/src/main/java/com/google/android/exoplayer2/util/MimeTypes.java +++ b/library/common/src/main/java/com/google/android/exoplayer2/util/MimeTypes.java @@ -17,6 +17,7 @@ package com.google.android.exoplayer2.util; import android.text.TextUtils; import androidx.annotation.Nullable; +import androidx.annotation.VisibleForTesting; import com.google.android.exoplayer2.C; import com.google.android.exoplayer2.audio.AacUtil; import java.util.ArrayList; @@ -28,19 +29,6 @@ import java.util.regex.Pattern; */ public final class MimeTypes { - /** An mp4a Object Type Indication (OTI) and its optional audio OTI is defined by RFC 6381. */ - public static final class Mp4aObjectType { - /** The Object Type Indication of the mp4a codec. */ - public final int objectTypeIndication; - /** The Audio Object Type Indication of the mp4a codec, or 0 if it is absent. */ - @AacUtil.AacAudioObjectType public final int audioObjectTypeIndication; - - private Mp4aObjectType(int objectTypeIndication, int audioObjectTypeIndication) { - this.objectTypeIndication = objectTypeIndication; - this.audioObjectTypeIndication = audioObjectTypeIndication; - } - } - public static final String BASE_TYPE_VIDEO = "video"; public static final String BASE_TYPE_AUDIO = "audio"; public static final String BASE_TYPE_TEXT = "text"; @@ -135,7 +123,7 @@ public final class MimeTypes { * via this method. If this method is used, it must be called before creating any player(s). * * @param mimeType The custom MIME type to register. - * @param codecPrefix The RFC 6381-style codec string prefix associated with the MIME type. + * @param codecPrefix The RFC 6381 codec string prefix associated with the MIME type. * @param trackType The {@link C}{@code .TRACK_TYPE_*} constant associated with the MIME type. * This value is ignored if the top-level type of {@code mimeType} is audio, video or text. */ @@ -181,13 +169,13 @@ public final class MimeTypes { } /** - * Returns true if it is known that all samples in a stream of the given sample MIME type are - * guaranteed to be sync samples (i.e., {@link C#BUFFER_FLAG_KEY_FRAME} is guaranteed to be set on - * every sample). + * Returns true if it is known that all samples in a stream of the given MIME type are guaranteed + * to be sync samples (i.e., {@link C#BUFFER_FLAG_KEY_FRAME} is guaranteed to be set on every + * sample). * - * @param mimeType The sample MIME type. - * @return True if it is known that all samples in a stream of the given sample MIME type are - * guaranteed to be sync samples. False otherwise, including if {@code null} is passed. + * @param mimeType A MIME type. + * @return True if it is known that all samples in a stream of the given MIME type are guaranteed + * to be sync samples. False otherwise, including if {@code null} is passed. */ public static boolean allSamplesAreSyncSamples(@Nullable String mimeType) { if (mimeType == null) { @@ -216,10 +204,10 @@ public final class MimeTypes { } /** - * Derives a video sample mimeType from a codecs attribute. + * Returns the first video MIME type derived from an RFC 6381 codecs string. * - * @param codecs The codecs attribute. - * @return The derived video mimeType, or null if it could not be derived. + * @param codecs An RFC 6381 codecs string. + * @return The first derived video MIME type, or {@code null}. */ @Nullable public static String getVideoMediaMimeType(@Nullable String codecs) { @@ -237,10 +225,10 @@ public final class MimeTypes { } /** - * Derives a audio sample mimeType from a codecs attribute. + * Returns the first audio MIME type derived from an RFC 6381 codecs string. * - * @param codecs The codecs attribute. - * @return The derived audio mimeType, or null if it could not be derived. + * @param codecs An RFC 6381 codecs string. + * @return The first derived audio MIME type, or {@code null}. */ @Nullable public static String getAudioMediaMimeType(@Nullable String codecs) { @@ -258,10 +246,10 @@ public final class MimeTypes { } /** - * Derives a text sample mimeType from a codecs attribute. + * Returns the first text MIME type derived from an RFC 6381 codecs string. * - * @param codecs The codecs attribute. - * @return The derived text mimeType, or null if it could not be derived. + * @param codecs An RFC 6381 codecs string. + * @return The first derived text MIME type, or {@code null}. */ @Nullable public static String getTextMediaMimeType(@Nullable String codecs) { @@ -279,10 +267,11 @@ public final class MimeTypes { } /** - * Derives a mimeType from a codec identifier, as defined in RFC 6381. + * Returns the MIME type corresponding to an RFC 6381 codec string, or {@code null} if it could + * not be determined. * - * @param codec The codec identifier to derive. - * @return The mimeType, or null if it could not be derived. + * @param codec An RFC 6381 codec string. + * @return The corresponding MIME type, or {@code null} if it could not be determined. */ @Nullable public static String getMediaMimeType(@Nullable String codec) { @@ -346,11 +335,11 @@ public final class MimeTypes { } /** - * Derives a mimeType from MP4 object type identifier, as defined in RFC 6381 and - * https://mp4ra.org/#/object_types. + * Returns the MIME type corresponding to an MP4 object type identifier, as defined in RFC 6381 + * and https://mp4ra.org/#/object_types. * - * @param objectType The objectType identifier to derive. - * @return The mimeType, or null if it could not be derived. + * @param objectType An MP4 object type identifier. + * @return The corresponding MIME type, or {@code null} if it could not be determined. */ @Nullable public static String getMimeTypeFromMp4ObjectType(int objectType) { @@ -402,12 +391,12 @@ public final class MimeTypes { } /** - * Returns the {@link C}{@code .TRACK_TYPE_*} constant that corresponds to a specified MIME type. - * {@link C#TRACK_TYPE_UNKNOWN} if the MIME type is not known or the mapping cannot be - * established. + * Returns the {@link C}{@code .TRACK_TYPE_*} constant corresponding to a specified MIME type, or + * {@link C#TRACK_TYPE_UNKNOWN} if it could not be determined. * - * @param mimeType The MIME type. - * @return The {@link C}{@code .TRACK_TYPE_*} constant that corresponds to a specified MIME type. + * @param mimeType A MIME type. + * @return The corresponding {@link C}{@code .TRACK_TYPE_*}, or {@link C#TRACK_TYPE_UNKNOWN} if it + * could not be determined. */ public static int getTrackType(@Nullable String mimeType) { if (TextUtils.isEmpty(mimeType)) { @@ -430,25 +419,24 @@ public final class MimeTypes { } /** - * Returns the {@link C}{@code .ENCODING_*} constant that corresponds to specified MIME type, if - * it is an encoded (non-PCM) audio format, or {@link C#ENCODING_INVALID} otherwise. + * Returns the {@link C.Encoding} constant corresponding to the specified audio MIME type and RFC + * 6381 codec string, or {@link C#ENCODING_INVALID} if the corresponding {@link C.Encoding} cannot + * be determined. * - * @param mimeType The MIME type. - * @param codecs Codecs of the format as described in RFC 6381, or null if unknown or not - * applicable. - * @return One of {@link C.Encoding} constants that corresponds to a specified MIME type, or - * {@link C#ENCODING_INVALID}. + * @param mimeType A MIME type. + * @param codec An RFC 6381 codec string, or {@code null} if unknown or not applicable. + * @return The corresponding {@link C.Encoding}, or {@link C#ENCODING_INVALID}. */ @C.Encoding - public static int getEncoding(String mimeType, @Nullable String codecs) { + public static int getEncoding(String mimeType, @Nullable String codec) { switch (mimeType) { case MimeTypes.AUDIO_MPEG: return C.ENCODING_MP3; case MimeTypes.AUDIO_AAC: - if (codecs == null) { + if (codec == null) { return C.ENCODING_INVALID; } - @Nullable Mp4aObjectType objectType = getObjectTypeFromMp4aRFC6381CodecString(codecs); + @Nullable Mp4aObjectType objectType = getObjectTypeFromMp4aRFC6381CodecString(codec); if (objectType == null) { return C.ENCODING_INVALID; } @@ -475,57 +463,19 @@ public final class MimeTypes { /** * Equivalent to {@code getTrackType(getMediaMimeType(codec))}. * - * @param codec The codec. - * @return The {@link C}{@code .TRACK_TYPE_*} constant that corresponds to a specified codec. + * @param codec An RFC 6381 codec string. + * @return The corresponding {@link C}{@code .TRACK_TYPE_*}, or {@link C#TRACK_TYPE_UNKNOWN} if it + * could not be determined. */ public static int getTrackTypeOfCodec(String codec) { return getTrackType(getMediaMimeType(codec)); } - /** - * Retrieves the object type of an mp4 audio codec from its string as defined in RFC 6381. - * - *

Per https://mp4ra.org/#/object_types and https://tools.ietf.org/html/rfc6381#section-3.3, an - * mp4 codec string has the form: - * - *

-   *         ~~~~~~~~~~~~~~ Object Type Indication (OTI) byte in hex
-   *    mp4a.[a-zA-Z0-9]{2}(.[0-9]{1,2})?
-   *                         ~~~~~~~~~~ audio OTI, decimal. Only for certain OTI.
-   * 
- * - * For example: mp4a.40.2, has an OTI of 0x40 and an audio OTI of 2. - * - * @param codec The string as defined in RFC 6381 describing an mp4 audio codec. - * @return The {@link Mp4aObjectType} or {@code null} if the input is invalid. - */ - @Nullable - public static Mp4aObjectType getObjectTypeFromMp4aRFC6381CodecString(String codec) { - Matcher matcher = MP4A_RFC_6381_CODEC_PATTERN.matcher(codec); - if (!matcher.matches()) { - return null; - } - String objectTypeIndicationHex = Assertions.checkNotNull(matcher.group(1)); - @Nullable String audioObjectTypeIndicationDec = matcher.group(2); - int objectTypeIndication; - int audioObjectTypeIndication = 0; - try { - objectTypeIndication = Integer.parseInt(objectTypeIndicationHex, 16); - if (audioObjectTypeIndicationDec != null) { - audioObjectTypeIndication = Integer.parseInt(audioObjectTypeIndicationDec); - } - } catch (NumberFormatException e) { - return null; - } - return new Mp4aObjectType(objectTypeIndication, audioObjectTypeIndication); - } - /** * Normalizes the MIME type provided so that equivalent MIME types are uniquely represented. * - * @param mimeType The MIME type to normalize. The MIME type provided is returned if its - * normalized form is unknown. - * @return The normalized MIME type. + * @param mimeType A MIME type to normalize. + * @return The normalized MIME type, or the argument MIME type if its normalized form is unknown. */ public static String normalizeMimeType(String mimeType) { switch (mimeType) { @@ -596,6 +546,59 @@ public final class MimeTypes { // Prevent instantiation. } + /** + * Returns the {@link Mp4aObjectType} of an RFC 6381 MP4 audio codec string. + * + *

Per https://mp4ra.org/#/object_types and https://tools.ietf.org/html/rfc6381#section-3.3, an + * MP4 codec string has the form: + * + *

+   *         ~~~~~~~~~~~~~~ Object Type Indication (OTI) byte in hex
+   *    mp4a.[a-zA-Z0-9]{2}(.[0-9]{1,2})?
+   *                         ~~~~~~~~~~ audio OTI, decimal. Only for certain OTI.
+   * 
+ * + * For example, mp4a.40.2 has an OTI of 0x40 and an audio OTI of 2. + * + * @param codec An RFC 6381 MP4 audio codec string. + * @return The {@link Mp4aObjectType}, or {@code null} if the input was invalid. + */ + @VisibleForTesting + @Nullable + /* package */ static Mp4aObjectType getObjectTypeFromMp4aRFC6381CodecString(String codec) { + Matcher matcher = MP4A_RFC_6381_CODEC_PATTERN.matcher(codec); + if (!matcher.matches()) { + return null; + } + String objectTypeIndicationHex = Assertions.checkNotNull(matcher.group(1)); + @Nullable String audioObjectTypeIndicationDec = matcher.group(2); + int objectTypeIndication; + int audioObjectTypeIndication = 0; + try { + objectTypeIndication = Integer.parseInt(objectTypeIndicationHex, 16); + if (audioObjectTypeIndicationDec != null) { + audioObjectTypeIndication = Integer.parseInt(audioObjectTypeIndicationDec); + } + } catch (NumberFormatException e) { + return null; + } + return new Mp4aObjectType(objectTypeIndication, audioObjectTypeIndication); + } + + /** An MP4A Object Type Indication (OTI) and its optional audio OTI is defined by RFC 6381. */ + @VisibleForTesting + /* package */ static final class Mp4aObjectType { + /** The Object Type Indication of the MP4A codec. */ + public final int objectTypeIndication; + /** The Audio Object Type Indication of the MP4A codec, or 0 if it is absent. */ + @AacUtil.AacAudioObjectType public final int audioObjectTypeIndication; + + public Mp4aObjectType(int objectTypeIndication, int audioObjectTypeIndication) { + this.objectTypeIndication = objectTypeIndication; + this.audioObjectTypeIndication = audioObjectTypeIndication; + } + } + private static final class CustomMimeType { public final String mimeType; public final String codecPrefix;