mirror of
https://github.com/samsonjs/media.git
synced 2026-04-27 15:07:40 +00:00
Refactor #6.HLS.0
Mechanical step to create a new HlsSource in the library. Note that naming is now confusing. This will be fixed in the next CL, when: HlsSource -> HlsSampleSource HlsSampleSource+HlsOutput -> HlsOutput ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=122054800
This commit is contained in:
parent
9ee3030b79
commit
5ca9f62753
5 changed files with 290 additions and 129 deletions
|
|
@ -24,18 +24,24 @@ import com.google.android.exoplayer.MediaCodecTrackRenderer.DecoderInitializatio
|
||||||
import com.google.android.exoplayer.MediaCodecUtil.DecoderQueryException;
|
import com.google.android.exoplayer.MediaCodecUtil.DecoderQueryException;
|
||||||
import com.google.android.exoplayer.SampleSource;
|
import com.google.android.exoplayer.SampleSource;
|
||||||
import com.google.android.exoplayer.TrackGroupArray;
|
import com.google.android.exoplayer.TrackGroupArray;
|
||||||
|
import com.google.android.exoplayer.dash.DashSampleSource;
|
||||||
import com.google.android.exoplayer.demo.player.DemoPlayer;
|
import com.google.android.exoplayer.demo.player.DemoPlayer;
|
||||||
import com.google.android.exoplayer.demo.player.SourceBuilder;
|
|
||||||
import com.google.android.exoplayer.demo.ui.TrackSelectionHelper;
|
import com.google.android.exoplayer.demo.ui.TrackSelectionHelper;
|
||||||
import com.google.android.exoplayer.drm.UnsupportedDrmException;
|
import com.google.android.exoplayer.drm.UnsupportedDrmException;
|
||||||
|
import com.google.android.exoplayer.extractor.ExtractorSampleSource;
|
||||||
|
import com.google.android.exoplayer.hls.HlsSource;
|
||||||
import com.google.android.exoplayer.metadata.id3.GeobFrame;
|
import com.google.android.exoplayer.metadata.id3.GeobFrame;
|
||||||
import com.google.android.exoplayer.metadata.id3.Id3Frame;
|
import com.google.android.exoplayer.metadata.id3.Id3Frame;
|
||||||
import com.google.android.exoplayer.metadata.id3.PrivFrame;
|
import com.google.android.exoplayer.metadata.id3.PrivFrame;
|
||||||
import com.google.android.exoplayer.metadata.id3.TxxxFrame;
|
import com.google.android.exoplayer.metadata.id3.TxxxFrame;
|
||||||
|
import com.google.android.exoplayer.smoothstreaming.SmoothStreamingSampleSource;
|
||||||
import com.google.android.exoplayer.text.CaptionStyleCompat;
|
import com.google.android.exoplayer.text.CaptionStyleCompat;
|
||||||
import com.google.android.exoplayer.text.Cue;
|
import com.google.android.exoplayer.text.Cue;
|
||||||
import com.google.android.exoplayer.text.SubtitleLayout;
|
import com.google.android.exoplayer.text.SubtitleLayout;
|
||||||
|
import com.google.android.exoplayer.upstream.Allocator;
|
||||||
|
import com.google.android.exoplayer.upstream.DataSource;
|
||||||
import com.google.android.exoplayer.upstream.DataSourceFactory;
|
import com.google.android.exoplayer.upstream.DataSourceFactory;
|
||||||
|
import com.google.android.exoplayer.upstream.DefaultAllocator;
|
||||||
import com.google.android.exoplayer.upstream.DefaultDataSourceFactory;
|
import com.google.android.exoplayer.upstream.DefaultDataSourceFactory;
|
||||||
import com.google.android.exoplayer.util.DebugTextViewHelper;
|
import com.google.android.exoplayer.util.DebugTextViewHelper;
|
||||||
import com.google.android.exoplayer.util.Util;
|
import com.google.android.exoplayer.util.Util;
|
||||||
|
|
@ -260,18 +266,25 @@ public class PlayerActivity extends Activity implements SurfaceHolder.Callback,
|
||||||
|
|
||||||
// Internal methods
|
// Internal methods
|
||||||
|
|
||||||
|
@SuppressWarnings("unused")
|
||||||
private SampleSource buildSource(Uri uri, String id, String provider, int type) {
|
private SampleSource buildSource(Uri uri, String id, String provider, int type) {
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case Util.TYPE_SS:
|
case Util.TYPE_SS:
|
||||||
return SourceBuilder.buildSmoothStreamingSource(player, dataSourceFactory, uri,
|
// TODO: Bring back DRM support. new SmoothStreamingTestMediaDrmCallback()
|
||||||
new SmoothStreamingTestMediaDrmCallback());
|
return new SmoothStreamingSampleSource(uri, dataSourceFactory, player.getBandwidthMeter(),
|
||||||
|
player.getMainHandler(), player);
|
||||||
case Util.TYPE_DASH:
|
case Util.TYPE_DASH:
|
||||||
return SourceBuilder.buildDashSource(player, dataSourceFactory, uri,
|
// TODO: Bring back DRM support. new WidevineTestMediaDrmCallback(id, provider)
|
||||||
new WidevineTestMediaDrmCallback(id, provider));
|
return new DashSampleSource(uri, dataSourceFactory, player.getBandwidthMeter(),
|
||||||
|
player.getMainHandler(), player);
|
||||||
case Util.TYPE_HLS:
|
case Util.TYPE_HLS:
|
||||||
return SourceBuilder.buildHlsSource(player, dataSourceFactory, uri);
|
return new HlsSource(uri, dataSourceFactory, player.getBandwidthMeter(),
|
||||||
|
player.getMainHandler(), player);
|
||||||
case Util.TYPE_OTHER:
|
case Util.TYPE_OTHER:
|
||||||
return SourceBuilder.buildExtractorSource(player, dataSourceFactory, uri);
|
Allocator allocator = new DefaultAllocator(C.DEFAULT_BUFFER_SEGMENT_SIZE);
|
||||||
|
DataSource dataSource = dataSourceFactory.createDataSource(player.getBandwidthMeter());
|
||||||
|
return new ExtractorSampleSource(uri, dataSource, allocator,
|
||||||
|
C.DEFAULT_MUXED_BUFFER_SIZE, player.getMainHandler(), player, 0);
|
||||||
default:
|
default:
|
||||||
throw new IllegalStateException("Unsupported type: " + type);
|
throw new IllegalStateException("Unsupported type: " + type);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -279,7 +279,7 @@ public class DemoPlayer implements ExoPlayer.Listener, DefaultTrackSelector.Even
|
||||||
return player.getPlayWhenReady();
|
return player.getPlayWhenReady();
|
||||||
}
|
}
|
||||||
|
|
||||||
/* package */ Handler getMainHandler() {
|
public Handler getMainHandler() {
|
||||||
return mainHandler;
|
return mainHandler;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,109 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (C) 2014 The Android Open Source Project
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
package com.google.android.exoplayer.demo.player;
|
|
||||||
|
|
||||||
import com.google.android.exoplayer.C;
|
|
||||||
import com.google.android.exoplayer.DefaultLoadControl;
|
|
||||||
import com.google.android.exoplayer.LoadControl;
|
|
||||||
import com.google.android.exoplayer.MultiSampleSource;
|
|
||||||
import com.google.android.exoplayer.SampleSource;
|
|
||||||
import com.google.android.exoplayer.chunk.FormatEvaluator;
|
|
||||||
import com.google.android.exoplayer.dash.DashSampleSource;
|
|
||||||
import com.google.android.exoplayer.drm.MediaDrmCallback;
|
|
||||||
import com.google.android.exoplayer.extractor.ExtractorSampleSource;
|
|
||||||
import com.google.android.exoplayer.hls.HlsChunkSource;
|
|
||||||
import com.google.android.exoplayer.hls.HlsSampleSource;
|
|
||||||
import com.google.android.exoplayer.hls.PtsTimestampAdjusterProvider;
|
|
||||||
import com.google.android.exoplayer.hls.playlist.HlsPlaylist;
|
|
||||||
import com.google.android.exoplayer.hls.playlist.HlsPlaylistParser;
|
|
||||||
import com.google.android.exoplayer.smoothstreaming.SmoothStreamingSampleSource;
|
|
||||||
import com.google.android.exoplayer.upstream.Allocator;
|
|
||||||
import com.google.android.exoplayer.upstream.BandwidthMeter;
|
|
||||||
import com.google.android.exoplayer.upstream.DataSource;
|
|
||||||
import com.google.android.exoplayer.upstream.DataSourceFactory;
|
|
||||||
import com.google.android.exoplayer.upstream.DefaultAllocator;
|
|
||||||
import com.google.android.exoplayer.util.ManifestFetcher;
|
|
||||||
|
|
||||||
import android.net.Uri;
|
|
||||||
import android.os.Handler;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A utility class for building {@link SampleSource} instances.
|
|
||||||
*/
|
|
||||||
public class SourceBuilder {
|
|
||||||
|
|
||||||
private SourceBuilder() {}
|
|
||||||
|
|
||||||
// TODO[REFACTOR]: Bring back DASH DRM support.
|
|
||||||
// TODO[REFACTOR]: Bring back DASH UTC timing element support.
|
|
||||||
public static SampleSource buildDashSource(DemoPlayer player, DataSourceFactory dataSourceFactory,
|
|
||||||
Uri uri, MediaDrmCallback drmCallback) {
|
|
||||||
return new DashSampleSource(uri, dataSourceFactory, player.getBandwidthMeter(),
|
|
||||||
player.getMainHandler(), player);
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO[REFACTOR]: Bring back DRM support.
|
|
||||||
public static SampleSource buildSmoothStreamingSource(DemoPlayer player,
|
|
||||||
DataSourceFactory dataSourceFactory, Uri uri, MediaDrmCallback drmCallback) {
|
|
||||||
return new SmoothStreamingSampleSource(uri, dataSourceFactory, player.getBandwidthMeter(),
|
|
||||||
player.getMainHandler(), player);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static SampleSource buildHlsSource(DemoPlayer player, DataSourceFactory dataSourceFactory,
|
|
||||||
Uri uri) {
|
|
||||||
HlsPlaylistParser parser = new HlsPlaylistParser();
|
|
||||||
DataSource manifestDataSource = dataSourceFactory.createDataSource();
|
|
||||||
// TODO[REFACTOR]: This needs releasing.
|
|
||||||
ManifestFetcher<HlsPlaylist> manifestFetcher = new ManifestFetcher<>(uri, manifestDataSource,
|
|
||||||
parser);
|
|
||||||
|
|
||||||
Handler mainHandler = player.getMainHandler();
|
|
||||||
BandwidthMeter bandwidthMeter = player.getBandwidthMeter();
|
|
||||||
LoadControl loadControl = new DefaultLoadControl(
|
|
||||||
new DefaultAllocator(C.DEFAULT_BUFFER_SEGMENT_SIZE));
|
|
||||||
PtsTimestampAdjusterProvider timestampAdjusterProvider = new PtsTimestampAdjusterProvider();
|
|
||||||
|
|
||||||
DataSource defaultDataSource = dataSourceFactory.createDataSource(bandwidthMeter);
|
|
||||||
HlsChunkSource defaultChunkSource = new HlsChunkSource(manifestFetcher, C.TRACK_TYPE_DEFAULT,
|
|
||||||
defaultDataSource, timestampAdjusterProvider,
|
|
||||||
new FormatEvaluator.AdaptiveEvaluator(bandwidthMeter));
|
|
||||||
HlsSampleSource defaultSampleSource = new HlsSampleSource(defaultChunkSource, loadControl,
|
|
||||||
C.DEFAULT_MUXED_BUFFER_SIZE, mainHandler, player, C.TRACK_TYPE_VIDEO);
|
|
||||||
|
|
||||||
DataSource audioDataSource = dataSourceFactory.createDataSource(bandwidthMeter);
|
|
||||||
HlsChunkSource audioChunkSource = new HlsChunkSource(manifestFetcher, C.TRACK_TYPE_AUDIO,
|
|
||||||
audioDataSource, timestampAdjusterProvider, null);
|
|
||||||
HlsSampleSource audioSampleSource = new HlsSampleSource(audioChunkSource, loadControl,
|
|
||||||
C.DEFAULT_AUDIO_BUFFER_SIZE, mainHandler, player, C.TRACK_TYPE_AUDIO);
|
|
||||||
|
|
||||||
DataSource subtitleDataSource = dataSourceFactory.createDataSource(bandwidthMeter);
|
|
||||||
HlsChunkSource subtitleChunkSource = new HlsChunkSource(manifestFetcher, C.TRACK_TYPE_TEXT,
|
|
||||||
subtitleDataSource, timestampAdjusterProvider, null);
|
|
||||||
HlsSampleSource subtitleSampleSource = new HlsSampleSource(subtitleChunkSource, loadControl,
|
|
||||||
C.DEFAULT_TEXT_BUFFER_SIZE, mainHandler, player, C.TRACK_TYPE_TEXT);
|
|
||||||
|
|
||||||
return new MultiSampleSource(defaultSampleSource, audioSampleSource, subtitleSampleSource);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static SampleSource buildExtractorSource(DemoPlayer player,
|
|
||||||
DataSourceFactory dataSourceFactory, Uri uri) {
|
|
||||||
Allocator allocator = new DefaultAllocator(C.DEFAULT_BUFFER_SEGMENT_SIZE);
|
|
||||||
DataSource dataSource = dataSourceFactory.createDataSource(player.getBandwidthMeter());
|
|
||||||
return new ExtractorSampleSource(uri, dataSource, allocator,
|
|
||||||
C.DEFAULT_MUXED_BUFFER_SIZE, player.getMainHandler(), player, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -45,7 +45,7 @@ import java.util.List;
|
||||||
/**
|
/**
|
||||||
* A {@link SampleSource} for HLS streams.
|
* A {@link SampleSource} for HLS streams.
|
||||||
*/
|
*/
|
||||||
public final class HlsSampleSource implements SampleSource, Loader.Callback {
|
public final class HlsSampleSource implements Loader.Callback {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The default minimum number of times to retry loading data prior to failing.
|
* The default minimum number of times to retry loading data prior to failing.
|
||||||
|
|
@ -139,9 +139,6 @@ public final class HlsSampleSource implements SampleSource, Loader.Callback {
|
||||||
pendingResetPositionUs = C.UNSET_TIME_US;
|
pendingResetPositionUs = C.UNSET_TIME_US;
|
||||||
}
|
}
|
||||||
|
|
||||||
// SampleSource implementation.
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean prepare(long positionUs) throws IOException {
|
public boolean prepare(long positionUs) throws IOException {
|
||||||
if (prepared) {
|
if (prepared) {
|
||||||
return true;
|
return true;
|
||||||
|
|
@ -173,17 +170,14 @@ public final class HlsSampleSource implements SampleSource, Loader.Callback {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public long getDurationUs() {
|
public long getDurationUs() {
|
||||||
return chunkSource.getDurationUs();
|
return chunkSource.getDurationUs();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public TrackGroupArray getTrackGroups() {
|
public TrackGroupArray getTrackGroups() {
|
||||||
return trackGroups;
|
return trackGroups;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public TrackStream[] selectTracks(List<TrackStream> oldStreams,
|
public TrackStream[] selectTracks(List<TrackStream> oldStreams,
|
||||||
List<TrackSelection> newSelections, long positionUs) {
|
List<TrackSelection> newSelections, long positionUs) {
|
||||||
Assertions.checkState(prepared);
|
Assertions.checkState(prepared);
|
||||||
|
|
@ -233,7 +227,6 @@ public final class HlsSampleSource implements SampleSource, Loader.Callback {
|
||||||
return newStreams;
|
return newStreams;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void continueBuffering(long playbackPositionUs) {
|
public void continueBuffering(long playbackPositionUs) {
|
||||||
downstreamPositionUs = playbackPositionUs;
|
downstreamPositionUs = playbackPositionUs;
|
||||||
discardSamplesForDisabledTracks();
|
discardSamplesForDisabledTracks();
|
||||||
|
|
@ -242,7 +235,6 @@ public final class HlsSampleSource implements SampleSource, Loader.Callback {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public long readReset() {
|
public long readReset() {
|
||||||
if (notifyReset) {
|
if (notifyReset) {
|
||||||
notifyReset = false;
|
notifyReset = false;
|
||||||
|
|
@ -251,7 +243,6 @@ public final class HlsSampleSource implements SampleSource, Loader.Callback {
|
||||||
return C.UNSET_TIME_US;
|
return C.UNSET_TIME_US;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public long getBufferedPositionUs() {
|
public long getBufferedPositionUs() {
|
||||||
if (loadingFinished) {
|
if (loadingFinished) {
|
||||||
return C.END_OF_SOURCE_US;
|
return C.END_OF_SOURCE_US;
|
||||||
|
|
@ -273,12 +264,10 @@ public final class HlsSampleSource implements SampleSource, Loader.Callback {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void seekToUs(long positionUs) {
|
public void seekToUs(long positionUs) {
|
||||||
seekToInternal(positionUs);
|
seekToInternal(positionUs);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void release() {
|
public void release() {
|
||||||
if (enabledTrackCount > 0) {
|
if (enabledTrackCount > 0) {
|
||||||
loadControl.unregister(this);
|
loadControl.unregister(this);
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,268 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2014 The Android Open Source Project
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package com.google.android.exoplayer.hls;
|
||||||
|
|
||||||
|
import com.google.android.exoplayer.C;
|
||||||
|
import com.google.android.exoplayer.DefaultLoadControl;
|
||||||
|
import com.google.android.exoplayer.LoadControl;
|
||||||
|
import com.google.android.exoplayer.SampleSource;
|
||||||
|
import com.google.android.exoplayer.TrackGroup;
|
||||||
|
import com.google.android.exoplayer.TrackGroupArray;
|
||||||
|
import com.google.android.exoplayer.TrackSelection;
|
||||||
|
import com.google.android.exoplayer.TrackStream;
|
||||||
|
import com.google.android.exoplayer.chunk.ChunkTrackStreamEventListener;
|
||||||
|
import com.google.android.exoplayer.chunk.FormatEvaluator;
|
||||||
|
import com.google.android.exoplayer.hls.playlist.HlsPlaylist;
|
||||||
|
import com.google.android.exoplayer.hls.playlist.HlsPlaylistParser;
|
||||||
|
import com.google.android.exoplayer.upstream.BandwidthMeter;
|
||||||
|
import com.google.android.exoplayer.upstream.DataSource;
|
||||||
|
import com.google.android.exoplayer.upstream.DataSourceFactory;
|
||||||
|
import com.google.android.exoplayer.upstream.DefaultAllocator;
|
||||||
|
import com.google.android.exoplayer.util.Assertions;
|
||||||
|
import com.google.android.exoplayer.util.ManifestFetcher;
|
||||||
|
|
||||||
|
import android.net.Uri;
|
||||||
|
import android.os.Handler;
|
||||||
|
import android.util.Pair;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.IdentityHashMap;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A {@link SampleSource} for HLS streams.
|
||||||
|
*/
|
||||||
|
public final class HlsSource implements SampleSource {
|
||||||
|
|
||||||
|
private final ManifestFetcher<HlsPlaylist> manifestFetcher;
|
||||||
|
private final HlsSampleSource[] sources;
|
||||||
|
private final IdentityHashMap<TrackStream, HlsSampleSource> trackStreamSources;
|
||||||
|
private final int[] selectedTrackCounts;
|
||||||
|
|
||||||
|
private boolean prepared;
|
||||||
|
private boolean seenFirstTrackSelection;
|
||||||
|
private long durationUs;
|
||||||
|
private TrackGroupArray trackGroups;
|
||||||
|
private HlsSampleSource[] enabledSources;
|
||||||
|
|
||||||
|
public HlsSource(Uri uri, DataSourceFactory dataSourceFactory, BandwidthMeter bandwidthMeter,
|
||||||
|
Handler eventHandler, ChunkTrackStreamEventListener eventListener) {
|
||||||
|
HlsPlaylistParser parser = new HlsPlaylistParser();
|
||||||
|
DataSource manifestDataSource = dataSourceFactory.createDataSource();
|
||||||
|
manifestFetcher = new ManifestFetcher<>(uri, manifestDataSource, parser);
|
||||||
|
|
||||||
|
LoadControl loadControl = new DefaultLoadControl(
|
||||||
|
new DefaultAllocator(C.DEFAULT_BUFFER_SEGMENT_SIZE));
|
||||||
|
PtsTimestampAdjusterProvider timestampAdjusterProvider = new PtsTimestampAdjusterProvider();
|
||||||
|
|
||||||
|
DataSource defaultDataSource = dataSourceFactory.createDataSource(bandwidthMeter);
|
||||||
|
HlsChunkSource defaultChunkSource = new HlsChunkSource(manifestFetcher, C.TRACK_TYPE_DEFAULT,
|
||||||
|
defaultDataSource, timestampAdjusterProvider,
|
||||||
|
new FormatEvaluator.AdaptiveEvaluator(bandwidthMeter));
|
||||||
|
HlsSampleSource defaultSampleSource = new HlsSampleSource(defaultChunkSource, loadControl,
|
||||||
|
C.DEFAULT_MUXED_BUFFER_SIZE, eventHandler, eventListener, C.TRACK_TYPE_VIDEO);
|
||||||
|
|
||||||
|
DataSource audioDataSource = dataSourceFactory.createDataSource(bandwidthMeter);
|
||||||
|
HlsChunkSource audioChunkSource = new HlsChunkSource(manifestFetcher, C.TRACK_TYPE_AUDIO,
|
||||||
|
audioDataSource, timestampAdjusterProvider, null);
|
||||||
|
HlsSampleSource audioSampleSource = new HlsSampleSource(audioChunkSource, loadControl,
|
||||||
|
C.DEFAULT_AUDIO_BUFFER_SIZE, eventHandler, eventListener, C.TRACK_TYPE_AUDIO);
|
||||||
|
|
||||||
|
DataSource subtitleDataSource = dataSourceFactory.createDataSource(bandwidthMeter);
|
||||||
|
HlsChunkSource subtitleChunkSource = new HlsChunkSource(manifestFetcher, C.TRACK_TYPE_TEXT,
|
||||||
|
subtitleDataSource, timestampAdjusterProvider, null);
|
||||||
|
HlsSampleSource subtitleSampleSource = new HlsSampleSource(subtitleChunkSource, loadControl,
|
||||||
|
C.DEFAULT_TEXT_BUFFER_SIZE, eventHandler, eventListener, C.TRACK_TYPE_TEXT);
|
||||||
|
|
||||||
|
sources = new HlsSampleSource[] {defaultSampleSource, audioSampleSource, subtitleSampleSource};
|
||||||
|
selectedTrackCounts = new int[sources.length];
|
||||||
|
trackStreamSources = new IdentityHashMap<>();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean prepare(long positionUs) throws IOException {
|
||||||
|
if (prepared) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
boolean sourcesPrepared = true;
|
||||||
|
for (HlsSampleSource source : sources) {
|
||||||
|
sourcesPrepared &= source.prepare(positionUs);
|
||||||
|
}
|
||||||
|
if (!sourcesPrepared) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
durationUs = 0;
|
||||||
|
int totalTrackGroupCount = 0;
|
||||||
|
for (HlsSampleSource source : sources) {
|
||||||
|
totalTrackGroupCount += source.getTrackGroups().length;
|
||||||
|
if (durationUs != C.UNSET_TIME_US) {
|
||||||
|
long sourceDurationUs = source.getDurationUs();
|
||||||
|
durationUs = sourceDurationUs == C.UNSET_TIME_US
|
||||||
|
? C.UNSET_TIME_US : Math.max(durationUs, sourceDurationUs);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
TrackGroup[] trackGroupArray = new TrackGroup[totalTrackGroupCount];
|
||||||
|
int trackGroupIndex = 0;
|
||||||
|
for (HlsSampleSource source : sources) {
|
||||||
|
int sourceTrackGroupCount = source.getTrackGroups().length;
|
||||||
|
for (int j = 0; j < sourceTrackGroupCount; j++) {
|
||||||
|
trackGroupArray[trackGroupIndex++] = source.getTrackGroups().get(j);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
trackGroups = new TrackGroupArray(trackGroupArray);
|
||||||
|
prepared = true;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long getDurationUs() {
|
||||||
|
return durationUs;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public TrackGroupArray getTrackGroups() {
|
||||||
|
return trackGroups;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public TrackStream[] selectTracks(List<TrackStream> oldStreams,
|
||||||
|
List<TrackSelection> newSelections, long positionUs) {
|
||||||
|
Assertions.checkState(prepared);
|
||||||
|
TrackStream[] newStreams = new TrackStream[newSelections.size()];
|
||||||
|
// Select tracks for each source.
|
||||||
|
int enabledSourceCount = 0;
|
||||||
|
for (int i = 0; i < sources.length; i++) {
|
||||||
|
selectedTrackCounts[i] += selectTracks(sources[i], oldStreams, newSelections, positionUs,
|
||||||
|
newStreams);
|
||||||
|
if (selectedTrackCounts[i] > 0) {
|
||||||
|
enabledSourceCount++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Update the enabled sources.
|
||||||
|
enabledSources = new HlsSampleSource[enabledSourceCount];
|
||||||
|
enabledSourceCount = 0;
|
||||||
|
for (int i = 0; i < sources.length; i++) {
|
||||||
|
if (selectedTrackCounts[i] > 0) {
|
||||||
|
enabledSources[enabledSourceCount++] = sources[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
seenFirstTrackSelection = true;
|
||||||
|
return newStreams;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void continueBuffering(long positionUs) {
|
||||||
|
for (HlsSampleSource source : enabledSources) {
|
||||||
|
source.continueBuffering(positionUs);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long readReset() {
|
||||||
|
long resetPositionUs = C.UNSET_TIME_US;
|
||||||
|
for (HlsSampleSource source : enabledSources) {
|
||||||
|
long childResetPositionUs = source.readReset();
|
||||||
|
if (resetPositionUs == C.UNSET_TIME_US) {
|
||||||
|
resetPositionUs = childResetPositionUs;
|
||||||
|
} else if (childResetPositionUs != C.UNSET_TIME_US) {
|
||||||
|
resetPositionUs = Math.min(resetPositionUs, childResetPositionUs);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return resetPositionUs;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long getBufferedPositionUs() {
|
||||||
|
long bufferedPositionUs = durationUs != C.UNSET_TIME_US ? durationUs : Long.MAX_VALUE;
|
||||||
|
for (HlsSampleSource source : enabledSources) {
|
||||||
|
long rendererBufferedPositionUs = source.getBufferedPositionUs();
|
||||||
|
if (rendererBufferedPositionUs == C.UNSET_TIME_US) {
|
||||||
|
return C.UNSET_TIME_US;
|
||||||
|
} else if (rendererBufferedPositionUs == C.END_OF_SOURCE_US) {
|
||||||
|
// This source is fully buffered.
|
||||||
|
} else {
|
||||||
|
bufferedPositionUs = Math.min(bufferedPositionUs, rendererBufferedPositionUs);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return bufferedPositionUs == Long.MAX_VALUE ? C.UNSET_TIME_US : bufferedPositionUs;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void seekToUs(long positionUs) {
|
||||||
|
for (HlsSampleSource source : enabledSources) {
|
||||||
|
source.seekToUs(positionUs);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void release() {
|
||||||
|
manifestFetcher.release();
|
||||||
|
for (HlsSampleSource source : sources) {
|
||||||
|
source.release();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Internal methods.
|
||||||
|
|
||||||
|
private int selectTracks(HlsSampleSource source, List<TrackStream> allOldStreams,
|
||||||
|
List<TrackSelection> allNewSelections, long positionUs, TrackStream[] allNewStreams) {
|
||||||
|
// Get the subset of the old streams for the source.
|
||||||
|
ArrayList<TrackStream> oldStreams = new ArrayList<>();
|
||||||
|
for (int i = 0; i < allOldStreams.size(); i++) {
|
||||||
|
TrackStream stream = allOldStreams.get(i);
|
||||||
|
if (trackStreamSources.get(stream) == source) {
|
||||||
|
trackStreamSources.remove(stream);
|
||||||
|
oldStreams.add(stream);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Get the subset of the new selections for the source.
|
||||||
|
ArrayList<TrackSelection> newSelections = new ArrayList<>();
|
||||||
|
int[] newSelectionOriginalIndices = new int[allNewSelections.size()];
|
||||||
|
for (int i = 0; i < allNewSelections.size(); i++) {
|
||||||
|
TrackSelection selection = allNewSelections.get(i);
|
||||||
|
Pair<HlsSampleSource, Integer> sourceAndGroup = getSourceAndGroup(selection.group);
|
||||||
|
if (sourceAndGroup.first == source) {
|
||||||
|
newSelectionOriginalIndices[newSelections.size()] = i;
|
||||||
|
newSelections.add(new TrackSelection(sourceAndGroup.second, selection.getTracks()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Do nothing if nothing has changed, except during the first selection.
|
||||||
|
if (seenFirstTrackSelection && oldStreams.isEmpty() && newSelections.isEmpty()) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
// Perform the selection.
|
||||||
|
TrackStream[] newStreams = source.selectTracks(oldStreams, newSelections, positionUs);
|
||||||
|
for (int j = 0; j < newStreams.length; j++) {
|
||||||
|
allNewStreams[newSelectionOriginalIndices[j]] = newStreams[j];
|
||||||
|
trackStreamSources.put(newStreams[j], source);
|
||||||
|
}
|
||||||
|
return newSelections.size() - oldStreams.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
private Pair<HlsSampleSource, Integer> getSourceAndGroup(int group) {
|
||||||
|
int totalTrackGroupCount = 0;
|
||||||
|
for (HlsSampleSource source : sources) {
|
||||||
|
int sourceTrackGroupCount = source.getTrackGroups().length;
|
||||||
|
if (group < totalTrackGroupCount + sourceTrackGroupCount) {
|
||||||
|
return Pair.create(source, group - totalTrackGroupCount);
|
||||||
|
}
|
||||||
|
totalTrackGroupCount += sourceTrackGroupCount;
|
||||||
|
}
|
||||||
|
throw new IndexOutOfBoundsException();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
Loading…
Reference in a new issue