如何通过ExoPlayer SubtitleView同步展示音频歌词?(v2.18.3)
ExoPlayer 2.18.3 实现音频歌词同步显示方案
针对你遇到的SubtitleView无法同步展示歌词的问题,核心是需要把自定义JSON格式的歌词转换成ExoPlayer可识别的字幕源,以下是具体实现步骤:
1. 解析JSON歌词数据
首先从目标JSON数据源提取歌词条目,每条歌词需包含时间戳与文本内容。假设JSON结构如下:
{ "lyrics": [ {"time": 1000, "text": "第一句歌词"}, {"time": 3000, "text": "第二句歌词"} // 更多歌词条目 ] }
解析时将时间戳转换为ExoPlayer使用的微秒(1毫秒=1000微秒),示例代码(Kotlin + Gson):
data class LyricItem(val time: Long, val text: String) data class SongData(val lyrics: List<LyricItem>) private fun parseLyricsJson(jsonContent: String): List<LyricItem> { return Gson().fromJson(jsonContent, SongData::class.java).lyrics }
2. 构造ExoPlayer兼容的字幕源
将解析后的歌词列表转换为SpannedSubtitle,并通过SingleSubtitleSource封装:
private fun createLyricSubtitleSource(lyricItems: List<LyricItem>): SingleSubtitleSource { val subtitleCues = mutableListOf<Cue>() lyricItems.forEachIndexed { index, item -> val startTimeUs = item.time * 1000 // 下一句歌词的时间作为当前句的结束时间,最后一句持续到音频结束 val endTimeUs = if (index < lyricItems.size - 1) { lyricItems[index + 1].time * 1000 } else { Long.MAX_VALUE } val cue = Cue.Builder() .setText(item.text) .setStartTimeUs(startTimeUs) .setEndTimeUs(endTimeUs) .build() subtitleCues.add(cue) } val subtitle = SpannedSubtitle(subtitleCues) return SingleSubtitleSource( subtitle, Format.createTextSampleFormat( id = "lyric-track", mimeType = MimeTypes.TEXT_VTT, selectionFlags = C.SELECTION_FLAG_DEFAULT ) ) }
3. 将字幕源附加到音频MediaItem
创建音频MediaItem时,把自定义字幕源添加到轨道信息中:
// 替换为你的音频Uri val audioUri = Uri.parse("your-audio-url") val parsedLyrics = parseLyricsJson(jsonContentFromSource) val mediaItem = MediaItem.Builder() .setUri(audioUri) .addMediaSource(createLyricSubtitleSource(parsedLyrics)) .build() exoPlayer.setMediaItem(mediaItem) exoPlayer.prepare()
4. 配置SubtitleView并关联播放器
在布局中添加SubtitleView:
<com.google.android.exoplayer2.ui.SubtitleView android:id="@+id/subtitleView" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_gravity="bottom" android:padding="16dp" app:subtitleTextColor="#FFFFFF" app:subtitleTextSize="22sp" />
代码中关联ExoPlayer:
val subtitleView = findViewById<SubtitleView>(R.id.subtitleView) subtitleView.setPlayer(exoPlayer) // 可选:自定义字幕样式 subtitleView.setStyle(R.style.CustomSubtitleStyle)
关键注意点
- 确认JSON中的时间戳单位(毫秒/秒),转换时需对应调整为ExoPlayer的微秒单位
- 若歌词包含富文本(如换行、颜色),可使用
Html.fromHtml()生成Spanned文本传入Cue - 若字幕仍不显示,检查:
- 字幕时间范围是否与音频时长匹配
- Format的mimeType是否设置正确(如
MimeTypes.TEXT_VTT) - SubtitleView是否已正确关联到ExoPlayer
内容的提问来源于stack exchange,提问作者YellowC
相关产品推荐
相关产品推荐

