轨道选择

当媒体项包含多个轨道时,轨道选择是确定选择其中哪些轨道进行播放的过程。轨道选择流程由 TrackSelectionParameters 配置,这允许指定许多不同的限制条件和替换项,以影响轨道选择。

查询可用轨道

您可以监听 Player.Listener.onTracksChanged,以便获取有关轨道更改的通知,包括:

  • 当正在播放的媒体项准备完毕时,可用轨道变为已知。请注意,播放器需要准备媒体项才能知道其中包含什么轨道。
  • 可用轨道因播放从一个媒体项到另一个媒体项而发生变化。
  • 对所选轨道的更改。

Kotlin

player.addListener(
  object : Player.Listener {
    override fun onTracksChanged(tracks: Tracks) {
      // Update UI using current tracks.
    }
  }
)

Java

player.addListener(
    new Player.Listener() {
      @Override
      public void onTracksChanged(Tracks tracks) {
        // Update UI using current tracks.
      }
    });

您也可以通过调用 player.getCurrentTracks() 查询当前轨道。 返回的 Tracks 包含一系列 Track.Group 对象,其中,单个 Group 中的轨道具有相同的内容,但采用不同的格式。

以如何对曲目分组的示例,假设有一种自适应播放,其中主视频 Feed 以五种比特率提供,备用视频 Feed(例如,体育比赛中的不同镜头角度)以两种比特率提供。在这种情况下,将有两个视频轨道组,一个对应于包含 5 个轨道的主视频 Feed,另一个对应于包含两个轨道的备用视频 Feed。

系统不会将语言不同的音轨归为一组,因为不同语言的内容会被视为不同内容。相反,如果音轨所用的语言仅在比特率、采样率、声道数量等方面有所不同,则可将其分组。这也适用于文本轨道。

您可以查询每个 Group,以确定支持播放的曲目、当前选择的曲目以及每个曲目使用的 Format

Kotlin

for (trackGroup in tracks.groups) {
  // Group level information.
  val trackType = trackGroup.type
  val trackInGroupIsSelected = trackGroup.isSelected
  val trackInGroupIsSupported = trackGroup.isSupported
  for (i in 0 until trackGroup.length) {
    // Individual track information.
    val isSupported = trackGroup.isTrackSupported(i)
    val isSelected = trackGroup.isTrackSelected(i)
    val trackFormat = trackGroup.getTrackFormat(i)
  }
}

Java

for (Tracks.Group trackGroup : tracks.getGroups()) {
  // Group level information.
  @C.TrackType int trackType = trackGroup.getType();
  boolean trackInGroupIsSelected = trackGroup.isSelected();
  boolean trackInGroupIsSupported = trackGroup.isSupported();
  for (int i = 0; i < trackGroup.length; i++) {
    // Individual track information.
    boolean isSupported = trackGroup.isTrackSupported(i);
    boolean isSelected = trackGroup.isTrackSelected(i);
    Format trackFormat = trackGroup.getTrackFormat(i);
  }
}

  • 如果 Player 能够解码和呈现其样本,则支持轨道。请注意,即使支持同一类型的多个轨道组(例如多个音轨组),这仅表示它们单独受支持,播放器不一定能同时播放这些轨道组。
  • 如果根据当前 TrackSelectionParameters 选择了某个曲目进行播放,则会选择该曲目。如果选择了一个轨道组中的多个轨道,播放器会使用这些轨道进行自适应播放(例如,多个比特率不同的视频轨道)。请注意,每次只会播放其中一个轨道。

修改轨道选择参数

您可以使用 Player.setTrackSelectionParameters 来配置轨道选择过程。您可以在播放之前和播放期间执行此操作。以下示例演示了如何从播放器获取当前的 TrackSelectionParameters、对其进行修改,并使用修改后的结果更新 Player

Kotlin

player.trackSelectionParameters =
  player.trackSelectionParameters
    .buildUpon()
    .setMaxVideoSizeSd()
    .setPreferredAudioLanguage("hu")
    .build()

Java

player.setTrackSelectionParameters(
    player
        .getTrackSelectionParameters()
        .buildUpon()
        .setMaxVideoSizeSd()
        .setPreferredAudioLanguage("hu")
        .build());

基于限制条件的轨道选择

TrackSelectionParameters 中的大多数选项都允许您指定约束条件,这些约束条件独立于实际可用的轨道。可用的限制条件包括:

  • 最大和最小视频宽度、高度、帧速率和比特率。
  • 最大声道数量和比特率。
  • 视频和音频的首选 MIME 类型。
  • 首选音频语言和角色标志。
  • 首选文本语言和角色标志。

ExoPlayer 为这些约束使用合理的默认设置,例如将视频分辨率限制为显示大小,并优先选用符合用户的系统语言区域设置的音频语言。

与从可用轨道中选择特定轨道相比,使用基于约束条件的轨道选择有几个好处:

  • 您可以先指定约束条件,然后再了解媒体项提供的跟踪内容。 这意味着,可以在播放器准备好媒体项之前指定约束条件,而选择特定轨道则需要应用代码等待,直到系统知道可用轨道为止。
  • 约束会应用于播放列表中的所有媒体项,即使这些媒体项具有不同的可用轨道。例如,系统将自动为所有媒体项应用首选音频语言约束条件,即使采用某个语言的轨道的 Format 因媒体项而异,也是如此。选择特定轨道时则并非如此,具体如下所述。

