Add optional id to TrackGroup.

This allows to give TrackGroups an identifier. The underlying goal is
to provide a way to make otherwise identical TrackGroups
distinguishable.

Also set this id in all internal sources that may produce identical
TrackGroups in certain edge cases.

Issue: google/ExoPlayer#9718
PiperOrigin-RevId: 413430719
This commit is contained in:
tonihei 2021-12-01 17:05:25 +00:00
parent 73ed482094
commit f1a5825d73
12 changed files with 254 additions and 32 deletions

View File

@ -1060,7 +1060,8 @@ public final class CastPlayer extends BasePlayer {
new TracksInfo.TrackGroupInfo[castMediaTracks.size()];
for (int i = 0; i < castMediaTracks.size(); i++) {
MediaTrack mediaTrack = castMediaTracks.get(i);
trackGroups[i] = new TrackGroup(CastUtils.mediaTrackToFormat(mediaTrack));
trackGroups[i] =
new TrackGroup(/* id= */ Integer.toString(i), CastUtils.mediaTrackToFormat(mediaTrack));
long id = mediaTrack.getId();
@C.TrackType int trackType = MimeTypes.getTrackType(mediaTrack.getContentType());

View File

@ -18,6 +18,7 @@ package androidx.media3.common;
import static androidx.media3.common.util.Assertions.checkArgument;
import android.os.Bundle;
import androidx.annotation.CheckResult;
import androidx.annotation.IntDef;
import androidx.annotation.Nullable;
import androidx.media3.common.util.BundleableUtil;
@ -38,6 +39,8 @@ public final class TrackGroup implements Bundleable {
/** The number of tracks in the group. */
public final int length;
/** An identifier for the track group. */
public final String id;
private final Format[] formats;
@ -45,18 +48,42 @@ public final class TrackGroup implements Bundleable {
private int hashCode;
/**
* Constructs an instance {@code TrackGroup} containing the provided {@code formats}.
* Constructs a track group containing the provided {@code formats}.
*
* @param formats Non empty array of format.
* @param formats The list of {@link Format Formats}. Must not be empty.
*/
@UnstableApi
public TrackGroup(Format... formats) {
this(/* id= */ "", formats);
}
/**
* Constructs a track group with the provided {@code id} and {@code formats}.
*
* @param id The identifier of the track group. May be an empty string.
* @param formats The list of {@link Format Formats}. Must not be empty.
*/
@UnstableApi
public TrackGroup(String id, Format... formats) {
checkArgument(formats.length > 0);
this.id = id;
this.formats = formats;
this.length = formats.length;
verifyCorrectness();
}
/**
* Returns a copy of this track group with the specified {@code id}.
*
* @param id The identifier for the copy of the track group.
* @return The copied track group.
*/
@UnstableApi
@CheckResult
public TrackGroup copyWithId(String id) {
return new TrackGroup(id, formats);
}
/**
* Returns the format of the track at a given index.
*
@ -89,6 +116,7 @@ public final class TrackGroup implements Bundleable {
public int hashCode() {
if (hashCode == 0) {
int result = 17;
result = 31 * result + id.hashCode();
result = 31 * result + Arrays.hashCode(formats);
hashCode = result;
}
@ -104,19 +132,18 @@ public final class TrackGroup implements Bundleable {
return false;
}
TrackGroup other = (TrackGroup) obj;
return length == other.length && Arrays.equals(formats, other.formats);
return length == other.length && id.equals(other.id) && Arrays.equals(formats, other.formats);
}
// Bundleable implementation.
@Documented
@Retention(RetentionPolicy.SOURCE)
@IntDef({
FIELD_FORMATS,
})
@IntDef({FIELD_FORMATS, FIELD_ID})
private @interface FieldNumber {}
private static final int FIELD_FORMATS = 0;
private static final int FIELD_ID = 1;
@UnstableApi
@Override
@ -124,6 +151,7 @@ public final class TrackGroup implements Bundleable {
Bundle bundle = new Bundle();
bundle.putParcelableArrayList(
keyForField(FIELD_FORMATS), BundleableUtil.toBundleArrayList(Lists.newArrayList(formats)));
bundle.putString(keyForField(FIELD_ID), id);
return bundle;
}
@ -136,7 +164,8 @@ public final class TrackGroup implements Bundleable {
Format.CREATOR,
bundle.getParcelableArrayList(keyForField(FIELD_FORMATS)),
ImmutableList.of());
return new TrackGroup(formats.toArray(new Format[0]));
String id = bundle.getString(keyForField(FIELD_ID), /* defaultValue= */ "");
return new TrackGroup(id, formats.toArray(new Format[0]));
};
private static String keyForField(@FieldNumber int field) {

View File

@ -30,8 +30,9 @@ public final class TrackGroupTest {
Format.Builder formatBuilder = new Format.Builder();
Format format1 = formatBuilder.setSampleMimeType(MimeTypes.VIDEO_H264).build();
Format format2 = formatBuilder.setSampleMimeType(MimeTypes.AUDIO_AAC).build();
String id = "abc";
TrackGroup trackGroupToBundle = new TrackGroup(format1, format2);
TrackGroup trackGroupToBundle = new TrackGroup(id, format1, format2);
TrackGroup trackGroupFromBundle = TrackGroup.CREATOR.fromBundle(trackGroupToBundle.toBundle());

View File

@ -15,10 +15,12 @@
*/
package androidx.media3.exoplayer.source;
import static androidx.media3.common.util.Assertions.checkNotNull;
import static java.lang.Math.max;
import androidx.annotation.Nullable;
import androidx.media3.common.C;
import androidx.media3.common.Format;
import androidx.media3.common.StreamKey;
import androidx.media3.common.TrackGroup;
import androidx.media3.common.TrackGroupArray;
@ -26,10 +28,14 @@ import androidx.media3.common.util.Assertions;
import androidx.media3.decoder.DecoderInputBuffer;
import androidx.media3.exoplayer.FormatHolder;
import androidx.media3.exoplayer.SeekParameters;
import androidx.media3.exoplayer.source.chunk.Chunk;
import androidx.media3.exoplayer.source.chunk.MediaChunk;
import androidx.media3.exoplayer.source.chunk.MediaChunkIterator;
import androidx.media3.exoplayer.trackselection.ExoTrackSelection;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.IdentityHashMap;
import java.util.List;
import org.checkerframework.checker.nullness.compatqual.NullableType;
@ -42,6 +48,7 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
private final IdentityHashMap<SampleStream, Integer> streamPeriodIndices;
private final CompositeSequenceableLoaderFactory compositeSequenceableLoaderFactory;
private final ArrayList<MediaPeriod> childrenPendingPreparation;
private final HashMap<TrackGroup, TrackGroup> childTrackGroupByMergedTrackGroup;
@Nullable private Callback callback;
@Nullable private TrackGroupArray trackGroups;
@ -55,6 +62,7 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
this.compositeSequenceableLoaderFactory = compositeSequenceableLoaderFactory;
this.periods = periods;
childrenPendingPreparation = new ArrayList<>();
childTrackGroupByMergedTrackGroup = new HashMap<>();
compositeSequenceableLoader =
compositeSequenceableLoaderFactory.createCompositeSequenceableLoader();
streamPeriodIndices = new IdentityHashMap<>();
@ -113,9 +121,11 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
streamChildIndices[i] = streamChildIndex == null ? C.INDEX_UNSET : streamChildIndex;
selectionChildIndices[i] = C.INDEX_UNSET;
if (selections[i] != null) {
TrackGroup trackGroup = selections[i].getTrackGroup();
TrackGroup mergedTrackGroup = selections[i].getTrackGroup();
TrackGroup childTrackGroup =
checkNotNull(childTrackGroupByMergedTrackGroup.get(mergedTrackGroup));
for (int j = 0; j < periods.length; j++) {
if (periods[j].getTrackGroups().indexOf(trackGroup) != C.INDEX_UNSET) {
if (periods[j].getTrackGroups().indexOf(childTrackGroup) != C.INDEX_UNSET) {
selectionChildIndices[i] = j;
break;
}
@ -131,7 +141,15 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
for (int i = 0; i < periods.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;
if (selectionChildIndices[j] == i) {
ExoTrackSelection mergedTrackSelection = checkNotNull(selections[j]);
TrackGroup mergedTrackGroup = mergedTrackSelection.getTrackGroup();
TrackGroup childTrackGroup =
checkNotNull(childTrackGroupByMergedTrackGroup.get(mergedTrackGroup));
childSelections[j] = new ForwardingTrackSelection(mergedTrackSelection, childTrackGroup);
} else {
childSelections[j] = null;
}
}
long selectPositionUs =
periods[i].selectTracks(
@ -270,11 +288,14 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
}
TrackGroup[] trackGroupArray = new TrackGroup[totalTrackGroupCount];
int trackGroupIndex = 0;
for (MediaPeriod period : periods) {
TrackGroupArray periodTrackGroups = period.getTrackGroups();
for (int i = 0; i < periods.length; i++) {
TrackGroupArray periodTrackGroups = periods[i].getTrackGroups();
int periodTrackGroupCount = periodTrackGroups.length;
for (int j = 0; j < periodTrackGroupCount; j++) {
trackGroupArray[trackGroupIndex++] = periodTrackGroups.get(j);
TrackGroup childTrackGroup = periodTrackGroups.get(j);
TrackGroup mergedTrackGroup = childTrackGroup.copyWithId(i + ":" + childTrackGroup.id);
childTrackGroupByMergedTrackGroup.put(mergedTrackGroup, childTrackGroup);
trackGroupArray[trackGroupIndex++] = mergedTrackGroup;
}
}
trackGroups = new TrackGroupArray(trackGroupArray);
@ -455,4 +476,138 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
return sampleStream.skipData(positionUs - timeOffsetUs);
}
}
private static final class ForwardingTrackSelection implements ExoTrackSelection {
private final ExoTrackSelection trackSelection;
private final TrackGroup trackGroup;
public ForwardingTrackSelection(ExoTrackSelection trackSelection, TrackGroup trackGroup) {
this.trackSelection = trackSelection;
this.trackGroup = trackGroup;
}
@Override
public @Type int getType() {
return trackSelection.getType();
}
@Override
public TrackGroup getTrackGroup() {
return trackGroup;
}
@Override
public int length() {
return trackSelection.length();
}
@Override
public Format getFormat(int index) {
return trackSelection.getFormat(index);
}
@Override
public int getIndexInTrackGroup(int index) {
return trackSelection.getIndexInTrackGroup(index);
}
@Override
public int indexOf(Format format) {
return trackSelection.indexOf(format);
}
@Override
public int indexOf(int indexInTrackGroup) {
return trackSelection.indexOf(indexInTrackGroup);
}
@Override
public void enable() {
trackSelection.enable();
}
@Override
public void disable() {
trackSelection.disable();
}
@Override
public Format getSelectedFormat() {
return trackSelection.getSelectedFormat();
}
@Override
public int getSelectedIndexInTrackGroup() {
return trackSelection.getSelectedIndexInTrackGroup();
}
@Override
public int getSelectedIndex() {
return trackSelection.getSelectedIndex();
}
@Override
public int getSelectionReason() {
return trackSelection.getSelectionReason();
}
@Nullable
@Override
public Object getSelectionData() {
return trackSelection.getSelectionData();
}
@Override
public void onPlaybackSpeed(float playbackSpeed) {
trackSelection.onPlaybackSpeed(playbackSpeed);
}
@Override
public void onDiscontinuity() {
trackSelection.onDiscontinuity();
}
@Override
public void onRebuffer() {
trackSelection.onRebuffer();
}
@Override
public void onPlayWhenReadyChanged(boolean playWhenReady) {
trackSelection.onPlayWhenReadyChanged(playWhenReady);
}
@Override
public void updateSelectedTrack(
long playbackPositionUs,
long bufferedDurationUs,
long availableDurationUs,
List<? extends MediaChunk> queue,
MediaChunkIterator[] mediaChunkIterators) {
trackSelection.updateSelectedTrack(
playbackPositionUs, bufferedDurationUs, availableDurationUs, queue, mediaChunkIterators);
}
@Override
public int evaluateQueueSize(long playbackPositionUs, List<? extends MediaChunk> queue) {
return trackSelection.evaluateQueueSize(playbackPositionUs, queue);
}
@Override
public boolean shouldCancelChunkLoad(
long playbackPositionUs, Chunk loadingChunk, List<? extends MediaChunk> queue) {
return trackSelection.shouldCancelChunkLoad(playbackPositionUs, loadingChunk, queue);
}
@Override
public boolean blacklist(int index, long exclusionDurationMs) {
return trackSelection.blacklist(index, exclusionDurationMs);
}
@Override
public boolean isBlacklisted(int index, long nowMs) {
return trackSelection.isBlacklisted(index, nowMs);
}
}
}

View File

@ -783,7 +783,7 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
}
}
trackFormat = trackFormat.copyWithCryptoType(drmSessionManager.getCryptoType(trackFormat));
trackArray[i] = new TrackGroup(trackFormat);
trackArray[i] = new TrackGroup(/* id= */ Integer.toString(i), trackFormat);
}
trackState = new TrackState(new TrackGroupArray(trackArray), trackIsAudioVideoFlags);
prepared = true;

View File

@ -277,7 +277,7 @@ public class EventLogger implements AnalyticsListener {
trackGroup.length,
mappedTrackInfo.getAdaptiveSupport(
rendererIndex, groupIndex, /* includeCapabilitiesExceededTracks= */ false));
logd(" Group:" + groupIndex + ", adaptive_supported=" + adaptiveSupport + " [");
logd(" Group:" + trackGroup.id + ", adaptive_supported=" + adaptiveSupport + " [");
for (int trackIndex = 0; trackIndex < trackGroup.length; trackIndex++) {
String status = getTrackStatusString(trackSelection, trackGroup, trackIndex);
String formatSupport =

View File

@ -675,13 +675,17 @@ import org.checkerframework.checker.nullness.compatqual.NullableType;
}
AdaptationSet firstAdaptationSet = adaptationSets.get(adaptationSetIndices[0]);
String trackGroupId =
firstAdaptationSet.id != AdaptationSet.ID_UNSET
? Integer.toString(firstAdaptationSet.id)
: ("unset:" + i);
int primaryTrackGroupIndex = trackGroupCount++;
int eventMessageTrackGroupIndex =
primaryGroupHasEventMessageTrackFlags[i] ? trackGroupCount++ : C.INDEX_UNSET;
int closedCaptionTrackGroupIndex =
primaryGroupClosedCaptionTrackFormats[i].length != 0 ? trackGroupCount++ : C.INDEX_UNSET;
trackGroups[primaryTrackGroupIndex] = new TrackGroup(formats);
trackGroups[primaryTrackGroupIndex] = new TrackGroup(trackGroupId, formats);
trackGroupInfos[primaryTrackGroupIndex] =
TrackGroupInfo.primaryTrack(
firstAdaptationSet.type,
@ -690,18 +694,20 @@ import org.checkerframework.checker.nullness.compatqual.NullableType;
eventMessageTrackGroupIndex,
closedCaptionTrackGroupIndex);
if (eventMessageTrackGroupIndex != C.INDEX_UNSET) {
String eventMessageTrackGroupId = trackGroupId + ":emsg";
Format format =
new Format.Builder()
.setId(firstAdaptationSet.id + ":emsg")
.setId(eventMessageTrackGroupId)
.setSampleMimeType(MimeTypes.APPLICATION_EMSG)
.build();
trackGroups[eventMessageTrackGroupIndex] = new TrackGroup(format);
trackGroups[eventMessageTrackGroupIndex] = new TrackGroup(eventMessageTrackGroupId, format);
trackGroupInfos[eventMessageTrackGroupIndex] =
TrackGroupInfo.embeddedEmsgTrack(adaptationSetIndices, primaryTrackGroupIndex);
}
if (closedCaptionTrackGroupIndex != C.INDEX_UNSET) {
String closedCaptionTrackGroupId = trackGroupId + ":cc";
trackGroups[closedCaptionTrackGroupIndex] =
new TrackGroup(primaryGroupClosedCaptionTrackFormats[i]);
new TrackGroup(closedCaptionTrackGroupId, primaryGroupClosedCaptionTrackFormats[i]);
trackGroupInfos[closedCaptionTrackGroupIndex] =
TrackGroupInfo.embeddedClosedCaptionTrack(adaptationSetIndices, primaryTrackGroupIndex);
}
@ -721,7 +727,8 @@ import org.checkerframework.checker.nullness.compatqual.NullableType;
.setId(eventStream.id())
.setSampleMimeType(MimeTypes.APPLICATION_EMSG)
.build();
trackGroups[existingTrackGroupCount] = new TrackGroup(format);
String uniqueTrackGroupId = eventStream.id() + ":" + i;
trackGroups[existingTrackGroupCount] = new TrackGroup(uniqueTrackGroupId, format);
trackGroupInfos[existingTrackGroupCount++] = TrackGroupInfo.mpdEventTrack(i);
}
}

