• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2016 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 package com.google.android.exoplayer2.util;
17 
18 import android.text.TextUtils;
19 import androidx.annotation.Nullable;
20 import com.google.android.exoplayer2.C;
21 import java.util.ArrayList;
22 
23 /**
24  * Defines common MIME types and helper methods.
25  */
26 public final class MimeTypes {
27 
28   public static final String BASE_TYPE_VIDEO = "video";
29   public static final String BASE_TYPE_AUDIO = "audio";
30   public static final String BASE_TYPE_TEXT = "text";
31   public static final String BASE_TYPE_APPLICATION = "application";
32 
33   public static final String VIDEO_MP4 = BASE_TYPE_VIDEO + "/mp4";
34   public static final String VIDEO_WEBM = BASE_TYPE_VIDEO + "/webm";
35   public static final String VIDEO_H263 = BASE_TYPE_VIDEO + "/3gpp";
36   public static final String VIDEO_H264 = BASE_TYPE_VIDEO + "/avc";
37   public static final String VIDEO_H265 = BASE_TYPE_VIDEO + "/hevc";
38   public static final String VIDEO_VP8 = BASE_TYPE_VIDEO + "/x-vnd.on2.vp8";
39   public static final String VIDEO_VP9 = BASE_TYPE_VIDEO + "/x-vnd.on2.vp9";
40   public static final String VIDEO_AV1 = BASE_TYPE_VIDEO + "/av01";
41   public static final String VIDEO_MP4V = BASE_TYPE_VIDEO + "/mp4v-es";
42   public static final String VIDEO_MPEG = BASE_TYPE_VIDEO + "/mpeg";
43   public static final String VIDEO_MPEG2 = BASE_TYPE_VIDEO + "/mpeg2";
44   public static final String VIDEO_VC1 = BASE_TYPE_VIDEO + "/wvc1";
45   public static final String VIDEO_DIVX = BASE_TYPE_VIDEO + "/divx";
46   public static final String VIDEO_DOLBY_VISION = BASE_TYPE_VIDEO + "/dolby-vision";
47   public static final String VIDEO_UNKNOWN = BASE_TYPE_VIDEO + "/x-unknown";
48 
49   public static final String AUDIO_MP4 = BASE_TYPE_AUDIO + "/mp4";
50   public static final String AUDIO_AAC = BASE_TYPE_AUDIO + "/mp4a-latm";
51   public static final String AUDIO_WEBM = BASE_TYPE_AUDIO + "/webm";
52   public static final String AUDIO_MPEG = BASE_TYPE_AUDIO + "/mpeg";
53   public static final String AUDIO_MPEG_L1 = BASE_TYPE_AUDIO + "/mpeg-L1";
54   public static final String AUDIO_MPEG_L2 = BASE_TYPE_AUDIO + "/mpeg-L2";
55   public static final String AUDIO_RAW = BASE_TYPE_AUDIO + "/raw";
56   public static final String AUDIO_ALAW = BASE_TYPE_AUDIO + "/g711-alaw";
57   public static final String AUDIO_MLAW = BASE_TYPE_AUDIO + "/g711-mlaw";
58   public static final String AUDIO_AC3 = BASE_TYPE_AUDIO + "/ac3";
59   public static final String AUDIO_E_AC3 = BASE_TYPE_AUDIO + "/eac3";
60   public static final String AUDIO_E_AC3_JOC = BASE_TYPE_AUDIO + "/eac3-joc";
61   public static final String AUDIO_AC4 = BASE_TYPE_AUDIO + "/ac4";
62   public static final String AUDIO_TRUEHD = BASE_TYPE_AUDIO + "/true-hd";
63   public static final String AUDIO_DTS = BASE_TYPE_AUDIO + "/vnd.dts";
64   public static final String AUDIO_DTS_HD = BASE_TYPE_AUDIO + "/vnd.dts.hd";
65   public static final String AUDIO_DTS_EXPRESS = BASE_TYPE_AUDIO + "/vnd.dts.hd;profile=lbr";
66   public static final String AUDIO_VORBIS = BASE_TYPE_AUDIO + "/vorbis";
67   public static final String AUDIO_OPUS = BASE_TYPE_AUDIO + "/opus";
68   public static final String AUDIO_AMR_NB = BASE_TYPE_AUDIO + "/3gpp";
69   public static final String AUDIO_AMR_WB = BASE_TYPE_AUDIO + "/amr-wb";
70   public static final String AUDIO_FLAC = BASE_TYPE_AUDIO + "/flac";
71   public static final String AUDIO_ALAC = BASE_TYPE_AUDIO + "/alac";
72   public static final String AUDIO_MSGSM = BASE_TYPE_AUDIO + "/gsm";
73   public static final String AUDIO_UNKNOWN = BASE_TYPE_AUDIO + "/x-unknown";
74 
75   public static final String TEXT_VTT = BASE_TYPE_TEXT + "/vtt";
76   public static final String TEXT_SSA = BASE_TYPE_TEXT + "/x-ssa";
77 
78   public static final String APPLICATION_MP4 = BASE_TYPE_APPLICATION + "/mp4";
79   public static final String APPLICATION_WEBM = BASE_TYPE_APPLICATION + "/webm";
80   public static final String APPLICATION_MPD = BASE_TYPE_APPLICATION + "/dash+xml";
81   public static final String APPLICATION_M3U8 = BASE_TYPE_APPLICATION + "/x-mpegURL";
82   public static final String APPLICATION_SS = BASE_TYPE_APPLICATION + "/vnd.ms-sstr+xml";
83   public static final String APPLICATION_ID3 = BASE_TYPE_APPLICATION + "/id3";
84   public static final String APPLICATION_CEA608 = BASE_TYPE_APPLICATION + "/cea-608";
85   public static final String APPLICATION_CEA708 = BASE_TYPE_APPLICATION + "/cea-708";
86   public static final String APPLICATION_SUBRIP = BASE_TYPE_APPLICATION + "/x-subrip";
87   public static final String APPLICATION_TTML = BASE_TYPE_APPLICATION + "/ttml+xml";
88   public static final String APPLICATION_TX3G = BASE_TYPE_APPLICATION + "/x-quicktime-tx3g";
89   public static final String APPLICATION_MP4VTT = BASE_TYPE_APPLICATION + "/x-mp4-vtt";
90   public static final String APPLICATION_MP4CEA608 = BASE_TYPE_APPLICATION + "/x-mp4-cea-608";
91   public static final String APPLICATION_RAWCC = BASE_TYPE_APPLICATION + "/x-rawcc";
92   public static final String APPLICATION_VOBSUB = BASE_TYPE_APPLICATION + "/vobsub";
93   public static final String APPLICATION_PGS = BASE_TYPE_APPLICATION + "/pgs";
94   public static final String APPLICATION_SCTE35 = BASE_TYPE_APPLICATION + "/x-scte35";
95   public static final String APPLICATION_CAMERA_MOTION = BASE_TYPE_APPLICATION + "/x-camera-motion";
96   public static final String APPLICATION_EMSG = BASE_TYPE_APPLICATION + "/x-emsg";
97   public static final String APPLICATION_DVBSUBS = BASE_TYPE_APPLICATION + "/dvbsubs";
98   public static final String APPLICATION_EXIF = BASE_TYPE_APPLICATION + "/x-exif";
99   public static final String APPLICATION_ICY = BASE_TYPE_APPLICATION + "/x-icy";
100   public static final String APPLICATION_AIT = BASE_TYPE_APPLICATION + "/vnd.dvb.ait";
101 
102   private static final ArrayList<CustomMimeType> customMimeTypes = new ArrayList<>();
103 
104   /**
105    * Registers a custom MIME type. Most applications do not need to call this method, as handling of
106    * standard MIME types is built in. These built-in MIME types take precedence over any registered
107    * via this method. If this method is used, it must be called before creating any player(s).
108    *
109    * @param mimeType The custom MIME type to register.
110    * @param codecPrefix The RFC 6381-style codec string prefix associated with the MIME type.
111    * @param trackType The {@link C}{@code .TRACK_TYPE_*} constant associated with the MIME type.
112    *     This value is ignored if the top-level type of {@code mimeType} is audio, video or text.
113    */
registerCustomMimeType(String mimeType, String codecPrefix, int trackType)114   public static void registerCustomMimeType(String mimeType, String codecPrefix, int trackType) {
115     CustomMimeType customMimeType = new CustomMimeType(mimeType, codecPrefix, trackType);
116     int customMimeTypeCount = customMimeTypes.size();
117     for (int i = 0; i < customMimeTypeCount; i++) {
118       if (mimeType.equals(customMimeTypes.get(i).mimeType)) {
119         customMimeTypes.remove(i);
120         break;
121       }
122     }
123     customMimeTypes.add(customMimeType);
124   }
125 
126   /** Returns whether the given string is an audio MIME type. */
isAudio(@ullable String mimeType)127   public static boolean isAudio(@Nullable String mimeType) {
128     return BASE_TYPE_AUDIO.equals(getTopLevelType(mimeType));
129   }
130 
131   /** Returns whether the given string is a video MIME type. */
isVideo(@ullable String mimeType)132   public static boolean isVideo(@Nullable String mimeType) {
133     return BASE_TYPE_VIDEO.equals(getTopLevelType(mimeType));
134   }
135 
136   /**
137    * Returns whether the given string is a text MIME type, including known text types that use
138    * &quot;application&quot; as their base type.
139    */
isText(@ullable String mimeType)140   public static boolean isText(@Nullable String mimeType) {
141     return BASE_TYPE_TEXT.equals(getTopLevelType(mimeType))
142         || APPLICATION_CEA608.equals(mimeType)
143         || APPLICATION_CEA708.equals(mimeType)
144         || APPLICATION_MP4CEA608.equals(mimeType)
145         || APPLICATION_SUBRIP.equals(mimeType)
146         || APPLICATION_TTML.equals(mimeType)
147         || APPLICATION_TX3G.equals(mimeType)
148         || APPLICATION_MP4VTT.equals(mimeType)
149         || APPLICATION_RAWCC.equals(mimeType)
150         || APPLICATION_VOBSUB.equals(mimeType)
151         || APPLICATION_PGS.equals(mimeType)
152         || APPLICATION_DVBSUBS.equals(mimeType);
153   }
154 
155   /**
156    * Returns true if it is known that all samples in a stream of the given sample MIME type are
157    * guaranteed to be sync samples (i.e., {@link C#BUFFER_FLAG_KEY_FRAME} is guaranteed to be set on
158    * every sample).
159    *
160    * @param mimeType The sample MIME type.
161    * @return True if it is known that all samples in a stream of the given sample MIME type are
162    *     guaranteed to be sync samples. False otherwise, including if {@code null} is passed.
163    */
allSamplesAreSyncSamples(@ullable String mimeType)164   public static boolean allSamplesAreSyncSamples(@Nullable String mimeType) {
165     if (mimeType == null) {
166       return false;
167     }
168     // TODO: Consider adding additional audio MIME types here.
169     switch (mimeType) {
170       case AUDIO_AAC:
171       case AUDIO_MPEG:
172       case AUDIO_MPEG_L1:
173       case AUDIO_MPEG_L2:
174         return true;
175       default:
176         return false;
177     }
178   }
179 
180   /**
181    * Derives a video sample mimeType from a codecs attribute.
182    *
183    * @param codecs The codecs attribute.
184    * @return The derived video mimeType, or null if it could not be derived.
185    */
186   @Nullable
getVideoMediaMimeType(@ullable String codecs)187   public static String getVideoMediaMimeType(@Nullable String codecs) {
188     if (codecs == null) {
189       return null;
190     }
191     String[] codecList = Util.splitCodecs(codecs);
192     for (String codec : codecList) {
193       @Nullable String mimeType = getMediaMimeType(codec);
194       if (mimeType != null && isVideo(mimeType)) {
195         return mimeType;
196       }
197     }
198     return null;
199   }
200 
201   /**
202    * Derives a audio sample mimeType from a codecs attribute.
203    *
204    * @param codecs The codecs attribute.
205    * @return The derived audio mimeType, or null if it could not be derived.
206    */
207   @Nullable
getAudioMediaMimeType(@ullable String codecs)208   public static String getAudioMediaMimeType(@Nullable String codecs) {
209     if (codecs == null) {
210       return null;
211     }
212     String[] codecList = Util.splitCodecs(codecs);
213     for (String codec : codecList) {
214       @Nullable String mimeType = getMediaMimeType(codec);
215       if (mimeType != null && isAudio(mimeType)) {
216         return mimeType;
217       }
218     }
219     return null;
220   }
221 
222   /**
223    * Derives a text sample mimeType from a codecs attribute.
224    *
225    * @param codecs The codecs attribute.
226    * @return The derived text mimeType, or null if it could not be derived.
227    */
228   @Nullable
getTextMediaMimeType(@ullable String codecs)229   public static String getTextMediaMimeType(@Nullable String codecs) {
230     if (codecs == null) {
231       return null;
232     }
233     String[] codecList = Util.splitCodecs(codecs);
234     for (String codec : codecList) {
235       @Nullable String mimeType = getMediaMimeType(codec);
236       if (mimeType != null && isText(mimeType)) {
237         return mimeType;
238       }
239     }
240     return null;
241   }
242 
243   /**
244    * Derives a mimeType from a codec identifier, as defined in RFC 6381.
245    *
246    * @param codec The codec identifier to derive.
247    * @return The mimeType, or null if it could not be derived.
248    */
249   @Nullable
getMediaMimeType(@ullable String codec)250   public static String getMediaMimeType(@Nullable String codec) {
251     if (codec == null) {
252       return null;
253     }
254     codec = Util.toLowerInvariant(codec.trim());
255     if (codec.startsWith("avc1") || codec.startsWith("avc3")) {
256       return MimeTypes.VIDEO_H264;
257     } else if (codec.startsWith("hev1") || codec.startsWith("hvc1")) {
258       return MimeTypes.VIDEO_H265;
259     } else if (codec.startsWith("dvav")
260         || codec.startsWith("dva1")
261         || codec.startsWith("dvhe")
262         || codec.startsWith("dvh1")) {
263       return MimeTypes.VIDEO_DOLBY_VISION;
264     } else if (codec.startsWith("av01")) {
265       return MimeTypes.VIDEO_AV1;
266     } else if (codec.startsWith("vp9") || codec.startsWith("vp09")) {
267       return MimeTypes.VIDEO_VP9;
268     } else if (codec.startsWith("vp8") || codec.startsWith("vp08")) {
269       return MimeTypes.VIDEO_VP8;
270     } else if (codec.startsWith("mp4a")) {
271       @Nullable String mimeType = null;
272       if (codec.startsWith("mp4a.")) {
273         String objectTypeString = codec.substring(5); // remove the 'mp4a.' prefix
274         if (objectTypeString.length() >= 2) {
275           try {
276             String objectTypeHexString = Util.toUpperInvariant(objectTypeString.substring(0, 2));
277             int objectTypeInt = Integer.parseInt(objectTypeHexString, 16);
278             mimeType = getMimeTypeFromMp4ObjectType(objectTypeInt);
279           } catch (NumberFormatException ignored) {
280             // Ignored.
281           }
282         }
283       }
284       return mimeType == null ? MimeTypes.AUDIO_AAC : mimeType;
285     } else if (codec.startsWith("ac-3") || codec.startsWith("dac3")) {
286       return MimeTypes.AUDIO_AC3;
287     } else if (codec.startsWith("ec-3") || codec.startsWith("dec3")) {
288       return MimeTypes.AUDIO_E_AC3;
289     } else if (codec.startsWith("ec+3")) {
290       return MimeTypes.AUDIO_E_AC3_JOC;
291     } else if (codec.startsWith("ac-4") || codec.startsWith("dac4")) {
292       return MimeTypes.AUDIO_AC4;
293     } else if (codec.startsWith("dtsc") || codec.startsWith("dtse")) {
294       return MimeTypes.AUDIO_DTS;
295     } else if (codec.startsWith("dtsh") || codec.startsWith("dtsl")) {
296       return MimeTypes.AUDIO_DTS_HD;
297     } else if (codec.startsWith("opus")) {
298       return MimeTypes.AUDIO_OPUS;
299     } else if (codec.startsWith("vorbis")) {
300       return MimeTypes.AUDIO_VORBIS;
301     } else if (codec.startsWith("flac")) {
302       return MimeTypes.AUDIO_FLAC;
303     } else if (codec.startsWith("stpp")) {
304       return MimeTypes.APPLICATION_TTML;
305     } else if (codec.startsWith("wvtt")) {
306       return MimeTypes.TEXT_VTT;
307     } else if (codec.contains("cea708")) {
308       return MimeTypes.APPLICATION_CEA708;
309     } else if (codec.contains("eia608") || codec.contains("cea608")) {
310       return MimeTypes.APPLICATION_CEA608;
311     } else {
312       return getCustomMimeTypeForCodec(codec);
313     }
314   }
315 
316   /**
317    * Derives a mimeType from MP4 object type identifier, as defined in RFC 6381 and
318    * https://mp4ra.org/#/object_types.
319    *
320    * @param objectType The objectType identifier to derive.
321    * @return The mimeType, or null if it could not be derived.
322    */
323   @Nullable
getMimeTypeFromMp4ObjectType(int objectType)324   public static String getMimeTypeFromMp4ObjectType(int objectType) {
325     switch (objectType) {
326       case 0x20:
327         return MimeTypes.VIDEO_MP4V;
328       case 0x21:
329         return MimeTypes.VIDEO_H264;
330       case 0x23:
331         return MimeTypes.VIDEO_H265;
332       case 0x60:
333       case 0x61:
334       case 0x62:
335       case 0x63:
336       case 0x64:
337       case 0x65:
338         return MimeTypes.VIDEO_MPEG2;
339       case 0x6A:
340         return MimeTypes.VIDEO_MPEG;
341       case 0x69:
342       case 0x6B:
343         return MimeTypes.AUDIO_MPEG;
344       case 0xA3:
345         return MimeTypes.VIDEO_VC1;
346       case 0xB1:
347         return MimeTypes.VIDEO_VP9;
348       case 0x40:
349       case 0x66:
350       case 0x67:
351       case 0x68:
352         return MimeTypes.AUDIO_AAC;
353       case 0xA5:
354         return MimeTypes.AUDIO_AC3;
355       case 0xA6:
356         return MimeTypes.AUDIO_E_AC3;
357       case 0xA9:
358       case 0xAC:
359         return MimeTypes.AUDIO_DTS;
360       case 0xAA:
361       case 0xAB:
362         return MimeTypes.AUDIO_DTS_HD;
363       case 0xAD:
364         return MimeTypes.AUDIO_OPUS;
365       case 0xAE:
366         return MimeTypes.AUDIO_AC4;
367       default:
368         return null;
369     }
370   }
371 
372   /**
373    * Returns the {@link C}{@code .TRACK_TYPE_*} constant that corresponds to a specified MIME type.
374    * {@link C#TRACK_TYPE_UNKNOWN} if the MIME type is not known or the mapping cannot be
375    * established.
376    *
377    * @param mimeType The MIME type.
378    * @return The {@link C}{@code .TRACK_TYPE_*} constant that corresponds to a specified MIME type.
379    */
getTrackType(@ullable String mimeType)380   public static int getTrackType(@Nullable String mimeType) {
381     if (TextUtils.isEmpty(mimeType)) {
382       return C.TRACK_TYPE_UNKNOWN;
383     } else if (isAudio(mimeType)) {
384       return C.TRACK_TYPE_AUDIO;
385     } else if (isVideo(mimeType)) {
386       return C.TRACK_TYPE_VIDEO;
387     } else if (isText(mimeType)) {
388       return C.TRACK_TYPE_TEXT;
389     } else if (APPLICATION_ID3.equals(mimeType)
390         || APPLICATION_EMSG.equals(mimeType)
391         || APPLICATION_SCTE35.equals(mimeType)) {
392       return C.TRACK_TYPE_METADATA;
393     } else if (APPLICATION_CAMERA_MOTION.equals(mimeType)) {
394       return C.TRACK_TYPE_CAMERA_MOTION;
395     } else {
396       return getTrackTypeForCustomMimeType(mimeType);
397     }
398   }
399 
400   /**
401    * Returns the {@link C}{@code .ENCODING_*} constant that corresponds to specified MIME type, if
402    * it is an encoded (non-PCM) audio format, or {@link C#ENCODING_INVALID} otherwise.
403    *
404    * @param mimeType The MIME type.
405    * @return The {@link C}{@code .ENCODING_*} constant that corresponds to a specified MIME type, or
406    *     {@link C#ENCODING_INVALID}.
407    */
getEncoding(String mimeType)408   public static @C.Encoding int getEncoding(String mimeType) {
409     switch (mimeType) {
410       case MimeTypes.AUDIO_MPEG:
411         return C.ENCODING_MP3;
412       case MimeTypes.AUDIO_AC3:
413         return C.ENCODING_AC3;
414       case MimeTypes.AUDIO_E_AC3:
415         return C.ENCODING_E_AC3;
416       case MimeTypes.AUDIO_E_AC3_JOC:
417         return C.ENCODING_E_AC3_JOC;
418       case MimeTypes.AUDIO_AC4:
419         return C.ENCODING_AC4;
420       case MimeTypes.AUDIO_DTS:
421         return C.ENCODING_DTS;
422       case MimeTypes.AUDIO_DTS_HD:
423         return C.ENCODING_DTS_HD;
424       case MimeTypes.AUDIO_TRUEHD:
425         return C.ENCODING_DOLBY_TRUEHD;
426       default:
427         return C.ENCODING_INVALID;
428     }
429   }
430 
431   /**
432    * Equivalent to {@code getTrackType(getMediaMimeType(codec))}.
433    *
434    * @param codec The codec.
435    * @return The {@link C}{@code .TRACK_TYPE_*} constant that corresponds to a specified codec.
436    */
getTrackTypeOfCodec(String codec)437   public static int getTrackTypeOfCodec(String codec) {
438     return getTrackType(getMediaMimeType(codec));
439   }
440 
441   /**
442    * Returns the top-level type of {@code mimeType}, or null if {@code mimeType} is null or does not
443    * contain a forward slash character ({@code '/'}).
444    */
445   @Nullable
getTopLevelType(@ullable String mimeType)446   private static String getTopLevelType(@Nullable String mimeType) {
447     if (mimeType == null) {
448       return null;
449     }
450     int indexOfSlash = mimeType.indexOf('/');
451     if (indexOfSlash == -1) {
452       return null;
453     }
454     return mimeType.substring(0, indexOfSlash);
455   }
456 
457   @Nullable
getCustomMimeTypeForCodec(String codec)458   private static String getCustomMimeTypeForCodec(String codec) {
459     int customMimeTypeCount = customMimeTypes.size();
460     for (int i = 0; i < customMimeTypeCount; i++) {
461       CustomMimeType customMimeType = customMimeTypes.get(i);
462       if (codec.startsWith(customMimeType.codecPrefix)) {
463         return customMimeType.mimeType;
464       }
465     }
466     return null;
467   }
468 
getTrackTypeForCustomMimeType(String mimeType)469   private static int getTrackTypeForCustomMimeType(String mimeType) {
470     int customMimeTypeCount = customMimeTypes.size();
471     for (int i = 0; i < customMimeTypeCount; i++) {
472       CustomMimeType customMimeType = customMimeTypes.get(i);
473       if (mimeType.equals(customMimeType.mimeType)) {
474         return customMimeType.trackType;
475       }
476     }
477     return C.TRACK_TYPE_UNKNOWN;
478   }
479 
MimeTypes()480   private MimeTypes() {
481     // Prevent instantiation.
482   }
483 
484   private static final class CustomMimeType {
485     public final String mimeType;
486     public final String codecPrefix;
487     public final int trackType;
488 
CustomMimeType(String mimeType, String codecPrefix, int trackType)489     public CustomMimeType(String mimeType, String codecPrefix, int trackType) {
490       this.mimeType = mimeType;
491       this.codecPrefix = codecPrefix;
492       this.trackType = trackType;
493     }
494   }
495 }
496