阿里云播放器SDK支持添加WebVTT、SRT、ASS格式的外挂字幕流并实现解析和渲染,同时也支持M3U8文件内嵌字幕流的解析和渲染。本文介绍使用阿里云播放器SDK进行外挂字幕添加、解析和渲染的实现方式,以及在Android和iOS平台上实现的具体技术方案。
本文所有功能相关代码和实现细节,建议优先参考API-Example示例工程,按照最佳实践进行适配和扩展。
具体实现可结合下文实现方案,并参考对应的 API-Example-Android 和API-Example-iOS外挂字幕演示与切换(ExternalSubtitle)模块源码。
使用限制
外挂字幕仅支持播放器专业版,请参考获取播放器SDK License获取专业版授权后使用。
目前仅支持添加WebVTT、SRT、ASS格式的外挂字幕流文件。
渲染示例
以下为播放器SDK渲染组件示例,支持普通字幕及自定义位置、字体、背景色、描边等高自由度渲染样式。
如需打包字幕流实现字幕渲染,请参考多字幕转码打包最佳实践进行配置。
Android 端关键实现
外挂字幕渲染
导入依赖库。
import com.aliyun.subtitle.SubTitleBase; import com.cicada.player.utils.webVtt.VttSubtitleView; import com.aliyun.player.IPlayer;设置显示视图。
vttSubtitleView = new VttSubtitleView(getContext()); vttSubtitleView.setId(R.id.cicada_player_vtt_subtitle); // 设置字幕的显示位置 - 添加到布局中央 FrameLayout.LayoutParams params = new FrameLayout.LayoutParams( FrameLayout.LayoutParams.WRAP_CONTENT, FrameLayout.LayoutParams.WRAP_CONTENT ); params.gravity = Gravity.CENTER; // 添加到布局中央 // 将VTT字幕View添加到根布局视图中 mRootFrameLayout.addView(mVttSubtitleView, params);设置回调。
//下述示例为mVideoListPlayer为listPlayer,使用aliPlayer 也是一致的 //1. 设置 OnSubtitleDisplayListener mVideoListPlayer.setOnSubtitleDisplayListener(new IPlayer.OnSubtitleDisplayListener() { @Override public void onSubtitleExtAdded(int trackIndex, String url) { //由于仅测试添加单个vtt文件,因此当vtt文件添加完毕时,直接选择该路字幕即可 mVideoListPlayer.selectExtSubtitle(trackIndex, true); } @Override public void onSubtitleShow(int trackIndex, long id, String data) { if (vttSubtitleView != null) { vttSubtitleView.show(id, data); } } @Override public void onSubtitleHide(int trackIndex, long id) { if (vttSubtitleView != null) { vttSubtitleView.dismiss(id); } } @Override public void onSubtitleHeader(int trackIndex, String header) { if (vttSubtitleView != null) { vttSubtitleView.setVttHeader(header); } } }); //2.设置VideoSizeChangedListener,下述流程为必要流程,需要将数据回传到vttSubtitleView中 mVideoListPlayer.setOnVideoSizeChangedListener(new IPlayer.OnVideoSizeChangedListener() { @Override public void onVideoSizeChanged(int width, int height) { int viewWidth = getWidth(); int viewHeight = getHeight(); IPlayer.ScaleMode mode = mVideoListPlayer.getScaleMode(); SubTitleBase.VideoDimensions videoDimensions = SubTitleBase.getVideoDimensionsWhenRenderChanged(width, height, viewWidth, viewHeight, mode); vttSubtitleView.setVideoRenderSize(videoDimensions.videoDisplayWidth, videoDimensions.videoDisplayHeight); } });播放器执行
prepare/moveTo/moveToNext/moveToPrev操作后,需清除显示视图。source = getSource(someParams);//伪代码 mVideoListPlayer.moveTo(mCurrentUUID + ""); if (vttSubtitleView != null) { vttSubtitleView.clearAll(); } if (!source.getExtSubtitleUrl().isEmpty()) { mCurrentExtSubtitle = source.getExtSubtitleUrl();//获取外挂字幕 url }播放器
onPrepared后,添加字幕文件。//当前仅能在播放器 onprepared后,调用addExtSubtitle mVideoListPlayer.addExtSubtitle(mCurrentExtSubtitle);
M3U8打包渲染
M3U8打包与外挂字幕不建议混合渲染。
导入依赖库。
import com.aliyun.subtitle.SubTitleBase; import com.cicada.player.utils.webVtt.VttSubtitleView; import com.aliyun.player.IPlayer;设置显示视图。
vttSubtitleView = new VttSubtitleView(getContext()); vttSubtitleView.setId(R.id.cicada_player_vtt_subtitle); // 设置字幕的显示位置 - 添加到布局中央 FrameLayout.LayoutParams params = new FrameLayout.LayoutParams( FrameLayout.LayoutParams.WRAP_CONTENT, FrameLayout.LayoutParams.WRAP_CONTENT ); params.gravity = Gravity.CENTER; // 添加到布局中央 // 将VTT字幕View添加到根布局视图中 mRootFrameLayout.addView(mVttSubtitleView, params);设置回调。
//下述示例为mVideoListPlayer为listPlayer,使用aliPlayer 也是一致的 //1. 设置 OnSubtitleDisplayListener mVideoListPlayer.setOnSubtitleDisplayListener(new IPlayer.OnSubtitleDisplayListener() { @Override public void onSubtitleExtAdded(int trackIndex, String url) { //由于仅测试添加单个vtt文件,因此当vtt文件添加完毕时,直接选择该路字幕即可 mVideoListPlayer.selectExtSubtitle(trackIndex, true); } @Override public void onSubtitleShow(int trackIndex, long id, String data) { if (vttSubtitleView != null) { vttSubtitleView.show(id, data); } } @Override public void onSubtitleHide(int trackIndex, long id) { if (vttSubtitleView != null) { vttSubtitleView.dismiss(id); } } @Override public void onSubtitleHeader(int trackIndex, String header) { if (vttSubtitleView != null) { vttSubtitleView.setVttHeader(header); } } }); //2.设置VideoSizeChangedListener,下述流程为必要流程,需要将数据回传到vttSubtitleView中 mVideoListPlayer.setOnVideoSizeChangedListener(new IPlayer.OnVideoSizeChangedListener() { @Override public void onVideoSizeChanged(int width, int height) { int viewWidth = getWidth(); int viewHeight = getHeight(); IPlayer.ScaleMode mode = mVideoListPlayer.getScaleMode(); SubTitleBase.VideoDimensions videoDimensions = SubTitleBase.getVideoDimensionsWhenRenderChanged(width, height, viewWidth, viewHeight, mode); vttSubtitleView.setVideoRenderSize(videoDimensions.videoDisplayWidth, videoDimensions.videoDisplayHeight); } });播放器执行
prepare/moveTo/moveToNext/moveToPrev操作后,需清除显示视图。source = getSource(someParams);//伪代码 mVideoListPlayer.moveTo(mCurrentUUID + ""); if (vttSubtitleView != null) { vttSubtitleView.clearAll(); } if (!source.getExtSubtitleUrl().isEmpty()) { mCurrentExtSubtitle = source.getExtSubtitleUrl();//获取外挂字幕 url }设置
onTrackReady回调获取子流信息。mAliPlayer.setOnTrackReadyListener(new IPlayer.OnTrackReadyListener() { @Override public void onTrackReady(MediaInfo mediaInfo) { List<TrackInfo> trackInfos = mediaInfo.getTrackInfos(); for (TrackInfo trackInfo : trackInfos) { if (trackInfo.getType() == TrackInfo.Type.TYPE_SUBTITLE) { //todo } } } });播放器
onPrepared后,调用selectTrack切换字幕。//index为目标字幕流的TrackIndex mAliPlayer.selectTrack(index);
iOS端关键实现
外挂字幕渲染
设置回调。
/** @brief 外挂字幕被添加 @param player 播放器player指针 @param trackIndex 字幕显示的索引号 @param URL 字幕url */ - (void)onSubtitleExtAdded:(AliPlayer*)player trackIndex:(int)trackIndex URL:(NSString *)URL { NSLog(@"onSubtitleExtAdded: %@, trackIndex: %d", URL, trackIndex); [self.listPlayer selectExtSubtitle:trackIndex enable:YES]; }播放器
onPrepared后,添加字幕文件。if (self.currentModel.extSubtitleUrl != Nil) { [self.listPlayer addExtSubtitle:self.currentModel.extSubtitleUrl]; }
M3U8打包渲染
M3U8打包与外挂字幕不建议混合渲染。
设置回调。
/** @brief 外挂字幕被添加 @param player 播放器player指针 @param trackIndex 字幕显示的索引号 @param URL 字幕url */ - (void)onSubtitleExtAdded:(AliPlayer*)player trackIndex:(int)trackIndex URL:(NSString *)URL { NSLog(@"onSubtitleExtAdded: %@, trackIndex: %d", URL, trackIndex); [self.listPlayer selectExtSubtitle:trackIndex enable:YES]; }设置
onTrackReady回调获取子流信息。- (void)onTrackReady:(AliPlayer*)player info:(NSArray<AVPTrackInfo*>*)info { // }播放器
prepare done后,调用selectTrack切换字幕。//index为目标字幕流的TrackIndex [self.player selectTrack:index];
基于WebVTT流实现自定义渲染
阿里云播放器支持标准WebVTT流的双端解析渲染,可读取CSS样式并按标准实现双端统一字幕样式。并支持单文件多文本样式,适用于角色对话区分、重点内容强调及特殊视觉效果等场景。
以下为示例WebVTT文件:
REGION:显示区域定义。
STYLE:字体样式定义(首项为默认样式)。
WEBVTT
REGION
id:bottom
width:70.000000%
lines:3
viewportanchor:15.000000%,95.000000%
regionanchor:0.000000%,100.000000%
scroll:up
STYLE
::cue {
color: white;
font-size: 70%;
font-family: Noto Sans;
font-weight: bold;
background-color: rgba(0, 0, 0, 0.2);
}
::cue(.font1) {
color: rgba(255, 255, 255, 1);
font-weight: bold;
font-family: Noto Sans;
outline-width: 3px;
outline-color: rgba(0, 0, 0, 1);
}
::cue(.font2) {
color: rgba(252, 255, 101, 1);
font-style: bold;
font-family: Noto Sans;
outline-width: 3px;
outline-color: rgba(0, 0, 0, 1);
}
::cue(.font3) {
color: rgba(255, 191 23, 1);
font-style: bold;
font-family: Noto Sans;
outline-width: 3px;
outline-color: rgba(183, 28, 28, 1);
}
00:00:00.200 --> 00:00:01.800 region:bottom align:center
被告人薄寒时
00:00:01.800 --> 00:00:03.200 region:bottom align:center
你还有什么话要说
00:00:04.100 --> 00:00:04.800 region:bottom align:center
我
00:00:11.200 --> 00:00:12.200 region:bottom align:center
<v.font1>我无话可说</v.font1>
00:00:14.500 --> 00:00:16.200 region:bottom align:center
被告人薄寒时
...为文字片段指定特定样式,请参照如下设置:
<v.font1>我无话可说</v.font1>