Clean up manifest MIME type and codec parsing

PiperOrigin-RevId: 305258836
This commit is contained in:
olly 2020-04-07 16:02:54 +01:00 committed by Oliver Woodman
parent f9679a2cfb
commit 74a9d8f680
4 changed files with 87 additions and 70 deletions

View file

@ -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);
}
/**
@ -210,6 +219,27 @@ public final class MimeTypes {
return null;
}
/**
* 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.
*
@ -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)

View file

@ -25,6 +25,29 @@ import org.junit.runner.RunWith;
@RunWith(AndroidJUnit4.class)
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);
@ -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

View file

@ -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 {

View file

@ -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,43 +1297,19 @@ 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.