Duo-Video 是一个强大的 Java 视频编辑 SDK,通过简洁优雅的 API 以编程方式生成专业级视频项目。项目采用分层架构设计,通过生成剪映工程文件实现视频创作

(本工程由 com.duoec.video.jy.JianyingBuilderTest.buildWithProjectJson 测试用例生成) 下载这个剪映工程
duo-video-base 定义了一套简洁而完整的视频数据模型 (参考:duo-video-jy/src/test/resources/001_base_project.json),用最小化的结构描述复杂的完整视频项目。
以 VideoProject 视频工程文件为基础。比剪映文件更加简洁、简化了复杂的本地文件引用,一个json文件就组建起整个视频的框架
更方便AI理解,并通过MCP,供AI Agent的调用,满足AI使用场景
AutoJY,以单任务的方式拉取视频任务,控制剪映生成视频。可以通过部署多个剪映生成服务,以支持大批量的视频创作
graph LR
A[AI生成
脚本、分镜、包装] --> B[API/MCP
多粒度接口功能]
B --> C[VideoProject
视频模型 JSON]
D[第三方系统
直接生成VideoProject] --> C
C --> E[生成剪映草稿
视频任务]
E --> F[AutoJY
领取任务、导出视频]
F --> G[用户下载
成片视频]
style A fill:#e1f5ff
style C fill:#fff4e1
style E fill:#e8f5e9
style F fill:#f3e5f5
文本预设样式 - 文本预设样式,简化配置,支持剪映划词高亮
| 素材类型 | 功能描述 | 特性 |
|---|---|---|
| 视频 | 支持常见视频格式 | 时间裁剪、变速、倒放 |
| 图片 | 支持常见图片格式 | 自定义显示时长、缩放 |
| 文本 | 富文本编辑 | 多样式、花字、描边、阴影、背景 |
| 字幕 | 基于文本系统 | 继承全部文本样式能力 |
| 音频 | 背景音乐、配音 | 时间范围、音量控制 |
| 文本模板 | 官方动画模板 | 多文本块、动态效果 |
| 特效类型 | 功能描述 | 应用场景 | 资源数量 |
|---|---|---|---|
| 特效音 | 短音效资源 | 转场音、点击音、环境音 | 875 |
| 贴纸 | 动态或静态贴纸 | 表情、标签、装饰 | 7805 |
| 转场 | 场景过渡动画 | 淡入淡出、擦除、翻转等 | 774 |
| 画面特效 | 全屏视觉效果 | 粒子、扭曲、色彩调整 | 1538 |
| 脸部特效 | AI 人脸特效 | 美颜、搞怪、风格化 | 310 |
剪映资源浏览:https://www.duoec.com/video

