public final class

MimeTypes

extends java.lang.Object

 java.lang.Object

↳androidx.media3.common.MimeTypes

Gradle dependencies

compile group: 'androidx.media3', name: 'media3-common', version: '1.5.0-alpha01'

  • groupId: androidx.media3
  • artifactId: media3-common
  • version: 1.5.0-alpha01

Artifact androidx.media3:media3-common:1.5.0-alpha01 it located at Google repository (https://maven.google.com/)

Overview

Defines common MIME types and helper methods.

Summary

Fields
public static final java.lang.StringAPPLICATION_AIT

public static final java.lang.StringAPPLICATION_CAMERA_MOTION

public static final java.lang.StringAPPLICATION_CEA608

public static final java.lang.StringAPPLICATION_CEA708

public static final java.lang.StringAPPLICATION_DEPTH_METADATA

public static final java.lang.StringAPPLICATION_DVBSUBS

public static final java.lang.StringAPPLICATION_EMSG

public static final java.lang.StringAPPLICATION_EXIF

public static final java.lang.StringAPPLICATION_EXTERNALLY_LOADED_IMAGE

MIME type for an image URI loaded from an external image management framework.

public static final java.lang.StringAPPLICATION_ICY

public static final java.lang.StringAPPLICATION_ID3

public static final java.lang.StringAPPLICATION_M3U8

public static final java.lang.StringAPPLICATION_MATROSKA

public static final java.lang.StringAPPLICATION_MEDIA3_CUES

public static final java.lang.StringAPPLICATION_MP4

public static final java.lang.StringAPPLICATION_MP4CEA608

public static final java.lang.StringAPPLICATION_MP4VTT

public static final java.lang.StringAPPLICATION_MPD

public static final java.lang.StringAPPLICATION_PGS

public static final java.lang.StringAPPLICATION_RAWCC

public static final java.lang.StringAPPLICATION_RTSP

public static final java.lang.StringAPPLICATION_SCTE35

public static final java.lang.StringAPPLICATION_SDP

public static final java.lang.StringAPPLICATION_SS

public static final java.lang.StringAPPLICATION_SUBRIP

public static final java.lang.StringAPPLICATION_TTML

public static final java.lang.StringAPPLICATION_TX3G

public static final java.lang.StringAPPLICATION_VOBSUB

public static final java.lang.StringAPPLICATION_WEBM

public static final java.lang.StringAUDIO_AAC

public static final java.lang.StringAUDIO_AC3

public static final java.lang.StringAUDIO_AC4

public static final java.lang.StringAUDIO_ALAC

public static final java.lang.StringAUDIO_ALAW

public static final java.lang.StringAUDIO_AMR

public static final java.lang.StringAUDIO_AMR_NB

public static final java.lang.StringAUDIO_AMR_WB

public static final java.lang.StringAUDIO_DTS

public static final java.lang.StringAUDIO_DTS_EXPRESS

public static final java.lang.StringAUDIO_DTS_HD

public static final java.lang.StringAUDIO_DTS_X

public static final java.lang.StringAUDIO_E_AC3

public static final java.lang.StringAUDIO_E_AC3_JOC

public static final java.lang.StringAUDIO_EXOPLAYER_MIDI

public static final java.lang.StringAUDIO_FLAC

public static final java.lang.StringAUDIO_IAMF

public static final java.lang.StringAUDIO_MATROSKA

public static final java.lang.StringAUDIO_MIDI

public static final java.lang.StringAUDIO_MLAW

public static final java.lang.StringAUDIO_MP4

public static final java.lang.StringAUDIO_MPEG

public static final java.lang.StringAUDIO_MPEG_L1

public static final java.lang.StringAUDIO_MPEG_L2

public static final java.lang.StringAUDIO_MPEGH_MHA1

public static final java.lang.StringAUDIO_MPEGH_MHM1

public static final java.lang.StringAUDIO_MSGSM

public static final java.lang.StringAUDIO_OGG

public static final java.lang.StringAUDIO_OPUS

public static final java.lang.StringAUDIO_RAW

public static final java.lang.StringAUDIO_TRUEHD

public static final java.lang.StringAUDIO_UNKNOWN

public static final java.lang.StringAUDIO_VORBIS

public static final java.lang.StringAUDIO_WAV

public static final java.lang.StringAUDIO_WEBM

public static final java.lang.StringBASE_TYPE_APPLICATION

public static final java.lang.StringBASE_TYPE_AUDIO

public static final java.lang.StringBASE_TYPE_IMAGE

public static final java.lang.StringBASE_TYPE_TEXT

public static final java.lang.StringBASE_TYPE_VIDEO

public static final java.lang.StringCODEC_E_AC3_JOC

A non-standard codec string for E-AC3-JOC.

public static final java.lang.StringIMAGE_AVIF

public static final java.lang.StringIMAGE_BMP

public static final java.lang.StringIMAGE_HEIC

public static final java.lang.StringIMAGE_HEIF

public static final java.lang.StringIMAGE_JPEG

public static final java.lang.StringIMAGE_JPEG_R

public static final java.lang.StringIMAGE_PNG

public static final java.lang.StringIMAGE_RAW

public static final java.lang.StringIMAGE_WEBP

public static final java.lang.StringTEXT_SSA

public static final java.lang.StringTEXT_UNKNOWN

public static final java.lang.StringTEXT_VTT

public static final java.lang.StringVIDEO_AV1

public static final java.lang.StringVIDEO_AVI

public static final java.lang.StringVIDEO_DIVX

public static final java.lang.StringVIDEO_DOLBY_VISION

public static final java.lang.StringVIDEO_FLV

public static final java.lang.StringVIDEO_H263

public static final java.lang.StringVIDEO_H264

public static final java.lang.StringVIDEO_H265

public static final java.lang.StringVIDEO_MATROSKA

public static final java.lang.StringVIDEO_MJPEG

public static final java.lang.StringVIDEO_MP2T

public static final java.lang.StringVIDEO_MP4

public static final java.lang.StringVIDEO_MP42

public static final java.lang.StringVIDEO_MP43

public static final java.lang.StringVIDEO_MP4V

public static final java.lang.StringVIDEO_MPEG

public static final java.lang.StringVIDEO_MPEG2

public static final java.lang.StringVIDEO_MV_HEVC

public static final java.lang.StringVIDEO_OGG

public static final java.lang.StringVIDEO_PS

public static final java.lang.StringVIDEO_RAW

public static final java.lang.StringVIDEO_UNKNOWN

public static final java.lang.StringVIDEO_VC1

public static final java.lang.StringVIDEO_VP8

public static final java.lang.StringVIDEO_VP9

public static final java.lang.StringVIDEO_WEBM

Methods
public static booleanallSamplesAreSyncSamples(java.lang.String mimeType, java.lang.String codec)

Returns true if it is known that all samples in a stream of the given MIME type and codec are guaranteed to be sync samples (i.e., C.BUFFER_FLAG_KEY_FRAME is guaranteed to be set on every sample) and the inherent duration of each sample is negligible (i.e., we never expect to require a sample because playback partially falls into its duration).

public static booleancontainsCodecsCorrespondingToMimeType(java.lang.String codecs, java.lang.String mimeType)

Returns whether the given codecs string contains a codec which corresponds to the given mimeType.

public static java.lang.StringgetAudioMediaMimeType(java.lang.String codecs)

Returns the first audio MIME type derived from an RFC 6381 codecs string.

public static java.lang.StringgetCodecsCorrespondingToMimeType(java.lang.String codecs, java.lang.String mimeType)

Returns a subsequence of codecs containing the codec strings that correspond to the given mimeType.

public static intgetEncoding(java.lang.String mimeType, java.lang.String codec)

Returns the C.Encoding constant corresponding to the specified audio MIME type and RFC 6381 codec string, or C.ENCODING_INVALID if the corresponding C.Encoding cannot be determined.

public static java.lang.StringgetMediaMimeType(java.lang.String codec)

Returns the MIME type corresponding to an RFC 6381 codec string, or null if it could not be determined.

public static java.lang.StringgetMimeTypeFromMp4ObjectType(int objectType)

Returns the MIME type corresponding to an MP4 object type identifier, as defined in RFC 6381 and https://mp4ra.org/#/object_types.

public static java.lang.BytegetMp4ObjectTypeFromMimeType(java.lang.String sampleMimeType)

Returns the MP4 object type identifier corresponding to a MIME type, as defined in RFC 6381 and MPEG-4 Object Types.

public static java.lang.StringgetTextMediaMimeType(java.lang.String codecs)

Returns the first text MIME type derived from an RFC 6381 codecs string.

public static intgetTrackType(java.lang.String mimeType)

Returns the track type constant corresponding to a specified MIME type, which may be C.TRACK_TYPE_UNKNOWN if it could not be determined.

public static intgetTrackTypeOfCodec(java.lang.String codec)

Equivalent to getTrackType(getMediaMimeType(codec)).

public static java.lang.StringgetVideoMediaMimeType(java.lang.String codecs)

Returns the first video MIME type derived from an RFC 6381 codecs string.

public static booleanisAudio(java.lang.String mimeType)

Returns whether the given string is an audio MIME type.

public static booleanisImage(java.lang.String mimeType)

Returns whether the given string is an image MIME type.

public static booleanisMatroska(java.lang.String mimeType)

Returns whether the given mimeType is a Matroska MIME type, including WebM.

public static booleanisText(java.lang.String mimeType)

Returns whether the given string is a text MIME type, including known text types that use "application" as their base type.

public static booleanisVideo(java.lang.String mimeType)

Returns whether the given string is a video MIME type.

public static java.lang.StringnormalizeMimeType(java.lang.String mimeType)

Normalizes the MIME type provided so that equivalent MIME types are uniquely represented.

public static voidregisterCustomMimeType(java.lang.String mimeType, java.lang.String codecPrefix, int trackType)

Registers a custom MIME type.

from java.lang.Objectclone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait

Fields

public static final java.lang.String BASE_TYPE_VIDEO

public static final java.lang.String BASE_TYPE_AUDIO

public static final java.lang.String BASE_TYPE_TEXT

public static final java.lang.String BASE_TYPE_IMAGE

public static final java.lang.String BASE_TYPE_APPLICATION

public static final java.lang.String VIDEO_MP4

public static final java.lang.String VIDEO_MATROSKA

public static final java.lang.String VIDEO_WEBM

public static final java.lang.String VIDEO_H263

public static final java.lang.String VIDEO_H264

public static final java.lang.String VIDEO_H265

public static final java.lang.String VIDEO_VP8

public static final java.lang.String VIDEO_VP9

public static final java.lang.String VIDEO_AV1

public static final java.lang.String VIDEO_MP2T

public static final java.lang.String VIDEO_MP4V

public static final java.lang.String VIDEO_MPEG

public static final java.lang.String VIDEO_PS

public static final java.lang.String VIDEO_MPEG2

public static final java.lang.String VIDEO_VC1

public static final java.lang.String VIDEO_DIVX

public static final java.lang.String VIDEO_FLV

public static final java.lang.String VIDEO_DOLBY_VISION

public static final java.lang.String VIDEO_OGG

public static final java.lang.String VIDEO_AVI

public static final java.lang.String VIDEO_MJPEG

public static final java.lang.String VIDEO_MP42

public static final java.lang.String VIDEO_MP43

public static final java.lang.String VIDEO_MV_HEVC

public static final java.lang.String VIDEO_RAW

public static final java.lang.String VIDEO_UNKNOWN

public static final java.lang.String AUDIO_MP4

public static final java.lang.String AUDIO_AAC

public static final java.lang.String AUDIO_MATROSKA

public static final java.lang.String AUDIO_WEBM

public static final java.lang.String AUDIO_MPEG

public static final java.lang.String AUDIO_MPEG_L1

public static final java.lang.String AUDIO_MPEG_L2

public static final java.lang.String AUDIO_MPEGH_MHA1

public static final java.lang.String AUDIO_MPEGH_MHM1

public static final java.lang.String AUDIO_RAW

public static final java.lang.String AUDIO_ALAW

public static final java.lang.String AUDIO_MLAW

public static final java.lang.String AUDIO_AC3

public static final java.lang.String AUDIO_E_AC3

public static final java.lang.String AUDIO_E_AC3_JOC

public static final java.lang.String AUDIO_AC4

public static final java.lang.String AUDIO_TRUEHD

public static final java.lang.String AUDIO_DTS

public static final java.lang.String AUDIO_DTS_HD

public static final java.lang.String AUDIO_DTS_EXPRESS

public static final java.lang.String AUDIO_DTS_X

public static final java.lang.String AUDIO_VORBIS

public static final java.lang.String AUDIO_OPUS

public static final java.lang.String AUDIO_AMR

public static final java.lang.String AUDIO_AMR_NB

public static final java.lang.String AUDIO_AMR_WB

public static final java.lang.String AUDIO_FLAC

public static final java.lang.String AUDIO_ALAC

public static final java.lang.String AUDIO_MSGSM

public static final java.lang.String AUDIO_OGG

public static final java.lang.String AUDIO_WAV

public static final java.lang.String AUDIO_MIDI

public static final java.lang.String AUDIO_IAMF

public static final java.lang.String AUDIO_EXOPLAYER_MIDI

public static final java.lang.String AUDIO_UNKNOWN

public static final java.lang.String TEXT_VTT

public static final java.lang.String TEXT_SSA

public static final java.lang.String TEXT_UNKNOWN

public static final java.lang.String APPLICATION_MP4

public static final java.lang.String APPLICATION_WEBM

public static final java.lang.String APPLICATION_MATROSKA

public static final java.lang.String APPLICATION_MPD

public static final java.lang.String APPLICATION_M3U8

public static final java.lang.String APPLICATION_SS

public static final java.lang.String APPLICATION_ID3

public static final java.lang.String APPLICATION_CEA608

public static final java.lang.String APPLICATION_CEA708

public static final java.lang.String APPLICATION_SUBRIP

public static final java.lang.String APPLICATION_TTML

public static final java.lang.String APPLICATION_TX3G

public static final java.lang.String APPLICATION_MP4VTT

public static final java.lang.String APPLICATION_MP4CEA608

public static final java.lang.String APPLICATION_RAWCC

Deprecated: RawCC is a Google-internal subtitle format that isn't supported by this version of Media3. There is no replacement for this value.

public static final java.lang.String APPLICATION_VOBSUB

public static final java.lang.String APPLICATION_PGS

public static final java.lang.String APPLICATION_SCTE35

public static final java.lang.String APPLICATION_SDP

public static final java.lang.String APPLICATION_CAMERA_MOTION

public static final java.lang.String APPLICATION_DEPTH_METADATA

public static final java.lang.String APPLICATION_EMSG

public static final java.lang.String APPLICATION_DVBSUBS

public static final java.lang.String APPLICATION_EXIF

public static final java.lang.String APPLICATION_ICY

public static final java.lang.String APPLICATION_AIT

public static final java.lang.String APPLICATION_RTSP

public static final java.lang.String APPLICATION_MEDIA3_CUES

public static final java.lang.String APPLICATION_EXTERNALLY_LOADED_IMAGE

MIME type for an image URI loaded from an external image management framework.

public static final java.lang.String IMAGE_JPEG

public static final java.lang.String IMAGE_JPEG_R

public static final java.lang.String IMAGE_PNG

public static final java.lang.String IMAGE_HEIF

public static final java.lang.String IMAGE_HEIC

public static final java.lang.String IMAGE_AVIF

public static final java.lang.String IMAGE_BMP

public static final java.lang.String IMAGE_WEBP

public static final java.lang.String IMAGE_RAW

public static final java.lang.String CODEC_E_AC3_JOC

A non-standard codec string for E-AC3-JOC. Use of this constant allows for disambiguation between regular E-AC3 ("ec-3") and E-AC3-JOC ("ec+3") streams from the codec string alone. The standard is to use "ec-3" for both, as per the MP4RA registered codec types.

Methods

public static void registerCustomMimeType(java.lang.String mimeType, java.lang.String codecPrefix, int trackType)

Registers a custom MIME type. Most applications do not need to call this method, as handling of standard MIME types is built in. These built-in MIME types take precedence over any registered via this method. If this method is used, it must be called before creating any player(s).

Parameters:

mimeType: The custom MIME type to register.
codecPrefix: The RFC 6381 codec string prefix associated with the MIME type.
trackType: The track type associated with the MIME type. This value is ignored if the top-level type of mimeType is audio, video or text.

public static boolean isAudio(java.lang.String mimeType)

Returns whether the given string is an audio MIME type.

public static boolean isVideo(java.lang.String mimeType)

Returns whether the given string is a video MIME type.

public static boolean isText(java.lang.String mimeType)

Returns whether the given string is a text MIME type, including known text types that use "application" as their base type.

public static boolean isImage(java.lang.String mimeType)

Returns whether the given string is an image MIME type.

public static boolean allSamplesAreSyncSamples(java.lang.String mimeType, java.lang.String codec)

Returns true if it is known that all samples in a stream of the given MIME type and codec are guaranteed to be sync samples (i.e., C.BUFFER_FLAG_KEY_FRAME is guaranteed to be set on every sample) and the inherent duration of each sample is negligible (i.e., we never expect to require a sample because playback partially falls into its duration).

Parameters:

mimeType: The MIME type of the stream.
codec: The RFC 6381 codec string of the stream, or null if unknown.

Returns:

Whether it is known that all samples in the stream are guaranteed to be sync samples.

public static java.lang.String getVideoMediaMimeType(java.lang.String codecs)

Returns the first video MIME type derived from an RFC 6381 codecs string.

Parameters:

codecs: An RFC 6381 codecs string.

Returns:

The first derived video MIME type, or null.

public static boolean containsCodecsCorrespondingToMimeType(java.lang.String codecs, java.lang.String mimeType)

Returns whether the given codecs string contains a codec which corresponds to the given mimeType.

Parameters:

codecs: An RFC 6381 codecs string.
mimeType: A MIME type to look for.

Returns:

Whether the given codecs string contains a codec which corresponds to the given mimeType.

public static java.lang.String getCodecsCorrespondingToMimeType(java.lang.String codecs, java.lang.String mimeType)

Returns a subsequence of codecs containing the codec strings that correspond to the given mimeType. Returns null if mimeType is null, codecs is null, or codecs does not contain a codec that corresponds to mimeType.

Parameters:

codecs: An RFC 6381 codecs string.
mimeType: A MIME type to look for.

Returns:

A subsequence of codecs containing the codec strings that correspond to the given mimeType. Returns null if mimeType is null, codecs is null, or codecs does not contain a codec that corresponds to mimeType.

public static java.lang.String getAudioMediaMimeType(java.lang.String codecs)

Returns the first audio MIME type derived from an RFC 6381 codecs string.

Parameters:

codecs: An RFC 6381 codecs string.

Returns:

The first derived audio MIME type, or null.

public static java.lang.String getTextMediaMimeType(java.lang.String codecs)

Returns the first text MIME type derived from an RFC 6381 codecs string.

Parameters:

codecs: An RFC 6381 codecs string.

Returns:

The first derived text MIME type, or null.

public static java.lang.String getMediaMimeType(java.lang.String codec)

Returns the MIME type corresponding to an RFC 6381 codec string, or null if it could not be determined.

Parameters:

codec: An RFC 6381 codec string.

Returns:

The corresponding MIME type, or null if it could not be determined.

public static java.lang.Byte getMp4ObjectTypeFromMimeType(java.lang.String sampleMimeType)

Returns the MP4 object type identifier corresponding to a MIME type, as defined in RFC 6381 and MPEG-4 Object Types.

Parameters:

sampleMimeType: The MIME type of the track.

Returns:

The corresponding MP4 object type identifier, or null if it could not be determined.

public static java.lang.String getMimeTypeFromMp4ObjectType(int objectType)

Returns the MIME type corresponding to an MP4 object type identifier, as defined in RFC 6381 and https://mp4ra.org/#/object_types.

Parameters:

objectType: An MP4 object type identifier.

Returns:

The corresponding MIME type, or null if it could not be determined.

public static int getTrackType(java.lang.String mimeType)

Returns the track type constant corresponding to a specified MIME type, which may be C.TRACK_TYPE_UNKNOWN if it could not be determined.

Parameters:

mimeType: A MIME type.

Returns:

The corresponding track type, which may be C.TRACK_TYPE_UNKNOWN if it could not be determined.

public static int getEncoding(java.lang.String mimeType, java.lang.String codec)

Returns the C.Encoding constant corresponding to the specified audio MIME type and RFC 6381 codec string, or C.ENCODING_INVALID if the corresponding C.Encoding cannot be determined.

Parameters:

mimeType: A MIME type.
codec: An RFC 6381 codec string, or null if unknown or not applicable.

Returns:

The corresponding C.Encoding, or C.ENCODING_INVALID.

public static int getTrackTypeOfCodec(java.lang.String codec)

Equivalent to getTrackType(getMediaMimeType(codec)).

Parameters:

codec: An RFC 6381 codec string.

Returns:

The corresponding track type, which may be C.TRACK_TYPE_UNKNOWN if it could not be determined.

public static java.lang.String normalizeMimeType(java.lang.String mimeType)

Normalizes the MIME type provided so that equivalent MIME types are uniquely represented.

Parameters:

mimeType: A MIME type to normalize, or null.

Returns:

The normalized MIME type, or the argument MIME type if its normalized form is unknown.

public static boolean isMatroska(java.lang.String mimeType)

Returns whether the given mimeType is a Matroska MIME type, including WebM.

Source

/*
 * Copyright (C) 2016 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package androidx.media3.common;

import android.text.TextUtils;
import androidx.annotation.Nullable;
import androidx.annotation.VisibleForTesting;
import androidx.media3.common.util.Assertions;
import androidx.media3.common.util.UnstableApi;
import androidx.media3.common.util.Util;
import com.google.common.base.Ascii;
import java.util.ArrayList;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.checkerframework.checker.nullness.qual.PolyNull;
import org.checkerframework.dataflow.qual.Pure;

/** Defines common MIME types and helper methods. */
public final class MimeTypes {

  @UnstableApi public static final String BASE_TYPE_VIDEO = "video";
  @UnstableApi public static final String BASE_TYPE_AUDIO = "audio";
  @UnstableApi public static final String BASE_TYPE_TEXT = "text";
  @UnstableApi public static final String BASE_TYPE_IMAGE = "image";
  @UnstableApi public static final String BASE_TYPE_APPLICATION = "application";

  // video/ MIME types

  public static final String VIDEO_MP4 = BASE_TYPE_VIDEO + "/mp4";
  @UnstableApi public static final String VIDEO_MATROSKA = BASE_TYPE_VIDEO + "/x-matroska";
  public static final String VIDEO_WEBM = BASE_TYPE_VIDEO + "/webm";
  public static final String VIDEO_H263 = BASE_TYPE_VIDEO + "/3gpp";
  public static final String VIDEO_H264 = BASE_TYPE_VIDEO + "/avc";
  public static final String VIDEO_H265 = BASE_TYPE_VIDEO + "/hevc";
  @UnstableApi public static final String VIDEO_VP8 = BASE_TYPE_VIDEO + "/x-vnd.on2.vp8";
  @UnstableApi public static final String VIDEO_VP9 = BASE_TYPE_VIDEO + "/x-vnd.on2.vp9";
  public static final String VIDEO_AV1 = BASE_TYPE_VIDEO + "/av01";
  public static final String VIDEO_MP2T = BASE_TYPE_VIDEO + "/mp2t";
  public static final String VIDEO_MP4V = BASE_TYPE_VIDEO + "/mp4v-es";
  public static final String VIDEO_MPEG = BASE_TYPE_VIDEO + "/mpeg";
  public static final String VIDEO_PS = BASE_TYPE_VIDEO + "/mp2p";
  public static final String VIDEO_MPEG2 = BASE_TYPE_VIDEO + "/mpeg2";
  public static final String VIDEO_VC1 = BASE_TYPE_VIDEO + "/wvc1";
  public static final String VIDEO_DIVX = BASE_TYPE_VIDEO + "/divx";
  @UnstableApi public static final String VIDEO_FLV = BASE_TYPE_VIDEO + "/x-flv";
  public static final String VIDEO_DOLBY_VISION = BASE_TYPE_VIDEO + "/dolby-vision";
  public static final String VIDEO_OGG = BASE_TYPE_VIDEO + "/ogg";
  public static final String VIDEO_AVI = BASE_TYPE_VIDEO + "/x-msvideo";
  public static final String VIDEO_MJPEG = BASE_TYPE_VIDEO + "/mjpeg";
  public static final String VIDEO_MP42 = BASE_TYPE_VIDEO + "/mp42";
  public static final String VIDEO_MP43 = BASE_TYPE_VIDEO + "/mp43";
  @UnstableApi public static final String VIDEO_MV_HEVC = BASE_TYPE_VIDEO + "/mv-hevc";
  @UnstableApi public static final String VIDEO_RAW = BASE_TYPE_VIDEO + "/raw";
  @UnstableApi public static final String VIDEO_UNKNOWN = BASE_TYPE_VIDEO + "/x-unknown";

  // audio/ MIME types

  public static final String AUDIO_MP4 = BASE_TYPE_AUDIO + "/mp4";
  public static final String AUDIO_AAC = BASE_TYPE_AUDIO + "/mp4a-latm";
  @UnstableApi public static final String AUDIO_MATROSKA = BASE_TYPE_AUDIO + "/x-matroska";
  public static final String AUDIO_WEBM = BASE_TYPE_AUDIO + "/webm";
  public static final String AUDIO_MPEG = BASE_TYPE_AUDIO + "/mpeg";
  public static final String AUDIO_MPEG_L1 = BASE_TYPE_AUDIO + "/mpeg-L1";
  public static final String AUDIO_MPEG_L2 = BASE_TYPE_AUDIO + "/mpeg-L2";
  public static final String AUDIO_MPEGH_MHA1 = BASE_TYPE_AUDIO + "/mha1";
  public static final String AUDIO_MPEGH_MHM1 = BASE_TYPE_AUDIO + "/mhm1";
  public static final String AUDIO_RAW = BASE_TYPE_AUDIO + "/raw";
  public static final String AUDIO_ALAW = BASE_TYPE_AUDIO + "/g711-alaw";
  public static final String AUDIO_MLAW = BASE_TYPE_AUDIO + "/g711-mlaw";
  public static final String AUDIO_AC3 = BASE_TYPE_AUDIO + "/ac3";
  public static final String AUDIO_E_AC3 = BASE_TYPE_AUDIO + "/eac3";
  public static final String AUDIO_E_AC3_JOC = BASE_TYPE_AUDIO + "/eac3-joc";
  public static final String AUDIO_AC4 = BASE_TYPE_AUDIO + "/ac4";
  public static final String AUDIO_TRUEHD = BASE_TYPE_AUDIO + "/true-hd";
  public static final String AUDIO_DTS = BASE_TYPE_AUDIO + "/vnd.dts";
  public static final String AUDIO_DTS_HD = BASE_TYPE_AUDIO + "/vnd.dts.hd";
  public static final String AUDIO_DTS_EXPRESS = BASE_TYPE_AUDIO + "/vnd.dts.hd;profile=lbr";
  @UnstableApi public static final String AUDIO_DTS_X = BASE_TYPE_AUDIO + "/vnd.dts.uhd;profile=p2";
  public static final String AUDIO_VORBIS = BASE_TYPE_AUDIO + "/vorbis";
  public static final String AUDIO_OPUS = BASE_TYPE_AUDIO + "/opus";
  public static final String AUDIO_AMR = BASE_TYPE_AUDIO + "/amr";
  public static final String AUDIO_AMR_NB = BASE_TYPE_AUDIO + "/3gpp";
  public static final String AUDIO_AMR_WB = BASE_TYPE_AUDIO + "/amr-wb";
  public static final String AUDIO_FLAC = BASE_TYPE_AUDIO + "/flac";
  public static final String AUDIO_ALAC = BASE_TYPE_AUDIO + "/alac";
  public static final String AUDIO_MSGSM = BASE_TYPE_AUDIO + "/gsm";
  public static final String AUDIO_OGG = BASE_TYPE_AUDIO + "/ogg";
  public static final String AUDIO_WAV = BASE_TYPE_AUDIO + "/wav";
  public static final String AUDIO_MIDI = BASE_TYPE_AUDIO + "/midi";
  @UnstableApi public static final String AUDIO_IAMF = BASE_TYPE_AUDIO + "/iamf";

  @UnstableApi
  public static final String AUDIO_EXOPLAYER_MIDI = BASE_TYPE_AUDIO + "/x-exoplayer-midi";

  @UnstableApi public static final String AUDIO_UNKNOWN = BASE_TYPE_AUDIO + "/x-unknown";

  // text/ MIME types

  public static final String TEXT_VTT = BASE_TYPE_TEXT + "/vtt";
  public static final String TEXT_SSA = BASE_TYPE_TEXT + "/x-ssa";
  @UnstableApi public static final String TEXT_UNKNOWN = BASE_TYPE_TEXT + "/x-unknown";

  // application/ MIME types

  public static final String APPLICATION_MP4 = BASE_TYPE_APPLICATION + "/mp4";
  public static final String APPLICATION_WEBM = BASE_TYPE_APPLICATION + "/webm";

  public static final String APPLICATION_MATROSKA = BASE_TYPE_APPLICATION + "/x-matroska";

  public static final String APPLICATION_MPD = BASE_TYPE_APPLICATION + "/dash+xml";
  public static final String APPLICATION_M3U8 = BASE_TYPE_APPLICATION + "/x-mpegURL";
  public static final String APPLICATION_SS = BASE_TYPE_APPLICATION + "/vnd.ms-sstr+xml";
  public static final String APPLICATION_ID3 = BASE_TYPE_APPLICATION + "/id3";
  public static final String APPLICATION_CEA608 = BASE_TYPE_APPLICATION + "/cea-608";
  public static final String APPLICATION_CEA708 = BASE_TYPE_APPLICATION + "/cea-708";
  public static final String APPLICATION_SUBRIP = BASE_TYPE_APPLICATION + "/x-subrip";
  public static final String APPLICATION_TTML = BASE_TYPE_APPLICATION + "/ttml+xml";
  public static final String APPLICATION_TX3G = BASE_TYPE_APPLICATION + "/x-quicktime-tx3g";
  public static final String APPLICATION_MP4VTT = BASE_TYPE_APPLICATION + "/x-mp4-vtt";
  public static final String APPLICATION_MP4CEA608 = BASE_TYPE_APPLICATION + "/x-mp4-cea-608";

  /**
   * @deprecated RawCC is a Google-internal subtitle format that isn't supported by this version of
   *     Media3. There is no replacement for this value.
   */
  @Deprecated public static final String APPLICATION_RAWCC = BASE_TYPE_APPLICATION + "/x-rawcc";

  public static final String APPLICATION_VOBSUB = BASE_TYPE_APPLICATION + "/vobsub";
  public static final String APPLICATION_PGS = BASE_TYPE_APPLICATION + "/pgs";
  @UnstableApi public static final String APPLICATION_SCTE35 = BASE_TYPE_APPLICATION + "/x-scte35";
  public static final String APPLICATION_SDP = BASE_TYPE_APPLICATION + "/sdp";

  @UnstableApi
  public static final String APPLICATION_CAMERA_MOTION = BASE_TYPE_APPLICATION + "/x-camera-motion";

  @UnstableApi
  public static final String APPLICATION_DEPTH_METADATA =
      BASE_TYPE_APPLICATION + "/x-depth-metadata";

  @UnstableApi public static final String APPLICATION_EMSG = BASE_TYPE_APPLICATION + "/x-emsg";
  public static final String APPLICATION_DVBSUBS = BASE_TYPE_APPLICATION + "/dvbsubs";
  @UnstableApi public static final String APPLICATION_EXIF = BASE_TYPE_APPLICATION + "/x-exif";
  @UnstableApi public static final String APPLICATION_ICY = BASE_TYPE_APPLICATION + "/x-icy";
  public static final String APPLICATION_AIT = BASE_TYPE_APPLICATION + "/vnd.dvb.ait";
  public static final String APPLICATION_RTSP = BASE_TYPE_APPLICATION + "/x-rtsp";

  @UnstableApi
  public static final String APPLICATION_MEDIA3_CUES = BASE_TYPE_APPLICATION + "/x-media3-cues";

  /** MIME type for an image URI loaded from an external image management framework. */
  @UnstableApi
  public static final String APPLICATION_EXTERNALLY_LOADED_IMAGE =
      BASE_TYPE_APPLICATION + "/x-image-uri";

  // image/ MIME types

  public static final String IMAGE_JPEG = BASE_TYPE_IMAGE + "/jpeg";
  @UnstableApi public static final String IMAGE_JPEG_R = BASE_TYPE_IMAGE + "/jpeg_r";
  @UnstableApi public static final String IMAGE_PNG = BASE_TYPE_IMAGE + "/png";
  @UnstableApi public static final String IMAGE_HEIF = BASE_TYPE_IMAGE + "/heif";
  @UnstableApi public static final String IMAGE_HEIC = BASE_TYPE_IMAGE + "/heic";
  @UnstableApi public static final String IMAGE_AVIF = BASE_TYPE_IMAGE + "/avif";
  @UnstableApi public static final String IMAGE_BMP = BASE_TYPE_IMAGE + "/bmp";
  @UnstableApi public static final String IMAGE_WEBP = BASE_TYPE_IMAGE + "/webp";
  @UnstableApi public static final String IMAGE_RAW = BASE_TYPE_IMAGE + "/raw";

  /**
   * A non-standard codec string for E-AC3-JOC. Use of this constant allows for disambiguation
   * between regular E-AC3 ("ec-3") and E-AC3-JOC ("ec+3") streams from the codec string alone. The
   * standard is to use "ec-3" for both, as per the <a href="https://mp4ra.org/#/codecs">MP4RA
   * registered codec types</a>.
   */
  @UnstableApi public static final String CODEC_E_AC3_JOC = "ec+3";

  private static final ArrayList<CustomMimeType> customMimeTypes = new ArrayList<>();

  private static final Pattern MP4A_RFC_6381_CODEC_PATTERN =
      Pattern.compile("^mp4a\\.([a-zA-Z0-9]{2})(?:\\.([0-9]{1,2}))?$");

  /**
   * Registers a custom MIME type. Most applications do not need to call this method, as handling of
   * standard MIME types is built in. These built-in MIME types take precedence over any registered
   * 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 codec string prefix associated with the MIME type.
   * @param trackType The {@link C.TrackType track type} associated with the MIME type. This value
   *     is ignored if the top-level type of {@code mimeType} is audio, video or text.
   */
  @UnstableApi
  public static void registerCustomMimeType(
      String mimeType, String codecPrefix, @C.TrackType int trackType) {
    CustomMimeType customMimeType = new CustomMimeType(mimeType, codecPrefix, trackType);
    int customMimeTypeCount = customMimeTypes.size();
    for (int i = 0; i < customMimeTypeCount; i++) {
      if (mimeType.equals(customMimeTypes.get(i).mimeType)) {
        customMimeTypes.remove(i);
        break;
      }
    }
    customMimeTypes.add(customMimeType);
  }

  /** Returns whether the given string is an audio MIME type. */
  @UnstableApi
  public static boolean isAudio(@Nullable String mimeType) {
    return BASE_TYPE_AUDIO.equals(getTopLevelType(mimeType));
  }

  /** Returns whether the given string is a video MIME type. */
  @UnstableApi
  public static boolean isVideo(@Nullable String mimeType) {
    return BASE_TYPE_VIDEO.equals(getTopLevelType(mimeType));
  }

  /**
   * Returns whether the given string is a text MIME type, including known text types that use
   * &quot;application&quot; as their base type.
   */
  @SuppressWarnings("deprecation") // Supporting deprecated MIME types
  @UnstableApi
  @Pure
  public static boolean isText(@Nullable String mimeType) {
    return BASE_TYPE_TEXT.equals(getTopLevelType(mimeType))
        || APPLICATION_MEDIA3_CUES.equals(mimeType)
        || APPLICATION_CEA608.equals(mimeType)
        || APPLICATION_CEA708.equals(mimeType)
        || APPLICATION_MP4CEA608.equals(mimeType)
        || APPLICATION_SUBRIP.equals(mimeType)
        || APPLICATION_TTML.equals(mimeType)
        || APPLICATION_TX3G.equals(mimeType)
        || APPLICATION_MP4VTT.equals(mimeType)
        || APPLICATION_RAWCC.equals(mimeType)
        || APPLICATION_VOBSUB.equals(mimeType)
        || APPLICATION_PGS.equals(mimeType)
        || APPLICATION_DVBSUBS.equals(mimeType);
  }

  /** Returns whether the given string is an image MIME type. */
  @UnstableApi
  public static boolean isImage(@Nullable String mimeType) {
    return BASE_TYPE_IMAGE.equals(getTopLevelType(mimeType))
        || APPLICATION_EXTERNALLY_LOADED_IMAGE.equals(mimeType);
  }

  /**
   * Returns true if it is known that all samples in a stream of the given MIME type and codec are
   * guaranteed to be sync samples (i.e., {@link C#BUFFER_FLAG_KEY_FRAME} is guaranteed to be set on
   * every sample) and the inherent duration of each sample is negligible (i.e., we never expect to
   * require a sample because playback partially falls into its duration).
   *
   * @param mimeType The MIME type of the stream.
   * @param codec The RFC 6381 codec string of the stream, or {@code null} if unknown.
   * @return Whether it is known that all samples in the stream are guaranteed to be sync samples.
   */
  @UnstableApi
  public static boolean allSamplesAreSyncSamples(
      @Nullable String mimeType, @Nullable String codec) {
    if (mimeType == null) {
      return false;
    }
    // TODO: Add additional audio MIME types. Also consider evaluating based on Format rather than
    // just MIME type, since in some cases the property is true for a subset of the profiles
    // belonging to a single MIME type. If we do this, we should move the method to a different
    // class. See [Internal ref: http://go/exo-audio-format-random-access].
    switch (mimeType) {
      case AUDIO_MPEG:
      case AUDIO_MPEG_L1:
      case AUDIO_MPEG_L2:
      case AUDIO_RAW:
      case AUDIO_ALAW:
      case AUDIO_MLAW:
      case AUDIO_FLAC:
      case AUDIO_AC3:
      case AUDIO_E_AC3:
      case AUDIO_E_AC3_JOC:
        return true;
      case AUDIO_AAC:
        if (codec == null) {
          return false;
        }
        @Nullable Mp4aObjectType objectType = getObjectTypeFromMp4aRFC6381CodecString(codec);
        if (objectType == null) {
          return false;
        }
        @C.Encoding int encoding = objectType.getEncoding();
        // xHE-AAC is an exception in which it's not true that all samples will be sync samples.
        // Also return false for ENCODING_INVALID, which indicates we weren't able to parse the
        // encoding from the codec string.
        return encoding != C.ENCODING_INVALID && encoding != C.ENCODING_AAC_XHE;
      default:
        return false;
    }
  }

  /**
   * Returns the first video MIME type derived from an RFC 6381 codecs string.
   *
   * @param codecs An RFC 6381 codecs string.
   * @return The first derived video MIME type, or {@code null}.
   */
  @UnstableApi
  @Nullable
  public static String getVideoMediaMimeType(@Nullable String codecs) {
    if (codecs == null) {
      return null;
    }
    String[] codecList = Util.splitCodecs(codecs);
    for (String codec : codecList) {
      @Nullable String mimeType = getMediaMimeType(codec);
      if (mimeType != null && isVideo(mimeType)) {
        return mimeType;
      }
    }
    return null;
  }

  /**
   * Returns whether the given {@code codecs} string contains a codec which corresponds to the given
   * {@code mimeType}.
   *
   * @param codecs An RFC 6381 codecs string.
   * @param mimeType A MIME type to look for.
   * @return Whether the given {@code codecs} string contains a codec which corresponds to the given
   *     {@code mimeType}.
   */
  @UnstableApi
  public static boolean containsCodecsCorrespondingToMimeType(
      @Nullable String codecs, String mimeType) {
    return getCodecsCorrespondingToMimeType(codecs, mimeType) != null;
  }

  /**
   * Returns a subsequence of {@code codecs} containing the codec strings that correspond to the
   * given {@code mimeType}. Returns null if {@code mimeType} is null, {@code codecs} is null, or
   * {@code codecs} does not contain a codec that corresponds to {@code mimeType}.
   *
   * @param codecs An RFC 6381 codecs string.
   * @param mimeType A MIME type to look for.
   * @return A subsequence of {@code codecs} containing the codec strings that correspond to the
   *     given {@code mimeType}. Returns null if {@code mimeType} is null, {@code codecs} is null,
   *     or {@code codecs} does not contain a codec that corresponds to {@code mimeType}.
   */
  @UnstableApi
  @Nullable
  public static String getCodecsCorrespondingToMimeType(
      @Nullable String codecs, @Nullable String mimeType) {
    if (codecs == null || mimeType == null) {
      return null;
    }
    String[] codecList = Util.splitCodecs(codecs);
    StringBuilder builder = new StringBuilder();
    for (String codec : codecList) {
      if (mimeType.equals(getMediaMimeType(codec))) {
        if (builder.length() > 0) {
          builder.append(",");
        }
        builder.append(codec);
      }
    }
    return builder.length() > 0 ? builder.toString() : null;
  }

  /**
   * Returns the first audio MIME type derived from an RFC 6381 codecs string.
   *
   * @param codecs An RFC 6381 codecs string.
   * @return The first derived audio MIME type, or {@code null}.
   */
  @UnstableApi
  @Nullable
  public static String getAudioMediaMimeType(@Nullable String codecs) {
    if (codecs == null) {
      return null;
    }
    String[] codecList = Util.splitCodecs(codecs);
    for (String codec : codecList) {
      @Nullable String mimeType = getMediaMimeType(codec);
      if (mimeType != null && isAudio(mimeType)) {
        return mimeType;
      }
    }
    return null;
  }

  /**
   * Returns the first text MIME type derived from an RFC 6381 codecs string.
   *
   * @param codecs An RFC 6381 codecs string.
   * @return The first derived text MIME type, or {@code null}.
   */
  @UnstableApi
  @Nullable
  public static String getTextMediaMimeType(@Nullable String codecs) {
    if (codecs == null) {
      return null;
    }
    String[] codecList = Util.splitCodecs(codecs);
    for (String codec : codecList) {
      @Nullable String mimeType = getMediaMimeType(codec);
      if (mimeType != null && isText(mimeType)) {
        return mimeType;
      }
    }
    return null;
  }

  /**
   * Returns the MIME type corresponding to an RFC 6381 codec string, or {@code null} if it could
   * not be determined.
   *
   * @param codec An RFC 6381 codec string.
   * @return The corresponding MIME type, or {@code null} if it could not be determined.
   */
  @UnstableApi
  @Nullable
  public static String getMediaMimeType(@Nullable String codec) {
    if (codec == null) {
      return null;
    }
    codec = Ascii.toLowerCase(codec.trim());
    if (codec.startsWith("avc1") || codec.startsWith("avc3")) {
      return MimeTypes.VIDEO_H264;
    } else if (codec.startsWith("hev1") || codec.startsWith("hvc1")) {
      return MimeTypes.VIDEO_H265;
    } else if (codec.startsWith("dvav")
        || codec.startsWith("dva1")
        || codec.startsWith("dvhe")
        || codec.startsWith("dvh1")) {
      return MimeTypes.VIDEO_DOLBY_VISION;
    } else if (codec.startsWith("av01")) {
      return MimeTypes.VIDEO_AV1;
    } else if (codec.startsWith("vp9") || codec.startsWith("vp09")) {
      return MimeTypes.VIDEO_VP9;
    } else if (codec.startsWith("vp8") || codec.startsWith("vp08")) {
      return MimeTypes.VIDEO_VP8;
    } else if (codec.startsWith("mp4a")) {
      @Nullable String mimeType = null;
      if (codec.startsWith("mp4a.")) {
        @Nullable Mp4aObjectType objectType = getObjectTypeFromMp4aRFC6381CodecString(codec);
        if (objectType != null) {
          mimeType = getMimeTypeFromMp4ObjectType(objectType.objectTypeIndication);
        }
      }
      return mimeType == null ? MimeTypes.AUDIO_AAC : mimeType;
    } else if (codec.startsWith("mha1")) {
      return MimeTypes.AUDIO_MPEGH_MHA1;
    } else if (codec.startsWith("mhm1")) {
      return MimeTypes.AUDIO_MPEGH_MHM1;
    } else if (codec.startsWith("ac-3") || codec.startsWith("dac3")) {
      return MimeTypes.AUDIO_AC3;
    } else if (codec.startsWith("ec-3") || codec.startsWith("dec3")) {
      return MimeTypes.AUDIO_E_AC3;
    } else if (codec.startsWith(CODEC_E_AC3_JOC)) {
      return MimeTypes.AUDIO_E_AC3_JOC;
    } else if (codec.startsWith("ac-4") || codec.startsWith("dac4")) {
      return MimeTypes.AUDIO_AC4;
    } else if (codec.startsWith("dtsc")) {
      return MimeTypes.AUDIO_DTS;
    } else if (codec.startsWith("dtse")) {
      return MimeTypes.AUDIO_DTS_EXPRESS;
    } else if (codec.startsWith("dtsh") || codec.startsWith("dtsl")) {
      return MimeTypes.AUDIO_DTS_HD;
    } else if (codec.startsWith("dtsx")) {
      return MimeTypes.AUDIO_DTS_X;
    } else if (codec.startsWith("opus")) {
      return MimeTypes.AUDIO_OPUS;
    } else if (codec.startsWith("vorbis")) {
      return MimeTypes.AUDIO_VORBIS;
    } else if (codec.startsWith("flac")) {
      return MimeTypes.AUDIO_FLAC;
    } else if (codec.startsWith("stpp")) {
      return MimeTypes.APPLICATION_TTML;
    } else if (codec.startsWith("wvtt")) {
      return MimeTypes.TEXT_VTT;
    } else if (codec.contains("cea708")) {
      return MimeTypes.APPLICATION_CEA708;
    } else if (codec.contains("eia608") || codec.contains("cea608")) {
      return MimeTypes.APPLICATION_CEA608;
    } else {
      return getCustomMimeTypeForCodec(codec);
    }
  }

  /**
   * Returns the MP4 object type identifier corresponding to a MIME type, as defined in RFC 6381 and
   * <a href="https://mp4ra.org/registered-types/object-types">MPEG-4 Object Types</a>.
   *
   * @param sampleMimeType The MIME type of the track.
   * @return The corresponding MP4 object type identifier, or {@code null} if it could not be
   *     determined.
   */
  @UnstableApi
  @Nullable
  public static Byte getMp4ObjectTypeFromMimeType(String sampleMimeType) {
    switch (sampleMimeType) {
      case MimeTypes.AUDIO_AAC:
        return (byte) 0x40;
      case MimeTypes.AUDIO_VORBIS:
        return (byte) 0xDD;
      case MimeTypes.VIDEO_MP4V:
        return (byte) 0x20;
      default:
        return null;
    }
  }

  /**
   * Returns the MIME type corresponding to an MP4 object type identifier, as defined in RFC 6381
   * and https://mp4ra.org/#/object_types.
   *
   * @param objectType An MP4 object type identifier.
   * @return The corresponding MIME type, or {@code null} if it could not be determined.
   */
  @UnstableApi
  @Nullable
  public static String getMimeTypeFromMp4ObjectType(int objectType) {
    switch (objectType) {
      case 0x20:
        return MimeTypes.VIDEO_MP4V;
      case 0x21:
        return MimeTypes.VIDEO_H264;
      case 0x23:
        return MimeTypes.VIDEO_H265;
      case 0x60:
      case 0x61:
      case 0x62:
      case 0x63:
      case 0x64:
      case 0x65:
        return MimeTypes.VIDEO_MPEG2;
      case 0x6A:
        return MimeTypes.VIDEO_MPEG;
      case 0x69:
      case 0x6B:
        return MimeTypes.AUDIO_MPEG;
      case 0x6C:
        return MimeTypes.IMAGE_JPEG;
      case 0xA3:
        return MimeTypes.VIDEO_VC1;
      case 0xB1:
        return MimeTypes.VIDEO_VP9;
      case 0x40:
      case 0x66:
      case 0x67:
      case 0x68:
        return MimeTypes.AUDIO_AAC;
      case 0xA5:
        return MimeTypes.AUDIO_AC3;
      case 0xA6:
        return MimeTypes.AUDIO_E_AC3;
      case 0xA9:
      case 0xAC:
        return MimeTypes.AUDIO_DTS;
      case 0xAA:
      case 0xAB:
        return MimeTypes.AUDIO_DTS_HD;
      case 0xAD:
        return MimeTypes.AUDIO_OPUS;
      case 0xAE:
        return MimeTypes.AUDIO_AC4;
      case 0xDD:
        return MimeTypes.AUDIO_VORBIS;
      default:
        return null;
    }
  }

  /**
   * Returns the {@link C.TrackType track type} constant corresponding to a specified MIME type,
   * which may be {@link C#TRACK_TYPE_UNKNOWN} if it could not be determined.
   *
   * @param mimeType A MIME type.
   * @return The corresponding {@link C.TrackType track type}, which may be {@link
   *     C#TRACK_TYPE_UNKNOWN} if it could not be determined.
   */
  @UnstableApi
  public static @C.TrackType int getTrackType(@Nullable String mimeType) {
    if (TextUtils.isEmpty(mimeType)) {
      return C.TRACK_TYPE_UNKNOWN;
    } else if (isAudio(mimeType)) {
      return C.TRACK_TYPE_AUDIO;
    } else if (isVideo(mimeType)) {
      return C.TRACK_TYPE_VIDEO;
    } else if (isText(mimeType)) {
      return C.TRACK_TYPE_TEXT;
    } else if (isImage(mimeType)) {
      return C.TRACK_TYPE_IMAGE;
    } else if (APPLICATION_ID3.equals(mimeType)
        || APPLICATION_EMSG.equals(mimeType)
        || APPLICATION_SCTE35.equals(mimeType)) {
      return C.TRACK_TYPE_METADATA;
    } else if (APPLICATION_CAMERA_MOTION.equals(mimeType)) {
      return C.TRACK_TYPE_CAMERA_MOTION;
    } else {
      return getTrackTypeForCustomMimeType(mimeType);
    }
  }

  /**
   * 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 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}.
   */
  @UnstableApi
  public static @C.Encoding int getEncoding(String mimeType, @Nullable String codec) {
    switch (mimeType) {
      case MimeTypes.AUDIO_MPEG:
        return C.ENCODING_MP3;
      case MimeTypes.AUDIO_AAC:
        if (codec == null) {
          return C.ENCODING_INVALID;
        }
        @Nullable Mp4aObjectType objectType = getObjectTypeFromMp4aRFC6381CodecString(codec);
        if (objectType == null) {
          return C.ENCODING_INVALID;
        }
        return objectType.getEncoding();
      case MimeTypes.AUDIO_AC3:
        return C.ENCODING_AC3;
      case MimeTypes.AUDIO_E_AC3:
        return C.ENCODING_E_AC3;
      case MimeTypes.AUDIO_E_AC3_JOC:
        return C.ENCODING_E_AC3_JOC;
      case MimeTypes.AUDIO_AC4:
        return C.ENCODING_AC4;
      case MimeTypes.AUDIO_DTS:
        return C.ENCODING_DTS;
      case MimeTypes.AUDIO_DTS_HD:
        return C.ENCODING_DTS_HD;
      case MimeTypes.AUDIO_DTS_EXPRESS:
        return C.ENCODING_DTS_HD;
      case MimeTypes.AUDIO_DTS_X:
        return C.ENCODING_DTS_UHD_P2;
      case MimeTypes.AUDIO_TRUEHD:
        return C.ENCODING_DOLBY_TRUEHD;
      case MimeTypes.AUDIO_OPUS:
        return C.ENCODING_OPUS;
      default:
        return C.ENCODING_INVALID;
    }
  }

  /**
   * Equivalent to {@code getTrackType(getMediaMimeType(codec))}.
   *
   * @param codec An RFC 6381 codec string.
   * @return The corresponding {@link C.TrackType track type}, which may be {@link
   *     C#TRACK_TYPE_UNKNOWN} if it could not be determined.
   */
  @UnstableApi
  public static @C.TrackType int getTrackTypeOfCodec(String codec) {
    return getTrackType(getMediaMimeType(codec));
  }

  /**
   * Normalizes the MIME type provided so that equivalent MIME types are uniquely represented.
   *
   * @param mimeType A MIME type to normalize, or null.
   * @return The normalized MIME type, or the argument MIME type if its normalized form is unknown.
   */
  @UnstableApi
  public static @PolyNull String normalizeMimeType(@PolyNull String mimeType) {
    if (mimeType == null) {
      return null;
    }
    mimeType = Ascii.toLowerCase(mimeType);
    switch (mimeType) {
      // Normalize uncommon versions of some audio MIME types to their standard equivalent.
      case BASE_TYPE_AUDIO + "/x-flac":
        return AUDIO_FLAC;
      case BASE_TYPE_AUDIO + "/mp3":
        return AUDIO_MPEG;
      case BASE_TYPE_AUDIO + "/x-wav":
        return AUDIO_WAV;
      // Normalize MIME types that are often written with upper-case letters to their common form.
      case "application/x-mpegurl":
        return APPLICATION_M3U8;
      case "audio/mpeg-l1":
        return AUDIO_MPEG_L1;
      case "audio/mpeg-l2":
        return AUDIO_MPEG_L2;
      default:
        return mimeType;
    }
  }

  /** Returns whether the given {@code mimeType} is a Matroska MIME type, including WebM. */
  @UnstableApi
  public static boolean isMatroska(@Nullable String mimeType) {
    if (mimeType == null) {
      return false;
    }
    return mimeType.startsWith(MimeTypes.VIDEO_WEBM)
        || mimeType.startsWith(MimeTypes.AUDIO_WEBM)
        || mimeType.startsWith(MimeTypes.APPLICATION_WEBM)
        || mimeType.startsWith(MimeTypes.VIDEO_MATROSKA)
        || mimeType.startsWith(MimeTypes.AUDIO_MATROSKA)
        || mimeType.startsWith(MimeTypes.APPLICATION_MATROSKA);
  }

  /**
   * Returns the top-level type of {@code mimeType}, or null if {@code mimeType} is null or does not
   * contain a forward slash character ({@code '/'}).
   */
  @UnstableApi
  @Nullable
  private static String getTopLevelType(@Nullable String mimeType) {
    if (mimeType == null) {
      return null;
    }
    int indexOfSlash = mimeType.indexOf('/');
    if (indexOfSlash == -1) {
      return null;
    }
    return mimeType.substring(0, indexOfSlash);
  }

  @Nullable
  private static String getCustomMimeTypeForCodec(String codec) {
    int customMimeTypeCount = customMimeTypes.size();
    for (int i = 0; i < customMimeTypeCount; i++) {
      CustomMimeType customMimeType = customMimeTypes.get(i);
      if (codec.startsWith(customMimeType.codecPrefix)) {
        return customMimeType.mimeType;
      }
    }
    return null;
  }

  private static @C.TrackType int getTrackTypeForCustomMimeType(String mimeType) {
    int customMimeTypeCount = customMimeTypes.size();
    for (int i = 0; i < customMimeTypeCount; i++) {
      CustomMimeType customMimeType = customMimeTypes.get(i);
      if (mimeType.equals(customMimeType.mimeType)) {
        return customMimeType.trackType;
      }
    }
    return C.TRACK_TYPE_UNKNOWN;
  }

  private MimeTypes() {
    // Prevent instantiation.
  }

  /**
   * Returns the {@link Mp4aObjectType} of an RFC 6381 MP4 audio codec string.
   *
   * <p>Per https://mp4ra.org/#/object_types and https://tools.ietf.org/html/rfc6381#section-3.3, an
   * MP4 codec string has the form:
   *
   * <pre>
   *         ~~~~~~~~~~~~~~ Object Type Indication (OTI) byte in hex
   *    mp4a.[a-zA-Z0-9]{2}(.[0-9]{1,2})?
   *                         ~~~~~~~~~~ audio OTI, decimal. Only for certain OTI.
   * </pre>
   *
   * 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. */
    public final int audioObjectTypeIndication;

    public Mp4aObjectType(int objectTypeIndication, int audioObjectTypeIndication) {
      this.objectTypeIndication = objectTypeIndication;
      this.audioObjectTypeIndication = audioObjectTypeIndication;
    }

    /** Returns the encoding for {@link #audioObjectTypeIndication}. */
    public @C.Encoding int getEncoding() {
      // See AUDIO_OBJECT_TYPE_AAC_* constants in AacUtil.
      switch (audioObjectTypeIndication) {
        case 2:
          return C.ENCODING_AAC_LC;
        case 5:
          return C.ENCODING_AAC_HE_V1;
        case 29:
          return C.ENCODING_AAC_HE_V2;
        case 42:
          return C.ENCODING_AAC_XHE;
        case 23:
          return C.ENCODING_AAC_ELD;
        case 22:
          return C.ENCODING_AAC_ER_BSAC;
        default:
          return C.ENCODING_INVALID;
      }
    }
  }

  private static final class CustomMimeType {
    public final String mimeType;
    public final String codecPrefix;
    public final @C.TrackType int trackType;

    public CustomMimeType(String mimeType, String codecPrefix, @C.TrackType int trackType) {
      this.mimeType = mimeType;
      this.codecPrefix = codecPrefix;
      this.trackType = trackType;
    }
  }
}