CLI-Anything Kdenlive Agent Harness:基于 JSON 项目与 MLT XML 的无头化视频剪辑命令行工具
2026/9/9 23:46:28 网站建设 项目流程

CLI-Anything Kdenlive Agent Harness:基于 JSON 项目与 MLT XML 的无头化视频剪辑命令行工具

【免费下载链接】CLI-Anything"CLI-Anything: Making ALL Software Agent-Native" -- CLI-Hub: https://clianything.cc/项目地址: https://gitcode.com/GitHub_Trending/cl/CLI-Anything

导读

本篇文章围绕 kdenlive/agent-harness/cli_anything/kdenlive/README.md 展开,系统讲解 CLI-Anything 生态中面向 Kdenlive 的 Agent Harness:一个「有状态」(stateful)的视频剪辑命令行接口。它把剪辑项目抽象为一份结构化 JSON 文档,并通过内部转换器生成可被 Kdenlive 与melt直接消费的 MLT XML,使素材导入、时间线编排、滤镜/转场/标记添加、撤销重做等剪辑操作全部可以脱离 GUI 以命令方式完成。读完本文,你将掌握该项目从环境安装、核心命令组用法、JSON 项目格式到 MLT XML 生成原理的完整链路,以及如何将这套 CLI 接入 Agent 工作流实现批量、可复现的视频制作。

定位:为 Agent 与自动化而生的剪辑状态层

与 Blender CLI harness 同一设计模式,Kdenlive harness 的核心理念是不直接驱动 Kdenlive GUI,而是维护一份可读、可版本化、可程序化操作的中间工程状态。安装与使用它编辑工程不需要本机安装 Kdenlive 或 melt;Kdenlive 仅作为可选查看器,用来打开最终生成的.kdenliveXML 文件(见 README.md 安装一节)。这从架构上把「剪辑决策」与「渲染/回放环境」解耦:

  • 编辑阶段:纯 Python 对象操作 + 磁盘 JSON,无需任何媒体框架;
  • 交付阶段:生成标准 MLT XML,交给 Kdenlive 或melt完成真实预览与渲染。

从源码结构看,整体入口与模块划分为(见 kdenlive/agent-harness/cli_anything/kdenlive/):

cli/ ├── __main__.py # python3 -m cli.kdenlive_cli ├── kdenlive_cli.py # 主 CLI 入口(Click + REPL) ├── core/ │ ├── project.py # 工程 创建/打开/保存/信息/profiles │ ├── bin.py # 素材箱管理 │ ├── timeline.py # 轨道与片段放置 │ ├── filters.py # 滤镜注册表与增删改查 │ ├── transitions.py # 转场管理 │ ├── guides.py # 标记/参考线管理 │ ├── export.py # XML 生成与渲染预设 │ └── session.py # 带撤销/重做的会话层 ├── utils/ │ ├── mlt_xml.py # MLT XML 生成、时间码换算 │ ├── melt_backend.py # melt 后端桥接 │ └── repl_skin.py # REPL 交互皮肤 └── tests/ ├── test_core.py # 单元测试 └── test_full_e2e.py # 端到端测试

仓库中还提供了可直接消费的 Skill 定义 kdenlive/agent-harness/cli_anything/kdenlive/skills/SKILL.md,其中声明该能力可通过pip install cli-anything-kdenlive安装,并以cli-anything-kdenlive作为命令名,适合接入支持 Claude Skills / Agent 工具的宿主环境。

环境安装与运行前提

在 agent-harness 目录下仅需安装 Click 一个 Python 依赖:

# 在 agent-harness 目录下执行 pip install click # 编辑 JSON 项目无需安装 Kdenlive 或 melt; # Kdenlive 仅用于打开生成的 .kdenlive XML 文件

按 skills/SKILL.md 的补充说明,作为独立 Python 包分发时要求Python 3.10+,若需要预览与渲染结果,则系统需安装 Kdenlive。两种入口等价:

# 仓库内以模块方式调用(README 默认写法) python3 -m cli.kdenlive_cli --help # 安装 pip 包后的命令方式 cli-anything-kdenlive --help

快速上手:一段完整的建片流程

README 提供了一条从零到导出的完整命令行流程,以下逐段说明每个操作的作用:

# 1) 新建工程(命名 + 预设 1080p30,写盘 project.json) python3 -m cli.kdenlive_cli project new --name "MyVideo" --profile hd1080p30 -o project.json # 2) 向素材箱导入素材(可指定名字与时长,时长以秒计) python3 -m cli.kdenlive_cli --project project.json bin import /path/to/video.mp4 --name "Interview" -d 120.5 python3 -m cli.kdenlive_cli --project project.json bin import /path/to/music.mp3 --name "BGM" -d 180.0 --type audio # 3) 添加视频轨与音频轨 python3 -m cli.kdenlive_cli --project project.json timeline add-track --type video python3 -m cli.kdenlive_cli --project project.json timeline add-track --type audio # 4) 将片段放置到时间线(轨道号 0/1 对应上面创建的轨道;--out 为出点秒数) python3 -m cli.kdenlive_cli --project project.json timeline add-clip 0 clip0 --position 0 --out 30.0 python3 -m cli.kdenlive_cli --project project.json timeline add-clip 1 clip1 --position 0 --out 60.0 # 5) 给轨道 0 第 0 个片段加 brightness 滤镜,设置 level=1.3 python3 -m cli.kdenlive_cli --project project.json filter add 0 0 brightness -p level=1.3 # 6) 在轨道 0 与 1 之间加 2.0s 的 dissolve 转场 python3 -m cli.kdenlive_cli --project project.json transition add dissolve 0 1 -d 2.0 # 7) 在 30.0s 处加一条名为 "Scene 2" 的标记 python3 -m cli.kdenlive_cli --project project.json guide add 30.0 --label "Scene 2" # 8) 导出为 Kdenlive/MLT XML python3 -m cli.kdenlive_cli --project project.json export xml -o output.kdenlive # 9) 保存工程 python3 -m cli.kdenlive_cli --project project.json project save

流程中体现了三个关键设计:

  1. --project全局状态注入cli组在收到--project路径时会先调用proj_mod.open_project()装载工程到全局会话,后续子命令全部作用于会话内的工程对象(见 kdenlive_cli.py 顶层cli函数);
  2. 退出时自动保存:通过 Click 的result_callback,一次性命令若改动过工程(sess._modified)会在进程退出前自动写盘,用户无需手工执行project save(kdenlive_cli.py 中auto_save_on_exit);
  3. 片段引用素材箱 IDtimeline add-clip 0 clip0中的clip0bin import自动生成的素材 ID(_next_clip_idclip0起递增,见 core/bin.py),时间线只保存引用关系与 in/out/position。

JSON 输出模式:为 Agent 解析而生

默认输出是人类可读的缩进文本,需要程序化消费结果时可加--json标志,使输出变为结构化 JSON:

# 以 JSON 输出新建工程 python3 -m cli.kdenlive_cli --json project new -o project.json # 以 JSON 输出素材箱清单 python3 -m cli.kdenlive_cli --json --project project.json bin list

从 kdenlive_cli.py 的output()handle_error装饰器可以看到,--json模式还会把异常序列化为{"error": ..., "type": ...}形式的 JSON 结构,让 Agent 能无歧义地判断成功与失败分支。此外还有两个对自动化友好的全局开关:

全局选项作用
--json将命令输出切换为 JSON
--project <path>指定.kdenlive-cli.json工程文件
--dry-run只执行不落盘(退出时跳过自动保存)

命令组全景:八个领域的可脚本化剪辑能力

Project Management(工程管理)

project new - 创建新工程 project open - 打开已有工程文件 project save - 保存当前工程 project info - 展示工程信息 project profiles - 列出可用视频预设 project json - 打印原始工程 JSON

project new支持--name/-n--profile/-p或自定义的--width/--height/--fps-num/--fps-den,若指定了命名预设则分辨率、帧率与宽高比全部取自预设表(PROFILES定义见 core/project.py)。校验逻辑同样在 core/project.py:未知预设直接抛ValueError,宽高、FPS 分子分母、显示宽高比都必须为正数。project infoget_project_info汇总输出,包含 profile 的解析分辨率、实际 FPS(fps_num/fps_den)、以及 bin 片段数、轨道数、时间线片段数、转场与标记计数的统计。

Media Bin(素材箱)

bin import - 导入素材到素材箱 bin remove - 从素材箱删除素材 bin list - 列出素材箱全部素材 bin get - 获取单个素材详情

bin import--type取值为video / audio / image / color / title,对应 core/bin.py 的CLIP_TYPES。不给名字时自动由源文件 basename 派生;素材 ID 自动递增且名称自动去重(重复名称会被追加.001序号)。-d/--duration以秒计。

Timeline(时间线)

timeline add-track - 添加视频轨或音频轨 timeline remove-track - 删除轨道 timeline add-clip - 在轨道放置片段 timeline remove-clip - 从轨道移除片段 timeline trim - 裁剪片段的 in/out 点 timeline split - 在指定时刻拆分片段 timeline move - 移动片段到新位置 timeline list - 列出所有轨道

轨道类型由--type限制为video|audioadd-clip支持--position/-p--in--out(不传--out时按素材时长自动计算)。add-track还支持--mute/--hide/--locked三个布尔旗标,其中--locked的轨道会拒绝新增片段——这一行为有专门的单测覆盖(见 tests/TEST.md 中 TestTimeline 的 “Reject add to locked track”)。

Filters(滤镜/特效)

filter add - 给片段加滤镜/特效 filter remove - 删除滤镜 filter set - 修改滤镜参数 filter list - 列出片段上的滤镜 filter available - 列出全部可用滤镜

filter add需要track_id clip_index filter_name,参数通过多次-p key=value传入。CLI 层解析参数时会把含小数点字符串转 float、整数串转 int(见 kdenlive_cli.py 的filter_add);而 core/filters.py 的_validate_filter_params会对照注册表做类型转换、未知参数拒绝、数值范围钳制三重校验。filter set则按滤镜参数规格(float/int/str+min/max)校验后再写入。

Transitions(转场)

transition add - 在轨道间添加转场 transition remove - 删除转场 transition set - 设置转场参数 transition list - 列出全部转场

transition add参数为type track_a track_b,可选--position/-p--duration/-d--param。校验规则见 core/transitions.py:两条轨道必须存在且不能相同,position 非负、duration 为正,未知类型或未知参数均报错。

Guides(标记/参考线)

guide add - 添加标记 guide remove - 删除标记 guide list - 列出标记

guide add <position>支持--label/-l--typedefault|chapter|segment)与--comment/-c。标记在 JSON 中按 position 有序存储,导出时会转换为 MLT 的 guides 序列属性(见下文 XML 解析)。

Export(导出)

export xml - 生成 Kdenlive/MLT XML export presets - 列出可用渲染预设

渲染预设表定义在 core/export.py 的RENDER_PRESETS:包括h264_hqh264_fasth265_hqwebm_vp9proreslossless(FFV1/FLAC/mkv)、gifaudio_only(WAV)。每项携带 vcodec/acodec/码率/封装扩展名描述。这些预设是「面向 melt/ffmpeg 渲染管线」的元数据清单——CLI 负责生成 XML,实际转码由 melt 后端执行(utils/melt_backend.py)。

Session(会话:撤销/重做)

session status - 显示会话状态 session undo - 撤销最近一次操作 session redo - 重做最近一次被撤销的操作 session history - 显示撤销历史

有状态会话:快照式撤销/重做与原子落盘

Session 是整套 CLI 的状态中枢(core/session.py):

  • 每次变更前调用snapshot(description):对当前完整工程做copy.deepcopy压入撤销栈,并清空重做栈
  • 撤销/重做都是把整份工程对象在栈间搬运,历史深度上限MAX_UNDO = 50,超出时弹出最旧状态;
  • 落盘使用_locked_save_json:借助fcntl.flock对文件加排他锁实现原子化 JSON 写入(非 POSIX 平台静默降级为普通写入),避免并发 Agent 进程互相破坏工程文件;
  • 每条命令通过sess.snapshot("描述性文字")记录,session history可回放最近的修改轨迹,这使整条操作链具有可审计性。

底层所有变更都以描述 + 完整工程快照组织,因此撤销粒度是「一条 CLI 命令」而非单帧操作——这非常适合 Agent 在长流程中的试探与回退。E2E 测试也专门验证了“跨复杂编辑序列的 undo/redo”(见 tests/TEST.md)。

可用滤镜注册表

README 列出的可用滤镜清单在 core/filters.py 的FILTER_REGISTRY中有更完整的定义。每项滤镜都映射到真实 MLT service,并给出参数类型、默认值与合法范围:

滤镜名MLT service关键参数(默认值 / 范围)类别
brightnessbrightnesslevel: float (1.0 / 0.0–5.0)color
contrastbrightnesslevel: float (1.0 / 0.0–5.0)color
saturationavfilter.eqsaturation: float (1.0 / 0.0–3.0)color
blurboxblurhblur, vblur: int (2 / 0–100)effect
fade_in_videobrightness(kdenlive: fade_from_black)duration: float (1.0 / 0.01–60.0)transition
fade_out_videobrightness(kdenlive: fade_to_black)duration: float (1.0 / 0.01–60.0)transition
fade_in_audiovolume(kdenlive: fadein)duration: float (1.0 / 0.01–60.0)transition
fade_out_audiovolume(kdenlive: fadeout)duration: float (1.0 / 0.01–60.0)transition
volumevolumegain: float (1.0 / 0.0–10.0)audio
cropcropleft/right/top/bottom: int (0 / 0–9999)effect
rotateaffineangle: float (0.0 / -360.0–360.0)effect
speedtimewarpspeed: float (1.0 / 0.01–100.0)effect
chroma_keyfrei0r.select0rcolor: str (#00ff00);variance: float (0.15 / 0.0–1.0)keying

注册表为每个滤镜都配了mlt_service,且 fade 类滤镜额外声明了kdenlive_name,这保证了「CLI 中的命名」与「Kdenlive GUI 中的标准滤镜名」一一对应,导出的 XML 才能被 Kdenlive 正确识别。filter available -c <category>可按类别过滤查询。

视频预设(Profile)速查

PROFILES表(core/project.py)内置 11 个常用预设:

预设名分辨率帧率逐行宽高比
hd1080p30 / p25 / p24 / p601920×108030 / 25 / 24 / 6016:9
hd720p30 / p25 / p601280×72030 / 25 / 6016:9
4k30 / 4k603840×216030 / 6016:9
sd_ntsc720×48030000/1001(≈29.97)否(隔行)4:3
sd_pal720×57625否(隔行)4:3

值得注意的细节:sd_ntsc的帧率以fps_num=30000, fps_den=1001表达 NTSC 的 29.97,XML 生成会保留这一分数形式的帧率,避免逐帧累计误差。自定义工程则标记 profile name 为"custom"

JSON 工程格式:整条链路的单一事实源

工程的磁盘格式为.kdenlive-cli.json,结构如下(摘自 README,含注释说明):

{ "version": "1.0", "name": "my_video", "profile": { "name": "hd1080p30", "width": 1920, "height": 1080, "fps_num": 30, "fps_den": 1, "progressive": true, "dar_num": 16, "dar_den": 9 }, "bin": [ {"id": "clip0", "name": "Interview", "source": "/path/to/video.mp4", "duration": 120.5, "type": "video"} ], "tracks": [ {"id": 0, "name": "V1", "type": "video", "mute": false, "hide": false, "locked": false, "clips": [ {"clip_id": "clip0", "in": 0.0, "out": 30.0, "position": 0.0, "filters": []} ]} ], "transitions": [], "guides": [], "metadata": {} }

几个结构性要点:

  • profile同时承载分辨率、帧率、逐行/隔行、显示宽高比,是 XML 生成时计算像素宽高比(sample aspect)与帧数的依据;
  • bin中的素材使用自动生成的字符串 ID(clip0,clip1, …),import时若传入重复名称会自动编号去重;
  • tracks.clips只引用clip_id,片段级状态是position / in / out,其中in/out是从素材中取用的子区间(秒),position是片段在轨道上的起点;
  • 每个时间线片段自带filters数组,滤镜参数与 enabled 状态就地保存。

open_project在加载时会校验顶层versionprofile键存在,非法文件直接拒绝(见 core/project.py)。由于整份工程是一个纯 JSON 文档,它可以被 git 版本管理、被 Agent 做 diff、甚至被第三方脚本在命令行之外直接生成——这让「AI 规划剪辑 → 落 JSON → 出 XML」的自动化管线成为可能。

MLT XML 导出原理:从 JSON 到可播放文档

export xml调用 core/export.py 的generate_kdenlive_xml(),实际实现位于 utils/mlt_xml.py 的build_mlt_xml()。该函数生成的是Kdenlive Gen 5(doc version 1.1)兼容的 MLT XML,其构造逻辑值得细看:

  1. Profile 与像素宽高比换算:由dar(显示宽高比 16:9)与分辨率反推sar_num/dar_num*heightsar_den=dar_den*width,写入<profile sample_aspect_* display_aspect_* frame_rate_*>
  2. 素材编号映射:bin 中每个素材被分配从 4 递增的kdenlive:id_CLIP_KDENLIVE_ID_START=4),Sequence 固定为 id 3、素材文件夹固定为 id 2;
  3. 轨道排序:先把音频轨排在前面、视频轨排在后面(保证 Kdenlive 中视频显示在上层),并维护原始索引到序列索引的映射orig_to_seq
  4. 每轨三件套:每条轨道生成<chain>(每个唯一素材一个,携带kdenlive:clip_typemute_on_pauseeof=pause等属性)、双<playlist>(第一个放片段条目并按 position 间隙自动插入<blank><entry>内联滤镜),以及包裹它们的<tractor>
  5. 轨道可见性映射hide/mute/locked被映射为 tractor<track hide="both|video|audio">,音频轨默认补 3 个禁用滤镜(volume/panner/audiolevel),视频轨则依赖内置qtblend合成;
  6. Sequence 组装:生成带 UUID 的序列 tractor,写入大量kdenlive:sequenceproperties.*元数据(tracksCount、activeTrack、zonein/zoneout、zoom 等),guides 被序列化为 JSON 数组属性kdenlive:sequenceproperties.guides
  7. 内部转场与用户转场:每个音轨自动加mix过渡、每个视频轨自动加qtblend过渡(标记internal_added=237),用户通过transition add定义的转场(如 dissolve→luma)以a_track/b_track/in/out追加在序列上;dissolve/wipe/slide/composite/affine 的 MLT service 映射见 core/transitions.py;
  8. 素材箱与工程 tractor:文档末尾生成main_binplaylist(记录 docproperties 版本、uuid、当前激活序列)与作为melt播放起点的tractor_project

时间处理方面,utils/mlt_xml.py 同时提供两套换算:seconds_to_timecode/timecode_to_seconds(支持HH:MM:SS.mmm或直接秒数)以及seconds_to_frames/frames_to_seconds(按工程的 fps_num/fps_den 换算)。这也意味着所有命令的 position/out/in 均可用时间码字符串书写,CLI 层通过parse_time统一换算为秒。

生成的 XML 因此具备三个用途(README 原文):直接在 Kdenlive 中打开、交给melt命令行工具处理、以及嵌入更上层的自动化渲染管线继续加工。E2E 测试验证了该输出的健壮性:<mlt>根元素、profile 分辨率与 fps、producer 数量与 bin 素材数一致、滤镜/转场/标记属性存在、特殊字符被 XML 转义、SD PAL 产生正确 profile 值等(见 tests/TEST.md 的 TestXMLGeneration)。

时间线上的剪辑语义:trim / split / move

除增删外,时间线还提供三个贴近剪辑台的操作(实现在 core/timeline.py,测试覆盖见 TestTimeline):

  • trimtrack clip_index --in <新入点> --out <新出点>:只修改片段自身的in/out,不改动 position,用于收放头尾;
  • splittrack clip_index <split_at 秒>:在指定时刻把一个片段拆成两个子片段(原片段的 out 收束到 split 点,新片段从 split 点续接),拒绝在边界点或超出时长处拆分;
  • movetrack clip_index <new_position 秒>:整体平移片段的 position,负数位置被拒绝。

