рд╕рднреА рдХреЛ рдирдорд╕реНрдХрд╛рд░редрдХреБрдЫ рджрд┐рдиреЛрдВ рдкрд╣рд▓реЗ HLS рд╕реНрдЯреНрд░реАрдо рдореЗрдВ WebVTT рд╕рдмрдЯрд╛рдЗрдЯ рдХреЛ рд╕реНрд╡рд┐рдЪ рдХрд░рдиреЗ рдХрд╛ рдПрдХ рдХрд╛рд░реНрдп рдерд╛редрд╣рдо рдПрдХреНрд╕реЛрдкреНрд▓реЗрдпрд░ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рд╡реАрдбрд┐рдпреЛ рдЦреЗрд▓рддреЗ рд╣реИрдВ, рдФрд░ рдкрд╣рд▓реЗ рдРрд╕рд╛ рд▓рдЧрддрд╛ рдерд╛ рдХрд┐ Google рдФрд░ рдХрдВрдкрдиреА рдХреЛ "рд▓рд┐рдпрд╛ рдФрд░ рдХрд┐рдпрд╛" рдмреЙрдХреНрд╕ рд╕реЗ рдПрдХ рд╕рдорд╛рдзрд╛рди рдкреНрд░рджрд╛рди рдХрд░рдирд╛ рдЪрд╛рд╣рд┐рдП рдерд╛ред рд▓реЗрдХрд┐рди рд╡рд╛рд╕реНрддрд╡рд┐рдХрддрд╛ рдЕрдкреЗрдХреНрд╖рд╛ рдХреЗ рдЕрдиреБрд░реВрдк рдирд╣реАрдВ рдереА :)Googling рдФрд░ Habring рдХрд╛ рдкрд░рд┐рдгрд╛рдо рдирд╣реАрдВ рдирд┐рдХрд▓рд╛ рдФрд░ рдпрд╣ рд╕рднреА рдЖрдзрд┐рдХрд╛рд░рд┐рдХ рдбреЗрдореЛ рдПрдкреНрд▓рд┐рдХреЗрд╢рди ExoPlayer рдХреЛ рдЪреБрдирдиреЗ рдХреЗ рд▓рд┐рдП рдиреАрдЪреЗ рдЖрдпрд╛ редрдЪреВрдВрдХрд┐ рдЪреВрдВрдХрд┐ рд▓реЗрдЦ рдПрдЪрдПрд▓рдПрд╕ рдХреА рд╕рдВрд░рдЪрдирд╛ рдФрд░ рдПрдХреНрд╕реЛрдкреНрд▓реЗрдпрд░ рдореЗрдВ рдХреБрдЫ рдЕрдиреБрднрд╡ рдХреА рдЙрдкрд╕реНрдерд┐рддрд┐ рдХреЗ рд╕рд╛рде рдХреБрдЫ рдкрд░рд┐рдЪрд┐рддрддрд╛ рдорд╛рдирддрд╛ рд╣реИ, рдЗрд╕рд▓рд┐рдП рд╣рдо рдмрд┐рдВрджреБ рдкрд░ рд╕рд╣реА рд╣реЛ рдЬрд╛рддреЗ рд╣реИрдВредрдпрд╣ рд╕реНрд╡рд┐рдЪрд┐рдВрдЧ рд╕реНрдЯреНрд░реАрдо (рд╡реАрдбрд┐рдпреЛ, рдСрдбрд┐рдпреЛ, рдЙрдкрд╢реАрд░реНрд╖рдХ) рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рджрд╕реНрддрд╛рд╡реЗрдЬ рд╣рдореЗрдВ рдмрддрд╛рддрд╛ рд╣реИ ред рдФрд░ рд╡рд╣ рд╣рдореЗрдВ рд▓рдЧрднрдЧ рдХреБрдЫ рднреА рдирд╣реАрдВ рдмрддрд╛рддреА рд╣реИ - DefaultTrackSelector рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рдЦрд┐рд▓рд╛рдбрд╝реА рдХреЛ рдЗрдирд┐рд╢рд┐рдпрд▓рд╛рдЗрдЬрд╝ рдХрд░реЗрдВ рдФрд░ рдЙрд╕рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░реЗрдВред рдпрд╣ рдареАрдХ рд╣реИ, :)рдХрд┐рд╕реА рднреА рдЕрдиреНрдп рдкрдЯрд░рд┐рдпреЛрдВ (CEA-608, WebVtt) рдХреЗ рдХрд┐рд╕реА рднреА рдЕрдиреНрдп рдЯреНрд░реИрдХ рдХреА рддрд░рд╣ рд╕рднреА рдЙрдкрд╢реАрд░реНрд╖рдХ DefaultTrackSelector рдХреЗ рдЕрдВрджрд░ рд╕рдВрдЧреНрд░рд╣реАрдд рд╣реИрдВ рдФрд░ рдЖрдкрдХреЛ рдЙрдиреНрд╣реЗрдВ рдкреНрд░рд╛рдкреНрдд рдХрд░рдиреЗ рдореЗрдВ рд╕рдХреНрд╖рдо рд╣реЛрдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИред рд╕рдм рдХреБрдЫ рд╕рдореВрд╣реЛрдВ рдФрд░ рдЙрдкрд╕рдореВрд╣реЛрдВ рдореЗрдВ рд╡рд┐рднрд╛рдЬрд┐рдд рд╣реИ, рдФрд░ рд╕рдВрдХреНрд╖реЗрдк рдореЗрдВ, рдЖрдВрддрд░рд┐рдХ рд╕рдВрд░рдЪрдирд╛ рдХреБрдЫ рдЗрд╕ рддрд░рд╣ рджрд┐рдЦрддреА рд╣реИ:рдЪрд▓рд┐рдП рдЕрдм WebVTT рдХреЗ рдЙрдкрд╢реАрд░реНрд╖рдХ рдкрд╛рдиреЗ рдХреА рдХреЛрд╢рд┐рд╢ рдХрд░рддреЗ рд╣реИрдВ, рдЙрдиреНрд╣реЗрдВ рд░реЗрдВрдбрд░рд░ рдХреЗ рдЕрдВрджрд░ рдЯрд╛рдЗрдк рдХрд┐рдпрд╛ рдЬрд╛рдирд╛ рдЪрд╛рд╣рд┐рдП "3" (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 рдкрд░ рд╕рдВрдпреЛрдЬрди рдФрд░ рдкреНрд░рджрд░реНрд╢рди рдХрд░рдирд╛ рдЗрд╕ рд▓реЗрдЦ рдХрд╛ рдЙрджреНрджреЗрд╢реНрдп рдирд╣реАрдВ рд╣реИред рдмрд╣реБрдд рддрд░реАрдХреЗ рд╣реИрдВред рд╣рдореЗрдВ рд╕рд┐рд░реНрдл рдЯреНрд░реИрдХ рд╕реЗрдЯ рдХрд░рдирд╛ рд╕реАрдЦрдирд╛ рд╣реЛрдЧрд╛редрд╕реНрдкрд╖реНрдЯрддрд╛ рдХреЗ рд▓рд┐рдП, рд╣рдо рдЗрд╕реЗ рдорд╛рдереЗ рдХреЗ рддрд░реАрдХреЗ рд╕реЗ рдХрд░реЗрдВрдЧреЗ, рддрд╛рдХрд┐ рд╕рднреА рдЪрдХреНрд░ рдФрд░ рд╕реВрдЪрдХрд╛рдВрдХ рд╕реНрдкрд╖реНрдЯ рд╣реЛрдВредрдЕрдкрдиреЗ рднрд╛рд╖рд╛ рдХреЛрдб рджреНрд╡рд╛рд░рд╛ рдЯреНрд░реИрдХ рдХреА рд╕реНрдерд╛рдкрдирд╛ ("рдЖрд░рдпреВ", "рдПрди", ...):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 рдЙрдкрд╢реАрд░реНрд╖рдХ рдкреНрд░рд╛рдкреНрдд рдХрд░рдиреЗ рдФрд░ рд╕реНрд╡рд┐рдЪ рдХрд░рдиреЗ рдХреЗ рддрд░реАрдХреЗ рдХреА рдореВрд▓ рдмрд╛рддреЗрдВ рдХрд╡рд░ рдХреА рд╣реИрдВредрд╡рд╛рд╕реНрддрд╡ рдореЗрдВ, рдПрдХ рд╣реА рд╡рд┐рдзрд┐ рдЖрд╕рд╛рдиреА рд╕реЗ рдЕрдиреНрдп рдкреНрд░рдХрд╛рд░ рдХреЗ рд╕рдмрдЯрд╛рдЗрдЯрд▓реНрд╕ рдХреЗ рд╕рд╛рде рдХрд╛рдо рдХрд░ рд╕рдХрддреА рд╣реИ - рдпрд╣ рдкреНрд░рдХрд╛рд░ рдХреЗ рд╕рд╛рде рддрд░реАрдХреЛрдВ рдХреЛ рдкреИрд░рд╛рдореАрдЯрд░ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдкрд░реНрдпрд╛рдкреНрдд рд╣реИред рдЙрд╕реА рддрд░рд╣, рдСрдбрд┐рдпреЛ рдЯреНрд░реИрдХ рдХреЗ рд╕рд╛рде рдХрд╛рдо рдХрд░рдирд╛ рдореБрд╢реНрдХрд┐рд▓ рдирд╣реАрдВ рд╣реЛрдЧрд╛ред рдмреЗрд╢рдХ, рдЗрд╕ рд░реВрдк рдореЗрдВ рд╕рдорд╛рдзрд╛рди рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдирд╛ рдХрд╛рдлреА рдХрдард┐рди рд╣реИ рдФрд░ рдЗрд╕реЗ рдФрд░ рдЕрдзрд┐рдХ рд╕реБрд╡рд┐рдзрд╛рдЬрдирдХ рд░реВрдк рдореЗрдВ рд▓рд╛рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИредрдзреНрдпрд╛рди рджреЗрдиреЗ рдХреЗ рд▓рд┐рдП рдЖрдкрдХреЛ рдзрдиреНрдпрд╡рд╛рджред