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:
parent
73ed482094
commit
f1a5825d73
@ -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());
|
||||
|
@ -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) {
|
||||
|
@ -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());
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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 =
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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")
|
||||
|
@ -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,
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user