mirror of
https://github.com/samsonjs/media.git
synced 2026-04-27 15:07:40 +00:00
Refactor #6.2: Start to simplify components.
Parse the duration of the media directly from the manifest in the DASH/SS SampleSource implementations. ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=121001296
This commit is contained in:
parent
b38d004553
commit
eb3460b3aa
6 changed files with 43 additions and 110 deletions
|
|
@ -43,7 +43,7 @@ import java.util.List;
|
||||||
* A {@link SampleSource} that loads media in {@link Chunk}s, which are themselves obtained from a
|
* A {@link SampleSource} that loads media in {@link Chunk}s, which are themselves obtained from a
|
||||||
* {@link ChunkSource}.
|
* {@link ChunkSource}.
|
||||||
*/
|
*/
|
||||||
public class ChunkSampleSource implements SampleSource, TrackStream, Loader.Callback {
|
public class ChunkSampleSource implements TrackStream, 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.
|
||||||
|
|
@ -60,7 +60,6 @@ public class ChunkSampleSource implements SampleSource, TrackStream, Loader.Call
|
||||||
private final EventDispatcher eventDispatcher;
|
private final EventDispatcher eventDispatcher;
|
||||||
private final LoadControl loadControl;
|
private final LoadControl loadControl;
|
||||||
|
|
||||||
private boolean prepared;
|
|
||||||
private boolean notifyReset;
|
private boolean notifyReset;
|
||||||
private long lastPreferredQueueSizeEvaluationTimeMs;
|
private long lastPreferredQueueSizeEvaluationTimeMs;
|
||||||
private Format downstreamFormat;
|
private Format downstreamFormat;
|
||||||
|
|
@ -130,35 +129,21 @@ public class ChunkSampleSource implements SampleSource, TrackStream, Loader.Call
|
||||||
|
|
||||||
// SampleSource implementation.
|
// SampleSource implementation.
|
||||||
|
|
||||||
@Override
|
public void prepare() {
|
||||||
public boolean prepare(long positionUs) throws IOException {
|
|
||||||
if (prepared) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
TrackGroup tracks = chunkSource.getTracks();
|
TrackGroup tracks = chunkSource.getTracks();
|
||||||
if (tracks != null) {
|
if (tracks != null) {
|
||||||
trackGroups = new TrackGroupArray(tracks);
|
trackGroups = new TrackGroupArray(tracks);
|
||||||
} else {
|
} else {
|
||||||
trackGroups = new TrackGroupArray();
|
trackGroups = new TrackGroupArray();
|
||||||
}
|
}
|
||||||
prepared = true;
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public long 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(oldStreams.size() <= 1);
|
Assertions.checkState(oldStreams.size() <= 1);
|
||||||
Assertions.checkState(newSelections.size() <= 1);
|
Assertions.checkState(newSelections.size() <= 1);
|
||||||
boolean trackWasEnabled = trackEnabled;
|
boolean trackWasEnabled = trackEnabled;
|
||||||
|
|
@ -201,7 +186,6 @@ public class ChunkSampleSource implements SampleSource, TrackStream, Loader.Call
|
||||||
return newStreams;
|
return newStreams;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void continueBuffering(long positionUs) {
|
public void continueBuffering(long positionUs) {
|
||||||
downstreamPositionUs = positionUs;
|
downstreamPositionUs = positionUs;
|
||||||
if (!loader.isLoading()) {
|
if (!loader.isLoading()) {
|
||||||
|
|
@ -209,7 +193,6 @@ public class ChunkSampleSource implements SampleSource, TrackStream, Loader.Call
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public long readReset() {
|
public long readReset() {
|
||||||
if (notifyReset) {
|
if (notifyReset) {
|
||||||
notifyReset = false;
|
notifyReset = false;
|
||||||
|
|
@ -218,7 +201,6 @@ public class ChunkSampleSource implements SampleSource, TrackStream, Loader.Call
|
||||||
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;
|
||||||
|
|
@ -236,7 +218,6 @@ public class ChunkSampleSource implements SampleSource, TrackStream, Loader.Call
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void seekToUs(long positionUs) {
|
public void seekToUs(long positionUs) {
|
||||||
downstreamPositionUs = positionUs;
|
downstreamPositionUs = positionUs;
|
||||||
lastSeekPositionUs = positionUs;
|
lastSeekPositionUs = positionUs;
|
||||||
|
|
@ -256,7 +237,6 @@ public class ChunkSampleSource implements SampleSource, TrackStream, Loader.Call
|
||||||
notifyReset = true;
|
notifyReset = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void release() {
|
public void release() {
|
||||||
if (trackEnabled) {
|
if (trackEnabled) {
|
||||||
loadControl.unregister(this);
|
loadControl.unregister(this);
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,6 @@
|
||||||
*/
|
*/
|
||||||
package com.google.android.exoplayer.chunk;
|
package com.google.android.exoplayer.chunk;
|
||||||
|
|
||||||
import com.google.android.exoplayer.C;
|
|
||||||
import com.google.android.exoplayer.TrackGroup;
|
import com.google.android.exoplayer.TrackGroup;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
@ -41,16 +40,6 @@ public interface ChunkSource {
|
||||||
*/
|
*/
|
||||||
void maybeThrowError() throws IOException;
|
void maybeThrowError() throws IOException;
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the duration of the source in microseconds.
|
|
||||||
* <p>
|
|
||||||
* This method should only be called after the source has been prepared.
|
|
||||||
*
|
|
||||||
* @return The duration of the source in microseconds, or {@link C#UNSET_TIME_US} if the duration
|
|
||||||
* is unknown.
|
|
||||||
*/
|
|
||||||
long getDurationUs();
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the group of tracks provided by the source.
|
* Gets the group of tracks provided by the source.
|
||||||
* <p>
|
* <p>
|
||||||
|
|
|
||||||
|
|
@ -71,10 +71,6 @@ public class DashChunkSource implements ChunkSource {
|
||||||
private final FormatEvaluator adaptiveFormatEvaluator;
|
private final FormatEvaluator adaptiveFormatEvaluator;
|
||||||
private final Evaluation evaluation;
|
private final Evaluation evaluation;
|
||||||
|
|
||||||
// Properties of the initial manifest.
|
|
||||||
private boolean live;
|
|
||||||
private long durationUs;
|
|
||||||
|
|
||||||
private MediaPresentationDescription currentManifest;
|
private MediaPresentationDescription currentManifest;
|
||||||
private DrmInitData drmInitData;
|
private DrmInitData drmInitData;
|
||||||
|
|
||||||
|
|
@ -118,11 +114,6 @@ public class DashChunkSource implements ChunkSource {
|
||||||
initForManifest(currentManifest);
|
initForManifest(currentManifest);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public long getDurationUs() {
|
|
||||||
return durationUs;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public final TrackGroup getTracks() {
|
public final TrackGroup getTracks() {
|
||||||
return trackGroup;
|
return trackGroup;
|
||||||
|
|
@ -293,9 +284,6 @@ public class DashChunkSource implements ChunkSource {
|
||||||
|
|
||||||
private void initForManifest(MediaPresentationDescription manifest) {
|
private void initForManifest(MediaPresentationDescription manifest) {
|
||||||
Period period = manifest.getPeriod(0);
|
Period period = manifest.getPeriod(0);
|
||||||
live = currentManifest.dynamic;
|
|
||||||
durationUs = live ? C.UNSET_TIME_US : currentManifest.duration * 1000;
|
|
||||||
|
|
||||||
for (int i = 0; i < period.adaptationSets.size(); i++) {
|
for (int i = 0; i < period.adaptationSets.size(); i++) {
|
||||||
AdaptationSet adaptationSet = period.adaptationSets.get(i);
|
AdaptationSet adaptationSet = period.adaptationSets.get(i);
|
||||||
if (adaptationSet.type == adaptationSetType) {
|
if (adaptationSet.type == adaptationSetType) {
|
||||||
|
|
|
||||||
|
|
@ -52,8 +52,8 @@ public final class DashSampleSource implements SampleSource {
|
||||||
|
|
||||||
private final ManifestFetcher<MediaPresentationDescription> manifestFetcher;
|
private final ManifestFetcher<MediaPresentationDescription> manifestFetcher;
|
||||||
private final DashChunkSource[] chunkSources;
|
private final DashChunkSource[] chunkSources;
|
||||||
private final SampleSource[] sources;
|
private final ChunkSampleSource[] sources;
|
||||||
private final IdentityHashMap<TrackStream, SampleSource> trackStreamSources;
|
private final IdentityHashMap<TrackStream, ChunkSampleSource> trackStreamSources;
|
||||||
private final int[] selectedTrackCounts;
|
private final int[] selectedTrackCounts;
|
||||||
|
|
||||||
private MediaPresentationDescription currentManifest;
|
private MediaPresentationDescription currentManifest;
|
||||||
|
|
@ -61,7 +61,7 @@ public final class DashSampleSource implements SampleSource {
|
||||||
private boolean seenFirstTrackSelection;
|
private boolean seenFirstTrackSelection;
|
||||||
private long durationUs;
|
private long durationUs;
|
||||||
private TrackGroupArray trackGroups;
|
private TrackGroupArray trackGroups;
|
||||||
private SampleSource[] enabledSources;
|
private ChunkSampleSource[] enabledSources;
|
||||||
|
|
||||||
public DashSampleSource(Uri uri, DataSourceFactory dataSourceFactory,
|
public DashSampleSource(Uri uri, DataSourceFactory dataSourceFactory,
|
||||||
BandwidthMeter bandwidthMeter, Handler eventHandler,
|
BandwidthMeter bandwidthMeter, Handler eventHandler,
|
||||||
|
|
@ -94,7 +94,7 @@ public final class DashSampleSource implements SampleSource {
|
||||||
C.DEFAULT_TEXT_BUFFER_SIZE, eventHandler, eventListener, C.TRACK_TYPE_TEXT);
|
C.DEFAULT_TEXT_BUFFER_SIZE, eventHandler, eventListener, C.TRACK_TYPE_TEXT);
|
||||||
|
|
||||||
chunkSources = new DashChunkSource[] {videoChunkSource, audioChunkSource, textChunkSource};
|
chunkSources = new DashChunkSource[] {videoChunkSource, audioChunkSource, textChunkSource};
|
||||||
sources = new SampleSource[] {videoSampleSource, audioSampleSource, textSampleSource};
|
sources = new ChunkSampleSource[] {videoSampleSource, audioSampleSource, textSampleSource};
|
||||||
trackStreamSources = new IdentityHashMap<>();
|
trackStreamSources = new IdentityHashMap<>();
|
||||||
selectedTrackCounts = new int[sources.length];
|
selectedTrackCounts = new int[sources.length];
|
||||||
}
|
}
|
||||||
|
|
@ -112,32 +112,23 @@ public final class DashSampleSource implements SampleSource {
|
||||||
manifestFetcher.requestRefresh();
|
manifestFetcher.requestRefresh();
|
||||||
return false;
|
return false;
|
||||||
} else {
|
} else {
|
||||||
|
durationUs = currentManifest.dynamic ? C.UNSET_TIME_US : currentManifest.duration * 1000;
|
||||||
for (DashChunkSource chunkSource : chunkSources) {
|
for (DashChunkSource chunkSource : chunkSources) {
|
||||||
chunkSource.init(currentManifest);
|
chunkSource.init(currentManifest);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean sourcesPrepared = true;
|
for (ChunkSampleSource source : sources) {
|
||||||
for (SampleSource source : sources) {
|
source.prepare();
|
||||||
sourcesPrepared &= source.prepare(positionUs);
|
|
||||||
}
|
}
|
||||||
if (!sourcesPrepared) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
durationUs = 0;
|
|
||||||
int totalTrackGroupCount = 0;
|
int totalTrackGroupCount = 0;
|
||||||
for (SampleSource source : sources) {
|
for (ChunkSampleSource source : sources) {
|
||||||
totalTrackGroupCount += source.getTrackGroups().length;
|
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];
|
TrackGroup[] trackGroupArray = new TrackGroup[totalTrackGroupCount];
|
||||||
int trackGroupIndex = 0;
|
int trackGroupIndex = 0;
|
||||||
for (SampleSource source : sources) {
|
for (ChunkSampleSource source : sources) {
|
||||||
int sourceTrackGroupCount = source.getTrackGroups().length;
|
int sourceTrackGroupCount = source.getTrackGroups().length;
|
||||||
for (int j = 0; j < sourceTrackGroupCount; j++) {
|
for (int j = 0; j < sourceTrackGroupCount; j++) {
|
||||||
trackGroupArray[trackGroupIndex++] = source.getTrackGroups().get(j);
|
trackGroupArray[trackGroupIndex++] = source.getTrackGroups().get(j);
|
||||||
|
|
@ -173,7 +164,7 @@ public final class DashSampleSource implements SampleSource {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Update the enabled sources.
|
// Update the enabled sources.
|
||||||
enabledSources = new SampleSource[enabledSourceCount];
|
enabledSources = new ChunkSampleSource[enabledSourceCount];
|
||||||
enabledSourceCount = 0;
|
enabledSourceCount = 0;
|
||||||
for (int i = 0; i < sources.length; i++) {
|
for (int i = 0; i < sources.length; i++) {
|
||||||
if (selectedTrackCounts[i] > 0) {
|
if (selectedTrackCounts[i] > 0) {
|
||||||
|
|
@ -210,7 +201,7 @@ public final class DashSampleSource implements SampleSource {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (SampleSource source : enabledSources) {
|
for (ChunkSampleSource source : enabledSources) {
|
||||||
source.continueBuffering(positionUs);
|
source.continueBuffering(positionUs);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -218,7 +209,7 @@ public final class DashSampleSource implements SampleSource {
|
||||||
@Override
|
@Override
|
||||||
public long readReset() {
|
public long readReset() {
|
||||||
long resetPositionUs = C.UNSET_TIME_US;
|
long resetPositionUs = C.UNSET_TIME_US;
|
||||||
for (SampleSource source : enabledSources) {
|
for (ChunkSampleSource source : enabledSources) {
|
||||||
long childResetPositionUs = source.readReset();
|
long childResetPositionUs = source.readReset();
|
||||||
if (resetPositionUs == C.UNSET_TIME_US) {
|
if (resetPositionUs == C.UNSET_TIME_US) {
|
||||||
resetPositionUs = childResetPositionUs;
|
resetPositionUs = childResetPositionUs;
|
||||||
|
|
@ -232,7 +223,7 @@ public final class DashSampleSource implements SampleSource {
|
||||||
@Override
|
@Override
|
||||||
public long getBufferedPositionUs() {
|
public long getBufferedPositionUs() {
|
||||||
long bufferedPositionUs = durationUs != C.UNSET_TIME_US ? durationUs : Long.MAX_VALUE;
|
long bufferedPositionUs = durationUs != C.UNSET_TIME_US ? durationUs : Long.MAX_VALUE;
|
||||||
for (SampleSource source : enabledSources) {
|
for (ChunkSampleSource source : enabledSources) {
|
||||||
long rendererBufferedPositionUs = source.getBufferedPositionUs();
|
long rendererBufferedPositionUs = source.getBufferedPositionUs();
|
||||||
if (rendererBufferedPositionUs == C.UNSET_TIME_US) {
|
if (rendererBufferedPositionUs == C.UNSET_TIME_US) {
|
||||||
return C.UNSET_TIME_US;
|
return C.UNSET_TIME_US;
|
||||||
|
|
@ -247,7 +238,7 @@ public final class DashSampleSource implements SampleSource {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void seekToUs(long positionUs) {
|
public void seekToUs(long positionUs) {
|
||||||
for (SampleSource source : enabledSources) {
|
for (ChunkSampleSource source : enabledSources) {
|
||||||
source.seekToUs(positionUs);
|
source.seekToUs(positionUs);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -255,14 +246,14 @@ public final class DashSampleSource implements SampleSource {
|
||||||
@Override
|
@Override
|
||||||
public void release() {
|
public void release() {
|
||||||
manifestFetcher.release();
|
manifestFetcher.release();
|
||||||
for (SampleSource source : sources) {
|
for (ChunkSampleSource source : sources) {
|
||||||
source.release();
|
source.release();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Internal methods.
|
// Internal methods.
|
||||||
|
|
||||||
private int selectTracks(SampleSource source, List<TrackStream> allOldStreams,
|
private int selectTracks(ChunkSampleSource source, List<TrackStream> allOldStreams,
|
||||||
List<TrackSelection> allNewSelections, long positionUs, TrackStream[] allNewStreams) {
|
List<TrackSelection> allNewSelections, long positionUs, TrackStream[] allNewStreams) {
|
||||||
// Get the subset of the old streams for the source.
|
// Get the subset of the old streams for the source.
|
||||||
ArrayList<TrackStream> oldStreams = new ArrayList<>();
|
ArrayList<TrackStream> oldStreams = new ArrayList<>();
|
||||||
|
|
@ -278,7 +269,7 @@ public final class DashSampleSource implements SampleSource {
|
||||||
int[] newSelectionOriginalIndices = new int[allNewSelections.size()];
|
int[] newSelectionOriginalIndices = new int[allNewSelections.size()];
|
||||||
for (int i = 0; i < allNewSelections.size(); i++) {
|
for (int i = 0; i < allNewSelections.size(); i++) {
|
||||||
TrackSelection selection = allNewSelections.get(i);
|
TrackSelection selection = allNewSelections.get(i);
|
||||||
Pair<SampleSource, Integer> sourceAndGroup = getSourceAndGroup(selection.group);
|
Pair<ChunkSampleSource, Integer> sourceAndGroup = getSourceAndGroup(selection.group);
|
||||||
if (sourceAndGroup.first == source) {
|
if (sourceAndGroup.first == source) {
|
||||||
newSelectionOriginalIndices[newSelections.size()] = i;
|
newSelectionOriginalIndices[newSelections.size()] = i;
|
||||||
newSelections.add(new TrackSelection(sourceAndGroup.second, selection.getTracks()));
|
newSelections.add(new TrackSelection(sourceAndGroup.second, selection.getTracks()));
|
||||||
|
|
@ -297,9 +288,9 @@ public final class DashSampleSource implements SampleSource {
|
||||||
return newSelections.size() - oldStreams.size();
|
return newSelections.size() - oldStreams.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
private Pair<SampleSource, Integer> getSourceAndGroup(int group) {
|
private Pair<ChunkSampleSource, Integer> getSourceAndGroup(int group) {
|
||||||
int totalTrackGroupCount = 0;
|
int totalTrackGroupCount = 0;
|
||||||
for (SampleSource source : sources) {
|
for (ChunkSampleSource source : sources) {
|
||||||
int sourceTrackGroupCount = source.getTrackGroups().length;
|
int sourceTrackGroupCount = source.getTrackGroups().length;
|
||||||
if (group < totalTrackGroupCount + sourceTrackGroupCount) {
|
if (group < totalTrackGroupCount + sourceTrackGroupCount) {
|
||||||
return Pair.create(source, group - totalTrackGroupCount);
|
return Pair.create(source, group - totalTrackGroupCount);
|
||||||
|
|
|
||||||
|
|
@ -60,7 +60,6 @@ public class SmoothStreamingChunkSource implements ChunkSource {
|
||||||
private final Evaluation evaluation;
|
private final Evaluation evaluation;
|
||||||
private final FormatEvaluator adaptiveFormatEvaluator;
|
private final FormatEvaluator adaptiveFormatEvaluator;
|
||||||
|
|
||||||
private long durationUs;
|
|
||||||
private TrackEncryptionBox[] trackEncryptionBoxes;
|
private TrackEncryptionBox[] trackEncryptionBoxes;
|
||||||
private DrmInitData.Mapped drmInitData;
|
private DrmInitData.Mapped drmInitData;
|
||||||
private SmoothStreamingManifest currentManifest;
|
private SmoothStreamingManifest currentManifest;
|
||||||
|
|
@ -107,7 +106,6 @@ public class SmoothStreamingChunkSource implements ChunkSource {
|
||||||
|
|
||||||
public void init(SmoothStreamingManifest initialManifest) {
|
public void init(SmoothStreamingManifest initialManifest) {
|
||||||
currentManifest = initialManifest;
|
currentManifest = initialManifest;
|
||||||
durationUs = currentManifest.durationUs;
|
|
||||||
ProtectionElement protectionElement = currentManifest.protectionElement;
|
ProtectionElement protectionElement = currentManifest.protectionElement;
|
||||||
if (protectionElement != null) {
|
if (protectionElement != null) {
|
||||||
byte[] keyId = getProtectionElementKeyId(protectionElement.data);
|
byte[] keyId = getProtectionElementKeyId(protectionElement.data);
|
||||||
|
|
@ -123,11 +121,6 @@ public class SmoothStreamingChunkSource implements ChunkSource {
|
||||||
initForManifest(currentManifest);
|
initForManifest(currentManifest);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public long getDurationUs() {
|
|
||||||
return durationUs;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public final TrackGroup getTracks() {
|
public final TrackGroup getTracks() {
|
||||||
return trackGroup;
|
return trackGroup;
|
||||||
|
|
@ -274,8 +267,9 @@ public class SmoothStreamingChunkSource implements ChunkSource {
|
||||||
extractorWrappers = new ChunkExtractorWrapper[formats.length];
|
extractorWrappers = new ChunkExtractorWrapper[formats.length];
|
||||||
for (int j = 0; j < formats.length; j++) {
|
for (int j = 0; j < formats.length; j++) {
|
||||||
int nalUnitLengthFieldLength = streamElementType == C.TRACK_TYPE_VIDEO ? 4 : -1;
|
int nalUnitLengthFieldLength = streamElementType == C.TRACK_TYPE_VIDEO ? 4 : -1;
|
||||||
Track track = new Track(j, streamElementType, timescale, C.UNSET_TIME_US, durationUs,
|
Track track = new Track(j, streamElementType, timescale, C.UNSET_TIME_US,
|
||||||
formats[j], trackEncryptionBoxes, nalUnitLengthFieldLength, null, null);
|
manifest.durationUs, formats[j], trackEncryptionBoxes, nalUnitLengthFieldLength,
|
||||||
|
null, null);
|
||||||
FragmentedMp4Extractor extractor = new FragmentedMp4Extractor(
|
FragmentedMp4Extractor extractor = new FragmentedMp4Extractor(
|
||||||
FragmentedMp4Extractor.FLAG_WORKAROUND_EVERY_VIDEO_FRAME_IS_SYNC_FRAME
|
FragmentedMp4Extractor.FLAG_WORKAROUND_EVERY_VIDEO_FRAME_IS_SYNC_FRAME
|
||||||
| FragmentedMp4Extractor.FLAG_WORKAROUND_IGNORE_TFDT_BOX, track);
|
| FragmentedMp4Extractor.FLAG_WORKAROUND_IGNORE_TFDT_BOX, track);
|
||||||
|
|
|
||||||
|
|
@ -53,8 +53,8 @@ public final class SmoothStreamingSampleSource implements SampleSource {
|
||||||
|
|
||||||
private final ManifestFetcher<SmoothStreamingManifest> manifestFetcher;
|
private final ManifestFetcher<SmoothStreamingManifest> manifestFetcher;
|
||||||
private final SmoothStreamingChunkSource[] chunkSources;
|
private final SmoothStreamingChunkSource[] chunkSources;
|
||||||
private final SampleSource[] sources;
|
private final ChunkSampleSource[] sources;
|
||||||
private final IdentityHashMap<TrackStream, SampleSource> trackStreamSources;
|
private final IdentityHashMap<TrackStream, ChunkSampleSource> trackStreamSources;
|
||||||
private final int[] selectedTrackCounts;
|
private final int[] selectedTrackCounts;
|
||||||
|
|
||||||
private SmoothStreamingManifest currentManifest;
|
private SmoothStreamingManifest currentManifest;
|
||||||
|
|
@ -62,7 +62,7 @@ public final class SmoothStreamingSampleSource implements SampleSource {
|
||||||
private boolean seenFirstTrackSelection;
|
private boolean seenFirstTrackSelection;
|
||||||
private long durationUs;
|
private long durationUs;
|
||||||
private TrackGroupArray trackGroups;
|
private TrackGroupArray trackGroups;
|
||||||
private SampleSource[] enabledSources;
|
private ChunkSampleSource[] enabledSources;
|
||||||
|
|
||||||
public SmoothStreamingSampleSource(Uri uri, DataSourceFactory dataSourceFactory,
|
public SmoothStreamingSampleSource(Uri uri, DataSourceFactory dataSourceFactory,
|
||||||
BandwidthMeter bandwidthMeter, Handler eventHandler,
|
BandwidthMeter bandwidthMeter, Handler eventHandler,
|
||||||
|
|
@ -99,7 +99,7 @@ public final class SmoothStreamingSampleSource implements SampleSource {
|
||||||
|
|
||||||
chunkSources = new SmoothStreamingChunkSource[] {videoChunkSource, audioChunkSource,
|
chunkSources = new SmoothStreamingChunkSource[] {videoChunkSource, audioChunkSource,
|
||||||
textChunkSource};
|
textChunkSource};
|
||||||
sources = new SampleSource[] {videoSampleSource, audioSampleSource, textSampleSource};
|
sources = new ChunkSampleSource[] {videoSampleSource, audioSampleSource, textSampleSource};
|
||||||
trackStreamSources = new IdentityHashMap<>();
|
trackStreamSources = new IdentityHashMap<>();
|
||||||
selectedTrackCounts = new int[sources.length];
|
selectedTrackCounts = new int[sources.length];
|
||||||
}
|
}
|
||||||
|
|
@ -117,32 +117,23 @@ public final class SmoothStreamingSampleSource implements SampleSource {
|
||||||
manifestFetcher.requestRefresh();
|
manifestFetcher.requestRefresh();
|
||||||
return false;
|
return false;
|
||||||
} else {
|
} else {
|
||||||
|
durationUs = currentManifest.durationUs;
|
||||||
for (SmoothStreamingChunkSource chunkSource : chunkSources) {
|
for (SmoothStreamingChunkSource chunkSource : chunkSources) {
|
||||||
chunkSource.init(currentManifest);
|
chunkSource.init(currentManifest);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean sourcesPrepared = true;
|
for (ChunkSampleSource source : sources) {
|
||||||
for (SampleSource source : sources) {
|
source.prepare();
|
||||||
sourcesPrepared &= source.prepare(positionUs);
|
|
||||||
}
|
}
|
||||||
if (!sourcesPrepared) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
durationUs = 0;
|
|
||||||
int totalTrackGroupCount = 0;
|
int totalTrackGroupCount = 0;
|
||||||
for (SampleSource source : sources) {
|
for (ChunkSampleSource source : sources) {
|
||||||
totalTrackGroupCount += source.getTrackGroups().length;
|
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];
|
TrackGroup[] trackGroupArray = new TrackGroup[totalTrackGroupCount];
|
||||||
int trackGroupIndex = 0;
|
int trackGroupIndex = 0;
|
||||||
for (SampleSource source : sources) {
|
for (ChunkSampleSource source : sources) {
|
||||||
int sourceTrackGroupCount = source.getTrackGroups().length;
|
int sourceTrackGroupCount = source.getTrackGroups().length;
|
||||||
for (int j = 0; j < sourceTrackGroupCount; j++) {
|
for (int j = 0; j < sourceTrackGroupCount; j++) {
|
||||||
trackGroupArray[trackGroupIndex++] = source.getTrackGroups().get(j);
|
trackGroupArray[trackGroupIndex++] = source.getTrackGroups().get(j);
|
||||||
|
|
@ -178,7 +169,7 @@ public final class SmoothStreamingSampleSource implements SampleSource {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Update the enabled sources.
|
// Update the enabled sources.
|
||||||
enabledSources = new SampleSource[enabledSourceCount];
|
enabledSources = new ChunkSampleSource[enabledSourceCount];
|
||||||
enabledSourceCount = 0;
|
enabledSourceCount = 0;
|
||||||
for (int i = 0; i < sources.length; i++) {
|
for (int i = 0; i < sources.length; i++) {
|
||||||
if (selectedTrackCounts[i] > 0) {
|
if (selectedTrackCounts[i] > 0) {
|
||||||
|
|
@ -211,7 +202,7 @@ public final class SmoothStreamingSampleSource implements SampleSource {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (SampleSource source : enabledSources) {
|
for (ChunkSampleSource source : enabledSources) {
|
||||||
source.continueBuffering(positionUs);
|
source.continueBuffering(positionUs);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -219,7 +210,7 @@ public final class SmoothStreamingSampleSource implements SampleSource {
|
||||||
@Override
|
@Override
|
||||||
public long readReset() {
|
public long readReset() {
|
||||||
long resetPositionUs = C.UNSET_TIME_US;
|
long resetPositionUs = C.UNSET_TIME_US;
|
||||||
for (SampleSource source : enabledSources) {
|
for (ChunkSampleSource source : enabledSources) {
|
||||||
long childResetPositionUs = source.readReset();
|
long childResetPositionUs = source.readReset();
|
||||||
if (resetPositionUs == C.UNSET_TIME_US) {
|
if (resetPositionUs == C.UNSET_TIME_US) {
|
||||||
resetPositionUs = childResetPositionUs;
|
resetPositionUs = childResetPositionUs;
|
||||||
|
|
@ -233,7 +224,7 @@ public final class SmoothStreamingSampleSource implements SampleSource {
|
||||||
@Override
|
@Override
|
||||||
public long getBufferedPositionUs() {
|
public long getBufferedPositionUs() {
|
||||||
long bufferedPositionUs = durationUs != C.UNSET_TIME_US ? durationUs : Long.MAX_VALUE;
|
long bufferedPositionUs = durationUs != C.UNSET_TIME_US ? durationUs : Long.MAX_VALUE;
|
||||||
for (SampleSource source : enabledSources) {
|
for (ChunkSampleSource source : enabledSources) {
|
||||||
long rendererBufferedPositionUs = source.getBufferedPositionUs();
|
long rendererBufferedPositionUs = source.getBufferedPositionUs();
|
||||||
if (rendererBufferedPositionUs == C.UNSET_TIME_US) {
|
if (rendererBufferedPositionUs == C.UNSET_TIME_US) {
|
||||||
return C.UNSET_TIME_US;
|
return C.UNSET_TIME_US;
|
||||||
|
|
@ -248,7 +239,7 @@ public final class SmoothStreamingSampleSource implements SampleSource {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void seekToUs(long positionUs) {
|
public void seekToUs(long positionUs) {
|
||||||
for (SampleSource source : enabledSources) {
|
for (ChunkSampleSource source : enabledSources) {
|
||||||
source.seekToUs(positionUs);
|
source.seekToUs(positionUs);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -256,14 +247,14 @@ public final class SmoothStreamingSampleSource implements SampleSource {
|
||||||
@Override
|
@Override
|
||||||
public void release() {
|
public void release() {
|
||||||
manifestFetcher.release();
|
manifestFetcher.release();
|
||||||
for (SampleSource source : sources) {
|
for (ChunkSampleSource source : sources) {
|
||||||
source.release();
|
source.release();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Internal methods.
|
// Internal methods.
|
||||||
|
|
||||||
private int selectTracks(SampleSource source, List<TrackStream> allOldStreams,
|
private int selectTracks(ChunkSampleSource source, List<TrackStream> allOldStreams,
|
||||||
List<TrackSelection> allNewSelections, long positionUs, TrackStream[] allNewStreams) {
|
List<TrackSelection> allNewSelections, long positionUs, TrackStream[] allNewStreams) {
|
||||||
// Get the subset of the old streams for the source.
|
// Get the subset of the old streams for the source.
|
||||||
ArrayList<TrackStream> oldStreams = new ArrayList<>();
|
ArrayList<TrackStream> oldStreams = new ArrayList<>();
|
||||||
|
|
@ -279,7 +270,7 @@ public final class SmoothStreamingSampleSource implements SampleSource {
|
||||||
int[] newSelectionOriginalIndices = new int[allNewSelections.size()];
|
int[] newSelectionOriginalIndices = new int[allNewSelections.size()];
|
||||||
for (int i = 0; i < allNewSelections.size(); i++) {
|
for (int i = 0; i < allNewSelections.size(); i++) {
|
||||||
TrackSelection selection = allNewSelections.get(i);
|
TrackSelection selection = allNewSelections.get(i);
|
||||||
Pair<SampleSource, Integer> sourceAndGroup = getSourceAndGroup(selection.group);
|
Pair<ChunkSampleSource, Integer> sourceAndGroup = getSourceAndGroup(selection.group);
|
||||||
if (sourceAndGroup.first == source) {
|
if (sourceAndGroup.first == source) {
|
||||||
newSelectionOriginalIndices[newSelections.size()] = i;
|
newSelectionOriginalIndices[newSelections.size()] = i;
|
||||||
newSelections.add(new TrackSelection(sourceAndGroup.second, selection.getTracks()));
|
newSelections.add(new TrackSelection(sourceAndGroup.second, selection.getTracks()));
|
||||||
|
|
@ -298,9 +289,9 @@ public final class SmoothStreamingSampleSource implements SampleSource {
|
||||||
return newSelections.size() - oldStreams.size();
|
return newSelections.size() - oldStreams.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
private Pair<SampleSource, Integer> getSourceAndGroup(int group) {
|
private Pair<ChunkSampleSource, Integer> getSourceAndGroup(int group) {
|
||||||
int totalTrackGroupCount = 0;
|
int totalTrackGroupCount = 0;
|
||||||
for (SampleSource source : sources) {
|
for (ChunkSampleSource source : sources) {
|
||||||
int sourceTrackGroupCount = source.getTrackGroups().length;
|
int sourceTrackGroupCount = source.getTrackGroups().length;
|
||||||
if (group < totalTrackGroupCount + sourceTrackGroupCount) {
|
if (group < totalTrackGroupCount + sourceTrackGroupCount) {
|
||||||
return Pair.create(source, group - totalTrackGroupCount);
|
return Pair.create(source, group - totalTrackGroupCount);
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue