use of com.google.android.exoplayer2.RendererConfiguration in project ExoPlayer by google.
the class ExoPlayerImplInternal method enableRenderers.
private void enableRenderers(boolean[] rendererWasEnabledFlags, int enabledRendererCount) throws ExoPlaybackException {
enabledRenderers = new Renderer[enabledRendererCount];
enabledRendererCount = 0;
for (int i = 0; i < renderers.length; i++) {
Renderer renderer = renderers[i];
TrackSelection newSelection = playingPeriodHolder.trackSelectorResult.selections.get(i);
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 == ExoPlayer.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;
}
// Start the renderer if playing.
if (playing) {
renderer.start();
}
}
}
}
}
use of com.google.android.exoplayer2.RendererConfiguration in project ExoPlayer by google.
the class ExoPlayerImplInternal method updatePeriods.
private void updatePeriods() throws ExoPlaybackException, IOException {
if (timeline == null) {
// We're waiting to get information about periods.
mediaSource.maybeThrowSourceInfoRefreshError();
return;
}
// Update the loading period if required.
maybeUpdateLoadingPeriod();
if (loadingPeriodHolder == null || loadingPeriodHolder.isFullyBuffered()) {
setIsLoading(false);
} else if (loadingPeriodHolder != null && loadingPeriodHolder.needsContinueLoading) {
maybeContinueLoading();
}
if (playingPeriodHolder == null) {
// We're waiting for the first period to be prepared.
return;
}
// Update the playing and reading periods.
while (playingPeriodHolder != readingPeriodHolder && rendererPositionUs >= playingPeriodHolder.next.rendererPositionOffsetUs) {
// All enabled renderers' streams have been read to the end, and the playback position reached
// the end of the playing period, so advance playback to the next period.
playingPeriodHolder.release();
setPlayingPeriodHolder(playingPeriodHolder.next);
playbackInfo = new PlaybackInfo(playingPeriodHolder.index, playingPeriodHolder.startPositionUs);
updatePlaybackPositions();
eventHandler.obtainMessage(MSG_POSITION_DISCONTINUITY, playbackInfo).sendToTarget();
}
if (readingPeriodHolder.isLast) {
for (int i = 0; i < renderers.length; i++) {
Renderer renderer = renderers[i];
SampleStream sampleStream = readingPeriodHolder.sampleStreams[i];
// stream in case of playlist changes that cause the stream to be no longer final.
if (sampleStream != null && renderer.getStream() == sampleStream && renderer.hasReadStreamToEnd()) {
renderer.setCurrentStreamFinal();
}
}
return;
}
for (int i = 0; i < renderers.length; i++) {
Renderer renderer = renderers[i];
SampleStream sampleStream = readingPeriodHolder.sampleStreams[i];
if (renderer.getStream() != sampleStream || (sampleStream != null && !renderer.hasReadStreamToEnd())) {
return;
}
}
if (readingPeriodHolder.next != null && readingPeriodHolder.next.prepared) {
TrackSelectorResult oldTrackSelectorResult = readingPeriodHolder.trackSelectorResult;
readingPeriodHolder = readingPeriodHolder.next;
TrackSelectorResult newTrackSelectorResult = readingPeriodHolder.trackSelectorResult;
boolean initialDiscontinuity = readingPeriodHolder.mediaPeriod.readDiscontinuity() != C.TIME_UNSET;
for (int i = 0; i < renderers.length; i++) {
Renderer renderer = renderers[i];
TrackSelection oldSelection = oldTrackSelectorResult.selections.get(i);
if (oldSelection == null) {
// The renderer has no current stream and will be enabled when we play the next period.
} else if (initialDiscontinuity) {
// 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.
renderer.setCurrentStreamFinal();
} else if (!renderer.isCurrentStreamFinal()) {
TrackSelection newSelection = newTrackSelectorResult.selections.get(i);
RendererConfiguration oldConfig = oldTrackSelectorResult.rendererConfigurations[i];
RendererConfiguration newConfig = newTrackSelectorResult.rendererConfigurations[i];
if (newSelection != null && newConfig.equals(oldConfig)) {
// Replace the renderer's SampleStream so the transition to playing the next period can
// be seamless.
Format[] formats = new Format[newSelection.length()];
for (int j = 0; j < formats.length; j++) {
formats[j] = newSelection.getFormat(j);
}
renderer.replaceStream(formats, readingPeriodHolder.sampleStreams[i], readingPeriodHolder.getRendererOffset());
} else {
// The renderer will be disabled when transitioning to playing the next period, either
// because there's no new selection or because a configuration change is required. Mark
// the SampleStream as final to play out any remaining data.
renderer.setCurrentStreamFinal();
}
}
}
}
}
use of com.google.android.exoplayer2.RendererConfiguration in project ExoPlayer by google.
the class MappingTrackSelector method maybeConfigureRenderersForTunneling.
/**
* Determines whether tunneling should be enabled, replacing {@link RendererConfiguration}s in
* {@code rendererConfigurations} with configurations that enable tunneling on the appropriate
* renderers if so.
*
* @param rendererCapabilities The {@link RendererCapabilities} of the renderers for which
* {@link TrackSelection}s are to be generated.
* @param rendererTrackGroupArrays An array of {@link TrackGroupArray}s where each entry
* corresponds to the renderer of equal index in {@code renderers}.
* @param rendererFormatSupports Maps every available track to a specific level of support as
* defined by the renderer {@code FORMAT_*} constants.
* @param rendererConfigurations The renderer configurations. Configurations may be replaced with
* ones that enable tunneling as a result of this call.
* @param trackSelections The renderer track selections.
* @param tunnelingAudioSessionId The audio session id to use when tunneling, or
* {@link C#AUDIO_SESSION_ID_UNSET} if tunneling should not be enabled.
*/
private static void maybeConfigureRenderersForTunneling(RendererCapabilities[] rendererCapabilities, TrackGroupArray[] rendererTrackGroupArrays, int[][][] rendererFormatSupports, RendererConfiguration[] rendererConfigurations, TrackSelection[] trackSelections, int tunnelingAudioSessionId) {
if (tunnelingAudioSessionId == C.AUDIO_SESSION_ID_UNSET) {
return;
}
// Check whether we can enable tunneling. To enable tunneling we require exactly one audio and
// one video renderer to support tunneling and have a selection.
int tunnelingAudioRendererIndex = -1;
int tunnelingVideoRendererIndex = -1;
boolean enableTunneling = true;
for (int i = 0; i < rendererCapabilities.length; i++) {
int rendererType = rendererCapabilities[i].getTrackType();
TrackSelection trackSelection = trackSelections[i];
if ((rendererType == C.TRACK_TYPE_AUDIO || rendererType == C.TRACK_TYPE_VIDEO) && trackSelection != null) {
if (rendererSupportsTunneling(rendererFormatSupports[i], rendererTrackGroupArrays[i], trackSelection)) {
if (rendererType == C.TRACK_TYPE_AUDIO) {
if (tunnelingAudioRendererIndex != -1) {
enableTunneling = false;
break;
} else {
tunnelingAudioRendererIndex = i;
}
} else {
if (tunnelingVideoRendererIndex != -1) {
enableTunneling = false;
break;
} else {
tunnelingVideoRendererIndex = i;
}
}
}
}
}
enableTunneling &= tunnelingAudioRendererIndex != -1 && tunnelingVideoRendererIndex != -1;
if (enableTunneling) {
RendererConfiguration tunnelingRendererConfiguration = new RendererConfiguration(tunnelingAudioSessionId);
rendererConfigurations[tunnelingAudioRendererIndex] = tunnelingRendererConfiguration;
rendererConfigurations[tunnelingVideoRendererIndex] = tunnelingRendererConfiguration;
}
}
use of com.google.android.exoplayer2.RendererConfiguration in project ExoPlayer by google.
the class MappingTrackSelector method selectTracks.
// TrackSelector implementation.
@Override
public final TrackSelectorResult selectTracks(RendererCapabilities[] rendererCapabilities, TrackGroupArray trackGroups) throws ExoPlaybackException {
// Structures into which data will be written during the selection. The extra item at the end
// of each array is to store data associated with track groups that cannot be associated with
// any renderer.
int[] rendererTrackGroupCounts = new int[rendererCapabilities.length + 1];
TrackGroup[][] rendererTrackGroups = new TrackGroup[rendererCapabilities.length + 1][];
int[][][] rendererFormatSupports = new int[rendererCapabilities.length + 1][][];
for (int i = 0; i < rendererTrackGroups.length; i++) {
rendererTrackGroups[i] = new TrackGroup[trackGroups.length];
rendererFormatSupports[i] = new int[trackGroups.length][];
}
// Determine the extent to which each renderer supports mixed mimeType adaptation.
int[] mixedMimeTypeAdaptationSupport = getMixedMimeTypeAdaptationSupport(rendererCapabilities);
// renderer provides for each track in the group.
for (int groupIndex = 0; groupIndex < trackGroups.length; groupIndex++) {
TrackGroup group = trackGroups.get(groupIndex);
// Associate the group to a preferred renderer.
int rendererIndex = findRenderer(rendererCapabilities, group);
// Evaluate the support that the renderer provides for each track in the group.
int[] rendererFormatSupport = rendererIndex == rendererCapabilities.length ? new int[group.length] : getFormatSupport(rendererCapabilities[rendererIndex], group);
// Stash the results.
int rendererTrackGroupCount = rendererTrackGroupCounts[rendererIndex];
rendererTrackGroups[rendererIndex][rendererTrackGroupCount] = group;
rendererFormatSupports[rendererIndex][rendererTrackGroupCount] = rendererFormatSupport;
rendererTrackGroupCounts[rendererIndex]++;
}
// Create a track group array for each renderer, and trim each rendererFormatSupports entry.
TrackGroupArray[] rendererTrackGroupArrays = new TrackGroupArray[rendererCapabilities.length];
int[] rendererTrackTypes = new int[rendererCapabilities.length];
for (int i = 0; i < rendererCapabilities.length; i++) {
int rendererTrackGroupCount = rendererTrackGroupCounts[i];
rendererTrackGroupArrays[i] = new TrackGroupArray(Arrays.copyOf(rendererTrackGroups[i], rendererTrackGroupCount));
rendererFormatSupports[i] = Arrays.copyOf(rendererFormatSupports[i], rendererTrackGroupCount);
rendererTrackTypes[i] = rendererCapabilities[i].getTrackType();
}
// Create a track group array for track groups not associated with a renderer.
int unassociatedTrackGroupCount = rendererTrackGroupCounts[rendererCapabilities.length];
TrackGroupArray unassociatedTrackGroupArray = new TrackGroupArray(Arrays.copyOf(rendererTrackGroups[rendererCapabilities.length], unassociatedTrackGroupCount));
TrackSelection[] trackSelections = selectTracks(rendererCapabilities, rendererTrackGroupArrays, rendererFormatSupports);
// Apply track disabling and overriding.
for (int i = 0; i < rendererCapabilities.length; i++) {
if (rendererDisabledFlags.get(i)) {
trackSelections[i] = null;
} else {
TrackGroupArray rendererTrackGroup = rendererTrackGroupArrays[i];
Map<TrackGroupArray, SelectionOverride> overrides = selectionOverrides.get(i);
SelectionOverride override = overrides == null ? null : overrides.get(rendererTrackGroup);
if (override != null) {
trackSelections[i] = override.createTrackSelection(rendererTrackGroup);
}
}
}
// Package up the track information and selections.
MappedTrackInfo mappedTrackInfo = new MappedTrackInfo(rendererTrackTypes, rendererTrackGroupArrays, mixedMimeTypeAdaptationSupport, rendererFormatSupports, unassociatedTrackGroupArray);
// Initialize the renderer configurations to the default configuration for all renderers with
// selections, and null otherwise.
RendererConfiguration[] rendererConfigurations = new RendererConfiguration[rendererCapabilities.length];
for (int i = 0; i < rendererCapabilities.length; i++) {
rendererConfigurations[i] = trackSelections[i] != null ? RendererConfiguration.DEFAULT : null;
}
// Configure audio and video renderers to use tunneling if appropriate.
maybeConfigureRenderersForTunneling(rendererCapabilities, rendererTrackGroupArrays, rendererFormatSupports, rendererConfigurations, trackSelections, tunnelingAudioSessionId);
return new TrackSelectorResult(trackGroups, new TrackSelectionArray(trackSelections), mappedTrackInfo, rendererConfigurations);
}
Aggregations