From f02788af4b409f4940f810179ac81945a4e7dd2a Mon Sep 17 00:00:00 2001 From: andrewlewis Date: Fri, 8 Jun 2018 04:45:57 -0700 Subject: [PATCH] Add support for registering custom MIME types Also add a few missing MP4 object types. Issue: #4264 ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=199778373 --- RELEASENOTES.md | 2 + .../android/exoplayer2/util/MimeTypes.java | 83 +++++++++++++++++-- 2 files changed, 79 insertions(+), 6 deletions(-) diff --git a/RELEASENOTES.md b/RELEASENOTES.md index a7a1266979..7507e8bec4 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -21,6 +21,8 @@ * Add method to `BandwidthMeter` to return the `TransferListener` used to gather bandwidth information. * Add callback to `VideoListener` to notify of surface size changes. +* Allow apps to register custom MIME types + ([#4264](https://github.com/google/ExoPlayer/issues/4264)). ### 2.8.2 ### diff --git a/library/core/src/main/java/com/google/android/exoplayer2/util/MimeTypes.java b/library/core/src/main/java/com/google/android/exoplayer2/util/MimeTypes.java index e5d871f082..f205953d8f 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/util/MimeTypes.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/util/MimeTypes.java @@ -18,6 +18,7 @@ package com.google.android.exoplayer2.util; import android.support.annotation.Nullable; import android.text.TextUtils; import com.google.android.exoplayer2.C; +import java.util.ArrayList; /** * Defines common MIME types and helper methods. @@ -92,7 +93,29 @@ public final class MimeTypes { public static final String APPLICATION_DVBSUBS = BASE_TYPE_APPLICATION + "/dvbsubs"; public static final String APPLICATION_EXIF = BASE_TYPE_APPLICATION + "/x-exif"; - private MimeTypes() {} + private static final ArrayList customMimeTypes = new ArrayList<>(); + + /** + * 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-style 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. + */ + public static void registerCustomMimeType(String mimeType, String codecPrefix, 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); + } /** * Whether the top-level type of {@code mimeType} is audio. @@ -222,8 +245,9 @@ public final class MimeTypes { return MimeTypes.AUDIO_OPUS; } else if (codec.startsWith("vorbis")) { return MimeTypes.AUDIO_VORBIS; + } else { + return getCustomMimeTypeForCodec(codec); } - return null; } /** @@ -236,18 +260,28 @@ public final class MimeTypes { @Nullable public static String getMimeTypeFromMp4ObjectType(int objectType) { switch (objectType) { - case 0x60: - case 0x61: - return MimeTypes.VIDEO_MPEG2; 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 0xA3: + return MimeTypes.VIDEO_VC1; + case 0xB1: + return MimeTypes.VIDEO_VP9; case 0x40: case 0x66: case 0x67: @@ -298,7 +332,7 @@ public final class MimeTypes { || APPLICATION_CAMERA_MOTION.equals(mimeType)) { return C.TRACK_TYPE_METADATA; } else { - return C.TRACK_TYPE_UNKNOWN; + return getTrackTypeForCustomMimeType(mimeType); } } @@ -355,4 +389,41 @@ public final class MimeTypes { return mimeType.substring(0, indexOfSlash); } + private static @Nullable 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 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. + } + + private static final class CustomMimeType { + public final String mimeType; + public final String codecPrefix; + public final int trackType; + + public CustomMimeType(String mimeType, String codecPrefix, int trackType) { + this.mimeType = mimeType; + this.codecPrefix = codecPrefix; + this.trackType = trackType; + } + } }