use of com.google.android.exoplayer2.source.hls.playlist.HlsMultivariantPlaylist.Variant in project twicalico by moko256.
the class ImagePagerChildFragment method onCreateView.
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
FlingLayout view = (FlingLayout) inflater.inflate(R.layout.fragment_image_pager_child, null);
view.setDismissListener(() -> {
getActivity().finish();
return Unit.INSTANCE;
});
view.setPositionChangeListener((Integer top, Integer left, Float dragRangeRate) -> {
view.setBackgroundColor(Color.argb(Math.round(255 * (1.0F - dragRangeRate)), 0, 0, 0));
return Unit.INSTANCE;
});
MediaEntity mediaEntity;
if (getArguments() == null)
return view;
mediaEntity = (MediaEntity) getArguments().getSerializable(FRAG_MEDIA_ENTITY);
if (mediaEntity == null)
return view;
switch(mediaEntity.getType()) {
case "video":
String videoPath = null;
boolean isHls = false;
for (MediaEntity.Variant variant : mediaEntity.getVideoVariants()) {
if (variant.getContentType().equals("application/x-mpegURL")) {
videoPath = variant.getUrl();
isHls = true;
}
}
if (videoPath == null) {
videoPath = mediaEntity.getVideoVariants()[0].getUrl();
}
videoPlayView = view.findViewById(R.id.fragment_image_pager_video);
videoPlayView.setVisibility(View.VISIBLE);
videoPlayView.setControllerVisibilityListener(visibility -> {
if (visibility != View.VISIBLE) {
hideSystemUI();
} else {
showSystemUI();
}
});
getActivity().getWindow().getDecorView().setOnSystemUiVisibilityChangeListener(visibility -> {
if ((visibility & View.SYSTEM_UI_FLAG_FULLSCREEN) == 0) {
((AppCompatActivity) getActivity()).getSupportActionBar().show();
videoPlayView.showController();
}
});
player = ExoPlayerFactory.newSimpleInstance(new DefaultRenderersFactory(getContext()), new DefaultTrackSelector(new AdaptiveTrackSelection.Factory(new DefaultBandwidthMeter(), Integer.MAX_VALUE, AdaptiveTrackSelection.DEFAULT_MIN_DURATION_FOR_QUALITY_INCREASE_MS, AdaptiveTrackSelection.DEFAULT_MAX_DURATION_FOR_QUALITY_DECREASE_MS, AdaptiveTrackSelection.DEFAULT_MIN_DURATION_TO_RETAIN_AFTER_DISCARD_MS, AdaptiveTrackSelection.DEFAULT_BANDWIDTH_FRACTION)), new DefaultLoadControl());
if (savedInstanceState != null) {
player.seekTo(savedInstanceState.getLong("video_time", 0));
}
videoPlayView.setPlayer(player);
player.prepare((isHls) ? new HlsMediaSource.Factory(new OkHttpDataSourceFactory(GlobalApplication.getOkHttpClient(), getResources().getText(R.string.app_name).toString(), null)).createMediaSource(Uri.parse(videoPath)) : new ExtractorMediaSource.Factory(new OkHttpDataSourceFactory(GlobalApplication.getOkHttpClient(), getResources().getText(R.string.app_name).toString(), null)).createMediaSource(Uri.parse(mediaEntity.getVideoVariants()[0].getUrl()), new Handler(), null));
break;
case "animated_gif":
videoPlayView = view.findViewById(R.id.fragment_image_pager_video);
videoPlayView.setVisibility(View.VISIBLE);
videoPlayView.setControllerVisibilityListener(visibility -> {
if (visibility != View.VISIBLE) {
hideSystemUI();
} else {
showSystemUI();
}
});
getActivity().getWindow().getDecorView().setOnSystemUiVisibilityChangeListener(visibility -> {
if ((visibility & View.SYSTEM_UI_FLAG_FULLSCREEN) == 0) {
((AppCompatActivity) getActivity()).getSupportActionBar().show();
videoPlayView.showController();
}
});
player = ExoPlayerFactory.newSimpleInstance(new DefaultRenderersFactory(getContext()), new DefaultTrackSelector(new AdaptiveTrackSelection.Factory(new DefaultBandwidthMeter(), Integer.MAX_VALUE, AdaptiveTrackSelection.DEFAULT_MIN_DURATION_FOR_QUALITY_INCREASE_MS, AdaptiveTrackSelection.DEFAULT_MAX_DURATION_FOR_QUALITY_DECREASE_MS, AdaptiveTrackSelection.DEFAULT_MIN_DURATION_TO_RETAIN_AFTER_DISCARD_MS, AdaptiveTrackSelection.DEFAULT_BANDWIDTH_FRACTION)), new DefaultLoadControl());
if (savedInstanceState != null) {
player.seekTo(savedInstanceState.getLong("video_time", 0));
}
videoPlayView.setPlayer(player);
player.prepare(new LoopingMediaSource(new ExtractorMediaSource.Factory(new OkHttpDataSourceFactory(GlobalApplication.getOkHttpClient(), getResources().getText(R.string.app_name).toString(), null)).createMediaSource(Uri.parse(mediaEntity.getVideoVariants()[0].getUrl()), new Handler(), null)));
player.setPlayWhenReady(true);
break;
case "photo":
default:
getActivity().getWindow().getDecorView().setOnSystemUiVisibilityChangeListener(visibility -> {
if ((visibility & View.SYSTEM_UI_FLAG_FULLSCREEN) == 0) {
((AppCompatActivity) getActivity()).getSupportActionBar().show();
}
});
imageView = view.findViewById(R.id.fragment_image_pager_image);
imageView.setVisibility(View.VISIBLE);
imageView.setOnClickListener(v -> {
if ((getActivity().getWindow().getDecorView().getSystemUiVisibility() & View.SYSTEM_UI_FLAG_FULLSCREEN) == 0) {
hideSystemUI();
} else {
showSystemUI();
}
});
imageView.setOnScaleChangeListener((float scaleFactor, float focusX, float focusY) -> view.setDragEnabled(scaleFactor <= 1F));
GlideApp.with(this).load(TwitterStringUtils.convertLargeImageUrl(mediaEntity.getMediaURLHttps())).fitCenter().thumbnail(GlideApp.with(this).load(TwitterStringUtils.convertSmallImageUrl(mediaEntity.getMediaURLHttps())).fitCenter()).into(imageView);
break;
}
return view;
}
use of com.google.android.exoplayer2.source.hls.playlist.HlsMultivariantPlaylist.Variant in project ExoPlayer by google.
the class HlsSampleStreamWrapper method deriveFormat.
/**
* Derives a track sample format from the corresponding format in the multivariant playlist, and a
* sample format that may have been obtained from a chunk belonging to a different track in the
* same track group.
*
* <p>Note: Since the sample format may have been obtained from a chunk belonging to a different
* track, it should not be used as a source for data that may vary between tracks.
*
* @param playlistFormat The format information obtained from the multivariant playlist.
* @param sampleFormat The format information obtained from samples within a chunk. The chunk may
* belong to a different track in the same track group.
* @param propagateBitrates Whether the bitrates from the playlist format should be included in
* the derived format.
* @return The derived track format.
*/
private static Format deriveFormat(@Nullable Format playlistFormat, Format sampleFormat, boolean propagateBitrates) {
if (playlistFormat == null) {
return sampleFormat;
}
int sampleTrackType = MimeTypes.getTrackType(sampleFormat.sampleMimeType);
@Nullable String sampleMimeType;
@Nullable String codecs;
if (Util.getCodecCountOfType(playlistFormat.codecs, sampleTrackType) == 1) {
// We can unequivocally map this track to a playlist variant because only one codec string
// matches this track's type.
codecs = Util.getCodecsOfType(playlistFormat.codecs, sampleTrackType);
sampleMimeType = MimeTypes.getMediaMimeType(codecs);
} else {
// The variant assigns more than one codec string to this track. We choose whichever codec
// string matches the sample mime type. This can happen when different languages are encoded
// using different codecs.
codecs = MimeTypes.getCodecsCorrespondingToMimeType(playlistFormat.codecs, sampleFormat.sampleMimeType);
sampleMimeType = sampleFormat.sampleMimeType;
}
Format.Builder formatBuilder = sampleFormat.buildUpon().setId(playlistFormat.id).setLabel(playlistFormat.label).setLanguage(playlistFormat.language).setSelectionFlags(playlistFormat.selectionFlags).setRoleFlags(playlistFormat.roleFlags).setAverageBitrate(propagateBitrates ? playlistFormat.averageBitrate : Format.NO_VALUE).setPeakBitrate(propagateBitrates ? playlistFormat.peakBitrate : Format.NO_VALUE).setCodecs(codecs);
if (sampleTrackType == C.TRACK_TYPE_VIDEO) {
formatBuilder.setWidth(playlistFormat.width).setHeight(playlistFormat.height).setFrameRate(playlistFormat.frameRate);
}
if (sampleMimeType != null) {
formatBuilder.setSampleMimeType(sampleMimeType);
}
if (playlistFormat.channelCount != Format.NO_VALUE && sampleTrackType == C.TRACK_TYPE_AUDIO) {
formatBuilder.setChannelCount(playlistFormat.channelCount);
}
if (playlistFormat.metadata != null) {
Metadata metadata = playlistFormat.metadata;
if (sampleFormat.metadata != null) {
metadata = sampleFormat.metadata.copyWithAppendedEntriesFrom(metadata);
}
formatBuilder.setMetadata(metadata);
}
return formatBuilder.build();
}
use of com.google.android.exoplayer2.source.hls.playlist.HlsMultivariantPlaylist.Variant in project ExoPlayer by google.
the class HlsSampleStreamWrapper method buildTracksFromSampleStreams.
/**
* Builds tracks that are exposed by this {@link HlsSampleStreamWrapper} instance, as well as
* internal data-structures required for operation.
*
* <p>Tracks in HLS are complicated. A HLS multivariant playlist contains a number of "variants".
* Each variant stream typically contains muxed video, audio and (possibly) additional audio,
* metadata and caption tracks. We wish to allow the user to select between an adaptive track that
* spans all variants, as well as each individual variant. If multiple audio tracks are present
* within each variant then we wish to allow the user to select between those also.
*
* <p>To do this, tracks are constructed as follows. The {@link HlsChunkSource} exposes (N+1)
* tracks, where N is the number of variants defined in the HLS multivariant playlist. These
* consist of one adaptive track defined to span all variants and a track for each individual
* variant. The adaptive track is initially selected. The extractor is then prepared to discover
* the tracks inside of each variant stream. The two sets of tracks are then combined by this
* method to create a third set, which is the set exposed by this {@link HlsSampleStreamWrapper}:
*
* <ul>
* <li>The extractor tracks are inspected to infer a "primary" track type. If a video track is
* present then it is always the primary type. If not, audio is the primary type if present.
* Else text is the primary type if present. Else there is no primary type.
* <li>If there is exactly one extractor track of the primary type, it's expanded into (N+1)
* exposed tracks, all of which correspond to the primary extractor track and each of which
* corresponds to a different chunk source track. Selecting one of these tracks has the
* effect of switching the selected track on the chunk source.
* <li>All other extractor tracks are exposed directly. Selecting one of these tracks has the
* effect of selecting an extractor track, leaving the selected track on the chunk source
* unchanged.
* </ul>
*/
@EnsuresNonNull({ "trackGroups", "optionalTrackGroups", "trackGroupToSampleQueueIndex" })
private void buildTracksFromSampleStreams() {
// Iterate through the extractor tracks to discover the "primary" track type, and the index
// of the single track of this type.
int primaryExtractorTrackType = C.TRACK_TYPE_NONE;
int primaryExtractorTrackIndex = C.INDEX_UNSET;
int extractorTrackCount = sampleQueues.length;
for (int i = 0; i < extractorTrackCount; i++) {
@Nullable String sampleMimeType = Assertions.checkStateNotNull(sampleQueues[i].getUpstreamFormat()).sampleMimeType;
int trackType;
if (MimeTypes.isVideo(sampleMimeType)) {
trackType = C.TRACK_TYPE_VIDEO;
} else if (MimeTypes.isAudio(sampleMimeType)) {
trackType = C.TRACK_TYPE_AUDIO;
} else if (MimeTypes.isText(sampleMimeType)) {
trackType = C.TRACK_TYPE_TEXT;
} else {
trackType = C.TRACK_TYPE_NONE;
}
if (getTrackTypeScore(trackType) > getTrackTypeScore(primaryExtractorTrackType)) {
primaryExtractorTrackType = trackType;
primaryExtractorTrackIndex = i;
} else if (trackType == primaryExtractorTrackType && primaryExtractorTrackIndex != C.INDEX_UNSET) {
// We have multiple tracks of the primary type. We only want an index if there only exists a
// single track of the primary type, so unset the index again.
primaryExtractorTrackIndex = C.INDEX_UNSET;
}
}
TrackGroup chunkSourceTrackGroup = chunkSource.getTrackGroup();
int chunkSourceTrackCount = chunkSourceTrackGroup.length;
// Instantiate the necessary internal data-structures.
primaryTrackGroupIndex = C.INDEX_UNSET;
trackGroupToSampleQueueIndex = new int[extractorTrackCount];
for (int i = 0; i < extractorTrackCount; i++) {
trackGroupToSampleQueueIndex[i] = i;
}
// Construct the set of exposed track groups.
TrackGroup[] trackGroups = new TrackGroup[extractorTrackCount];
for (int i = 0; i < extractorTrackCount; i++) {
Format sampleFormat = Assertions.checkStateNotNull(sampleQueues[i].getUpstreamFormat());
if (i == primaryExtractorTrackIndex) {
Format[] formats = new Format[chunkSourceTrackCount];
for (int j = 0; j < chunkSourceTrackCount; j++) {
Format playlistFormat = chunkSourceTrackGroup.getFormat(j);
if (primaryExtractorTrackType == C.TRACK_TYPE_AUDIO && muxedAudioFormat != null) {
playlistFormat = playlistFormat.withManifestFormatInfo(muxedAudioFormat);
}
// If there's only a single variant (chunkSourceTrackCount == 1) then we can safely
// retain all fields from sampleFormat. Else we need to use deriveFormat to retain only
// the fields that will be the same for all variants.
formats[j] = chunkSourceTrackCount == 1 ? sampleFormat.withManifestFormatInfo(playlistFormat) : deriveFormat(playlistFormat, sampleFormat, /* propagateBitrates= */
true);
}
trackGroups[i] = new TrackGroup(uid, formats);
primaryTrackGroupIndex = i;
} else {
@Nullable Format playlistFormat = primaryExtractorTrackType == C.TRACK_TYPE_VIDEO && MimeTypes.isAudio(sampleFormat.sampleMimeType) ? muxedAudioFormat : null;
String muxedTrackGroupId = uid + ":muxed:" + (i < primaryExtractorTrackIndex ? i : i - 1);
trackGroups[i] = new TrackGroup(muxedTrackGroupId, deriveFormat(playlistFormat, sampleFormat, /* propagateBitrates= */
false));
}
}
this.trackGroups = createTrackGroupArrayWithDrmInfo(trackGroups);
Assertions.checkState(optionalTrackGroups == null);
optionalTrackGroups = Collections.emptySet();
}
use of com.google.android.exoplayer2.source.hls.playlist.HlsMultivariantPlaylist.Variant in project ExoPlayer by google.
the class HlsMediaPeriod method buildAndPrepareMainSampleStreamWrapper.
/**
* This method creates and starts preparation of the main {@link HlsSampleStreamWrapper}.
*
* <p>The main sample stream wrapper is the first element of {@link #sampleStreamWrappers}. It
* provides {@link SampleStream}s for the variant urls in the multivariant playlist. It may be
* adaptive and may contain multiple muxed tracks.
*
* <p>If chunkless preparation is allowed, the media period will try preparation without segment
* downloads. This is only possible if variants contain the CODECS attribute. If not, traditional
* preparation with segment downloads will take place. The following points apply to chunkless
* preparation:
*
* <ul>
* <li>A muxed audio track will be exposed if the codecs list contain an audio entry and the
* multivariant playlist either contains an EXT-X-MEDIA tag without the URI attribute or
* does not contain any EXT-X-MEDIA tag.
* <li>Closed captions will only be exposed if they are declared by the multivariant playlist.
* <li>An ID3 track is exposed preemptively, in case the segments contain an ID3 track.
* </ul>
*
* @param multivariantPlaylist The HLS multivariant playlist.
* @param positionUs If preparation requires any chunk downloads, the position in microseconds at
* which downloading should start. Ignored otherwise.
* @param sampleStreamWrappers List to which the built main sample stream wrapper should be added.
* @param manifestUrlIndicesPerWrapper List to which the selected variant indices should be added.
* @param overridingDrmInitData Overriding {@link DrmInitData}, keyed by protection scheme type
* (i.e. {@link DrmInitData#schemeType}).
*/
private void buildAndPrepareMainSampleStreamWrapper(HlsMultivariantPlaylist multivariantPlaylist, long positionUs, List<HlsSampleStreamWrapper> sampleStreamWrappers, List<int[]> manifestUrlIndicesPerWrapper, Map<String, DrmInitData> overridingDrmInitData) {
int[] variantTypes = new int[multivariantPlaylist.variants.size()];
int videoVariantCount = 0;
int audioVariantCount = 0;
for (int i = 0; i < multivariantPlaylist.variants.size(); i++) {
Variant variant = multivariantPlaylist.variants.get(i);
Format format = variant.format;
if (format.height > 0 || Util.getCodecsOfType(format.codecs, C.TRACK_TYPE_VIDEO) != null) {
variantTypes[i] = C.TRACK_TYPE_VIDEO;
videoVariantCount++;
} else if (Util.getCodecsOfType(format.codecs, C.TRACK_TYPE_AUDIO) != null) {
variantTypes[i] = C.TRACK_TYPE_AUDIO;
audioVariantCount++;
} else {
variantTypes[i] = C.TRACK_TYPE_UNKNOWN;
}
}
boolean useVideoVariantsOnly = false;
boolean useNonAudioVariantsOnly = false;
int selectedVariantsCount = variantTypes.length;
if (videoVariantCount > 0) {
// We've identified some variants as definitely containing video. Assume variants within the
// multivariant playlist are marked consistently, and hence that we have the full set. Filter
// out any other variants, which are likely to be audio only.
useVideoVariantsOnly = true;
selectedVariantsCount = videoVariantCount;
} else if (audioVariantCount < variantTypes.length) {
// We've identified some variants, but not all, as being audio only. Filter them out to leave
// the remaining variants, which are likely to contain video.
useNonAudioVariantsOnly = true;
selectedVariantsCount = variantTypes.length - audioVariantCount;
}
Uri[] selectedPlaylistUrls = new Uri[selectedVariantsCount];
Format[] selectedPlaylistFormats = new Format[selectedVariantsCount];
int[] selectedVariantIndices = new int[selectedVariantsCount];
int outIndex = 0;
for (int i = 0; i < multivariantPlaylist.variants.size(); i++) {
if ((!useVideoVariantsOnly || variantTypes[i] == C.TRACK_TYPE_VIDEO) && (!useNonAudioVariantsOnly || variantTypes[i] != C.TRACK_TYPE_AUDIO)) {
Variant variant = multivariantPlaylist.variants.get(i);
selectedPlaylistUrls[outIndex] = variant.url;
selectedPlaylistFormats[outIndex] = variant.format;
selectedVariantIndices[outIndex++] = i;
}
}
String codecs = selectedPlaylistFormats[0].codecs;
int numberOfVideoCodecs = Util.getCodecCountOfType(codecs, C.TRACK_TYPE_VIDEO);
int numberOfAudioCodecs = Util.getCodecCountOfType(codecs, C.TRACK_TYPE_AUDIO);
boolean codecsStringAllowsChunklessPreparation = numberOfAudioCodecs <= 1 && numberOfVideoCodecs <= 1 && numberOfAudioCodecs + numberOfVideoCodecs > 0;
@C.TrackType int trackType = !useVideoVariantsOnly && numberOfAudioCodecs > 0 ? C.TRACK_TYPE_AUDIO : C.TRACK_TYPE_DEFAULT;
String sampleStreamWrapperUid = "main";
HlsSampleStreamWrapper sampleStreamWrapper = buildSampleStreamWrapper(sampleStreamWrapperUid, trackType, selectedPlaylistUrls, selectedPlaylistFormats, multivariantPlaylist.muxedAudioFormat, multivariantPlaylist.muxedCaptionFormats, overridingDrmInitData, positionUs);
sampleStreamWrappers.add(sampleStreamWrapper);
manifestUrlIndicesPerWrapper.add(selectedVariantIndices);
if (allowChunklessPreparation && codecsStringAllowsChunklessPreparation) {
List<TrackGroup> muxedTrackGroups = new ArrayList<>();
if (numberOfVideoCodecs > 0) {
Format[] videoFormats = new Format[selectedVariantsCount];
for (int i = 0; i < videoFormats.length; i++) {
videoFormats[i] = deriveVideoFormat(selectedPlaylistFormats[i]);
}
muxedTrackGroups.add(new TrackGroup(sampleStreamWrapperUid, videoFormats));
if (numberOfAudioCodecs > 0 && (multivariantPlaylist.muxedAudioFormat != null || multivariantPlaylist.audios.isEmpty())) {
muxedTrackGroups.add(new TrackGroup(/* id= */
sampleStreamWrapperUid + ":audio", deriveAudioFormat(selectedPlaylistFormats[0], multivariantPlaylist.muxedAudioFormat, /* isPrimaryTrackInVariant= */
false)));
}
List<Format> ccFormats = multivariantPlaylist.muxedCaptionFormats;
if (ccFormats != null) {
for (int i = 0; i < ccFormats.size(); i++) {
String ccId = sampleStreamWrapperUid + ":cc:" + i;
muxedTrackGroups.add(new TrackGroup(ccId, ccFormats.get(i)));
}
}
} else /* numberOfAudioCodecs > 0 */
{
// Variants only contain audio.
Format[] audioFormats = new Format[selectedVariantsCount];
for (int i = 0; i < audioFormats.length; i++) {
audioFormats[i] = deriveAudioFormat(/* variantFormat= */
selectedPlaylistFormats[i], multivariantPlaylist.muxedAudioFormat, /* isPrimaryTrackInVariant= */
true);
}
muxedTrackGroups.add(new TrackGroup(sampleStreamWrapperUid, audioFormats));
}
TrackGroup id3TrackGroup = new TrackGroup(/* id= */
sampleStreamWrapperUid + ":id3", new Format.Builder().setId("ID3").setSampleMimeType(MimeTypes.APPLICATION_ID3).build());
muxedTrackGroups.add(id3TrackGroup);
sampleStreamWrapper.prepareWithMultivariantPlaylistInfo(muxedTrackGroups.toArray(new TrackGroup[0]), /* primaryTrackGroupIndex= */
0, /* optionalTrackGroupsIndices...= */
muxedTrackGroups.indexOf(id3TrackGroup));
}
}
use of com.google.android.exoplayer2.source.hls.playlist.HlsMultivariantPlaylist.Variant in project ExoPlayer by google.
the class HlsMediaPeriod method selectTracks.
@Override
public long selectTracks(@NullableType ExoTrackSelection[] selections, boolean[] mayRetainStreamFlags, @NullableType SampleStream[] streams, boolean[] streamResetFlags, long positionUs) {
// Map each selection and stream onto a child period index.
int[] streamChildIndices = new int[selections.length];
int[] selectionChildIndices = new int[selections.length];
for (int i = 0; i < selections.length; i++) {
streamChildIndices[i] = streams[i] == null ? C.INDEX_UNSET : streamWrapperIndices.get(streams[i]);
selectionChildIndices[i] = C.INDEX_UNSET;
if (selections[i] != null) {
TrackGroup trackGroup = selections[i].getTrackGroup();
for (int j = 0; j < sampleStreamWrappers.length; j++) {
if (sampleStreamWrappers[j].getTrackGroups().indexOf(trackGroup) != C.INDEX_UNSET) {
selectionChildIndices[i] = j;
break;
}
}
}
}
boolean forceReset = false;
streamWrapperIndices.clear();
// Select tracks for each child, copying the resulting streams back into a new streams array.
SampleStream[] newStreams = new SampleStream[selections.length];
@NullableType SampleStream[] childStreams = new SampleStream[selections.length];
@NullableType ExoTrackSelection[] childSelections = new ExoTrackSelection[selections.length];
int newEnabledSampleStreamWrapperCount = 0;
HlsSampleStreamWrapper[] newEnabledSampleStreamWrappers = new HlsSampleStreamWrapper[sampleStreamWrappers.length];
for (int i = 0; i < sampleStreamWrappers.length; i++) {
for (int j = 0; j < selections.length; j++) {
childStreams[j] = streamChildIndices[j] == i ? streams[j] : null;
childSelections[j] = selectionChildIndices[j] == i ? selections[j] : null;
}
HlsSampleStreamWrapper sampleStreamWrapper = sampleStreamWrappers[i];
boolean wasReset = sampleStreamWrapper.selectTracks(childSelections, mayRetainStreamFlags, childStreams, streamResetFlags, positionUs, forceReset);
boolean wrapperEnabled = false;
for (int j = 0; j < selections.length; j++) {
SampleStream childStream = childStreams[j];
if (selectionChildIndices[j] == i) {
// Assert that the child provided a stream for the selection.
Assertions.checkNotNull(childStream);
newStreams[j] = childStream;
wrapperEnabled = true;
streamWrapperIndices.put(childStream, i);
} else if (streamChildIndices[j] == i) {
// Assert that the child cleared any previous stream.
Assertions.checkState(childStream == null);
}
}
if (wrapperEnabled) {
newEnabledSampleStreamWrappers[newEnabledSampleStreamWrapperCount] = sampleStreamWrapper;
if (newEnabledSampleStreamWrapperCount++ == 0) {
// The first enabled wrapper is always allowed to initialize timestamp adjusters. Note
// that the first wrapper will correspond to a variant, or else an audio rendition, or
// else a text rendition, in that order.
sampleStreamWrapper.setIsTimestampMaster(true);
if (wasReset || enabledSampleStreamWrappers.length == 0 || sampleStreamWrapper != enabledSampleStreamWrappers[0]) {
// The wrapper responsible for initializing the timestamp adjusters was reset or
// changed. We need to reset the timestamp adjuster provider and all other wrappers.
timestampAdjusterProvider.reset();
forceReset = true;
}
} else {
// Additional wrappers are also allowed to initialize timestamp adjusters if they contain
// audio or video, since they are expected to contain dense samples. Text wrappers are not
// permitted except in the case above in which no variant or audio rendition wrappers are
// enabled.
sampleStreamWrapper.setIsTimestampMaster(i < audioVideoSampleStreamWrapperCount);
}
}
}
// Copy the new streams back into the streams array.
System.arraycopy(newStreams, 0, streams, 0, newStreams.length);
// Update the local state.
enabledSampleStreamWrappers = Util.nullSafeArrayCopy(newEnabledSampleStreamWrappers, newEnabledSampleStreamWrapperCount);
compositeSequenceableLoader = compositeSequenceableLoaderFactory.createCompositeSequenceableLoader(enabledSampleStreamWrappers);
return positionUs;
}
Aggregations