返回

ExoPlayer 内嵌字幕显示指南:自动与手动选择

Android

ExoPlayer 展示内嵌字幕

视频播放时,内嵌字幕是一种常见需求。通常,视频文件本身就包含字幕数据,无需额外字幕文件。此文将介绍如何使用 ExoPlayer 显示这些内嵌字幕。

问题分析

ExoPlayer 可以处理多种字幕格式,包括外挂字幕和内嵌字幕。对于外挂字幕,像文章开头提供的代码那样配置 SubtitleConfiguration 即可。对于内嵌字幕,播放器会自动检测并尝试解码。问题的关键在于,默认情况下,ExoPlayer 可能没有启用对所有可用内嵌字幕轨道的自动选择。

解决方案一:启用默认字幕轨道选择

一个简单的办法是告诉 ExoPlayer 选择默认的字幕轨道。这通过调整 DefaultTrackSelector 的行为来实现。DefaultTrackSelector 负责决定选择哪个音视频和字幕轨道。

以下步骤和代码演示如何操作:

  1. 创建 DefaultTrackSelector 并配置其参数。allowVideoMixedMimeTypeAdaptiveness 用于设置混合编码自适应的规则。
  2. 实例化 ExoPlayer 时,将配置过的 TrackSelector 传递进去。这样 ExoPlayer 就知道了应如何选择合适的音视频和字幕轨道。
val trackSelector = DefaultTrackSelector(context).apply {
   parameters = buildUponParameters()
       .setRendererDisabled(C.TRACK_TYPE_TEXT, false) //确保字幕渲染器未禁用
        .setAllowVideoMixedMimeTypeAdaptiveness(true)  // 如果存在,启用视频自适应。 这取决于情况
        .setSelectionOverride(0, C.TRACK_TYPE_TEXT, null).build()
 }

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

player.setMediaItem(MediaItem.fromUri(videoUri))
player.prepare()
player.play()

此处 setRendererDisabled(C.TRACK_TYPE_TEXT, false) 非常关键,确保字幕渲染器不被禁用。setSelectionOverride(0, C.TRACK_TYPE_TEXT, null),表示选择索引为 0,且类型为TEXT的字幕轨道。 这会在无首选语言的情况下强制执行。

通过这些步骤,ExoPlayer 大概率会自动选择合适的字幕轨道。

解决方案二:显式选择字幕轨道

有时自动选择不能满足需要。如果想控制选择特定语言的字幕,或当有多个字幕轨道时进行手动选择,可以使用 Player.getCurrentTracks()方法获取当前媒体的所有可用轨道,并显式选择特定字幕轨道。

操作步骤如下:

  1. 获取当前媒体的 Tracks 对象。使用 player.getCurrentTracks() 获取 Tracks 实例,并通过循环遍历获取字幕轨道的信息。
  2. 过滤出 TRACK_TYPE_TEXT 的轨道并展示可用字幕的列表,可以选择使用对话框或是其它展示形式。
  3. 当用户选择了目标字幕,则使用trackSelectionParameters强制 ExoPlayer 选择对应的字幕轨道。
val mappedTrackInfo = player.currentTracksInfo

for (group in mappedTrackInfo.trackGroupInfos) {
    val trackGroup = group.mediaTrackGroup
    for(i in 0 until trackGroup.length){
        val trackFormat = trackGroup.getFormat(i)
        if(MimeTypes.isText(trackFormat.sampleMimeType)){

          // 在这里展示轨道信息
            Log.d(TAG, "Track found:${trackFormat.language} id: $i  mimeType:${trackFormat.sampleMimeType}")

            // 假设现在要选英文 (根据需要选择其它字幕,例如根据id选择)
           if("eng" == trackFormat.language){
              val trackSelector = DefaultTrackSelector(context)

              val override = MappingTrackSelector.SelectionOverride(i,  C.FORMAT_HANDLED)

              trackSelector.parameters = trackSelector.buildUponParameters()
                       .setSelectionOverride(0,C.TRACK_TYPE_TEXT,override) //  0: Media Track Group index;
                       .build()
              player.trackSelectionParameters = trackSelector.parameters

              break; //找到目标就跳出,实际项目中需谨慎
          }

        }
    }
}

这段代码示例说明了如何在多个字幕轨道中根据语言选择字幕。关键是通过 setSelectionOverride 方法配置 TrackSelector 参数,实现指定字幕轨道的选取。代码里的 if("eng" == trackFormat.language) 可以按实际的业务需求更改。需要指出的是 SelectionOverride 参数的第一个 int 类型的参数表示 trackGroup 在集合 TrackGroupInfo里的索引位置, 可以设置 0 或者从实际的情况进行选择,该参数非常关键,设置不当会出现 IllegalArgumentException: trackGroupIndex invalid:的错误。

总结

这两种方案都能解决在 ExoPlayer 中展示内嵌字幕的问题。第一种方法简洁,依赖 ExoPlayer 的自动选择逻辑。第二种方法更加灵活,可用于处理复杂场景或需要手动选择的情况。具体采用哪种,取决于项目的需求和对字幕控制的精细程度。选用时需综合考虑。务必确保正确设置了 DefaultTrackSelector 的相关参数,以防止出现字幕轨道被忽略的情况。同时需注意处理好多语言支持和无字幕轨道的情况。