Commit 92bf8e91 by tonihei Committed by Oliver Woodman

Change getStreamKeys to take a list of TrackSelections.

Converting a single track selection to stream keys is only possible if the output
is independent from other track selections being made.

This is not the case for DASH and HLS embedded track groups which should select the
already selected primary track if possible (and thus needs to know  whether a primary
track group is selected).

Also, update the test method to take a period index.

PiperOrigin-RevId: 231385490
parent f74e0eb9
...@@ -87,18 +87,18 @@ public interface MediaPeriod extends SequenceableLoader { ...@@ -87,18 +87,18 @@ public interface MediaPeriod extends SequenceableLoader {
TrackGroupArray getTrackGroups(); TrackGroupArray getTrackGroups();
/** /**
* Returns a list of {@link StreamKey stream keys} which allow to filter the media in this period * Returns a list of {@link StreamKey StreamKeys} which allow to filter the media in this period
* to load only the parts needed to play the provided {@link TrackSelection}. * to load only the parts needed to play the provided {@link TrackSelection TrackSelections}.
* *
* <p>This method is only called after the period has been prepared. * <p>This method is only called after the period has been prepared.
* *
* @param trackSelection The {@link TrackSelection} describing the tracks for which stream keys * @param trackSelections The {@link TrackSelection TrackSelections} describing the tracks for
* are requested. * which stream keys are requested.
* @return The corresponding {@link StreamKey stream keys} for the selected tracks, or an empty * @return The corresponding {@link StreamKey StreamKeys} for the selected tracks, or an empty
* list if filtering is not possible and the entire media needs to be loaded to play the * list if filtering is not possible and the entire media needs to be loaded to play the
* selected tracks. * selected tracks.
*/ */
default List<StreamKey> getStreamKeys(TrackSelection trackSelection) { default List<StreamKey> getStreamKeys(List<TrackSelection> trackSelections) {
return Collections.emptyList(); return Collections.emptyList();
} }
......
...@@ -144,12 +144,15 @@ import java.util.List; ...@@ -144,12 +144,15 @@ import java.util.List;
} }
@Override @Override
public List<StreamKey> getStreamKeys(TrackSelection trackSelection) { public List<StreamKey> getStreamKeys(List<TrackSelection> trackSelections) {
List<StreamKey> streamKeys = new ArrayList<>(trackSelection.length()); List<StreamKey> streamKeys = new ArrayList<>();
for (int selectionIndex = 0; selectionIndex < trackSelections.size(); selectionIndex++) {
TrackSelection trackSelection = trackSelections.get(selectionIndex);
int streamElementIndex = trackGroups.indexOf(trackSelection.getTrackGroup()); int streamElementIndex = trackGroups.indexOf(trackSelection.getTrackGroup());
for (int i = 0; i < trackSelection.length(); i++) { for (int i = 0; i < trackSelection.length(); i++) {
streamKeys.add(new StreamKey(streamElementIndex, trackSelection.getIndexInTrackGroup(i))); streamKeys.add(new StreamKey(streamElementIndex, trackSelection.getIndexInTrackGroup(i)));
} }
}
return streamKeys; return streamKeys;
} }
......
...@@ -61,7 +61,7 @@ public class SsMediaPeriodTest { ...@@ -61,7 +61,7 @@ public class SsMediaPeriodTest {
createStreamElement( createStreamElement(
/* name= */ "text", C.TRACK_TYPE_TEXT, createTextFormat(/* language= */ "eng"))); /* name= */ "text", C.TRACK_TYPE_TEXT, createTextFormat(/* language= */ "eng")));
FilterableManifestMediaPeriodFactory<SsManifest> mediaPeriodFactory = FilterableManifestMediaPeriodFactory<SsManifest> mediaPeriodFactory =
manifest -> (manifest, periodIndex) ->
new SsMediaPeriod( new SsMediaPeriod(
manifest, manifest,
mock(SsChunkSource.Factory.class), mock(SsChunkSource.Factory.class),
...@@ -77,7 +77,7 @@ public class SsMediaPeriodTest { ...@@ -77,7 +77,7 @@ public class SsMediaPeriodTest {
mock(Allocator.class)); mock(Allocator.class));
MediaPeriodAsserts.assertGetStreamKeysAndManifestFilterIntegration( MediaPeriodAsserts.assertGetStreamKeysAndManifestFilterIntegration(
mediaPeriodFactory, testManifest); mediaPeriodFactory, testManifest, /* periodIndex= */ 0);
} }
private static Format createVideoFormat(int bitrate) { private static Format createVideoFormat(int bitrate) {
......
...@@ -30,6 +30,8 @@ import com.google.android.exoplayer2.trackselection.BaseTrackSelection; ...@@ -30,6 +30,8 @@ import com.google.android.exoplayer2.trackselection.BaseTrackSelection;
import com.google.android.exoplayer2.trackselection.TrackSelection; import com.google.android.exoplayer2.trackselection.TrackSelection;
import com.google.android.exoplayer2.util.ConditionVariable; import com.google.android.exoplayer2.util.ConditionVariable;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet; import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.concurrent.atomic.AtomicReference; import java.util.concurrent.atomic.AtomicReference;
...@@ -45,53 +47,81 @@ public final class MediaPeriodAsserts { ...@@ -45,53 +47,81 @@ public final class MediaPeriodAsserts {
public interface FilterableManifestMediaPeriodFactory<T extends FilterableManifest<T>> { public interface FilterableManifestMediaPeriodFactory<T extends FilterableManifest<T>> {
/** Returns media period based on the provided filterable manifest. */ /** Returns media period based on the provided filterable manifest. */
MediaPeriod createMediaPeriod(T manifest); MediaPeriod createMediaPeriod(T manifest, int periodIndex);
} }
private MediaPeriodAsserts() {} private MediaPeriodAsserts() {}
/** /**
* Asserts that the values returns by {@link MediaPeriod#getStreamKeys(TrackSelection)} are * Asserts that the values returns by {@link MediaPeriod#getStreamKeys(List)} are compatible with
* compatible with a {@link FilterableManifest} using these stream keys. * a {@link FilterableManifest} using these stream keys.
* *
* @param mediaPeriodFactory A factory to create a {@link MediaPeriod} based on a manifest. * @param mediaPeriodFactory A factory to create a {@link MediaPeriod} based on a manifest.
* @param manifest The manifest which is to be tested. * @param manifest The manifest which is to be tested.
* @param periodIndex The index of period in the manifest.
*/ */
public static <T extends FilterableManifest<T>> public static <T extends FilterableManifest<T>>
void assertGetStreamKeysAndManifestFilterIntegration( void assertGetStreamKeysAndManifestFilterIntegration(
FilterableManifestMediaPeriodFactory<T> mediaPeriodFactory, T manifest) { FilterableManifestMediaPeriodFactory<T> mediaPeriodFactory, T manifest, int periodIndex) {
MediaPeriod mediaPeriod = mediaPeriodFactory.createMediaPeriod(manifest); MediaPeriod mediaPeriod = mediaPeriodFactory.createMediaPeriod(manifest, periodIndex);
TrackGroupArray trackGroupArray = getTrackGroups(mediaPeriod); TrackGroupArray trackGroupArray = getTrackGroups(mediaPeriod);
// Create test vector of query test selections:
// - One selection with one track per group, two tracks or all tracks.
// - Two selections with tracks from multiple groups, or tracks from a single group.
// - Multiple selections with tracks from all groups.
List<List<TrackSelection>> testSelections = new ArrayList<>();
for (int i = 0; i < trackGroupArray.length; i++) { for (int i = 0; i < trackGroupArray.length; i++) {
TrackGroup trackGroup = trackGroupArray.get(i); TrackGroup trackGroup = trackGroupArray.get(i);
// For each track group, create various test selections.
List<TrackSelection> testSelections = new ArrayList<>();
for (int j = 0; j < trackGroup.length; j++) { for (int j = 0; j < trackGroup.length; j++) {
testSelections.add(new TestTrackSelection(trackGroup, j)); testSelections.add(Collections.singletonList(new TestTrackSelection(trackGroup, j)));
} }
if (trackGroup.length > 1) { if (trackGroup.length > 1) {
testSelections.add(new TestTrackSelection(trackGroup, 0, 1)); testSelections.add(Collections.singletonList(new TestTrackSelection(trackGroup, 0, 1)));
testSelections.add(
Arrays.asList(
new TrackSelection[] {
new TestTrackSelection(trackGroup, 0), new TestTrackSelection(trackGroup, 1)
}));
} }
if (trackGroup.length > 2) { if (trackGroup.length > 2) {
int[] allTracks = new int[trackGroup.length]; int[] allTracks = new int[trackGroup.length];
for (int j = 0; j < trackGroup.length; j++) { for (int j = 0; j < trackGroup.length; j++) {
allTracks[j] = j; allTracks[j] = j;
} }
testSelections.add(new TestTrackSelection(trackGroup, allTracks)); testSelections.add(
Collections.singletonList(new TestTrackSelection(trackGroup, allTracks)));
}
}
if (trackGroupArray.length > 1) {
testSelections.add(
Arrays.asList(
new TrackSelection[] {
new TestTrackSelection(trackGroupArray.get(0), 0),
new TestTrackSelection(trackGroupArray.get(1), 0)
}));
}
if (trackGroupArray.length > 2) {
List<TrackSelection> selectionsFromAllGroups = new ArrayList<>();
for (int i = 0; i < trackGroupArray.length; i++) {
selectionsFromAllGroups.add(new TestTrackSelection(trackGroupArray.get(i), 0));
}
testSelections.add(selectionsFromAllGroups);
} }
// Get stream keys for each selection and check that the resulting filtered manifest includes // Verify for each case that stream keys can be used to create filtered tracks which still
// at least the same subset of tracks. // contain at least all requested formats.
for (TrackSelection testSelection : testSelections) { for (List<TrackSelection> testSelection : testSelections) {
List<StreamKey> streamKeys = mediaPeriod.getStreamKeys(testSelection); List<StreamKey> streamKeys = mediaPeriod.getStreamKeys(testSelection);
T filteredManifest = manifest.copy(streamKeys); T filteredManifest = manifest.copy(streamKeys);
MediaPeriod filteredMediaPeriod = mediaPeriodFactory.createMediaPeriod(filteredManifest); // The filtered manifest should only have one period left.
MediaPeriod filteredMediaPeriod =
mediaPeriodFactory.createMediaPeriod(filteredManifest, /* periodIndex= */ 0);
TrackGroupArray filteredTrackGroupArray = getTrackGroups(filteredMediaPeriod); TrackGroupArray filteredTrackGroupArray = getTrackGroups(filteredMediaPeriod);
Format[] expectedFormats = new Format[testSelection.length()]; for (TrackSelection trackSelection : testSelection) {
for (int k = 0; k < testSelection.length(); k++) { Format[] expectedFormats = new Format[trackSelection.length()];
expectedFormats[k] = testSelection.getFormat(k); for (int k = 0; k < trackSelection.length(); k++) {
expectedFormats[k] = trackSelection.getFormat(k);
} }
assertOneTrackGroupContainsFormats(filteredTrackGroupArray, expectedFormats); assertOneTrackGroupContainsFormats(filteredTrackGroupArray, expectedFormats);
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment