From 5d459c8103a00735260a2f849c00f98a1d6e865d Mon Sep 17 00:00:00 2001 From: aquilescanta Date: Fri, 5 May 2017 03:49:22 -0700 Subject: [PATCH] Expose no CC tracks if CLOSED-CAPTIONS=NONE is present Issue:#2743 ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=155182859 --- .../playlist/HlsMasterPlaylistParserTest.java | 14 ++++- .../exoplayer2/source/hls/HlsChunkSource.java | 3 +- .../exoplayer2/source/hls/HlsMediaChunk.java | 11 +++- .../hls/playlist/HlsMasterPlaylist.java | 62 ++++++++++++++++--- .../hls/playlist/HlsPlaylistParser.java | 13 +++- 5 files changed, 90 insertions(+), 13 deletions(-) diff --git a/library/hls/src/androidTest/java/com/google/android/exoplayer2/source/hls/playlist/HlsMasterPlaylistParserTest.java b/library/hls/src/androidTest/java/com/google/android/exoplayer2/source/hls/playlist/HlsMasterPlaylistParserTest.java index aa279f23f4..912dcb28b2 100644 --- a/library/hls/src/androidTest/java/com/google/android/exoplayer2/source/hls/playlist/HlsMasterPlaylistParserTest.java +++ b/library/hls/src/androidTest/java/com/google/android/exoplayer2/source/hls/playlist/HlsMasterPlaylistParserTest.java @@ -23,6 +23,7 @@ import com.google.android.exoplayer2.util.MimeTypes; import java.io.ByteArrayInputStream; import java.io.IOException; import java.nio.charset.Charset; +import java.util.Collections; import java.util.List; import junit.framework.TestCase; @@ -56,16 +57,22 @@ public class HlsMasterPlaylistParserTest extends TestCase { private static final String MASTER_PLAYLIST_WITH_CC = " #EXTM3U \n" + "#EXT-X-MEDIA:TYPE=CLOSED-CAPTIONS,LANGUAGE=\"es\",NAME=\"Eng\",INSTREAM-ID=\"SERVICE4\"\n" - + "\n" + "#EXT-X-STREAM-INF:BANDWIDTH=1280000,CODECS=\"mp4a.40.2,avc1.66.30\",RESOLUTION=304x128\n" + "http://example.com/low.m3u8\n"; + private static final String MASTER_PLAYLIST_WITHOUT_CC = " #EXTM3U \n" + + "#EXT-X-MEDIA:TYPE=CLOSED-CAPTIONS,LANGUAGE=\"es\",NAME=\"Eng\",INSTREAM-ID=\"SERVICE4\"\n" + + "#EXT-X-STREAM-INF:BANDWIDTH=1280000,CODECS=\"mp4a.40.2,avc1.66.30\",RESOLUTION=304x128," + + "CLOSED-CAPTIONS=NONE\n" + + "http://example.com/low.m3u8\n"; + public void testParseMasterPlaylist() throws IOException{ HlsMasterPlaylist masterPlaylist = parseMasterPlaylist(PLAYLIST_URI, MASTER_PLAYLIST); List variants = masterPlaylist.variants; assertNotNull(variants); assertEquals(5, variants.size()); + assertNull(masterPlaylist.muxedCaptionFormats); assertEquals(1280000, variants.get(0).format.bitrate); assertNotNull(variants.get(0).format.codecs); @@ -117,6 +124,11 @@ public class HlsMasterPlaylistParserTest extends TestCase { assertEquals("es", closedCaptionFormat.language); } + public void testPlaylistWithoutClosedCaptions() throws IOException { + HlsMasterPlaylist playlist = parseMasterPlaylist(PLAYLIST_URI, MASTER_PLAYLIST_WITHOUT_CC); + assertEquals(Collections.emptyList(), playlist.muxedCaptionFormats); + } + private static HlsMasterPlaylist parseMasterPlaylist(String uri, String playlistString) throws IOException { Uri playlistUri = Uri.parse(uri); diff --git a/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/HlsChunkSource.java b/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/HlsChunkSource.java index ea99dae345..49c4d04abc 100644 --- a/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/HlsChunkSource.java +++ b/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/HlsChunkSource.java @@ -111,7 +111,8 @@ import java.util.Locale; * @param timestampAdjusterProvider A provider of {@link TimestampAdjuster} instances. If * multiple {@link HlsChunkSource}s are used for a single playback, they should all share the * same provider. - * @param muxedCaptionFormats List of muxed caption {@link Format}s. + * @param muxedCaptionFormats List of muxed caption {@link Format}s. Null if no closed caption + * information is available in the master playlist. */ public HlsChunkSource(HlsPlaylistTracker playlistTracker, HlsUrl[] variants, HlsDataSourceFactory dataSourceFactory, TimestampAdjusterProvider timestampAdjusterProvider, diff --git a/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/HlsMediaChunk.java b/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/HlsMediaChunk.java index 6f516923f9..6997324f02 100644 --- a/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/HlsMediaChunk.java +++ b/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/HlsMediaChunk.java @@ -39,6 +39,7 @@ import com.google.android.exoplayer2.util.ParsableByteArray; import com.google.android.exoplayer2.util.TimestampAdjuster; import com.google.android.exoplayer2.util.Util; import java.io.IOException; +import java.util.Collections; import java.util.List; import java.util.concurrent.atomic.AtomicInteger; @@ -104,7 +105,8 @@ import java.util.concurrent.atomic.AtomicInteger; * @param dataSpec Defines the data to be loaded. * @param initDataSpec Defines the initialization data to be fed to new extractors. May be null. * @param hlsUrl The url of the playlist from which this chunk was obtained. - * @param muxedCaptionFormats List of muxed caption {@link Format}s. + * @param muxedCaptionFormats List of muxed caption {@link Format}s. Null if no closed caption + * information is available in the master playlist. * @param trackSelectionReason See {@link #trackSelectionReason}. * @param trackSelectionData See {@link #trackSelectionData}. * @param startTimeUs The start time of the chunk in microseconds. @@ -356,9 +358,12 @@ import java.util.concurrent.atomic.AtomicInteger; // This flag ensures the change of pid between streams does not affect the sample queues. @DefaultTsPayloadReaderFactory.Flags int esReaderFactoryFlags = DefaultTsPayloadReaderFactory.FLAG_IGNORE_SPLICE_INFO_STREAM; - if (!muxedCaptionFormats.isEmpty()) { + List closedCaptionFormats = muxedCaptionFormats; + if (closedCaptionFormats != null) { // The playlist declares closed caption renditions, we should ignore descriptors. esReaderFactoryFlags |= DefaultTsPayloadReaderFactory.FLAG_OVERRIDE_CAPTION_DESCRIPTORS; + } else { + closedCaptionFormats = Collections.emptyList(); } String codecs = trackFormat.codecs; if (!TextUtils.isEmpty(codecs)) { @@ -373,7 +378,7 @@ import java.util.concurrent.atomic.AtomicInteger; } } extractor = new TsExtractor(TsExtractor.MODE_HLS, timestampAdjuster, - new DefaultTsPayloadReaderFactory(esReaderFactoryFlags, muxedCaptionFormats)); + new DefaultTsPayloadReaderFactory(esReaderFactoryFlags, closedCaptionFormats)); } if (usingNewExtractor) { extractor.init(extractorOutput); diff --git a/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/playlist/HlsMasterPlaylist.java b/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/playlist/HlsMasterPlaylist.java index 5a8c63f609..874c865049 100644 --- a/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/playlist/HlsMasterPlaylist.java +++ b/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/playlist/HlsMasterPlaylist.java @@ -30,15 +30,31 @@ public final class HlsMasterPlaylist extends HlsPlaylist { */ public static final class HlsUrl { + /** + * The http url from which the media playlist can be obtained. + */ public final String url; + /** + * Format information associated with the HLS url. + */ public final Format format; - public static HlsUrl createMediaPlaylistHlsUrl(String baseUri) { + /** + * Creates an HLS url from a given http url. + * + * @param url The url. + * @return An HLS url. + */ + public static HlsUrl createMediaPlaylistHlsUrl(String url) { Format format = Format.createContainerFormat("0", MimeTypes.APPLICATION_M3U8, null, null, Format.NO_VALUE, 0, null); - return new HlsUrl(baseUri, format); + return new HlsUrl(url, format); } + /** + * @param url See {@link #url}. + * @param format See {@link #format}. + */ public HlsUrl(String url, Format format) { this.url = url; this.format = format; @@ -46,13 +62,39 @@ public final class HlsMasterPlaylist extends HlsPlaylist { } + /** + * The list of variants declared by the playlist. + */ public final List variants; + /** + * The list of demuxed audios declared by the playlist. + */ public final List audios; + /** + * The list of subtitles declared by the playlist. + */ public final List subtitles; + /** + * The format of the audio muxed in the variants. May be null if the playlist does not declare any + * muxed audio. + */ public final Format muxedAudioFormat; + /** + * The format of the closed captions declared by the playlist. May be empty if the playlist + * explicitly declares no captions are available, or null if the playlist does not declare any + * captions information. + */ public final List muxedCaptionFormats; + /** + * @param baseUri The base uri. Used to resolve relative paths. + * @param variants See {@link #variants}. + * @param audios See {@link #audios}. + * @param subtitles See {@link #subtitles}. + * @param muxedAudioFormat See {@link #muxedAudioFormat}. + * @param muxedCaptionFormats See {@link #muxedCaptionFormats}. + */ public HlsMasterPlaylist(String baseUri, List variants, List audios, List subtitles, Format muxedAudioFormat, List muxedCaptionFormats) { super(baseUri); @@ -60,14 +102,20 @@ public final class HlsMasterPlaylist extends HlsPlaylist { this.audios = Collections.unmodifiableList(audios); this.subtitles = Collections.unmodifiableList(subtitles); this.muxedAudioFormat = muxedAudioFormat; - this.muxedCaptionFormats = Collections.unmodifiableList(muxedCaptionFormats); + this.muxedCaptionFormats = muxedCaptionFormats != null + ? Collections.unmodifiableList(muxedCaptionFormats) : null; } - public static HlsMasterPlaylist createSingleVariantMasterPlaylist(String variantUri) { - List variant = Collections.singletonList(HlsUrl.createMediaPlaylistHlsUrl(variantUri)); + /** + * Creates a playlist with a single variant. + * + * @param variantUrl The url of the single variant. + * @return A master playlist with a single variant for the provided url. + */ + public static HlsMasterPlaylist createSingleVariantMasterPlaylist(String variantUrl) { + List variant = Collections.singletonList(HlsUrl.createMediaPlaylistHlsUrl(variantUrl)); List emptyList = Collections.emptyList(); - return new HlsMasterPlaylist(null, variant, emptyList, emptyList, null, - Collections.emptyList()); + return new HlsMasterPlaylist(null, variant, emptyList, emptyList, null, null); } } diff --git a/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/playlist/HlsPlaylistParser.java b/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/playlist/HlsPlaylistParser.java index 8e01dec6fe..664306baff 100644 --- a/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/playlist/HlsPlaylistParser.java +++ b/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/playlist/HlsPlaylistParser.java @@ -29,6 +29,7 @@ import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.util.ArrayList; +import java.util.Collections; import java.util.LinkedList; import java.util.List; import java.util.Queue; @@ -70,6 +71,8 @@ public final class HlsPlaylistParser implements ParsingLoadable.Parser audios = new ArrayList<>(); ArrayList subtitles = new ArrayList<>(); Format muxedAudioFormat = null; - ArrayList muxedCaptionFormats = new ArrayList<>(); + List muxedCaptionFormats = null; + boolean noClosedCaptions = false; String line; while (iterator.hasNext()) { @@ -210,6 +214,9 @@ public final class HlsPlaylistParser implements ParsingLoadable.Parser(); + } muxedCaptionFormats.add(Format.createTextContainerFormat(id, null, mimeType, null, Format.NO_VALUE, selectionFlags, language, accessibilityChannel)); break; @@ -221,6 +228,7 @@ public final class HlsPlaylistParser implements ParsingLoadable.Parser