Use TracksInfo and selection override in users
Update the UI module, the demos and most other users to make use of the new player TracksInfo and track selection override APIs. PiperOrigin-RevId: 402817857
This commit is contained in:
parent
fe0a5662de
commit
98ee159df1
@ -19,7 +19,6 @@ import android.content.Context;
|
|||||||
import android.view.KeyEvent;
|
import android.view.KeyEvent;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.annotation.Nullable;
|
|
||||||
import com.google.android.exoplayer2.C;
|
import com.google.android.exoplayer2.C;
|
||||||
import com.google.android.exoplayer2.ExoPlayer;
|
import com.google.android.exoplayer2.ExoPlayer;
|
||||||
import com.google.android.exoplayer2.MediaItem;
|
import com.google.android.exoplayer2.MediaItem;
|
||||||
@ -28,12 +27,9 @@ import com.google.android.exoplayer2.Player.DiscontinuityReason;
|
|||||||
import com.google.android.exoplayer2.Player.TimelineChangeReason;
|
import com.google.android.exoplayer2.Player.TimelineChangeReason;
|
||||||
import com.google.android.exoplayer2.SimpleExoPlayer;
|
import com.google.android.exoplayer2.SimpleExoPlayer;
|
||||||
import com.google.android.exoplayer2.Timeline;
|
import com.google.android.exoplayer2.Timeline;
|
||||||
|
import com.google.android.exoplayer2.TracksInfo;
|
||||||
import com.google.android.exoplayer2.ext.cast.CastPlayer;
|
import com.google.android.exoplayer2.ext.cast.CastPlayer;
|
||||||
import com.google.android.exoplayer2.ext.cast.SessionAvailabilityListener;
|
import com.google.android.exoplayer2.ext.cast.SessionAvailabilityListener;
|
||||||
import com.google.android.exoplayer2.source.TrackGroupArray;
|
|
||||||
import com.google.android.exoplayer2.trackselection.DefaultTrackSelector;
|
|
||||||
import com.google.android.exoplayer2.trackselection.MappingTrackSelector;
|
|
||||||
import com.google.android.exoplayer2.trackselection.TrackSelectionArray;
|
|
||||||
import com.google.android.exoplayer2.ui.PlayerControlView;
|
import com.google.android.exoplayer2.ui.PlayerControlView;
|
||||||
import com.google.android.exoplayer2.ui.PlayerView;
|
import com.google.android.exoplayer2.ui.PlayerView;
|
||||||
import com.google.android.gms.cast.framework.CastContext;
|
import com.google.android.gms.cast.framework.CastContext;
|
||||||
@ -58,13 +54,12 @@ import java.util.ArrayList;
|
|||||||
|
|
||||||
private final PlayerView localPlayerView;
|
private final PlayerView localPlayerView;
|
||||||
private final PlayerControlView castControlView;
|
private final PlayerControlView castControlView;
|
||||||
private final DefaultTrackSelector trackSelector;
|
private final Player localPlayer;
|
||||||
private final SimpleExoPlayer exoPlayer;
|
|
||||||
private final CastPlayer castPlayer;
|
private final CastPlayer castPlayer;
|
||||||
private final ArrayList<MediaItem> mediaQueue;
|
private final ArrayList<MediaItem> mediaQueue;
|
||||||
private final Listener listener;
|
private final Listener listener;
|
||||||
|
|
||||||
private TrackGroupArray lastSeenTrackGroupArray;
|
private TracksInfo lastSeenTrackGroupInfo;
|
||||||
private int currentItemIndex;
|
private int currentItemIndex;
|
||||||
private Player currentPlayer;
|
private Player currentPlayer;
|
||||||
|
|
||||||
@ -89,17 +84,16 @@ import java.util.ArrayList;
|
|||||||
mediaQueue = new ArrayList<>();
|
mediaQueue = new ArrayList<>();
|
||||||
currentItemIndex = C.INDEX_UNSET;
|
currentItemIndex = C.INDEX_UNSET;
|
||||||
|
|
||||||
trackSelector = new DefaultTrackSelector(context);
|
localPlayer = new ExoPlayer.Builder(context).build();
|
||||||
exoPlayer = new ExoPlayer.Builder(context).setTrackSelector(trackSelector).build();
|
localPlayer.addListener(this);
|
||||||
exoPlayer.addListener(this);
|
localPlayerView.setPlayer(localPlayer);
|
||||||
localPlayerView.setPlayer(exoPlayer);
|
|
||||||
|
|
||||||
castPlayer = new CastPlayer(castContext);
|
castPlayer = new CastPlayer(castContext);
|
||||||
castPlayer.addListener(this);
|
castPlayer.addListener(this);
|
||||||
castPlayer.setSessionAvailabilityListener(this);
|
castPlayer.setSessionAvailabilityListener(this);
|
||||||
castControlView.setPlayer(castPlayer);
|
castControlView.setPlayer(castPlayer);
|
||||||
|
|
||||||
setCurrentPlayer(castPlayer.isCastSessionAvailable() ? castPlayer : exoPlayer);
|
setCurrentPlayer(castPlayer.isCastSessionAvailable() ? castPlayer : localPlayer);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Queue manipulation methods.
|
// Queue manipulation methods.
|
||||||
@ -200,7 +194,7 @@ import java.util.ArrayList;
|
|||||||
* @return Whether the event was handled by the target view.
|
* @return Whether the event was handled by the target view.
|
||||||
*/
|
*/
|
||||||
public boolean dispatchKeyEvent(KeyEvent event) {
|
public boolean dispatchKeyEvent(KeyEvent event) {
|
||||||
if (currentPlayer == exoPlayer) {
|
if (currentPlayer == localPlayer) {
|
||||||
return localPlayerView.dispatchKeyEvent(event);
|
return localPlayerView.dispatchKeyEvent(event);
|
||||||
} else /* currentPlayer == castPlayer */ {
|
} else /* currentPlayer == castPlayer */ {
|
||||||
return castControlView.dispatchKeyEvent(event);
|
return castControlView.dispatchKeyEvent(event);
|
||||||
@ -214,7 +208,7 @@ import java.util.ArrayList;
|
|||||||
castPlayer.setSessionAvailabilityListener(null);
|
castPlayer.setSessionAvailabilityListener(null);
|
||||||
castPlayer.release();
|
castPlayer.release();
|
||||||
localPlayerView.setPlayer(null);
|
localPlayerView.setPlayer(null);
|
||||||
exoPlayer.release();
|
localPlayer.release();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Player.Listener implementation.
|
// Player.Listener implementation.
|
||||||
@ -238,24 +232,17 @@ import java.util.ArrayList;
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onTracksChanged(
|
public void onTracksInfoChanged(TracksInfo tracksInfo) {
|
||||||
@NonNull TrackGroupArray trackGroups, @NonNull TrackSelectionArray trackSelections) {
|
if (currentPlayer != localPlayer || tracksInfo == lastSeenTrackGroupInfo) {
|
||||||
if (currentPlayer == exoPlayer && trackGroups != lastSeenTrackGroupArray) {
|
return;
|
||||||
@Nullable
|
}
|
||||||
MappingTrackSelector.MappedTrackInfo mappedTrackInfo =
|
if (!tracksInfo.isTypeSupportedOrEmpty(C.TRACK_TYPE_VIDEO)) {
|
||||||
trackSelector.getCurrentMappedTrackInfo();
|
|
||||||
if (mappedTrackInfo != null) {
|
|
||||||
if (mappedTrackInfo.getTypeSupport(C.TRACK_TYPE_VIDEO)
|
|
||||||
== MappingTrackSelector.MappedTrackInfo.RENDERER_SUPPORT_UNSUPPORTED_TRACKS) {
|
|
||||||
listener.onUnsupportedTrack(C.TRACK_TYPE_VIDEO);
|
listener.onUnsupportedTrack(C.TRACK_TYPE_VIDEO);
|
||||||
}
|
}
|
||||||
if (mappedTrackInfo.getTypeSupport(C.TRACK_TYPE_AUDIO)
|
if (!tracksInfo.isTypeSupportedOrEmpty(C.TRACK_TYPE_AUDIO)) {
|
||||||
== MappingTrackSelector.MappedTrackInfo.RENDERER_SUPPORT_UNSUPPORTED_TRACKS) {
|
|
||||||
listener.onUnsupportedTrack(C.TRACK_TYPE_AUDIO);
|
listener.onUnsupportedTrack(C.TRACK_TYPE_AUDIO);
|
||||||
}
|
}
|
||||||
}
|
lastSeenTrackGroupInfo = tracksInfo;
|
||||||
lastSeenTrackGroupArray = trackGroups;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// CastPlayer.SessionAvailabilityListener implementation.
|
// CastPlayer.SessionAvailabilityListener implementation.
|
||||||
@ -267,7 +254,7 @@ import java.util.ArrayList;
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onCastSessionUnavailable() {
|
public void onCastSessionUnavailable() {
|
||||||
setCurrentPlayer(exoPlayer);
|
setCurrentPlayer(localPlayer);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Internal methods.
|
// Internal methods.
|
||||||
@ -286,7 +273,7 @@ import java.util.ArrayList;
|
|||||||
}
|
}
|
||||||
|
|
||||||
// View management.
|
// View management.
|
||||||
if (currentPlayer == exoPlayer) {
|
if (currentPlayer == localPlayer) {
|
||||||
localPlayerView.setVisibility(View.VISIBLE);
|
localPlayerView.setVisibility(View.VISIBLE);
|
||||||
castControlView.hide();
|
castControlView.hide();
|
||||||
} else /* currentPlayer == castPlayer */ {
|
} else /* currentPlayer == castPlayer */ {
|
||||||
|
@ -38,6 +38,7 @@ import com.google.android.exoplayer2.PlaybackException;
|
|||||||
import com.google.android.exoplayer2.Player;
|
import com.google.android.exoplayer2.Player;
|
||||||
import com.google.android.exoplayer2.RenderersFactory;
|
import com.google.android.exoplayer2.RenderersFactory;
|
||||||
import com.google.android.exoplayer2.SimpleExoPlayer;
|
import com.google.android.exoplayer2.SimpleExoPlayer;
|
||||||
|
import com.google.android.exoplayer2.TracksInfo;
|
||||||
import com.google.android.exoplayer2.audio.AudioAttributes;
|
import com.google.android.exoplayer2.audio.AudioAttributes;
|
||||||
import com.google.android.exoplayer2.drm.FrameworkMediaDrm;
|
import com.google.android.exoplayer2.drm.FrameworkMediaDrm;
|
||||||
import com.google.android.exoplayer2.ext.ima.ImaAdsLoader;
|
import com.google.android.exoplayer2.ext.ima.ImaAdsLoader;
|
||||||
@ -46,11 +47,8 @@ import com.google.android.exoplayer2.mediacodec.MediaCodecUtil.DecoderQueryExcep
|
|||||||
import com.google.android.exoplayer2.offline.DownloadRequest;
|
import com.google.android.exoplayer2.offline.DownloadRequest;
|
||||||
import com.google.android.exoplayer2.source.DefaultMediaSourceFactory;
|
import com.google.android.exoplayer2.source.DefaultMediaSourceFactory;
|
||||||
import com.google.android.exoplayer2.source.MediaSourceFactory;
|
import com.google.android.exoplayer2.source.MediaSourceFactory;
|
||||||
import com.google.android.exoplayer2.source.TrackGroupArray;
|
|
||||||
import com.google.android.exoplayer2.source.ads.AdsLoader;
|
import com.google.android.exoplayer2.source.ads.AdsLoader;
|
||||||
import com.google.android.exoplayer2.trackselection.DefaultTrackSelector;
|
import com.google.android.exoplayer2.trackselection.DefaultTrackSelector;
|
||||||
import com.google.android.exoplayer2.trackselection.MappingTrackSelector.MappedTrackInfo;
|
|
||||||
import com.google.android.exoplayer2.trackselection.TrackSelectionArray;
|
|
||||||
import com.google.android.exoplayer2.ui.StyledPlayerControlView;
|
import com.google.android.exoplayer2.ui.StyledPlayerControlView;
|
||||||
import com.google.android.exoplayer2.ui.StyledPlayerView;
|
import com.google.android.exoplayer2.ui.StyledPlayerView;
|
||||||
import com.google.android.exoplayer2.upstream.DataSource;
|
import com.google.android.exoplayer2.upstream.DataSource;
|
||||||
@ -69,7 +67,7 @@ public class PlayerActivity extends AppCompatActivity
|
|||||||
|
|
||||||
// Saved instance state keys.
|
// Saved instance state keys.
|
||||||
|
|
||||||
private static final String KEY_TRACK_SELECTOR_PARAMETERS = "track_selector_parameters";
|
private static final String KEY_TRACK_SELECTION_PARAMETERS = "track_selection_parameters";
|
||||||
private static final String KEY_WINDOW = "window";
|
private static final String KEY_WINDOW = "window";
|
||||||
private static final String KEY_POSITION = "position";
|
private static final String KEY_POSITION = "position";
|
||||||
private static final String KEY_AUTO_PLAY = "auto_play";
|
private static final String KEY_AUTO_PLAY = "auto_play";
|
||||||
@ -84,9 +82,9 @@ public class PlayerActivity extends AppCompatActivity
|
|||||||
private DataSource.Factory dataSourceFactory;
|
private DataSource.Factory dataSourceFactory;
|
||||||
private List<MediaItem> mediaItems;
|
private List<MediaItem> mediaItems;
|
||||||
private DefaultTrackSelector trackSelector;
|
private DefaultTrackSelector trackSelector;
|
||||||
private DefaultTrackSelector.Parameters trackSelectorParameters;
|
private DefaultTrackSelector.Parameters trackSelectionParameters;
|
||||||
private DebugTextViewHelper debugViewHelper;
|
private DebugTextViewHelper debugViewHelper;
|
||||||
private TrackGroupArray lastSeenTrackGroupArray;
|
private TracksInfo lastSeenTracksInfo;
|
||||||
private boolean startAutoPlay;
|
private boolean startAutoPlay;
|
||||||
private int startWindow;
|
private int startWindow;
|
||||||
private long startPosition;
|
private long startPosition;
|
||||||
@ -114,16 +112,16 @@ public class PlayerActivity extends AppCompatActivity
|
|||||||
playerView.requestFocus();
|
playerView.requestFocus();
|
||||||
|
|
||||||
if (savedInstanceState != null) {
|
if (savedInstanceState != null) {
|
||||||
trackSelectorParameters =
|
// Restore as DefaultTrackSelector.Parameters in case ExoPlayer specific parameters were set.
|
||||||
|
trackSelectionParameters =
|
||||||
DefaultTrackSelector.Parameters.CREATOR.fromBundle(
|
DefaultTrackSelector.Parameters.CREATOR.fromBundle(
|
||||||
savedInstanceState.getBundle(KEY_TRACK_SELECTOR_PARAMETERS));
|
savedInstanceState.getBundle(KEY_TRACK_SELECTION_PARAMETERS));
|
||||||
startAutoPlay = savedInstanceState.getBoolean(KEY_AUTO_PLAY);
|
startAutoPlay = savedInstanceState.getBoolean(KEY_AUTO_PLAY);
|
||||||
startWindow = savedInstanceState.getInt(KEY_WINDOW);
|
startWindow = savedInstanceState.getInt(KEY_WINDOW);
|
||||||
startPosition = savedInstanceState.getLong(KEY_POSITION);
|
startPosition = savedInstanceState.getLong(KEY_POSITION);
|
||||||
} else {
|
} else {
|
||||||
DefaultTrackSelector.ParametersBuilder builder =
|
trackSelectionParameters =
|
||||||
new DefaultTrackSelector.ParametersBuilder(/* context= */ this);
|
new DefaultTrackSelector.ParametersBuilder(/* context= */ this).build();
|
||||||
trackSelectorParameters = builder.build();
|
|
||||||
clearStartPosition();
|
clearStartPosition();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -209,7 +207,7 @@ public class PlayerActivity extends AppCompatActivity
|
|||||||
super.onSaveInstanceState(outState);
|
super.onSaveInstanceState(outState);
|
||||||
updateTrackSelectorParameters();
|
updateTrackSelectorParameters();
|
||||||
updateStartPosition();
|
updateStartPosition();
|
||||||
outState.putBundle(KEY_TRACK_SELECTOR_PARAMETERS, trackSelectorParameters.toBundle());
|
outState.putBundle(KEY_TRACK_SELECTION_PARAMETERS, trackSelectionParameters.toBundle());
|
||||||
outState.putBoolean(KEY_AUTO_PLAY, startAutoPlay);
|
outState.putBoolean(KEY_AUTO_PLAY, startAutoPlay);
|
||||||
outState.putInt(KEY_WINDOW, startWindow);
|
outState.putInt(KEY_WINDOW, startWindow);
|
||||||
outState.putLong(KEY_POSITION, startPosition);
|
outState.putLong(KEY_POSITION, startPosition);
|
||||||
@ -272,13 +270,13 @@ public class PlayerActivity extends AppCompatActivity
|
|||||||
.setAdViewProvider(playerView);
|
.setAdViewProvider(playerView);
|
||||||
|
|
||||||
trackSelector = new DefaultTrackSelector(/* context= */ this);
|
trackSelector = new DefaultTrackSelector(/* context= */ this);
|
||||||
trackSelector.setParameters(trackSelectorParameters);
|
lastSeenTracksInfo = TracksInfo.EMPTY;
|
||||||
lastSeenTrackGroupArray = null;
|
|
||||||
player =
|
player =
|
||||||
new ExoPlayer.Builder(/* context= */ this, renderersFactory)
|
new ExoPlayer.Builder(/* context= */ this, renderersFactory)
|
||||||
.setMediaSourceFactory(mediaSourceFactory)
|
.setMediaSourceFactory(mediaSourceFactory)
|
||||||
.setTrackSelector(trackSelector)
|
.setTrackSelector(trackSelector)
|
||||||
.build();
|
.build();
|
||||||
|
player.setTrackSelectionParameters(trackSelectionParameters);
|
||||||
player.addListener(new PlayerEventListener());
|
player.addListener(new PlayerEventListener());
|
||||||
player.addAnalyticsListener(new EventLogger(trackSelector));
|
player.addAnalyticsListener(new EventLogger(trackSelector));
|
||||||
player.setAudioAttributes(AudioAttributes.DEFAULT, /* handleAudioFocus= */ true);
|
player.setAudioAttributes(AudioAttributes.DEFAULT, /* handleAudioFocus= */ true);
|
||||||
@ -361,7 +359,6 @@ public class PlayerActivity extends AppCompatActivity
|
|||||||
player.release();
|
player.release();
|
||||||
player = null;
|
player = null;
|
||||||
mediaItems = Collections.emptyList();
|
mediaItems = Collections.emptyList();
|
||||||
trackSelector = null;
|
|
||||||
}
|
}
|
||||||
if (adsLoader != null) {
|
if (adsLoader != null) {
|
||||||
adsLoader.setPlayer(null);
|
adsLoader.setPlayer(null);
|
||||||
@ -377,8 +374,11 @@ public class PlayerActivity extends AppCompatActivity
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void updateTrackSelectorParameters() {
|
private void updateTrackSelectorParameters() {
|
||||||
if (trackSelector != null) {
|
if (player != null) {
|
||||||
trackSelectorParameters = trackSelector.getParameters();
|
// Until the demo app is fully migrated to TrackSelectionParameters, rely on ExoPlayer to use
|
||||||
|
// DefaultTrackSelector by default.
|
||||||
|
trackSelectionParameters =
|
||||||
|
(DefaultTrackSelector.Parameters) player.getTrackSelectionParameters();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -438,23 +438,18 @@ public class PlayerActivity extends AppCompatActivity
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
@SuppressWarnings("ReferenceEquality")
|
@SuppressWarnings("ReferenceEquality")
|
||||||
public void onTracksChanged(
|
public void onTracksInfoChanged(TracksInfo tracksInfo) {
|
||||||
@NonNull TrackGroupArray trackGroups, @NonNull TrackSelectionArray trackSelections) {
|
|
||||||
updateButtonVisibility();
|
updateButtonVisibility();
|
||||||
if (trackGroups != lastSeenTrackGroupArray) {
|
if (tracksInfo == lastSeenTracksInfo) {
|
||||||
MappedTrackInfo mappedTrackInfo = trackSelector.getCurrentMappedTrackInfo();
|
return;
|
||||||
if (mappedTrackInfo != null) {
|
}
|
||||||
if (mappedTrackInfo.getTypeSupport(C.TRACK_TYPE_VIDEO)
|
if (!tracksInfo.isTypeSupportedOrEmpty(C.TRACK_TYPE_VIDEO)) {
|
||||||
== MappedTrackInfo.RENDERER_SUPPORT_UNSUPPORTED_TRACKS) {
|
|
||||||
showToast(R.string.error_unsupported_video);
|
showToast(R.string.error_unsupported_video);
|
||||||
}
|
}
|
||||||
if (mappedTrackInfo.getTypeSupport(C.TRACK_TYPE_AUDIO)
|
if (!tracksInfo.isTypeSupportedOrEmpty(C.TRACK_TYPE_AUDIO)) {
|
||||||
== MappedTrackInfo.RENDERER_SUPPORT_UNSUPPORTED_TRACKS) {
|
|
||||||
showToast(R.string.error_unsupported_audio);
|
showToast(R.string.error_unsupported_audio);
|
||||||
}
|
}
|
||||||
}
|
lastSeenTracksInfo = tracksInfo;
|
||||||
lastSeenTrackGroupArray = trackGroups;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -58,8 +58,6 @@ import com.google.android.exoplayer2.Timeline;
|
|||||||
import com.google.android.exoplayer2.source.ads.AdPlaybackState;
|
import com.google.android.exoplayer2.source.ads.AdPlaybackState;
|
||||||
import com.google.android.exoplayer2.source.ads.AdsLoader.EventListener;
|
import com.google.android.exoplayer2.source.ads.AdsLoader.EventListener;
|
||||||
import com.google.android.exoplayer2.source.ads.AdsMediaSource.AdLoadException;
|
import com.google.android.exoplayer2.source.ads.AdsMediaSource.AdLoadException;
|
||||||
import com.google.android.exoplayer2.trackselection.TrackSelectionArray;
|
|
||||||
import com.google.android.exoplayer2.trackselection.TrackSelectionUtil;
|
|
||||||
import com.google.android.exoplayer2.ui.AdOverlayInfo;
|
import com.google.android.exoplayer2.ui.AdOverlayInfo;
|
||||||
import com.google.android.exoplayer2.ui.AdViewProvider;
|
import com.google.android.exoplayer2.ui.AdViewProvider;
|
||||||
import com.google.android.exoplayer2.upstream.DataSpec;
|
import com.google.android.exoplayer2.upstream.DataSpec;
|
||||||
@ -706,8 +704,7 @@ import java.util.Map;
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Check for a selected track using an audio renderer.
|
// Check for a selected track using an audio renderer.
|
||||||
TrackSelectionArray trackSelections = player.getCurrentTrackSelections();
|
return player.getCurrentTracksInfo().isTypeSelected(C.TRACK_TYPE_AUDIO) ? 100 : 0;
|
||||||
return TrackSelectionUtil.hasTrackOfType(trackSelections, C.TRACK_TYPE_AUDIO) ? 100 : 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void handleAdEvent(AdEvent adEvent) {
|
private void handleAdEvent(AdEvent adEvent) {
|
||||||
|
@ -112,10 +112,13 @@ public final class TracksInfo implements Bundleable {
|
|||||||
/**
|
/**
|
||||||
* Returns if a track in a {@link TrackGroup} is selected for playback.
|
* Returns if a track in a {@link TrackGroup} is selected for playback.
|
||||||
*
|
*
|
||||||
* <p>Multiple tracks of a track group may be selected, in which case the the active one
|
* <p>Multiple tracks of a track group may be selected. This is common in adaptive streaming,
|
||||||
* (currently playing) is undefined. This is common in adaptive streaming, where multiple tracks
|
* where multiple tracks of different quality are selected and the player switches between them
|
||||||
* of different quality are selected and the active one changes depending on the network and the
|
* depending on the network and the {@link TrackSelectionParameters}.
|
||||||
* {@link TrackSelectionParameters}.
|
*
|
||||||
|
* <p>While this class doesn't provide which selected track is currently playing, some player
|
||||||
|
* implementations have ways of getting such information. For example ExoPlayer provides this
|
||||||
|
* information in {@code ExoTrackSelection.getSelectedFormat}.
|
||||||
*
|
*
|
||||||
* @param trackIndex The index of the track in the {@link TrackGroup}.
|
* @param trackIndex The index of the track in the {@link TrackGroup}.
|
||||||
* @return true if the track is selected, false otherwise.
|
* @return true if the track is selected, false otherwise.
|
||||||
|
@ -27,6 +27,7 @@ import com.google.android.exoplayer2.PlaybackException;
|
|||||||
import com.google.android.exoplayer2.Player;
|
import com.google.android.exoplayer2.Player;
|
||||||
import com.google.android.exoplayer2.Timeline;
|
import com.google.android.exoplayer2.Timeline;
|
||||||
import com.google.android.exoplayer2.Timeline.Period;
|
import com.google.android.exoplayer2.Timeline.Period;
|
||||||
|
import com.google.android.exoplayer2.TracksInfo;
|
||||||
import com.google.android.exoplayer2.analytics.PlaybackStats.EventTimeAndException;
|
import com.google.android.exoplayer2.analytics.PlaybackStats.EventTimeAndException;
|
||||||
import com.google.android.exoplayer2.analytics.PlaybackStats.EventTimeAndFormat;
|
import com.google.android.exoplayer2.analytics.PlaybackStats.EventTimeAndFormat;
|
||||||
import com.google.android.exoplayer2.analytics.PlaybackStats.EventTimeAndPlaybackState;
|
import com.google.android.exoplayer2.analytics.PlaybackStats.EventTimeAndPlaybackState;
|
||||||
@ -34,9 +35,7 @@ import com.google.android.exoplayer2.analytics.PlaybackStats.PlaybackState;
|
|||||||
import com.google.android.exoplayer2.source.LoadEventInfo;
|
import com.google.android.exoplayer2.source.LoadEventInfo;
|
||||||
import com.google.android.exoplayer2.source.MediaLoadData;
|
import com.google.android.exoplayer2.source.MediaLoadData;
|
||||||
import com.google.android.exoplayer2.source.MediaSource.MediaPeriodId;
|
import com.google.android.exoplayer2.source.MediaSource.MediaPeriodId;
|
||||||
import com.google.android.exoplayer2.trackselection.TrackSelection;
|
|
||||||
import com.google.android.exoplayer2.util.Assertions;
|
import com.google.android.exoplayer2.util.Assertions;
|
||||||
import com.google.android.exoplayer2.util.MimeTypes;
|
|
||||||
import com.google.android.exoplayer2.util.Util;
|
import com.google.android.exoplayer2.util.Util;
|
||||||
import com.google.android.exoplayer2.video.VideoSize;
|
import com.google.android.exoplayer2.video.VideoSize;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
@ -523,23 +522,11 @@ public final class PlaybackStatsListener
|
|||||||
hasFatalError = false;
|
hasFatalError = false;
|
||||||
}
|
}
|
||||||
if (isForeground && !isInterruptedByAd) {
|
if (isForeground && !isInterruptedByAd) {
|
||||||
boolean videoEnabled = false;
|
TracksInfo currentTracksInfo = player.getCurrentTracksInfo();
|
||||||
boolean audioEnabled = false;
|
if (!currentTracksInfo.isTypeSelected(C.TRACK_TYPE_VIDEO)) {
|
||||||
for (TrackSelection trackSelection : player.getCurrentTrackSelections().getAll()) {
|
|
||||||
if (trackSelection != null && trackSelection.length() > 0) {
|
|
||||||
@C.TrackType
|
|
||||||
int trackType = MimeTypes.getTrackType(trackSelection.getFormat(0).sampleMimeType);
|
|
||||||
if (trackType == C.TRACK_TYPE_VIDEO) {
|
|
||||||
videoEnabled = true;
|
|
||||||
} else if (trackType == C.TRACK_TYPE_AUDIO) {
|
|
||||||
audioEnabled = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!videoEnabled) {
|
|
||||||
maybeUpdateVideoFormat(eventTime, /* newFormat= */ null);
|
maybeUpdateVideoFormat(eventTime, /* newFormat= */ null);
|
||||||
}
|
}
|
||||||
if (!audioEnabled) {
|
if (!currentTracksInfo.isTypeSelected(C.TRACK_TYPE_AUDIO)) {
|
||||||
maybeUpdateAudioFormat(eventTime, /* newFormat= */ null);
|
maybeUpdateAudioFormat(eventTime, /* newFormat= */ null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -17,12 +17,21 @@ package com.google.android.exoplayer2.trackselection;
|
|||||||
|
|
||||||
import android.os.SystemClock;
|
import android.os.SystemClock;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
|
import com.google.android.exoplayer2.C;
|
||||||
|
import com.google.android.exoplayer2.TracksInfo;
|
||||||
|
import com.google.android.exoplayer2.TracksInfo.TrackGroupInfo;
|
||||||
|
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.trackselection.DefaultTrackSelector.SelectionOverride;
|
import com.google.android.exoplayer2.trackselection.DefaultTrackSelector.SelectionOverride;
|
||||||
import com.google.android.exoplayer2.trackselection.ExoTrackSelection.Definition;
|
import com.google.android.exoplayer2.trackselection.ExoTrackSelection.Definition;
|
||||||
|
import com.google.android.exoplayer2.trackselection.TrackSelectionParameters.TrackSelectionOverride;
|
||||||
import com.google.android.exoplayer2.upstream.LoadErrorHandlingPolicy;
|
import com.google.android.exoplayer2.upstream.LoadErrorHandlingPolicy;
|
||||||
import com.google.android.exoplayer2.util.MimeTypes;
|
import com.google.android.exoplayer2.util.MimeTypes;
|
||||||
|
import com.google.common.collect.ImmutableList;
|
||||||
|
import com.google.common.collect.ImmutableMap;
|
||||||
|
import java.util.Map;
|
||||||
import org.checkerframework.checker.nullness.compatqual.NullableType;
|
import org.checkerframework.checker.nullness.compatqual.NullableType;
|
||||||
|
import org.checkerframework.dataflow.qual.Pure;
|
||||||
|
|
||||||
/** Track selection related utility methods. */
|
/** Track selection related utility methods. */
|
||||||
public final class TrackSelectionUtil {
|
public final class TrackSelectionUtil {
|
||||||
@ -101,22 +110,6 @@ public final class TrackSelectionUtil {
|
|||||||
return builder.build();
|
return builder.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Returns if a {@link TrackSelectionArray} has at least one track of the given type. */
|
|
||||||
public static boolean hasTrackOfType(TrackSelectionArray trackSelections, int trackType) {
|
|
||||||
for (int i = 0; i < trackSelections.length; i++) {
|
|
||||||
@Nullable TrackSelection trackSelection = trackSelections.get(i);
|
|
||||||
if (trackSelection == null) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
for (int j = 0; j < trackSelection.length(); j++) {
|
|
||||||
if (MimeTypes.getTrackType(trackSelection.getFormat(j).sampleMimeType) == trackType) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the {@link LoadErrorHandlingPolicy.FallbackOptions} with the tracks of the given {@link
|
* Returns the {@link LoadErrorHandlingPolicy.FallbackOptions} with the tracks of the given {@link
|
||||||
* ExoTrackSelection} and with a single location option indicating that there are no alternative
|
* ExoTrackSelection} and with a single location option indicating that there are no alternative
|
||||||
@ -141,4 +134,67 @@ public final class TrackSelectionUtil {
|
|||||||
numberOfTracks,
|
numberOfTracks,
|
||||||
numberOfExcludedTracks);
|
numberOfExcludedTracks);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Forces tracks in a {@link TrackGroup} to be the only ones selected for a {@link C.TrackType}.
|
||||||
|
* No other tracks of that type will be selectable. If the forced tracks are not supported, then
|
||||||
|
* no tracks of that type will be selected.
|
||||||
|
*
|
||||||
|
* @param trackSelectionOverrides The current {@link TrackSelectionOverride overrides}.
|
||||||
|
* @param tracksInfo The current {@link TracksInfo}.
|
||||||
|
* @param forcedTrackGroupIndex The index of the {@link TrackGroup} in {@code tracksInfo} that
|
||||||
|
* should have its track selected.
|
||||||
|
* @param forcedTrackSelectionOverride The tracks to force selection of.
|
||||||
|
* @return The updated {@link TrackSelectionOverride overrides}.
|
||||||
|
*/
|
||||||
|
@Pure
|
||||||
|
public static ImmutableMap<TrackGroup, TrackSelectionOverride> forceTrackSelection(
|
||||||
|
ImmutableMap<TrackGroup, TrackSelectionOverride> trackSelectionOverrides,
|
||||||
|
TracksInfo tracksInfo,
|
||||||
|
int forcedTrackGroupIndex,
|
||||||
|
TrackSelectionOverride forcedTrackSelectionOverride) {
|
||||||
|
@C.TrackType
|
||||||
|
int trackType = tracksInfo.getTrackGroupInfos().get(forcedTrackGroupIndex).getTrackType();
|
||||||
|
ImmutableMap.Builder<TrackGroup, TrackSelectionOverride> overridesBuilder =
|
||||||
|
new ImmutableMap.Builder<>();
|
||||||
|
// Maintain overrides for the other track types.
|
||||||
|
for (Map.Entry<TrackGroup, TrackSelectionOverride> entry : trackSelectionOverrides.entrySet()) {
|
||||||
|
if (MimeTypes.getTrackType(entry.getKey().getFormat(0).sampleMimeType) != trackType) {
|
||||||
|
overridesBuilder.put(entry);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ImmutableList<TrackGroupInfo> trackGroupInfos = tracksInfo.getTrackGroupInfos();
|
||||||
|
for (int i = 0; i < trackGroupInfos.size(); i++) {
|
||||||
|
TrackGroup trackGroup = trackGroupInfos.get(i).getTrackGroup();
|
||||||
|
if (i == forcedTrackGroupIndex) {
|
||||||
|
overridesBuilder.put(trackGroup, forcedTrackSelectionOverride);
|
||||||
|
} else {
|
||||||
|
overridesBuilder.put(trackGroup, TrackSelectionOverride.DISABLE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return overridesBuilder.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes all {@link TrackSelectionOverride overrides} associated with {@link TrackGroup
|
||||||
|
* TrackGroups} of type {@code trackType}.
|
||||||
|
*
|
||||||
|
* @param trackType The {@link C.TrackType} of all overrides to remove.
|
||||||
|
* @param trackSelectionOverrides The current {@link TrackSelectionOverride overrides}.
|
||||||
|
* @return The updated {@link TrackSelectionOverride overrides}.
|
||||||
|
*/
|
||||||
|
@Pure
|
||||||
|
public static ImmutableMap<TrackGroup, TrackSelectionOverride>
|
||||||
|
clearTrackSelectionOverridesForType(
|
||||||
|
@C.TrackType int trackType,
|
||||||
|
ImmutableMap<TrackGroup, TrackSelectionOverride> trackSelectionOverrides) {
|
||||||
|
ImmutableMap.Builder<TrackGroup, TrackSelectionOverride> overridesBuilder =
|
||||||
|
ImmutableMap.builder();
|
||||||
|
for (Map.Entry<TrackGroup, TrackSelectionOverride> entry : trackSelectionOverrides.entrySet()) {
|
||||||
|
if (MimeTypes.getTrackType(entry.getKey().getFormat(0).sampleMimeType) != trackType) {
|
||||||
|
overridesBuilder.put(entry);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return overridesBuilder.build();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -7349,7 +7349,7 @@ public final class ExoPlayerTest {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
AtomicReference<Timeline> timelineAfterError = new AtomicReference<>();
|
AtomicReference<Timeline> timelineAfterError = new AtomicReference<>();
|
||||||
AtomicReference<TrackGroupArray> trackGroupsAfterError = new AtomicReference<>();
|
AtomicReference<TracksInfo> trackInfosAfterError = new AtomicReference<>();
|
||||||
AtomicReference<TrackSelectionArray> trackSelectionsAfterError = new AtomicReference<>();
|
AtomicReference<TrackSelectionArray> trackSelectionsAfterError = new AtomicReference<>();
|
||||||
AtomicInteger windowIndexAfterError = new AtomicInteger();
|
AtomicInteger windowIndexAfterError = new AtomicInteger();
|
||||||
ActionSchedule actionSchedule =
|
ActionSchedule actionSchedule =
|
||||||
@ -7363,7 +7363,7 @@ public final class ExoPlayerTest {
|
|||||||
@Override
|
@Override
|
||||||
public void onPlayerError(EventTime eventTime, PlaybackException error) {
|
public void onPlayerError(EventTime eventTime, PlaybackException error) {
|
||||||
timelineAfterError.set(player.getCurrentTimeline());
|
timelineAfterError.set(player.getCurrentTimeline());
|
||||||
trackGroupsAfterError.set(player.getCurrentTrackGroups());
|
trackInfosAfterError.set(player.getCurrentTracksInfo());
|
||||||
trackSelectionsAfterError.set(player.getCurrentTrackSelections());
|
trackSelectionsAfterError.set(player.getCurrentTrackSelections());
|
||||||
windowIndexAfterError.set(player.getCurrentWindowIndex());
|
windowIndexAfterError.set(player.getCurrentWindowIndex());
|
||||||
}
|
}
|
||||||
@ -7393,8 +7393,8 @@ public final class ExoPlayerTest {
|
|||||||
|
|
||||||
assertThat(timelineAfterError.get().getWindowCount()).isEqualTo(1);
|
assertThat(timelineAfterError.get().getWindowCount()).isEqualTo(1);
|
||||||
assertThat(windowIndexAfterError.get()).isEqualTo(0);
|
assertThat(windowIndexAfterError.get()).isEqualTo(0);
|
||||||
assertThat(trackGroupsAfterError.get().length).isEqualTo(1);
|
assertThat(trackInfosAfterError.get().getTrackGroupInfos()).hasSize(1);
|
||||||
assertThat(trackGroupsAfterError.get().get(0).getFormat(0))
|
assertThat(trackInfosAfterError.get().getTrackGroupInfos().get(0).getTrackGroup().getFormat(0))
|
||||||
.isEqualTo(ExoPlayerTestRunner.AUDIO_FORMAT);
|
.isEqualTo(ExoPlayerTestRunner.AUDIO_FORMAT);
|
||||||
assertThat(trackSelectionsAfterError.get().get(0)).isNull(); // Video renderer.
|
assertThat(trackSelectionsAfterError.get().get(0)).isNull(); // Video renderer.
|
||||||
assertThat(trackSelectionsAfterError.get().get(1)).isNotNull(); // Audio renderer.
|
assertThat(trackSelectionsAfterError.get().get(1)).isNotNull(); // Audio renderer.
|
||||||
|
@ -47,7 +47,6 @@ import androidx.annotation.RequiresApi;
|
|||||||
import androidx.core.content.ContextCompat;
|
import androidx.core.content.ContextCompat;
|
||||||
import com.google.android.exoplayer2.C;
|
import com.google.android.exoplayer2.C;
|
||||||
import com.google.android.exoplayer2.ControlDispatcher;
|
import com.google.android.exoplayer2.ControlDispatcher;
|
||||||
import com.google.android.exoplayer2.Format;
|
|
||||||
import com.google.android.exoplayer2.ForwardingPlayer;
|
import com.google.android.exoplayer2.ForwardingPlayer;
|
||||||
import com.google.android.exoplayer2.MediaMetadata;
|
import com.google.android.exoplayer2.MediaMetadata;
|
||||||
import com.google.android.exoplayer2.PlaybackException;
|
import com.google.android.exoplayer2.PlaybackException;
|
||||||
@ -57,12 +56,9 @@ import com.google.android.exoplayer2.Timeline;
|
|||||||
import com.google.android.exoplayer2.Timeline.Period;
|
import com.google.android.exoplayer2.Timeline.Period;
|
||||||
import com.google.android.exoplayer2.TracksInfo;
|
import com.google.android.exoplayer2.TracksInfo;
|
||||||
import com.google.android.exoplayer2.text.Cue;
|
import com.google.android.exoplayer2.text.Cue;
|
||||||
import com.google.android.exoplayer2.trackselection.TrackSelection;
|
|
||||||
import com.google.android.exoplayer2.trackselection.TrackSelectionArray;
|
|
||||||
import com.google.android.exoplayer2.ui.AspectRatioFrameLayout.ResizeMode;
|
import com.google.android.exoplayer2.ui.AspectRatioFrameLayout.ResizeMode;
|
||||||
import com.google.android.exoplayer2.util.Assertions;
|
import com.google.android.exoplayer2.util.Assertions;
|
||||||
import com.google.android.exoplayer2.util.ErrorMessageProvider;
|
import com.google.android.exoplayer2.util.ErrorMessageProvider;
|
||||||
import com.google.android.exoplayer2.util.MimeTypes;
|
|
||||||
import com.google.android.exoplayer2.util.RepeatModeUtil;
|
import com.google.android.exoplayer2.util.RepeatModeUtil;
|
||||||
import com.google.android.exoplayer2.util.Util;
|
import com.google.android.exoplayer2.util.Util;
|
||||||
import com.google.android.exoplayer2.video.VideoSize;
|
import com.google.android.exoplayer2.video.VideoSize;
|
||||||
@ -1256,7 +1252,9 @@ public class PlayerView extends FrameLayout implements AdViewProvider {
|
|||||||
|
|
||||||
private void updateForCurrentTrackSelections(boolean isNewPlayer) {
|
private void updateForCurrentTrackSelections(boolean isNewPlayer) {
|
||||||
@Nullable Player player = this.player;
|
@Nullable Player player = this.player;
|
||||||
if (player == null || player.getCurrentTrackGroups().isEmpty()) {
|
if (player == null
|
||||||
|
|| !player.isCommandAvailable(Player.COMMAND_GET_TRACK_INFOS)
|
||||||
|
|| player.getCurrentTracksInfo().getTrackGroupInfos().isEmpty()) {
|
||||||
if (!keepContentOnPlayerReset) {
|
if (!keepContentOnPlayerReset) {
|
||||||
hideArtwork();
|
hideArtwork();
|
||||||
closeShutter();
|
closeShutter();
|
||||||
@ -1268,22 +1266,12 @@ public class PlayerView extends FrameLayout implements AdViewProvider {
|
|||||||
// Hide any video from the previous player.
|
// Hide any video from the previous player.
|
||||||
closeShutter();
|
closeShutter();
|
||||||
}
|
}
|
||||||
|
if (player.getCurrentTracksInfo().isTypeSelected(C.TRACK_TYPE_VIDEO)) {
|
||||||
TrackSelectionArray trackSelections = player.getCurrentTrackSelections();
|
|
||||||
for (int i = 0; i < trackSelections.length; i++) {
|
|
||||||
@Nullable TrackSelection trackSelection = trackSelections.get(i);
|
|
||||||
if (trackSelection != null) {
|
|
||||||
for (int j = 0; j < trackSelection.length(); j++) {
|
|
||||||
Format format = trackSelection.getFormat(j);
|
|
||||||
if (MimeTypes.getTrackType(format.sampleMimeType) == C.TRACK_TYPE_VIDEO) {
|
|
||||||
// Video enabled, so artwork must be hidden. If the shutter is closed, it will be opened
|
// Video enabled, so artwork must be hidden. If the shutter is closed, it will be opened
|
||||||
// in onRenderedFirstFrame().
|
// in onRenderedFirstFrame().
|
||||||
hideArtwork();
|
hideArtwork();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Video disabled so the shutter must be closed.
|
// Video disabled so the shutter must be closed.
|
||||||
closeShutter();
|
closeShutter();
|
||||||
@ -1518,7 +1506,7 @@ public class PlayerView extends FrameLayout implements AdViewProvider {
|
|||||||
Timeline timeline = player.getCurrentTimeline();
|
Timeline timeline = player.getCurrentTimeline();
|
||||||
if (timeline.isEmpty()) {
|
if (timeline.isEmpty()) {
|
||||||
lastPeriodUidWithTracks = null;
|
lastPeriodUidWithTracks = null;
|
||||||
} else if (!player.getCurrentTrackGroups().isEmpty()) {
|
} else if (!player.getCurrentTracksInfo().getTrackGroupInfos().isEmpty()) {
|
||||||
lastPeriodUidWithTracks =
|
lastPeriodUidWithTracks =
|
||||||
timeline.getPeriod(player.getCurrentPeriodIndex(), period, /* setIds= */ true).uid;
|
timeline.getPeriod(player.getCurrentPeriodIndex(), period, /* setIds= */ true).uid;
|
||||||
} else if (lastPeriodUidWithTracks != null) {
|
} else if (lastPeriodUidWithTracks != null) {
|
||||||
|
@ -32,6 +32,8 @@ import static com.google.android.exoplayer2.Player.EVENT_SEEK_FORWARD_INCREMENT_
|
|||||||
import static com.google.android.exoplayer2.Player.EVENT_SHUFFLE_MODE_ENABLED_CHANGED;
|
import static com.google.android.exoplayer2.Player.EVENT_SHUFFLE_MODE_ENABLED_CHANGED;
|
||||||
import static com.google.android.exoplayer2.Player.EVENT_TIMELINE_CHANGED;
|
import static com.google.android.exoplayer2.Player.EVENT_TIMELINE_CHANGED;
|
||||||
import static com.google.android.exoplayer2.Player.EVENT_TRACKS_CHANGED;
|
import static com.google.android.exoplayer2.Player.EVENT_TRACKS_CHANGED;
|
||||||
|
import static com.google.android.exoplayer2.trackselection.TrackSelectionUtil.clearTrackSelectionOverridesForType;
|
||||||
|
import static com.google.android.exoplayer2.trackselection.TrackSelectionUtil.forceTrackSelection;
|
||||||
import static com.google.android.exoplayer2.util.Assertions.checkNotNull;
|
import static com.google.android.exoplayer2.util.Assertions.checkNotNull;
|
||||||
|
|
||||||
import android.annotation.SuppressLint;
|
import android.annotation.SuppressLint;
|
||||||
@ -59,7 +61,6 @@ import androidx.recyclerview.widget.RecyclerView;
|
|||||||
import com.google.android.exoplayer2.C;
|
import com.google.android.exoplayer2.C;
|
||||||
import com.google.android.exoplayer2.ControlDispatcher;
|
import com.google.android.exoplayer2.ControlDispatcher;
|
||||||
import com.google.android.exoplayer2.DefaultControlDispatcher;
|
import com.google.android.exoplayer2.DefaultControlDispatcher;
|
||||||
import com.google.android.exoplayer2.ExoPlayer;
|
|
||||||
import com.google.android.exoplayer2.ExoPlayerLibraryInfo;
|
import com.google.android.exoplayer2.ExoPlayerLibraryInfo;
|
||||||
import com.google.android.exoplayer2.Format;
|
import com.google.android.exoplayer2.Format;
|
||||||
import com.google.android.exoplayer2.ForwardingPlayer;
|
import com.google.android.exoplayer2.ForwardingPlayer;
|
||||||
@ -67,24 +68,23 @@ import com.google.android.exoplayer2.Player;
|
|||||||
import com.google.android.exoplayer2.Player.Events;
|
import com.google.android.exoplayer2.Player.Events;
|
||||||
import com.google.android.exoplayer2.Player.State;
|
import com.google.android.exoplayer2.Player.State;
|
||||||
import com.google.android.exoplayer2.Timeline;
|
import com.google.android.exoplayer2.Timeline;
|
||||||
|
import com.google.android.exoplayer2.TracksInfo;
|
||||||
|
import com.google.android.exoplayer2.TracksInfo.TrackGroupInfo;
|
||||||
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.trackselection.TrackSelectionParameters;
|
||||||
import com.google.android.exoplayer2.trackselection.DefaultTrackSelector;
|
import com.google.android.exoplayer2.trackselection.TrackSelectionParameters.TrackSelectionOverride;
|
||||||
import com.google.android.exoplayer2.trackselection.DefaultTrackSelector.ParametersBuilder;
|
|
||||||
import com.google.android.exoplayer2.trackselection.DefaultTrackSelector.SelectionOverride;
|
|
||||||
import com.google.android.exoplayer2.trackselection.MappingTrackSelector.MappedTrackInfo;
|
|
||||||
import com.google.android.exoplayer2.trackselection.TrackSelection;
|
|
||||||
import com.google.android.exoplayer2.trackselection.TrackSelectionArray;
|
|
||||||
import com.google.android.exoplayer2.trackselection.TrackSelector;
|
|
||||||
import com.google.android.exoplayer2.util.Assertions;
|
import com.google.android.exoplayer2.util.Assertions;
|
||||||
import com.google.android.exoplayer2.util.RepeatModeUtil;
|
import com.google.android.exoplayer2.util.RepeatModeUtil;
|
||||||
import com.google.android.exoplayer2.util.Util;
|
import com.google.android.exoplayer2.util.Util;
|
||||||
|
import com.google.common.collect.ImmutableMap;
|
||||||
|
import com.google.common.collect.ImmutableSet;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.Formatter;
|
import java.util.Formatter;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
|
import java.util.Map;
|
||||||
import java.util.concurrent.CopyOnWriteArrayList;
|
import java.util.concurrent.CopyOnWriteArrayList;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -437,9 +437,8 @@ public class StyledPlayerControlView extends FrameLayout {
|
|||||||
private boolean needToHideBars;
|
private boolean needToHideBars;
|
||||||
private int settingsWindowMargin;
|
private int settingsWindowMargin;
|
||||||
|
|
||||||
@Nullable private DefaultTrackSelector trackSelector;
|
private TextTrackSelectionAdapter textTrackSelectionAdapter;
|
||||||
private TrackSelectionAdapter textTrackSelectionAdapter;
|
private AudioTrackSelectionAdapter audioTrackSelectionAdapter;
|
||||||
private TrackSelectionAdapter audioTrackSelectionAdapter;
|
|
||||||
// TODO(insun): Add setTrackNameProvider to use customized track name provider.
|
// TODO(insun): Add setTrackNameProvider to use customized track name provider.
|
||||||
private TrackNameProvider trackNameProvider;
|
private TrackNameProvider trackNameProvider;
|
||||||
|
|
||||||
@ -764,14 +763,6 @@ public class StyledPlayerControlView extends FrameLayout {
|
|||||||
if (player instanceof ForwardingPlayer) {
|
if (player instanceof ForwardingPlayer) {
|
||||||
player = ((ForwardingPlayer) player).getWrappedPlayer();
|
player = ((ForwardingPlayer) player).getWrappedPlayer();
|
||||||
}
|
}
|
||||||
if (player instanceof ExoPlayer) {
|
|
||||||
TrackSelector trackSelector = ((ExoPlayer) player).getTrackSelector();
|
|
||||||
if (trackSelector instanceof DefaultTrackSelector) {
|
|
||||||
this.trackSelector = (DefaultTrackSelector) trackSelector;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
this.trackSelector = null;
|
|
||||||
}
|
|
||||||
updateAll();
|
updateAll();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -818,7 +809,7 @@ public class StyledPlayerControlView extends FrameLayout {
|
|||||||
* @param listener The listener to be notified about visibility changes.
|
* @param listener The listener to be notified about visibility changes.
|
||||||
*/
|
*/
|
||||||
public void addVisibilityListener(VisibilityListener listener) {
|
public void addVisibilityListener(VisibilityListener listener) {
|
||||||
Assertions.checkNotNull(listener);
|
checkNotNull(listener);
|
||||||
visibilityListeners.add(listener);
|
visibilityListeners.add(listener);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1254,58 +1245,46 @@ public class StyledPlayerControlView extends FrameLayout {
|
|||||||
private void initTrackSelectionAdapter() {
|
private void initTrackSelectionAdapter() {
|
||||||
textTrackSelectionAdapter.clear();
|
textTrackSelectionAdapter.clear();
|
||||||
audioTrackSelectionAdapter.clear();
|
audioTrackSelectionAdapter.clear();
|
||||||
if (player == null || trackSelector == null) {
|
if (player == null
|
||||||
|
|| !player.isCommandAvailable(Player.COMMAND_GET_TRACK_INFOS)
|
||||||
|
|| !player.isCommandAvailable(Player.COMMAND_SET_TRACK_SELECTION_PARAMETERS)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
DefaultTrackSelector trackSelector = this.trackSelector;
|
TracksInfo tracksInfo = player.getCurrentTracksInfo();
|
||||||
@Nullable MappedTrackInfo mappedTrackInfo = trackSelector.getCurrentMappedTrackInfo();
|
List<TrackGroupInfo> trackGroupInfos = tracksInfo.getTrackGroupInfos();
|
||||||
if (mappedTrackInfo == null) {
|
if (trackGroupInfos.isEmpty()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
List<TrackInfo> textTracks = new ArrayList<>();
|
List<TrackInformation> textTracks = new ArrayList<>();
|
||||||
List<TrackInfo> audioTracks = new ArrayList<>();
|
List<TrackInformation> audioTracks = new ArrayList<>();
|
||||||
List<Integer> textRendererIndices = new ArrayList<>();
|
for (int trackGroupIndex = 0; trackGroupIndex < trackGroupInfos.size(); trackGroupIndex++) {
|
||||||
List<Integer> audioRendererIndices = new ArrayList<>();
|
TrackGroupInfo trackGroupInfo = trackGroupInfos.get(trackGroupIndex);
|
||||||
for (int rendererIndex = 0;
|
if (!trackGroupInfo.isSupported()) {
|
||||||
rendererIndex < mappedTrackInfo.getRendererCount();
|
continue;
|
||||||
rendererIndex++) {
|
}
|
||||||
if (mappedTrackInfo.getRendererType(rendererIndex) == C.TRACK_TYPE_TEXT
|
if (trackGroupInfo.getTrackType() == C.TRACK_TYPE_TEXT
|
||||||
&& controlViewLayoutManager.getShowButton(subtitleButton)) {
|
&& controlViewLayoutManager.getShowButton(subtitleButton)) {
|
||||||
// Get TrackSelection at the corresponding renderer index.
|
// Get TrackSelection at the corresponding renderer index.
|
||||||
gatherTrackInfosForAdapter(mappedTrackInfo, rendererIndex, textTracks);
|
gatherTrackInfosForAdapter(tracksInfo, trackGroupIndex, textTracks);
|
||||||
textRendererIndices.add(rendererIndex);
|
} else if (trackGroupInfo.getTrackType() == C.TRACK_TYPE_AUDIO) {
|
||||||
} else if (mappedTrackInfo.getRendererType(rendererIndex) == C.TRACK_TYPE_AUDIO) {
|
gatherTrackInfosForAdapter(tracksInfo, trackGroupIndex, audioTracks);
|
||||||
gatherTrackInfosForAdapter(mappedTrackInfo, rendererIndex, audioTracks);
|
|
||||||
audioRendererIndices.add(rendererIndex);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
textTrackSelectionAdapter.init(textRendererIndices, textTracks, mappedTrackInfo);
|
textTrackSelectionAdapter.init(textTracks);
|
||||||
audioTrackSelectionAdapter.init(audioRendererIndices, audioTracks, mappedTrackInfo);
|
audioTrackSelectionAdapter.init(audioTracks);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void gatherTrackInfosForAdapter(
|
private void gatherTrackInfosForAdapter(
|
||||||
MappedTrackInfo mappedTrackInfo, int rendererIndex, List<TrackInfo> tracks) {
|
TracksInfo tracksInfo, int trackGroupIndex, List<TrackInformation> tracks) {
|
||||||
TrackGroupArray trackGroupArray = mappedTrackInfo.getTrackGroups(rendererIndex);
|
|
||||||
|
|
||||||
TrackSelectionArray trackSelections = checkNotNull(player).getCurrentTrackSelections();
|
TrackGroupInfo trackGroupInfo = tracksInfo.getTrackGroupInfos().get(trackGroupIndex);
|
||||||
@Nullable TrackSelection trackSelection = trackSelections.get(rendererIndex);
|
TrackGroup trackGroup = trackGroupInfo.getTrackGroup();
|
||||||
|
|
||||||
for (int groupIndex = 0; groupIndex < trackGroupArray.length; groupIndex++) {
|
|
||||||
TrackGroup trackGroup = trackGroupArray.get(groupIndex);
|
|
||||||
for (int trackIndex = 0; trackIndex < trackGroup.length; trackIndex++) {
|
for (int trackIndex = 0; trackIndex < trackGroup.length; trackIndex++) {
|
||||||
Format format = trackGroup.getFormat(trackIndex);
|
Format format = trackGroup.getFormat(trackIndex);
|
||||||
if (mappedTrackInfo.getTrackSupport(rendererIndex, groupIndex, trackIndex)
|
if (trackGroupInfo.isTrackSupported(trackIndex)) {
|
||||||
== C.FORMAT_HANDLED) {
|
|
||||||
boolean trackIsSelected =
|
|
||||||
trackSelection != null && trackSelection.indexOf(format) != C.INDEX_UNSET;
|
|
||||||
tracks.add(
|
tracks.add(
|
||||||
new TrackInfo(
|
new TrackInformation(
|
||||||
rendererIndex,
|
tracksInfo, trackGroupIndex, trackIndex, trackNameProvider.getTrackName(format)));
|
||||||
groupIndex,
|
|
||||||
trackIndex,
|
|
||||||
trackNameProvider.getTrackName(format),
|
|
||||||
trackIsSelected));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1988,33 +1967,36 @@ public class StyledPlayerControlView extends FrameLayout {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static final class TrackInfo {
|
private static final class TrackInformation {
|
||||||
|
|
||||||
public final int rendererIndex;
|
private TracksInfo tracksInfo;
|
||||||
public final int groupIndex;
|
private int trackGroupIndex;
|
||||||
|
public final TrackGroupInfo trackGroupInfo;
|
||||||
|
public final TrackGroup trackGroup;
|
||||||
public final int trackIndex;
|
public final int trackIndex;
|
||||||
public final String trackName;
|
public final String trackName;
|
||||||
public final boolean selected;
|
|
||||||
|
|
||||||
public TrackInfo(
|
public TrackInformation(
|
||||||
int rendererIndex, int groupIndex, int trackIndex, String trackName, boolean selected) {
|
TracksInfo tracksInfo, int trackGroupIndex, int trackIndex, String trackName) {
|
||||||
this.rendererIndex = rendererIndex;
|
this.tracksInfo = tracksInfo;
|
||||||
this.groupIndex = groupIndex;
|
this.trackGroupIndex = trackGroupIndex;
|
||||||
|
this.trackGroupInfo = tracksInfo.getTrackGroupInfos().get(trackGroupIndex);
|
||||||
|
this.trackGroup = trackGroupInfo.getTrackGroup();
|
||||||
this.trackIndex = trackIndex;
|
this.trackIndex = trackIndex;
|
||||||
this.trackName = trackName;
|
this.trackName = trackName;
|
||||||
this.selected = selected;
|
}
|
||||||
|
|
||||||
|
public boolean isSelected() {
|
||||||
|
return trackGroupInfo.isTrackSelected(trackIndex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private final class TextTrackSelectionAdapter extends TrackSelectionAdapter {
|
private final class TextTrackSelectionAdapter extends TrackSelectionAdapter {
|
||||||
@Override
|
@Override
|
||||||
public void init(
|
public void init(List<TrackInformation> trackInformations) {
|
||||||
List<Integer> rendererIndices,
|
|
||||||
List<TrackInfo> trackInfos,
|
|
||||||
MappedTrackInfo mappedTrackInfo) {
|
|
||||||
boolean subtitleIsOn = false;
|
boolean subtitleIsOn = false;
|
||||||
for (int i = 0; i < trackInfos.size(); i++) {
|
for (int i = 0; i < trackInformations.size(); i++) {
|
||||||
if (trackInfos.get(i).selected) {
|
if (trackInformations.get(i).isSelected()) {
|
||||||
subtitleIsOn = true;
|
subtitleIsOn = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -2026,9 +2008,7 @@ public class StyledPlayerControlView extends FrameLayout {
|
|||||||
subtitleButton.setContentDescription(
|
subtitleButton.setContentDescription(
|
||||||
subtitleIsOn ? subtitleOnContentDescription : subtitleOffContentDescription);
|
subtitleIsOn ? subtitleOnContentDescription : subtitleOffContentDescription);
|
||||||
}
|
}
|
||||||
this.rendererIndices = rendererIndices;
|
this.tracks = trackInformations;
|
||||||
this.tracks = trackInfos;
|
|
||||||
this.mappedTrackInfo = mappedTrackInfo;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -2037,7 +2017,7 @@ public class StyledPlayerControlView extends FrameLayout {
|
|||||||
holder.textView.setText(R.string.exo_track_selection_none);
|
holder.textView.setText(R.string.exo_track_selection_none);
|
||||||
boolean isTrackSelectionOff = true;
|
boolean isTrackSelectionOff = true;
|
||||||
for (int i = 0; i < tracks.size(); i++) {
|
for (int i = 0; i < tracks.size(); i++) {
|
||||||
if (tracks.get(i).selected) {
|
if (tracks.get(i).isSelected()) {
|
||||||
isTrackSelectionOff = false;
|
isTrackSelectionOff = false;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -2045,16 +2025,18 @@ public class StyledPlayerControlView extends FrameLayout {
|
|||||||
holder.checkView.setVisibility(isTrackSelectionOff ? VISIBLE : INVISIBLE);
|
holder.checkView.setVisibility(isTrackSelectionOff ? VISIBLE : INVISIBLE);
|
||||||
holder.itemView.setOnClickListener(
|
holder.itemView.setOnClickListener(
|
||||||
v -> {
|
v -> {
|
||||||
if (trackSelector != null) {
|
if (player != null) {
|
||||||
ParametersBuilder parametersBuilder = trackSelector.getParameters().buildUpon();
|
TrackSelectionParameters trackSelectionParameters =
|
||||||
for (int i = 0; i < rendererIndices.size(); i++) {
|
player.getTrackSelectionParameters();
|
||||||
int rendererIndex = rendererIndices.get(i);
|
player.setTrackSelectionParameters(
|
||||||
parametersBuilder =
|
trackSelectionParameters
|
||||||
parametersBuilder
|
.buildUpon()
|
||||||
.clearSelectionOverrides(rendererIndex)
|
.setDisabledTrackTypes(
|
||||||
.setRendererDisabled(rendererIndex, true);
|
new ImmutableSet.Builder<@C.TrackType Integer>()
|
||||||
}
|
.addAll(trackSelectionParameters.disabledTrackTypes)
|
||||||
checkNotNull(trackSelector).setParameters(parametersBuilder);
|
.add(C.TRACK_TYPE_TEXT)
|
||||||
|
.build())
|
||||||
|
.build());
|
||||||
settingsWindow.dismiss();
|
settingsWindow.dismiss();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -2064,8 +2046,8 @@ public class StyledPlayerControlView extends FrameLayout {
|
|||||||
public void onBindViewHolder(SubSettingViewHolder holder, int position) {
|
public void onBindViewHolder(SubSettingViewHolder holder, int position) {
|
||||||
super.onBindViewHolder(holder, position);
|
super.onBindViewHolder(holder, position);
|
||||||
if (position > 0) {
|
if (position > 0) {
|
||||||
TrackInfo track = tracks.get(position - 1);
|
TrackInformation track = tracks.get(position - 1);
|
||||||
holder.checkView.setVisibility(track.selected ? VISIBLE : INVISIBLE);
|
holder.checkView.setVisibility(track.isSelected() ? VISIBLE : INVISIBLE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2083,11 +2065,9 @@ public class StyledPlayerControlView extends FrameLayout {
|
|||||||
holder.textView.setText(R.string.exo_track_selection_auto);
|
holder.textView.setText(R.string.exo_track_selection_auto);
|
||||||
// hasSelectionOverride is true means there is an explicit track selection, not "Auto".
|
// hasSelectionOverride is true means there is an explicit track selection, not "Auto".
|
||||||
boolean hasSelectionOverride = false;
|
boolean hasSelectionOverride = false;
|
||||||
DefaultTrackSelector.Parameters parameters = checkNotNull(trackSelector).getParameters();
|
TrackSelectionParameters parameters = checkNotNull(player).getTrackSelectionParameters();
|
||||||
for (int i = 0; i < rendererIndices.size(); i++) {
|
for (int i = 0; i < tracks.size(); i++) {
|
||||||
int rendererIndex = rendererIndices.get(i);
|
if (parameters.trackSelectionOverrides.containsKey(tracks.get(i).trackGroup)) {
|
||||||
TrackGroupArray trackGroups = checkNotNull(mappedTrackInfo).getTrackGroups(rendererIndex);
|
|
||||||
if (parameters.hasSelectionOverride(rendererIndex, trackGroups)) {
|
|
||||||
hasSelectionOverride = true;
|
hasSelectionOverride = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -2095,14 +2075,20 @@ public class StyledPlayerControlView extends FrameLayout {
|
|||||||
holder.checkView.setVisibility(hasSelectionOverride ? INVISIBLE : VISIBLE);
|
holder.checkView.setVisibility(hasSelectionOverride ? INVISIBLE : VISIBLE);
|
||||||
holder.itemView.setOnClickListener(
|
holder.itemView.setOnClickListener(
|
||||||
v -> {
|
v -> {
|
||||||
if (trackSelector != null) {
|
if (player == null) {
|
||||||
ParametersBuilder parametersBuilder = trackSelector.getParameters().buildUpon();
|
return;
|
||||||
for (int i = 0; i < rendererIndices.size(); i++) {
|
|
||||||
int rendererIndex = rendererIndices.get(i);
|
|
||||||
parametersBuilder = parametersBuilder.clearSelectionOverrides(rendererIndex);
|
|
||||||
}
|
|
||||||
checkNotNull(trackSelector).setParameters(parametersBuilder);
|
|
||||||
}
|
}
|
||||||
|
TrackSelectionParameters trackSelectionParameters =
|
||||||
|
player.getTrackSelectionParameters();
|
||||||
|
// Remove all audio overrides.
|
||||||
|
ImmutableMap<TrackGroup, TrackSelectionOverride> trackSelectionOverrides =
|
||||||
|
clearTrackSelectionOverridesForType(
|
||||||
|
C.TRACK_TYPE_AUDIO, trackSelectionParameters.trackSelectionOverrides);
|
||||||
|
player.setTrackSelectionParameters(
|
||||||
|
trackSelectionParameters
|
||||||
|
.buildUpon()
|
||||||
|
.setTrackSelectionOverrides(trackSelectionOverrides)
|
||||||
|
.build());
|
||||||
settingsAdapter.setSubTextAtPosition(
|
settingsAdapter.setSubTextAtPosition(
|
||||||
SETTINGS_AUDIO_TRACK_SELECTION_POSITION,
|
SETTINGS_AUDIO_TRACK_SELECTION_POSITION,
|
||||||
getResources().getString(R.string.exo_track_selection_auto));
|
getResources().getString(R.string.exo_track_selection_auto));
|
||||||
@ -2116,22 +2102,19 @@ public class StyledPlayerControlView extends FrameLayout {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void init(
|
public void init(List<TrackInformation> trackInformations) {
|
||||||
List<Integer> rendererIndices,
|
|
||||||
List<TrackInfo> trackInfos,
|
|
||||||
MappedTrackInfo mappedTrackInfo) {
|
|
||||||
// Update subtext in settings menu with current audio track selection.
|
// Update subtext in settings menu with current audio track selection.
|
||||||
boolean hasSelectionOverride = false;
|
boolean hasSelectionOverride = false;
|
||||||
for (int i = 0; i < rendererIndices.size(); i++) {
|
for (int i = 0; i < trackInformations.size(); i++) {
|
||||||
int rendererIndex = rendererIndices.get(i);
|
if (checkNotNull(player)
|
||||||
TrackGroupArray trackGroups = mappedTrackInfo.getTrackGroups(rendererIndex);
|
.getTrackSelectionParameters()
|
||||||
if (trackSelector != null
|
.trackSelectionOverrides
|
||||||
&& trackSelector.getParameters().hasSelectionOverride(rendererIndex, trackGroups)) {
|
.containsKey(trackInformations.get(i).trackGroup)) {
|
||||||
hasSelectionOverride = true;
|
hasSelectionOverride = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (trackInfos.isEmpty()) {
|
if (trackInformations.isEmpty()) {
|
||||||
settingsAdapter.setSubTextAtPosition(
|
settingsAdapter.setSubTextAtPosition(
|
||||||
SETTINGS_AUDIO_TRACK_SELECTION_POSITION,
|
SETTINGS_AUDIO_TRACK_SELECTION_POSITION,
|
||||||
getResources().getString(R.string.exo_track_selection_none));
|
getResources().getString(R.string.exo_track_selection_none));
|
||||||
@ -2142,35 +2125,28 @@ public class StyledPlayerControlView extends FrameLayout {
|
|||||||
SETTINGS_AUDIO_TRACK_SELECTION_POSITION,
|
SETTINGS_AUDIO_TRACK_SELECTION_POSITION,
|
||||||
getResources().getString(R.string.exo_track_selection_auto));
|
getResources().getString(R.string.exo_track_selection_auto));
|
||||||
} else {
|
} else {
|
||||||
for (int i = 0; i < trackInfos.size(); i++) {
|
for (int i = 0; i < trackInformations.size(); i++) {
|
||||||
TrackInfo track = trackInfos.get(i);
|
TrackInformation track = trackInformations.get(i);
|
||||||
if (track.selected) {
|
if (track.isSelected()) {
|
||||||
settingsAdapter.setSubTextAtPosition(
|
settingsAdapter.setSubTextAtPosition(
|
||||||
SETTINGS_AUDIO_TRACK_SELECTION_POSITION, track.trackName);
|
SETTINGS_AUDIO_TRACK_SELECTION_POSITION, track.trackName);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
this.rendererIndices = rendererIndices;
|
this.tracks = trackInformations;
|
||||||
this.tracks = trackInfos;
|
|
||||||
this.mappedTrackInfo = mappedTrackInfo;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private abstract class TrackSelectionAdapter extends RecyclerView.Adapter<SubSettingViewHolder> {
|
private abstract class TrackSelectionAdapter extends RecyclerView.Adapter<SubSettingViewHolder> {
|
||||||
|
|
||||||
protected List<Integer> rendererIndices;
|
protected List<TrackInformation> tracks;
|
||||||
protected List<TrackInfo> tracks;
|
|
||||||
protected @Nullable MappedTrackInfo mappedTrackInfo;
|
|
||||||
|
|
||||||
public TrackSelectionAdapter() {
|
protected TrackSelectionAdapter() {
|
||||||
this.rendererIndices = new ArrayList<>();
|
|
||||||
this.tracks = new ArrayList<>();
|
this.tracks = new ArrayList<>();
|
||||||
this.mappedTrackInfo = null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public abstract void init(
|
public abstract void init(List<TrackInformation> trackInformations);
|
||||||
List<Integer> rendererIndices, List<TrackInfo> trackInfos, MappedTrackInfo mappedTrackInfo);
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public SubSettingViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
|
public SubSettingViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
|
||||||
@ -2181,52 +2157,48 @@ public class StyledPlayerControlView extends FrameLayout {
|
|||||||
return new SubSettingViewHolder(v);
|
return new SubSettingViewHolder(v);
|
||||||
}
|
}
|
||||||
|
|
||||||
public abstract void onBindViewHolderAtZeroPosition(SubSettingViewHolder holder);
|
protected abstract void onBindViewHolderAtZeroPosition(SubSettingViewHolder holder);
|
||||||
|
|
||||||
public abstract void onTrackSelection(String subtext);
|
protected abstract void onTrackSelection(String subtext);
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onBindViewHolder(SubSettingViewHolder holder, int position) {
|
public void onBindViewHolder(SubSettingViewHolder holder, int position) {
|
||||||
if (trackSelector == null || mappedTrackInfo == null) {
|
if (player == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (position == 0) {
|
if (position == 0) {
|
||||||
onBindViewHolderAtZeroPosition(holder);
|
onBindViewHolderAtZeroPosition(holder);
|
||||||
} else {
|
} else {
|
||||||
TrackInfo track = tracks.get(position - 1);
|
TrackInformation track = tracks.get(position - 1);
|
||||||
TrackGroupArray trackGroups = mappedTrackInfo.getTrackGroups(track.rendererIndex);
|
|
||||||
boolean explicitlySelected =
|
boolean explicitlySelected =
|
||||||
checkNotNull(trackSelector)
|
checkNotNull(player)
|
||||||
.getParameters()
|
.getTrackSelectionParameters()
|
||||||
.hasSelectionOverride(track.rendererIndex, trackGroups)
|
.trackSelectionOverrides
|
||||||
&& track.selected;
|
.containsKey(track.trackGroup)
|
||||||
|
&& track.isSelected();
|
||||||
holder.textView.setText(track.trackName);
|
holder.textView.setText(track.trackName);
|
||||||
holder.checkView.setVisibility(explicitlySelected ? VISIBLE : INVISIBLE);
|
holder.checkView.setVisibility(explicitlySelected ? VISIBLE : INVISIBLE);
|
||||||
holder.itemView.setOnClickListener(
|
holder.itemView.setOnClickListener(
|
||||||
v -> {
|
v -> {
|
||||||
if (mappedTrackInfo != null && trackSelector != null) {
|
if (player == null) {
|
||||||
ParametersBuilder parametersBuilder = trackSelector.getParameters().buildUpon();
|
return;
|
||||||
for (int i = 0; i < rendererIndices.size(); i++) {
|
|
||||||
int rendererIndex = rendererIndices.get(i);
|
|
||||||
if (rendererIndex == track.rendererIndex) {
|
|
||||||
parametersBuilder =
|
|
||||||
parametersBuilder
|
|
||||||
.setSelectionOverride(
|
|
||||||
rendererIndex,
|
|
||||||
checkNotNull(mappedTrackInfo).getTrackGroups(rendererIndex),
|
|
||||||
new SelectionOverride(track.groupIndex, track.trackIndex))
|
|
||||||
.setRendererDisabled(rendererIndex, false);
|
|
||||||
} else {
|
|
||||||
parametersBuilder =
|
|
||||||
parametersBuilder
|
|
||||||
.clearSelectionOverrides(rendererIndex)
|
|
||||||
.setRendererDisabled(rendererIndex, true);
|
|
||||||
}
|
}
|
||||||
}
|
TrackSelectionParameters trackSelectionParameters =
|
||||||
checkNotNull(trackSelector).setParameters(parametersBuilder);
|
player.getTrackSelectionParameters();
|
||||||
|
Map<TrackGroup, TrackSelectionOverride> overrides =
|
||||||
|
forceTrackSelection(
|
||||||
|
trackSelectionParameters.trackSelectionOverrides,
|
||||||
|
track.tracksInfo,
|
||||||
|
track.trackGroupIndex,
|
||||||
|
new TrackSelectionOverride(ImmutableSet.of(track.trackIndex)));
|
||||||
|
checkNotNull(player)
|
||||||
|
.setTrackSelectionParameters(
|
||||||
|
trackSelectionParameters
|
||||||
|
.buildUpon()
|
||||||
|
.setTrackSelectionOverrides(overrides)
|
||||||
|
.build());
|
||||||
onTrackSelection(track.trackName);
|
onTrackSelection(track.trackName);
|
||||||
settingsWindow.dismiss();
|
settingsWindow.dismiss();
|
||||||
}
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2236,9 +2208,8 @@ public class StyledPlayerControlView extends FrameLayout {
|
|||||||
return tracks.isEmpty() ? 0 : tracks.size() + 1;
|
return tracks.isEmpty() ? 0 : tracks.size() + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void clear() {
|
protected void clear() {
|
||||||
tracks = Collections.emptyList();
|
tracks = Collections.emptyList();
|
||||||
mappedTrackInfo = null;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -48,7 +48,6 @@ import androidx.annotation.RequiresApi;
|
|||||||
import androidx.core.content.ContextCompat;
|
import androidx.core.content.ContextCompat;
|
||||||
import com.google.android.exoplayer2.C;
|
import com.google.android.exoplayer2.C;
|
||||||
import com.google.android.exoplayer2.ControlDispatcher;
|
import com.google.android.exoplayer2.ControlDispatcher;
|
||||||
import com.google.android.exoplayer2.Format;
|
|
||||||
import com.google.android.exoplayer2.ForwardingPlayer;
|
import com.google.android.exoplayer2.ForwardingPlayer;
|
||||||
import com.google.android.exoplayer2.MediaMetadata;
|
import com.google.android.exoplayer2.MediaMetadata;
|
||||||
import com.google.android.exoplayer2.PlaybackException;
|
import com.google.android.exoplayer2.PlaybackException;
|
||||||
@ -58,12 +57,9 @@ import com.google.android.exoplayer2.Timeline;
|
|||||||
import com.google.android.exoplayer2.Timeline.Period;
|
import com.google.android.exoplayer2.Timeline.Period;
|
||||||
import com.google.android.exoplayer2.TracksInfo;
|
import com.google.android.exoplayer2.TracksInfo;
|
||||||
import com.google.android.exoplayer2.text.Cue;
|
import com.google.android.exoplayer2.text.Cue;
|
||||||
import com.google.android.exoplayer2.trackselection.TrackSelection;
|
|
||||||
import com.google.android.exoplayer2.trackselection.TrackSelectionArray;
|
|
||||||
import com.google.android.exoplayer2.ui.AspectRatioFrameLayout.ResizeMode;
|
import com.google.android.exoplayer2.ui.AspectRatioFrameLayout.ResizeMode;
|
||||||
import com.google.android.exoplayer2.util.Assertions;
|
import com.google.android.exoplayer2.util.Assertions;
|
||||||
import com.google.android.exoplayer2.util.ErrorMessageProvider;
|
import com.google.android.exoplayer2.util.ErrorMessageProvider;
|
||||||
import com.google.android.exoplayer2.util.MimeTypes;
|
|
||||||
import com.google.android.exoplayer2.util.RepeatModeUtil;
|
import com.google.android.exoplayer2.util.RepeatModeUtil;
|
||||||
import com.google.android.exoplayer2.util.Util;
|
import com.google.android.exoplayer2.util.Util;
|
||||||
import com.google.android.exoplayer2.video.VideoSize;
|
import com.google.android.exoplayer2.video.VideoSize;
|
||||||
@ -1296,7 +1292,7 @@ public class StyledPlayerView extends FrameLayout implements AdViewProvider {
|
|||||||
|
|
||||||
private void updateForCurrentTrackSelections(boolean isNewPlayer) {
|
private void updateForCurrentTrackSelections(boolean isNewPlayer) {
|
||||||
@Nullable Player player = this.player;
|
@Nullable Player player = this.player;
|
||||||
if (player == null || player.getCurrentTrackGroups().isEmpty()) {
|
if (player == null || player.getCurrentTracksInfo().getTrackGroupInfos().isEmpty()) {
|
||||||
if (!keepContentOnPlayerReset) {
|
if (!keepContentOnPlayerReset) {
|
||||||
hideArtwork();
|
hideArtwork();
|
||||||
closeShutter();
|
closeShutter();
|
||||||
@ -1309,21 +1305,12 @@ public class StyledPlayerView extends FrameLayout implements AdViewProvider {
|
|||||||
closeShutter();
|
closeShutter();
|
||||||
}
|
}
|
||||||
|
|
||||||
TrackSelectionArray trackSelections = player.getCurrentTrackSelections();
|
if (player.getCurrentTracksInfo().isTypeSelected(C.TRACK_TYPE_VIDEO)) {
|
||||||
for (int i = 0; i < trackSelections.length; i++) {
|
|
||||||
@Nullable TrackSelection trackSelection = trackSelections.get(i);
|
|
||||||
if (trackSelection != null) {
|
|
||||||
for (int j = 0; j < trackSelection.length(); j++) {
|
|
||||||
Format format = trackSelection.getFormat(j);
|
|
||||||
if (MimeTypes.getTrackType(format.sampleMimeType) == C.TRACK_TYPE_VIDEO) {
|
|
||||||
// Video enabled, so artwork must be hidden. If the shutter is closed, it will be opened
|
// Video enabled, so artwork must be hidden. If the shutter is closed, it will be opened
|
||||||
// in onRenderedFirstFrame().
|
// in onRenderedFirstFrame().
|
||||||
hideArtwork();
|
hideArtwork();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Video disabled so the shutter must be closed.
|
// Video disabled so the shutter must be closed.
|
||||||
closeShutter();
|
closeShutter();
|
||||||
@ -1558,7 +1545,7 @@ public class StyledPlayerView extends FrameLayout implements AdViewProvider {
|
|||||||
Timeline timeline = player.getCurrentTimeline();
|
Timeline timeline = player.getCurrentTimeline();
|
||||||
if (timeline.isEmpty()) {
|
if (timeline.isEmpty()) {
|
||||||
lastPeriodUidWithTracks = null;
|
lastPeriodUidWithTracks = null;
|
||||||
} else if (!player.getCurrentTrackGroups().isEmpty()) {
|
} else if (!player.getCurrentTracksInfo().getTrackGroupInfos().isEmpty()) {
|
||||||
lastPeriodUidWithTracks =
|
lastPeriodUidWithTracks =
|
||||||
timeline.getPeriod(player.getCurrentPeriodIndex(), period, /* setIds= */ true).uid;
|
timeline.getPeriod(player.getCurrentPeriodIndex(), period, /* setIds= */ true).uid;
|
||||||
} else if (lastPeriodUidWithTracks != null) {
|
} else if (lastPeriodUidWithTracks != null) {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user