diff --git a/demo_misc/webm_sw_decoder/src/main/java/com/google/android/exoplayer/demo/webm/DashRendererBuilder.java b/demo_misc/webm_sw_decoder/src/main/java/com/google/android/exoplayer/demo/webm/DashRendererBuilder.java index 4f59a3b396..f199091cb2 100644 --- a/demo_misc/webm_sw_decoder/src/main/java/com/google/android/exoplayer/demo/webm/DashRendererBuilder.java +++ b/demo_misc/webm_sw_decoder/src/main/java/com/google/android/exoplayer/demo/webm/DashRendererBuilder.java @@ -38,7 +38,8 @@ import com.google.android.exoplayer.upstream.DefaultHttpDataSource; import com.google.android.exoplayer.upstream.DefaultUriDataSource; import com.google.android.exoplayer.util.ManifestFetcher; import com.google.android.exoplayer.util.ManifestFetcher.ManifestCallback; -import com.google.android.exoplayer.util.MimeTypes; + +import android.text.TextUtils; import java.io.IOException; import java.util.ArrayList; @@ -82,6 +83,7 @@ public class DashRendererBuilder implements ManifestCallback videoRepresentationsList = new ArrayList<>(); Period period = manifest.getPeriod(0); for (int i = 0; i < period.adaptationSets.size(); i++) { @@ -89,9 +91,12 @@ public class DashRendererBuilder implements ManifestCallback adaptationSets = manifest.getPeriod(periodIndex).adaptationSets; AdaptationSet adaptationSet = adaptationSets.get(adaptationSetIndex); Format representationFormat = adaptationSet.representations.get(representationIndex).format; - MediaFormat trackFormat = buildTrackFormat(adaptationSet.type, representationFormat, - manifest.dynamic ? C.UNKNOWN_TIME_US : manifest.duration * 1000); + String mediaMimeType = getMediaMimeType(representationFormat); + if (mediaMimeType == null) { + Log.w(TAG, "Skipped track " + representationFormat.id + " (unknown media mime type)"); + return; + } + MediaFormat trackFormat = getTrackFormat(adaptationSet.type, representationFormat, + mediaMimeType, manifest.dynamic ? C.UNKNOWN_TIME_US : manifest.duration * 1000); + if (trackFormat == null) { + Log.w(TAG, "Skipped track " + representationFormat.id + " (unknown media format)"); + return; + } tracks.add(new ExposedTrack(trackFormat, adaptationSetIndex, representationFormat)); } @@ -574,34 +596,64 @@ public class DashChunkSource implements ChunkSource, Output { Collections.singletonList(period)); } - private static MediaFormat buildTrackFormat(int adaptationSetType, Format format, - long durationUs) { + private static MediaFormat getTrackFormat(int adaptationSetType, Format format, + String mediaMimeType, long durationUs) { switch (adaptationSetType) { case AdaptationSet.TYPE_VIDEO: - return MediaFormat.createVideoFormat(getMediaMimeType(format), format.bitrate, - MediaFormat.NO_VALUE, durationUs, format.width, format.height, 0, null); + return MediaFormat.createVideoFormat(mediaMimeType, format.bitrate, MediaFormat.NO_VALUE, + durationUs, format.width, format.height, 0, null); case AdaptationSet.TYPE_AUDIO: - return MediaFormat.createAudioFormat(getMediaMimeType(format), format.bitrate, - MediaFormat.NO_VALUE, durationUs, format.audioChannels, format.audioSamplingRate, null); + return MediaFormat.createAudioFormat(mediaMimeType, format.bitrate, MediaFormat.NO_VALUE, + durationUs, format.audioChannels, format.audioSamplingRate, null); case AdaptationSet.TYPE_TEXT: - return MediaFormat.createTextFormat(getMediaMimeType(format), format.bitrate, - format.language, durationUs); + return MediaFormat.createTextFormat(mediaMimeType, format.bitrate, format.language, + durationUs); default: - throw new IllegalStateException("Invalid type: " + adaptationSetType); + return null; } } private static String getMediaMimeType(Format format) { - String mimeType = format.mimeType; - if (MimeTypes.APPLICATION_MP4.equals(format.mimeType) && "stpp".equals(format.codecs)) { + String formatMimeType = format.mimeType; + String codecs = format.codecs; + if (MimeTypes.isAudio(formatMimeType)) { + return getAudioMediaMimeType(codecs); + } else if (MimeTypes.isVideo(formatMimeType)) { + return getVideoMediaMimeType(codecs); + } else if (mimeTypeIsRawText(formatMimeType)) { + return formatMimeType; + } else if (MimeTypes.APPLICATION_MP4.equals(formatMimeType) && "stpp".equals(codecs)) { return MimeTypes.APPLICATION_TTML; + } else { + return null; } - // TODO: Use codecs to determine media mime type for other formats too. - return mimeType; + } + + private static String getVideoMediaMimeType(String codecs) { + if (TextUtils.isEmpty(codecs)) { + return MimeTypes.VIDEO_UNKNOWN; + } else if (codecs.startsWith("vp9")) { + return MimeTypes.VIDEO_VP9; + } else if (codecs.startsWith("vp8")) { + return MimeTypes.VIDEO_VP8; + } + // TODO: Parse more codecs values here. + return MimeTypes.VIDEO_UNKNOWN; + } + + private static String getAudioMediaMimeType(String codecs) { + if (TextUtils.isEmpty(codecs)) { + return MimeTypes.AUDIO_UNKNOWN; + } else if (codecs.startsWith("opus")) { + return MimeTypes.AUDIO_OPUS; + } + // TODO: Parse more codecs values here. + return MimeTypes.AUDIO_UNKNOWN; } /* package */ static boolean mimeTypeIsWebm(String mimeType) { - return mimeType.startsWith(MimeTypes.VIDEO_WEBM) || mimeType.startsWith(MimeTypes.AUDIO_WEBM); + return mimeType.startsWith(MimeTypes.VIDEO_WEBM) || mimeType.startsWith(MimeTypes.AUDIO_WEBM) + || mimeType.startsWith(MimeTypes.APPLICATION_WEBM); } /* package */ static boolean mimeTypeIsRawText(String mimeType) { diff --git a/library/src/main/java/com/google/android/exoplayer/util/MimeTypes.java b/library/src/main/java/com/google/android/exoplayer/util/MimeTypes.java index 24e3568f48..d8fb740792 100644 --- a/library/src/main/java/com/google/android/exoplayer/util/MimeTypes.java +++ b/library/src/main/java/com/google/android/exoplayer/util/MimeTypes.java @@ -25,6 +25,7 @@ public final class MimeTypes { public static final String BASE_TYPE_TEXT = "text"; public static final String BASE_TYPE_APPLICATION = "application"; + public static final String VIDEO_UNKNOWN = BASE_TYPE_VIDEO + "/x-unknown"; public static final String VIDEO_MP4 = BASE_TYPE_VIDEO + "/mp4"; public static final String VIDEO_WEBM = BASE_TYPE_VIDEO + "/webm"; public static final String VIDEO_H263 = BASE_TYPE_VIDEO + "/3gpp"; @@ -34,25 +35,25 @@ public final class MimeTypes { public static final String VIDEO_VP9 = BASE_TYPE_VIDEO + "/x-vnd.on2.vp9"; public static final String VIDEO_MP4V = BASE_TYPE_VIDEO + "/mp4v-es"; + public static final String AUDIO_UNKNOWN = BASE_TYPE_AUDIO + "/x-unknown"; public static final String AUDIO_MP4 = BASE_TYPE_AUDIO + "/mp4"; public static final String AUDIO_AAC = BASE_TYPE_AUDIO + "/mp4a-latm"; 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_RAW = BASE_TYPE_AUDIO + "/raw"; public static final String AUDIO_AC3 = BASE_TYPE_AUDIO + "/ac3"; public static final String AUDIO_EC3 = BASE_TYPE_AUDIO + "/eac3"; public static final String AUDIO_DTS = BASE_TYPE_AUDIO + "/x-dts"; public static final String AUDIO_DTS_HD = BASE_TYPE_AUDIO + "/vnd.dts.hd"; - public static final String AUDIO_VORBIS = BASE_TYPE_AUDIO + "/vorbis"; public static final String AUDIO_OPUS = BASE_TYPE_AUDIO + "/opus"; public static final String TEXT_VTT = BASE_TYPE_TEXT + "/vtt"; 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_ID3 = BASE_TYPE_APPLICATION + "/id3"; public static final String APPLICATION_EIA608 = BASE_TYPE_APPLICATION + "/eia-608"; public static final String APPLICATION_SUBRIP = BASE_TYPE_APPLICATION + "/x-subrip"; @@ -62,20 +63,6 @@ public final class MimeTypes { private MimeTypes() {} - /** - * Returns the top-level type of {@code mimeType}. - * - * @param mimeType The mimeType whose top-level type is required. - * @return The top-level type. - */ - public static String getTopLevelType(String mimeType) { - int indexOfSlash = mimeType.indexOf('/'); - if (indexOfSlash == -1) { - throw new IllegalArgumentException("Invalid mime type: " + mimeType); - } - return mimeType.substring(0, indexOfSlash); - } - /** * Whether the top-level type of {@code mimeType} is audio. * @@ -116,4 +103,18 @@ public final class MimeTypes { return getTopLevelType(mimeType).equals(BASE_TYPE_APPLICATION); } + /** + * Returns the top-level type of {@code mimeType}. + * + * @param mimeType The mimeType whose top-level type is required. + * @return The top-level type. + */ + private static String getTopLevelType(String mimeType) { + int indexOfSlash = mimeType.indexOf('/'); + if (indexOfSlash == -1) { + throw new IllegalArgumentException("Invalid mime type: " + mimeType); + } + return mimeType.substring(0, indexOfSlash); + } + }