客户端超分(Super Resolution, SR)功能,是利用设备端的高性能 AI 模型,实时增强视频画质的技术。该功能通过智能超分辨率算法,不仅能提升视频的分辨率,更能大幅增强画面的清晰度、锐度和内容细节,在不增加网络带宽消耗的前提下,为用户带来媲美原生高分辨率视频的观看体验。客户端超分主要适用于以下场景:
您可以前往官方 Demo 下载页面下载并安装 App。在播放设置页面开启超分功能后,即可直观体验该功能的效果。
在实现客户端超分功能前,请确保您已完成以下操作:
在您 App 模块的 build.gradle 文件的 dependencies 代码块中,除了确保已集成高级版SDK 外,还需添加超分功能所必需的 ttbmf_lite 模块。
// app/build.gradle dependencies { // 添加高级版 SDK 1.45.3 或之后版本 // 将 x.x.x.x 替换为具体的版本号 // implementation "com.bytedanceapi:ttsdk-player_premium:x.x.x.x" // 添加超分模块依赖 // 将 x.x.x.x 替换为具体的版本号,需与高级版 SDK 保持一致 implementation "com.bytedanceapi:ttsdk-ttbmf_lite:x.x.x.x" }
在您的 ProGuard 混淆配置文件中,添加以下规则,防止超分模块的相关类被混淆。
-keep class com.bytedance.bmf.** {*;} -keep class com.bytedance.bmf_mods.** {*;} -keep class com.bytedance.bmf_mods_api.** {*;} -keep class com.bytedance.bmf_mods_lite_api.** {*;} -keep class com.bytedance.bmf_mods_lite.** {*;}
超分模块的初始化是与播放器实例 TTVideoEngine 绑定的。您需要在创建播放器实例后、调用 play() 之前,为该实例完成超分的初始化配置。建议将初始化逻辑封装成一个独立的函数以便复用。
/** * 初始化指定播放器实例的超分功能 * * @param context 应用上下文 * @param videoEngine 需要开启超分的播放器实例 * @param enableSr 起播时是否自动开启超分 */ private static void initSuperResolution(Context context, TTVideoEngine videoEngine, boolean enableSr) { // 1. 创建超分模型所需的本地缓存目录 final File root = new File(context.getCacheDir(), "bmf"); final File binDir = new File(root, "bin"); final File cacheDir = new File(root, "cache"); if (!binDir.exists()) binDir.mkdirs(); if (!cacheDir.exists()) cacheDir.mkdirs(); // 2. 构建超分配置 Bundle final Bundle bundle = new Bundle(); bundle.putInt(TextureRenderKeys.KEY_IS_ACTION, TextureRenderKeys.TEXTURE_OPTION_INIT_EFFECT); bundle.putInt(TextureRenderKeys.KEY_IS_EFFECT_TYPE, TextureRenderKeys.TYPE_EFFECT_SUPPER_RESOLUTION); bundle.putInt(TextureRenderKeys.KEY_IS_USE_BMF_DIRECTINVOKE, 1); bundle.putInt(TextureRenderKeys.KEY_IS_USE_BMF_COMPONENT, 1); bundle.putInt(TextureRenderKeys.KEY_SR_ALG_TYPE, VideoSurface.SUPER_RES_STAT_BMF_SR_HP_V3_6); bundle.putInt(TextureRenderKeys.KEY_SR_BMF_BACKEND, VideoSurface.SUPER_RES_STAT_BMF_BACKEND_OPENGL); // 设置超分倍数: // 1.5 倍超分:VideoSurface.SUPER_SCALE_TYPE_1_5 (推荐) // 2.0 倍超分:VideoSurface.SUPER_SCALE_TYPE_2_0 bundle.putInt(TextureRenderKeys.KEY_BMF_SCALE_TYPE, VideoSurface.SUPER_SCALE_TYPE_1_5); bundle.putInt(TextureRenderKeys.KEY_BMFSR_POOLSIZE, 2); bundle.putString(TextureRenderKeys.KEY_KERNEL_BIN_PATH, binDir.getAbsolutePath()); bundle.putString(TextureRenderKeys.KEY_BMF_PROGRAM_CACHE_DIR, cacheDir.getAbsolutePath()); // 3. 将配置应用到播放器实例 // 注意:此方法必须在 openTextureSR 之前调用 videoEngine.setEffect(bundle); // 4. 配置超分的行为限制和开关 // 当视频分辨率的长边超过 1440 时,不开启超分,以避免性能问题 videoEngine.setSrMaxTextureSize(1440, 1440); videoEngine.asyncInitSR(false); videoEngine.ignoreSRResolutionLimit(true); videoEngine.dynamicControlSR(true); // 5. 开启超分功能 // SDK 内部有机型白名单限制,不在名单内的机型即使调用了此接口也不会实际开启超分 // enableSr 参数决定了在调用 play() 后,是否立即应用超分效果 videoEngine.openTextureSR(true, enableSr); }
在您的业务播放逻辑中,创建播放器实例后,调用上一步封装的 initSuperResolution 方法即可。
private Context mContext; private TTVideoEngine mVideoEngine; /** * 业务播放方法 */ public void play() { if (mVideoEngine == null) { // 创建播放器实例 mVideoEngine = new TTVideoEngine(mContext); // 设置播放源 mVideoEngine.setStrategySource(source); // 为该实例初始化超分,并设置起播时自动开启 initSuperResolution(mContext, mVideoEngine, true); } mVideoEngine.play(); } /** * 检查当前视频是否已成功开启超分 * @return true 表示正在使用超分,false 表示未使用 */ public boolean isSuperResolutionEnabled() { if (mVideoEngine != null) { return mVideoEngine.isplaybackUsedSR(); } return false; } /** * 在播放开始后,动态切换超分的开启状态 * @param enabled true 开启超分, false 关闭超分 */ public void setSuperResolutionEnabled(boolean enabled) { if (mVideoEngine != null) { // 第二个参数 `true/false` 决定了是开启还是关闭 mVideoEngine.openTextureSR(true, enabled); } }
如果您使用 SDK 提供的预渲染策略,超分功能需要与预渲染流程正确结合,才能确保在命中预渲染缓存时也能正常工作。
通过实现 EngineStrategyListener,您可以在 SDK 创建预渲染播放器实例时,立即为其初始化超分。
/** * 初始化预渲染策略,并为预渲染的播放器实例开启超分 * @param context 应用上下文 */ public static void initPreRenderStrategy(final Context context) { TTVideoEngine.setEngineStrategyListener(new EngineStrategyListener() { @Override public TTVideoEngine createPreRenderEngine(final StrategySource source) { // SDK 回调此方法,要求创建一个用于预渲染的播放器实例 final TTVideoEngine videoEngine = new TTVideoEngine(context); videoEngine.setStrategySource(source); // 关键:为这个即将用于预渲染的实例初始化超分 initSuperResolution(context, videoEngine, true); return videoEngine; } }); }
在您的业务播放逻辑中,需要判断是否命中了预渲染。在未命中预渲染、需要创建新播放器实例时,为播放器实例初始化超分。如果命中了预渲染,说明已为该实例开启过超分,无需重复操作。
private Context mContext; private TTVideoEngine mVideoEngine; private StrategySource mSource; private VideoEngineCallback mCallback; /** * 业务播放方法,实现了预渲染实例的复用逻辑,并正确处理超分初始化 */ public void play() { if (mVideoEngine == null) { // 尝试从预渲染缓存中获取播放器实例 final TTVideoEngine preRenderedEngine = TTVideoEngine.removePreRenderEngine(mSource.vid()); if (preRenderedEngine == null) { // 场景:未命中预渲染 // 创建一个新的播放器实例 mVideoEngine = new TTVideoEngine(mContext); mVideoEngine.setStrategySource(mSource); // 关键:为这个新实例初始化超分 initSuperResolution(mContext, mVideoEngine, true); } else { // 场景:命中预渲染 // 直接复用已经配置好超分的预渲染实例 mVideoEngine = preRenderedEngine; // 预渲染的播放器已处于 prepared 状态,这里可以手动补发一个 onPrepared 回调(如果业务逻辑依赖该回调) if (mCallback != null) { mCallback.onPrepared(mVideoEngine); } } mVideoEngine.setVideoEngineCallback(mCallback); } mVideoEngine.play(); }