本文介绍如何通过 Android 点播 SDK 搭建“抖音”同款短视频场景,实现“零首帧”的短视频播放效果。
在短视频场景中,缩短视频首帧耗时和提升视频上下滑动的流畅度是提升用户观看体验的重要手段:
为了帮助您快速搭建“抖音”同款短视频场景,点播 SDK 基于抖音亿级日活跃用户的真实反馈和大规模实践经验,提供两大最佳策略:预加载策略和预渲染策略。此外,您还可参考开源示例项目,实现播放提前、播放器异步调用和设置封面图等策略。这些策略可单独应用,也可相互搭配。
通过采用这些策略,您可将视频首帧耗时缩短至 100-300 毫秒,为用户呈现极速首帧和流畅丝滑的播放体验,让用户享受到与抖音相媲美的视觉盛宴。
以下视频展示了接入短视频场景最佳实践前后的播放效果对比
接入短视频场景最佳实践前 | 接入短视频场景最佳实践后 |
---|---|
上下滑动视频时有明显的卡顿感 | 播放流畅丝滑 |
下载地址:Android 示例项目。
策略 | 说明 | 优化效果 |
---|---|---|
预加载策略 | 预加载是指在播放当前视频时,提前下载后续视频的数据,以便在切换到下一个视频时实现快速起播,从而优化用户的播放体验。 | 缩短视频首帧耗时 |
预渲染策略 | 预渲染是指在播放当前视频时,提前创建播放器,对下一个视频进行解码和渲染操作。同时,您还可将预渲染的首帧用作视频封面,提前展示给用户,增强视觉效果。 | 缩短视频首帧耗时 |
播放提前 | 在上下滑动视频时,建议您在用户手指抬起后、下一个页面将要显示时调用播放接口,而非等待滑动停止后再调用播放接口。具体实现可参考 Android 示例项目。 | 缩短视频首帧耗时 |
播放器异步调用 | 建议您使用点播 SDK 提供的异步接口(例如 | 提升视频上下滑动的流畅度 |
设置封面图 | 建议您使用视频默认抽取的非黑首帧作为封面图,以避免在画面尚未渲染时出现黑屏无内容的情况。如果您不自行设置封面图,点播 SDK 的预渲染策略也会抽取首帧作为封面图,但该策略仅适用于向下滑动的视频,并且不能预渲染过多的视频,以避免性能消耗。因此,建议您选择自行设置封面图以提升用户体验。 | 避免出现黑屏,提升用户体验 |
为接入预加载策略或预渲染策略,您需要使用以下方式设置播放源。
参考以下示例代码设置 Vid 播放源。除了 vid
和 playAuthToken
外,您还需指定 resolution
,且此处设置的 resolution
必须和设置预加载源时的 resolution
保持一致。
final String vid = "YOUR_VIDEO_ID"; // appServer 下发 final String playAuthToken = "YOUR_PLAYAUTHTOKEN"; // appServer 下发 final int encodeType = TTVideoEngine.CODEC_TYPE_H264; // final int encodeType = TTVideoEngine.CODEC_TYPE_h265; // final int encodeType = TTVideoEngine.CODEC_TYPE_h266; // 1. 组装 Vid 播放源 StrategySource vidSource = new VidPlayAuthTokenSource.Builder() .setVid(vid) .setPlayAuthToken(playAuthToken) .setEncodeType(encodeType) // 设置起播清晰度,此处为 480P。不传使用默认值 360P .setResolution(Resolution.High) .build(); // 2. 设置播放源 ttVideoEngine.setStrategySource(vidSource); // 3. 播放 ttVideoEngine.play()
参考以下示例代码设置 DirectUrl 播放源。url
、vid
和 cacheKey
均为必填参数。其中:
vid
:视频 ID,可以使用 Vid 或者 Vid 的 MD5 值。cacheKey
:缓存 key,即 URL 的唯一标识。每个视频可能存在多个不同清晰度的 URL,每个 URL 对应一个 cacheKey
,但是多个 URL 对应同一个视频 ID。您可以使用 URL 中不变的部分进行 MD5 操作,将 MD5 值用作 cacheKey
。例如,对于 https://www.xxx.com/xxx/x/number
, number
之前的部分是不变的。注意
addItem
至少设置 1 个。vid
和 cacheKey
,不能为空。setEncodeType
设置。final String vid = "YOUR_VIDEO_ID"; // 替换成您自己的视频 ID final String url = "http://www.example.com/h264.mp4"; // 替换成您自己的视频 URL final String cacheKey = TTVideoEngine.computeMD5(h264Url); // 1. 组装播放源 StrategySource directUrlSource = new DirectUrlSource.Builder() .setVid(vid) .addItem( new DirectUrlSource.UrlItem.Builder() .setEncodeType(TTVideoEngine.CODEC_TYPE_H264) .setUrl(url) .setCacheKey(cacheKey) .build()) .build(); // 2. 设置播放源 ttVideoEngine.setStrategySource(directUrlSource); // 3. 播放 ttVideoEngine.play()
为接入预加载策略,您需要将视频播放列表传入 SDK 作为预加载源。SDK 会根据您提供的播放列表,在播放当前视频时提前下载后续的视频内容。
您可使用默认的预加载策略,使用火山引擎内部沉淀的、可平衡播放器体验和成本的预加载策略配置。SDK 会根据当前的播放状态自动管理预加载的时机和配置,例如预加载的并发数和数据大小。
具体步骤如下:
示例代码如下:
// 1. 全局开启预加载策略,需要在主线程调用 TTVideoEngine.enableEngineStrategy(STRATEGY_TYPE_PRELOAD, STRATEGY_SCENE_SMALL_VIDEO); List<StrategySource> sources = new ArrayList<>(); // 2. 重置视频播放列表,首次加载或者下拉刷新时调用 TTVideoEngine.setStrategySources(sources); // 播放列表有新增时(如上滑加载更多数据),可通过此接口向视频播放列表中增加数据。 // 会在之前设置给 SDK 的列表后累加。 // TTVideoEngine.addStrategySources(sources); // 3. 设置视频源并开始播放,见上文《设置播放源》章节 ttVideoEngine.setStrategySource(strategySource); ttVideoEngine.play()
注意
如果您对于预加载策略有特殊的需求,例如在业务初期成本压力不大且想要获得更好的播放体验,则可自定义预加载策略配置。
注意
仅 1.42.2.6 或之后版本支持自定义预加载策略。
示例代码如下:
// 1. 全局开启预加载策略,需要在主线程调用 TTVideoEngine.enableEngineStrategy(STRATEGY_TYPE_PRELOAD, STRATEGY_SCENE_SMALL_VIDEO); // 2. 自定义预加载策略配置 StrategyPreloadConfig config = new StrategyPreloadConfig.Builder() .setCount(count) // 预加载视频个数,不建议值设置过大会造成成本的浪费,短视频场景建议设置 3-5 个 .setSize(size)// 预加载视频大小,单位为 kb,不建议值设置过大会造成成本的浪费,10 分钟内短视频建议设置 800k .setStartBufferLimit(start_buffer_limit)// 预加载开始时机,单位为秒,例如设置 15 则表示播放器的缓冲水位达到 15 秒及以上开始去预加载视频,原则是优先保证当前播放视频的网络带宽,短视频建议设置 15 秒 .setStopBufferLimit(stop_buffer_limit)// 预加载停止时机,单位为秒,例如设置 5 则表示播放器的缓冲水位小于 5 秒则会取消当前的预加载任务,优先保证当前播放视频的网络带宽,短视频建议设置 5 秒 .build(); StrategyManager.instance().setCustomPreloadConfig(config); List<StrategySource> sources = new ArrayList<>(); // 3. 重置视频播放列表,首次加载或者下拉刷新时调用 TTVideoEngine.setStrategySources(sources); // 播放列表有新增时(如上滑加载更多数据),可通过此接口向视频播放列表中增加数据。 // 会在之前设置给 SDK 的列表后累加。 // TTVideoEngine.addStrategySources(sources); // 4. 设置视频源并开始播放,见上文《设置播放源》章节 ttVideoEngine.setStrategySource(strategySource); ttVideoEngine.play()
为接入预渲染策略,您需要将视频播放列表传入 SDK 作为预渲染源。SDK 会根据您提供的播放列表,在播放当前视频时,提前创建播放器,对播放列表中的下一个视频进行解码和渲染操作。点播 SDK 当前只支持预渲染下一个视频,不支持预渲染上一个视频。
接入预渲染策略的具体步骤如下:
enableReleasePreRenderEngineInstanceByLRU
开启预渲染 engine 释放策略,即根据 LRU (Least Recently Used) 机制释放。removePreRenderEngine
判断预渲染是否完成,处理播放逻辑。说明
调用 getPreRenderEngine
和 removePreRenderEngine
均可获取 engine 对象,但存在以下区别:
getPreRenderEngine
获取到的 engine 对象,不会脱离 SDK 内部的预渲染模块,建议不要在业务逻辑中持有该对象。removePreRenderEngine
获取到的 engine 对象,会脱离 SDK 内部的预渲染模块,您需在业务逻辑中持有该对象并自行管理其释放逻辑。接入预渲染策略的示例代码如下:
// 1. 全局开启预渲染策略,需要在主线程调用 TTVideoEngine.enableEngineStrategy(STRATEGY_TYPE_PRE_RENDER, STRATEGY_SCENE_SMALL_VIDEO); // (推荐)开启预渲染 engine 根据 LRU 机制释放 StrategyManager.instance().enableReleasePreRenderEngineInstanceByLRU(true); // 2. 重置播放列表,首次加载或者下拉刷新时调用。如同时接入预加载策略和预渲染策略,仅需设置一次视频播放列表。 List<StrategySource> sources = new ArrayList<>(); TTVideoEngine.setStrategySources(sources); // 播放列表有新增时(如上滑加载更多数据),可通过此接口向播放列表中增加数据。 // 会在先前设置给 SDK 的列表后累加。 // TTVideoEngine.addStrategySources(sources); // 3. 设置 Listener,监听预渲染回调 TTVideoEngine.setEngineStrategyListener(new EngineStrategyListener() { @Override public TTVideoEngine createPreRenderEngine(final StrategySource source) { // 创建用于预渲染下个视频的 engine,返回给 SDK。 TTVideoEngine engine = createVideoEngine(source); return engine; } }); // 4. 设置预渲染封面。 // 建议在 TextureView 的 SurfaceTextureListener 的 onSurfaceTextureAvailable 中设置。 TTVideoEngine preRenderEngine = TTVideoEngine.getPreRenderEngine(mStrategySource) if (preRenderEngine != null) { // 使用预渲染播放器渲染的首帧作为封面。这里只设置 Surface 渲染封面,业务不用持有 preRenderEngine。 preRenderEngine.setSurface(surface); preRenderEngine.forceDraw(); } else { // 使用业务自己的图片加载库加载图片封面 } // 5. 播放下个视频时,判断预渲染是否完成 TTVideoEngine mEngine; TTVideoEngine preRenderEngine = TTVideoEngine.removePreRenderEngine(mStrategySource.vid()) if (preRenderEngine != null) { // 不为 null 说明预渲染完成,直接调用播放即可。业务持有这个播放器,负责实例 release。 mEngine = preRenderEngine; } else { // 为 null 说明无预渲染,您需构造 engine 后播放。 mEngine = createVideoEngine(source); } // 设置当前页面可用 surface,建议在 TextureView 的 SurfaceTextureListener 的 onSurfaceTextureAvailable 中获取 surface。 mEngine.setSurface(surface); // 播放 mEngine.play(); private static TTVideoEngine createVideoEngine(final StrategySource source) { TTVideoEngine engine = new TTVideoEngine(this, ITTVideoEngineInternal.PLAYER_TYPE_OWN); // (必须)设置播放源。 engine.setStrategySource(source); // 根据需求自定义设置。 // engine.setIntOption(PLAYER_OPTION_USE_TEXTURE_RENDER, 1); engine.setIntOption(....); return engine; }
说明
getPreRenderEngine
和 removePreRenderEngine
获取预渲染 engine 时,如果该 engine 预渲染失败,则会被释放。removePreRenderEngine
获取到的 engine 对象,会脱离 SDK 的预渲染模块,需要您在业务逻辑中持有并自行管理其释放逻辑。removePreRenderEngine
移除的 engine。在退出短视频页面或切换到其他页面时调用 clearAllStrategy 关闭所有策略,释放资源。
TTVideoEngine.clearAllStrategy();