选择特定轨道

您可以使用 TrackSelectionParameters 选择特定轨道。首先,应使用 Player.getCurrentTracks 查询播放器的当前可用曲目。其次,确定要选择的轨道后,可以使用 TrackSelectionOverrideTrackSelectionParameters 上设置这些轨道。例如,如需从特定 audioTrackGroup 中选择第一首曲目,请使用以下代码:

Kotlin

player.trackSelectionParameters =
  player.trackSelectionParameters
    .buildUpon()
    .setOverrideForType(
      TrackSelectionOverride(audioTrackGroup.mediaTrackGroup, /* trackIndex= */ 0)
    )
    .build()

Java

player.setTrackSelectionParameters(
    player
        .getTrackSelectionParameters()
        .buildUpon()
        .setOverrideForType(
            new TrackSelectionOverride(
                audioTrackGroup.getMediaTrackGroup(), /* trackIndex= */ 0))
        .build());

TrackSelectionOverride 将仅适用于所含 TrackGroup 与替换中指定的内容完全匹配的媒体内容。因此,如果后续媒体项包含不同的轨道,替换项可能不会应用于该媒体项。

停用轨道类型或组

您可以使用 TrackSelectionParameters.Builder.setTrackTypeDisabled 完全停用视频、音频或文字等轨道类型。系统会为所有媒体内容停用已停用的轨道类型:

Kotlin

player.trackSelectionParameters =
  player.trackSelectionParameters
    .buildUpon()
    .setTrackTypeDisabled(C.TRACK_TYPE_VIDEO, /* disabled= */ true)
    .build()

Java

player.setTrackSelectionParameters(
    player
        .getTrackSelectionParameters()
        .buildUpon()
        .setTrackTypeDisabled(C.TRACK_TYPE_VIDEO, /* disabled= */ true)
        .build());

或者,也可以通过为相应组指定空的替换值来阻止从特定 TrackGroup 选择轨道:

Kotlin

player.trackSelectionParameters =
  player.trackSelectionParameters
    .buildUpon()
    .addOverride(
      TrackSelectionOverride(disabledTrackGroup.mediaTrackGroup, /* trackIndices= */ listOf())
    )
    .build()

Java

player.setTrackSelectionParameters(
    player
        .getTrackSelectionParameters()
        .buildUpon()
        .addOverride(
            new TrackSelectionOverride(
                disabledTrackGroup.getMediaTrackGroup(),
                /* trackIndices= */ ImmutableList.of()))
        .build());

自定义轨道选择器

轨道的选择由 TrackSelector 负责,每当构建 ExoPlayer 并在稍后使用 ExoPlayer.getTrackSelector() 获取该实例时,均可提供该实例。

Kotlin

val trackSelector = DefaultTrackSelector(context)
val player = ExoPlayer.Builder(context).setTrackSelector(trackSelector).build()

Java

DefaultTrackSelector trackSelector = new DefaultTrackSelector(context);
ExoPlayer player = new ExoPlayer.Builder(context).setTrackSelector(trackSelector).build();

DefaultTrackSelector 是一个灵活的 TrackSelector,适合大多数用例。它使用 Player 中设置的 TrackSelectionParameters,但还提供了一些可在 DefaultTrackSelector.ParametersBuilder 中指定的高级自定义选项:

Kotlin

trackSelector.setParameters(
  trackSelector.buildUponParameters().setAllowVideoMixedMimeTypeAdaptiveness(true))
)

Java

trackSelector.setParameters(
    trackSelector.buildUponParameters().setAllowVideoMixedMimeTypeAdaptiveness(true));

隧道

如果渲染程序和所选轨道的组合支持隧道式播放,您可以启用隧道播放。为此,请使用 DefaultTrackSelector.ParametersBuilder.setTunnelingEnabled(true)

音频分流 (offload)

如果渲染程序和所选轨道的组合支持分流音频播放,您可以启用分流音频播放。为此,请在 TrackSelectionParameters 中指定 AudioOffloadModePreferences

Kotlin

val audioOffloadPreferences =
  AudioOffloadPreferences.Builder()
      .setAudioOffloadMode(AudioOffloadPreferences.AUDIO_OFFLOAD_MODE_ENABLED)
      // Add additional options as needed
      .setIsGaplessSupportRequired(true)
      .build()
player.trackSelectionParameters =
  player.trackSelectionParameters
    .buildUpon()
    .setAudioOffloadPreferences(audioOffloadPreferences)
    .build()

Java

AudioOffloadPreferences audioOffloadPreferences =
  new AudioOffloadPreferences.Builder()
      .setAudioOffloadMode(AudioOffloadPreferences.AUDIO_OFFLOAD_MODE_ENABLED)
      // Add additional options as needed
      .setIsGaplessSupportRequired(true)
      .build();
player.setTrackSelectionParameters(
  player.getTrackSelectionParameters()
    .buildUpon()
    .setAudioOffloadPreferences(audioOffloadPreferences)
    .build());
);