Olá a todos.Alguns dias atrás, havia uma tarefa de alternar legendas do WebVTT no fluxo HLS.Reproduzimos o vídeo usando o ExoPlayer e, a princípio, parecia que o Google e a empresa precisariam fornecer uma solução da caixa "tirado e pronto". Mas a realidade não coincidiu com a expectativa :)Googling e Habring não levaram a um resultado e tudo se resumiu a escolher o aplicativo de demonstração oficial ExoPlayer.Porque Como o artigo assume alguma familiaridade com a estrutura do HLS e a presença de alguma experiência no ExoPlayer, vamos direto ao ponto.É o que a documentação sobre a troca de fluxos (vídeo, áudio, legendas) nos diz . E ela não nos diz quase nada - inicialize o player usando DefaultTrackSelector e use-o. É isso aí, ok :)Todas as legendas de qualquer tipo (CEA-608, WebVtt), como qualquer outra faixa, são armazenadas no DefaultTrackSelector e você precisa acessá-las. Tudo é dividido em grupos e subgrupos e, em suma, a estrutura interna se parece com isso:Agora vamos tentar obter legendas do tipo WebVTT, elas devem ser armazenadas no Renderer com o tipo “3” (C.TRACK_TYPE_TEXT - constante no 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
}
Como você pode ver, algumas maneiras convenientes de iterar e pesquisar não são fornecidas e você deve fazer todos os loops com canetas.Mas precisamos saber não apenas sobre a lista em si, mas também sobre as opções selecionadas (que escolheremos no futuro). Por algum motivo, não é possível obter as faixas selecionadas no DefaultTrackSelector, mas no ExoPlayer. O esquema para obter é aproximadamente o mesmo, vamos mais fundo, mas aqui pulamos a passagem pelos renderizadores: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
}
Bem, temos uma lista comum e uma lista dos selecionados. Como combinar e exibir na interface do usuário não é o objetivo deste artigo. Existem muitos caminhos. Nós apenas temos que aprender como definir a trilha.Para maior clareza, faremos isso de maneira frontal, para que todos os ciclos e índices sejam óbvios.Instalação de uma faixa pelo seu código de idioma ("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
}
}
}
}
}
}
}
Conclusão
Abordamos o básico de como obter e alternar legendas do WebVTT no ExoPlayer.Na realidade, o mesmo método pode trabalhar facilmente com outros tipos de legendas - basta parametrizar os métodos com o tipo. Da mesma forma, não será difícil trabalhar com faixas de áudio. Obviamente, é bastante difícil usar a solução nesta forma e é necessário trazê-la para uma forma mais conveniente.Obrigado pela atenção.