use of com.google.android.exoplayer2.source.TrackGroupArray in project ExoPlayer by google.
the class HlsSampleStreamWrapper method buildTracks.
/**
* Builds tracks that are exposed by this {@link HlsSampleStreamWrapper} instance, as well as
* internal data-structures required for operation.
* <p>
* Tracks in HLS are complicated. A HLS master playlist contains a number of "variants". Each
* variant stream typically contains muxed video, audio and (possibly) additional audio, metadata
* and caption tracks. We wish to allow the user to select between an adaptive track that spans
* all variants, as well as each individual variant. If multiple audio tracks are present within
* each variant then we wish to allow the user to select between those also.
* <p>
* To do this, tracks are constructed as follows. The {@link HlsChunkSource} exposes (N+1) tracks,
* where N is the number of variants defined in the HLS master playlist. These consist of one
* adaptive track defined to span all variants and a track for each individual variant. The
* adaptive track is initially selected. The extractor is then prepared to discover the tracks
* inside of each variant stream. The two sets of tracks are then combined by this method to
* create a third set, which is the set exposed by this {@link HlsSampleStreamWrapper}:
* <ul>
* <li>The extractor tracks are inspected to infer a "primary" track type. If a video track is
* present then it is always the primary type. If not, audio is the primary type if present.
* Else text is the primary type if present. Else there is no primary type.</li>
* <li>If there is exactly one extractor track of the primary type, it's expanded into (N+1)
* exposed tracks, all of which correspond to the primary extractor track and each of which
* corresponds to a different chunk source track. Selecting one of these tracks has the effect
* of switching the selected track on the chunk source.</li>
* <li>All other extractor tracks are exposed directly. Selecting one of these tracks has the
* effect of selecting an extractor track, leaving the selected track on the chunk source
* unchanged.</li>
* </ul>
*/
private void buildTracks() {
// Iterate through the extractor tracks to discover the "primary" track type, and the index
// of the single track of this type.
int primaryExtractorTrackType = PRIMARY_TYPE_NONE;
int primaryExtractorTrackIndex = C.INDEX_UNSET;
int extractorTrackCount = sampleQueues.size();
for (int i = 0; i < extractorTrackCount; i++) {
String sampleMimeType = sampleQueues.valueAt(i).getUpstreamFormat().sampleMimeType;
int trackType;
if (MimeTypes.isVideo(sampleMimeType)) {
trackType = PRIMARY_TYPE_VIDEO;
} else if (MimeTypes.isAudio(sampleMimeType)) {
trackType = PRIMARY_TYPE_AUDIO;
} else if (MimeTypes.isText(sampleMimeType)) {
trackType = PRIMARY_TYPE_TEXT;
} else {
trackType = PRIMARY_TYPE_NONE;
}
if (trackType > primaryExtractorTrackType) {
primaryExtractorTrackType = trackType;
primaryExtractorTrackIndex = i;
} else if (trackType == primaryExtractorTrackType && primaryExtractorTrackIndex != C.INDEX_UNSET) {
// We have multiple tracks of the primary type. We only want an index if there only exists a
// single track of the primary type, so unset the index again.
primaryExtractorTrackIndex = C.INDEX_UNSET;
}
}
TrackGroup chunkSourceTrackGroup = chunkSource.getTrackGroup();
int chunkSourceTrackCount = chunkSourceTrackGroup.length;
// Instantiate the necessary internal data-structures.
primaryTrackGroupIndex = C.INDEX_UNSET;
groupEnabledStates = new boolean[extractorTrackCount];
// Construct the set of exposed track groups.
TrackGroup[] trackGroups = new TrackGroup[extractorTrackCount];
for (int i = 0; i < extractorTrackCount; i++) {
Format sampleFormat = sampleQueues.valueAt(i).getUpstreamFormat();
if (i == primaryExtractorTrackIndex) {
Format[] formats = new Format[chunkSourceTrackCount];
for (int j = 0; j < chunkSourceTrackCount; j++) {
formats[j] = deriveFormat(chunkSourceTrackGroup.getFormat(j), sampleFormat);
}
trackGroups[i] = new TrackGroup(formats);
primaryTrackGroupIndex = i;
} else {
Format trackFormat = primaryExtractorTrackType == PRIMARY_TYPE_VIDEO && MimeTypes.isAudio(sampleFormat.sampleMimeType) ? muxedAudioFormat : null;
trackGroups[i] = new TrackGroup(deriveFormat(trackFormat, sampleFormat));
}
}
this.trackGroups = new TrackGroupArray(trackGroups);
}
use of com.google.android.exoplayer2.source.TrackGroupArray in project ExoPlayer by google.
the class DashMediaPeriod method buildTrackGroups.
// Internal methods.
private static Pair<TrackGroupArray, EmbeddedTrackInfo[]> buildTrackGroups(List<AdaptationSet> adaptationSets) {
int adaptationSetCount = adaptationSets.size();
int embeddedTrackCount = getEmbeddedTrackCount(adaptationSets);
TrackGroup[] trackGroupArray = new TrackGroup[adaptationSetCount + embeddedTrackCount];
EmbeddedTrackInfo[] embeddedTrackInfos = new EmbeddedTrackInfo[embeddedTrackCount];
int embeddedTrackIndex = 0;
for (int i = 0; i < adaptationSetCount; i++) {
AdaptationSet adaptationSet = adaptationSets.get(i);
List<Representation> representations = adaptationSet.representations;
Format[] formats = new Format[representations.size()];
for (int j = 0; j < formats.length; j++) {
formats[j] = representations.get(j).format;
}
trackGroupArray[i] = new TrackGroup(formats);
if (hasEventMessageTrack(adaptationSet)) {
Format format = Format.createSampleFormat(adaptationSet.id + ":emsg", MimeTypes.APPLICATION_EMSG, null, Format.NO_VALUE, null);
trackGroupArray[adaptationSetCount + embeddedTrackIndex] = new TrackGroup(format);
embeddedTrackInfos[embeddedTrackIndex++] = new EmbeddedTrackInfo(i, C.TRACK_TYPE_METADATA);
}
if (hasCea608Track(adaptationSet)) {
Format format = Format.createTextSampleFormat(adaptationSet.id + ":cea608", MimeTypes.APPLICATION_CEA608, null, Format.NO_VALUE, 0, null, null);
trackGroupArray[adaptationSetCount + embeddedTrackIndex] = new TrackGroup(format);
embeddedTrackInfos[embeddedTrackIndex++] = new EmbeddedTrackInfo(i, C.TRACK_TYPE_TEXT);
}
}
return Pair.create(new TrackGroupArray(trackGroupArray), embeddedTrackInfos);
}
use of com.google.android.exoplayer2.source.TrackGroupArray in project ExoPlayer by google.
the class EventLogger method onTracksChanged.
@Override
public void onTracksChanged(TrackGroupArray ignored, TrackSelectionArray trackSelections) {
MappedTrackInfo mappedTrackInfo = trackSelector.getCurrentMappedTrackInfo();
if (mappedTrackInfo == null) {
Log.d(TAG, "Tracks []");
return;
}
Log.d(TAG, "Tracks [");
// Log tracks associated to renderers.
for (int rendererIndex = 0; rendererIndex < mappedTrackInfo.length; rendererIndex++) {
TrackGroupArray rendererTrackGroups = mappedTrackInfo.getTrackGroups(rendererIndex);
TrackSelection trackSelection = trackSelections.get(rendererIndex);
if (rendererTrackGroups.length > 0) {
Log.d(TAG, " Renderer:" + rendererIndex + " [");
for (int groupIndex = 0; groupIndex < rendererTrackGroups.length; groupIndex++) {
TrackGroup trackGroup = rendererTrackGroups.get(groupIndex);
String adaptiveSupport = getAdaptiveSupportString(trackGroup.length, mappedTrackInfo.getAdaptiveSupport(rendererIndex, groupIndex, false));
Log.d(TAG, " Group:" + groupIndex + ", adaptive_supported=" + adaptiveSupport + " [");
for (int trackIndex = 0; trackIndex < trackGroup.length; trackIndex++) {
String status = getTrackStatusString(trackSelection, trackGroup, trackIndex);
String formatSupport = getFormatSupportString(mappedTrackInfo.getTrackFormatSupport(rendererIndex, groupIndex, trackIndex));
Log.d(TAG, " " + status + " Track:" + trackIndex + ", " + Format.toLogString(trackGroup.getFormat(trackIndex)) + ", supported=" + formatSupport);
}
Log.d(TAG, " ]");
}
// Log metadata for at most one of the tracks selected for the renderer.
if (trackSelection != null) {
for (int selectionIndex = 0; selectionIndex < trackSelection.length(); selectionIndex++) {
Metadata metadata = trackSelection.getFormat(selectionIndex).metadata;
if (metadata != null) {
Log.d(TAG, " Metadata [");
printMetadata(metadata, " ");
Log.d(TAG, " ]");
break;
}
}
}
Log.d(TAG, " ]");
}
}
// Log tracks not associated with a renderer.
TrackGroupArray unassociatedTrackGroups = mappedTrackInfo.getUnassociatedTrackGroups();
if (unassociatedTrackGroups.length > 0) {
Log.d(TAG, " Renderer:None [");
for (int groupIndex = 0; groupIndex < unassociatedTrackGroups.length; groupIndex++) {
Log.d(TAG, " Group:" + groupIndex + " [");
TrackGroup trackGroup = unassociatedTrackGroups.get(groupIndex);
for (int trackIndex = 0; trackIndex < trackGroup.length; trackIndex++) {
String status = getTrackStatusString(false);
String formatSupport = getFormatSupportString(RendererCapabilities.FORMAT_UNSUPPORTED_TYPE);
Log.d(TAG, " " + status + " Track:" + trackIndex + ", " + Format.toLogString(trackGroup.getFormat(trackIndex)) + ", supported=" + formatSupport);
}
Log.d(TAG, " ]");
}
Log.d(TAG, " ]");
}
Log.d(TAG, "]");
}
use of com.google.android.exoplayer2.source.TrackGroupArray in project ExoPlayer by google.
the class DefaultTrackSelector method selectAudioTrack.
// Audio track selection implementation.
protected TrackSelection selectAudioTrack(TrackGroupArray groups, int[][] formatSupport, String preferredAudioLanguage, boolean exceedRendererCapabilitiesIfNecessary) {
TrackGroup selectedGroup = null;
int selectedTrackIndex = 0;
int selectedTrackScore = 0;
for (int groupIndex = 0; groupIndex < groups.length; groupIndex++) {
TrackGroup trackGroup = groups.get(groupIndex);
int[] trackFormatSupport = formatSupport[groupIndex];
for (int trackIndex = 0; trackIndex < trackGroup.length; trackIndex++) {
if (isSupported(trackFormatSupport[trackIndex], exceedRendererCapabilitiesIfNecessary)) {
Format format = trackGroup.getFormat(trackIndex);
boolean isDefault = (format.selectionFlags & C.SELECTION_FLAG_DEFAULT) != 0;
int trackScore;
if (formatHasLanguage(format, preferredAudioLanguage)) {
if (isDefault) {
trackScore = 4;
} else {
trackScore = 3;
}
} else if (isDefault) {
trackScore = 2;
} else {
trackScore = 1;
}
if (isSupported(trackFormatSupport[trackIndex], false)) {
trackScore += WITHIN_RENDERER_CAPABILITIES_BONUS;
}
if (trackScore > selectedTrackScore) {
selectedGroup = trackGroup;
selectedTrackIndex = trackIndex;
selectedTrackScore = trackScore;
}
}
}
}
return selectedGroup == null ? null : new FixedTrackSelection(selectedGroup, selectedTrackIndex);
}
use of com.google.android.exoplayer2.source.TrackGroupArray in project ExoPlayer by google.
the class DefaultTrackSelector method selectOtherTrack.
// General track selection methods.
protected TrackSelection selectOtherTrack(int trackType, TrackGroupArray groups, int[][] formatSupport, boolean exceedRendererCapabilitiesIfNecessary) {
TrackGroup selectedGroup = null;
int selectedTrackIndex = 0;
int selectedTrackScore = 0;
for (int groupIndex = 0; groupIndex < groups.length; groupIndex++) {
TrackGroup trackGroup = groups.get(groupIndex);
int[] trackFormatSupport = formatSupport[groupIndex];
for (int trackIndex = 0; trackIndex < trackGroup.length; trackIndex++) {
if (isSupported(trackFormatSupport[trackIndex], exceedRendererCapabilitiesIfNecessary)) {
Format format = trackGroup.getFormat(trackIndex);
boolean isDefault = (format.selectionFlags & C.SELECTION_FLAG_DEFAULT) != 0;
int trackScore = isDefault ? 2 : 1;
if (isSupported(trackFormatSupport[trackIndex], false)) {
trackScore += WITHIN_RENDERER_CAPABILITIES_BONUS;
}
if (trackScore > selectedTrackScore) {
selectedGroup = trackGroup;
selectedTrackIndex = trackIndex;
selectedTrackScore = trackScore;
}
}
}
}
return selectedGroup == null ? null : new FixedTrackSelection(selectedGroup, selectedTrackIndex);
}
Aggregations