How can I display HLS embedded subtitles using AndroidX Media3 ExoPlayer and Jetpack Compose?
Below is what I tried but no subtitles show up, nor does any button to show/hide them. Thanks for your help!
@Composable
fun MyPlayer() {
val hlsUri = Uri.parse("https://some.website/video.m3u8")
val context = LocalContext.current
val player: ExoPlayer = remember {
ExoPlayer.Builder(context)
.build()
.apply {
setMediaItem(MediaItem.fromUri(hlsUri))
prepare()
}
}
AndroidView(
factory = {
PlayerView(context).apply {
this.player = player
layoutParams = FrameLayout.LayoutParams(MATCH_PARENT, MATCH_PARENT)
}
}
)
}
Dependencies:
# gradle/libs.versions.toml
androidXMedia = "1.0.2"
androidx-media-player = { group = "androidx.media3", name = "media3-exoplayer", version.ref = "androidXMedia" }
androidx-media-ui = { group = "androidx.media3", name = "media3-ui", version.ref = "androidXMedia" }
androidx-media-hls = { group = "androidx.media3", name = "media3-exoplayer-hls", version.ref = "androidXMedia" }
// app/build.gradle.kts
dependencies {
// ...
implementation(libs.androidx.media.player)
implementation(libs.androidx.media.ui)
implementation(libs.androidx.media.hls)
}
Here is what the HLS file looks like:
#EXTM3U
#EXT-X-INDEPENDENT-SEGMENTS
#EXT-X-MEDIA:TYPE=SUBTITLES,GROUP-ID="subs",NAME="English",LANGUAGE="en",URI="https://.../playlist.m3u8",AUTOSELECT=YES,DEFAULT=NO
#EXT-X-MEDIA:TYPE=SUBTITLES,GROUP-ID="subs",NAME="Français",LANGUAGE="fr",URI="https://.../playlist.m3u8",AUTOSELECT=YES,DEFAULT=NO
#EXT-X-MEDIA:TYPE=AUDIO,GROUP-ID="audio-medium",NAME="audio",AUTOSELECT=YES,DEFAULT=YES,CHANNELS="2",URI="https://.../playlist.m3u8"
#EXT-X-MEDIA:TYPE=AUDIO,GROUP-ID="audio-high",NAME="audio",AUTOSELECT=YES,DEFAULT=YES,CHANNELS="2",URI="https://.../playlist.m3u8"
#EXT-X-STREAM-INF:SUBTITLES="subs",BANDWIDTH=2255226,AVERAGE-BANDWIDTH=1578000,RESOLUTION=1280x720,FRAME-RATE=24.000,CODECS="avc1.640020,mp4a.40.2",AUDIO="audio-high"
https://.../playlist.m3u8
#EXT-X-STREAM-INF:SUBTITLES="subs",BANDWIDTH=698963,AVERAGE-BANDWIDTH=537000,RESOLUTION=640x360,FRAME-RATE=24.000,CODECS="avc1.64001E,mp4a.40.2",AUDIO="audio-medium"
https://.../playlist.m3u8
#EXT-X-STREAM-INF:SUBTITLES="subs",BANDWIDTH=463242,AVERAGE-BANDWIDTH=332000,RESOLUTION=426x240,FRAME-RATE=24.000,CODECS="avc1.640015,mp4a.40.2",AUDIO="audio-medium"
https://.../playlist.m3u8
#EXT-X-STREAM-INF:SUBTITLES="subs",BANDWIDTH=5496152,AVERAGE-BANDWIDTH=4096000,RESOLUTION=1920x1080,FRAME-RATE=24.000,CODECS="avc1.640028,mp4a.40.2",AUDIO="audio-high"
https://.../playlist.m3u8
#EXT-X-STREAM-INF:SUBTITLES="subs",BANDWIDTH=1440054,AVERAGE-BANDWIDTH=965000,RESOLUTION=960x540,FRAME-RATE=24.000,CODECS="avc1.64001F,mp4a.40.2",AUDIO="audio-medium"
https://.../playlist.m3u8
I had the same problem, the solution I found was to use the setShowSubtitleButton function:
AndroidView(
factory = { context ->
PlayerView(context).apply {
player = [email protected]
setShowSubtitleButton(true)
}
},
modifier = modifier
)
The only problem is that it is an UnstableApi, in the function you need to add this annotation:
@androidx.annotation.OptIn(androidx.media3.common.util.UnstableApi::class)
The full code:
@androidx.annotation.OptIn(androidx.media3.common.util.UnstableApi::class)
@Composable
private fun VideoPlayer(
modifier: Modifier = Modifier
) {
AndroidView(
factory = { context ->
PlayerView(context).apply {
player = [email protected]
setShowSubtitleButton(true)
}
},
modifier = modifier
)
}