播放器 SDK 支持下载功能。用户可在有网络的条件下将视频下载至本地,随后在无网络的环境下观看。播放器 SDK 支持下载 DirectUrl 视频源和 Vid 视频源,并提供开始、暂停、恢复、删除等控制下载任务的方法。本文介绍如何接入播放器 SDK 的下载功能,包含功能介绍、前提条件、集成步骤等内容。
注意
如需下载 HLS 视频,请集成 iOS 播放器 SDK 1.37.1.7 或以上版本。
使用下载功能前,您需要先在播放器 SDK 初始化过程中对下载功能进行一些必要的配置,例如是否开启下载 HLS 视频的能力、设置下载路径。此外您还可以设置最大并发数和空闲磁盘空间大小的限制等。
注意
需要特别注意的是,初始化代码的时序对下载功能是否能正常工作有直接影响:
HLSProxyModule,从而开启 HLS 下载功能。此方法必须在 [TTSDKManager startWithConfiguration:] 方法之前调用。[TTSDKManager startWithConfiguration:] 方法之前调用。[TTSDKManager startWithConfiguration:] 方法之后调用。示例代码如下:
#import <TTSDKFramework/TTVideoEngine+Preload.h> #import <TTSDKFramework/TTVideoEngine+Options.h> #import <TTSDKFramework/TTVideoEngineDownloader.h> - (void)initTTSDK { // 开启 HLS 下载功能。可选,如业务中无需下载 HLS 视频,可跳过。 [[TTVideoEngine ls_localServerConfigure] setOptionForKey:@(VEKKeyHLSProxyProtocolEnable_BOOL) value:@YES]; // 必填,设置下载文件存储路径 // 注意:必须是沙盒可写存储路径,并且是绝对路径 // 以下为存储路径示例,您也可以根据实际情况填写其他 app 可写路径 NSArray *paths = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES); NSString *cacheDir = [paths firstObject]; [TTVideoEngine ls_localServerConfigure].downloadDirectory = [cacheDir stringByAppendingPathComponent:@"VideoDownload"]; // 初始化播放器 SDK [TTSDKManager startWithConfiguration:configuration]; // 选填,设置最大并发下载数,默认值为 1 [TTVideoEngineDownloader shareLoader].maxDownloadOperationCount = 3; // 选填,设置空闲磁盘空间大小的限制,默认值 1 GB // 当前设为 1 GB,如果剩余磁盘大小不足 1 GB,则返回 TTVideoEngineErrorNotEnoughDiskSpace 错误 [TTVideoEngineDownloader shareLoader].limitFreeDiskSize = 1024 * 1024 * 1024; // iOS 播放器 SDK 默认支持缓存最多 50 个视频,如业务超出此限制,需进行以下设置 [TTVideoEngine setGlobalForKey:VEGSKeyPlayerVideoModelMaxCache_NSInteger value:@(500)]; }
播放器 SDK 支持播放 DirectUrl 视频源和 Vid 视频源。与之对应,播放器 SDK 也提供了不同数据源的下载能力。创建新的下载任务之前,建议您调用 getAllTasksWithCompletionHandler 方法获取已有下载任务。播放器 SDK 会自动保存未完成的下载任务,在对应业务启动时调用可以获取先前被中断的下载任务。您可以在 getAllTasksWithCompletionHandler 的 block 中创建下载任务,以保证调用顺序。
说明
getAllTasksWithCompletionHandler 需要在主线程调用。适用于下载来自火山引擎或第三方 CDN 的视频 URL 地址。通过传入视频的直接播放地址来指定播放内容。除了 url,您还必须提供以下参数:
cacheKey:视频的缓存索引 Key。为确保唯一性,推荐使用 URL 的 MD5 值。为确保播放器缓存和下载功能的稳定性,强烈建议您遵循以下规范来设置 cacheKey:
cacheKey 的取值应仅包含字母 (a-z, A-Z) 和数字 (0-9)。cacheKey 中使用任何特殊符号,例如 _、-、/、?、& 等。[[TTVideoEngineDownloader shareLoader] getAllTasksWithCompletionHandler:^(NSArray<__kindof TTVideoEngineDownloadTask *> * _Nonnull tasks) { TTVideoEngineDownloadURLTask *urlTask = [[TTVideoEngineDownloader shareLoader] urlTask:@[urlString] key:key videoId:nil]; [urlTask resume]; }];
适用于播放已上传至火山引擎视频点播服务的视频。通过视频的 Vid 和其对应的临时播放凭证 PlayAuthToken 来指定播放内容。这两个参数通常由您的业务服务端下发,客户端直接使用即可。详情请见通过临时播放 Token 播放。
[[TTVideoEngineDownloader shareLoader] getAllTasksWithCompletionHandler:^(NSArray<__kindof TTVideoEngineDownloadTask *> * _Nonnull tasks) { TTVideoEngineDownloadVidTask *vidTask = [[TTVideoEngineDownloader shareLoader] vidTask:videoID playAuthToken:token resolution:TTVideoEngineResolutionTypeSD]; [vidTask resume]; }];
通过以下方法控制单个下载任务:
// 开始/恢复单个下载任务。 // 支持断点续传。 [task resume]; // 暂停单个下载任务,支持断点续传。 // 此方法需要在主线程调用。 [task suspend]; // 删除单个下载任务。 // 下载任务被删除后,任务会停止,同时 TTVideoEngineDownloader 将不再管理这个任务。 // 此接口为异步操作,您需要在 `getAllTasksWithCompletionHandler` 的回调中检查是否被删除。 [task invalidateAndCancel];
通过以下方法控制所有下载任务:
// 暂停所有下载任务。 // 此方法必须在 `getAllTasksWithCompletionHandler` 之后调用。 [[TTVideoEngineDownloader shareLoader] suspendAllTasks]; // 开始/恢复所有下载任务。 // 此方法必须在 `getAllTasksWithCompletionHandler` 之后调用。 [[TTVideoEngineDownloader shareLoader] resumeAllTasks]; // 删除所有下载任务。 // 此方法必须在 `getAllTasksWithCompletionHandler` 之后调用。 [[TTVideoEngineDownloader shareLoader] removeAllTasks];
注意
下载任务删除后,该任务对应的视频文件也会被删除。
下载任务的完成情况、进度和状态等信息都需要通过实现 TTVideoEngineDownloaderDelegate 中的方法来获取,示例代码如下:
// 设置回调接收 [TTVideoEngineDownloader shareLoader].delegate = self;
/** * 下载任务完成回调。 * @param downloadTask 当前下载任务。 * @param error 错误。error 为 null 则为下载任务成功,否则为下载任务失败。详细信息,请见[错误码文档](https://www.volcengine.com/docs/4/66441)。 * - TTVideoEngineErrorNetworkNotAvailable = -9960,//网络不可用 * - TTVideoEngineErrorSaveTaskItem = -9949, * - TTVideoEngineErrorWriteFile = -9948, * - TTVideoEngineErrorNotEnoughDiskSpace = -9947, * - TTVideoEngineErrorURLUnavailable = -9945, * - TTVideoEngineErrorServiceInaccessible = -9944, * - TTVideoEngineErrorExistedTask = -9943, */ - (void)VideoEngineDownloader:(TTVideoEngineDownloader *)downloader downloadTask:(TTVideoEngineDownloadTask *)downloadTask didCompleteWithError:(nullable NSError *)error; /** * 下载任务进度更新回调。 * @param downloadTask 当前下载任务。 * - downloadTask.countOfBytesReceived 当前下载任务已下载的数据总量(HLS 不适用,见下方注意点) * - downloadTask.countOfBytesExpectedToReceive 当前下载任务需要下载的总数据量(HLS 不适用,见下方注意点) * - downloadTask.progress 当前下载任务进度 0.0~1.0 * @param bytesWritten 本次回调新增下载的数据量,单位为 Byte。 * @param timeMS 当前时间。 */ - (void)VideoEngineDownloader:(TTVideoEngineDownloader *)downloader downloadTask:(TTVideoEngineDownloadTask *)downloadTask writeData:(int64_t)bytesWritten timeInterval:(double)timeMS; /** * 下载任务开始/恢复回调。 * @param downloadTask 当前下载任务。 * @param fileOffset 已下载的数据量。 * @param expectedTotalBytes 该任务要下载的总数据量。 */ - (void)VideoEngineDownloader:(TTVideoEngineDownloader *)downloader downloadTask:(TTVideoEngineDownloadTask *)downloadTask didResumeAtOffset:(int64_t)fileOffset expectedTotalBytes:(int64_t)expectedTotalBytes; /** * 下载任务状态变更回调。 * @param downloadTask 当前下载任务。 * @param downloadState 当前下载任务状态: * - TTVideoEngineDownloadStateInit(0): 初始化。 * - TTVideoEngineDownloadStateWaiting(1): 等待中。 * - TTVideoEngineDownloadStateRunning(2): 运行中。 * - TTVideoEngineDownloadStateSuspended(3): 暂停。 * - TTVideoEngineDownloadStateCanceling(4): 正在取消。 * - TTVideoEngineDownloadStateCompleted(5): 完成。 */ - (void)VideoEngineDownloader:(TTVideoEngineDownloader *)downloader downloadTask:(TTVideoEngineDownloadTask *)downloadTask stateChanged:(TTVideoEngineDownloadState)downloadState;
注意
如果下载的媒体类型为 HLS(M3U8),SDK 无法知道整个视频的文件大小,回调中的 countOfBytesReceived 和 countOfBytesExpectedToReceive 数值并不准确。因此,对于 HLS(M3U8)您仅可以通过 - [TTVideoEngineDownloadTask progress] 获取下载的进度。
SDK 内部已经处理了下载缓存与播放的关联关系。SDK 会优先播放已经下载的视频,即使它们尚未完全下载完成,因此您播放时无需额外设置。
参考以下示例代码播放 DirectUrl 视频源:
// 播放已下载的 HLS 视频前必须设置以下 option [self.videoEngine setOptionForKey:VEKKeyIsAllowAllExtensions value:@1]; // 注意 cacheKey 与下载时使用的 cacheKey 一致 TTVideoEngineUrlSource *urlSource = [[TTVideoEngineUrlSource alloc] initWithUrl:videoUrl cacheKey:cacheKey]; [self.videoEngine setVideoEngineVideoSource:urlSource]; [self.videoEngine play];
参考以下示例代码播放 Vid 视频源:
// 离线播放已下载的视频前必须设置以下 option [self.videoEngine setOptionForKey:VEKKeyModelCacheVideoInfoEnable_BOOL value:@(YES)]; [self.videoEngine setOptionForKey:VEKKeyPlayerVideoModelPriority_ENUM value:@(TTVideoEngineVideoModelUseLocal)]; // 播放已下载的 HLS 视频前必须设置以下 option [self.videoEngine setOptionForKey:VEKKeyIsAllowAllExtensions value:@1]; // 注意 resolution 与下载时使用的 resolution 一致 TTVideoEngineVidSource *vidSource = [[TTVideoEngineVidSource alloc] initWithVid:vid playAuthToken:playAuthToken resolution:resolution]; [self.videoEngine setVideoEngineVideoSource:vidSource]; [self.videoEngine play];
播放器 SDK 支持在下载视频时一并下载外挂字幕,覆盖 URL 和 VID 两种视频源。SDK 先下载视频,再下载选中的一条字幕,供后续离线播放时加载。
注意
外挂字幕下载自 iOS 播放器 SDK 1.51.3.9 起支持,基础版、高级版和企业版均可使用。请集成 1.51.3.9 或以上版本。
getAllTasksWithCompletionHandler 回调中创建下载任务。通过 urlTask:key:videoId:subtitleInfoModel:subtitleId: 传入字幕信息和本次要下载的字幕 ID:
[[TTVideoEngineDownloader shareLoader] getAllTasksWithCompletionHandler:^(NSArray<__kindof TTVideoEngineDownloadTask *> * _Nonnull tasks) { TTVideoEngineDownloadURLTask *task = [[TTVideoEngineDownloader shareLoader] urlTask:@[urlString] key:key videoId:videoId subtitleInfoModel:subtitleInfoModel subtitleId:subtitleId // 返回本次要下载的字幕 subtitle id ]; // 可选:字幕失败不阻断整体下载任务,默认为 NO。 // YES:忽略字幕下载失败,下载任务状态为下载成功;NO:字幕下载失败,下载任务状态为下载失败; task.ignoreSubtitleDownloadFailure = YES; // 开始下载 [task resume]; }];
通过 vidTask:playAuthToken:resolution:subtitleAuthToken:downloadSubtitleModelBlock: 传入字幕鉴权 Token,并在 Block 中返回本次要下载的字幕:
[[TTVideoEngineDownloader shareLoader] getAllTasksWithCompletionHandler:^(NSArray<__kindof TTVideoEngineDownloadTask *> * _Nonnull tasks) { TTVideoEngineDownloadVidTask *task = [[TTVideoEngineDownloader shareLoader] vidTask:videoID playAuthToken:token resolution:resolution subtitleAuthToken:subtitleAuthToken downloadSubtitleModelBlock:^id<TTVideoEngineSubProtocol>(NSArray<id<TTVideoEngineSubProtocol>> *subModels) { // 返回本次要下载的字幕;返回 nil 时 SDK 默认选择第一条。 return subModels.firstObject; }]; // 可选:字幕失败不阻断整体下载任务,默认为 NO。 // YES:忽略字幕下载失败,下载任务状态为下载成功;NO:字幕下载失败,下载任务状态为下载失败; task.ignoreSubtitleDownloadFailure = YES; // 开始下载 [task resume]; }];
ignoreSubtitleDownloadFailure 默认值为 NO,设置为 YES 后字幕下载失败不影响整体下载任务的结果。
视频播放源按播放视频配置,cacheKey、resolution 等参数与下载时保持一致。
字幕按添加外挂字幕配置功能开关和字幕源,SDK 返回字幕文本,业务通过自己的 UI 展示。下载任务或字幕缓存被删除后,需要重新下载。
resume() 方法尝试恢复下载,会出现报错,错误码为 -9943。该错误码的含义是“任务已存在”。URL。vid 和 playAuthToken。[task invalidateAndCancel] 方法删除当前任务。SDK 会触发 VideoEngineDownloader:downloadTask:didCompleteWithError 的回调。didCompleteWithError 回调中,通过判断 error.code == TTVideoEngineErrorUserCancel 来确认任务是由用户(或代码逻辑)主动取消的。确认后,即可使用第一步中保存的任务信息,重新创建一个新的下载任务并开始下载。