mirror of
https://github.com/samsonjs/media.git
synced 2026-04-27 15:07:40 +00:00
Remove "variant" terminology from HlsChunkSource
HlsChunkSource may also be downloading segments from demuxed renditions, which are not variants. PiperOrigin-RevId: 240625139
This commit is contained in:
parent
65bab95f72
commit
0810fe9159
1 changed files with 50 additions and 50 deletions
|
|
@ -96,7 +96,7 @@ import java.util.Map;
|
||||||
private final DataSource mediaDataSource;
|
private final DataSource mediaDataSource;
|
||||||
private final DataSource encryptionDataSource;
|
private final DataSource encryptionDataSource;
|
||||||
private final TimestampAdjusterProvider timestampAdjusterProvider;
|
private final TimestampAdjusterProvider timestampAdjusterProvider;
|
||||||
private final HlsUrl[] variants;
|
private final HlsUrl[] hlsUrls;
|
||||||
private final HlsPlaylistTracker playlistTracker;
|
private final HlsPlaylistTracker playlistTracker;
|
||||||
private final TrackGroup trackGroup;
|
private final TrackGroup trackGroup;
|
||||||
private final List<Format> muxedCaptionFormats;
|
private final List<Format> muxedCaptionFormats;
|
||||||
|
|
@ -119,7 +119,8 @@ import java.util.Map;
|
||||||
* @param extractorFactory An {@link HlsExtractorFactory} from which to obtain the extractors for
|
* @param extractorFactory An {@link HlsExtractorFactory} from which to obtain the extractors for
|
||||||
* media chunks.
|
* media chunks.
|
||||||
* @param playlistTracker The {@link HlsPlaylistTracker} from which to obtain media playlists.
|
* @param playlistTracker The {@link HlsPlaylistTracker} from which to obtain media playlists.
|
||||||
* @param variants The available variants.
|
* @param hlsUrls The {@link HlsUrl} instances corresponding to media playlists from which this
|
||||||
|
* chunk source can obtain media.
|
||||||
* @param dataSourceFactory An {@link HlsDataSourceFactory} to create {@link DataSource}s for the
|
* @param dataSourceFactory An {@link HlsDataSourceFactory} to create {@link DataSource}s for the
|
||||||
* chunks.
|
* chunks.
|
||||||
* @param mediaTransferListener The transfer listener which should be informed of any media data
|
* @param mediaTransferListener The transfer listener which should be informed of any media data
|
||||||
|
|
@ -133,22 +134,22 @@ import java.util.Map;
|
||||||
public HlsChunkSource(
|
public HlsChunkSource(
|
||||||
HlsExtractorFactory extractorFactory,
|
HlsExtractorFactory extractorFactory,
|
||||||
HlsPlaylistTracker playlistTracker,
|
HlsPlaylistTracker playlistTracker,
|
||||||
HlsUrl[] variants,
|
HlsUrl[] hlsUrls,
|
||||||
HlsDataSourceFactory dataSourceFactory,
|
HlsDataSourceFactory dataSourceFactory,
|
||||||
@Nullable TransferListener mediaTransferListener,
|
@Nullable TransferListener mediaTransferListener,
|
||||||
TimestampAdjusterProvider timestampAdjusterProvider,
|
TimestampAdjusterProvider timestampAdjusterProvider,
|
||||||
List<Format> muxedCaptionFormats) {
|
List<Format> muxedCaptionFormats) {
|
||||||
this.extractorFactory = extractorFactory;
|
this.extractorFactory = extractorFactory;
|
||||||
this.playlistTracker = playlistTracker;
|
this.playlistTracker = playlistTracker;
|
||||||
this.variants = variants;
|
this.hlsUrls = hlsUrls;
|
||||||
this.timestampAdjusterProvider = timestampAdjusterProvider;
|
this.timestampAdjusterProvider = timestampAdjusterProvider;
|
||||||
this.muxedCaptionFormats = muxedCaptionFormats;
|
this.muxedCaptionFormats = muxedCaptionFormats;
|
||||||
keyCache = new FullSegmentEncryptionKeyCache();
|
keyCache = new FullSegmentEncryptionKeyCache();
|
||||||
liveEdgeInPeriodTimeUs = C.TIME_UNSET;
|
liveEdgeInPeriodTimeUs = C.TIME_UNSET;
|
||||||
Format[] variantFormats = new Format[variants.length];
|
Format[] trackFormats = new Format[hlsUrls.length];
|
||||||
int[] initialTrackSelection = new int[variants.length];
|
int[] initialTrackSelection = new int[hlsUrls.length];
|
||||||
for (int i = 0; i < variants.length; i++) {
|
for (int i = 0; i < hlsUrls.length; i++) {
|
||||||
variantFormats[i] = variants[i].format;
|
trackFormats[i] = hlsUrls[i].format;
|
||||||
initialTrackSelection[i] = i;
|
initialTrackSelection[i] = i;
|
||||||
}
|
}
|
||||||
mediaDataSource = dataSourceFactory.createDataSource(C.DATA_TYPE_MEDIA);
|
mediaDataSource = dataSourceFactory.createDataSource(C.DATA_TYPE_MEDIA);
|
||||||
|
|
@ -156,7 +157,7 @@ import java.util.Map;
|
||||||
mediaDataSource.addTransferListener(mediaTransferListener);
|
mediaDataSource.addTransferListener(mediaTransferListener);
|
||||||
}
|
}
|
||||||
encryptionDataSource = dataSourceFactory.createDataSource(C.DATA_TYPE_DRM);
|
encryptionDataSource = dataSourceFactory.createDataSource(C.DATA_TYPE_DRM);
|
||||||
trackGroup = new TrackGroup(variantFormats);
|
trackGroup = new TrackGroup(trackFormats);
|
||||||
trackSelection = new InitializationTrackSelection(trackGroup, initialTrackSelection);
|
trackSelection = new InitializationTrackSelection(trackGroup, initialTrackSelection);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -234,12 +235,11 @@ import java.util.Map;
|
||||||
public void getNextChunk(
|
public void getNextChunk(
|
||||||
long playbackPositionUs, long loadPositionUs, List<HlsMediaChunk> queue, HlsChunkHolder out) {
|
long playbackPositionUs, long loadPositionUs, List<HlsMediaChunk> queue, HlsChunkHolder out) {
|
||||||
HlsMediaChunk previous = queue.isEmpty() ? null : queue.get(queue.size() - 1);
|
HlsMediaChunk previous = queue.isEmpty() ? null : queue.get(queue.size() - 1);
|
||||||
int oldVariantIndex = previous == null ? C.INDEX_UNSET
|
int oldTrackIndex = previous == null ? C.INDEX_UNSET : trackGroup.indexOf(previous.trackFormat);
|
||||||
: trackGroup.indexOf(previous.trackFormat);
|
|
||||||
long bufferedDurationUs = loadPositionUs - playbackPositionUs;
|
long bufferedDurationUs = loadPositionUs - playbackPositionUs;
|
||||||
long timeToLiveEdgeUs = resolveTimeToLiveEdgeUs(playbackPositionUs);
|
long timeToLiveEdgeUs = resolveTimeToLiveEdgeUs(playbackPositionUs);
|
||||||
if (previous != null && !independentSegments) {
|
if (previous != null && !independentSegments) {
|
||||||
// Unless segments are known to be independent, switching variant requires downloading
|
// Unless segments are known to be independent, switching tracks requires downloading
|
||||||
// overlapping segments. Hence we subtract the previous segment's duration from the buffered
|
// overlapping segments. Hence we subtract the previous segment's duration from the buffered
|
||||||
// duration.
|
// duration.
|
||||||
// This may affect the live-streaming adaptive track selection logic, when we compare the
|
// This may affect the live-streaming adaptive track selection logic, when we compare the
|
||||||
|
|
@ -252,23 +252,23 @@ import java.util.Map;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Select the variant.
|
// Select the track.
|
||||||
MediaChunkIterator[] mediaChunkIterators = createMediaChunkIterators(previous, loadPositionUs);
|
MediaChunkIterator[] mediaChunkIterators = createMediaChunkIterators(previous, loadPositionUs);
|
||||||
trackSelection.updateSelectedTrack(
|
trackSelection.updateSelectedTrack(
|
||||||
playbackPositionUs, bufferedDurationUs, timeToLiveEdgeUs, queue, mediaChunkIterators);
|
playbackPositionUs, bufferedDurationUs, timeToLiveEdgeUs, queue, mediaChunkIterators);
|
||||||
int selectedVariantIndex = trackSelection.getSelectedIndexInTrackGroup();
|
int selectedTrackIndex = trackSelection.getSelectedIndexInTrackGroup();
|
||||||
|
|
||||||
boolean switchingVariant = oldVariantIndex != selectedVariantIndex;
|
boolean switchingTrack = oldTrackIndex != selectedTrackIndex;
|
||||||
HlsUrl selectedUrl = variants[selectedVariantIndex];
|
HlsUrl selectedHlsUrl = hlsUrls[selectedTrackIndex];
|
||||||
if (!playlistTracker.isSnapshotValid(selectedUrl)) {
|
if (!playlistTracker.isSnapshotValid(selectedHlsUrl)) {
|
||||||
out.playlist = selectedUrl;
|
out.playlist = selectedHlsUrl;
|
||||||
seenExpectedPlaylistError &= expectedPlaylistUrl == selectedUrl;
|
seenExpectedPlaylistError &= expectedPlaylistUrl == selectedHlsUrl;
|
||||||
expectedPlaylistUrl = selectedUrl;
|
expectedPlaylistUrl = selectedHlsUrl;
|
||||||
// Retry when playlist is refreshed.
|
// Retry when playlist is refreshed.
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
HlsMediaPlaylist mediaPlaylist =
|
HlsMediaPlaylist mediaPlaylist =
|
||||||
playlistTracker.getPlaylistSnapshot(selectedUrl, /* isForPlayback= */ true);
|
playlistTracker.getPlaylistSnapshot(selectedHlsUrl, /* isForPlayback= */ true);
|
||||||
independentSegments = mediaPlaylist.hasIndependentSegments;
|
independentSegments = mediaPlaylist.hasIndependentSegments;
|
||||||
|
|
||||||
updateLiveEdgeTimeUs(mediaPlaylist);
|
updateLiveEdgeTimeUs(mediaPlaylist);
|
||||||
|
|
@ -278,14 +278,15 @@ import java.util.Map;
|
||||||
mediaPlaylist.startTimeUs - playlistTracker.getInitialStartTimeUs();
|
mediaPlaylist.startTimeUs - playlistTracker.getInitialStartTimeUs();
|
||||||
long chunkMediaSequence =
|
long chunkMediaSequence =
|
||||||
getChunkMediaSequence(
|
getChunkMediaSequence(
|
||||||
previous, switchingVariant, mediaPlaylist, startOfPlaylistInPeriodUs, loadPositionUs);
|
previous, switchingTrack, mediaPlaylist, startOfPlaylistInPeriodUs, loadPositionUs);
|
||||||
if (chunkMediaSequence < mediaPlaylist.mediaSequence) {
|
if (chunkMediaSequence < mediaPlaylist.mediaSequence) {
|
||||||
if (previous != null && switchingVariant) {
|
if (previous != null && switchingTrack) {
|
||||||
// We try getting the next chunk without adapting in case that's the reason for falling
|
// We try getting the next chunk without adapting in case that's the reason for falling
|
||||||
// behind the live window.
|
// behind the live window.
|
||||||
selectedVariantIndex = oldVariantIndex;
|
selectedTrackIndex = oldTrackIndex;
|
||||||
selectedUrl = variants[selectedVariantIndex];
|
selectedHlsUrl = hlsUrls[selectedTrackIndex];
|
||||||
mediaPlaylist = playlistTracker.getPlaylistSnapshot(selectedUrl, /* isForPlayback= */ true);
|
mediaPlaylist =
|
||||||
|
playlistTracker.getPlaylistSnapshot(selectedHlsUrl, /* isForPlayback= */ true);
|
||||||
startOfPlaylistInPeriodUs =
|
startOfPlaylistInPeriodUs =
|
||||||
mediaPlaylist.startTimeUs - playlistTracker.getInitialStartTimeUs();
|
mediaPlaylist.startTimeUs - playlistTracker.getInitialStartTimeUs();
|
||||||
chunkMediaSequence = previous.getNextChunkIndex();
|
chunkMediaSequence = previous.getNextChunkIndex();
|
||||||
|
|
@ -300,9 +301,9 @@ import java.util.Map;
|
||||||
if (mediaPlaylist.hasEndTag) {
|
if (mediaPlaylist.hasEndTag) {
|
||||||
out.endOfStream = true;
|
out.endOfStream = true;
|
||||||
} else /* Live */ {
|
} else /* Live */ {
|
||||||
out.playlist = selectedUrl;
|
out.playlist = selectedHlsUrl;
|
||||||
seenExpectedPlaylistError &= expectedPlaylistUrl == selectedUrl;
|
seenExpectedPlaylistError &= expectedPlaylistUrl == selectedHlsUrl;
|
||||||
expectedPlaylistUrl = selectedUrl;
|
expectedPlaylistUrl = selectedHlsUrl;
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
@ -315,12 +316,12 @@ import java.util.Map;
|
||||||
|
|
||||||
// Check if the segment or its initialization segment are fully encrypted.
|
// Check if the segment or its initialization segment are fully encrypted.
|
||||||
Uri initSegmentKeyUri = getFullEncryptionKeyUri(mediaPlaylist, segment.initializationSegment);
|
Uri initSegmentKeyUri = getFullEncryptionKeyUri(mediaPlaylist, segment.initializationSegment);
|
||||||
out.chunk = maybeCreateEncryptionChunkFor(initSegmentKeyUri, selectedVariantIndex);
|
out.chunk = maybeCreateEncryptionChunkFor(initSegmentKeyUri, selectedTrackIndex);
|
||||||
if (out.chunk != null) {
|
if (out.chunk != null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Uri mediaSegmentKeyUri = getFullEncryptionKeyUri(mediaPlaylist, segment);
|
Uri mediaSegmentKeyUri = getFullEncryptionKeyUri(mediaPlaylist, segment);
|
||||||
out.chunk = maybeCreateEncryptionChunkFor(mediaSegmentKeyUri, selectedVariantIndex);
|
out.chunk = maybeCreateEncryptionChunkFor(mediaSegmentKeyUri, selectedTrackIndex);
|
||||||
if (out.chunk != null) {
|
if (out.chunk != null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
@ -332,7 +333,7 @@ import java.util.Map;
|
||||||
startOfPlaylistInPeriodUs,
|
startOfPlaylistInPeriodUs,
|
||||||
mediaPlaylist,
|
mediaPlaylist,
|
||||||
segmentIndexInPlaylist,
|
segmentIndexInPlaylist,
|
||||||
selectedUrl,
|
selectedHlsUrl,
|
||||||
muxedCaptionFormats,
|
muxedCaptionFormats,
|
||||||
trackSelection.getSelectionReason(),
|
trackSelection.getSelectionReason(),
|
||||||
trackSelection.getSelectionData(),
|
trackSelection.getSelectionData(),
|
||||||
|
|
@ -374,13 +375,13 @@ import java.util.Map;
|
||||||
/**
|
/**
|
||||||
* Called when a playlist load encounters an error.
|
* Called when a playlist load encounters an error.
|
||||||
*
|
*
|
||||||
* @param url The url of the playlist whose load encountered an error.
|
* @param hlsUrl The {@link HlsUrl} of the playlist whose load encountered an error.
|
||||||
* @param blacklistDurationMs The duration for which the playlist should be blacklisted. Or {@link
|
* @param blacklistDurationMs The duration for which the playlist should be blacklisted. Or {@link
|
||||||
* C#TIME_UNSET} if the playlist should not be blacklisted.
|
* C#TIME_UNSET} if the playlist should not be blacklisted.
|
||||||
* @return True if blacklisting did not encounter errors. False otherwise.
|
* @return True if blacklisting did not encounter errors. False otherwise.
|
||||||
*/
|
*/
|
||||||
public boolean onPlaylistError(HlsUrl url, long blacklistDurationMs) {
|
public boolean onPlaylistError(HlsUrl hlsUrl, long blacklistDurationMs) {
|
||||||
int trackGroupIndex = trackGroup.indexOf(url.format);
|
int trackGroupIndex = trackGroup.indexOf(hlsUrl.format);
|
||||||
if (trackGroupIndex == C.INDEX_UNSET) {
|
if (trackGroupIndex == C.INDEX_UNSET) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
@ -388,7 +389,7 @@ import java.util.Map;
|
||||||
if (trackSelectionIndex == C.INDEX_UNSET) {
|
if (trackSelectionIndex == C.INDEX_UNSET) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
seenExpectedPlaylistError |= expectedPlaylistUrl == url;
|
seenExpectedPlaylistError |= expectedPlaylistUrl == hlsUrl;
|
||||||
return blacklistDurationMs == C.TIME_UNSET
|
return blacklistDurationMs == C.TIME_UNSET
|
||||||
|| trackSelection.blacklist(trackSelectionIndex, blacklistDurationMs);
|
|| trackSelection.blacklist(trackSelectionIndex, blacklistDurationMs);
|
||||||
}
|
}
|
||||||
|
|
@ -402,24 +403,23 @@ import java.util.Map;
|
||||||
*/
|
*/
|
||||||
public MediaChunkIterator[] createMediaChunkIterators(
|
public MediaChunkIterator[] createMediaChunkIterators(
|
||||||
@Nullable HlsMediaChunk previous, long loadPositionUs) {
|
@Nullable HlsMediaChunk previous, long loadPositionUs) {
|
||||||
int oldVariantIndex =
|
int oldTrackIndex = previous == null ? C.INDEX_UNSET : trackGroup.indexOf(previous.trackFormat);
|
||||||
previous == null ? C.INDEX_UNSET : trackGroup.indexOf(previous.trackFormat);
|
|
||||||
MediaChunkIterator[] chunkIterators = new MediaChunkIterator[trackSelection.length()];
|
MediaChunkIterator[] chunkIterators = new MediaChunkIterator[trackSelection.length()];
|
||||||
for (int i = 0; i < chunkIterators.length; i++) {
|
for (int i = 0; i < chunkIterators.length; i++) {
|
||||||
int variantIndex = trackSelection.getIndexInTrackGroup(i);
|
int trackIndex = trackSelection.getIndexInTrackGroup(i);
|
||||||
HlsUrl variantUrl = variants[variantIndex];
|
HlsUrl hlsUrl = hlsUrls[trackIndex];
|
||||||
if (!playlistTracker.isSnapshotValid(variantUrl)) {
|
if (!playlistTracker.isSnapshotValid(hlsUrl)) {
|
||||||
chunkIterators[i] = MediaChunkIterator.EMPTY;
|
chunkIterators[i] = MediaChunkIterator.EMPTY;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
HlsMediaPlaylist playlist =
|
HlsMediaPlaylist playlist =
|
||||||
playlistTracker.getPlaylistSnapshot(variantUrl, /* isForPlayback= */ false);
|
playlistTracker.getPlaylistSnapshot(hlsUrl, /* isForPlayback= */ false);
|
||||||
long startOfPlaylistInPeriodUs =
|
long startOfPlaylistInPeriodUs =
|
||||||
playlist.startTimeUs - playlistTracker.getInitialStartTimeUs();
|
playlist.startTimeUs - playlistTracker.getInitialStartTimeUs();
|
||||||
boolean switchingVariant = variantIndex != oldVariantIndex;
|
boolean switchingTrack = trackIndex != oldTrackIndex;
|
||||||
long chunkMediaSequence =
|
long chunkMediaSequence =
|
||||||
getChunkMediaSequence(
|
getChunkMediaSequence(
|
||||||
previous, switchingVariant, playlist, startOfPlaylistInPeriodUs, loadPositionUs);
|
previous, switchingTrack, playlist, startOfPlaylistInPeriodUs, loadPositionUs);
|
||||||
if (chunkMediaSequence < playlist.mediaSequence) {
|
if (chunkMediaSequence < playlist.mediaSequence) {
|
||||||
chunkIterators[i] = MediaChunkIterator.EMPTY;
|
chunkIterators[i] = MediaChunkIterator.EMPTY;
|
||||||
continue;
|
continue;
|
||||||
|
|
@ -437,8 +437,8 @@ import java.util.Map;
|
||||||
* Returns the media sequence number of the segment to load next in {@code mediaPlaylist}.
|
* Returns the media sequence number of the segment to load next in {@code mediaPlaylist}.
|
||||||
*
|
*
|
||||||
* @param previous The last (at least partially) loaded segment.
|
* @param previous The last (at least partially) loaded segment.
|
||||||
* @param switchingVariant Whether the segment to load is not preceded by a segment in the same
|
* @param switchingTrack Whether the segment to load is not preceded by a segment in the same
|
||||||
* variant.
|
* track.
|
||||||
* @param mediaPlaylist The media playlist to which the segment to load belongs.
|
* @param mediaPlaylist The media playlist to which the segment to load belongs.
|
||||||
* @param startOfPlaylistInPeriodUs The start of {@code mediaPlaylist} relative to the period
|
* @param startOfPlaylistInPeriodUs The start of {@code mediaPlaylist} relative to the period
|
||||||
* start in microseconds.
|
* start in microseconds.
|
||||||
|
|
@ -447,11 +447,11 @@ import java.util.Map;
|
||||||
*/
|
*/
|
||||||
private long getChunkMediaSequence(
|
private long getChunkMediaSequence(
|
||||||
@Nullable HlsMediaChunk previous,
|
@Nullable HlsMediaChunk previous,
|
||||||
boolean switchingVariant,
|
boolean switchingTrack,
|
||||||
HlsMediaPlaylist mediaPlaylist,
|
HlsMediaPlaylist mediaPlaylist,
|
||||||
long startOfPlaylistInPeriodUs,
|
long startOfPlaylistInPeriodUs,
|
||||||
long loadPositionUs) {
|
long loadPositionUs) {
|
||||||
if (previous == null || switchingVariant) {
|
if (previous == null || switchingTrack) {
|
||||||
long endOfPlaylistInPeriodUs = startOfPlaylistInPeriodUs + mediaPlaylist.durationUs;
|
long endOfPlaylistInPeriodUs = startOfPlaylistInPeriodUs + mediaPlaylist.durationUs;
|
||||||
long targetPositionInPeriodUs =
|
long targetPositionInPeriodUs =
|
||||||
(previous == null || independentSegments) ? loadPositionUs : previous.startTimeUs;
|
(previous == null || independentSegments) ? loadPositionUs : previous.startTimeUs;
|
||||||
|
|
@ -487,7 +487,7 @@ import java.util.Map;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
private Chunk maybeCreateEncryptionChunkFor(@Nullable Uri keyUri, int selectedVariantIndex) {
|
private Chunk maybeCreateEncryptionChunkFor(@Nullable Uri keyUri, int selectedTrackIndex) {
|
||||||
if (keyUri == null) {
|
if (keyUri == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
@ -502,7 +502,7 @@ import java.util.Map;
|
||||||
return new EncryptionKeyChunk(
|
return new EncryptionKeyChunk(
|
||||||
encryptionDataSource,
|
encryptionDataSource,
|
||||||
dataSpec,
|
dataSpec,
|
||||||
variants[selectedVariantIndex].format,
|
hlsUrls[selectedTrackIndex].format,
|
||||||
trackSelection.getSelectionReason(),
|
trackSelection.getSelectionReason(),
|
||||||
trackSelection.getSelectionData(),
|
trackSelection.getSelectionData(),
|
||||||
scratchSpace);
|
scratchSpace);
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue