对于包含多种清晰度、多语言音轨或多语种字幕的视频,播放器 SDK 支持在播放的各个阶段进行精确的管理和切换。本文详细介绍多路流的实现方案,并指导您如何完成集成,以及如何优化切换体验。
播放器 SDK 支持自研协议与标准协议两大类多路流方案,您可以根据业务场景和媒资来源灵活选择。
协议类型 | 播放模式 | 核心原理 | 优点 | 缺点 | 适用场景 |
|---|---|---|---|---|---|
自研协议 | Vid 模式 | 客户端通过 Vid 请求,由视频点播服务端智能下发包含所有可用清晰度的 VideoModel。 | 接入最简单,且安全性强。客户端逻辑清晰,服务端自动处理降级和媒资关联,支持帧对齐平滑切换。 | 依赖视频点播服务,对音轨/字幕的底层控制能力有限。 | 适用于媒资全部托管在火山引擎视频点播服务的场景。 |
VideoModel 模式 | 由您的业务服务端自行构造或从点播服务获取完整的 VideoModel,并下发给客户端。 | 性能最优,减少了一次客户端到点播服务的网络请求,首帧更快。对多路流的管理方式与 Vid 模式一致。 | 需自行实现构造 VideoModel 的逻辑,复杂度稍高。 | 对首帧性能有极致要求的场景,例如短视频信息流。 | |
标准协议 | HLS (Master M3U8) | 客户端直接播放标准的 Master M3U8 文件。SDK 解析文件后,通过底层回调和 Option 设置,允许您对视频流、音轨、字幕进行精细化控制。 | 兼容性最强,适用于任意来源的 HLS 视频流。提供了最底层的控制能力,灵活性最高。 | 客户端实现逻辑最复杂,需要自行处理流信息的遍历、决策和切换。 | 需要播放第三方 HLS 视频流,或需要对音轨、字幕进行精细化管理的场景。 |
DASH | 建设中,敬请期待 | ||||
对于客户端的多清晰度管理,Vid 模式和 VideoModel 模式共享一套简单、直观的 API。
在进行多路流相关开发前,请确保已完成以下准备工作:
PlayAuthToken 时,可不指定 Definition 参数。视频点播服务在响应播放请求时,将默认返回该视频所有可用清晰度的播放地址。当 TTVideoEngine 接收到 fetchedVideoModel 回调时,您可调用 supportedResolutionTypes 方法获取到所有清晰度的数组。您可用该数组做清晰度列表的展示和清晰度逻辑选择。示例代码如下:
player.fetchedVideoModel = () async { List<TTVideoEngineResolutionType>? resTypes = await player.supportedResolutionTypes; };
在调用 play 方法前调用 configResolutionBeforeStart 指定视频的起播清晰度。如果您设置的清晰度在 supportedResolutionTypes 列表中不存在,SDK 会自动选择一个当前已支持的、不高于您设定值的最接近档位进行播放。
// 设置起播清晰度 player.configResolutionBeforeStart(<TTVideoEngineResolutionType>);
当用户在 UI 上选择新的清晰度后,调用 configResolutionAfterStart 进行切换。
// 起播后切换清晰度 player.configResolutionAfterStart(targetResolution:<TTVideoEngineResolutionType>);
// 获取视频清晰度信息,需要在 onPrepared 之后获取 TTVideoEngineResolutionType resolution = await player.currentResolution
对于标准的 Master M3U8 播放源,播放器 SDK 提供了精细的控制能力,允许开发者在播放生命周期的不同阶段介入,精确选择要使用的视频流(清晰度)和音频流(音轨)。
注意
该功能仅 Android 支持。
// 方法定义在 VodPlayerFlutter /* master-m3u8 起播前档位选择 getHlsStreamInfos - 档位回调 selectHlsVideoStream - 视频档位选择, 返回视频stream的bandwidth selectHlsRendition - 音轨选择,返回音频rendition的infoId switchHlsVideoBitrate - 档位选择回调, 如发生档位切换,回调选择档位的bandwidth */ Future<void> setHLSMultiBitrateConfig( {void Function(TTMasterPlaylist playlist)? getHlsStreamInfos, int? Function()? selectHlsVideoStream, int? Function(int variantIndex)? selectHlsRendition, void Function(int bitrate)? switchHlsVideoBitrate}) // 示例代码 (以随机档位为例,仅做参考) _player?.setHLSMultiBitrateConfig( getHlsStreamInfos: (TTMasterPlaylist playlist) { _playlist = playlist; print('HLS档位回调:${playlist.toJson()}'); }, selectHlsVideoStream: () { // 示例选择档位随机 if (_playlist!.variantStreams!.isNotEmpty) { int index = Random().nextInt(_playlist!.variantStreams!.length); TTMasterVariantStream stream = _playlist!.variantStreams![index]; print('HLS视频起播档位选择, 随机index=$index, resolution-${stream.resolution} bandwidth-${stream.bandwidth}'); return stream.bandwidth; } return -1; }, selectHlsRendition: (int variantIndex) { // 示例选择音轨 'en' for (TTMasterRendition rendition in _playlist!.renditions!) { if (rendition.variantIndex != variantIndex) { continue; } if (rendition.language == 'en') { print('HLS音频起播档位选择, rendition.language=${rendition.language}, rendition.infoId-${rendition.infoId}'); return rendition.infoId; } } return -1; }, switchHlsVideoBitrate: (int bitrate) { print("HLS选择档位完成 最终bitrate = $bitrate"); }, );
// 播放中切换 hls 视频档位,如传入的bitrate档位不存在,选择最接近的档位 Future<void> switchHlsVideoBitrate({required int bitrate}) // 播放中切换 hls 音轨,如传入的 audioInfoId 不存在,不切换 Future<void> switchHlsAudioRendition({required audioInfoId})
如果您使用 SDK 提供的预加载策略,同样可以介入并指定预加载哪些流,以优化起播速度和节省带宽。
// 方法定义在 TTVideoEnginePreload /* master-m3u8起播前档位选择 getHlsStreamInfos - 档位回调 selectHlsVideoStream - 视频档位选择, 返回视频stream的bandwidth selectHlsRendition - 音轨选择,返回音频rendition的infoId switchHlsVideoBitrate - 档位选择回调, 如发生档位切换,回调选择档位的bandwidth */ Future<void> setHLSMultiBitrateConfig( {void Function(TTMasterPlaylist playlist)? getHlsStreamInfos, int? Function()? selectHlsVideoStream, int? Function(int variantIndex)? selectHlsRendition, void Function(int bitrate)? switchHlsVideoBitrate}) // 示例代码 (以随机档位为例,仅做参考) TTVideoEnginePreload.setMasterPlaylistPreloaderCallback( onMasterM3U8PlaylistSelectPreloadUrls: (TTMasterPlaylist playlist) { if (playlist.variantStreams!.isEmpty) { return null; } List<TTMasterPreloadURLInfo> urlInfos = []; // 预加载视频流 int index = Random().nextInt(playlist.variantStreams!.length); TTMasterVariantStream stream = playlist.variantStreams![index]; TTMasterPreloadURLInfo urlInfo = TTMasterPreloadURLInfo(uri: stream.uri, preloadSize: 800 * 1024); urlInfos.add(urlInfo); print('预加载playlist 随机视频流uri=${stream.uri}, resolution=${stream.resolution} bandwidth=${stream.bandwidth}'); // 预加载音频流 if (playlist.renditions == null) { return urlInfos; } for (TTMasterRendition rendition in playlist.renditions!) { if (rendition.groupId == stream.audioGroupId) { TTMasterPreloadURLInfo urlInfo = TTMasterPreloadURLInfo(uri: rendition.uri, preloadSize: 500 * 1024); urlInfos.add(urlInfo); print('预加载playlist音频流uri=${rendition.uri}'); } } return urlInfos; });
针对视频点播服务生成的帧对齐的 MP4、HLS 视频,且以 Vid 或者 VideoModel 形式播放时,支持在播放过程中平滑切换多个分辨率的播放地址,提升用户的播放体验。参考以下代码开启平滑切换:
注意
如需关于转码生成帧对齐视频的帮助,可提交工单联系火山引擎技术支持。
player.setSmoothSwitchEnable(true);
清晰度 | 视频清晰度 | 音频清晰度 | 视频描述 | 音频描述 |
|---|---|---|---|---|
TTVideoEngineResolutionTypeSD | 360P | medium | 标清 | 普通音质 |
TTVideoEngineResolutionTypeHD | 480P | higher | 高清 | 高音质 |
TTVideoEngineResolutionTypeHD_H | 540P |
| 540P |
|
TTVideoEngineResolutionTypeFullHD | 720P | highest | 超清 | 音乐音质 |
TTVideoEngineResolutionType1080P | 1080P | original | 1080P | 原画 |
TTVideoEngineResolutionType2K | 2K |
| 2K |
|
TTVideoEngineResolutionType4K | 4K |
| 4K |
|