From f342df204777fe2d369532205d491fb6da9be39d Mon Sep 17 00:00:00 2001 From: olly Date: Fri, 21 Feb 2020 19:41:31 +0000 Subject: [PATCH] Migrate DASH to Format.Builder Bitrates in the DASH manifest are peak bitrates, as per the ref'd issue. Issue: #5978 PiperOrigin-RevId: 296478812 --- .../source/dash/DashMediaPeriod.java | 27 +++-- .../dash/manifest/DashManifestParser.java | 111 ++++++------------ .../source/dash/DashMediaPeriodTest.java | 55 +++------ .../exoplayer2/source/dash/DashUtilTest.java | 28 ++--- .../source/dash/EventSampleStreamTest.java | 5 +- .../dash/manifest/DashManifestTest.java | 3 +- 6 files changed, 88 insertions(+), 141 deletions(-) diff --git a/library/dash/src/main/java/com/google/android/exoplayer2/source/dash/DashMediaPeriod.java b/library/dash/src/main/java/com/google/android/exoplayer2/source/dash/DashMediaPeriod.java index ffd4ccd751..c51a883049 100644 --- a/library/dash/src/main/java/com/google/android/exoplayer2/source/dash/DashMediaPeriod.java +++ b/library/dash/src/main/java/com/google/android/exoplayer2/source/dash/DashMediaPeriod.java @@ -642,7 +642,10 @@ import org.checkerframework.checker.nullness.compatqual.NullableType; cea608TrackGroupIndex); if (eventMessageTrackGroupIndex != C.INDEX_UNSET) { Format format = - Format.createSampleFormat(firstAdaptationSet.id + ":emsg", MimeTypes.APPLICATION_EMSG); + new Format.Builder() + .setId(firstAdaptationSet.id + ":emsg") + .setSampleMimeType(MimeTypes.APPLICATION_EMSG) + .build(); trackGroups[eventMessageTrackGroupIndex] = new TrackGroup(format); trackGroupInfos[eventMessageTrackGroupIndex] = TrackGroupInfo.embeddedEmsgTrack(adaptationSetIndices, primaryTrackGroupIndex); @@ -660,7 +663,11 @@ import org.checkerframework.checker.nullness.compatqual.NullableType; TrackGroup[] trackGroups, TrackGroupInfo[] trackGroupInfos, int existingTrackGroupCount) { for (int i = 0; i < eventStreams.size(); i++) { EventStream eventStream = eventStreams.get(i); - Format format = Format.createSampleFormat(eventStream.id(), MimeTypes.APPLICATION_EMSG); + Format format = + new Format.Builder() + .setId(eventStream.id()) + .setSampleMimeType(MimeTypes.APPLICATION_EMSG) + .build(); trackGroups[existingTrackGroupCount] = new TrackGroup(format); trackGroupInfos[existingTrackGroupCount++] = TrackGroupInfo.mpdEventTrack(i); } @@ -804,16 +811,16 @@ import org.checkerframework.checker.nullness.compatqual.NullableType; private static Format buildCea608TrackFormat( int adaptationSetId, @Nullable String language, int accessibilityChannel) { - return Format.createTextSampleFormat( + String id = adaptationSetId + ":cea608" - + (accessibilityChannel != Format.NO_VALUE ? ":" + accessibilityChannel : ""), - MimeTypes.APPLICATION_CEA608, - /* selectionFlags= */ 0, - language, - accessibilityChannel, - Format.OFFSET_SAMPLE_RELATIVE, - /* initializationData= */ null); + + (accessibilityChannel != Format.NO_VALUE ? ":" + accessibilityChannel : ""); + return new Format.Builder() + .setId(id) + .setSampleMimeType(MimeTypes.APPLICATION_CEA608) + .setLanguage(language) + .setAccessibilityChannel(accessibilityChannel) + .build(); } // We won't assign the array to a variable that erases the generic type, and then write into it. diff --git a/library/dash/src/main/java/com/google/android/exoplayer2/source/dash/manifest/DashManifestParser.java b/library/dash/src/main/java/com/google/android/exoplayer2/source/dash/manifest/DashManifestParser.java index b107be4794..85470b07b5 100644 --- a/library/dash/src/main/java/com/google/android/exoplayer2/source/dash/manifest/DashManifestParser.java +++ b/library/dash/src/main/java/com/google/android/exoplayer2/source/dash/manifest/DashManifestParser.java @@ -589,76 +589,40 @@ public class DashManifestParser extends DefaultHandler List accessibilityDescriptors, @Nullable String codecs, List supplementalProperties) { - String sampleMimeType = getSampleMimeType(containerMimeType, codecs); + @Nullable String sampleMimeType = getSampleMimeType(containerMimeType, codecs); + if (MimeTypes.AUDIO_E_AC3.equals(sampleMimeType)) { + sampleMimeType = parseEac3SupplementalProperties(supplementalProperties); + } @C.SelectionFlags int selectionFlags = parseSelectionFlagsFromRoleDescriptors(roleDescriptors); @C.RoleFlags int roleFlags = parseRoleFlagsFromRoleDescriptors(roleDescriptors); roleFlags |= parseRoleFlagsFromAccessibilityDescriptors(accessibilityDescriptors); - if (sampleMimeType != null) { - if (MimeTypes.AUDIO_E_AC3.equals(sampleMimeType)) { - sampleMimeType = parseEac3SupplementalProperties(supplementalProperties); - } - if (MimeTypes.isVideo(sampleMimeType)) { - return Format.createVideoContainerFormat( - id, - /* label= */ null, - containerMimeType, - sampleMimeType, - codecs, - /* metadata= */ null, - bitrate, - width, - height, - frameRate, - /* initializationData= */ null, - selectionFlags, - roleFlags); - } else if (MimeTypes.isAudio(sampleMimeType)) { - return Format.createAudioContainerFormat( - id, - /* label= */ null, - containerMimeType, - sampleMimeType, - codecs, - /* metadata= */ null, - bitrate, - audioChannels, - audioSamplingRate, - /* initializationData= */ null, - selectionFlags, - roleFlags, - language); - } else if (mimeTypeIsRawText(sampleMimeType)) { - int accessibilityChannel; - if (MimeTypes.APPLICATION_CEA608.equals(sampleMimeType)) { - accessibilityChannel = parseCea608AccessibilityChannel(accessibilityDescriptors); - } else if (MimeTypes.APPLICATION_CEA708.equals(sampleMimeType)) { - accessibilityChannel = parseCea708AccessibilityChannel(accessibilityDescriptors); - } else { - accessibilityChannel = Format.NO_VALUE; - } - return Format.createTextContainerFormat( - id, - /* label= */ null, - containerMimeType, - sampleMimeType, - codecs, - bitrate, - selectionFlags, - roleFlags, - language, - accessibilityChannel); + + Format.Builder formatBuilder = + new Format.Builder() + .setId(id) + .setContainerMimeType(containerMimeType) + .setSampleMimeType(sampleMimeType) + .setCodecs(codecs) + .setPeakBitrate(bitrate) + .setSelectionFlags(selectionFlags) + .setRoleFlags(roleFlags) + .setLanguage(language); + + if (MimeTypes.isVideo(sampleMimeType)) { + formatBuilder.setWidth(width).setHeight(height).setFrameRate(frameRate); + } else if (MimeTypes.isAudio(sampleMimeType)) { + formatBuilder.setChannelCount(audioChannels).setSampleRate(audioSamplingRate); + } else if (mimeTypeIsRawText(sampleMimeType)) { + int accessibilityChannel = Format.NO_VALUE; + if (MimeTypes.APPLICATION_CEA608.equals(sampleMimeType)) { + accessibilityChannel = parseCea608AccessibilityChannel(accessibilityDescriptors); + } else if (MimeTypes.APPLICATION_CEA708.equals(sampleMimeType)) { + accessibilityChannel = parseCea708AccessibilityChannel(accessibilityDescriptors); } + formatBuilder.setAccessibilityChannel(accessibilityChannel); } - return Format.createContainerFormat( - id, - /* label= */ null, - containerMimeType, - sampleMimeType, - codecs, - bitrate, - selectionFlags, - roleFlags, - language); + + return formatBuilder.build(); } protected Representation buildRepresentation( @@ -667,24 +631,25 @@ public class DashManifestParser extends DefaultHandler @Nullable String extraDrmSchemeType, ArrayList extraDrmSchemeDatas, ArrayList extraInbandEventStreams) { - Format format = representationInfo.format; + Format.Builder formatBuilder = representationInfo.format.buildUpon(); if (label != null) { - format = format.copyWithLabel(label); + formatBuilder.setLabel(label); + } + @Nullable String drmSchemeType = representationInfo.drmSchemeType; + if (drmSchemeType == null) { + drmSchemeType = extraDrmSchemeType; } - String drmSchemeType = representationInfo.drmSchemeType != null - ? representationInfo.drmSchemeType : extraDrmSchemeType; ArrayList drmSchemeDatas = representationInfo.drmSchemeDatas; drmSchemeDatas.addAll(extraDrmSchemeDatas); if (!drmSchemeDatas.isEmpty()) { filterRedundantIncompleteSchemeDatas(drmSchemeDatas); - DrmInitData drmInitData = new DrmInitData(drmSchemeType, drmSchemeDatas); - format = format.copyWithDrmInitData(drmInitData); + formatBuilder.setDrmInitData(new DrmInitData(drmSchemeType, drmSchemeDatas)); } ArrayList inbandEventStreams = representationInfo.inbandEventStreams; inbandEventStreams.addAll(extraInbandEventStreams); return Representation.newInstance( representationInfo.revisionId, - format, + formatBuilder.build(), representationInfo.baseUrl, representationInfo.segmentBase, inbandEventStreams); @@ -709,7 +674,7 @@ public class DashManifestParser extends DefaultHandler indexLength = Long.parseLong(indexRange[1]) - indexStart + 1; } - RangedUri initialization = parent != null ? parent.initialization : null; + @Nullable RangedUri initialization = parent != null ? parent.initialization : null; do { xpp.next(); if (XmlPullParserUtil.isStartTag(xpp, "Initialization")) { diff --git a/library/dash/src/test/java/com/google/android/exoplayer2/source/dash/DashMediaPeriodTest.java b/library/dash/src/test/java/com/google/android/exoplayer2/source/dash/DashMediaPeriodTest.java index f7d7b9674b..92aa49d3f1 100644 --- a/library/dash/src/test/java/com/google/android/exoplayer2/source/dash/DashMediaPeriodTest.java +++ b/library/dash/src/test/java/com/google/android/exoplayer2/source/dash/DashMediaPeriodTest.java @@ -186,50 +186,33 @@ public final class DashMediaPeriodTest { } private static Format createVideoFormat(int bitrate) { - return Format.createContainerFormat( - /* id= */ null, - /* label= */ null, - MimeTypes.VIDEO_MP4, - MimeTypes.VIDEO_H264, - /* codecs= */ null, - bitrate, - /* selectionFlags= */ 0, - /* roleFlags= */ 0, - /* language= */ null); + return new Format.Builder() + .setContainerMimeType(MimeTypes.VIDEO_MP4) + .setSampleMimeType(MimeTypes.VIDEO_H264) + .setPeakBitrate(bitrate) + .build(); } private static Representation createAudioRepresentation(int bitrate) { + Format format = + new Format.Builder() + .setContainerMimeType(MimeTypes.AUDIO_MP4) + .setSampleMimeType(MimeTypes.AUDIO_AAC) + .setPeakBitrate(bitrate) + .build(); return Representation.newInstance( - /* revisionId= */ 0, - Format.createContainerFormat( - /* id= */ null, - /* label= */ null, - MimeTypes.AUDIO_MP4, - MimeTypes.AUDIO_AAC, - /* codecs= */ null, - bitrate, - /* selectionFlags= */ 0, - /* roleFlags= */ 0, - /* language= */ null), - /* baseUrl= */ "", - new SingleSegmentBase()); + /* revisionId= */ 0, format, /* baseUrl= */ "", new SingleSegmentBase()); } private static Representation createTextRepresentation(String language) { + Format format = + new Format.Builder() + .setContainerMimeType(MimeTypes.APPLICATION_MP4) + .setSampleMimeType(MimeTypes.TEXT_VTT) + .setLanguage(language) + .build(); return Representation.newInstance( - /* revisionId= */ 0, - Format.createContainerFormat( - /* id= */ null, - /* label= */ null, - MimeTypes.APPLICATION_MP4, - MimeTypes.TEXT_VTT, - /* codecs= */ null, - /* bitrate= */ Format.NO_VALUE, - /* selectionFlags= */ 0, - /* roleFlags= */ 0, - language), - /* baseUrl= */ "", - new SingleSegmentBase()); + /* revisionId= */ 0, format, /* baseUrl= */ "", new SingleSegmentBase()); } private static Descriptor createSwitchDescriptor(int... ids) { diff --git a/library/dash/src/test/java/com/google/android/exoplayer2/source/dash/DashUtilTest.java b/library/dash/src/test/java/com/google/android/exoplayer2/source/dash/DashUtilTest.java index 6e769b72e1..86a3fe0dd8 100644 --- a/library/dash/src/test/java/com/google/android/exoplayer2/source/dash/DashUtilTest.java +++ b/library/dash/src/test/java/com/google/android/exoplayer2/source/dash/DashUtilTest.java @@ -38,21 +38,21 @@ public final class DashUtilTest { @Test public void testLoadDrmInitDataFromManifest() throws Exception { - Period period = newPeriod(newAdaptationSets(newRepresentations(newDrmInitData()))); + Period period = newPeriod(newAdaptationSet(newRepresentation(newDrmInitData()))); DrmInitData drmInitData = DashUtil.loadDrmInitData(DummyDataSource.INSTANCE, period); assertThat(drmInitData).isEqualTo(newDrmInitData()); } @Test public void testLoadDrmInitDataMissing() throws Exception { - Period period = newPeriod(newAdaptationSets(newRepresentations(null /* no init data */))); + Period period = newPeriod(newAdaptationSet(newRepresentation(null /* no init data */))); DrmInitData drmInitData = DashUtil.loadDrmInitData(DummyDataSource.INSTANCE, period); assertThat(drmInitData).isNull(); } @Test public void testLoadDrmInitDataNoRepresentations() throws Exception { - Period period = newPeriod(newAdaptationSets(/* no representation */ )); + Period period = newPeriod(newAdaptationSet(/* no representation */ )); DrmInitData drmInitData = DashUtil.loadDrmInitData(DummyDataSource.INSTANCE, period); assertThat(drmInitData).isNull(); } @@ -68,26 +68,16 @@ public final class DashUtilTest { return new Period("", 0, Arrays.asList(adaptationSets)); } - private static AdaptationSet newAdaptationSets(Representation... representations) { + private static AdaptationSet newAdaptationSet(Representation... representations) { return new AdaptationSet(0, C.TRACK_TYPE_VIDEO, Arrays.asList(representations), null, null); } - private static Representation newRepresentations(DrmInitData drmInitData) { + private static Representation newRepresentation(DrmInitData drmInitData) { Format format = - Format.createVideoContainerFormat( - "id", - "label", - MimeTypes.VIDEO_MP4, - MimeTypes.VIDEO_H264, - /* codecs= */ "", - /* metadata= */ null, - Format.NO_VALUE, - /* width= */ 1024, - /* height= */ 768, - Format.NO_VALUE, - /* initializationData= */ null, - /* selectionFlags= */ 0, - /* roleFlags= */ 0); + new Format.Builder() + .setContainerMimeType(MimeTypes.VIDEO_MP4) + .setSampleMimeType(MimeTypes.VIDEO_H264) + .build(); if (drmInitData != null) { format = format.copyWithDrmInitData(drmInitData); } diff --git a/library/dash/src/test/java/com/google/android/exoplayer2/source/dash/EventSampleStreamTest.java b/library/dash/src/test/java/com/google/android/exoplayer2/source/dash/EventSampleStreamTest.java index 10342ed4ab..d77b20e0c4 100644 --- a/library/dash/src/test/java/com/google/android/exoplayer2/source/dash/EventSampleStreamTest.java +++ b/library/dash/src/test/java/com/google/android/exoplayer2/source/dash/EventSampleStreamTest.java @@ -38,7 +38,10 @@ public final class EventSampleStreamTest { private static final String SCHEME_ID = "urn:test"; private static final String VALUE = "123"; private static final Format FORMAT = - Format.createSampleFormat("urn:test/123", MimeTypes.APPLICATION_EMSG); + new Format.Builder() + .setId("urn:test/123") + .setSampleMimeType(MimeTypes.APPLICATION_EMSG) + .build(); private static final byte[] MESSAGE_DATA = new byte[] {1, 2, 3, 4}; private static final long DURATION_MS = 3000; private static final long TIME_SCALE = 1000; diff --git a/library/dash/src/test/java/com/google/android/exoplayer2/source/dash/manifest/DashManifestTest.java b/library/dash/src/test/java/com/google/android/exoplayer2/source/dash/manifest/DashManifestTest.java index 8134b2ba61..f98d929376 100644 --- a/library/dash/src/test/java/com/google/android/exoplayer2/source/dash/manifest/DashManifestTest.java +++ b/library/dash/src/test/java/com/google/android/exoplayer2/source/dash/manifest/DashManifestTest.java @@ -35,8 +35,7 @@ public class DashManifestTest { private static final UtcTimingElement DUMMY_UTC_TIMING = new UtcTimingElement("", ""); private static final SingleSegmentBase DUMMY_SEGMENT_BASE = new SingleSegmentBase(); - private static final Format DUMMY_FORMAT = - Format.createSampleFormat(/* id= */ "", /* sampleMimeType= */ ""); + private static final Format DUMMY_FORMAT = new Format.Builder().build(); @Test public void testCopy() {