点击浏览:https://www.duoec.com/video 点击资源图片,自动复制资源ID到粘贴板
duo-video/
├── auto-jy/ # 自动剪映工具(视频任务自动领取、生成、上报)
│ ├── auto-jy-win/ # Windows版自动剪映工具
│ └── auto-jy-mac/ # MAC版自动剪映工具
├── duo-server-base/ # 基础工具库(文件处理、JSON、工具类)
├── duo-video-base/ # 核心数据模型(VideoProject、Material、Segment)
├── duo-video-jy/ # 剪映集成(将数据模型转换为剪映工程格式)
│ ├── builder/ # 17 个专业 Builder 类
│ ├── dto/ # 剪映数据结构映射
│ └── service/ # 素材下载、FFmpeg、Exiftool 集成
└── duo-video-api/ # RESTful API 接口(视频生产接口、视频任务接口)
├── controller/ # HTTP 接口控制器
├── dto/ # 请求/响应数据传输对象
└── server/ # 业务服务层
VideoProject (视频项目)
├── projectName: 项目名称
├── width/height: 分辨率
├── fps: 帧率
├── scripts: List<VideoScript> (分镜列表,用于组织复杂的项目)
│ └── VideoScript (分镜)
│ ├── time: 时间范围(可选,未填写时自动扩容)
│ └── segments: List<VideoSegment> (片段列表)
│ └── VideoSegment (片段)
│ ├── materialId: 关联的素材ID
│ ├── type: 素材类型
│ ├── time: 显示时间范围
│ ├── speed: 变速
│ ├── zoom: 缩放
│ ├── point: 位置
│ ├── rotate: 旋转
│ ├── opacity: 透明度
│ ├── volume: 音量
│ └── refs: 关联的其他素材(如转场)
└── materials: List<BaseMaterial> (素材库)
Y+
↑
|
X- ←--(0,0)--→ X+
|
↓
Y-
参考剪映的坐标系
所有时间参数使用 毫秒(ms) 为单位:
轨道自下而上的渲染顺序(数字越小越在底层):
{
"scripts": [ // 分镜。也可以一个视频都放在一个分镜下,仅为方便管理
{
"segments": [
{
"id": 296653948753219561,
"time": { // 当前视频展示的
"start": 3000, // 当前片段从第几毫秒开始,单位:毫秒
"duration": 5000 // 当前片段持续时长,单位:毫秒
},
"materialId": 535010997887571046, // 引用的素材ID
"materialStart": 10000, // 当前片段的视频从第几毫秒开始
"type": "video"
}
]
}
],
"materials": [
{
"id": 535010997887571046, // 全局唯一。生成剪映工程时会将它作为临时文件名,如果重复,视频引用会乱掉!
"url": "https://api.duoec.com/public/video/535010997887571046.mov",
//"url": "file:///Users/xuwenzhen/Downloads/535010997887571046.mov", # 支持本地文件
"type": "video"
}
]
}
{
"scripts": [
{
"segments": [
{
"id": 296653948753219560,
"time": {
"start": 0,
"duration": 3000
},
"materialId": 535010997887571021,
"materialStart": 5000,
"type": "video"
}
]
}
],
"materials": [
{
"id": 535010997887571021, // 素材ID,是一个全局唯一的整数
"url": "https://api.duoec.com/public/video/535010997887571021.mp4",
"type": "video",
"time": { // 素材使用片段。可选,为空时表示整个视频
"start": 0,
"duration": 86586
},
"greenBackground": { // 绿幕配置,当然也支持白幕、蓝幕。以下参数可以使用AI推荐(需要多模态支持)
"materialId": 535010997887571022, // 绿幕素材,可以是图片、视频
"baseBackgroundColor": "#4e8a1fff", // 绿幕颜色
"strength": 20, // 强度。参考剪映里的 强度
"edgeFeather": 10, // 边缘羽化。参考剪映
"edgeCleanup": 10, // 边缘清理。参考剪映
"shadow": 0 // 阴影。参考剪映,旧版本不支持
}
},
{ // 绿幕背景的素材
"id": 535010997887571022,
"url": "https://api.duoec.com/public/greenScreen/d8a0e31b50166b6219b1df1dbb90e284.png",
"type": "image"
}
]
}
{
"scripts": [
{
"segments": [
{
"id": 296653948753219564,
"time": {
"start": 4000,
"duration": 3000
},
"materialId": 535010997887571021, // 注意,多次复用时,会复用第一次出现时的构建复合片段
"materialStart": 9000,
"type": "video",
"refs": {
"296653948753219539": "mask"
}
}
]
}
],
"materials": [
{
"id": 535010997887571021, // 素材ID,是一个全局唯一的整数
"url": "https://api.duoec.com/public/video/535010997887571021.mp4",
"type": "video",
"time": { // 素材使用片段。可选,为空时表示整个视频
"start": 0,
"duration": 86586
},
"greenBackground": { // 绿幕配置,当然也支持白幕、蓝幕。以下参数可以使用AI推荐(需要多模态支持)
"materialId": 535010997887571022, // 绿幕素材,可以是图片、视频
"baseBackgroundColor": "#4e8a1fff", // 绿幕颜色
"strength": 20, // 强度。参考剪映里的 强度
"edgeFeather": 10, // 边缘羽化。参考剪映
"edgeCleanup": 10, // 边缘清理。参考剪映
"shadow": 0 // 阴影。参考剪映,旧版本不支持
}
},
{ // 绿幕背景的素材
"id": 535010997887571022,
"url": "https://api.duoec.com/public/greenScreen/d8a0e31b50166b6219b1df1dbb90e284.png",
"type": "image"
},
{
"id": 296653948753219539,
"resourceId": 270415264124764161, // 蒙板-圆形的资源ID
"type": "mask",
"config": { // 以下是蒙板的配置,有点复杂,需要配合人脸识别小模型才能完成程序自动生成。这一部分可能还会进行优化
"width": 0.5, // 蒙板宽度比例(与视频宽的比值)
"height": 0.28, // 蒙板高度比例(与视频高的比值)
"centerX": 0.07, // 蒙板中心位置X轴(与视频宽的比值,有点奇葩)
"centerY": 0.25, // 蒙板中心位置Y轴(与视频高的比值,有点奇葩)
"pointX": 400, // 蒙板视频的位移X轴,与剪映界面值一致
"pointY": 400 // 蒙板视频的位移Y轴,与剪映界面值一致
}
}
]
}
{
"scripts": [
{
"segments": [
{
"id": 296653948753219562,
"time": {
"start": 10,
"duration": 1990
},
"materialId": 535010997887571047,
"materialStart": 0,
"type": "subtitle",
"layoutIndex": 1000,
"refs": {},
"speed": 100,
"point": {
"x": 0,
"y": -1000
},
"rotate": 0
}
]
}
],
"materials": [
{
"id": 535010997887571047,
"type": "text",
"text": "测试中文字幕",
"textType": "subtitle",
"style": {
"fontSize": 14,
"bold": false,
"italic": false,
"textAlign": 1,
"fontName": "微软雅黑",
"fillColor": "#FFFFFF",
"strokeColor": "#FF0000",
"strokeWidth": 10
},
"words": [
{
"index": 2,
"length": 2,
"fontSize": 16,
"fillColor": "#00FFFF",
"strokeColor": "#0000FF",
"strokeWidth": 20
},
{
"index": 3,
"length": 2,
"fontSize": 18,
"fillColor": "#FFFF00",
"backgroundColor": "#FF0000"
}
]
}
]
}
实现预设样式,可以在需要使用的地方简单使用 styleId引用即可,还支持预设样式的覆盖
{
"scripts": [
{
"segments": [
{
"id": 535010997887571047,
"type": "text",
"text": "测试中文字幕",
"textType": "subtitle",
"styleId": 296653948753219540, // 可以直接引用文本样式,以简化样式定义
"style": {
"fontSize": 14 // 可以覆盖样式,仅覆盖当前样式,不会污染预设样式
},
"words": [
{
"index": 2,
"length": 2,
"fontSize": 16,
"fillColor": "#00FFFF",
"strokeColor": "#0000FF",
"strokeWidth": 20
},
{
"index": 3,
"length": 2,
"styleId": 296653948753219540, // 文本片段样式也可以直接引用样式
"fontSize": 18 // 在引用的样式之后,可以覆盖样式
}
]
}
]
}
],
"materials": [
{ // 定义一个样式表
"id": 296653948753219540,
"type": "style",
"globalKeywordStyle": true, // 设置为全局关键字样式,作为剪映的划词默认样式,此样式全局仅存在一个为true
"style": {
"fontSize": 28,
"bold": true,
"italic": true,
"textAlign": 1,
"fontName": "抖音美好体",
"fillColor": "#FFFF00",
"strokeColor": "#FF0000",
"strokeWidth": 10
}
}
]
}
{
"scripts": [
{
"segments": [
{
"id": 296653948753219503,
"time": {
"start": 0,
"duration": 2000
},
"materialId": 535010997887571000,
"type": "text",
"zoom": { // 文本模板的缩放
"x": 5000, // 单位:万分之几,5000即 50%
"y": 5000
},
"point": { // 文本模板位置,与剪映一致
"x": 0,
"y": 1400
}
}
]
}
],
"materials": [
{
"id": 535010997887571000,
"type": "text_template", // 类型
"texts": [ // 内容,需要与文本模板匹配
"非常棒"
],
"resourceId": 270464050694389761 // 文本模板资源ID,可以到 https://www.duoec.com/video 上查询
}
]
}
```java /* * 合并为复合片段 * 将已经添加进 剪映草稿 的多段片段抽取成复合片段。程序将会自动迁移指定片段依赖的materials一并迁移到复合片段内 * 跟在剪映上直接合并复合片段是一样的效果 * @param projectInfo 工程 * @param segments 需要合并的segments / com.duoec.video.jy.utils.Jianyi
$ claude mcp add duo-video \
-- python -m otcore.mcp_server <graph>