| name | digital-human-video |
| description | 用抖音系服务(火山引擎·即梦AI)制作竖版短视频,两条路线:数字人口播(OmniHuman,对口型)与氛围画面配旁白(视频生成3.0 Pro,不对口型),动手前先选。先问清场景(给谁看/看完得到什么/要他做什么/片子类型),再定选题;输入=一段文本(主题或原始素材)+目标时长+人像或场景图;文案、生成的图片、分镜与成本表三处均须用户确认(成本确认可被用户常驻豁免),确认后才调计费 API 制作(TTS→数字人或视频生成→ffmpeg 竖版合成,含 AI 标识)。当用户要"做数字人视频/口播视频/宣传视频/AI 生成视频"时使用。首次使用前须先跑 digital-human-video-init 配置密钥。 |
数字人口播视频 · 制作
⓪ 先问场景(硬门,不问清不动手)
2026-08-02 教训:跳过这一步做出来的片子「非常没有意思」。 当时用户给了一份现成的数据稿,
技能直接照做,产出一条讲「我们跑了 45 道题、某引擎提了我们 22 次」的片子——数据全对、合规全过、
观众毫无理由看完。根因是拿内容源当需求用:有人给一段文本,不等于这段文本适合做成这条片子。
动手前必须问到下面四件,缺哪件问哪件,不许替用户假设:
- 给谁看——目标观众是谁、他们此刻的处境是什么。写「中小企业市场负责人,老板问他品牌在 AI 里
排第几,他答不上来」这种具体的人,不写「潜在客户」。
- 看完得到什么——观众能带走的一件事:学会一个判断方法 / 看懂一个现象 / 避开一个坑。
如果答不出观众能带走什么,这条片子不该做。
- 要他做什么(转化目标)——看完去哪、怎么承接(关注公众号 / 私信关键词 / 官网 / 什么都不做只求曝光)。
- 片子类型——干货科普 / 现象观察 / 案例拆解 / 观点表达 / 产品演示。
这四问是给一个账号/一个系列定调的,定过一次就不必每条重问;后续每条片子只按下面「输入」那两样收料即可。
引流片 ≠ 推广片(最常见的一次性搞砸)
| 引流片 | 推广片 |
|---|
| 主角 | 观众的问题 | 我们的产品 |
| 数据的用法 | 当论据支撑一个观众关心的判断 | 当成绩陈列 |
| 观众的收获 | 学到能自己用的东西 | 知道了有这么个产品 |
| 适用场景 | 冷启动、涨粉、公域引流 | 已有信任的私域、落地页、发布会 |
默认按引流片写。 用户明确说「做产品介绍/发布」才写推广片。
自查一句:把品牌名全部抹掉,这条片子还有人看吗? 没有 → 是推广片,回炉。
输入(每条片子固定收两样,缺一不做)
① 文案
口播全文,或要点(由本技能改写成口播稿)。时长由文案长度决定:每 13 秒 ≈ 65 汉字。
⚠️ 文案完整性优先于时长——不得为了凑短而删内容(2026-08-03 用户明确要求)。
15 秒是 OmniHuman 单次调用的上限,不是成片的上限:超了就按语义拆成多段、逐段生成、
拼接成一条完整片子。硬压文案会把信息压没——把「五种角色各自是干什么的」压成五个光秃秃的
名词,观众记不住也听不懂,等于白做。
⚠️ 文案是素材不是需求:若 ⓪ 尚未定过调,先问完再动笔。常见情形是用户手边只有一份
内部数据稿,而它并不适合直接做片子——此时据 ⓪ 另提选题给用户选,不要照着硬做。
② 一张图
这张图同时决定成片里的「人」和「背景」——OmniHuman 只接收图 + 音频,没有任何场景
提示词参数(2026-08 核实)。所以图什么样,成片就什么样。
要求:单人、正脸、人脸占比大,JPG/PNG <5MB <4096²(sips -g pixelWidth -g pixelHeight 核验);
竖版 9:16 最省事(横图会按原比例出片,与竖版成片不匹配)。
肖像须已获本人授权(或为 AI 合成形象);用户主动提供并指示用于本片,即视为授权,如实记档,
不必反复追问。
这张图从哪来(按优先级):
| 来源 | 何时用 | 注意 |
|---|
| 实拍照片 | 车里、办公室、家里这类随手能拍的场景 | 首选。真脸真光真环境,零 AI 味、零肖像争议;五分钟拍三五张够用很久 |
| 用户自备的生成图 | 用户自己做好了图 | 直接用,不必追问怎么来的 |
gen_scene.py 图生图 | 拍不到、又要人物在场景里 | 见下方「进阶」的实测结论 |
gen_scene.py 文生图 + make_portrait.sh 合成 | 拍不到的场景,且必须保住真脸 | 脸 100% 不动,代价是可能有贴纸感 |
前置:配置文件 ~/.config/zmh-dhv/env 存在(所有脚本自动读取);不存在则引导用户先跑 digital-human-video-init。
进阶:自己做输入图(拍不到的场景才用)
两个脚本,都在 scripts/:
python3 scripts/gen_scene.py --prompt "汽车驾驶座,暖色车内,窗外街景虚化" --out scene.png
python3 scripts/gen_scene.py --image <人像公网URL> --prompt "同一个人坐在驾驶座上" --strength 0.45 --out shot.png
scripts/make_portrait.sh green <绿幕人像> scene.png out.png [相似度] [羽化]
scripts/make_portrait.sh check out.png
2026-08-02 实测结论,别重复踩:
- 提示词里不要写「留出人物站位」这类话——模型会照办,直接画一个灰色人形占位块。
空镜就老实写「空镜,画面中没有人」。
- 图生图
strength=0.45 时人脸已被换掉:发色改变、脸型削瘦、五官磨皮成通用 AI 脸,
另有手部结构错误与过曝高光。用户一眼判「很假」。降到 0.25~0.3 能多保住脸,但融合变差,
容易变成「证件照硬贴进场景」的另一种假。
- 因此:本人出镜的片子优先实拍。生成图的用武之地是拍不到的场景(演播室、机房、
发布会背景板),以及封面配图这类不涉及本人真实呈现的素材。
- 若仍要用生成图做本人出镜:必须把图交给本人确认「这还是我」,不确认不进 OmniHuman。
两条产出路线(动手前先选,选错整条片子废)
技能有两个互不相通的引擎,区别只有一条,但它决定整条片子的形态:
| 数字人 OmniHuman | 视频生成 3.0 Pro |
|---|
| 脚本 | jimeng_dh.py | jimeng_video.py |
| req_key | jimeng_realman_avatar_picture_omni_v15 | jimeng_ti2v_v30_pro |
| 接口 | CVSubmitTask / CVGetResult | CVSync2AsyncSubmitTask / CVSync2AsyncGetResult |
| 对不对口型 | 对 | 不对 |
| 片子形态 | 真人口播(人在说话) | 氛围画面配画外音 |
| 输入图要求 | 正面、匀光、简背景、嘴部无遮挡(极严) | 宽松,侧脸暗调都能出 |
| 输出画幅 | 不固定:见过 480P 小画幅,也见过 1088x1920 整幅 | 1088x1920(注意不是 1080) |
| 单段长度 | 跟音频走 | frames 121≈5s / 241≈10s |
| segments.txt 类型 | dh | clip |
别搞混:拿 jimeng_video.py 做口播,会得到「人在动、嘴不动、声音在念」的诡异片子。
要嘴型对得上只有 OmniHuman 一条路。
数字人的输出画幅不固定,合成前必须探
同一个 jimeng_realman_avatar_picture_omni_v15,2026-08-02 回的是 480P 小画幅,
2026-08-04 回的是 1088x1920 整幅。compose.sh 的 dh 分支原先写死「缩到画面上部、
下方留字幕区」,拿整幅素材跑会把画面往下推 200px 再裁掉底部。
现已改为按 ffprobe 探到的实际高度分流(≥1600 视为整幅,走铺满裁切;否则走上部留白)。
教训:输出画幅是服务端的事,不是我们能假设的常量。 任何「XX 一定是 480P」这类
写死的画幅假设,都该换成一次 ffprobe。
数字人段合成时用 - 走 mp4 自带音轨,不要外挂原始 wav:OmniHuman 的输出会比
源音频长 0.04~0.18 秒(收尾帧对齐),外挂 wav 有让口型与声音错位的风险,
自带音轨则严格同源。
视频生成的两条实测纪律
- 每段都锚回同一张原图,不要拿上一段的末帧接龙(2026-08-04 实测踩到)。
接龙的本意是接成一条连续镜头,实际上 ti2v 每次都是拿首帧重新合成人脸与场景,
误差逐代累积:第 2 代人物转身只剩后脑勺,第 3 代换了张脸,第 4 代连街景都从
红霓虹漂成绿路灯。七段下来是七个人物不一致的镜头,不是一条镜头。
正确做法:每段首帧都用同一张原图,靠
--prompt 里的运镜描述做出差异,
靠 --seed 固定可复现。宁可少切几刀——frames 241(10 秒)出 4 段,
比 frames 121(5 秒)出 7 段剪切点少一半,脸也更稳。
- 提示词写运镜和动态,不写画面内容。内容已经由首帧图决定了,再描述一遍只会打架。
写「镜头极缓慢推近,人物轻微呼吸与眨眼,背景霓虹光斑流动」,
不写「一个女性站在雨夜街头」。结尾固定加「电影感,人物面容保持一致,画面稳定不变形」。
req_key 备胎(某一个额度用尽时直接顶上)
即梦的视频能力是按 req_key 分别计额度的,一个用尽不影响另一个。实测可互换:
| req_key | 名义 | 实测 | 规格 |
|---|
jimeng_ti2v_v30_pro | 3.0 Pro 图文生视频 | 吃 image_urls | 1088x1920,241帧=10.04s |
jimeng_t2v_v30_1080p | 3.0 1080P 文生视频 | 同样吃 image_urls | 与上完全一致 |
名字里的 t2v 不代表它不收图(2026-08-04 实测:3.0 Pro 额度耗尽后,同样的
image_urls + frames + aspect_ratio 原样换到 jimeng_t2v_v30_1080p,
两段都一次出成,参数一个字没改)。所以出片脚本应当按 req_key 列表依次退避,
而不是撞到 50400 就停下来问用户充值:
for RK in jimeng_t2v_v30_1080p jimeng_ti2v_v30_pro jimeng_i2v_first_tail_v30; do
python3 scripts/jimeng_video.py --req-key "$RK" ... && break
done
零成本判断某个 key 还能不能用:拿假 task_id 打 CVSync2AsyncGetResult,
50400 = 该 key 不可用(额度尽或未开通),50500 = 可用(查不到假任务而已),
50200 = 名字不存在。注意这里 50500 反而是好消息,与直觉相反。
已知瞬时错误
50220 Download Url Error — 即梦服务端拉不到我们图床上的首帧图(connection reset)。
不是参数错,重试即可,别去改 URL 或重传图片。批量出片时要能单段补跑。
50400 Access Denied: api forbidden — 这个码有歧义,别一看到就断定「没开通」。
2026-08-04 实测:同一个 jimeng_ti2v_v30_pro,同一批里第 1、3 段成功、第 2、4 段回 50400。
能力显然是开通的,所以此处的 50400 是限流或额度耗尽,不是权限。
判别法:这个 req_key 在本次会话里成功过吗?
成功过 → 限流/额度,隔开重试,别去动权限和 IAM;
从没成功过 → 才考虑是能力未开通(此时再用别的已开通 key 做对照探针)。
批量出片必须能单段补跑:一批里失败几段是常态(上面两个码都会随机命中),
脚本要按段落文件名判断哪些缺失、只补缺的那几段,不能整批重来——重来等于把
成功的那几段再花一次钱。
流程(严格按序,三道确认门)
① 生成视频脚本(不花钱)
前提:⓪ 四问已答完。 未答完不进本步——照着一段现成文本硬写,产出的必然是「数据都对但没人想看」的片子。
开篇 3 秒决定完播率,写之前先定钩子。可用的三种(都不要以「大家好」「今天跟大家聊聊」开场):
- 反常识:「AI 说错一个产品的价格时,它不会说不知道,它会编一张完整的价目表。」
- 具体处境:「老板问你品牌在豆包里排第几,你答得上来吗?」
- 可验证的动作:「教你十分钟自己查一遍,不用买任何工具。」
首尾两段必须是人脸(2026-08-10 用户定的硬规则)
片子的第一段和最后一段一律用数字人,中间可以用图卡。
理由是两端承担的功能不同,都撑不住静态卡:
- 第一段决定留不留人。留存曲线显示前 7 秒流失 86%,而人脸是短视频里最强的注意力钩子。
开头放一张静态卡等于把最贵的 7 秒交给了最弱的画面。
- 最后一段决定行不行动。CTA 由一个人说出来,和由一张卡片写出来,说服力不是一回事。
顺带解决一个听感问题:同一段 TTS 配「会动的嘴」和配「静态卡」,听起来是不一样的。
2026-08-10 实测——用户反馈第 3 条「语音跟前两条不一样」,而字节级比对证明 TTS 完全相同
(同一句话两次生成 md5 一致)。差异来自两处:① 该片满是英文专有名词,中文 TTS 读英文韵律不同;
② 全片无人脸。视听整合会改变听感,这不是错觉。所以首尾配人脸也是在稳听感。
开场:唯一有实测数据的一条(2026-08-10 首条成片回流)
第一条片子发出后拿到了真实留存曲线,结论比任何经验之谈都硬:
0s 100% → 7s ≈14% → 14s ≈10% → 21s ≈8% → 28s ≈5% → 35s ≈0
前 7 秒流失 86%,7 秒之后近似平线。(片长 36.5s,完播率 7.13%,平均播放 10.06s)
三条可直接照用的推论:
- 一条片子的成败几乎全在前 7 秒。中后段做什么都影响不到大多数人——
那条片子 9 秒处才切出精心画的框架图,而那时观众只剩 14%,绝大多数人根本没看到。
所以:先把开场做对,再谈结构。
- 别把需要背景知识的专有名词放开头。原开场第一句是「Anthropic 很多团队九成以上的代码」,
对不认识 Anthropic 的人,前 3 秒等于没有信息——而前 3 秒正是决定划走的窗口。
- 别在开场把结论说完。原开场以「这套分法过时了」收尾,观众信息到手即可离开。
改法(同一内容只换开头的示范):
原:「Anthropic 很多团队九成以上的代码,已经是 AI 写的。Claude Code 之父说,
正因为人人都能写代码,前端、后端、产品、设计这套分法过时了。」
改:「写代码这件事,正在从『会不会』变成『还要不要人写』。九成——这是 Anthropic 内部
现在由 AI 写出的代码比例。他们团队因此重新分了工,分成五种人,其中一种现在特别抢手。」
三处变化:数字前置(第 3 秒就砸出具体数字)、留悬念(不说是哪一种)、
开头不放需要背景知识的专有名词。
⚠️ 这条数据只来自 1 条片子,是信号不是定律。 但它推翻了我们自己此前的一个推断
(曾从「完播率+平均时长」两个聚合数推出「观众在切图表处流失」,曲线证明是错的),
所以:能拿到留存曲线时,永远不要用聚合数去推流失点。
⚠️ 「改开场」这个变量单独测不出来:同一账号不能把同一条内容发两遍,
新开场必然伴随新选题。留存若改善,无法区分是开场还是选题的功劳。
交付时要如实说明这一点,不要包装成对照实验。
按输入文本与时长产出分镜脚本,格式:
- 分镜表:段号 | 形态(数字人/图卡) | 口播文案(每段 ≤65 字) | 预计秒数 | 预计成本
- 成本优化默认形态:数字人只出镜开场与收尾,中段用零成本数据图卡;用户点名全程数字人则照做并重报成本
- 图卡文案(如有)
- 合计:总时长、总成本(数字人段秒数合计 × 1 元 + TTS<1 元)
长文案的拆段规则(超 15 秒时按此拆,不许删内容):
-
按语义拆,不按字数硬切:一个完整意思落在一段里;拆在句号处,绝不在半句或词中间断开。
-
每段 ≤65 汉字(约 13~14 秒 @1.0x 语速),留出余量——TTS 实际时长会因语速与标点浮动,
顶着 15 秒写容易超。写完用 tts.py 实测,以实测秒数为准,不用估的。
注意语速会改变字数与秒数的换算:TTS_RATE=+50%(1.5 倍速)时,同样 65 字只要约 9 秒,
单段可以放到约 95 字。永远以 tts.py 报的实测秒数为准,别按字数硬套。
-
拆完先自检衔接:逐段连读一遍,段与段之间不能出现「话说一半」。compose.sh 是
concat -c copy 直接拼接,段间没有过渡也没有留白,是硬切——所以每段的收尾要是一个
可以停顿的位置。
-
成本按总秒数线性算:数字人 1 元/秒,拆成 3 段 45 秒就是 ¥45,不因为分段而变便宜。
成本表必须报总时长与总金额,不能只报单段。
-
中段若可以用图卡承载(数据、清单、对比),优先用图卡——零成本,且清单类信息看比听记得住。
有先后/层级关系的内容,用 make_diagram.py 画框架图,别用 make_card.sh 罗列文字:
五个角色摆成五行字,观众只看到一张清单;画成「想法→产品→规模」的链路加两个贯穿角色,
观众看到的是一个结构。同一张框架图分段 --highlight 不同节点,能让观众跟着讲解
一步步建立心智模型,比每段换一张不相干的卡有效得多。
⚠️ 画框架图不等于可以重排用户给的内容(2026-08-03 实测踩到):用户给了五个角色的
有序清单,技能自作主张拆成「主链 + 贯穿全程」两组,把第 3 位的「维护者」挪到了第 4 位
「扩展者」后面——顺序错了,而且那个分组是技能凭空发明的、原文里没有。
规则:结构可以可视化,顺序与语义不能改。 原文是有序列表就照序画成链;要提出别的
组织方式,先在门 A 连同文案一起报给用户,由用户定,不许直接落到图上。
框架图一律用代码画,不要用 AI 生成图:AI 生成图里的中文几乎必错(缺笔画、造字、
串行),而框架图的信息全在文字上,错一个字整张图就废。代码画的字 100% 可控、可复现,
改词重画成本为零。AI 生成图适合做底纹与氛围,不适合承载文字信息。
语速:由配置项 TTS_RATE 控制(edge-tts 的百分比增量,+0%=1.0x、+50%=1.5x;
豆包与 macOS say 兜底会自动换算成各自的倍率)。短视频平台上 1.5 倍速通常比常速更抓人。
⚠️ 语速只能在 TTS 阶段调,绝不能在成片上加速:数字人口型由音频驱动,成片加速会把口型
一起拉快、看着像快放;而 TTS 按目标语速合成时,口型天然就是那个节奏。
⚠️ 改语速 = 音频变了 = 数字人段必须重新生成(重新计费)。所以语速要在门 A 确认文案时
一并定下来,别等成片出来再改。
文案红线(违反即返工):不承诺"保证收录/霸屏/快速见效";数字可溯源且带口径限定;竞品不贬损;结尾引导语统一取配置项 BRAND_CTA(grep '^BRAND_CTA=' ~/.config/zmh-dhv/env),未配置则问用户要一句、用户说不加就不加,不得自行编造品牌名或引导语;若文本涉敏感词风险(品牌名密集)在脚本下方注明 50413 备选改法。
确认门 A:文案(硬门)
口播稿写完先给用户看,拿到确认才继续。 给的时候连这几项一起报:全文、分段、每段字数与预计秒数、
钩子是哪句。用户改就改完再确认一次。
为什么单独设这道门:文案是整条片子的地基,改文案要重配音、重生成数字人段——在这里改是零成本,
到成片再改是重新烧钱。
确认门 B:图片(硬门,仅当图由我们生成时)
凡是我们生成的图(文生图/图生图/合成图),一律先发给用户看,拿到确认才往下走。 不确认不上传、
不进 OmniHuman。
- 本人出镜的片子,确认的问题是「这还是你吗」,不是「好不好看」。2026-08-02 实测:图生图
strength=0.45 就已经换脸(发色、脸型、五官全变),用户一眼判「很假」。这种图拿去驱动口型,
等于用一张不是本人的脸对外说话。
- 用户自带的图跳过本门(他自己给的,不必替他审)。
- 确认时一并报清楚:图从哪来(实拍/文生图/图生图/合成)、用了什么提示词与参数——用户要复现或
微调时用得上。
确认门 C:分镜与成本(硬门,可被用户常驻豁免)
本工作区现行豁免(2026-08-04,用户明示):「后续确认好文案后直接生成,不需要确认视频了」。
即门 A 通过后,门 C 视为已授权,可直接带 --confirmed 出片,不必逐段回来问成本。
边界:豁免的是成本确认,不豁免门 A(文案)与门 B(图片);换账号、换计费方式、
或单次量级明显超出既往(例如从几十秒跳到几分钟)时,仍要回来报一次。
用户说「停一下/先别花钱」即刻失效。
无豁免时:把完整分镜脚本 + 成本表报给用户,明确拿到"确认/开做"才进入 ③。用户改稿则改后再确认。
未确认不得调用 CVSubmitTask / CVSync2AsyncSubmitTask(这两个是仅有的计费接口)。
这道门有机器闸兜底:jimeng_dh.py / jimeng_video.py 不带 --confirmed 会直接拒绝提交,
并打印本段的时长与预估。纪律会漏,闸门不会。
有常驻豁免时 --confirmed 才是默认可带的;没有豁免时它应当是「已拿到用户确认」的证据,
不是一个固定参数。
③ 制作(开始花钱)
cd "${CLAUDE_PLUGIN_ROOT}/skills/digital-human-video"
python3 scripts/tts.py --script <确认稿.md> --outdir work/<项目名>/audio
scripts/make_card.sh work/<项目名>/card1.png "标题" "行1|行2|行3" "脚注"
python3 scripts/make_diagram.py --out work/<项目名>/diag.png --title "五种角色" \
--chain "原型师|抓住第一个想法" "构建者|做成产品" "扩展者|放大十倍" \
--side "维护者|守住它" "收尾人|打磨" --stage "想法" "产品" "规模" --highlight 0 1
scripts/upload_asset.sh <人像图> work/<项目名>/audio/seg_01.wav ...
python3 scripts/jimeng_dh.py --image <图URL> --audio <段URL> --out work/<项目名>/dh_XX.mp4 --confirmed
python3 scripts/jimeng_video.py --image <同一张图URL> --prompt "<运镜与动态描述>" \
--frames 241 --aspect-ratio 9:16 --seed <固定值> --out work/<项目名>/clip_XX.mp4 --confirmed
scripts/compose.sh work/<项目名> work/<项目名>/成品.mp4
- 音频每段必须 ≤15 秒(超了回 ① 按语义拆段,不是删文案);video_url 1 小时有效,脚本已即时下载。
- 数字人段生成失败:5041x/5051x=审核不过(按脚本备选改法换词重来,只重做失败段)、50429/50430=限流退避、50500/50501=可重试。
- 制作完把服务器上的临时素材删掉(尤其人像图):
ssh $ZMH_ASSET_SSH rm ...。
④ 交付与归档
- 给用户成片路径 + 实际总成本(按各段产出秒数合计)+ 生成耗时;
- 显式「视频由 AI 制作」角标已由 compose.sh 烧录,jimeng_dh.py 输出 aigc_meta_tagged=true 才算隐式标识成功——两者缺一在交付时明示;
- 运营用途的片子:成片信息按所在工作区的归档约定记档(有台账则记入当期档);提醒发布时在平台侧勾选 AI 生成声明;发布一律人工,不在本技能内。
背景音乐(可选,但只能用自己合成的)
永远不要给成片配一首现成的曲子。 受版权保护的音乐发到公开平台就是侵权,平台的
版权识别还会给视频打标记直接限流——法律和流量两头都是硬伤。素材站上标「免费下载」的,
多半只是免费试听,授权条款经常不许商用或要求署名,逐条核实的成本比自己合成还高。
make_bgm.py 纯代码合成,每个采样点都是现算的,可商用、可修改、无需署名、零成本:
python3 scripts/make_bgm.py --out work/<项目名>/bgm.wav --seconds 33 --mood calm
混音:默认恒定音量,不要侧链闪避
侧链闪避(人一说话音乐自动下潜)在广播里是标准做法,但在短视频里听感是「音乐忽大忽小」,
用户会直接抱怨(2026-08-04 实测)。短视频只有几十秒、人声几乎不停,闪避不断触发与释放,
观众听到的就是一层不停呼吸的底噪。默认不用闪避,选一个从头到尾压得住的恒定音量。
两遍 loudnorm,第二遍必须 linear=true——单遍 loudnorm 本身是动态的,
即使去掉了侧链,它也会自己把音乐泵起来又压下去。「忽大忽小」有这两个来源,
只去掉侧链是修不干净的。
ffmpeg -i 成片.mp4 -i bgm.wav -filter_complex \
"[1:a]volume=0.09[m];[0:a][m]amix=inputs=2:normalize=0:duration=first[a]" \
-map "[a]" -c:a pcm_s16le mix_raw.wav
ffmpeg -i mix_raw.wav -af loudnorm=I=-14:TP=-1.5:LRA=11:print_format=json -f null -
ffmpeg -y -i 成片.mp4 -i bgm.wav -filter_complex "
[1:a]volume=0.09[m];[0:a][m]amix=inputs=2:normalize=0:duration=first[mx];
[mx]loudnorm=I=-14:TP=-1.5:LRA=11:linear=true:measured_I=<I>:measured_TP=<TP>:measured_LRA=<LRA>:measured_thresh=<TH>[a]" \
-map 0:v -map "[a]" -c:v copy -c:a aac -b:a 192k -shortest 成片-配乐.mp4
normalize=0 必带,否则 amix 会把总音量砍半
loudnorm=I=-14 是社交平台的通行响度,不做的话在信息流里会明显比别人小声
- 验收:量音乐层逐秒电平的标准差,σ<4 dB 才算平稳;残余波动应能归因到曲子本身
调平必须量 1~4kHz,不能量全频段(这条最容易错)
2026-08-04 实测:全频段 RMS 显示音乐「低于人声 8.8 dB」,数字很合理,
用户在手机上完全听不见。逐频段拆开才看到真相:
| 频段 | 音乐 vs 人声 | 手机能不能放 |
|---|
| 20~150 Hz | +27.9 dB | 放不出 |
| 150~400 Hz | +8.3 dB | 很弱 |
| 400~1200 Hz | −3.3 dB | 勉强 |
| 1200~4000 Hz | −19.7 dB | 手机最响、人耳最敏感 |
| 4000~8000 Hz | −33.7 dB | 空 |
音乐能量几乎全堆在手机放不出的低频,把全频段 RMS 撑得很好看,而真正决定
「听不听得见」的 1~4kHz 是空的。手机喇叭在 1~4kHz 效率最高,人耳也在这一带最敏感。
所以调平只看 1~4kHz 这一段的音乐/人声差值:
| 位置 | 1~4kHz 音乐应低于人声 |
|---|
| 人声停顿处 | 6~10 dB |
| 人声最响处 | 14~18 dB |
def band_db(x, lo, hi, SR):
X = np.fft.rfft(x); f = np.fft.rfftfreq(len(x), 1/SR); m = (f >= lo) & (f < hi)
return 20*np.log10(max(np.sqrt((np.abs(X[m])**2).sum()/len(x)), 1e-9))
配乐若是外来成品,选曲时就该挑有中高频内容的(钢琴、吉他分解、铃音、轻打击);
纯低频 pad 或纯氛围垫在手机上必然消失,再怎么调音量也救不回来。
另一个测量陷阱:不要拿「混音后 vs 原音轨」去测侧链闪避。音乐在总和里占比很小,
压不压都测不出差别,会误判成「侧链没工作」。必须把音乐支路单独渲出来与人声逐秒比对。
⚠️ zsh 陷阱:本机默认 shell 是 zsh,$2:ratio= 里的 :r、:a 会被当成参数修饰符
(:r 去扩展名、:a 转绝对路径),把滤镜串吃坏且报错难懂。滤镜里引用位置参数一律写
${2} 带花括号。
结尾引流卡(CTA)
引流片结尾加一张 CTA 卡,配音 + 图卡 + 字幕三处同时给出同一句话。
配音要补静音:TTS 念一句短 CTA 只要 2 秒左右,卡片跟着只停留 2 秒——观众来不及看清、
更来不及去评论。补静音到 3.5~4 秒再进合成:
ffmpeg -y -i cta.wav -af "apad=pad_dur=1.65" -t 3.6 cta_padded.wav
照用户原话渲染,不要替他改写措辞。 CTA 是转化环节,用词是用户的决定。
短标题与描述(发布必备,与成片、封面一起交付)
成片不是交付物的全部。 一条片子要发出去,至少需要四样:成片、封面、短标题、描述。
少任何一样,用户都得自己现编——而临场编出来的东西不会被记进台账,复盘时说不清用的是哪版。
短标题(6~16 字)
平台用它做搜索与话题聚合。规则:
- 把片子最硬的那个具体事实塞进去,别写概括性的标题。
「九成代码已经是AI写的」优于「聊聊 AI 写代码」;「数据全在小王微信里」优于「企业为什么用不好 AI」。
- 不重复封面上的字。封面和短标题在信息流里同时出现,写一样等于浪费一个位置。
描述
体例固定四段,按序:
- 钩子句 —— 通常就是口播稿的第一句。信息流会截断,第一行决定展不展开。
- 内容要点 —— 把片子的骨架用文字再给一遍。这不是冗余:很多人静音刷,
描述是他们唯一能读到的完整内容;而且文字内容会被平台索引。
- CTA —— 必须与片尾口播一致。片尾说 A、描述写 B,观众会困惑该做哪个。
- 话题标签 3~5 个 —— 多了会被判堆砌,少了进不了话题池。
置顶评论(有归因需求时必备)
置顶评论不是描述的重复,它有两个职责:
- 承载归因链接(带参 URL,让服务器日志能识别来源)
- 补一件片子里没说的事
第 2 条才是关键。 只放链接的置顶评论没人点开,链接也就白放了。
必须给一个「片子看完了还值得看这条评论」的理由。
好用的三种补法(2026-08 三条片子各用了一种):
| 补法 | 例子 |
|---|
| 解释片中一个没展开的概念 | 片尾 CTA 提到一个术语,正文没解释——评论区补上,顺带把断裂变成钩子 |
| 把片中的一个自测题扩成一份清单 | 片里给 1 个问题,评论区给 3 个,成为可直接拿去用的自查表 |
| 补核实时读到、但片长放不下的内容 | 核实第三方事实时官方页里的次要事实,片子放不下,正好填评论区 |
最后一种最省力:核实本来就要做,副产品直接就是评论区的料。
写完存台账,与描述放在一起,发布后原样粘贴。
三条硬规矩
- 引用第三方事实必须标来源,并且发布前自己核实过。
2026-08-10 实测:用户给的一条 AI 资讯,核实后发现基本属实,
但官方页里有一层用户那份没提(检测工具尚未公开),那一层反而成了片子最值钱的落点。
核实不只是防错,还常常能捡到别人没说的东西。
- 引流片的描述里不出现自有产品名、不写任何效果承诺。判断标准与片子本身一致:
把品牌名全部抹掉,这段描述还有人愿意读完吗?
- 描述定稿后原样存进台账,发布时复制粘贴,不临场改。改了就和登记的对不上。
封面(发布必备,与成片一起交付)
make_cover.py 从原图或成片抽帧加大字钩子,输出 1080x1440(视频号封面比例)。
python3 scripts/make_cover.py --image 原图.png --out cover.png --anchor 0.78 \
--tag "Anthropic 内部" --line "九成代码" --line "已经是 AI 写的"
封面是在缩略图尺寸下被看到的,一切取舍由此而来:字要极大、一行 ≤8 字、
最多两行、深底金/白字加深色描边。写满一句话在信息流里就是一团灰。
三条实测纪律(2026-08-04 都踩过):
- 用原图,不要从成片抽帧 —— 成片有烧录字幕和 AI 角标,会一起被抠进封面。
- 文字不能压在脸上。人脸是封面最大的注意力钩子,压掉它等于自废武功。
人像片子把文字放在胸口/大衣区域(
--anchor 0.78)或头顶上方(--anchor 0.15),
出图后一定要看一眼——脚本不知道脸在哪,--anchor 是人来定的。
- 钩子里要有具体数字。「九成代码已经是 AI 写的」止得住手指,
「分成了五种角色」缺主语、单看封面不知道在说谁。
成片验收(合成完必做,不做不交付)
抽帧看全画幅,每个分镜至少一帧。 不是看素材图、不是看日志——素材单看都是好的,
毛病全出在叠加之后:字幕条是 45% 半透明黑,压住图上的字不是遮掉,是透出一层鬼影。
for t in 4 14 22 29; do ffmpeg -y -loglevel error -ss $t -i 成片.mp4 -frames:v 1 -vf scale=380:-1 f_$t.png; done
ffmpeg -y -loglevel error -i f_4.png -i f_14.png -i f_22.png -i f_29.png -filter_complex "[0][1][2][3]hstack=inputs=4" grid.png
逐条看:① 图上有没有内容被字幕条压住 ② 字幕有没有标点落行首 ③ 词有没有被拦腰断开
④ 角标在不在 ⑤ 图里的顺序/措辞与口播稿是否逐项一致(第 ⑤ 条最容易漏,因为图本身好看)。
2026-08-03 实测:同一条片子连交两次都带着「出处小字透在字幕里」,原因就是只看了
框架图 PNG、没看合成后的帧。素材没问题 ≠ 成片没问题。
计费事实(2026-07 文档口径,报价前可复核控制台)
数字人快速模式 1 元/秒(480P,并发 1);即梦视频生成3.0 若用作 B-roll:720P 0.28 元/秒。只有调用成功才计费。
技术路线
数字人与视频生成统一走抖音系服务(火山引擎·即梦AI API),需企业认证账号并在控制台开通「数字人快速模式」。本技能产片定位为实验/宣传用途,成片是否用于正式投放由使用方另行决定。