View File

@ -80,12 +80,13 @@ public final class DashMediaPeriodTest {
TrackGroupArray expectedTrackGroups =
new TrackGroupArray(
new TrackGroup(
/* id= */ "0",
adaptationSets.get(0).representations.get(0).format,
adaptationSets.get(0).representations.get(1).format,
adaptationSets.get(2).representations.get(0).format,
adaptationSets.get(2).representations.get(1).format,
adaptationSets.get(3).representations.get(0).format),
new TrackGroup(adaptationSets.get(1).representations.get(0).format));
new TrackGroup(/* id= */ "3", adaptationSets.get(1).representations.get(0).format));
MediaPeriodAsserts.assertTrackGroups(dashMediaPeriod, expectedTrackGroups);
}
@ -101,10 +102,12 @@ public final class DashMediaPeriodTest {
TrackGroupArray expectedTrackGroups =
new TrackGroupArray(
new TrackGroup(
/* id= */ "0",
adaptationSets.get(0).representations.get(0).format,
adaptationSets.get(0).representations.get(1).format,
adaptationSets.get(1).representations.get(0).format),
new TrackGroup(
/* id= */ "2",
adaptationSets.get(2).representations.get(0).format,
adaptationSets.get(2).representations.get(1).format,
adaptationSets.get(3).representations.get(0).format));
@ -124,6 +127,7 @@ public final class DashMediaPeriodTest {
TrackGroupArray expectedTrackGroups =
new TrackGroupArray(
new TrackGroup(
/* id= */ "0",
adaptationSets.get(0).representations.get(0).format,
adaptationSets.get(0).representations.get(1).format,
adaptationSets.get(1).representations.get(0).format,
@ -147,9 +151,11 @@ public final class DashMediaPeriodTest {
TrackGroupArray expectedTrackGroups =
new TrackGroupArray(
new TrackGroup(
/* id= */ "123",
adaptationSets.get(0).representations.get(0).format,
adaptationSets.get(0).representations.get(1).format),
new TrackGroup(
/* id= */ "123:cc",
cea608FormatBuilder
.setId("123:cea608:1")
.setLanguage("eng")
@ -177,9 +183,11 @@ public final class DashMediaPeriodTest {
TrackGroupArray expectedTrackGroups =
new TrackGroupArray(
new TrackGroup(
/* id= */ "123",
adaptationSets.get(0).representations.get(0).format,
adaptationSets.get(0).representations.get(1).format),
new TrackGroup(
/* id= */ "123:cc",
cea608FormatBuilder
.setId("123:cea708:1")
.setLanguage("eng")

View File

@ -528,8 +528,10 @@ public final class HlsMediaPeriod
// Subtitle stream wrappers. We can always use master playlist information to prepare these.
for (int i = 0; i < subtitleRenditions.size(); i++) {
Rendition subtitleRendition = subtitleRenditions.get(i);
String sampleStreamWrapperUid = "subtitle:" + i + ":" + subtitleRendition.name;
HlsSampleStreamWrapper sampleStreamWrapper =
buildSampleStreamWrapper(
sampleStreamWrapperUid,
C.TRACK_TYPE_TEXT,
new Uri[] {subtitleRendition.url},
new Format[] {subtitleRendition.format},
@ -540,7 +542,7 @@ public final class HlsMediaPeriod
manifestUrlIndicesPerWrapper.add(new int[] {i});
sampleStreamWrappers.add(sampleStreamWrapper);
sampleStreamWrapper.prepareWithMasterPlaylistInfo(
new TrackGroup[] {new TrackGroup(subtitleRendition.format)},
new TrackGroup[] {new TrackGroup(sampleStreamWrapperUid, subtitleRendition.format)},
/* primaryTrackGroupIndex= */ 0);
}
@ -646,8 +648,10 @@ public final class HlsMediaPeriod
!useVideoVariantsOnly && numberOfAudioCodecs > 0
? C.TRACK_TYPE_AUDIO
: C.TRACK_TYPE_DEFAULT;
String sampleStreamWrapperUid = "main";
HlsSampleStreamWrapper sampleStreamWrapper =
buildSampleStreamWrapper(
sampleStreamWrapperUid,
trackType,
selectedPlaylistUrls,
selectedPlaylistFormats,
@ -664,12 +668,13 @@ public final class HlsMediaPeriod
for (int i = 0; i < videoFormats.length; i++) {
videoFormats[i] = deriveVideoFormat(selectedPlaylistFormats[i]);
}
muxedTrackGroups.add(new TrackGroup(videoFormats));
muxedTrackGroups.add(new TrackGroup(sampleStreamWrapperUid, videoFormats));
if (numberOfAudioCodecs > 0
&& (masterPlaylist.muxedAudioFormat != null || masterPlaylist.audios.isEmpty())) {
muxedTrackGroups.add(
new TrackGroup(
/* id= */ sampleStreamWrapperUid + ":audio",
deriveAudioFormat(
selectedPlaylistFormats[0],
masterPlaylist.muxedAudioFormat,
@ -678,7 +683,8 @@ public final class HlsMediaPeriod
List<Format> ccFormats = masterPlaylist.muxedCaptionFormats;
if (ccFormats != null) {
for (int i = 0; i < ccFormats.size(); i++) {
muxedTrackGroups.add(new TrackGroup(ccFormats.get(i)));
String ccId = sampleStreamWrapperUid + ":cc:" + i;
muxedTrackGroups.add(new TrackGroup(ccId, ccFormats.get(i)));
}
}
} else /* numberOfAudioCodecs > 0 */ {
@ -691,11 +697,12 @@ public final class HlsMediaPeriod
masterPlaylist.muxedAudioFormat,
/* isPrimaryTrackInVariant= */ true);
}
muxedTrackGroups.add(new TrackGroup(audioFormats));
muxedTrackGroups.add(new TrackGroup(sampleStreamWrapperUid, audioFormats));
}
TrackGroup id3TrackGroup =
new TrackGroup(
/* id= */ sampleStreamWrapperUid + ":id3",
new Format.Builder()
.setId("ID3")
.setSampleMimeType(MimeTypes.APPLICATION_ID3)
@ -747,8 +754,10 @@ public final class HlsMediaPeriod
}
}
String sampleStreamWrapperUid = "audio:" + name;
HlsSampleStreamWrapper sampleStreamWrapper =
buildSampleStreamWrapper(
sampleStreamWrapperUid,
C.TRACK_TYPE_AUDIO,
scratchPlaylistUrls.toArray(Util.castNonNullTypeArray(new Uri[0])),
scratchPlaylistFormats.toArray(new Format[0]),
@ -762,12 +771,14 @@ public final class HlsMediaPeriod
if (allowChunklessPreparation && codecStringsAllowChunklessPreparation) {
Format[] renditionFormats = scratchPlaylistFormats.toArray(new Format[0]);
sampleStreamWrapper.prepareWithMasterPlaylistInfo(
new TrackGroup[] {new TrackGroup(renditionFormats)}, /* primaryTrackGroupIndex= */ 0);
new TrackGroup[] {new TrackGroup(sampleStreamWrapperUid, renditionFormats)},
/* primaryTrackGroupIndex= */ 0);
}
}
}
private HlsSampleStreamWrapper buildSampleStreamWrapper(
String uid,
@C.TrackType int trackType,
Uri[] playlistUrls,
Format[] playlistFormats,
@ -787,6 +798,7 @@ public final class HlsMediaPeriod
muxedCaptionFormats,
playerId);
return new HlsSampleStreamWrapper(
uid,
trackType,
/* callback= */ this,
defaultChunkSource,

View File

@ -125,6 +125,7 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull;
new HashSet<>(
Arrays.asList(C.TRACK_TYPE_AUDIO, C.TRACK_TYPE_VIDEO, C.TRACK_TYPE_METADATA)));
private final String uid;
private final @C.TrackType int trackType;
private final Callback callback;
private final HlsChunkSource chunkSource;
@ -185,6 +186,8 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull;
@Nullable private HlsMediaChunk sourceChunk;
/**
* @param uid A identifier for this sample stream wrapper. Identifiers must be unique within the
* period.
* @param trackType The {@link C.TrackType track type}.
* @param callback A callback for the wrapper.
* @param chunkSource A {@link HlsChunkSource} from which chunks to load are obtained.
@ -203,6 +206,7 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull;
* events.
*/
public HlsSampleStreamWrapper(
String uid,
@C.TrackType int trackType,
Callback callback,
HlsChunkSource chunkSource,
@ -215,6 +219,7 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull;
LoadErrorHandlingPolicy loadErrorHandlingPolicy,
MediaSourceEventListener.EventDispatcher mediaSourceEventDispatcher,
@HlsMediaSource.MetadataType int metadataType) {
this.uid = uid;
this.trackType = trackType;
this.callback = callback;
this.chunkSource = chunkSource;
@ -1416,7 +1421,7 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull;
? sampleFormat.withManifestFormatInfo(playlistFormat)
: deriveFormat(playlistFormat, sampleFormat, /* propagateBitrates= */ true);
}
trackGroups[i] = new TrackGroup(formats);
trackGroups[i] = new TrackGroup(uid, formats);
primaryTrackGroupIndex = i;
} else {
@Nullable
@ -1425,8 +1430,10 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull;
&& 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));
}
}
@ -1443,7 +1450,7 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull;
Format format = trackGroup.getFormat(j);
exposedFormats[j] = format.copyWithCryptoType(drmSessionManager.getCryptoType(format));
}
trackGroups[i] = new TrackGroup(exposedFormats);
trackGroups[i] = new TrackGroup(trackGroup.id, exposedFormats);
}
return new TrackGroupArray(trackGroups);
}

View File

@ -402,7 +402,9 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
SampleQueue sampleQueue;
for (int i = 0; i < rtspLoaderWrappers.size(); i++) {
sampleQueue = rtspLoaderWrappers.get(i).sampleQueue;
listBuilder.add(new TrackGroup(checkNotNull(sampleQueue.getUpstreamFormat())));
listBuilder.add(
new TrackGroup(
/* id= */ Integer.toString(i), checkNotNull(sampleQueue.getUpstreamFormat())));
}
return listBuilder.build();
}

View File

@ -263,7 +263,7 @@ import org.checkerframework.checker.nullness.compatqual.NullableType;
exposedFormats[j] =
manifestFormat.copyWithCryptoType(drmSessionManager.getCryptoType(manifestFormat));
}
trackGroups[i] = new TrackGroup(exposedFormats);
trackGroups[i] = new TrackGroup(/* id= */ Integer.toString(i), exposedFormats);
}
return new TrackGroupArray(trackGroups);
}