doc/SUBTITLE_CN.md
GSYVideoPlayer 现在提供一套和播放内核解耦的外挂字幕能力。字幕由播放器 UI 基类统一加载、解析和渲染,不再依赖 Media3 的 SubtitleView 或 ExoPlayer 的 MergingMediaSource。
application/x-subriptext/vtt如果没有显式传 mimeType,会按 URL 后缀推断,.vtt / .webvtt 识别为 WebVTT,其余默认按 SRT 解析。
GSYSubtitleSource source = new GSYSubtitleSource.Builder("https://example.com/subtitle.srt")
.setId("zh-main")
.setMimeType(GSYSubtitleMime.APPLICATION_SUBRIP)
.setLanguage("zh")
.setLabel("中文")
.setCharsetName("UTF-8")
.setOffsetMs(0)
.setDefault(true)
.build();
videoPlayer.setSubtitleSource(source);
videoPlayer.setSubtitleEnabled(true);
List<GSYSubtitleSource> subtitles = new ArrayList<>();
subtitles.add(new GSYSubtitleSource.Builder(zhUrl).setLanguage("zh").setDefault(true).build());
subtitles.add(new GSYSubtitleSource.Builder(enUrl).setLanguage("en").build());
videoPlayer.setSubtitleSources(subtitles);
videoPlayer.selectSubtitle("en");
建议业务侧给每条字幕设置稳定的 id,例如 zh-main、zh-forced、en-sdh。language 只表达语言,label 只用于展示。
selectSubtitle() 可以传 source 的 id,也兼容传 language、label 或 url。
GSYSubtitleStyle style = new GSYSubtitleStyle.Builder()
.setTextColor(Color.WHITE)
.setTextSizeSp(16)
.setShadow(Color.BLACK, 3, 1, 1)
.setBottomMarginDp(56)
.build();
videoPlayer.setSubtitleStyle(style);
videoPlayer.setSubtitleOffsetMs(500);
字幕位置可以通过 setPosition() 调整:
GSYSubtitleStyle topStyle = new GSYSubtitleStyle.Builder()
.setPosition(Gravity.TOP | Gravity.CENTER_HORIZONTAL, 16, 72)
.build();
GSYSubtitleStyle bottomStyle = new GSYSubtitleStyle.Builder()
.setPosition(Gravity.BOTTOM | Gravity.CENTER_HORIZONTAL, 16, 56)
.build();
layoutGravity 控制字幕在播放器里的上、中、下位置,horizontalMarginDp 控制左右边距,verticalMarginDp 控制顶部或底部距离。旧的 setBottomMarginDp() 仍然可用,等价于底部字幕的垂直边距。
setSubtitleOffsetMs() 是全局偏移,GSYSubtitleSource#setOffsetMs() 是单条字幕源自己的偏移,两者会相加。
Media3 内嵌字幕仍由 ExoPlayer 解析,但 demo 中的 GSYExoSubTitleVideoView 会把 CueGroup 转成通用字幕文本:
外挂字幕加载、网络、解析失败或解析为空时,只清空字幕显示并打印 warning,不会抛异常,也不会影响视频 prepare/play。
Demo 入口:
自定义EXO支持字幕:Exo/Media3 场景,演示 setSubtitleSources(...) 走 GSY 通用外挂字幕,不再把外挂字幕合并进 Exo 的 MediaSource;Media3 内嵌字幕仍可以通过 onCues(CueGroup) 桥接到同一套 overlay。通用字幕非Exo:强制切到 IJK 内核,演示非 Exo 内核也可以直接使用 setSubtitleSources(...)。两个页面都提供三种字幕源切换,方便验证不同格式和真实网络字幕:
SUBTITLE SRT LOCAL:本地 res/raw/demo_subtitle.srt,离线可用。SUBTITLE VTT LOCAL:本地 res/raw/demo_subtitle_vtt.vtt,覆盖 WebVTT 解析。SUBTITLE SRT NETWORK:项目历史使用过的真实字幕链接 http://img.cdn.guoshuyu.cn/subtitle2.srt,用于验证网络 SRT 加载。两个页面都提供 GSY SUBTITLE ON/OFF 字幕开关、SUBTITLE SIZE 字号切换按钮和 SUBTITLE SRT LOCAL/VTT LOCAL/SRT NETWORK 字幕源切换按钮。
每次改字幕相关代码,建议至少跑:
./gradlew :gsyVideoPlayer-java:testDebugUnitTest :app:assembleDebug
adb install -r app/build/outputs/apk/debug/app-debug.apk
adb shell am start -n com.example.gsyvideoplayer/.MainActivity
真机手动检查:
自定义EXO支持字幕 和 通用字幕非Exo,点击播放,确认视频能进入 onPrepared。GSY SUBTITLE OFF/ON,确认字幕只开关显示,不影响视频播放。SUBTITLE SIZE 22/16,确认字号可以切换,样式不遮挡播放器控制栏。SUBTITLE SRT LOCAL/VTT LOCAL/SRT NETWORK,确认本地 SRT、本地 VTT、真实网络 SRT 都可以切换;网络字幕失败时只清空字幕,不影响视频播放。FATAL EXCEPTION、NullPointerException、IllegalStateException、Player error。异常场景:
.vtt 或 .srt,确认 MIME 推断正确。