如何在 Exoplayer 的 HLS Streaming URL 中打开 On/OFF 隐藏式字幕?

How to turn On/OFF closed captions in HLS Streaming URL in Exoplayer?

我正在使用 Exoplayer 版本 2.0.4 播放 HLS 流(.m3u8)。我的 HLS 流包含隐藏式字幕。我如何使用 exoplayer 控制隐藏式字幕?可不可以hide/show需要时加字幕,需要时改变字幕布局的位置?

我能够使用 DefaultTrackSelector 在 ExoPlayer 2 中控制字幕选择。下面的代码是根据ExoPlayer 2 Demo的TrackSelectionHelperclass修改的,更多实现细节可以参考

要关闭字幕,您需要禁用文本轨道的渲染器并清除选择覆盖。

trackSelector.setRendererDisabled(TRACK_TEXT, true);
trackSelector.clearSelectionOverrides();

TRACK_TEXT 是我创建的局部静态变量,代表文本轨道 (2) 的索引,与 video/audio 轨道相关。我相信 SelectionOverrides 只是以编程方式指定的轨道选择。

要再次启用轨道,您需要为文本轨道启用渲染器,然后为您想要的文本轨道设置一个新的 SelectionOverride。在执行此操作之前,您需要从 DefaultTrackSelector.

中获取当前映射的文本轨道的 TrackGroupArray
MappingTrackSelector.MappedTrackInfo mappedTrackInfo = trackSelector.getCurrentMappedTrackInfo();
TrackGroupArray textGroups = mappedTrackInfo.getTrackGroups(TRACK_TEXT); // list of captions
int groupIndex = 1; // index of desired caption track within the textGroups array

trackSelector.setRendererDisabled(TRACK_TEXT, false);
MappingTrackSelector.SelectionOverride override = 
    new MappingTrackSelector.SelectionOverride(fixedFactory, groupIndex, 0);
trackSelector.setSelectionOverride(TRACK_TEXT, textGroups, override);

有关更多实现细节(例如,初始化 trackSelector 和 fixedFactory),请查看 ExoPlayer 2 Demo

您可以使用 SubtitleView 在布局中定位字幕。您的 class 将需要实施 TextRenderer.Output 并覆盖 onCues() 方法。

@Override
public void onCues(List<Cue> cues) {
    if (subtitleView != null) {
        subtitleView.onCues(cues);
    }
}

在我的应用程序中,我将 trackselecktor 初始化如下

关闭视频轨道的隐藏式字幕

trackSelector = new DefaultTrackSelector(videoTrackSelectionFactory);
    trackSelector.setParameters(new DefaultTrackSelector.ParametersBuilder()
            .setRendererDisabled(C.TRACK_TYPE_VIDEO, true)
            .build()
    );

打开视频轨道的隐藏式字幕

trackSelector = new DefaultTrackSelector(videoTrackSelectionFactory);
    trackSelector.setParameters(new DefaultTrackSelector.ParametersBuilder()
            .setRendererDisabled(C.TRACK_TYPE_VIDEO, false)
            .build()
    );

更新ExoPlayer库后

implementation 'com.google.android.exoplayer:exoplayer:2.9.5'

我发现 MappingTrackSelector.SelectionOverride 方法已经不存在了。

我无法找到可行的替代方案,因为仅替换为 DefaultTrackSelector.SelectionOverride 对我不起作用,而且我的视频没有播放字幕。

MediaSource mediaSource =  new HlsMediaSource.Factory(mediaDataSourceFactory).createMediaSource(uri);

最后一组对我有用的行:

TrackGroupArray trackGroups = trackSelector.getCurrentMappedTrackInfo().getTrackGroups(newSubtitle.renderIndex);

DefaultTrackSelector.ParametersBuilder paramsBuilder = trackSelector.buildUponParameters();

DefaultTrackSelector.SelectionOverride sOverride = new DefaultTrackSelector.SelectionOverride(newSubtitle.groupIndex, newSubtitle.indexWithinGroup);

boolean isDisabled = trackSelector.getParameters().getRendererDisabled(newSubtitle.renderIndex);

paramsBuilder.setRendererDisabled(newSubtitle.renderIndex, isDisabled);

if (sOverride != null) {
    paramsBuilder.setSelectionOverride(newSubtitle.renderIndex, trackGroups, sOverride);
} else {
    paramsBuilder.clearSelectionOverrides(newSubtitle.renderIndex);
}

trackSelector.setParameters(paramsBuilder);

旧代码是:

TrackGroupArray trackGroups = trackSelector.getCurrentMappedTrackInfo().getTrackGroups(newSubtitle.renderIndex);

MappingTrackSelector.SelectionOverride sOverride = new MappingTrackSelector.SelectionOverride(
    new FixedTrackSelection.Factory(), 
    newSubtitle.groupIndex, 
    newSubtitle.indexWithinGroup
);

trackSelector.setSelectionOverride(newSubtitle.renderIndex, trackGroups, sOverride);
trackSelector.setRendererDisabled(newSubtitle.renderIndex, false);

关闭字幕:

DefaultTrackSelector.ParametersBuilder paramsBuilder = trackSelector.buildUponParameters();

paramsBuilder.setRendererDisabled(playingSubtitle.renderIndex, true);

trackSelector.setParameters(paramsBuilder);

要禁用轨道,比方说字幕(文本)轨道,您需要使用您之前传递给 ExoPlayerFactory.newSimpleInstanceDefaultTrackSelector 来禁用track 你需要它的 rendererIndex。在 ExoPlayer 中选择曲目实际上有两个令人困惑的术语(至少对我而言!),一个是 TrackType,另一个是 渲染器索引。基本上有一些TrackTypes可以在com.google.android.exoplayer2.C class中访问,主要的是TRACK_TYPE_AUDIOTRACK_TYPE_VIDEOTRACK_TYPE_TEXT。但另一方面 rendererIndex 可以是从 0 开始的任何数字(我猜)。因此,要禁用轨道,您需要先找到它的 rendererIndex。然后使用下面的代码禁用轨道:

trackSelector
            ?.buildUponParameters()
            ?.setRendererDisabled(rendererIndex, true)
            ?.let {
                trackSelector?.setParameters(it)
            }

Xamarin.Android 的解决方案:

[Obsolete]
private DefaultTrackSelector CreateTrackSelector()
{
    var bandwidthMeter = new DefaultBandwidthMeter();
    var videoTrackSelectionFactory = new AdaptiveTrackSelection.Factory(bandwidthMeter);
    var trackSelector = new DefaultTrackSelector(videoTrackSelectionFactory);
    var trackParameter = new DefaultTrackSelector.ParametersBuilder()
         // disables closed caption / subtitle
        .SetDisabledTextTrackSelectionFlags(C.TrackTypeText)
        .Build();
    trackSelector.SetParameters(trackParameter);
    return trackSelector;
}

我强烈建议不要像这样使用常量 TRACK_TEXTC.TRACK_TYPE_TEXT

trackSelector.setRendererDisabled(TRACK_TEXT, true);
trackSelector.clearSelectionOverrides();

因为它可能因您使用的资产而异,您可以确保使用以下代码(Kotlin 版本)禁用正确的渲染器:

  private fun disableSubtitles(){
    (0 until (trackSelector.currentMappedTrackInfo?.rendererCount ?: 0)).filter {position ->
      player.getRendererType(position) == C.TRACK_TYPE_TEXT
    }.map {position ->
      trackSelector.parameters = trackSelector.buildUponParameters()
          .setRendererDisabled(position,true)
          .clearSelectionOverrides(position)
          .build()
    }
  }