外挂字幕指与视频文件分离的字幕文件,用户可在播放时按需导入。播放器 SDK 支持添加 WebVTT (Web Video Text Tracks) 和 SRT (SubRip Text) 格式的外挂字幕。外挂字幕的优势在于其灵活性,用户可按需选择是否加载字幕以及加载何种语言的字幕,且无需进行视频转码,只需在播放端设置即可显示。本文介绍如何使用播放器 SDK 添加外挂字幕。
注意
自 1.36.1 版本起,外挂字幕功能由增值服务调整至高级版和企业版。若您集成 1.36.1 之前的版本且想要使用此功能,请升级至最新版本。
出于拓展性的考量,播放器 SDK 只返回字幕文本信息,具体的字幕展示需要您结合 UI 控件自行实现。实现外挂字幕功能的核心流程如下:
play 之前,通过 setOptionForKey 方法开启外挂字幕功能及相关优化项,然后设置字幕源(二选一:直接将字幕文件 URL 设置给播放器,适用于对起播速度有要求的场景,如短剧、短视频;与视频点播服务深度集成,开发简单,管理便捷),最后再调用 setSubtitleDelegate 注册监听器,以接收字幕内容。onSubtitleInfoCallBack 回调中获取 SDK 按时间顺序推送的字幕文本,并将其渲染到您的 UI 控件(如 TextView)上。调用 setOptionForKey 控制字幕的显示与隐藏;调用 setOptionForKey 并传入目标语言的 sub_id 实现切换。参考以下示例代码开启外挂字幕功能:
// 外挂字幕功能总开关,建议在设置 vid 之前调用 [self.videoEngine setOptionForKey:VEKeyPlayerEnableSubThread_BOOL value:@(YES)]; // 外挂字幕加载优化开关 // NO: 关闭外挂字幕加载优化;YES: 开启外挂字幕加载优化 [self.videoEngine setOptionForKey:VEKKeyPlayerSubtitleOptEnable_BOOL value:@(YES)]; // 使用数据加载模块 MDL 加载外挂字幕,提升加载成功率 // YES: 使用 MDL 加载外挂字幕 // NO: 不使用 MDL 加载外挂字幕 [self.videoEngine setOptionForKey:VEKKeySubTitleEnableMDL_BOOL value:@(YES)];
播放器 SDK 支持以下两种方式设置字幕源。您需根据实际情况选择。
使用 DirectURL 方式设置字幕源。您需要实现 TTVideoEngineSubDecInfoProtocol 协议构建字幕源。示例代码如下:
说明
若您需要将已经下载到本地设备的离线字幕文件作为字幕源,将 url 设为本地文件绝对路径即可,形如 file://xxxxx/xxx.srt。
NSString *url = @"http://www.example.com/h264.mp4"; NSString *cacheKey = [url md5String]; // cacheKey 用作磁盘缓存的文件名,建议采用 URL 中能标识视频文件的部分的 MD5 值 TTVideoEngineUrlSource *source = [[TTVideoEngineUrlSource alloc] initWithUrl:url cacheKey:cacheKey]; [self.videoEngine setVideoEngineVideoSource: source]; // 设置 DirectURL 模式下的字幕源 // 该字幕源需要实现 TTVideoEngineSubDecInfoProtocol 协议 [self.videoEngine setSubDecInfoModel:self]; // MARK: - TTVideoEngineSubDecInfoProtocol // 返回包含外挂字幕 URL 等信息的 JSON 字符串,详见本文 JSON 字幕信息说明章节 - (NSString *_Nullable)jsonString { return subtitleJSONStr; } // 返回字幕 list 包含的字幕数量 - (NSInteger)subtitleCount { return count; }
使用 Vid + SubtitleToken 方式设置字幕源。示例代码如下:
说明
您可在应用服务端通过视频点播服务端 SDK 签发字幕鉴权 Token。
NSString *vid = @"YOUR_VIDEO_ID"; // AppServer 下发 NSString *playAuthToken = @"YOUR_PLAYAUTHTOKEN"; // AppServer 下发 // resolution 为视频分辨率,例如:TTVideoEngineResolutionTypeHD TTVideoEngineVidSource *vidSource = [[TTVideoEngineVidSource alloc] initWithVid:vid playAuthToken:playAuthToken resolution:TTVideoEngineResolutionTypeHD]; // 设置字幕鉴权 token,需在起播前设置 [self.videoEngine setSubtitleAuthToken:@"SUBTITLE_AUTHTOKEN"]; // AppServer 下发 // 设置默认展示语言。如不设置,SDK 会以点播服务端下发的顺序展示第一位语言 // 字幕语言映射表见:https://www.volcengine.com/docs/4/1186356 // 需传入 SubtitleID。SubtitleID 可通过 -[TTVideoEngine subtitleIDs] 获取。 [self.videoEngine setOptionForKey:VEKeyPlayerSwitchSubtitleId_NSInteger value:@(<#SubtitleID#>)]; [self.videoEngine setVideoEngineVideoSource:vidSource]; [self.videoEngine play];
在调用 play 播放前,调用 setSubtitleDelegate 设置字幕回调:
// 设置回调接收 [self.videoEngine setSubtitleDelegate:self];
字幕回调的具体使用说明如下:
/** * 字幕回调 * <TTVideoEngineSubtitleDelegate> */ // SDK 提供了多种字幕信息回调方法,以下列举核心的几种。推荐使用第二种 onSubtitleInfoCallBack 重载方法,因其提供了更丰富的字幕信息。 // 方法一:仅返回字幕内容和时间戳 - (void)videoEngine:(TTVideoEngine *)videoEngine onSubtitleInfoCallBack:(NSString *)content pts:(NSUInteger)pts { // 刷新字幕 // 示例: [self.subtitleView refreshContent:content]; } // 方法二:返回包含字幕内容、时间戳、持续时长等信息的 TTVideoEngineSubInfo 对象 - (void)videoEngine:(TTVideoEngine *)videoEngine onSubtitleInfoCallBack:(TTVideoEngineSubInfo *)subInfo { // subInfo.pts: 字幕开始显示的时间戳 // subInfo.content: 字幕内容 // subInfo.duration: 字幕要持续的时长。 } // 针对 Vid 播放,当请求到字幕时播放器回调,可以用来更新字幕列表,也可以用于设置默认字幕。适用于 1.47.3 及之后版本 - (void)videoEngine:(TTVideoEngine *)videoEngine onSubtitleInfoRequestFinish:(TTVideoEngineSubDecInfoModel *)subtitleInfoModel error:(NSError * _Nullable)error { } // [videoEngine setOptionForKey:VEKeyPlayerSwitchSubtitleId_NSInteger value:@(<#SubtitleID#>)]; 设置默认字幕或切换字幕 } // 字幕切换完成,currentLangId:当前语言ID - (void)videoEngine:(TTVideoEngine *)videoEngine onSubSwitchCompleted:(BOOL)success currentLangId:(NSInteger)currentLangId { } // 当前字幕加载完成 - (void)videoEngine:(TTVideoEngine *)videoEngine onSubLoadFinished:(BOOL)success info:(TTVideoEngineLoadInfo *)info { if (!success) { // 字幕加载失败。可移除字幕渲染或重新请求 } else { // 字幕加载成功。 // info.firstPts 字幕首次出现的时间戳 } } // 自定义本地缓存字幕 cache key - (NSString *)videoEngine:(TTVideoEngine *)videoEngine generateSubtitleCachKey:(NSString *)subTitleUrl extendInfo:(NSDictionary *)extendInfo { return nil; }
参考以下示例代码在起播时或者播放过程中控制开启或者关闭字幕:
// 起播时或者播放过程中控制展示或者关闭字幕 // YES: 输出字幕;NO: 停止输出字幕 [self.videoEngine setOptionForKey:VEKKeyPlayerSubEnabled_BOOL value:@(YES)];
参考以下示例代码传入字幕 ID 切换不同的字幕:
[self.videoEngine setOptionForKey:VEKeyPlayerSwitchSubtitleId_NSInteger value:@(<#NSInteger#>)];
说明
SubtitleId。SubtitleId 可通过 -[TTVideoEngine subtitleIDs] 获取。sub_id 字段。为提升用户观看视频时字幕的加载速度和成功率,可结合视频预加载策略,在播放前提前缓存字幕文件。此功能需在预加载阶段就指定好视频源和字幕源。
说明
参考文档开启预加载策略。
构建字幕源信息:创建一个 TTVideoEngineSubDecInfoModel 实例,用于承载字幕的详细信息,如 URL、格式、语言等。
- (TTVideoEngineSubDecInfoModel *)getSubtitleInfoModel { // 中文字幕 NSDictionary *subtitle1Dictionary = @{ @"format" : @"webvtt", // 字幕格式 @"sub_id" : @(429984091), // 字幕 ID @"language_id" : @(1), // 字幕语言 ID @"language" : @"cmn-Hans-CN", // 字幕语言 @"url" : @"https://example.com/1.vtt" // 字幕下载地址 }; // 英文字幕 NSDictionary *subtitle2Dictionary = @{ @"format" : @"webvtt", // 字幕格式 @"sub_id" : @(429984092), // 字幕 ID @"language_id" : @(2), // 字幕语言 ID @"language" : @"eng-US", // 字幕语言 @"url" : @"https://example.com/2.vtt" // 字幕下载地址 }; // 构建所有字幕的列表 NSArray *subtitleArray = @[subtitle1Dictionary, subtitle2Dictionary]; // 获得最终字幕数据结构,不要改变 “list” 字段名称 NSDictionary *subtitlesDictionary = @{ @"list": subtitleArray }; // 创建字幕 subModel TTVideoEngineSubDecInfoModel *subtitleInfoModel = [[TTVideoEngineSubDecInfoModel alloc] initWithDictionary:subtitlesDictionary]; return subtitleInfoModel; }
构建并配置播放源:创建 TTVideoEngineUrlSource 时,关联上一步创建的字幕信息模型,并指定要预加载的字幕 ID。
/// 播放 url 地址 NSString *url = @"play url"; /// 本地缓存 cache key,确保跟视频一一对应且不变,这样重复播放的时候才会命中缓存 // 可以使用 url 不变部分的 md5 值,因为 url 里可能会带有时间戳等可变字段,需要处理下 NSString *cacheKey = url.md5String; TTVideoEngineUrlSource *source = [[TTVideoEngineUrlSource alloc] initWithUrl:url cacheKey:cacheKey]; // 指定预加载字幕 ID source.subtitleId = 429984092; // 指定预加载字幕源字段 source.subtitleInfoModel = [self getSubtitleInfoModel];
构造用于预加载的 Vid 播放源时,除了视频的 vid 和 playAuthToken,还需提供字幕鉴权 token。
TTVideoEngineVidSource *vidSource = (TTVideoEngineVidSource *)source; vidSource.vid = @"video id"; // 视频id vidSource.playAuthToken = @"play token"; // 播放的 token vidSource.subtitleAuthToken = @"subtitle token"; // 字幕的 token vidSource.preloadSubtitleModelBlock = ^id<TTVideoEngineSubProtocol> _Nonnull(NSArray<id<TTVideoEngineSubProtocol>> * _Nonnull subModels) { if (subModels && subModels.count > 0) { // 选择要预加载的字幕,例如这里处理为预加载第一个字幕 // 此处请根据业务逻辑(如字幕语言)匹配要预加载的字幕 return [subModels firstObject]; } return nil; };
使用字幕预加载必须要开启数据加载模块 MDL 来加载外挂字幕。
// 使用数据加载模块 MDL 加载外挂字幕,提升加载成功率 // 0: 不使用 MDL 加载外挂字幕;1: 使用 MDL 加载外挂字幕 [self.videoEngine setOptionForKey:VEKKeySubTitleEnableMDL_BOOL value:@(1)];
指定播放的字幕 ID。将占位符 <#SubtitleID#> 替换为预加载播放源中 source.subtitleId 指定的字幕 ID。
[self.videoEngine setOptionForKey:VEKeyPlayerSwitchSubtitleId_NSInteger value:@(<#SubtitleID#>)];
监听命中回调 :通过实现 TTVideoEngineDelegate 的 videoEngine:subtitleKey:subtitleHitCacheSize: 方法,根据 cacheSize 是否大于 0 来判断本次播放是否成功命中了预加载的字幕缓存。
/** * @locale zh * @type callback * @brief 字幕预加载命中回调。 * @param videoEngine `videoEngine` 对象。 * @param key 字幕缓存的唯一标识符。 * @param cacheSize 命中缓存大小。 * @notes 如果您使用字幕预加载功能,通过 `cacheSize` 是否大于 0 可以判断当此播放是否命中字幕预加载。 */ - (void)videoEngine:(TTVideoEngine *)videoEngine subtitleKey:(NSString *)key subtitleHitCacheSize:(NSInteger)cacheSize { }
在播放过程中,可以通过 addNewSubtitleModel 或 switchNewSubtitleModel 方法动态地添加新的字幕源并按需切换。
说明
动态添加字幕源自 1.47.1.10 起支持。
// 初始化JSON字幕信息 // sub_id:(必填)字幕 ID,用于切换不同字幕;业务需要确保 sub_id 是唯一的。 // language:(必填)字幕语言,字幕语言和字幕ID对照表参考链接 // language_id:(必填)语言 ID,字幕语言和字幕ID对照表参考链接 // url:(必填)字幕文件 URL // format:(必填)字幕格式,支持 webvtt 和 srt NSDictionary *subModelDic = @{ @"sub_id": @(1), @"language": @"cmn-Hans-CN", @"language_id": @(1), @"url": @"https://example.srt", @"format": @"srt" }; // 构建字幕源Model TTVideoEngineSubModel *subModel = [[TTVideoEngineSubModel alloc] initWithDictionary:subModelDic]; // 播放过程中添加字幕,不会切换到新添加的字幕,需要手动切换新添加的字幕 [self.videoEngine addNewSubtitleModel:subModel];
// 初始化JSON字幕信息 // sub_id:(必填)字幕 ID,用于切换不同字幕 // language:(必填)字幕语言,字幕语言和字幕ID对照表参考链接 // language_id:(必填)语言 ID,字幕语言和字幕ID对照表参考链接 // url:(必填)字幕文件 URL // format:(必填)字幕格式,支持 webvtt 和 srt NSDictionary *subModelDic = @{ @"sub_id": @(1), @"language": @"cmn-Hans-CN", @"language_id": @(1), @"url": @"https://example.srt", @"format": @"srt" }; // 构建字幕源 Model TTVideoEngineSubModel *subModel = [[TTVideoEngineSubModel alloc] initWithDictionary:subModelDic]; // 播放过程中添加字幕,会自动切换到新添的字幕 // 会触发 videoEngine:onSubSwitchCompleted:currentLangId: 回调 [self.videoEngine switchNewSubtitleModel:subModel];
JSON 字幕信息包含以下字段:
字段 | 说明 |
|---|---|
sub_id | (必填)字幕 ID,用于在播放器中区分不同的字幕。
|
language_id | (必填)语言 ID。取值详见语言。您需要自行维护字幕 ID 与语言 ID 的映射关系。 |
language | (必填)语言。取值详见语言。 |
url | (必填)字幕文件 URL。 |
format | (必填)字幕格式,支持 |
示例如下:
{ "list": [ { "language": "rus-RU", "language_id": 6, "url": "https://example.volcengine.com/cbebedaade0947ce51a*******17f0b13/6087d12f/video/tos/cn/tos-cn-o-0004/52ce3882d70941d5b660913cbd83d969/", "format": "webvtt", "sub_id": 328934091 }, { "language": "cmn-Hans-CN", "language_id": 1, "url": "https://example.volcengine.com/93adb942***bdfce8cb/6087d12f/video/tos/***a4122dac42d69e8233a4dfda82fe/", "format": "webvtt", "sub_id": 429984091 }, { "language": "cmn-Hans-CN|eng-US", "language_id": 5, "url": "https://***.com/d782d36702***7b9719/6087d12f/video/tos/***5f0d106146a19ad566b967211091/", "format": "webvtt", "sub_id": 829987091 } ] }