外挂字幕是指字幕文件与视频文件分开存储,用户在播放视频时按需导入字幕文件。React Native SDK 支持配置外挂字幕、切换字幕及字幕显示与加载的相关回调。
创建播放器后,调用 enableSubThread 方法开启播放器的字幕总开关,提升字幕加载性能。
const player = await initPlayer({viewId: 'player'}); // 字幕总开关 player.enableSubThread(true);
调用 enableSubtitle 方法开启或关闭字幕解析。开启后,播放器将解析字幕并通过回调返回数据。如果传入 false,则播放器停止解析字幕,字幕回调也将停止触发。您可以使用此方法作为字幕显示的开关。
// 字幕解析开关 player.enableSubtitle(true);
播放器 SDK 支持以下两种方式设置字幕源。您可根据实际情况选择。
说明
若您需要预渲染外挂字幕,推荐在预渲染回调 onPlayerCreated 中进行。也推荐在 onPlayerCreated 中添加预渲染播放器的字幕回调。
应用服务端下发字幕地址,客户端按照字幕信息说明组建字幕数据,再调用 setSubDesInfoModel 方法设置字幕信息。
import { createDirectUrlSource } from '@volcengine/react-native-vod-player'; // 组建字幕数据 const subtitleInfo = { list: [ { id: 1, language: 'cmn-Hans-CN', language_id: 1, url: 'https://demo.com/e87a83***961e?auth_key=17607***xt_plain', format: 'webvtt', sub_id: 1, }, { id: 2, language: 'eng-US', language_id: 2, url: 'https://demo.com/e87a83***00eb0a6f3432e?auth_key=1760759306-****lain', format: 'webvtt', sub_id: 2, }, ], }; const source = createDirectUrlSource({ vid: 'v0d032g1***5q6nkalr3ig', url: 'https://demo.com/9fc0da***7e97a10b7f9ca7?a=0&auth_key=1760758121-422b49c****w%3D%3D&vl=&vr=', cacheKey: 'v0d032g1***alr3ig', }); player.setVideoSource(source); // 设置字幕信息 player.setSubDesInfoModel(subtitleInfo);
您需在应用服务端使用视频点播服务端 SDK 签发临时播放 Token 和字幕鉴权 Token,然后在客户端调用 setSubtitleAuthToken 方法设置字幕源。详见签发字幕鉴权 Token。
import { createVidSource } from '@volcengine/react-native-vod-player'; // 视频 vid const vid = 'videovid'; // 由服务端签发的临时播放 Token const playAuthToken = 'playAuthToken'; // 创建播放源 const source = createVidSource({ vid, playAuthToken, cacheKey: vid, }); // 设置播放源 player.setVideoSource(source); // 设置用于字幕获取的 subAuthToken player.setSubtitleAuthToken(subtitleToken);
说明
生成 playAuthToken、subAuthToken 和调用 createVidSource 方法创建播放源时所用的 Vid 必须保持一致,否则会导致解析错误。
调用 setSubtitleCallback 设置字幕回调来更新字幕状态及字幕显示内容。
player.setSubtitleCallback({ // 字幕信息回调,用于更新显示字幕 onSubtitleInfoCallback(subInfo) { console.log(`subtitle update to ${subInfo.content}`); }, onSubtitleInfoRequested(jsonInfo: string, error?: Error) { // 针对 Vid 播放,当请求到字幕时播放器回调,此时可以调用 getSubtitleIDs 获取字幕 ID 列表 if (!error) { const ids = player.getSubtitleIDs(); if (ids && ids.length) { // 切换到第一个字幕 player.switchSubtitleById(ids[0]); } } }, onSubLoadFinished(success: boolean) { // 当前字幕加载完成 console.log(`current subtitle load ${success ? 'success' : 'fail'}`); }, onSubSwitchCompleted(success: boolean, id: number) { // 字幕切换完成,currentLangId:当前语言 ID console.log(`subtitle ${id} switch ${success ? 'success' : 'fail'}`); }, });
其中最重要的回调是 onSubtitleInfoCallback。该回调会在字幕随播放进度发生变化时触发,包括字幕清除。您需根据回调的 subInfo 信息更新显示的字幕。subInfo 包含以下信息:
content:字幕内容。duration:该段字幕持续时间。pts:该段字幕对应的视频播放时间。以下为在 React Native 组件中更新显示字幕的示例代码:
import {useState} from 'react'; // .... const [curText, setCurText] = useState(''); const [enableSub, setEnableSub] = useState(true); player.setSubtitleCallback({ onSubtitleInfoCallback(subInfo) { // 字幕信息回调,用于更新显示字幕 setCurText(subInfo.content) }, }); // .... return ( <View> {enableSub && ( <View style={[styles.sub]}> <Text>{curText}</Text> </View> )} </View> )
可通过 getSubtitleIDs 获取字幕 ID 列表,再调用 switchSubtitleById 传入字幕 ID 进行字幕切换。
// 获取字幕 ID 列表 const ids = player.getSubtitleIDs(); // 切换字幕 player.switchSubtitleById(ids[0]);
如果要设置起播的默认字幕,则可在调用 play 前调用 switchSubtitleById 设置字幕 ID。
字幕回调 onSubtitleInfoRequested 中的 jsonInfo 参数为一个 JSON 字符串。解析该字符串后,所得对象的 list 属性为一个数组,数组中的每一项均为 SubDesInfoModel 类型。每项的具体数据类型如下,各字段的含义详见字幕信息说明。
{ id: number, language: string, language_id: number, url: string, format: string, sub_id: number, }
您可基于此列表数据渲染字幕列表 UI:
onSubtitleInfoRequested(jsonInfo: string, error?: Error) { // 针对 Vid 播放,当请求到字幕时播放器回调,此时可以调用 getSubtitleIDs 获取字幕 ID 列表 if (!error) { try { // 解析 jsonInfo const json = JSON.parse(jsonInfo); // 渲染字幕列表 UI setVidSubList(json.list); } catch (err) { console.error(err); } } },
为提升用户观看视频时字幕的加载速度和成功率,您可结合视频预加载策略,在设置预加载视频源的同时,为每个视频源关联一个需要提前加载的外挂字幕文件。
注意
只能预加载一个字幕源。
根据播放源类型的不同,配置方式如下:
对于 DirectUrl 源,您需要在创建播放源时提供完整的字幕列表,并明确指定要预加载哪一个。调用 createDirectUrlSource 创建播放源时,传入以下两个关键参数:
subtitleInfoModel: 包含所有可用字幕信息的完整对象。subtitleId: 您希望预加载的那个字幕的 sub_id。import { createDirectUrlSource } from '@volcengine/react-native-vod-player'; const subtitleInfo = { list: [ { language: 'cmn-Hans-CN', language_id: 1, url: '...', format: 'webvtt', sub_id: -987900477 }, { language: 'eng-US', language_id: 2, url: '...', format: 'webvtt', sub_id: 1868145343 }, ], }; const urlSource = createDirectUrlSource({ vid: 'your_vid_1', url: 'https://example.com/video.mp4', cacheKey: 'your_cache_key_1', // 1. 提供完整的字幕列表 subtitleInfoModel: subtitleInfo, // 2. 指定你想预加载的那个字幕的 ID (这里选择英语字幕) subtitleId: 1868145343, }); // 将配置好的视频源加入预加载任务列表 setStrategySources([urlSource, /* other sources */]);
在播放该视频时,您需要先设置相同的字幕信息,然后切换到预加载时指定的字幕 ID。
// 开启字幕功能 player.enableSubThread(true); player.enableSubtitle(true); // 1. 必须传入与预加载时相同的 subtitleInfoModel player.setSubDesInfoModel(subtitleInfo); // 2. 切换到预加载时指定的 subtitleId player.switchSubtitleById(1868145343);
对于 Vid 源,由于字幕列表是动态请求的,预加载的配置流程有所不同。您需要先指定一个目标语言,然后播放器会在获取到字幕列表后,自动预加载匹配该语言的字幕。创建 Vid 源时,除了 playAuthToken,还需传入 subtitleAuthToken。
import { createVidSource } from '@volcengine/react-native-vod-player'; const vidSource = createVidSource({ vid: 'your_vid_2', playAuthToken: 'your_play_auth_token', subtitleAuthToken: 'your_subtitle_auth_token', });
在启动预加载任务前,通过以下函数告知预加载模块您希望优先加载哪种语言的字幕。
setDefaultPreloadTaskFeature(languageId):设置目标字幕的语言 ID。预加载模块会寻找与此 ID 匹配的字幕进行下载。如果找不到,则会默认选择字幕列表中的第一个。setPreloadTaskFactory():应用设置并启动预加载任务。// 设置预加载的目标字幕语言为英语 (language_id = 2) setDefaultPreloadTaskFeature(2); // 启动预加载任务 setPreloadTaskFactory(); // 您也可以在后续动态更新目标语言 // setDefaultPreloadTaskFeature(1); // 更新为中文
播放视频时,您需要在字幕信息回调中,找到与您在步骤 2 中设置的语言 ID 相匹配的字幕,并主动切换过去。
// 开启字幕功能 player.enableSubThread(true); player.enableSubtitle(true); // 设置字幕请求所需的 token player.setSubtitleAuthToken('your_subtitle_auth_token'); // 设置字幕回调,以在获取到列表后执行切换 player.setSubtitleCallback({ onSubtitleInfoRequested: (jsonInfo, error) => { if (error) { console.error('Failed to request subtitle info:', error); return; } const data = JSON.parse(jsonInfo); // 假设在预加载时设置了 language_id 为 2 (英语) const targetLanguageId = 2; // 查找与预加载时语言 ID 匹配的字幕 const targetSub = data.list.find((s: any) => s.language_id === targetLanguageId); if (targetSub) { // 切换到目标字幕,此时会优先使用已缓存的数据 player?.switchSubtitleById(targetSub.sub_id); } }, });
无论使用哪种播放源,您都可以通过监听 onSubtitleHitCacheChange 事件来确认字幕是否成功命中了预加载缓存。
player.setListener({ onSubtitleHitCacheChange: (subtitleKey, subCacheSize) => { if (subCacheSize > 0) { console.log(`Subtitle cache hit! Key: ${subtitleKey}, Size: ${subCacheSize} bytes`); } }, });
预加载的执行会受到当前网络状况、设备性能和播放器缓冲策略的影响。在切换到下一个视频时,如果对应的预加载任务尚未完成,播放器仍会正常在线请求字幕文件,不影响字幕的最终播放,只是无法享受预加载带来的加速效果。