多次插入后片段会按 position 自动排序,这保证了后续 trim/split/filter 使用的「clip_index」始终与可视顺序一致——对于依赖索引寻址的 Agent 而言,稳定的排序语义至关重要。

交互式 REPL 与运行测试

REPL 模式

不带子命令直接运行即进入交互式 REPL:

python3 -m cli.kdenlive_cli repl # 或携带已有工程启动: python3 -m cli.kdenlive_cli repl --project project.json

REPL 由 kdenlive_cli.py 中的repl命令实现:内部通过shlex.split切分用户输入并递归调用同一个 Click CLIcli.main(args, standalone_mode=False)),因此 REPL 内可用命令与一次性命令完全一致,并借助 utils/repl_skin.py 提供横幅、提示符、help 与错误着色。REPL 模式下的异常不会导致进程退出(handle_error_repl_mode判断),适合人工交互式验证剪辑脚本。

测试体系

在 agent-harness 目录下运行:

# 全部测试 python3 -m pytest cli/tests/ -v # 仅单元测试 python3 -m pytest cli/tests/test_core.py -v # 仅 E2E 测试 python3 -m pytest cli/tests/test_full_e2e.py -v

按 tests/TEST.md 的清单,test_core.py含 8 个测试类共 118 个纯内存单测(不依赖 Kdenlive 安装),覆盖工程、素材箱、时间线、滤镜、转场、标记、时间码工具与会话;test_full_e2e.py含 3 个测试类共 33 个 E2E 用例,验证真实 MLT XML 生成、格式合规性与完整编辑工作流(多机位、音视频分轨、trim/split、滤镜链、转场、marker、undo/redo、全 profile 出 XML 等),实测汇总为151 passed in 0.18s。这套测试既是质量门禁,也为二次开发提供了现成的行为契约参照。

把 Kdenlive harness 接入 Agent 工作流的三种姿势

综合 README、源码与 SKILL 定义,可将该 harness 用于自动化剪辑的三条路径归纳如下:

  1. 一次性命令 +--json:每个操作一条命令,输出为 JSON,配合--project携带工程路径与退出时自动保存。适合 Agent「决策—执行—校验」的原子化步骤;
  2. 交互式 REPL:在一个长会话内连续输入多条命令,借助全局 session 的 undo/redo 与 history 随时回退试错,适合需要多轮尝试的复杂编排;
  3. 纯 JSON 管道:由于工程本身是纯 JSON,Agent 可先计算/规划整棵 JSON 结构,再一次性project open+export xml落盘——剪辑逻辑甚至可以脱离 CLI 单独构造,CLI 只是读写与导出的边界。

需要渲染成最终视频时,再将导出的 XML 交给 melt(utils/melt_backend.py)并按 core/export.py 的RENDER_PRESETS指定编码参数,即可形成「JSON 编辑 → XML → 渲染」的完整无头化视频生产链路。

小结

Kdenlive Agent Harness 的价值在于把视频剪辑还原为可编程、可状态化、可验证的工程操作:JSON 是唯一事实源,Session 提供快照式 undo/redo,build_mlt_xml负责把状态无损翻译成 Kdenlive/melt 都能消费的 MLT XML。阅读本文后,你可以沿着 README.md → kdenlive_cli.py → core/ → utils/mlt_xml.py → tests/ 的顺序继续深入,把这条无头剪辑管线接入你自己的 Agent 或批量渲染系统中。

【免费下载链接】CLI-Anything"CLI-Anything: Making ALL Software Agent-Native" -- CLI-Hub: https://clianything.cc/项目地址: https://gitcode.com/GitHub_Trending/cl/CLI-Anything

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询