最近更新时间:2024.01.04 15:36:00
首次发布时间:2022.08.30 16:59:12
直播 SDK 提供与智能美化特效(CV)SDK 联合方案,您可以通过调用直播 SDK 提供的美颜处理接口,快速接入 CV 功能,对本地采集的视频添加美颜、滤镜、贴纸等特效,相较于通过直播 SDK 自定义视频处理功能接入第三方美颜,集成更快捷、使用更方便、效果更佳。
本文介绍如何在直播应用中接入 CV SDK,并调用直播 SDK 接口实现美颜、滤镜等功能。另外,您也可以参考 veVOS Demo 中直播推流部分的实现,完成 CV SDK 的接入。
说明
完整的授权信息参考智能特效在线授权说明。
您需要先集成 CV SDK 和资源文件,才可以正常调用直播 SDK 接口实现美颜效果。本章节介绍如何集成 CV SDK 及其资源文件。
解压 CV SDK 文件压缩包,找到 effectAAR-release.aar
文件。
将第 1 步中找到的 AAR 文件拷贝至工程目录下的 app/libs
目录内,如果没有 libs
目录,请新建一份。
使用 Android Studio 打开工程,编辑 app 的 build.gradle
文件,在 depedencies 中新增 CV SDK 依赖。
dependencies { // ... implementation(name: 'effectAAR-release', ext: 'aar') // ... }
解压 CV 资源压缩包,解压后的特效资源如下图所示。
拷贝解压过的资源包到工程 assets 目录下,拷贝后的特效资源如下图所示。
App 启动时,在 VeLiveEffectHelper.initVideoEffectResource();
方法中将 assets
目录下的资源文件复制到外部存储中应用的私有目录 storage/xx/"$packageName"/assets/resource/
。
package com.ttsdk.quickstart.helper; import android.content.Context; import android.text.TextUtils; import com.pandora.common.env.Env; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; public class VeLiveEffectHelper { /** * 获取证书文件路径 */ public static String getLicensePath(String name) { return Env.getApplicationContext().getExternalFilesDir("assets").getAbsolutePath() + "/resource/LicenseBag.bundle/" + name; } /** * 获取模型文件路径 */ public static String getModelPath() { return Env.getApplicationContext().getExternalFilesDir("assets").getAbsolutePath() + "/resource/ModelResource.bundle"; } /** * 获取美颜文件路径 */ public static String getBeautyPathByName(String subPath) { return Env.getApplicationContext().getExternalFilesDir("assets").getAbsolutePath() + "/resource/ComposeMakeup.bundle/ComposeMakeup/" + subPath; } /** * 获取贴纸文件路径 * @param name 贴纸文件名称 */ public static String getStickerPathByName(String name) { return Env.getApplicationContext().getExternalFilesDir("assets").getAbsolutePath() + "/resource/StickerResource.bundle/stickers/" + name; } /** * 获取滤镜文件路径 * @param name 滤镜文件名称 */ public static String getFilterPathByName(String name) { return Env.getApplicationContext().getExternalFilesDir("assets").getAbsolutePath() + "/resource/FilterResource.bundle/Filter/" + name; } /** * 初始化美颜资源文件 * 将安装包内的资源文件拷贝到外部存储上 */ public static void initVideoEffectResource() { Context context = Env.getApplicationContext(); File versionFile = new File(getExternalResourcePath(), "version"); if (versionFile.exists()) { String oldVer = readVersion(versionFile.getAbsolutePath()); copyAssetFolder(context, "resource/version", versionFile.getAbsolutePath()); String newVer = readVersion(versionFile.getAbsolutePath()); if (TextUtils.equals(oldVer, newVer)) { return; } } else { copyAssetFile(context, "resource/version", versionFile.getAbsolutePath()); } updateEffectResource(context); } private static String readVersion(String fileName) { String version = ""; try { FileInputStream fin = new FileInputStream(fileName); int length = fin.available(); byte [] buffer = new byte[length]; fin.read(buffer); version = new String(buffer); fin.close(); } catch(Exception e){ e.printStackTrace(); } return version; } private static void updateEffectResource(Context context) { File licensePath = new File(getExternalResourcePath(), "LicenseBag.bundle"); removeFile(licensePath.getAbsolutePath()); copyAssetFolder(context, "resource/LicenseBag.bundle", licensePath.getAbsolutePath()); File modelPath = new File(getExternalResourcePath(), "ModelResource.bundle"); removeFile(modelPath.getAbsolutePath()); copyAssetFolder(context, "resource/ModelResource.bundle", modelPath.getAbsolutePath()); File stickerPath = new File(getExternalResourcePath(), "StickerResource.bundle"); removeFile(stickerPath.getAbsolutePath()); copyAssetFolder(context, "resource/StickerResource.bundle", stickerPath.getAbsolutePath()); File filterPath = new File(getExternalResourcePath(), "FilterResource.bundle"); removeFile(filterPath.getAbsolutePath()); copyAssetFolder(context, "resource/FilterResource.bundle", filterPath.getAbsolutePath()); File composerPath = new File(getExternalResourcePath(), "ComposeMakeup.bundle"); removeFile(composerPath.getAbsolutePath()); copyAssetFolder(context, "resource/ComposeMakeup.bundle", composerPath.getAbsolutePath()); } private static void removeFile(String filePath) { if(filePath == null || filePath.length() == 0){ return; } try { File file = new File(filePath); if(file.exists()){ removeFile(file); } }catch (Exception ex){ ex.printStackTrace(); } } private static void removeFile(File file){ // 如果是文件直接删除 if(file.isFile()){ file.delete(); return; } // 如果是目录,递归判断,如果是空目录,直接删除,如果是文件,遍历删除 if(file.isDirectory()){ File[] childFile = file.listFiles(); if(childFile == null || childFile.length == 0){ file.delete(); return; } for(File f : childFile){ removeFile(f); } file.delete(); } } public static String getExternalResourcePath() { return Env.getApplicationContext().getExternalFilesDir("assets").getAbsolutePath() + "/resource/"; } public static boolean copyAssetFolder(Context context, String srcName, String dstName) { try { boolean result = true; String fileList[] = context.getAssets().list(srcName); if (fileList == null) return false; if (fileList.length == 0) { result = copyAssetFile(context, srcName, dstName); } else { File file = new File(dstName); result = file.mkdirs(); for (String filename : fileList) { result &= copyAssetFolder(context, srcName + File.separator + filename, dstName + File.separator + filename); } } return result; } catch (IOException e) { e.printStackTrace(); return false; } } public static boolean copyAssetFile(Context context, String srcName, String dstName) { try { InputStream in = context.getAssets().open(srcName); File outFile = new File(dstName); OutputStream out = new FileOutputStream(outFile); byte[] buffer = new byte[1024]; int read; while ((read = in.read(buffer)) != -1) { out.write(buffer, 0, read); } in.close(); out.close(); return true; } catch (IOException e) { e.printStackTrace(); return false; } } }
本章节介绍如何调用直播 SDK 接口,实现美颜、贴纸等功能。
调用 config.build();
创建引擎并开启视频采集后,您需先初始化美颜资源,并设置美颜资源和证书路径,方可开启美颜,在本地预览画面中看到美颜效果。您需设置完整的证书文件路径,即指定到具体的证书文件;模型文件路径指定到 ModelResource.bundle
这层即可。
集成完成后,可通过调用 setEnable
查看回调结果,0 表示集成成功,非 0 表示集成失败。
// 推流配置 VeLivePusherConfiguration config = new VeLivePusherConfiguration(); // 配置上下文 config.setContext(this); // 失败重连次数 config.setReconnectCount(10); // 创建推流器 mLivePusher = config.build(); // 注意:本方法只在工程中集成过 CV SDK 时生效 VeLiveVideoEffectManager effectManager = mLivePusher.getVideoEffectManager(); // License 路径,请根据工程配置查找正确的路径 String licPath = VeLiveEffectHelper.getLicensePath("xxx.licbag"); // 特效模型资源包路径 String algoModePath = VeLiveEffectHelper.getModelPath(); if (!VeLiveSDKHelper.isFileExists(licPath)) { return; } // 创建美颜配置 VeLivePusherDef.VeLiveVideoEffectLicenseConfiguration licConfig = VeLivePusherDef.VeLiveVideoEffectLicenseConfiguration.create(licPath); // 设置美颜配置 effectManager.setupWithConfig(licConfig); // 设置算法包路径 effectManager.setAlgorithmModelPath(algoModePath); // 开启美颜特效处理 effectManager.setEnable(true, new VeLivePusherDef.VeLiveVideoEffectCallback() { @Override public void onResult(int result, String msg) { if (result != 0) { Log.e("VeLiveQuickStartDemo", "Effect init error:" + msg); } } }); // 关闭美颜特效处理 effectManager.setEnable(false, new VeLivePusherDef.VeLiveVideoEffectCallback() { @Override public void onResult(int result, String msg) { if (result != 0) { Log.e("VeLiveQuickStartDemo", "Effect init error:" + msg); } } });
美颜特效素材存放在 ComposeMakeup.bundle
文件中,您需使用 setComposeNodes
设置素材路径并使用 updateComposerNodeIntensity
更新特效强度才会显示美颜效果。updateComposerNodeIntensity
可以设置的素材 key 可以参考素材 key 对应说明。
注意
资源路径需要指定到 ../ComposeMakeup.bundle/ComposeMakeup/beauty_Android_lite
这层。
// 根据特效资源包,查找正确的资源路径,一般到 `reshape_lite`、`beauty_Android_lite` 目录 String beautyPath = VeLiveEffectHelper.getBeautyPathByName("xxx"); if (!VeLiveSDKHelper.isFileExists(beautyPath)) { return; } // 设置美颜美型特效资源包 mLivePusher.getVideoEffectManager().setComposeNodes(new String[]{ beautyPath }); // 设置美颜美型特效强度, NodeKey 可在资源包下的 `.config_file` 中获取,如果没有 `.config_file`,请联系商务咨询 mLivePusher.getVideoEffectManager().updateComposerNodeIntensity(beautyPath, "whiten", 0.5F);
滤镜特效素材存放在 FilterResource.bundle
文件中,您需使用 setFilter
设置素材路径并使用 updateFilterIntensity
设置滤镜强度后方可显示滤镜效果。
注意
滤镜路径需要指定到特定滤镜名,例如 ../FilterResource.bundle/Filter/Filter_01_38
。
// 滤镜资源包,查找正确的资源路径,一般到 `Filter_01_xx` 目录 String filterPath = VeLiveEffectHelper.getFilterPathByName("xxx"); if (!VeLiveSDKHelper.isFileExists(filterPath)) { return; } // 设置滤镜资源包路径 mLivePusher.getVideoEffectManager().setFilter(filterPath); // 设置滤镜特效强度 mLivePusher.getVideoEffectManager().updateFilterIntensity(0.5F);
贴纸特效素材存放在 StickerResource.bundle
文件中,您需使用的接口为 setSticker
设置素材路径后方可显示贴纸效果。
注意
贴纸路径需要指定到特定贴纸名,例如 ../StickerResource.bundle/stickers/stickers_zhaocaimao
。
// 贴纸资源包,查找正确的资源路径,一般到 `stickers_xxx` 目录 String stickerPath = VeLiveEffectHelper.getStickerPathByName("xxx"); if (!VeLiveSDKHelper.isFileExists(stickerPath)) { return; } // 设置贴纸资源包路径 mLivePusher.getVideoEffectManager().setSticker(stickerPath);
风格妆特效素材存放在 ComposeMakeup.bundle
文件中,您需使用 setComposeNodes
设置素材路径并使用 updateComposerNodeIntensity
更新特效强度方可显示风格妆效果。updateComposerNodeIntensity
可以设置的素材 key 可以参考素材 key 对应说明。
注意
风格妆路径需要指定到特定风格妆名,例如 ../ComposeMakeup.bundle/ComposeMakeup/style_makeup/aidou
。
// 根据特效资源包,查找正确的资源路径,一般到 `style_makeup` 目录 String beautyPath = VeLiveEffectHelper.getBeautyPathByName("style_makeup/aidou"); if (!VeLiveSDKHelper.isFileExists(beautyPath)) { return; } // 设置美颜美型特效资源包 mLivePusher.getVideoEffectManager().setComposeNodes(new String[]{ beautyPath }); // 设置美颜美型特效强度, NodeKey 可在资源包下的 `.config_file` 中获取,如果没有 `.config_file`,请联系商务咨询 mLivePusher.getVideoEffectManager().updateComposerNodeIntensity(beautyPath, "Filter_ALL", 0.5F); mLivePusher.getVideoEffectManager().updateComposerNodeIntensity(beautyPath, "Makeup_ALL", 0.5F);