1 /* 2 * Copyright (C) 2016 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 package com.google.android.exoplayer2.trackselection; 17 18 import android.util.Pair; 19 import androidx.annotation.IntDef; 20 import androidx.annotation.Nullable; 21 import com.google.android.exoplayer2.C; 22 import com.google.android.exoplayer2.ExoPlaybackException; 23 import com.google.android.exoplayer2.Renderer; 24 import com.google.android.exoplayer2.RendererCapabilities; 25 import com.google.android.exoplayer2.RendererCapabilities.AdaptiveSupport; 26 import com.google.android.exoplayer2.RendererCapabilities.Capabilities; 27 import com.google.android.exoplayer2.RendererCapabilities.FormatSupport; 28 import com.google.android.exoplayer2.RendererConfiguration; 29 import com.google.android.exoplayer2.Timeline; 30 import com.google.android.exoplayer2.source.MediaSource.MediaPeriodId; 31 import com.google.android.exoplayer2.source.TrackGroup; 32 import com.google.android.exoplayer2.source.TrackGroupArray; 33 import com.google.android.exoplayer2.util.MimeTypes; 34 import com.google.android.exoplayer2.util.Util; 35 import java.lang.annotation.Documented; 36 import java.lang.annotation.Retention; 37 import java.lang.annotation.RetentionPolicy; 38 import java.util.Arrays; 39 import org.checkerframework.checker.nullness.compatqual.NullableType; 40 41 /** 42 * Base class for {@link TrackSelector}s that first establish a mapping between {@link TrackGroup}s 43 * and {@link Renderer}s, and then from that mapping create a {@link TrackSelection} for each 44 * renderer. 45 */ 46 public abstract class MappingTrackSelector extends TrackSelector { 47 48 /** 49 * Provides mapped track information for each renderer. 50 */ 51 public static final class MappedTrackInfo { 52 53 /** 54 * Levels of renderer support. Higher numerical values indicate higher levels of support. One of 55 * {@link #RENDERER_SUPPORT_NO_TRACKS}, {@link #RENDERER_SUPPORT_UNSUPPORTED_TRACKS}, {@link 56 * #RENDERER_SUPPORT_EXCEEDS_CAPABILITIES_TRACKS} or {@link #RENDERER_SUPPORT_PLAYABLE_TRACKS}. 57 */ 58 @Documented 59 @Retention(RetentionPolicy.SOURCE) 60 @IntDef({ 61 RENDERER_SUPPORT_NO_TRACKS, 62 RENDERER_SUPPORT_UNSUPPORTED_TRACKS, 63 RENDERER_SUPPORT_EXCEEDS_CAPABILITIES_TRACKS, 64 RENDERER_SUPPORT_PLAYABLE_TRACKS 65 }) 66 @interface RendererSupport {} 67 /** The renderer does not have any associated tracks. */ 68 public static final int RENDERER_SUPPORT_NO_TRACKS = 0; 69 /** 70 * The renderer has tracks mapped to it, but all are unsupported. In other words, {@link 71 * #getTrackSupport(int, int, int)} returns {@link RendererCapabilities#FORMAT_UNSUPPORTED_DRM}, 72 * {@link RendererCapabilities#FORMAT_UNSUPPORTED_SUBTYPE} or {@link 73 * RendererCapabilities#FORMAT_UNSUPPORTED_TYPE} for all tracks mapped to the renderer. 74 */ 75 public static final int RENDERER_SUPPORT_UNSUPPORTED_TRACKS = 1; 76 /** 77 * The renderer has tracks mapped to it and at least one is of a supported type, but all such 78 * tracks exceed the renderer's capabilities. In other words, {@link #getTrackSupport(int, int, 79 * int)} returns {@link RendererCapabilities#FORMAT_EXCEEDS_CAPABILITIES} for at least one 80 * track mapped to the renderer, but does not return {@link 81 * RendererCapabilities#FORMAT_HANDLED} for any tracks mapped to the renderer. 82 */ 83 public static final int RENDERER_SUPPORT_EXCEEDS_CAPABILITIES_TRACKS = 2; 84 /** 85 * The renderer has tracks mapped to it, and at least one such track is playable. In other 86 * words, {@link #getTrackSupport(int, int, int)} returns {@link 87 * RendererCapabilities#FORMAT_HANDLED} for at least one track mapped to the renderer. 88 */ 89 public static final int RENDERER_SUPPORT_PLAYABLE_TRACKS = 3; 90 91 /** @deprecated Use {@link #getRendererCount()}. */ 92 @Deprecated public final int length; 93 94 private final int rendererCount; 95 private final String[] rendererNames; 96 private final int[] rendererTrackTypes; 97 private final TrackGroupArray[] rendererTrackGroups; 98 @AdaptiveSupport private final int[] rendererMixedMimeTypeAdaptiveSupports; 99 @Capabilities private final int[][][] rendererFormatSupports; 100 private final TrackGroupArray unmappedTrackGroups; 101 102 /** 103 * @param rendererNames The name of each renderer. 104 * @param rendererTrackTypes The track type handled by each renderer. 105 * @param rendererTrackGroups The {@link TrackGroup}s mapped to each renderer. 106 * @param rendererMixedMimeTypeAdaptiveSupports The {@link AdaptiveSupport} for mixed MIME type 107 * adaptation for the renderer. 108 * @param rendererFormatSupports The {@link Capabilities} for each mapped track, indexed by 109 * renderer, track group and track (in that order). 110 * @param unmappedTrackGroups {@link TrackGroup}s not mapped to any renderer. 111 */ 112 @SuppressWarnings("deprecation") MappedTrackInfo( String[] rendererNames, int[] rendererTrackTypes, TrackGroupArray[] rendererTrackGroups, @AdaptiveSupport int[] rendererMixedMimeTypeAdaptiveSupports, @Capabilities int[][][] rendererFormatSupports, TrackGroupArray unmappedTrackGroups)113 /* package */ MappedTrackInfo( 114 String[] rendererNames, 115 int[] rendererTrackTypes, 116 TrackGroupArray[] rendererTrackGroups, 117 @AdaptiveSupport int[] rendererMixedMimeTypeAdaptiveSupports, 118 @Capabilities int[][][] rendererFormatSupports, 119 TrackGroupArray unmappedTrackGroups) { 120 this.rendererNames = rendererNames; 121 this.rendererTrackTypes = rendererTrackTypes; 122 this.rendererTrackGroups = rendererTrackGroups; 123 this.rendererFormatSupports = rendererFormatSupports; 124 this.rendererMixedMimeTypeAdaptiveSupports = rendererMixedMimeTypeAdaptiveSupports; 125 this.unmappedTrackGroups = unmappedTrackGroups; 126 this.rendererCount = rendererTrackTypes.length; 127 this.length = rendererCount; 128 } 129 130 /** Returns the number of renderers. */ getRendererCount()131 public int getRendererCount() { 132 return rendererCount; 133 } 134 135 /** 136 * Returns the name of the renderer at a given index. 137 * 138 * @see Renderer#getName() 139 * @param rendererIndex The renderer index. 140 * @return The name of the renderer. 141 */ getRendererName(int rendererIndex)142 public String getRendererName(int rendererIndex) { 143 return rendererNames[rendererIndex]; 144 } 145 146 /** 147 * Returns the track type that the renderer at a given index handles. 148 * 149 * @see Renderer#getTrackType() 150 * @param rendererIndex The renderer index. 151 * @return One of the {@code TRACK_TYPE_*} constants defined in {@link C}. 152 */ getRendererType(int rendererIndex)153 public int getRendererType(int rendererIndex) { 154 return rendererTrackTypes[rendererIndex]; 155 } 156 157 /** 158 * Returns the {@link TrackGroup}s mapped to the renderer at the specified index. 159 * 160 * @param rendererIndex The renderer index. 161 * @return The corresponding {@link TrackGroup}s. 162 */ getTrackGroups(int rendererIndex)163 public TrackGroupArray getTrackGroups(int rendererIndex) { 164 return rendererTrackGroups[rendererIndex]; 165 } 166 167 /** 168 * Returns the extent to which a renderer can play the tracks that are mapped to it. 169 * 170 * @param rendererIndex The renderer index. 171 * @return The {@link RendererSupport}. 172 */ 173 @RendererSupport getRendererSupport(int rendererIndex)174 public int getRendererSupport(int rendererIndex) { 175 @RendererSupport int bestRendererSupport = RENDERER_SUPPORT_NO_TRACKS; 176 @Capabilities int[][] rendererFormatSupport = rendererFormatSupports[rendererIndex]; 177 for (@Capabilities int[] trackGroupFormatSupport : rendererFormatSupport) { 178 for (@Capabilities int trackFormatSupport : trackGroupFormatSupport) { 179 int trackRendererSupport; 180 switch (RendererCapabilities.getFormatSupport(trackFormatSupport)) { 181 case RendererCapabilities.FORMAT_HANDLED: 182 return RENDERER_SUPPORT_PLAYABLE_TRACKS; 183 case RendererCapabilities.FORMAT_EXCEEDS_CAPABILITIES: 184 trackRendererSupport = RENDERER_SUPPORT_EXCEEDS_CAPABILITIES_TRACKS; 185 break; 186 case RendererCapabilities.FORMAT_UNSUPPORTED_TYPE: 187 case RendererCapabilities.FORMAT_UNSUPPORTED_SUBTYPE: 188 case RendererCapabilities.FORMAT_UNSUPPORTED_DRM: 189 trackRendererSupport = RENDERER_SUPPORT_UNSUPPORTED_TRACKS; 190 break; 191 default: 192 throw new IllegalStateException(); 193 } 194 bestRendererSupport = Math.max(bestRendererSupport, trackRendererSupport); 195 } 196 } 197 return bestRendererSupport; 198 } 199 200 /** @deprecated Use {@link #getTypeSupport(int)}. */ 201 @Deprecated 202 @RendererSupport getTrackTypeRendererSupport(int trackType)203 public int getTrackTypeRendererSupport(int trackType) { 204 return getTypeSupport(trackType); 205 } 206 207 /** 208 * Returns the extent to which tracks of a specified type are supported. This is the best level 209 * of support obtained from {@link #getRendererSupport(int)} for all renderers that handle the 210 * specified type. If no such renderers exist then {@link #RENDERER_SUPPORT_NO_TRACKS} is 211 * returned. 212 * 213 * @param trackType The track type. One of the {@link C} {@code TRACK_TYPE_*} constants. 214 * @return The {@link RendererSupport}. 215 */ 216 @RendererSupport getTypeSupport(int trackType)217 public int getTypeSupport(int trackType) { 218 @RendererSupport int bestRendererSupport = RENDERER_SUPPORT_NO_TRACKS; 219 for (int i = 0; i < rendererCount; i++) { 220 if (rendererTrackTypes[i] == trackType) { 221 bestRendererSupport = Math.max(bestRendererSupport, getRendererSupport(i)); 222 } 223 } 224 return bestRendererSupport; 225 } 226 227 /** @deprecated Use {@link #getTrackSupport(int, int, int)}. */ 228 @Deprecated 229 @FormatSupport getTrackFormatSupport(int rendererIndex, int groupIndex, int trackIndex)230 public int getTrackFormatSupport(int rendererIndex, int groupIndex, int trackIndex) { 231 return getTrackSupport(rendererIndex, groupIndex, trackIndex); 232 } 233 234 /** 235 * Returns the extent to which an individual track is supported by the renderer. 236 * 237 * @param rendererIndex The renderer index. 238 * @param groupIndex The index of the track group to which the track belongs. 239 * @param trackIndex The index of the track within the track group. 240 * @return The {@link FormatSupport}. 241 */ 242 @FormatSupport getTrackSupport(int rendererIndex, int groupIndex, int trackIndex)243 public int getTrackSupport(int rendererIndex, int groupIndex, int trackIndex) { 244 return RendererCapabilities.getFormatSupport( 245 rendererFormatSupports[rendererIndex][groupIndex][trackIndex]); 246 } 247 248 /** 249 * Returns the extent to which a renderer supports adaptation between supported tracks in a 250 * specified {@link TrackGroup}. 251 * 252 * <p>Tracks for which {@link #getTrackSupport(int, int, int)} returns {@link 253 * RendererCapabilities#FORMAT_HANDLED} are always considered. Tracks for which {@link 254 * #getTrackSupport(int, int, int)} returns {@link 255 * RendererCapabilities#FORMAT_EXCEEDS_CAPABILITIES} are also considered if {@code 256 * includeCapabilitiesExceededTracks} is set to {@code true}. Tracks for which {@link 257 * #getTrackSupport(int, int, int)} returns {@link RendererCapabilities#FORMAT_UNSUPPORTED_DRM}, 258 * {@link RendererCapabilities#FORMAT_UNSUPPORTED_TYPE} or {@link 259 * RendererCapabilities#FORMAT_UNSUPPORTED_SUBTYPE} are never considered. 260 * 261 * @param rendererIndex The renderer index. 262 * @param groupIndex The index of the track group. 263 * @param includeCapabilitiesExceededTracks Whether tracks that exceed the capabilities of the 264 * renderer are included when determining support. 265 * @return The {@link AdaptiveSupport}. 266 */ 267 @AdaptiveSupport getAdaptiveSupport( int rendererIndex, int groupIndex, boolean includeCapabilitiesExceededTracks)268 public int getAdaptiveSupport( 269 int rendererIndex, int groupIndex, boolean includeCapabilitiesExceededTracks) { 270 int trackCount = rendererTrackGroups[rendererIndex].get(groupIndex).length; 271 // Iterate over the tracks in the group, recording the indices of those to consider. 272 int[] trackIndices = new int[trackCount]; 273 int trackIndexCount = 0; 274 for (int i = 0; i < trackCount; i++) { 275 @FormatSupport int fixedSupport = getTrackSupport(rendererIndex, groupIndex, i); 276 if (fixedSupport == RendererCapabilities.FORMAT_HANDLED 277 || (includeCapabilitiesExceededTracks 278 && fixedSupport == RendererCapabilities.FORMAT_EXCEEDS_CAPABILITIES)) { 279 trackIndices[trackIndexCount++] = i; 280 } 281 } 282 trackIndices = Arrays.copyOf(trackIndices, trackIndexCount); 283 return getAdaptiveSupport(rendererIndex, groupIndex, trackIndices); 284 } 285 286 /** 287 * Returns the extent to which a renderer supports adaptation between specified tracks within a 288 * {@link TrackGroup}. 289 * 290 * @param rendererIndex The renderer index. 291 * @param groupIndex The index of the track group. 292 * @return The {@link AdaptiveSupport}. 293 */ 294 @AdaptiveSupport getAdaptiveSupport(int rendererIndex, int groupIndex, int[] trackIndices)295 public int getAdaptiveSupport(int rendererIndex, int groupIndex, int[] trackIndices) { 296 int handledTrackCount = 0; 297 @AdaptiveSupport int adaptiveSupport = RendererCapabilities.ADAPTIVE_SEAMLESS; 298 boolean multipleMimeTypes = false; 299 String firstSampleMimeType = null; 300 for (int i = 0; i < trackIndices.length; i++) { 301 int trackIndex = trackIndices[i]; 302 String sampleMimeType = 303 rendererTrackGroups[rendererIndex].get(groupIndex).getFormat(trackIndex).sampleMimeType; 304 if (handledTrackCount++ == 0) { 305 firstSampleMimeType = sampleMimeType; 306 } else { 307 multipleMimeTypes |= !Util.areEqual(firstSampleMimeType, sampleMimeType); 308 } 309 adaptiveSupport = 310 Math.min( 311 adaptiveSupport, 312 RendererCapabilities.getAdaptiveSupport( 313 rendererFormatSupports[rendererIndex][groupIndex][i])); 314 } 315 return multipleMimeTypes 316 ? Math.min(adaptiveSupport, rendererMixedMimeTypeAdaptiveSupports[rendererIndex]) 317 : adaptiveSupport; 318 } 319 320 /** @deprecated Use {@link #getUnmappedTrackGroups()}. */ 321 @Deprecated getUnassociatedTrackGroups()322 public TrackGroupArray getUnassociatedTrackGroups() { 323 return getUnmappedTrackGroups(); 324 } 325 326 /** Returns {@link TrackGroup}s not mapped to any renderer. */ getUnmappedTrackGroups()327 public TrackGroupArray getUnmappedTrackGroups() { 328 return unmappedTrackGroups; 329 } 330 331 } 332 333 @Nullable private MappedTrackInfo currentMappedTrackInfo; 334 335 /** 336 * Returns the mapping information for the currently active track selection, or null if no 337 * selection is currently active. 338 */ getCurrentMappedTrackInfo()339 public final @Nullable MappedTrackInfo getCurrentMappedTrackInfo() { 340 return currentMappedTrackInfo; 341 } 342 343 // TrackSelector implementation. 344 345 @Override onSelectionActivated(Object info)346 public final void onSelectionActivated(Object info) { 347 currentMappedTrackInfo = (MappedTrackInfo) info; 348 } 349 350 @Override selectTracks( RendererCapabilities[] rendererCapabilities, TrackGroupArray trackGroups, MediaPeriodId periodId, Timeline timeline)351 public final TrackSelectorResult selectTracks( 352 RendererCapabilities[] rendererCapabilities, 353 TrackGroupArray trackGroups, 354 MediaPeriodId periodId, 355 Timeline timeline) 356 throws ExoPlaybackException { 357 // Structures into which data will be written during the selection. The extra item at the end 358 // of each array is to store data associated with track groups that cannot be associated with 359 // any renderer. 360 int[] rendererTrackGroupCounts = new int[rendererCapabilities.length + 1]; 361 TrackGroup[][] rendererTrackGroups = new TrackGroup[rendererCapabilities.length + 1][]; 362 @Capabilities int[][][] rendererFormatSupports = new int[rendererCapabilities.length + 1][][]; 363 for (int i = 0; i < rendererTrackGroups.length; i++) { 364 rendererTrackGroups[i] = new TrackGroup[trackGroups.length]; 365 rendererFormatSupports[i] = new int[trackGroups.length][]; 366 } 367 368 // Determine the extent to which each renderer supports mixed mimeType adaptation. 369 @AdaptiveSupport 370 int[] rendererMixedMimeTypeAdaptationSupports = 371 getMixedMimeTypeAdaptationSupports(rendererCapabilities); 372 373 // Associate each track group to a preferred renderer, and evaluate the support that the 374 // renderer provides for each track in the group. 375 for (int groupIndex = 0; groupIndex < trackGroups.length; groupIndex++) { 376 TrackGroup group = trackGroups.get(groupIndex); 377 // Associate the group to a preferred renderer. 378 boolean preferUnassociatedRenderer = 379 MimeTypes.getTrackType(group.getFormat(0).sampleMimeType) == C.TRACK_TYPE_METADATA; 380 int rendererIndex = 381 findRenderer( 382 rendererCapabilities, group, rendererTrackGroupCounts, preferUnassociatedRenderer); 383 // Evaluate the support that the renderer provides for each track in the group. 384 @Capabilities 385 int[] rendererFormatSupport = 386 rendererIndex == rendererCapabilities.length 387 ? new int[group.length] 388 : getFormatSupport(rendererCapabilities[rendererIndex], group); 389 // Stash the results. 390 int rendererTrackGroupCount = rendererTrackGroupCounts[rendererIndex]; 391 rendererTrackGroups[rendererIndex][rendererTrackGroupCount] = group; 392 rendererFormatSupports[rendererIndex][rendererTrackGroupCount] = rendererFormatSupport; 393 rendererTrackGroupCounts[rendererIndex]++; 394 } 395 396 // Create a track group array for each renderer, and trim each rendererFormatSupports entry. 397 TrackGroupArray[] rendererTrackGroupArrays = new TrackGroupArray[rendererCapabilities.length]; 398 String[] rendererNames = new String[rendererCapabilities.length]; 399 int[] rendererTrackTypes = new int[rendererCapabilities.length]; 400 for (int i = 0; i < rendererCapabilities.length; i++) { 401 int rendererTrackGroupCount = rendererTrackGroupCounts[i]; 402 rendererTrackGroupArrays[i] = 403 new TrackGroupArray( 404 Util.nullSafeArrayCopy(rendererTrackGroups[i], rendererTrackGroupCount)); 405 rendererFormatSupports[i] = 406 Util.nullSafeArrayCopy(rendererFormatSupports[i], rendererTrackGroupCount); 407 rendererNames[i] = rendererCapabilities[i].getName(); 408 rendererTrackTypes[i] = rendererCapabilities[i].getTrackType(); 409 } 410 411 // Create a track group array for track groups not mapped to a renderer. 412 int unmappedTrackGroupCount = rendererTrackGroupCounts[rendererCapabilities.length]; 413 TrackGroupArray unmappedTrackGroupArray = 414 new TrackGroupArray( 415 Util.nullSafeArrayCopy( 416 rendererTrackGroups[rendererCapabilities.length], unmappedTrackGroupCount)); 417 418 // Package up the track information and selections. 419 MappedTrackInfo mappedTrackInfo = 420 new MappedTrackInfo( 421 rendererNames, 422 rendererTrackTypes, 423 rendererTrackGroupArrays, 424 rendererMixedMimeTypeAdaptationSupports, 425 rendererFormatSupports, 426 unmappedTrackGroupArray); 427 428 Pair<@NullableType RendererConfiguration[], @NullableType TrackSelection[]> result = 429 selectTracks( 430 mappedTrackInfo, rendererFormatSupports, rendererMixedMimeTypeAdaptationSupports); 431 return new TrackSelectorResult(result.first, result.second, mappedTrackInfo); 432 } 433 434 /** 435 * Given mapped track information, returns a track selection and configuration for each renderer. 436 * 437 * @param mappedTrackInfo Mapped track information. 438 * @param rendererFormatSupports The {@link Capabilities} for ach mapped track, indexed by 439 * renderer, track group and track (in that order). 440 * @param rendererMixedMimeTypeAdaptationSupport The {@link AdaptiveSupport} for mixed MIME type 441 * adaptation for the renderer. 442 * @return A pair consisting of the track selections and configurations for each renderer. A null 443 * configuration indicates the renderer should be disabled, in which case the track selection 444 * will also be null. A track selection may also be null for a non-disabled renderer if {@link 445 * RendererCapabilities#getTrackType()} is {@link C#TRACK_TYPE_NONE}. 446 * @throws ExoPlaybackException If an error occurs while selecting the tracks. 447 */ 448 protected abstract Pair<@NullableType RendererConfiguration[], @NullableType TrackSelection[]> selectTracks( MappedTrackInfo mappedTrackInfo, @Capabilities int[][][] rendererFormatSupports, @AdaptiveSupport int[] rendererMixedMimeTypeAdaptationSupport)449 selectTracks( 450 MappedTrackInfo mappedTrackInfo, 451 @Capabilities int[][][] rendererFormatSupports, 452 @AdaptiveSupport int[] rendererMixedMimeTypeAdaptationSupport) 453 throws ExoPlaybackException; 454 455 /** 456 * Finds the renderer to which the provided {@link TrackGroup} should be mapped. 457 * 458 * <p>A {@link TrackGroup} is mapped to the renderer that reports the highest of (listed in 459 * decreasing order of support) {@link RendererCapabilities#FORMAT_HANDLED}, {@link 460 * RendererCapabilities#FORMAT_EXCEEDS_CAPABILITIES}, {@link 461 * RendererCapabilities#FORMAT_UNSUPPORTED_DRM} and {@link 462 * RendererCapabilities#FORMAT_UNSUPPORTED_SUBTYPE}. 463 * 464 * <p>In the case that two or more renderers report the same level of support, the assignment 465 * depends on {@code preferUnassociatedRenderer}. 466 * 467 * <ul> 468 * <li>If {@code preferUnassociatedRenderer} is false, the renderer with the lowest index is 469 * chosen regardless of how many other track groups are already mapped to this renderer. 470 * <li>If {@code preferUnassociatedRenderer} is true, the renderer with the lowest index and no 471 * other mapped track group is chosen, or the renderer with the lowest index if all 472 * available renderers have already mapped track groups. 473 * </ul> 474 * 475 * <p>If all renderers report {@link RendererCapabilities#FORMAT_UNSUPPORTED_TYPE} for all of the 476 * tracks in the group, then {@code renderers.length} is returned to indicate that the group was 477 * not mapped to any renderer. 478 * 479 * @param rendererCapabilities The {@link RendererCapabilities} of the renderers. 480 * @param group The track group to map to a renderer. 481 * @param rendererTrackGroupCounts The number of already mapped track groups for each renderer. 482 * @param preferUnassociatedRenderer Whether renderers unassociated to any track group should be 483 * preferred. 484 * @return The index of the renderer to which the track group was mapped, or {@code 485 * renderers.length} if it was not mapped to any renderer. 486 * @throws ExoPlaybackException If an error occurs finding a renderer. 487 */ findRenderer( RendererCapabilities[] rendererCapabilities, TrackGroup group, int[] rendererTrackGroupCounts, boolean preferUnassociatedRenderer)488 private static int findRenderer( 489 RendererCapabilities[] rendererCapabilities, 490 TrackGroup group, 491 int[] rendererTrackGroupCounts, 492 boolean preferUnassociatedRenderer) 493 throws ExoPlaybackException { 494 int bestRendererIndex = rendererCapabilities.length; 495 @FormatSupport int bestFormatSupportLevel = RendererCapabilities.FORMAT_UNSUPPORTED_TYPE; 496 boolean bestRendererIsUnassociated = true; 497 for (int rendererIndex = 0; rendererIndex < rendererCapabilities.length; rendererIndex++) { 498 RendererCapabilities rendererCapability = rendererCapabilities[rendererIndex]; 499 @FormatSupport int formatSupportLevel = RendererCapabilities.FORMAT_UNSUPPORTED_TYPE; 500 for (int trackIndex = 0; trackIndex < group.length; trackIndex++) { 501 @FormatSupport 502 int trackFormatSupportLevel = 503 RendererCapabilities.getFormatSupport( 504 rendererCapability.supportsFormat(group.getFormat(trackIndex))); 505 formatSupportLevel = Math.max(formatSupportLevel, trackFormatSupportLevel); 506 } 507 boolean rendererIsUnassociated = rendererTrackGroupCounts[rendererIndex] == 0; 508 if (formatSupportLevel > bestFormatSupportLevel 509 || (formatSupportLevel == bestFormatSupportLevel 510 && preferUnassociatedRenderer 511 && !bestRendererIsUnassociated 512 && rendererIsUnassociated)) { 513 bestRendererIndex = rendererIndex; 514 bestFormatSupportLevel = formatSupportLevel; 515 bestRendererIsUnassociated = rendererIsUnassociated; 516 } 517 } 518 return bestRendererIndex; 519 } 520 521 /** 522 * Calls {@link RendererCapabilities#supportsFormat} for each track in the specified {@link 523 * TrackGroup}, returning the results in an array. 524 * 525 * @param rendererCapabilities The {@link RendererCapabilities} of the renderer. 526 * @param group The track group to evaluate. 527 * @return An array containing {@link Capabilities} for each track in the group. 528 * @throws ExoPlaybackException If an error occurs determining the format support. 529 */ 530 @Capabilities getFormatSupport(RendererCapabilities rendererCapabilities, TrackGroup group)531 private static int[] getFormatSupport(RendererCapabilities rendererCapabilities, TrackGroup group) 532 throws ExoPlaybackException { 533 @Capabilities int[] formatSupport = new int[group.length]; 534 for (int i = 0; i < group.length; i++) { 535 formatSupport[i] = rendererCapabilities.supportsFormat(group.getFormat(i)); 536 } 537 return formatSupport; 538 } 539 540 /** 541 * Calls {@link RendererCapabilities#supportsMixedMimeTypeAdaptation()} for each renderer, 542 * returning the results in an array. 543 * 544 * @param rendererCapabilities The {@link RendererCapabilities} of the renderers. 545 * @return An array containing the {@link AdaptiveSupport} for mixed MIME type adaptation for the 546 * renderer. 547 * @throws ExoPlaybackException If an error occurs determining the adaptation support. 548 */ 549 @AdaptiveSupport getMixedMimeTypeAdaptationSupports( RendererCapabilities[] rendererCapabilities)550 private static int[] getMixedMimeTypeAdaptationSupports( 551 RendererCapabilities[] rendererCapabilities) throws ExoPlaybackException { 552 @AdaptiveSupport int[] mixedMimeTypeAdaptationSupport = new int[rendererCapabilities.length]; 553 for (int i = 0; i < mixedMimeTypeAdaptationSupport.length; i++) { 554 mixedMimeTypeAdaptationSupport[i] = rendererCapabilities[i].supportsMixedMimeTypeAdaptation(); 555 } 556 return mixedMimeTypeAdaptationSupport; 557 } 558 559 } 560