Commit 2690f569 by olly Committed by Oliver Woodman

Enable track selection + WebVTT for HLS.

See the documentation of buildTracks for the gory details.

Issue: #151
Issue: #676
-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=112149293
parent b6b97a86
...@@ -25,12 +25,14 @@ import com.google.android.exoplayer.audio.AudioCapabilities; ...@@ -25,12 +25,14 @@ import com.google.android.exoplayer.audio.AudioCapabilities;
import com.google.android.exoplayer.demo.player.DemoPlayer.RendererBuilder; import com.google.android.exoplayer.demo.player.DemoPlayer.RendererBuilder;
import com.google.android.exoplayer.hls.DefaultHlsTrackSelector; import com.google.android.exoplayer.hls.DefaultHlsTrackSelector;
import com.google.android.exoplayer.hls.HlsChunkSource; import com.google.android.exoplayer.hls.HlsChunkSource;
import com.google.android.exoplayer.hls.HlsMasterPlaylist;
import com.google.android.exoplayer.hls.HlsPlaylist; import com.google.android.exoplayer.hls.HlsPlaylist;
import com.google.android.exoplayer.hls.HlsPlaylistParser; import com.google.android.exoplayer.hls.HlsPlaylistParser;
import com.google.android.exoplayer.hls.HlsSampleSource; import com.google.android.exoplayer.hls.HlsSampleSource;
import com.google.android.exoplayer.hls.PtsTimestampAdjusterProvider; import com.google.android.exoplayer.hls.PtsTimestampAdjusterProvider;
import com.google.android.exoplayer.metadata.Id3Parser; import com.google.android.exoplayer.metadata.Id3Parser;
import com.google.android.exoplayer.metadata.MetadataTrackRenderer; import com.google.android.exoplayer.metadata.MetadataTrackRenderer;
import com.google.android.exoplayer.text.TextTrackRenderer;
import com.google.android.exoplayer.text.eia608.Eia608TrackRenderer; import com.google.android.exoplayer.text.eia608.Eia608TrackRenderer;
import com.google.android.exoplayer.upstream.DataSource; import com.google.android.exoplayer.upstream.DataSource;
import com.google.android.exoplayer.upstream.DefaultAllocator; import com.google.android.exoplayer.upstream.DefaultAllocator;
...@@ -53,7 +55,8 @@ import java.util.Map; ...@@ -53,7 +55,8 @@ import java.util.Map;
public class HlsRendererBuilder implements RendererBuilder { public class HlsRendererBuilder implements RendererBuilder {
private static final int BUFFER_SEGMENT_SIZE = 64 * 1024; private static final int BUFFER_SEGMENT_SIZE = 64 * 1024;
private static final int BUFFER_SEGMENTS = 256; private static final int MAIN_BUFFER_SEGMENTS = 256;
private static final int TEXT_BUFFER_SEGMENTS = 2;
private final Context context; private final Context context;
private final String userAgent; private final String userAgent;
...@@ -127,13 +130,15 @@ public class HlsRendererBuilder implements RendererBuilder { ...@@ -127,13 +130,15 @@ public class HlsRendererBuilder implements RendererBuilder {
Handler mainHandler = player.getMainHandler(); Handler mainHandler = player.getMainHandler();
LoadControl loadControl = new DefaultLoadControl(new DefaultAllocator(BUFFER_SEGMENT_SIZE)); LoadControl loadControl = new DefaultLoadControl(new DefaultAllocator(BUFFER_SEGMENT_SIZE));
DefaultBandwidthMeter bandwidthMeter = new DefaultBandwidthMeter(); DefaultBandwidthMeter bandwidthMeter = new DefaultBandwidthMeter();
PtsTimestampAdjusterProvider timestampAdjusterProvider = new PtsTimestampAdjusterProvider();
// Build the video/audio/metadata renderers.
DataSource dataSource = new DefaultUriDataSource(context, bandwidthMeter, userAgent); DataSource dataSource = new DefaultUriDataSource(context, bandwidthMeter, userAgent);
HlsChunkSource chunkSource = new HlsChunkSource(true /* isMaster */, dataSource, url, HlsChunkSource chunkSource = new HlsChunkSource(true /* isMaster */, dataSource, url,
manifest, DefaultHlsTrackSelector.newDefaultInstance(context), bandwidthMeter, manifest, DefaultHlsTrackSelector.newDefaultInstance(context), bandwidthMeter,
new PtsTimestampAdjusterProvider(), HlsChunkSource.ADAPTIVE_MODE_SPLICE); timestampAdjusterProvider, HlsChunkSource.ADAPTIVE_MODE_SPLICE);
HlsSampleSource sampleSource = new HlsSampleSource(chunkSource, loadControl, HlsSampleSource sampleSource = new HlsSampleSource(chunkSource, loadControl,
BUFFER_SEGMENTS * BUFFER_SEGMENT_SIZE, mainHandler, player, DemoPlayer.TYPE_VIDEO); MAIN_BUFFER_SEGMENTS * BUFFER_SEGMENT_SIZE, mainHandler, player, DemoPlayer.TYPE_VIDEO);
MediaCodecVideoTrackRenderer videoRenderer = new MediaCodecVideoTrackRenderer(context, MediaCodecVideoTrackRenderer videoRenderer = new MediaCodecVideoTrackRenderer(context,
sampleSource, MediaCodecSelector.DEFAULT, MediaCodec.VIDEO_SCALING_MODE_SCALE_TO_FIT, sampleSource, MediaCodecSelector.DEFAULT, MediaCodec.VIDEO_SCALING_MODE_SCALE_TO_FIT,
5000, mainHandler, player, 50); 5000, mainHandler, player, 50);
...@@ -142,14 +147,30 @@ public class HlsRendererBuilder implements RendererBuilder { ...@@ -142,14 +147,30 @@ public class HlsRendererBuilder implements RendererBuilder {
AudioCapabilities.getCapabilities(context), AudioManager.STREAM_MUSIC); AudioCapabilities.getCapabilities(context), AudioManager.STREAM_MUSIC);
MetadataTrackRenderer<Map<String, Object>> id3Renderer = new MetadataTrackRenderer<>( MetadataTrackRenderer<Map<String, Object>> id3Renderer = new MetadataTrackRenderer<>(
sampleSource, new Id3Parser(), player, mainHandler.getLooper()); sampleSource, new Id3Parser(), player, mainHandler.getLooper());
Eia608TrackRenderer closedCaptionRenderer = new Eia608TrackRenderer(sampleSource, player,
mainHandler.getLooper()); // Build the text renderer, preferring Webvtt where available.
boolean preferWebvtt = false;
if (manifest instanceof HlsMasterPlaylist) {
preferWebvtt = !((HlsMasterPlaylist) manifest).subtitles.isEmpty();
}
TrackRenderer textRenderer;
if (preferWebvtt) {
DataSource textDataSource = new DefaultUriDataSource(context, bandwidthMeter, userAgent);
HlsChunkSource textChunkSource = new HlsChunkSource(false /* isMaster */, textDataSource,
url, manifest, DefaultHlsTrackSelector.newVttInstance(), bandwidthMeter,
timestampAdjusterProvider, HlsChunkSource.ADAPTIVE_MODE_SPLICE);
HlsSampleSource textSampleSource = new HlsSampleSource(textChunkSource, loadControl,
TEXT_BUFFER_SEGMENTS * BUFFER_SEGMENT_SIZE, mainHandler, player, DemoPlayer.TYPE_TEXT);
textRenderer = new TextTrackRenderer(textSampleSource, player, mainHandler.getLooper());
} else {
textRenderer = new Eia608TrackRenderer(sampleSource, player, mainHandler.getLooper());
}
TrackRenderer[] renderers = new TrackRenderer[DemoPlayer.RENDERER_COUNT]; TrackRenderer[] renderers = new TrackRenderer[DemoPlayer.RENDERER_COUNT];
renderers[DemoPlayer.TYPE_VIDEO] = videoRenderer; renderers[DemoPlayer.TYPE_VIDEO] = videoRenderer;
renderers[DemoPlayer.TYPE_AUDIO] = audioRenderer; renderers[DemoPlayer.TYPE_AUDIO] = audioRenderer;
renderers[DemoPlayer.TYPE_METADATA] = id3Renderer; renderers[DemoPlayer.TYPE_METADATA] = id3Renderer;
renderers[DemoPlayer.TYPE_TEXT] = closedCaptionRenderer; renderers[DemoPlayer.TYPE_TEXT] = textRenderer;
player.onRenderers(renderers, bandwidthMeter); player.onRenderers(renderers, bandwidthMeter);
} }
......
...@@ -234,6 +234,13 @@ public final class MediaFormat { ...@@ -234,6 +234,13 @@ public final class MediaFormat {
subsampleOffsetUs, initializationData, adaptive, maxWidth, maxHeight); subsampleOffsetUs, initializationData, adaptive, maxWidth, maxHeight);
} }
public MediaFormat copyWithFixedTrackInfo(String trackId, int bitrate, int width, int height,
String language) {
return new MediaFormat(trackId, mimeType, bitrate, maxInputSize, durationUs, width, height,
rotationDegrees, pixelWidthHeightRatio, channelCount, sampleRate, language,
subsampleOffsetUs, initializationData, adaptive, NO_VALUE, NO_VALUE);
}
public MediaFormat copyAsAdaptive(String trackId) { public MediaFormat copyAsAdaptive(String trackId) {
return new MediaFormat(trackId, mimeType, NO_VALUE, NO_VALUE, durationUs, NO_VALUE, NO_VALUE, return new MediaFormat(trackId, mimeType, NO_VALUE, NO_VALUE, durationUs, NO_VALUE, NO_VALUE,
NO_VALUE, NO_VALUE, NO_VALUE, NO_VALUE, null, OFFSET_SAMPLE_RELATIVE, null, true, maxWidth, NO_VALUE, NO_VALUE, NO_VALUE, NO_VALUE, null, OFFSET_SAMPLE_RELATIVE, null, true, maxWidth,
......
...@@ -133,7 +133,7 @@ public class HlsChunkSource implements HlsTrackSelector.Output { ...@@ -133,7 +133,7 @@ public class HlsChunkSource implements HlsTrackSelector.Output {
// TODO: Expose tracks. // TODO: Expose tracks.
private final ArrayList<ExposedTrack> tracks; private final ArrayList<ExposedTrack> tracks;
private ExposedTrack enabledTrack; private int selectedTrackIndex;
// A list of variants considered during playback, ordered by decreasing bandwidth. The following // A list of variants considered during playback, ordered by decreasing bandwidth. The following
// three arrays are of the same length and are ordered in the same way (i.e. variantPlaylists[i], // three arrays are of the same length and are ordered in the same way (i.e. variantPlaylists[i],
...@@ -295,6 +295,18 @@ public class HlsChunkSource implements HlsTrackSelector.Output { ...@@ -295,6 +295,18 @@ public class HlsChunkSource implements HlsTrackSelector.Output {
return variants.length == 1 ? variants[0] : null; return variants.length == 1 ? variants[0] : null;
} }
/**
* Returns the currently selected track index.
* <p>
* This method should only be called after the source has been prepared.
*
* @return The currently selected track index.
*/
public int getSelectedTrackIndex() {
return selectedTrackIndex;
}
/** /**
* Selects a track for use. * Selects a track for use.
* <p> * <p>
...@@ -303,9 +315,10 @@ public class HlsChunkSource implements HlsTrackSelector.Output { ...@@ -303,9 +315,10 @@ public class HlsChunkSource implements HlsTrackSelector.Output {
* @param index The track index. * @param index The track index.
*/ */
public void selectTrack(int index) { public void selectTrack(int index) {
enabledTrack = tracks.get(index); selectedTrackIndex = index;
selectedVariantIndex = enabledTrack.defaultVariantIndex; ExposedTrack selectedTrack = tracks.get(selectedTrackIndex);
variants = enabledTrack.variants; selectedVariantIndex = selectedTrack.defaultVariantIndex;
variants = selectedTrack.variants;
variantPlaylists = new HlsMediaPlaylist[variants.length]; variantPlaylists = new HlsMediaPlaylist[variants.length];
variantLastPlaylistLoadTimesMs = new long[variants.length]; variantLastPlaylistLoadTimesMs = new long[variants.length];
variantBlacklistTimes = new long[variants.length]; variantBlacklistTimes = new long[variants.length];
...@@ -472,9 +485,10 @@ public class HlsChunkSource implements HlsTrackSelector.Output { ...@@ -472,9 +485,10 @@ public class HlsChunkSource implements HlsTrackSelector.Output {
// The master source has yet to instantiate an adjuster for the discontinuity sequence. // The master source has yet to instantiate an adjuster for the discontinuity sequence.
return; return;
} }
ExposedTrack selectedTrack = tracks.get(selectedTrackIndex);
Extractor extractor = new TsExtractor(timestampAdjuster); Extractor extractor = new TsExtractor(timestampAdjuster);
extractorWrapper = new HlsExtractorWrapper(trigger, format, startTimeUs, extractor, extractorWrapper = new HlsExtractorWrapper(trigger, format, startTimeUs, extractor,
switchingVariantSpliced, enabledTrack.adaptiveMaxWidth, enabledTrack.adaptiveMaxHeight); switchingVariantSpliced, selectedTrack.adaptiveMaxWidth, selectedTrack.adaptiveMaxHeight);
} else { } else {
// MPEG-2 TS segments, and we need to continue using the same extractor. // MPEG-2 TS segments, and we need to continue using the same extractor.
extractorWrapper = previousTsChunk.extractorWrapper; extractorWrapper = previousTsChunk.extractorWrapper;
......
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