この記事では、Androidで動画字幕を実装する際の初歩の知識で調べたことをまとめる。
サンプルのリポジトリはこちら。
前提
- media3
- 字幕ファイルのフォーマットは WebVTT
字幕の読み込み
字幕ファイルが映像と別に提供されている場合
字幕の読み込みは次の通り(Android Developers)。
val subtitle = MediaItem.SubtitleConfiguration
.Builder(subtitleUrl.toUri())
.setMimeType(MimeTypes.TEXT_VTT)
.setLanguage("en")
.setLabel("English")
.build()
val mediaItem = MediaItem.Builder()
.setUri(videoUrl)
.setSubtitleConfigurations(listOf(subtitle))
.build()
player.setMediaItem(mediaItem)
字幕ファイルがHLSで動画ストリームと同時に提供されている場合
HLSを読み込むと同時に、字幕も内部的に読み込んでくれる。
HLSの読み込みについては次の通り(Android Developers)。
// Create a player instance.
val player = ExoPlayer.Builder(context).build()
// Set the media item to be played.
player.setMediaItem(MediaItem.fromUri(hlsUri))
// Prepare the player.
player.prepare()
字幕の表示・非表示
字幕の表示・非表示の切り替えUIと、字幕UIの2つを自作するかどうかでいくつかのパターンがある。
media3-uiですべてまかなう場合
setShowSubtitleButton
を使う(Android Developers)。
PlayerView(c).apply {
this.player = player
setShowSubtitleButton(true)
}
字幕の表示・非表示の切り替えUIを自作する場合
PlayerView
に対して、表示・非表示の設定を伝える必要がある。
2つの方法がある。
字幕UI自体の表示・非表示を切り替える場合は、 subtitleView
にアクセスする。
PlayerView(c).apply {
subtitleView.visibility = if(isSubtitleVisible) {
View.VISIBLE
} else {
View.GONE
}
}
または、そもそもデータソース上から字幕を消すことで、結果的に字幕を非表示にすることもできる。
player.trackSelector?.parameters?.let { params ->
val preferredLanguage = if(isSubtitleVisible) {
listOf("en")
} else {
emptyList()
}
player.trackSelector?.parameters = params.buildUpon()
.setPreferredTextLanguages(*preferredLanguage.toTypedArray())
.build()
}
字幕UIを自作する場合
字幕UIを自作する場合は、字幕の内容を取得する必要がある。
字幕ファイルの提供フォーマットがなんであれ、ExoPlayerは内部的に字幕データをパースして保持している。
字幕ひとつひとつは Cue
という単位で管理されている。
playerにListenerを設定することで、適当なタイミングでCue
を取得できる。
player.addListener(object: Player.Listener {
override fun onCues(cueGroup: CueGroup) {
super.onCues(cueGroup)
Log.d(":memo:", cueGroup.cues.joinToString("\n") {
"[${it.position}]L${it.line}:${it.text}"
})
}
})
ListenerでCueが取得できたら、あとはそのデータを使ってUIを表示すればよい。