Expose no CC tracks if CLOSED-CAPTIONS=NONE is present
Issue:#2743 ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=155182859
This commit is contained in:
parent
4c39627ed1
commit
5d459c8103
@ -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<HlsMasterPlaylist.HlsUrl> 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);
|
||||
|
@ -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,
|
||||
|
@ -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<Format> 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);
|
||||
|
@ -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<HlsUrl> variants;
|
||||
/**
|
||||
* The list of demuxed audios declared by the playlist.
|
||||
*/
|
||||
public final List<HlsUrl> audios;
|
||||
/**
|
||||
* The list of subtitles declared by the playlist.
|
||||
*/
|
||||
public final List<HlsUrl> 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<Format> 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<HlsUrl> variants, List<HlsUrl> audios,
|
||||
List<HlsUrl> subtitles, Format muxedAudioFormat, List<Format> 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<HlsUrl> 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<HlsUrl> variant = Collections.singletonList(HlsUrl.createMediaPlaylistHlsUrl(variantUrl));
|
||||
List<HlsUrl> emptyList = Collections.emptyList();
|
||||
return new HlsMasterPlaylist(null, variant, emptyList, emptyList, null,
|
||||
Collections.<Format>emptyList());
|
||||
return new HlsMasterPlaylist(null, variant, emptyList, emptyList, null, null);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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<HlsPlayli
|
||||
private static final String BOOLEAN_TRUE = "YES";
|
||||
private static final String BOOLEAN_FALSE = "NO";
|
||||
|
||||
private static final String ATTR_CLOSED_CAPTIONS_NONE = "CLOSED-CAPTIONS=NONE";
|
||||
|
||||
private static final Pattern REGEX_BANDWIDTH = Pattern.compile("BANDWIDTH=(\\d+)\\b");
|
||||
private static final Pattern REGEX_CODECS = Pattern.compile("CODECS=\"(.+?)\"");
|
||||
private static final Pattern REGEX_RESOLUTION = Pattern.compile("RESOLUTION=(\\d+x\\d+)");
|
||||
@ -173,7 +176,8 @@ public final class HlsPlaylistParser implements ParsingLoadable.Parser<HlsPlayli
|
||||
ArrayList<HlsMasterPlaylist.HlsUrl> audios = new ArrayList<>();
|
||||
ArrayList<HlsMasterPlaylist.HlsUrl> subtitles = new ArrayList<>();
|
||||
Format muxedAudioFormat = null;
|
||||
ArrayList<Format> muxedCaptionFormats = new ArrayList<>();
|
||||
List<Format> muxedCaptionFormats = null;
|
||||
boolean noClosedCaptions = false;
|
||||
|
||||
String line;
|
||||
while (iterator.hasNext()) {
|
||||
@ -210,6 +214,9 @@ public final class HlsPlaylistParser implements ParsingLoadable.Parser<HlsPlayli
|
||||
mimeType = MimeTypes.APPLICATION_CEA708;
|
||||
accessibilityChannel = Integer.parseInt(instreamId.substring(7));
|
||||
}
|
||||
if (muxedCaptionFormats == null) {
|
||||
muxedCaptionFormats = new ArrayList<>();
|
||||
}
|
||||
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<HlsPlayli
|
||||
int bitrate = parseIntAttr(line, REGEX_BANDWIDTH);
|
||||
String codecs = parseOptionalStringAttr(line, REGEX_CODECS);
|
||||
String resolutionString = parseOptionalStringAttr(line, REGEX_RESOLUTION);
|
||||
noClosedCaptions |= line.contains(ATTR_CLOSED_CAPTIONS_NONE);
|
||||
int width;
|
||||
int height;
|
||||
if (resolutionString != null) {
|
||||
@ -243,6 +251,9 @@ public final class HlsPlaylistParser implements ParsingLoadable.Parser<HlsPlayli
|
||||
variants.add(new HlsMasterPlaylist.HlsUrl(line, format));
|
||||
}
|
||||
}
|
||||
if (noClosedCaptions) {
|
||||
muxedCaptionFormats = Collections.emptyList();
|
||||
}
|
||||
return new HlsMasterPlaylist(baseUri, variants, audios, subtitles, muxedAudioFormat,
|
||||
muxedCaptionFormats);
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user