本文为您介绍如何使用 Flutter 点播 SDK 的进阶功能。
为了帮助您快速搭建“抖音”同款短视频场景,点播 SDK 基于抖音亿级日活跃用户的真实反馈和大规模实践经验,提供两大最佳策略:预加载策略和预渲染策略。详细功能介绍,请见抖音同款短视频最佳实践。
注意
该功能仅高级版或企业版支持。请确保您已购买高级版或企业版的 License,详见 License 包管理。
// 方法定义见 TTVideoEngineStrategy // 开启预加载策略,建议在进入短视频页面开启 TTVideoEngineStrategy.enableEngineStrategy( strategyType: TTVideoEngineStrategyType.preload, scene: TTVideoEngineStrategyScene.smallVideo); // 设置预加载列表 static Future<void> setStrategyVideoSources({required List<TTVideoEngineMediaSource> videoSources}) // 更新预加载列表 static Future<void> addStrategyVideoSources({required List<TTVideoEngineMediaSource> videoSources}) // 关闭全部策略 TTVideoEngineStrategy.clearAllEngineStrategy();
// 方法定义见 TTVideoEngineStrategy // 开启预渲染策略,建议在进入短视频页面开启 TTVideoEngineStrategy.enableEngineStrategy( strategyType: TTVideoEngineStrategyType.preRender, scene: TTVideoEngineStrategyScene.smallVideo); // 设置和更新预渲染列表和预加载列表。仅需设置一次 // (可选)监听预渲染播放器完成回调,在回调内对预渲染播放器进行起播前配置(如 HLS 选档、硬解配置等),示例如下: TTVideoEngineStrategy.init(); TTVideoEngineStrategy.onCreatePreRenderEngine = ((source) async { VodPlayerFlutter player = VodPlayerFlutter(); String coreHashHex = await player.createPlayer(vid: source.getVid, preCreated: true); player.setUrlSource(source as TTVideoEngineUrlSource); player.setHLSMultiBitrateConfig( selectHlsVideoStream: () { return 800 * 1024; }, selectHlsRendition: (variantIndex) { return 0; }, ); player.setHardwareDecode(GlobalConfiguration.isHardwareDecode); player.setTrackVolumeEnabled(GlobalConfiguration.isTrackVolume); player.setCustomHeader('x-tt-flutter-test-demo', '1'); return player; });
预加载是指在开始播放之前提前下载即将播放视频的头部数据,以实现快速起播,从而显著优化播放体验。详细功能介绍,请见 Android 自定义预加载。
注意
该功能仅高级版或企业版支持。请确保您已购买高级版或企业版的 License,详见 License 包管理。
实现自定义预加载的步骤如下:
构造播放源并添加预加载任务。Vid 模式和 DirectUrl 模式的示例代码具体如下:
// 使用vid和playAuthToken初始化vid source, resolution为期望预加载的档位 TTVideoEngineVidSource source = TTVideoEngineVidSource.init( vid: <vid>, playAuthToken: <playAuthToken>, resolution: <TTVideoEngineResolutionType>); // 使用sourcec和preloadSize初始化PreloaderVidItem, 预加载字节数preloadSize默认800K TTVideoEnginePreloaderVidItem item = TTVideoEnginePreloaderVidItem.vidItemWithVideoSource(source, 800 * 1024); // 添加预加载任务 TTVideoEnginePreload.addTaskWithVidItem(item);
取消预加载任务:
// 取消全部预加载任务 TTVideoEnginePreload.cancelAllTask(); // 根据key取消一个预加载任务,key为创建预加载任务使用的cacheKey TTVideoEnginePreload.cancelTaskByKey(Key);
监听预加载任务状态:
// 对已添加的预加载任务PreloaderURLItem,监听item的cancel和end回调 // 预加载任务取消 item.onPreloadCancel = () { print('TTF -- 预加载cancel 回调到dart'); }; // 预加载任务完成 // taskInfo - 预加载任务的文件信息和下载信息 // error - 预加载任务的error信息 item.onPreloadEnd = (TTVideoEngineLocalServerTaskInfo? taskInfo, TTError? error) { Map<dynamic, dynamic>? map = taskInfo?.toJson(); String errorStr = error.toString(); print('TTF -- 预加载end 回调到dart end = $map error = $errorStr'); };
注意
该功能仅 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})
// 方法定义在 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; });
外挂字幕是指字幕文件与视频文件分开存储,用户在播放视频时按需导入字幕文件。点播 SDK 当前支持添加 WebVTT (Web Video Text Tracks) 格式的字幕文件。这种方式的优势在于其灵活性,用户可以根据实际需求选择是否导入字幕文件,或者选择加载不同语言的字幕。更重要的是,您无需进行额外的视频转码,只需要在播放端进行适当设置,便可显示字幕。本文为您介绍使用点播 SDK 时如何添加外挂字幕。
注意
该功能仅高级版或企业版支持。请确保您已购买高级版或企业版的 License,详见 License 包管理。
如果您通过 Vid 方式播放视频,需要准备字幕文件:
参考以下示例代码开启外挂字幕功能:
// 开启外挂字幕 Future<void> setSubtitleEnabled(bool enabled) // prepare 之前调用
点播 SDK 支持以下两种方式设置字幕源。您需根据实际情况选择。
使用 Vid + SubtitleToken 方式设置字幕源的示例代码如下:
说明
您可在应用服务端通过视频点播服务端 SDK 签发字幕鉴权 Token。
// 设置 Vid 字幕源 Future<void> setSubtitleAuthToken(String subtitleAuthToken)
使用 DirectURL 方式设置字幕源的示例代码如下:
// 设置 DirectURL 字幕源 // createPlayer 之后,prepare 之前调用 Future<void> setSubtitles(List<TTSubtitle> subtitles)
参考以下示例代码在起播时或者播放过程中控制开启或者关闭字幕输出:
// 开启或者关闭字幕 // createPlayer 之后调用 Future<void> setSubtitleShow(bool enabled)
参考以下示例代码在起播时或者播放过程中切换字幕:
// 切换字幕 // createPlayer 之后调用 Future<void> setSelectedSubtitle(int subtitleId);
参考以下示例代码接收字幕回调。设置字幕回调前需要先调用 setSubtitleShow(true)
开启字幕显示。
// vid + subTitleToken 播放,字幕列表信息回调 Future<void> Function(bool success, List<TTSubtitle>? subtitles, TTError? error)? onSubtitlesFetched; // 字幕文件加载结果回调 Future<void> Function(bool success)? onSubtitleFileLoadResult; // 字幕语言切换回调 Future<void> Function(bool success, int subtitleId)? onSubtitleSelected; // 字幕信息回调 Future<void> Function(String? content, double pts, double duration)? onSubtitleShow;
SDK 支持下载功能。用户可在有网络的条件下将视频下载至本地,随后在无网络的环境下观看。SDK 支持下载 DirectUrl 视频源和 Vid 视频源,并提供开始、暂停、恢复、删除等控制下载任务的方法。
说明
需要特别注意的是,初始化代码的时序对下载功能是否能正常工作有直接影响:
startWithConfiguration(<sdkConfig>)
方法之前调用。startWithConfiguration(<sdkConfig>)
方法之前调用。startWithConfiguration(<sdkConfig>)
方法之后调用。示例代码如下:
// 开启 HLS 下载功能。可选,如业务中无需下载 HLS 视频,可跳过。 TTVideoEngineDownloadTaskManager.enableHlsProxy(true); // 必填,设置下载文件存储路径 String platformDir; if (Platform.isIOS) { platformDir = (await getApplicationDocumentsDirectory()).path; } else { platformDir = (await getDownloadsDirectory())!.path; } platformDir = "$platformDir/xxxx"; TTVideoEngineDownloadTaskManager.setDownloadDirectory(docDir); // 初始化 SDK FlutterTTSDKManager.startWithConfiguration(sdkConfig); // 选填,设置最大并发下载数,默认值为 1 TTVideoEngineDownloadTaskManager.setMaxDownloadOperationCount(3); // 选填,设置空闲磁盘空间大小的限制,默认值 1G TTVideoEngineDownloadTaskManager.setLimitFreeDiskSize(1024 * 1024 * 1024); // 默认支持缓存最多 50 个视频。如业务超出此限制,需进行以下设置 TTVideoEngineDownloadTaskManager.setLimitFreeDiskCount(500); // 加载所有预加载任务 TTVideoEngineDownloadTaskManager.loadAllTask();
SDK 支持播放 DirectUrl 视频源和 Vid 视频源。与之对应,SDK 也提供了不同数据源的下载能力。
// 传入 urls、cacheKey、videoId,其中 urls 和 cacheKey 必填,cacheKey 需和视频源一一对应 TTVideoEngineDownloadURLTask task = TTVideoEngineDownloadURLTask(urls: <urls>, cacheKey: <cachekey>, videoId: <videoId>); task.resume();
// 传入 videoId、playAuthToken 和目标清晰度 TTVideoEngineDownloadVidTask task = TTVideoEngineDownloadVidTask( videoId: <videoId>, playAuthToken: <playAuthToken>, resolution: <resolution>); task.resume();
通过以下方法控制单个下载任务:
// 开始/恢复单个下载任务。 // 支持断点续传。 [task resume]; // 暂停单个下载任务,支持断点续传。 [task suspend]; // 删除单个下载任务。 // 下载任务被删除后,任务会停止,同时 TTVideoEngineDownloadTaskManager 将不再管理这个任务。 [task invalidateAndCancel];
通过以下方法控制所有下载任务:
// 开始/恢复所有下载任务 TTVideoEngineDownloadTaskManager.resumeAllTask(); // 暂停所有下载任务 TTVideoEngineDownloadTaskManager.suspendAllTask(); // 删除所有下载任务 TTVideoEngineDownloadTaskManager.removeAllTask();
/** * 下载任务完成回调。 * @param task 当前下载任务。 * @param error 错误。error 为 null 则为下载任务成功,否则为下载任务失败。 */ TTVideoEngineDownloadTaskManager.onComplete = (TTVideoEngineDownloadTask task, TTError? error) { print('Download-onComplete: $task, $error'); }; /** * 下载任务进度更新回调。 * @param task 当前下载任务。 * - downloadTask.countOfBytesReceived 当前下载任务已下载的数据总量(HLS 不适用,见下方注意点) * - downloadTask.countOfBytesExpectedToReceive 当前下载任务需要下载的总数据量(HLS 不适用,见下方注意点) * - progress 当前下载任务进度 0.0~1.0 */ TTVideoEngineDownloadTaskManager.onProgress = (TTVideoEngineDownloadTask task, double progress) { print('Download-onProgress: $task, $progress'); }; /** * 下载任务开始/恢复回调。 * @param downloadTask 当前下载任务。 * @param fileOffset 已下载的数据量。 * @param expectedTotalBytes 该任务要下载的总数据量。 */ TTVideoEngineDownloadTaskManager.onResume = (TTVideoEngineDownloadTask task, int fileOffset, int expectedTotalBytes) { print('Download-onResume: $task, $fileOffset, $expectedTotalBytes'); }; /** * 下载任务状态变更回调。 * @param task 当前下载任务。 * @param state 当前下载任务状态: * - init(0):初始化。 * - waiting(1): 等待中。 * - running(2): 运行中。 * - suspended(3): 暂停。 * - canceling(4): 正在取消。 * - completed(5): 完成。 */ TTVideoEngineDownloadTaskManager.onStateChanged = (TTVideoEngineDownloadTask task, TTVideoEngineDownloadState state) { print('Download-onStateChanged: $task, $state'); };
说明
如果下载的媒体类型为 HLS(M3U8),SDK 无法获知整个视频的文件大小, 回调中的 countOfBytesReceived
和 countOfBytesExpectedToReceive
数值并不准确。 因此,对于 HLS(M3U8) 您仅可以通过 task.progress
获取下载的进度。
SDK 内部已处理下载缓存与播放的联动关系。SDK 会优先播放已经下载的视频,即使它们尚未完全下载完成,因此您播放时无需额外设置。
参考以下示例代码播放 DirectUrl 视频源:
// 设置source前,开启离线播放已下载视频 player.enablePlayCachedSource(); // 注意 cacheKey 与下载时使用的 cacheKey 一致 TTVideoEngineUrlSource source = TTVideoEngineUrlSource.initWithURLS(<urls>, <cacheKey>); player.setMediaSource(source);
参考以下示例代码播放 Vid 视频源:
// 设置 source 前,开启离线播放已下载视频 player.enablePlayCachedSource(); // 注意 resoluton 与下载时使用的 resolution 一致 TTVideoEngineVidSource source = TTVideoEngineVidSource.init(vid: <vid>, playAuthToken: <playAuthToken>, resolution: <resolutionType>); player.setMediaSource(source);