大家好。几天前,有一项任务是在HLS流中切换WebVTT字幕。我们使用ExoPlayer播放视频,起初看来Google和Co.应该已经在“完成并完成”框中提供了解决方案。但是现实并不符合预期:)Googling和Habring并没有导致结果,而是归结为选择了官方演示应用程序 ExoPlayer。因为由于本文假设您对HLS的结构已经有所了解,并且在ExoPlayer中具有一定的经验,因此我们将重点放在这一点上。这是有关切换流(视频,音频,字幕)的文档告诉我们的。她几乎没有告诉我们-使用DefaultTrackSelector初始化播放器并使用它。就是这样,好的:)所有其他字幕(CEA-608,WebVtt)都像其他轨道一样,都存储在DefaultTrackSelector中,您需要能够获取它们。一切都分为组和子组,总之,内部结构如下所示:现在,让我们尝试获取WebVTT类型的字幕,它们应该以“ 3”类型存储在Renderer中(C.TRACK_TYPE_TEXT-Exo中的常量):fun getVttSubtitles(): List<String> {
val tracks = mutableListOf<String>()
defaultTrackSelector.currentMappedTrackInfo?.let { mappedTrackInfo ->
val renderCount = mappedTrackInfo.rendererCount
for (renderIndex in 0 until renderCount) {
val renderType = mappedTrackInfo.getRendererType(renderIndex)
if (renderType == C.TRACK_TYPE_TEXT) {
val trackGroupArray = mappedTrackInfo.getTrackGroups(renderIndex)
for (trackGroupArrayIndex in 0 until trackGroupArray.length) {
val trackGroup = trackGroupArray[trackGroupArrayIndex]
for (trackGroupIndex in 0 until trackGroup.length) {
val format = trackGroup.getFormat(trackGroupIndex)
if (format.sampleMimeType == MimeTypes.TEXT_VTT) {
tracks += format.language.orEmpty()
}
}
}
}
}
}
return tracks
}
如您所见,没有提供一些方便的迭代和搜索方式,您必须使用笔进行所有循环。但是我们不仅需要了解列表本身,还需要了解所选的选项(我们将在以后选择)。由于某些原因,您无法从DefaultTrackSelector获取选定的曲目,但可以使用ExoPlayer本身。获取方案大致相同,我们会做得更深入,但是在这里,我们跳过了通过渲染器的过程:fun getSelectedVttSubtitles(): List<String> {
val selectedLangs = mutableListOf<String>()
val currentTrackSelections = exoPlayer.currentTrackSelections
for (selectionIndex in 0 until currentTrackSelections.length) {
val trackSelection = currentTrackSelections[selectionIndex]
if (trackSelection != null) {
val length = trackSelection.length()
for (trackIndex in 0 until length) {
val format = trackSelection.getFormat(trackIndex)
if (format.sampleMimeType == MimeTypes.TEXT_VTT) {
selectedLangs += format.language.orEmpty()
}
}
}
}
return selectedLangs
}
好吧,我们有一个公共列表和一个选定列表。如何在UI上组合和显示不是本文的目的。有很多方法。我们只需要学习如何设置轨道即可。为了清楚起见,我们将以额头方式进行此操作,以便所有循环和索引均显而易见。通过其语言代码(“ ru”,“ en”,...)安装轨道:fun selectTrackByIsoCodeAndType(langCode: String) {
defaultTrackSelector.currentMappedTrackInfo?.let { mappedTrackInfo ->
val renderCount = mappedTrackInfo.rendererCount
for (renderIndex in 0 until renderCount) {
val renderType = mappedTrackInfo.getRendererType(renderIndex)
if (renderType == C.TRACK_TYPE_TEXT) {
val trackGroupArray = mappedTrackInfo.getTrackGroups(renderIndex)
for (trackGroupArrayIndex in 0 until trackGroupArray.length) {
val trackGroup = trackGroupArray[trackGroupArrayIndex]
for (trackGroupIndex in 0 until trackGroup.length) {
val format = trackGroup.getFormat(trackGroupIndex)
if (format.sampleMimeType == MimeTypes.TEXT_VTT
&& format.language == langCode
) {
val currentParams = defaultTrackSelector.buildUponParameters()
currentParams.clearSelectionOverride(
renderIndex, trackGroupArray
)
val override = DefaultTrackSelector.SelectionOverride(
trackGroupArrayIndex, trackGroupIndex
)
currentParams.setSelectionOverride(
renderIndex,
trackGroupArray,
override
)
defaultTrackSelector.setParameters(currentParams)
return
}
}
}
}
}
}
}
结论
我们已经介绍了如何在ExoPlayer中获取和切换WebVTT字幕的基础知识。实际上,相同的方法可以轻松地与其他类型的字幕配合使用-只需用该类型参数化方法就足够了。同样,处理音轨也不难。当然,以这种形式使用该解决方案是非常困难的,并且需要将其带到更方便的形式。谢谢您的关注。