Commit 74a9d8f6 by olly Committed by Oliver Woodman

Clean up manifest MIME type and codec parsing

PiperOrigin-RevId: 305258836
parent f9679a2c
......@@ -133,14 +133,23 @@ public final class MimeTypes {
return BASE_TYPE_VIDEO.equals(getTopLevelType(mimeType));
}
/** Returns whether the given string is a text MIME type. */
/**
* Returns whether the given string is a text MIME type, including known text types that use
* "application" as their base type.
*/
public static boolean isText(@Nullable String mimeType) {
return BASE_TYPE_TEXT.equals(getTopLevelType(mimeType));
}
/** Returns whether the given string is an application MIME type. */
public static boolean isApplication(@Nullable String mimeType) {
return BASE_TYPE_APPLICATION.equals(getTopLevelType(mimeType));
return BASE_TYPE_TEXT.equals(getTopLevelType(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);
}
/**
......@@ -211,6 +220,27 @@ public final class MimeTypes {
}
/**
* Derives a text sample mimeType from a codecs attribute.
*
* @param codecs The codecs attribute.
* @return The derived text mimeType, or null if it could not be derived.
*/
@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;
}
/**
* Derives a mimeType from a codec identifier, as defined in RFC 6381.
*
* @param codec The codec identifier to derive.
......@@ -274,6 +304,10 @@ public final class MimeTypes {
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);
}
......@@ -350,12 +384,7 @@ public final class MimeTypes {
return C.TRACK_TYPE_AUDIO;
} else if (isVideo(mimeType)) {
return C.TRACK_TYPE_VIDEO;
} else if (isText(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)) {
} else if (isText(mimeType)) {
return C.TRACK_TYPE_TEXT;
} else if (APPLICATION_ID3.equals(mimeType)
|| APPLICATION_EMSG.equals(mimeType)
......
......@@ -26,6 +26,29 @@ import org.junit.runner.RunWith;
public final class MimeTypesTest {
@Test
public void isText_returnsCorrectResult() {
assertThat(MimeTypes.isText(MimeTypes.TEXT_VTT)).isTrue();
assertThat(MimeTypes.isText(MimeTypes.TEXT_SSA)).isTrue();
assertThat(MimeTypes.isText(MimeTypes.APPLICATION_CEA608)).isTrue();
assertThat(MimeTypes.isText(MimeTypes.APPLICATION_CEA708)).isTrue();
assertThat(MimeTypes.isText(MimeTypes.APPLICATION_MP4CEA608)).isTrue();
assertThat(MimeTypes.isText(MimeTypes.APPLICATION_SUBRIP)).isTrue();
assertThat(MimeTypes.isText(MimeTypes.APPLICATION_TTML)).isTrue();
assertThat(MimeTypes.isText(MimeTypes.APPLICATION_TX3G)).isTrue();
assertThat(MimeTypes.isText(MimeTypes.APPLICATION_MP4VTT)).isTrue();
assertThat(MimeTypes.isText(MimeTypes.APPLICATION_VOBSUB)).isTrue();
assertThat(MimeTypes.isText(MimeTypes.APPLICATION_PGS)).isTrue();
assertThat(MimeTypes.isText(MimeTypes.APPLICATION_DVBSUBS)).isTrue();
assertThat(MimeTypes.isText("text/custom")).isTrue();
assertThat(MimeTypes.isText(MimeTypes.VIDEO_MP4)).isFalse();
assertThat(MimeTypes.isText(MimeTypes.VIDEO_H264)).isFalse();
assertThat(MimeTypes.isText(MimeTypes.AUDIO_MP4)).isFalse();
assertThat(MimeTypes.isText(MimeTypes.AUDIO_AAC)).isFalse();
assertThat(MimeTypes.isText("application/custom")).isFalse();
}
@Test
public void getMediaMimeType_fromValidCodecs_returnsCorrectMimeType() {
assertThat(MimeTypes.getMediaMimeType("avc1")).isEqualTo(MimeTypes.VIDEO_H264);
assertThat(MimeTypes.getMediaMimeType("avc1.42E01E")).isEqualTo(MimeTypes.VIDEO_H264);
......@@ -77,6 +100,9 @@ public final class MimeTypesTest {
assertThat(MimeTypes.getMediaMimeType("wvtt")).isEqualTo(MimeTypes.TEXT_VTT);
assertThat(MimeTypes.getMediaMimeType("stpp.")).isEqualTo(MimeTypes.APPLICATION_TTML);
assertThat(MimeTypes.getMediaMimeType("stpp.ttml.im1t")).isEqualTo(MimeTypes.APPLICATION_TTML);
assertThat(MimeTypes.getMediaMimeType("eia608.")).isEqualTo(MimeTypes.APPLICATION_CEA608);
assertThat(MimeTypes.getMediaMimeType("cea608")).isEqualTo(MimeTypes.APPLICATION_CEA608);
assertThat(MimeTypes.getMediaMimeType("cea708")).isEqualTo(MimeTypes.APPLICATION_CEA708);
}
@Test
......
......@@ -772,10 +772,6 @@ public class DefaultDashChunkSource implements DashChunkSource {
|| mimeType.startsWith(MimeTypes.APPLICATION_WEBM);
}
private static boolean mimeTypeIsRawText(String mimeType) {
return MimeTypes.isText(mimeType) || MimeTypes.APPLICATION_TTML.equals(mimeType);
}
private static @Nullable ChunkExtractorWrapper createExtractorWrapper(
int trackType,
Representation representation,
......@@ -783,12 +779,15 @@ public class DefaultDashChunkSource implements DashChunkSource {
List<Format> closedCaptionFormats,
@Nullable TrackOutput playerEmsgTrackOutput) {
String containerMimeType = representation.format.containerMimeType;
if (mimeTypeIsRawText(containerMimeType)) {
return null;
}
Extractor extractor;
if (MimeTypes.APPLICATION_RAWCC.equals(containerMimeType)) {
extractor = new RawCcExtractor(representation.format);
if (MimeTypes.isText(containerMimeType)) {
if (MimeTypes.APPLICATION_RAWCC.equals(containerMimeType)) {
// RawCC is special because it's a text specific container format.
extractor = new RawCcExtractor(representation.format);
} else {
// All other text types are raw formats that do not need an extractor.
return null;
}
} else if (mimeTypeIsWebm(containerMimeType)) {
extractor = new MatroskaExtractor(MatroskaExtractor.FLAG_DISABLE_SEEK_FOR_CUES);
} else {
......
......@@ -337,8 +337,9 @@ public class DashManifestParser extends DefaultHandler
supplementalProperties,
segmentBase,
periodDurationMs);
contentType = checkContentTypeConsistency(contentType,
getContentType(representationInfo.format));
contentType =
checkContentTypeConsistency(
contentType, MimeTypes.getTrackType(representationInfo.format.sampleMimeType));
representationInfos.add(representationInfo);
} else if (XmlPullParserUtil.isStartTag(xpp, "SegmentBase")) {
segmentBase = parseSegmentBase(xpp, (SingleSegmentBase) segmentBase);
......@@ -389,20 +390,6 @@ public class DashManifestParser extends DefaultHandler
: C.TRACK_TYPE_UNKNOWN;
}
protected int getContentType(Format format) {
String sampleMimeType = format.sampleMimeType;
if (TextUtils.isEmpty(sampleMimeType)) {
return C.TRACK_TYPE_UNKNOWN;
} else if (MimeTypes.isVideo(sampleMimeType)) {
return C.TRACK_TYPE_VIDEO;
} else if (MimeTypes.isAudio(sampleMimeType)) {
return C.TRACK_TYPE_AUDIO;
} else if (mimeTypeIsRawText(sampleMimeType)) {
return C.TRACK_TYPE_TEXT;
}
return C.TRACK_TYPE_UNKNOWN;
}
/**
* Parses a ContentProtection element.
*
......@@ -620,7 +607,7 @@ public class DashManifestParser extends DefaultHandler
formatBuilder.setWidth(width).setHeight(height).setFrameRate(frameRate);
} else if (MimeTypes.isAudio(sampleMimeType)) {
formatBuilder.setChannelCount(audioChannels).setSampleRate(audioSamplingRate);
} else if (mimeTypeIsRawText(sampleMimeType)) {
} else if (MimeTypes.isText(sampleMimeType)) {
int accessibilityChannel = Format.NO_VALUE;
if (MimeTypes.APPLICATION_CEA608.equals(sampleMimeType)) {
accessibilityChannel = parseCea608AccessibilityChannel(accessibilityDescriptors);
......@@ -1310,44 +1297,20 @@ public class DashManifestParser extends DefaultHandler
return MimeTypes.getAudioMediaMimeType(codecs);
} else if (MimeTypes.isVideo(containerMimeType)) {
return MimeTypes.getVideoMediaMimeType(codecs);
} else if (mimeTypeIsRawText(containerMimeType)) {
} else if (MimeTypes.isText(containerMimeType)) {
if (MimeTypes.APPLICATION_RAWCC.equals(containerMimeType)) {
// RawCC is special because it's a text specific container format.
return MimeTypes.getTextMediaMimeType(codecs);
}
// All other text types are raw formats.
return containerMimeType;
} else if (MimeTypes.APPLICATION_MP4.equals(containerMimeType)) {
if (codecs != null) {
if (codecs.startsWith("stpp")) {
return MimeTypes.APPLICATION_TTML;
} else if (codecs.startsWith("wvtt")) {
return MimeTypes.APPLICATION_MP4VTT;
}
}
} else if (MimeTypes.APPLICATION_RAWCC.equals(containerMimeType)) {
if (codecs != null) {
if (codecs.contains("cea708")) {
return MimeTypes.APPLICATION_CEA708;
} else if (codecs.contains("eia608") || codecs.contains("cea608")) {
return MimeTypes.APPLICATION_CEA608;
}
}
return null;
return MimeTypes.getMediaMimeType(codecs);
}
return null;
}
/**
* Returns whether a mimeType is a text sample mimeType.
*
* @param mimeType The mimeType.
* @return Whether the mimeType is a text sample mimeType.
*/
private static boolean mimeTypeIsRawText(@Nullable String mimeType) {
return MimeTypes.isText(mimeType)
|| MimeTypes.APPLICATION_TTML.equals(mimeType)
|| MimeTypes.APPLICATION_MP4VTT.equals(mimeType)
|| MimeTypes.APPLICATION_CEA708.equals(mimeType)
|| MimeTypes.APPLICATION_CEA608.equals(mimeType);
}
/**
* Checks two languages for consistency, returning the consistent language, or throwing an {@link
* IllegalStateException} if the languages are inconsistent.
*
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment