SDM(Smart Device Model)
开发,了解 SDM
相关请查看 SDM 文档。详见 面板小程序 > 搭建环境。
在复杂视频场景中,利用 AI 技术识别并突出显示关键主体(如宠物、人像等),以增强视觉焦点。
面板小程序的开发在 小程序开发者 平台上进行操作,首先请前往 小程序开发者平台 完成平台的注册登录。
详细操作步骤,请参考 创建面板小程序。
打开物料广场基于 AI 视频主体突出示例 物料,创建一个小程序项目,需要在 Tuya MiniApp IDE 上操作。
详细操作步骤,请参考 初始化项目工程。
完成以上步骤后,一个面板小程序的开发模板初始化完成。以下为工程目录的介绍:
├── src
│ ├── api // 面板所有云端 API 请求聚合文件
│ ├── components
│ │ ├── GlobalToast // 全局轻弹窗
│ │ ├── IconFont // svg 图标容器组件
│ │ ├── MusicSelectModal // 背景音乐选择弹窗
│ │ ├── TopBar // 顶部信息栏
│ │ ├── TouchableOpacity // 点击按钮组件
│ │ ├── Video // 视频容器组件
│ │ ├── VideoSeeker // 视频滑动条组件
│ ├── constant
│ │ ├── dpCodes.ts // dpCode 常量
│ │ ├── index.ts // 存放所有的常量配置
│ ├── devices // 设备模型
│ ├── hooks // hooks
│ ├── i18n // 多语言
│ ├── pages
│ │ ├── home // 首页
│ │ ├── AISkillBtn // AI 视频处理能力按钮组件
│ │ ├── MusicSelectBtn // 背景音乐选择按钮组件
│ ├── redux // redux
│ ├── res // 图片资源 & svg 相关
│ ├── styles // 全局样式
│ ├── types // 全局类型定义
│ ├── utils // 业务常用工具方法
│ ├── app.config.ts
│ ├── app.less
│ ├── app.tsx
│ ├── composeLayout.tsx // 处理监听子设备添加、解绑、DP 变化等
│ ├── global.config.ts
│ ├── mixins.less // less mixins
│ ├── routes.config.ts // 配置路由
│ ├── variables.less // less variables
功能介绍
视频资源在初始化导入阶段依赖以下两个关键能力:
相关代码段
import { chooseMedia, clipVideo } from "@ray-js/ray";
// 由于系统兼容性问题,该路径用于视频展示
const [videoSrc, setVideoSrc] = useState("");
// 由于系统兼容性问题,该路径用于视频生成
const [videoFileSrc, setVideoFileSrc] = useState("");
// 存储视频首帧渲染图片
const [posterSrc, setPosterSrc] = useState("");
// 导入视频资源
const getVideoSourceList = () => {
paseVideo();
chooseMedia({
mediaType: "video",
sourceType: ["album", "camera"],
isFetchVideoFile: true,
success: (res) => {
initState();
const { tempFiles } = res;
console.log("==tempFiles", tempFiles);
clipVideo({
filePath: tempFiles[0].tempFilePath,
startTime: 0,
endTime: tempFiles[0].duration * 1000,
level: 4,
success: ({ videoClipPath }) => {
console.log("====clipVideo==success", videoClipPath);
setVideoSrc(videoClipPath);
setPosterSrc(tempFiles[0].thumbTempFilePath);
setHandleState("inputDone");
},
fail: (error) => {
console.log("====clipVideo==fail", error);
setHandleState("idle");
},
});
},
});
};
功能介绍
视频 AI 生成后导出功能,主要用于支持 C 端用户完成视频素材编辑后将视频转存至手机相册。
相关代码段
import { saveVideoToPhotosAlbum, showToast } from "@ray-js/ray";
// 由于系统兼容性问题,该路径用于视频生成
const [videoFileSrc, setVideoFileSrc] = useState("");
// 导出视频资源
const handleOutputVideo = () => {
saveVideoToPhotosAlbum({
filePath: videoFileSrc,
success: (res) => {
// 进行视频导出成功提示
showToast({
title: Strings.getLang("dsc_output_video_success"),
icon: "success",
});
},
fail: (error) => {
console.log("==saveVideoToPhotosAlbum==fail", error);
},
});
};
组件介绍
视频展示组件用于原始视频素材、AI 生成视频素材的展示,支持 C 端用户随时播放、暂停视频,同时组件内部镶嵌了视频进度条,支持 C 端用户滑动预览视频内容。
相关代码段
import { saveVideoToPhotosAlbum, showToast } from "@ray-js/ray";
// 由于系统兼容性问题,该路径用于视频展示
const [videoSrc, setVideoSrc] = useState("");
// 存储视频首帧渲染图片
const [posterSrc, setPosterSrc] = useState("");
<Video id="video-editor" type="previewer" src={videoSrc} poster={posterSrc} />;
功能介绍
目前模版提供部分默认背景音乐供开发者获取、使用,后续音乐内容将进行扩充,其中获取默认背景音乐主要分为以下两个步骤:
相关代码段
import { backgroundMusicList, backgroundMusicDownload } from "@ray-js/ray";
const createLocalMusicPath = (idx: number) => {
const fileRoot = ty.env.USER_DATA_PATH;
const filePath = `${fileRoot}/music${idx + 1}.mp4`;
return filePath;
};
// 下载所有音乐
const downloadMusic = (musicArray: Array<ItemMusic>) => {
// 使用 map 遍历每个 URL,并用 Promise 包裹同步调用
const downloadPromises = musicArray.map((music, index) => {
const localPath = createLocalMusicPath(index);
return new Promise((resolve, reject) => {
try {
backgroundMusicDownload({
musicUrl: music.musicUrl,
musicPath: localPath,
success: (res) => {
console.log("==backgroundMusicDownload==success", res);
resolve({
id: music.musicTitle,
...music,
musicLocalPath: localPath,
});
},
fail: ({ errorMsg }) => {
console.log("==backgroundMusicDownload==fail", errorMsg);
},
});
} catch (error) {
reject(error);
}
});
});
return Promise.all(downloadPromises)
.then((localMusicArray) => {
console.log("下载完成:", localMusicArray);
return localMusicArray;
})
.catch((error) => {
console.error("下载过程中出现错误:", error);
});
};
// 初始化本地音乐资源列表
const initLocalMusicSource = () => {
backgroundMusicList({
success: ({ musicList }) => {
console.log("===backgroundMusicList==", musicList);
downloadMusic(musicList)
.then((resList) => {
console.log("===downloadMusic==success", resList);
// 将背景音乐数据缓存至面板 redux 中
dispatch(updateMusicInfoList(resList));
})
.catch((error) => {
console.log("===downloadMusic==fail", error);
});
},
fail: ({ errorMsg }) => {
console.log("====backgroundMusicList==fail", errorMsg);
},
});
};
// 在面板初始化时完成背景音乐初始化
initLocalMusicSource();
功能介绍
目前模版提供 LocalMusicList
组件,用于展示、试听背景音乐;其中音乐的试听能力,主要通过 InnerAudioContext
实例实现。
相关代码段
import { createInnerAudioContext } from "@ray-js/ray";
// 初始化 audioManager 实例
const audioManager = createInnerAudioContext({
success: (res) => {
console.log("==createInnerAudioContext==success", res);
},
fail: (error) => {
console.log("==createInnerAudioContext==fail", error);
},
});
// 通过本地路径播放本地音乐
audioManager.play({
src: currentMusic.musicLocalPath,
success: (res) => {
console.log("==play==success", res);
},
fail: (error) => {
console.log("==play==fail", error);
},
});
// 暂停音乐播放
audioManager.pause({
success: (res) => {
console.log("==stop==pause", res);
},
fail: (error) => {
console.log("==stop==pause", error);
},
});
// 销毁音频管理实例
audioManager.destroy({
success: (res) => {
console.log("==destroy==success", res);
},
fail: (error) => {
console.log("==destroy==fail", error);
},
});
宠物、人像主体突出
功能介绍
C 端用户可在模版中选择希望突出的主体分类,AI 将根据用户选项自动处理。
视频流背景音乐编辑
功能介绍
C 端用户可在模版中选择希望与 AI 视频合并导出的背景音乐,同时模版支持 C 端用户自定义原视频音频与背景音乐的混音比例。
import { ai } from "@ray-js/ray";
import { createTempVideoRoot } from "@/utils";
const {
objectDetectCreate,
objectDetectDestroy,
objectDetectForVideo,
objectDetectForVideoCancel,
offVideoObjectDetectProgress,
onVideoObjectDetectProgress,
} = ai;
// 当前 AI 视频的编辑状态
const [handleState, setHandleState] = useState("idle");
// 当前 AI 视频流处理进度
const [progressState, setProgressState] = useState(0);
// 注册 App AI 实例
useEffect(() => {
objectDetectCreate();
return () => {
// 页面销毁时同时销毁 App AI 实例
objectDetectDestroy();
audioManager.destroy({
success: (res) => {
console.log("==destroy2==success", res);
},
fail: (error) => {
console.log("==destroy2==fail", error);
},
});
};
}, []);
// AI 视频流处理功能
const handleVideoByAI = (
detectType: number,
imageEditType: number,
musicPath = ""
) => {
// 生成 AI 主体突出视频时建议关闭音乐播放,避免系统出现未知错误
paseVideo();
// 生成 AI 主体突出视频导出路径
const tempVideoPath = createTempVideoRoot();
// 开启 AI 主体突出视频生成进度监听
onVideoObjectDetectProgress(handleListenerProgress);
objectDetectForVideo({
inputVideoPath: videoSrc,
outputVideoPath: tempVideoPath,
detectType,
musicPath,
originAudioVolume: volumeObj.video / 100,
overlayAudioVolume: volumeObj.music / 100,
imageEditType,
audioEditType: 2,
success: ({ path }) => {
// 注销 AI 主体突出视频生成进度监听
offVideoObjectDetectProgress(handleListenerProgress);
setProgressState(0);
fetchVideoThumbnails({
filePath: path,
startTime: 0,
endTime: 1,
thumbnailCount: 1,
thumbnailWidth: 375,
thumbnailHeight: 212,
success: (res) => {
setHandleState("success");
setVideoSrc(path);
showToast({
title: Strings.getLang("dsc_ai_generates_success"),
icon: "success",
});
},
fail: ({ errorMsg }) => {
console.log("==fetchVideoThumbnails==fail==", errorMsg);
},
});
},
fail: ({ errorMsg }) => {
console.log("==objectDetectForVideo==fail==", errorMsg);
offVideoObjectDetectProgress(handleListenerProgress);
setProgressState(0);
setHandleState("fail");
setHandleState("selectSkill");
setIsShowAISkills(true);
showToast({
title: Strings.getLang("dsc_ai_generates_fail"),
icon: "error",
});
},
});
};
// 打断 AI 主体突出视频流生成
const handleCancelAIProcess = () => {
objectDetectForVideoCancel({
success: () => {
setHandleState("select");
},
});
};
具体 AI 技术方案介绍,详见:视频解决方案—视频主体突出方案
具体 API 相关介绍,详见:开发者文档—AI 基础包