Added support for No-Sample Renderer.
Currently our Renderer is always associated with and consume data from some SampleStreams, which were constructed from the provided MediaSource. There are use-cases, in which the users want to have simple Renderer implementation that does not consume data from SampleStream at all, but render using their custom logic at each rendering position - they mostly just need ExoPlayer to keep track of the playback position and enable/disable the renderer. This CL adds support for such Renderer by adding a TRACK_TYPE_NONE. Renderer of such type will be: - Associated with null TrackSelection as the result of track-selection operation. - Associated with EmptySampleStream. GitHub: #3212 ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=168545749
This commit is contained in:
parent
5019da3e7b
commit
c9591d7617
@ -519,6 +519,10 @@ public final class C {
|
|||||||
* A type constant for metadata tracks.
|
* A type constant for metadata tracks.
|
||||||
*/
|
*/
|
||||||
public static final int TRACK_TYPE_METADATA = 4;
|
public static final int TRACK_TYPE_METADATA = 4;
|
||||||
|
/**
|
||||||
|
* A type constant for a dummy or empty track.
|
||||||
|
*/
|
||||||
|
public static final int TRACK_TYPE_NONE = 5;
|
||||||
/**
|
/**
|
||||||
* Applications or extensions may define custom {@code TRACK_TYPE_*} constants greater than or
|
* Applications or extensions may define custom {@code TRACK_TYPE_*} constants greater than or
|
||||||
* equal to this value.
|
* equal to this value.
|
||||||
|
@ -21,11 +21,13 @@ import android.os.Looper;
|
|||||||
import android.os.Message;
|
import android.os.Message;
|
||||||
import android.os.Process;
|
import android.os.Process;
|
||||||
import android.os.SystemClock;
|
import android.os.SystemClock;
|
||||||
|
import android.support.annotation.NonNull;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.util.Pair;
|
import android.util.Pair;
|
||||||
import com.google.android.exoplayer2.ExoPlayer.ExoPlayerMessage;
|
import com.google.android.exoplayer2.ExoPlayer.ExoPlayerMessage;
|
||||||
import com.google.android.exoplayer2.MediaPeriodInfoSequence.MediaPeriodInfo;
|
import com.google.android.exoplayer2.MediaPeriodInfoSequence.MediaPeriodInfo;
|
||||||
import com.google.android.exoplayer2.source.ClippingMediaPeriod;
|
import com.google.android.exoplayer2.source.ClippingMediaPeriod;
|
||||||
|
import com.google.android.exoplayer2.source.EmptySampleStream;
|
||||||
import com.google.android.exoplayer2.source.MediaPeriod;
|
import com.google.android.exoplayer2.source.MediaPeriod;
|
||||||
import com.google.android.exoplayer2.source.MediaSource;
|
import com.google.android.exoplayer2.source.MediaSource;
|
||||||
import com.google.android.exoplayer2.source.MediaSource.MediaPeriodId;
|
import com.google.android.exoplayer2.source.MediaSource.MediaPeriodId;
|
||||||
@ -1343,24 +1345,22 @@ import java.io.IOException;
|
|||||||
readingPeriodHolder.mediaPeriod.readDiscontinuity() != C.TIME_UNSET;
|
readingPeriodHolder.mediaPeriod.readDiscontinuity() != C.TIME_UNSET;
|
||||||
for (int i = 0; i < renderers.length; i++) {
|
for (int i = 0; i < renderers.length; i++) {
|
||||||
Renderer renderer = renderers[i];
|
Renderer renderer = renderers[i];
|
||||||
TrackSelection oldSelection = oldTrackSelectorResult.selections.get(i);
|
boolean rendererWasEnabled = oldTrackSelectorResult.renderersEnabled[i];
|
||||||
if (oldSelection == null) {
|
if (!rendererWasEnabled) {
|
||||||
// The renderer has no current stream and will be enabled when we play the next period.
|
// The renderer was disabled and will be enabled when we play the next period.
|
||||||
} else if (initialDiscontinuity) {
|
} else if (initialDiscontinuity) {
|
||||||
// The new period starts with a discontinuity, so the renderer will play out all data then
|
// The new period starts with a discontinuity, so the renderer will play out all data then
|
||||||
// be disabled and re-enabled when it starts playing the next period.
|
// be disabled and re-enabled when it starts playing the next period.
|
||||||
renderer.setCurrentStreamFinal();
|
renderer.setCurrentStreamFinal();
|
||||||
} else if (!renderer.isCurrentStreamFinal()) {
|
} else if (!renderer.isCurrentStreamFinal()) {
|
||||||
TrackSelection newSelection = newTrackSelectorResult.selections.get(i);
|
TrackSelection newSelection = newTrackSelectorResult.selections.get(i);
|
||||||
|
boolean newRendererEnabled = newTrackSelectorResult.renderersEnabled[i];
|
||||||
RendererConfiguration oldConfig = oldTrackSelectorResult.rendererConfigurations[i];
|
RendererConfiguration oldConfig = oldTrackSelectorResult.rendererConfigurations[i];
|
||||||
RendererConfiguration newConfig = newTrackSelectorResult.rendererConfigurations[i];
|
RendererConfiguration newConfig = newTrackSelectorResult.rendererConfigurations[i];
|
||||||
if (newSelection != null && newConfig.equals(oldConfig)) {
|
if (newRendererEnabled && newConfig.equals(oldConfig)) {
|
||||||
// Replace the renderer's SampleStream so the transition to playing the next period can
|
// Replace the renderer's SampleStream so the transition to playing the next period can
|
||||||
// be seamless.
|
// be seamless.
|
||||||
Format[] formats = new Format[newSelection.length()];
|
Format[] formats = getFormats(newSelection);
|
||||||
for (int j = 0; j < formats.length; j++) {
|
|
||||||
formats[j] = newSelection.getFormat(j);
|
|
||||||
}
|
|
||||||
renderer.replaceStream(formats, readingPeriodHolder.sampleStreams[i],
|
renderer.replaceStream(formats, readingPeriodHolder.sampleStreams[i],
|
||||||
readingPeriodHolder.getRendererOffset());
|
readingPeriodHolder.getRendererOffset());
|
||||||
} else {
|
} else {
|
||||||
@ -1461,11 +1461,10 @@ import java.io.IOException;
|
|||||||
for (int i = 0; i < renderers.length; i++) {
|
for (int i = 0; i < renderers.length; i++) {
|
||||||
Renderer renderer = renderers[i];
|
Renderer renderer = renderers[i];
|
||||||
rendererWasEnabledFlags[i] = renderer.getState() != Renderer.STATE_DISABLED;
|
rendererWasEnabledFlags[i] = renderer.getState() != Renderer.STATE_DISABLED;
|
||||||
TrackSelection newSelection = periodHolder.trackSelectorResult.selections.get(i);
|
if (periodHolder.trackSelectorResult.renderersEnabled[i]) {
|
||||||
if (newSelection != null) {
|
|
||||||
enabledRendererCount++;
|
enabledRendererCount++;
|
||||||
}
|
}
|
||||||
if (rendererWasEnabledFlags[i] && (newSelection == null
|
if (rendererWasEnabledFlags[i] && (!periodHolder.trackSelectorResult.renderersEnabled[i]
|
||||||
|| (renderer.isCurrentStreamFinal()
|
|| (renderer.isCurrentStreamFinal()
|
||||||
&& renderer.getStream() == playingPeriodHolder.sampleStreams[i]))) {
|
&& renderer.getStream() == playingPeriodHolder.sampleStreams[i]))) {
|
||||||
// The renderer should be disabled before playing the next period, either because it's not
|
// The renderer should be disabled before playing the next period, either because it's not
|
||||||
@ -1487,49 +1486,63 @@ import java.io.IOException;
|
|||||||
enableRenderers(rendererWasEnabledFlags, enabledRendererCount);
|
enableRenderers(rendererWasEnabledFlags, enabledRendererCount);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void enableRenderers(boolean[] rendererWasEnabledFlags, int enabledRendererCount)
|
private void enableRenderers(boolean[] rendererWasEnabledFlags, int totalEnabledRendererCount)
|
||||||
throws ExoPlaybackException {
|
throws ExoPlaybackException {
|
||||||
enabledRenderers = new Renderer[enabledRendererCount];
|
enabledRenderers = new Renderer[totalEnabledRendererCount];
|
||||||
enabledRendererCount = 0;
|
int enabledRendererCount = 0;
|
||||||
for (int i = 0; i < renderers.length; i++) {
|
for (int i = 0; i < renderers.length; i++) {
|
||||||
Renderer renderer = renderers[i];
|
if (playingPeriodHolder.trackSelectorResult.renderersEnabled[i]) {
|
||||||
TrackSelection newSelection = playingPeriodHolder.trackSelectorResult.selections.get(i);
|
enableRenderer(i, rendererWasEnabledFlags[i], enabledRendererCount++);
|
||||||
if (newSelection != null) {
|
|
||||||
enabledRenderers[enabledRendererCount++] = renderer;
|
|
||||||
if (renderer.getState() == Renderer.STATE_DISABLED) {
|
|
||||||
RendererConfiguration rendererConfiguration =
|
|
||||||
playingPeriodHolder.trackSelectorResult.rendererConfigurations[i];
|
|
||||||
// The renderer needs enabling with its new track selection.
|
|
||||||
boolean playing = playWhenReady && state == Player.STATE_READY;
|
|
||||||
// Consider as joining only if the renderer was previously disabled.
|
|
||||||
boolean joining = !rendererWasEnabledFlags[i] && playing;
|
|
||||||
// Build an array of formats contained by the selection.
|
|
||||||
Format[] formats = new Format[newSelection.length()];
|
|
||||||
for (int j = 0; j < formats.length; j++) {
|
|
||||||
formats[j] = newSelection.getFormat(j);
|
|
||||||
}
|
|
||||||
// Enable the renderer.
|
|
||||||
renderer.enable(rendererConfiguration, formats, playingPeriodHolder.sampleStreams[i],
|
|
||||||
rendererPositionUs, joining, playingPeriodHolder.getRendererOffset());
|
|
||||||
MediaClock mediaClock = renderer.getMediaClock();
|
|
||||||
if (mediaClock != null) {
|
|
||||||
if (rendererMediaClock != null) {
|
|
||||||
throw ExoPlaybackException.createForUnexpected(
|
|
||||||
new IllegalStateException("Multiple renderer media clocks enabled."));
|
|
||||||
}
|
|
||||||
rendererMediaClock = mediaClock;
|
|
||||||
rendererMediaClockSource = renderer;
|
|
||||||
rendererMediaClock.setPlaybackParameters(playbackParameters);
|
|
||||||
}
|
|
||||||
// Start the renderer if playing.
|
|
||||||
if (playing) {
|
|
||||||
renderer.start();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void enableRenderer(int rendererIndex, boolean wasRendererEnabled,
|
||||||
|
int enabledRendererIndex) throws ExoPlaybackException {
|
||||||
|
Renderer renderer = renderers[rendererIndex];
|
||||||
|
enabledRenderers[enabledRendererIndex] = renderer;
|
||||||
|
if (renderer.getState() == Renderer.STATE_DISABLED) {
|
||||||
|
RendererConfiguration rendererConfiguration =
|
||||||
|
playingPeriodHolder.trackSelectorResult.rendererConfigurations[rendererIndex];
|
||||||
|
TrackSelection newSelection = playingPeriodHolder.trackSelectorResult.selections.get(
|
||||||
|
rendererIndex);
|
||||||
|
Format[] formats = getFormats(newSelection);
|
||||||
|
// The renderer needs enabling with its new track selection.
|
||||||
|
boolean playing = playWhenReady && state == Player.STATE_READY;
|
||||||
|
// Consider as joining only if the renderer was previously disabled.
|
||||||
|
boolean joining = !wasRendererEnabled && playing;
|
||||||
|
// Enable the renderer.
|
||||||
|
renderer.enable(rendererConfiguration, formats,
|
||||||
|
playingPeriodHolder.sampleStreams[rendererIndex], rendererPositionUs,
|
||||||
|
joining, playingPeriodHolder.getRendererOffset());
|
||||||
|
MediaClock mediaClock = renderer.getMediaClock();
|
||||||
|
if (mediaClock != null) {
|
||||||
|
if (rendererMediaClock != null) {
|
||||||
|
throw ExoPlaybackException.createForUnexpected(
|
||||||
|
new IllegalStateException("Multiple renderer media clocks enabled."));
|
||||||
|
}
|
||||||
|
rendererMediaClock = mediaClock;
|
||||||
|
rendererMediaClockSource = renderer;
|
||||||
|
rendererMediaClock.setPlaybackParameters(playbackParameters);
|
||||||
|
}
|
||||||
|
// Start the renderer if playing.
|
||||||
|
if (playing) {
|
||||||
|
renderer.start();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
private static Format[] getFormats(TrackSelection newSelection) {
|
||||||
|
// Build an array of formats contained by the selection.
|
||||||
|
int length = newSelection != null ? newSelection.length() : 0;
|
||||||
|
Format[] formats = new Format[length];
|
||||||
|
for (int i = 0; i < length; i++) {
|
||||||
|
formats[i] = newSelection.getFormat(i);
|
||||||
|
}
|
||||||
|
return formats;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Holds a {@link MediaPeriod} with information required to play it as part of a timeline.
|
* Holds a {@link MediaPeriod} with information required to play it as part of a timeline.
|
||||||
*/
|
*/
|
||||||
@ -1656,17 +1669,24 @@ import java.io.IOException;
|
|||||||
&& trackSelectorResult.isEquivalent(periodTrackSelectorResult, i);
|
&& trackSelectorResult.isEquivalent(periodTrackSelectorResult, i);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Undo the effect of previous call to associate no-sample renderers with empty tracks
|
||||||
|
// so the mediaPeriod receives back whatever it sent us before.
|
||||||
|
disassociateNoSampleRenderersWithEmptySampleStream(sampleStreams);
|
||||||
// Disable streams on the period and get new streams for updated/newly-enabled tracks.
|
// Disable streams on the period and get new streams for updated/newly-enabled tracks.
|
||||||
positionUs = mediaPeriod.selectTracks(trackSelections.getAll(), mayRetainStreamFlags,
|
positionUs = mediaPeriod.selectTracks(trackSelections.getAll(), mayRetainStreamFlags,
|
||||||
sampleStreams, streamResetFlags, positionUs);
|
sampleStreams, streamResetFlags, positionUs);
|
||||||
|
associateNoSampleRenderersWithEmptySampleStream(sampleStreams);
|
||||||
periodTrackSelectorResult = trackSelectorResult;
|
periodTrackSelectorResult = trackSelectorResult;
|
||||||
|
|
||||||
// Update whether we have enabled tracks and sanity check the expected streams are non-null.
|
// Update whether we have enabled tracks and sanity check the expected streams are non-null.
|
||||||
hasEnabledTracks = false;
|
hasEnabledTracks = false;
|
||||||
for (int i = 0; i < sampleStreams.length; i++) {
|
for (int i = 0; i < sampleStreams.length; i++) {
|
||||||
if (sampleStreams[i] != null) {
|
if (sampleStreams[i] != null) {
|
||||||
Assertions.checkState(trackSelections.get(i) != null);
|
Assertions.checkState(trackSelectorResult.renderersEnabled[i]);
|
||||||
hasEnabledTracks = true;
|
// hasEnabledTracks should be true only when non-empty streams exists.
|
||||||
|
if (rendererCapabilities[i].getTrackType() != C.TRACK_TYPE_NONE) {
|
||||||
|
hasEnabledTracks = true;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
Assertions.checkState(trackSelections.get(i) == null);
|
Assertions.checkState(trackSelections.get(i) == null);
|
||||||
}
|
}
|
||||||
@ -1690,6 +1710,31 @@ import java.io.IOException;
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* For each renderer of type {@link C#TRACK_TYPE_NONE}, we will remove the dummy
|
||||||
|
* {@link EmptySampleStream} that was associated with it.
|
||||||
|
*/
|
||||||
|
private void disassociateNoSampleRenderersWithEmptySampleStream(SampleStream[] sampleStreams) {
|
||||||
|
for (int i = 0; i < rendererCapabilities.length; i++) {
|
||||||
|
if (rendererCapabilities[i].getTrackType() == C.TRACK_TYPE_NONE) {
|
||||||
|
sampleStreams[i] = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* For each renderer of type {@link C#TRACK_TYPE_NONE} that was enabled, we will
|
||||||
|
* associate it with a dummy {@link EmptySampleStream}.
|
||||||
|
*/
|
||||||
|
private void associateNoSampleRenderersWithEmptySampleStream(SampleStream[] sampleStreams) {
|
||||||
|
for (int i = 0; i < rendererCapabilities.length; i++) {
|
||||||
|
if (rendererCapabilities[i].getTrackType() == C.TRACK_TYPE_NONE
|
||||||
|
&& trackSelectorResult.renderersEnabled[i]) {
|
||||||
|
sampleStreams[i] = new EmptySampleStream();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static final class SeekPosition {
|
private static final class SeekPosition {
|
||||||
|
@ -0,0 +1,278 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2016 The Android Open Source Project
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package com.google.android.exoplayer2;
|
||||||
|
|
||||||
|
import com.google.android.exoplayer2.source.SampleStream;
|
||||||
|
import com.google.android.exoplayer2.util.Assertions;
|
||||||
|
import com.google.android.exoplayer2.util.MediaClock;
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A {@link Renderer} implementation whose track type is {@link C#TRACK_TYPE_NONE} and does not
|
||||||
|
* consume data from its {@link SampleStream}.
|
||||||
|
*/
|
||||||
|
public abstract class NoSampleRenderer implements Renderer, RendererCapabilities {
|
||||||
|
|
||||||
|
private RendererConfiguration configuration;
|
||||||
|
private int index;
|
||||||
|
private int state;
|
||||||
|
private SampleStream stream;
|
||||||
|
private boolean streamIsFinal;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public final int getTrackType() {
|
||||||
|
return C.TRACK_TYPE_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public final RendererCapabilities getCapabilities() {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public final void setIndex(int index) {
|
||||||
|
this.index = index;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public MediaClock getMediaClock() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public final int getState() {
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Replaces the {@link SampleStream} that will be associated with this renderer.
|
||||||
|
* <p>
|
||||||
|
* This method may be called when the renderer is in the following states:
|
||||||
|
* {@link #STATE_DISABLED}.
|
||||||
|
*
|
||||||
|
* @param configuration The renderer configuration.
|
||||||
|
* @param formats The enabled formats. Should be empty.
|
||||||
|
* @param stream The {@link SampleStream} from which the renderer should consume.
|
||||||
|
* @param positionUs The player's current position.
|
||||||
|
* @param joining Whether this renderer is being enabled to join an ongoing playback.
|
||||||
|
* @param offsetUs The offset that should be subtracted from {@code positionUs}
|
||||||
|
* to get the playback position with respect to the media.
|
||||||
|
* @throws ExoPlaybackException If an error occurs.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public final void enable(RendererConfiguration configuration, Format[] formats,
|
||||||
|
SampleStream stream, long positionUs, boolean joining, long offsetUs)
|
||||||
|
throws ExoPlaybackException {
|
||||||
|
Assertions.checkState(state == STATE_DISABLED);
|
||||||
|
this.configuration = configuration;
|
||||||
|
state = STATE_ENABLED;
|
||||||
|
onEnabled(joining);
|
||||||
|
replaceStream(formats, stream, offsetUs);
|
||||||
|
onPositionReset(positionUs, joining);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public final void start() throws ExoPlaybackException {
|
||||||
|
Assertions.checkState(state == STATE_ENABLED);
|
||||||
|
state = STATE_STARTED;
|
||||||
|
onStarted();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Replaces the {@link SampleStream} that will be associated with this renderer.
|
||||||
|
* <p>
|
||||||
|
* This method may be called when the renderer is in the following states:
|
||||||
|
* {@link #STATE_ENABLED}, {@link #STATE_STARTED}.
|
||||||
|
*
|
||||||
|
* @param formats The enabled formats. Should be empty.
|
||||||
|
* @param stream The {@link SampleStream} to be associated with this renderer.
|
||||||
|
* @param offsetUs The offset that should be subtracted from {@code positionUs} in
|
||||||
|
* {@link #render(long, long)} to get the playback position with respect to the media.
|
||||||
|
* @throws ExoPlaybackException If an error occurs.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public final void replaceStream(Format[] formats, SampleStream stream, long offsetUs)
|
||||||
|
throws ExoPlaybackException {
|
||||||
|
Assertions.checkState(!streamIsFinal);
|
||||||
|
this.stream = stream;
|
||||||
|
onRendererOffsetChanged(offsetUs);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public final SampleStream getStream() {
|
||||||
|
return stream;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public final boolean hasReadStreamToEnd() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public final void setCurrentStreamFinal() {
|
||||||
|
streamIsFinal = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public final boolean isCurrentStreamFinal() {
|
||||||
|
return streamIsFinal;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public final void maybeThrowStreamError() throws IOException {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public final void resetPosition(long positionUs) throws ExoPlaybackException {
|
||||||
|
streamIsFinal = false;
|
||||||
|
onPositionReset(positionUs, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public final void stop() throws ExoPlaybackException {
|
||||||
|
Assertions.checkState(state == STATE_STARTED);
|
||||||
|
state = STATE_ENABLED;
|
||||||
|
onStopped();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public final void disable() {
|
||||||
|
Assertions.checkState(state == STATE_ENABLED);
|
||||||
|
state = STATE_DISABLED;
|
||||||
|
stream = null;
|
||||||
|
streamIsFinal = false;
|
||||||
|
onDisabled();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isReady() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isEnded() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// RendererCapabilities implementation.
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int supportsFormat(Format format) throws ExoPlaybackException {
|
||||||
|
return FORMAT_UNSUPPORTED_TYPE;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int supportsMixedMimeTypeAdaptation() throws ExoPlaybackException {
|
||||||
|
return ADAPTIVE_NOT_SUPPORTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ExoPlayerComponent implementation.
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void handleMessage(int what, Object object) throws ExoPlaybackException {
|
||||||
|
// Do nothing.
|
||||||
|
}
|
||||||
|
|
||||||
|
// Methods to be overridden by subclasses.
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called when the renderer is enabled.
|
||||||
|
* <p>
|
||||||
|
* The default implementation is a no-op.
|
||||||
|
*
|
||||||
|
* @param joining Whether this renderer is being enabled to join an ongoing playback.
|
||||||
|
* @throws ExoPlaybackException If an error occurs.
|
||||||
|
*/
|
||||||
|
protected void onEnabled(boolean joining) throws ExoPlaybackException {
|
||||||
|
// Do nothing.
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called when the renderer's offset has been changed.
|
||||||
|
* <p>
|
||||||
|
* The default implementation is a no-op.
|
||||||
|
*
|
||||||
|
* @param offsetUs The offset that should be subtracted from {@code positionUs} in
|
||||||
|
* {@link #render(long, long)} to get the playback position with respect to the media.
|
||||||
|
* @throws ExoPlaybackException If an error occurs.
|
||||||
|
*/
|
||||||
|
protected void onRendererOffsetChanged(long offsetUs) throws ExoPlaybackException {
|
||||||
|
// Do nothing.
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called when the position is reset. This occurs when the renderer is enabled after
|
||||||
|
* {@link #onRendererOffsetChanged(long)} has been called, and also when a position
|
||||||
|
* discontinuity is encountered.
|
||||||
|
* <p>
|
||||||
|
* The default implementation is a no-op.
|
||||||
|
*
|
||||||
|
* @param positionUs The new playback position in microseconds.
|
||||||
|
* @param joining Whether this renderer is being enabled to join an ongoing playback.
|
||||||
|
* @throws ExoPlaybackException If an error occurs.
|
||||||
|
*/
|
||||||
|
protected void onPositionReset(long positionUs, boolean joining) throws ExoPlaybackException {
|
||||||
|
// Do nothing.
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called when the renderer is started.
|
||||||
|
* <p>
|
||||||
|
* The default implementation is a no-op.
|
||||||
|
*
|
||||||
|
* @throws ExoPlaybackException If an error occurs.
|
||||||
|
*/
|
||||||
|
protected void onStarted() throws ExoPlaybackException {
|
||||||
|
// Do nothing.
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called when the renderer is stopped.
|
||||||
|
* <p>
|
||||||
|
* The default implementation is a no-op.
|
||||||
|
*
|
||||||
|
* @throws ExoPlaybackException If an error occurs.
|
||||||
|
*/
|
||||||
|
protected void onStopped() throws ExoPlaybackException {
|
||||||
|
// Do nothing.
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called when the renderer is disabled.
|
||||||
|
* <p>
|
||||||
|
* The default implementation is a no-op.
|
||||||
|
*/
|
||||||
|
protected void onDisabled() {
|
||||||
|
// Do nothing.
|
||||||
|
}
|
||||||
|
|
||||||
|
// Methods to be called by subclasses.
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the configuration set when the renderer was most recently enabled.
|
||||||
|
*/
|
||||||
|
protected final RendererConfiguration getConfiguration() {
|
||||||
|
return configuration;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the index of the renderer within the player.
|
||||||
|
*/
|
||||||
|
protected final int getIndex() {
|
||||||
|
return index;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -573,6 +573,8 @@ public abstract class MappingTrackSelector extends TrackSelector {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
boolean[] rendererEnabled = determineEnabledRenderers(rendererCapabilities, trackSelections);
|
||||||
|
|
||||||
// Package up the track information and selections.
|
// Package up the track information and selections.
|
||||||
MappedTrackInfo mappedTrackInfo = new MappedTrackInfo(rendererTrackTypes,
|
MappedTrackInfo mappedTrackInfo = new MappedTrackInfo(rendererTrackTypes,
|
||||||
rendererTrackGroupArrays, mixedMimeTypeAdaptationSupport, rendererFormatSupports,
|
rendererTrackGroupArrays, mixedMimeTypeAdaptationSupport, rendererFormatSupports,
|
||||||
@ -583,14 +585,26 @@ public abstract class MappingTrackSelector extends TrackSelector {
|
|||||||
RendererConfiguration[] rendererConfigurations =
|
RendererConfiguration[] rendererConfigurations =
|
||||||
new RendererConfiguration[rendererCapabilities.length];
|
new RendererConfiguration[rendererCapabilities.length];
|
||||||
for (int i = 0; i < rendererCapabilities.length; i++) {
|
for (int i = 0; i < rendererCapabilities.length; i++) {
|
||||||
rendererConfigurations[i] = trackSelections[i] != null ? RendererConfiguration.DEFAULT : null;
|
rendererConfigurations[i] = rendererEnabled[i] ? RendererConfiguration.DEFAULT : null;
|
||||||
}
|
}
|
||||||
// Configure audio and video renderers to use tunneling if appropriate.
|
// Configure audio and video renderers to use tunneling if appropriate.
|
||||||
maybeConfigureRenderersForTunneling(rendererCapabilities, rendererTrackGroupArrays,
|
maybeConfigureRenderersForTunneling(rendererCapabilities, rendererTrackGroupArrays,
|
||||||
rendererFormatSupports, rendererConfigurations, trackSelections, tunnelingAudioSessionId);
|
rendererFormatSupports, rendererConfigurations, trackSelections, tunnelingAudioSessionId);
|
||||||
|
|
||||||
return new TrackSelectorResult(trackGroups, new TrackSelectionArray(trackSelections),
|
return new TrackSelectorResult(trackGroups, rendererEnabled,
|
||||||
mappedTrackInfo, rendererConfigurations);
|
new TrackSelectionArray(trackSelections), mappedTrackInfo, rendererConfigurations);
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean[] determineEnabledRenderers(RendererCapabilities[] rendererCapabilities,
|
||||||
|
TrackSelection[] trackSelections) {
|
||||||
|
boolean[] rendererEnabled = new boolean[trackSelections.length];
|
||||||
|
for (int i = 0; i < rendererEnabled.length; i++) {
|
||||||
|
boolean forceRendererDisabled = rendererDisabledFlags.get(i);
|
||||||
|
rendererEnabled[i] = !forceRendererDisabled
|
||||||
|
&& (rendererCapabilities[i].getTrackType() == C.TRACK_TYPE_NONE
|
||||||
|
|| trackSelections[i] != null);
|
||||||
|
}
|
||||||
|
return rendererEnabled;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -28,6 +28,10 @@ public final class TrackSelectorResult {
|
|||||||
* The track groups that were provided to the {@link TrackSelector}.
|
* The track groups that were provided to the {@link TrackSelector}.
|
||||||
*/
|
*/
|
||||||
public final TrackGroupArray groups;
|
public final TrackGroupArray groups;
|
||||||
|
/**
|
||||||
|
* An array containing whether each renderer is enabled after the track selection operation.
|
||||||
|
*/
|
||||||
|
public final boolean[] renderersEnabled;
|
||||||
/**
|
/**
|
||||||
* A {@link TrackSelectionArray} containing the track selection for each renderer.
|
* A {@link TrackSelectionArray} containing the track selection for each renderer.
|
||||||
*/
|
*/
|
||||||
@ -38,21 +42,25 @@ public final class TrackSelectorResult {
|
|||||||
*/
|
*/
|
||||||
public final Object info;
|
public final Object info;
|
||||||
/**
|
/**
|
||||||
* A {@link RendererConfiguration} for each renderer, to be used with the selections.
|
* A {@link RendererConfiguration} for each enabled renderer, to be used with the selections.
|
||||||
*/
|
*/
|
||||||
public final RendererConfiguration[] rendererConfigurations;
|
public final RendererConfiguration[] rendererConfigurations;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param groups The track groups provided to the {@link TrackSelector}.
|
* @param groups The track groups provided to the {@link TrackSelector}.
|
||||||
|
* @param renderersEnabled An array containing whether each renderer is enabled after the track
|
||||||
|
* selection operation.
|
||||||
* @param selections A {@link TrackSelectionArray} containing the selection for each renderer.
|
* @param selections A {@link TrackSelectionArray} containing the selection for each renderer.
|
||||||
* @param info An opaque object that will be returned to
|
* @param info An opaque object that will be returned to
|
||||||
* {@link TrackSelector#onSelectionActivated(Object)} should the selection be activated.
|
* {@link TrackSelector#onSelectionActivated(Object)} should the selection be activated.
|
||||||
* @param rendererConfigurations A {@link RendererConfiguration} for each renderer, to be used
|
* @param rendererConfigurations A {@link RendererConfiguration} for each enabled renderer,
|
||||||
* with the selections.
|
* to be used with the selections.
|
||||||
*/
|
*/
|
||||||
public TrackSelectorResult(TrackGroupArray groups, TrackSelectionArray selections, Object info,
|
public TrackSelectorResult(TrackGroupArray groups, boolean[] renderersEnabled,
|
||||||
|
TrackSelectionArray selections, Object info,
|
||||||
RendererConfiguration[] rendererConfigurations) {
|
RendererConfiguration[] rendererConfigurations) {
|
||||||
this.groups = groups;
|
this.groups = groups;
|
||||||
|
this.renderersEnabled = renderersEnabled;
|
||||||
this.selections = selections;
|
this.selections = selections;
|
||||||
this.info = info;
|
this.info = info;
|
||||||
this.rendererConfigurations = rendererConfigurations;
|
this.rendererConfigurations = rendererConfigurations;
|
||||||
@ -79,8 +87,8 @@ public final class TrackSelectorResult {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns whether this result is equivalent to {@code other} for the renderer at the given index.
|
* Returns whether this result is equivalent to {@code other} for the renderer at the given index.
|
||||||
* The results are equivalent if they have equal track selections and configurations for the
|
* The results are equivalent if they have equal renderersEnabled array, track selections, and
|
||||||
* renderer.
|
* configurations for the renderer.
|
||||||
*
|
*
|
||||||
* @param other The other {@link TrackSelectorResult}. May be null, in which case {@code false}
|
* @param other The other {@link TrackSelectorResult}. May be null, in which case {@code false}
|
||||||
* will be returned.
|
* will be returned.
|
||||||
@ -92,7 +100,8 @@ public final class TrackSelectorResult {
|
|||||||
if (other == null) {
|
if (other == null) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return Util.areEqual(selections.get(index), other.selections.get(index))
|
return renderersEnabled[index] == other.renderersEnabled[index]
|
||||||
|
&& Util.areEqual(selections.get(index), other.selections.get(index))
|
||||||
&& Util.areEqual(rendererConfigurations[index], other.rendererConfigurations[index]);
|
&& Util.areEqual(rendererConfigurations[index], other.rendererConfigurations[index]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -15,15 +15,18 @@
|
|||||||
*/
|
*/
|
||||||
package com.google.android.exoplayer2.trackselection;
|
package com.google.android.exoplayer2.trackselection;
|
||||||
|
|
||||||
|
import static com.google.android.exoplayer2.RendererConfiguration.DEFAULT;
|
||||||
import static com.google.common.truth.Truth.assertThat;
|
import static com.google.common.truth.Truth.assertThat;
|
||||||
|
|
||||||
import com.google.android.exoplayer2.C;
|
import com.google.android.exoplayer2.C;
|
||||||
import com.google.android.exoplayer2.ExoPlaybackException;
|
import com.google.android.exoplayer2.ExoPlaybackException;
|
||||||
import com.google.android.exoplayer2.Format;
|
import com.google.android.exoplayer2.Format;
|
||||||
import com.google.android.exoplayer2.RendererCapabilities;
|
import com.google.android.exoplayer2.RendererCapabilities;
|
||||||
|
import com.google.android.exoplayer2.RendererConfiguration;
|
||||||
import com.google.android.exoplayer2.source.TrackGroup;
|
import com.google.android.exoplayer2.source.TrackGroup;
|
||||||
import com.google.android.exoplayer2.source.TrackGroupArray;
|
import com.google.android.exoplayer2.source.TrackGroupArray;
|
||||||
import com.google.android.exoplayer2.util.MimeTypes;
|
import com.google.android.exoplayer2.util.MimeTypes;
|
||||||
|
import java.util.Arrays;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.junit.runner.RunWith;
|
import org.junit.runner.RunWith;
|
||||||
import org.robolectric.RobolectricTestRunner;
|
import org.robolectric.RobolectricTestRunner;
|
||||||
@ -40,9 +43,15 @@ public final class MappingTrackSelectorTest {
|
|||||||
new FakeRendererCapabilities(C.TRACK_TYPE_VIDEO);
|
new FakeRendererCapabilities(C.TRACK_TYPE_VIDEO);
|
||||||
private static final RendererCapabilities AUDIO_CAPABILITIES =
|
private static final RendererCapabilities AUDIO_CAPABILITIES =
|
||||||
new FakeRendererCapabilities(C.TRACK_TYPE_AUDIO);
|
new FakeRendererCapabilities(C.TRACK_TYPE_AUDIO);
|
||||||
|
private static final RendererCapabilities NO_SAMPLE_CAPABILITIES =
|
||||||
|
new FakeRendererCapabilities(C.TRACK_TYPE_NONE);
|
||||||
private static final RendererCapabilities[] RENDERER_CAPABILITIES = new RendererCapabilities[] {
|
private static final RendererCapabilities[] RENDERER_CAPABILITIES = new RendererCapabilities[] {
|
||||||
VIDEO_CAPABILITIES, AUDIO_CAPABILITIES
|
VIDEO_CAPABILITIES, AUDIO_CAPABILITIES
|
||||||
};
|
};
|
||||||
|
private static final RendererCapabilities[] RENDERER_CAPABILITIES_WITH_NO_SAMPLE_RENDERER =
|
||||||
|
new RendererCapabilities[] {
|
||||||
|
VIDEO_CAPABILITIES, AUDIO_CAPABILITIES, NO_SAMPLE_CAPABILITIES
|
||||||
|
};
|
||||||
|
|
||||||
private static final TrackGroup VIDEO_TRACK_GROUP = new TrackGroup(
|
private static final TrackGroup VIDEO_TRACK_GROUP = new TrackGroup(
|
||||||
Format.createVideoSampleFormat("video", MimeTypes.VIDEO_H264, null, Format.NO_VALUE,
|
Format.createVideoSampleFormat("video", MimeTypes.VIDEO_H264, null, Format.NO_VALUE,
|
||||||
@ -58,6 +67,13 @@ public final class MappingTrackSelectorTest {
|
|||||||
new FixedTrackSelection(AUDIO_TRACK_GROUP, 0)
|
new FixedTrackSelection(AUDIO_TRACK_GROUP, 0)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
private static final TrackSelection[] TRACK_SELECTIONS_WITH_NO_SAMPLE_RENDERER =
|
||||||
|
new TrackSelection[] {
|
||||||
|
new FixedTrackSelection(VIDEO_TRACK_GROUP, 0),
|
||||||
|
new FixedTrackSelection(AUDIO_TRACK_GROUP, 0),
|
||||||
|
null
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tests that the video and audio track groups are mapped onto the correct renderers.
|
* Tests that the video and audio track groups are mapped onto the correct renderers.
|
||||||
*/
|
*/
|
||||||
@ -104,10 +120,14 @@ public final class MappingTrackSelectorTest {
|
|||||||
*/
|
*/
|
||||||
@Test
|
@Test
|
||||||
public void testSelectTracks() throws ExoPlaybackException {
|
public void testSelectTracks() throws ExoPlaybackException {
|
||||||
FakeMappingTrackSelector trackSelector = new FakeMappingTrackSelector(TRACK_SELECTIONS);
|
FakeMappingTrackSelector trackSelector = new FakeMappingTrackSelector(
|
||||||
|
TRACK_SELECTIONS);
|
||||||
TrackSelectorResult result = trackSelector.selectTracks(RENDERER_CAPABILITIES, TRACK_GROUPS);
|
TrackSelectorResult result = trackSelector.selectTracks(RENDERER_CAPABILITIES, TRACK_GROUPS);
|
||||||
assertThat(result.selections.get(0)).isEqualTo(TRACK_SELECTIONS[0]);
|
assertThat(result.selections.get(0)).isEqualTo(TRACK_SELECTIONS[0]);
|
||||||
assertThat(result.selections.get(1)).isEqualTo(TRACK_SELECTIONS[1]);
|
assertThat(result.selections.get(1)).isEqualTo(TRACK_SELECTIONS[1]);
|
||||||
|
assertThat(new boolean[] {true, true}).isEqualTo(result.renderersEnabled);
|
||||||
|
assertThat(new RendererConfiguration[] {DEFAULT, DEFAULT})
|
||||||
|
.isEqualTo(result.rendererConfigurations);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -115,11 +135,15 @@ public final class MappingTrackSelectorTest {
|
|||||||
*/
|
*/
|
||||||
@Test
|
@Test
|
||||||
public void testSelectTracksWithNullOverride() throws ExoPlaybackException {
|
public void testSelectTracksWithNullOverride() throws ExoPlaybackException {
|
||||||
FakeMappingTrackSelector trackSelector = new FakeMappingTrackSelector(TRACK_SELECTIONS);
|
FakeMappingTrackSelector trackSelector = new FakeMappingTrackSelector(
|
||||||
|
TRACK_SELECTIONS);
|
||||||
trackSelector.setSelectionOverride(0, new TrackGroupArray(VIDEO_TRACK_GROUP), null);
|
trackSelector.setSelectionOverride(0, new TrackGroupArray(VIDEO_TRACK_GROUP), null);
|
||||||
TrackSelectorResult result = trackSelector.selectTracks(RENDERER_CAPABILITIES, TRACK_GROUPS);
|
TrackSelectorResult result = trackSelector.selectTracks(RENDERER_CAPABILITIES, TRACK_GROUPS);
|
||||||
assertThat(result.selections.get(0)).isNull();
|
assertThat(result.selections.get(0)).isNull();
|
||||||
assertThat(result.selections.get(1)).isEqualTo(TRACK_SELECTIONS[1]);
|
assertThat(result.selections.get(1)).isEqualTo(TRACK_SELECTIONS[1]);
|
||||||
|
assertThat(new boolean[] {false, true}).isEqualTo(result.renderersEnabled);
|
||||||
|
assertThat(new RendererConfiguration[] {null, DEFAULT})
|
||||||
|
.isEqualTo(result.rendererConfigurations);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -127,12 +151,16 @@ public final class MappingTrackSelectorTest {
|
|||||||
*/
|
*/
|
||||||
@Test
|
@Test
|
||||||
public void testSelectTracksWithClearedNullOverride() throws ExoPlaybackException {
|
public void testSelectTracksWithClearedNullOverride() throws ExoPlaybackException {
|
||||||
FakeMappingTrackSelector trackSelector = new FakeMappingTrackSelector(TRACK_SELECTIONS);
|
FakeMappingTrackSelector trackSelector = new FakeMappingTrackSelector(
|
||||||
|
TRACK_SELECTIONS);
|
||||||
trackSelector.setSelectionOverride(0, new TrackGroupArray(VIDEO_TRACK_GROUP), null);
|
trackSelector.setSelectionOverride(0, new TrackGroupArray(VIDEO_TRACK_GROUP), null);
|
||||||
trackSelector.clearSelectionOverride(0, new TrackGroupArray(VIDEO_TRACK_GROUP));
|
trackSelector.clearSelectionOverride(0, new TrackGroupArray(VIDEO_TRACK_GROUP));
|
||||||
TrackSelectorResult result = trackSelector.selectTracks(RENDERER_CAPABILITIES, TRACK_GROUPS);
|
TrackSelectorResult result = trackSelector.selectTracks(RENDERER_CAPABILITIES, TRACK_GROUPS);
|
||||||
assertThat(result.selections.get(0)).isEqualTo(TRACK_SELECTIONS[0]);
|
assertThat(result.selections.get(0)).isEqualTo(TRACK_SELECTIONS[0]);
|
||||||
assertThat(result.selections.get(1)).isEqualTo(TRACK_SELECTIONS[1]);
|
assertThat(result.selections.get(1)).isEqualTo(TRACK_SELECTIONS[1]);
|
||||||
|
assertThat(new boolean[] {true, true}).isEqualTo(result.renderersEnabled);
|
||||||
|
assertThat(new RendererConfiguration[] {DEFAULT, DEFAULT})
|
||||||
|
.isEqualTo(result.rendererConfigurations);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -140,12 +168,133 @@ public final class MappingTrackSelectorTest {
|
|||||||
*/
|
*/
|
||||||
@Test
|
@Test
|
||||||
public void testSelectTracksWithNullOverrideForDifferentTracks() throws ExoPlaybackException {
|
public void testSelectTracksWithNullOverrideForDifferentTracks() throws ExoPlaybackException {
|
||||||
FakeMappingTrackSelector trackSelector = new FakeMappingTrackSelector(TRACK_SELECTIONS);
|
FakeMappingTrackSelector trackSelector = new FakeMappingTrackSelector(
|
||||||
|
TRACK_SELECTIONS);
|
||||||
trackSelector.setSelectionOverride(0, new TrackGroupArray(VIDEO_TRACK_GROUP), null);
|
trackSelector.setSelectionOverride(0, new TrackGroupArray(VIDEO_TRACK_GROUP), null);
|
||||||
TrackSelectorResult result = trackSelector.selectTracks(RENDERER_CAPABILITIES,
|
TrackSelectorResult result = trackSelector.selectTracks(RENDERER_CAPABILITIES,
|
||||||
new TrackGroupArray(VIDEO_TRACK_GROUP, AUDIO_TRACK_GROUP, VIDEO_TRACK_GROUP));
|
new TrackGroupArray(VIDEO_TRACK_GROUP, AUDIO_TRACK_GROUP, VIDEO_TRACK_GROUP));
|
||||||
assertThat(result.selections.get(0)).isEqualTo(TRACK_SELECTIONS[0]);
|
assertThat(result.selections.get(0)).isEqualTo(TRACK_SELECTIONS[0]);
|
||||||
assertThat(result.selections.get(1)).isEqualTo(TRACK_SELECTIONS[1]);
|
assertThat(result.selections.get(1)).isEqualTo(TRACK_SELECTIONS[1]);
|
||||||
|
assertThat(new boolean[] {true, true}).isEqualTo(result.renderersEnabled);
|
||||||
|
assertThat(new RendererConfiguration[] {DEFAULT, DEFAULT})
|
||||||
|
.isEqualTo(result.rendererConfigurations);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests the result of {@link MappingTrackSelector#selectTracks(RendererCapabilities[],
|
||||||
|
* TrackGroupArray[], int[][][])} is propagated correctly to the result of
|
||||||
|
* {@link MappingTrackSelector#selectTracks(RendererCapabilities[], TrackGroupArray)}
|
||||||
|
* when there is no-sample renderer.
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testSelectTracksWithNoSampleRenderer() throws ExoPlaybackException {
|
||||||
|
TrackSelection[] expectedTrackSelection = TRACK_SELECTIONS_WITH_NO_SAMPLE_RENDERER;
|
||||||
|
FakeMappingTrackSelector trackSelector = new FakeMappingTrackSelector(expectedTrackSelection);
|
||||||
|
TrackSelectorResult result = trackSelector.selectTracks(
|
||||||
|
RENDERER_CAPABILITIES_WITH_NO_SAMPLE_RENDERER, TRACK_GROUPS);
|
||||||
|
assertThat(result.selections.get(0)).isEqualTo(expectedTrackSelection[0]);
|
||||||
|
assertThat(result.selections.get(1)).isEqualTo(expectedTrackSelection[1]);
|
||||||
|
assertThat(result.selections.get(2)).isNull();
|
||||||
|
assertThat(new boolean[] {true, true, true}).isEqualTo(result.renderersEnabled);
|
||||||
|
assertThat(new RendererConfiguration[] {DEFAULT, DEFAULT, DEFAULT})
|
||||||
|
.isEqualTo(result.rendererConfigurations);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests that a null override clears a track selection when there is no-sample renderer.
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testSelectTracksWithNoSampleRendererWithNullOverride() throws ExoPlaybackException {
|
||||||
|
TrackSelection[] expectedTrackSelection = TRACK_SELECTIONS_WITH_NO_SAMPLE_RENDERER;
|
||||||
|
FakeMappingTrackSelector trackSelector = new FakeMappingTrackSelector(expectedTrackSelection);
|
||||||
|
trackSelector.setSelectionOverride(0, new TrackGroupArray(VIDEO_TRACK_GROUP), null);
|
||||||
|
TrackSelectorResult result = trackSelector.selectTracks(
|
||||||
|
RENDERER_CAPABILITIES_WITH_NO_SAMPLE_RENDERER, TRACK_GROUPS);
|
||||||
|
assertThat(result.selections.get(0)).isNull();
|
||||||
|
assertThat(result.selections.get(1)).isEqualTo(expectedTrackSelection[1]);
|
||||||
|
assertThat(result.selections.get(2)).isNull();
|
||||||
|
assertThat(new boolean[] {false, true, true}).isEqualTo(result.renderersEnabled);
|
||||||
|
assertThat(new RendererConfiguration[] {null, DEFAULT, DEFAULT})
|
||||||
|
.isEqualTo(result.rendererConfigurations);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests that a null override can be cleared when there is no-sample renderer.
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testSelectTracksWithNoSampleRendererWithClearedNullOverride()
|
||||||
|
throws ExoPlaybackException {
|
||||||
|
TrackSelection[] expectedTrackSelection = TRACK_SELECTIONS_WITH_NO_SAMPLE_RENDERER;
|
||||||
|
FakeMappingTrackSelector trackSelector = new FakeMappingTrackSelector(expectedTrackSelection);
|
||||||
|
trackSelector.setSelectionOverride(0, new TrackGroupArray(VIDEO_TRACK_GROUP), null);
|
||||||
|
trackSelector.clearSelectionOverride(0, new TrackGroupArray(VIDEO_TRACK_GROUP));
|
||||||
|
TrackSelectorResult result = trackSelector.selectTracks(
|
||||||
|
RENDERER_CAPABILITIES_WITH_NO_SAMPLE_RENDERER, TRACK_GROUPS);
|
||||||
|
assertThat(result.selections.get(0)).isEqualTo(expectedTrackSelection[0]);
|
||||||
|
assertThat(result.selections.get(1)).isEqualTo(expectedTrackSelection[1]);
|
||||||
|
assertThat(result.selections.get(2)).isNull();
|
||||||
|
assertThat(new boolean[] {true, true, true}).isEqualTo(result.renderersEnabled);
|
||||||
|
assertThat(new RendererConfiguration[] {DEFAULT, DEFAULT, DEFAULT})
|
||||||
|
.isEqualTo(result.rendererConfigurations);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests that an override is not applied for a different set of available track groups
|
||||||
|
* when there is no-sample renderer.
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testSelectTracksWithNoSampleRendererWithNullOverrideForDifferentTracks()
|
||||||
|
throws ExoPlaybackException {
|
||||||
|
TrackSelection[] expectedTrackSelection = TRACK_SELECTIONS_WITH_NO_SAMPLE_RENDERER;
|
||||||
|
FakeMappingTrackSelector trackSelector = new FakeMappingTrackSelector(expectedTrackSelection);
|
||||||
|
trackSelector.setSelectionOverride(0, new TrackGroupArray(VIDEO_TRACK_GROUP), null);
|
||||||
|
TrackSelectorResult result = trackSelector.selectTracks(
|
||||||
|
RENDERER_CAPABILITIES_WITH_NO_SAMPLE_RENDERER,
|
||||||
|
new TrackGroupArray(VIDEO_TRACK_GROUP, AUDIO_TRACK_GROUP, VIDEO_TRACK_GROUP));
|
||||||
|
assertThat(result.selections.get(0)).isEqualTo(expectedTrackSelection[0]);
|
||||||
|
assertThat(result.selections.get(1)).isEqualTo(expectedTrackSelection[1]);
|
||||||
|
assertThat(result.selections.get(2)).isNull();
|
||||||
|
assertThat(new boolean[] {true, true, true}).isEqualTo(result.renderersEnabled);
|
||||||
|
assertThat(new RendererConfiguration[] {DEFAULT, DEFAULT, DEFAULT})
|
||||||
|
.isEqualTo(result.rendererConfigurations);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests that disabling another renderer works when there is no-sample renderer.
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testSelectTracksDisablingNormalRendererWithNoSampleRenderer()
|
||||||
|
throws ExoPlaybackException {
|
||||||
|
TrackSelection[] expectedTrackSelection = TRACK_SELECTIONS_WITH_NO_SAMPLE_RENDERER;
|
||||||
|
FakeMappingTrackSelector trackSelector = new FakeMappingTrackSelector(expectedTrackSelection);
|
||||||
|
trackSelector.setRendererDisabled(0, true);
|
||||||
|
TrackSelectorResult result = trackSelector.selectTracks(
|
||||||
|
RENDERER_CAPABILITIES_WITH_NO_SAMPLE_RENDERER, TRACK_GROUPS);
|
||||||
|
assertThat(result.selections.get(0)).isNull();
|
||||||
|
assertThat(result.selections.get(1)).isEqualTo(expectedTrackSelection[1]);
|
||||||
|
assertThat(result.selections.get(2)).isNull();
|
||||||
|
assertThat(new boolean[] {false, true, true}).isEqualTo(result.renderersEnabled);
|
||||||
|
assertThat(new RendererConfiguration[] {null, DEFAULT, DEFAULT})
|
||||||
|
.isEqualTo(result.rendererConfigurations);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests that disabling no-sample renderer work.
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testSelectTracksDisablingNoSampleRenderer()
|
||||||
|
throws ExoPlaybackException {
|
||||||
|
TrackSelection[] expectedTrackSelection = TRACK_SELECTIONS_WITH_NO_SAMPLE_RENDERER;
|
||||||
|
FakeMappingTrackSelector trackSelector = new FakeMappingTrackSelector(expectedTrackSelection);
|
||||||
|
trackSelector.setRendererDisabled(2, true);
|
||||||
|
TrackSelectorResult result = trackSelector.selectTracks(
|
||||||
|
RENDERER_CAPABILITIES_WITH_NO_SAMPLE_RENDERER, TRACK_GROUPS);
|
||||||
|
assertThat(result.selections.get(0)).isEqualTo(expectedTrackSelection[0]);
|
||||||
|
assertThat(result.selections.get(1)).isEqualTo(expectedTrackSelection[1]);
|
||||||
|
assertThat(result.selections.get(2)).isNull();
|
||||||
|
assertThat(new boolean[] {true, true, false}).isEqualTo(result.renderersEnabled);
|
||||||
|
assertThat(new RendererConfiguration[] {DEFAULT, DEFAULT, null})
|
||||||
|
.isEqualTo(result.rendererConfigurations);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -166,7 +315,12 @@ public final class MappingTrackSelectorTest {
|
|||||||
TrackGroupArray[] rendererTrackGroupArrays, int[][][] rendererFormatSupports)
|
TrackGroupArray[] rendererTrackGroupArrays, int[][][] rendererFormatSupports)
|
||||||
throws ExoPlaybackException {
|
throws ExoPlaybackException {
|
||||||
lastRendererTrackGroupArrays = rendererTrackGroupArrays;
|
lastRendererTrackGroupArrays = rendererTrackGroupArrays;
|
||||||
return result == null ? new TrackSelection[rendererCapabilities.length] : result;
|
TrackSelection[] trackSelectionResult = new TrackSelection[rendererCapabilities.length];
|
||||||
|
return result == null ? trackSelectionResult
|
||||||
|
// return a copy of the provided result, because MappingTrackSelector
|
||||||
|
// might modify the returned array here, and we don't want that to affect
|
||||||
|
// the original array.
|
||||||
|
: Arrays.asList(result).toArray(trackSelectionResult);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void assertMappedTrackGroups(int rendererIndex, TrackGroup... expected) {
|
public void assertMappedTrackGroups(int rendererIndex, TrackGroup... expected) {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user