对于标准的 Master M3U8 播放源,播放器 SDK 提供了精细的控制能力,允许开发者在播放生命周期的不同阶段介入,精确选择要使用的视频流(清晰度)和音频流(音轨)。
通过设置 masterPlaylistDelegate,您可以在播放器 SDK 解析完 M3U8 文件后、开始下载媒体数据前,通过代理方法返回您期望的视频流和音轨的索引,从而控制起播。具体工作流程如下:
设置代理:为播放器实例设置 masterPlaylistDelegate 并遵循 TTVideoEngineMasterPlaylistDelegate 协议。
接收流信息:当 M3U8 解析完成后,SDK 触发 onMasterPlaylist 回调。您可以在此获取并保存包含所有视频流 variantStreams 和音频流 renditions 的 masterPlaylist 对象。
// 遵循 TTVideoEngineMasterPlaylistDelegate 协议 // @interface YourViewController () <TTVideoEngineMasterPlaylistDelegate> // 设置代理 self.videoEngine.masterPlaylistDelegate = self; #pragma mark - TTVideoEngineMasterPlaylistDelegate /** * M3U8 解析完成的回调。 * 在此处保存 masterPlaylist 对象,以便在播放中切换清晰度或音轨时使用。 */ - (void)videoEngine:(TTVideoEngine *)videoEngine onMasterPlaylist:(TTVideoEngineMasterPlaylist *)masterPlaylist { self.masterPlaylist = masterPlaylist; NSLog(@"M3U8 解析完成,可用视频流为:%ld", (long)masterPlaylist.variantStreams.count); }
返回决策索引:通过 indexOfVariantOnPlayMasterPlaylist 和 indexOfRenditionOnPlayMasterPlaylist 返回您选定的视频流和音频流的索引。以下示例代码展示了以 720p 分辨率和英文音轨起播:
// 返回起播的视频流的序号,-1 表示自动选择 - (int)videoEngine:(TTVideoEngine *)videoEngine indexOfVariantOnPlayMasterPlaylist:(TTVideoEngineMasterPlaylist *)masterPlaylist { if (self.masterPlaylistPlayTargetIndex >= -1 && self.masterPlaylistPlayTargetIndex < (int)masterPlaylist.variantStreams.count) { return self.masterPlaylistPlayTargetIndex; } NSLog(@"清晰度选择错误:当前视频支持: -1 ~ %d,将播放默认清晰度", (int)(masterPlaylist.variantStreams.count - 1)); return -1; } // 返回起播的音频流的 streamId,-1 表示自动选择 - (int)videoEngine:(TTVideoEngine *)videoEngine indexOfRenditionOnPlayMasterPlaylist:(TTVideoEngineMasterPlaylist *)masterPlaylist { if (self.masterPlaylistAudioTrackIndex == -1) { return -1; } if (self.masterPlaylistAudioTrackIndex >= 0 && self.masterPlaylistAudioTrackIndex < (int)masterPlaylist.renditions.count) { return [[self.masterPlaylist.renditions objectAtIndex:self.masterPlaylistAudioTrackIndex].inStreamId intValue];; } NSLog(@"清晰度选择错误(rendition):当前视频支持: -1 ~ %d,将播放默认 rendition", (int)(masterPlaylist.renditions.count - 1)); return -1; }
要切换视频清晰度,您需要获取目标流的带宽值,并调用 setIntOption 方法,将 PLAYER_OPTION_SET_MASTER_M3U8_VIDEO_BANDWIDTH 作为键,带宽值作为值传入。
NSString* inputBitrate = [_inputBitrateTextView.text stringByTrim]; // 通过 setOptionForKey 切换视频流 [self.player.videoEngine setOptionForKey:VEKKeySetMasterm3u8VideoBandwidth_NSInteger value:@(inputBitrate.intValue)];
要切换音轨,您需要获取目标音轨的 InfoId,并调用 setOptionForKey:value: 方法,将 VEKKeyPlayerSwitchAudioInfoId_NSInteger 作为键,InfoId 作为值传入。
NSString* inputStreamId = [_inputStreamIdTextView.text stringByTrim]; // 通过 setOptionForKey 切换音频流 [self.player.videoEngine setOptionForKey:VEKKeyPlayerSwitchAudioInfoId_NSInteger value:@(inputStreamId.intValue)];
如果您使用 SDK 提供的预加载策略,同样可以介入并指定预加载哪些流。通过设置 TTVideoEnginePreloadDelegate,您可以在预加载任务解析完 M3U8 后,通过代理方法返回要预加载的流的索引。
// 设置预加载代理 // @interface YourAppDelegate () <TTVideoEnginePreloadDelegate> [TTVideoEngine ls_setPreloadDelegate:self]; #pragma mark - TTVideoEnginePreloadDelegate // 返回预加载的视频流的序号,-1 表示自动选择 - (int)indexOfVariantOnPreloadMasterPlaylist:(TTVideoEngineMasterPlaylist *)masterPlaylist { if (self.masterPlaylistPreloadTargetIndex >= -1 && self.masterPlaylistPreloadTargetIndex < (int)masterPlaylist.variantStreams.count) { return self.masterPlaylistPreloadTargetIndex; } NSLog(@"清晰度选择错误:当前视频支持: -1 ~ %d,将预加载默认清晰度", (int)(masterPlaylist.variantStreams.count - 1)); return -1; } // 返回预加载的音频流的序号,-1 表示自动选择 - (int)indexOfRendtionOnPreloadMasterPlaylist:(TTVideoEngineMasterPlaylist *)masterPlaylist { if (masterPlaylist.renditions.count == 0) { return -1; } if (self.masterPlaylistPreloadTargetIndex >= -1 && self.masterPlaylistPreloadTargetIndex < (int)masterPlaylist.renditions.count) { return self.masterPlaylistPreloadTargetIndex; } NSLog(@"清晰度选择错误(rendition):当前视频支持: -1 ~ %d,将预加载默认 rendition", (int)(masterPlaylist.renditions.count - 1)); return -1; }