diff --git a/video-ai-system/CURRENT.hdlp b/video-ai-system/CURRENT.hdlp index 967ef5b..2635037 100644 --- a/video-ai-system/CURRENT.hdlp +++ b/video-ai-system/CURRENT.hdlp @@ -128,6 +128,7 @@ JZAO外置盘: 产物存放地,不是状态主控。 | 牌匾固定贴图 | ✅ PNG已生成 | `video-ai-system/assets/props/PROP-TDZ-PLAQUE/texture/tdz-plaque-texture.png` | | 字幕渲染合成 | ✅ 粗白短剧样式RUN-004通过 | `video-ai-system/outputs/tests/TEST-SUBTITLE-004-SHORT-DRAMA-BOLD-REPORT.hdlp` | | 字幕样式标准 | ✅ 已建立 | `video-ai-system/knowledge/SUBTITLE-STYLE-STANDARD.hdlp` | +| 商用字幕工具链 | 🟡 待开发 | `video-ai-system/plans/D144-SUBTITLE-PRODUCTION-TOOLCHAIN.hdlp` | | 百宗会人群底片 | 🟡 RUN-002可作氛围候选 | `video-ai-system/outputs/tests/TEST-PROP-001-TDZ-PLAQUE-RUN-002-REPORT.hdlp` | | 苏白TTS配音 | ✅ 工程测试通过 | `video-ai-system/outputs/tests/TEST-TTS-001-SUBAI-RUN-001-REPORT.hdlp` | | 模型/成本路线 | ✅ 已建立 | `video-ai-system/knowledge/D144-MODEL-COST-ROUTE.hdlp` | diff --git a/video-ai-system/engines/subtitle-renderer.py b/video-ai-system/engines/subtitle-renderer.py index a8c9d38..b04be77 100644 --- a/video-ai-system/engines/subtitle-renderer.py +++ b/video-ai-system/engines/subtitle-renderer.py @@ -27,7 +27,7 @@ Subtitle Renderer · 字幕渲染引擎 字幕样式配置: --font-size : 字体大小(默认 36) --font-color : 字体颜色(默认 white) - --style : 字幕样式(short-drama-bold / clean-white / black-box,默认 short-drama-bold) + --style : 字幕样式(reference-drama / short-drama-bold / clean-white / black-box,默认 reference-drama) --position : 位置(top / middle / bottom,默认 bottom) --margin-bottom : 底部边距(默认 100px) @@ -60,11 +60,11 @@ except ImportError: # 默认字幕样式 DEFAULT_STYLE = { - "font_size": 44, + "font_size": 38, "font_color": "white", "bg_enabled": False, "position": "bottom", # top / middle / bottom - "margin_bottom": 84, + "margin_bottom": 28, "margin_horizontal": 60, "stroke_color": "black", "stroke_width": 1, @@ -74,18 +74,28 @@ DEFAULT_STYLE = { } SUBTITLE_STYLE_PRESETS = { + "reference-drama": { + "font_color": (255, 255, 255, 255), + "bg_enabled": False, + "stroke_width": 2, + "stroke_color": (0, 0, 0, 235), + "bold_weight": 1, + "line_box_ratio": 1.45, + }, "short-drama-bold": { "font_color": (255, 255, 255, 255), "bg_enabled": False, "stroke_width": 1, "stroke_color": (18, 18, 18, 220), "bold_weight": 2, + "line_box_ratio": 1.55, }, "clean-white": { "font_color": (255, 255, 255, 255), "bg_enabled": False, "stroke_width": 0, "bold_weight": 1, + "line_box_ratio": 1.55, }, "black-box": { "font_color": (255, 255, 255, 255), @@ -93,6 +103,7 @@ SUBTITLE_STYLE_PRESETS = { "bg_fill": (0, 0, 0, 160), "stroke_width": 0, "bold_weight": 1, + "line_box_ratio": 1.55, }, "outlined-white": { "font_color": (255, 255, 255, 255), @@ -100,6 +111,7 @@ SUBTITLE_STYLE_PRESETS = { "stroke_width": 2, "stroke_color": (0, 0, 0, 255), "bold_weight": 1, + "line_box_ratio": 1.55, }, } @@ -235,7 +247,9 @@ def render_subtitles( # 渲染 PNG png_path = os.path.join(output_dir, f"{idx}.png") video_width = style.get("video_width", 1080) if style else 1080 - png_height = style.get("font_size", 36) * 3 if style else 108 + font_size = style.get("font_size", 36) if style else 36 + line_box_ratio = style.get("line_box_ratio", 1.55) if style else 1.55 + png_height = int(font_size * line_box_ratio) ok = render_subtitle_png(text, png_path, width=video_width, height=png_height, style=style) if ok: @@ -348,7 +362,8 @@ def main(): parser.add_argument("--output", help="输出视频路径(配合 --video 使用)") parser.add_argument("--font-size", type=int, default=36, help="字体大小") parser.add_argument("--font-color", default="white", help="字体颜色") - parser.add_argument("--style", default="short-drama-bold", choices=sorted(SUBTITLE_STYLE_PRESETS.keys()), help="字幕样式") + parser.add_argument("--style", default="reference-drama", choices=sorted(SUBTITLE_STYLE_PRESETS.keys()), help="字幕样式") + parser.add_argument("--margin-bottom", type=int, default=None, help="字幕距离画面底部的像素边距") parser.add_argument("--position", default="bottom", choices=["top", "middle", "bottom"], help="字幕位置") parser.add_argument("--video-width", type=int, default=1080, help="视频宽度") parser.add_argument("--video-height", type=int, default=1920, help="视频高度") @@ -364,6 +379,8 @@ def main(): "video_width": args.video_width, "video_height": args.video_height, } + if args.margin_bottom is not None: + style["margin_bottom"] = args.margin_bottom # 渲染 PNG 序列 output_dir = args.output_dir or "./subtitles-png/" diff --git a/video-ai-system/knowledge/SUBTITLE-STYLE-STANDARD.hdlp b/video-ai-system/knowledge/SUBTITLE-STYLE-STANDARD.hdlp index 48e6930..0e7a213 100644 --- a/video-ai-system/knowledge/SUBTITLE-STYLE-STANDARD.hdlp +++ b/video-ai-system/knowledge/SUBTITLE-STYLE-STANDARD.hdlp @@ -37,15 +37,14 @@ https://www.atsc.org/wp-content/uploads/2024/04/A343-2024-04-Captions-and-Subtit --- -## EP01竖屏短剧默认样式 +## EP01默认样式 ``` -style_id: short-drama-bold +style_id: reference-drama font_color: white / #FFFFFF / alpha 255 -font_weight: bold background: none shadow: none -stroke: 1px dark edge, only for readability +stroke: 2px black edge alignment: center position: lower third, safe area inside max_lines: 2 @@ -54,9 +53,9 @@ max_lines: 2 说明: ``` -用户反馈上一版字幕太细、太淡。 -因此默认不再使用clean-white细字。 -默认改为粗白字。 +用户提供的商业样片字幕不是大号黑底字幕。 +其特征是: 中等字号、白字、黑描边、贴近视频画面底部但不贴边。 +因此默认改为 reference-drama。 ``` --- @@ -64,8 +63,8 @@ max_lines: 2 ## 为什么保留极细暗边 ``` -纯白粗字在天空、白衣、雾气、浅石头上会丢失。 -极细暗边不是阴影,也不是黑底。 +纯白字在天空、白衣、雾气、浅石头上会丢失。 +黑描边不是阴影,也不是黑底。 它只用于保证手机观看时文字不发飘。 ``` @@ -91,4 +90,3 @@ stroke_width可降为0。 两行以内 与角色对白时间轴同步 ``` - diff --git a/video-ai-system/memory/zai-fu-fei-xiu-xian/STATUS.hdlp b/video-ai-system/memory/zai-fu-fei-xiu-xian/STATUS.hdlp index 6e42a97..88405af 100644 --- a/video-ai-system/memory/zai-fu-fei-xiu-xian/STATUS.hdlp +++ b/video-ai-system/memory/zai-fu-fei-xiu-xian/STATUS.hdlp @@ -114,6 +114,7 @@ preview-003: 暂不生成。 | 牌匾固定贴图 | ✅ PNG已生成 | `assets/props/PROP-TDZ-PLAQUE/texture/tdz-plaque-texture.png` | | 字幕渲染合成 | ✅ 粗白短剧样式RUN-004通过 | `outputs/tests/TEST-SUBTITLE-004-SHORT-DRAMA-BOLD-REPORT.hdlp` | | 字幕样式标准 | ✅ 已建立 | `knowledge/SUBTITLE-STYLE-STANDARD.hdlp` | +| 商用字幕工具链 | 🟡 待开发 | `plans/D144-SUBTITLE-PRODUCTION-TOOLCHAIN.hdlp` | | 百宗会人群底片 | 🟡 RUN-002可作氛围候选 | `outputs/tests/TEST-PROP-001-TDZ-PLAQUE-RUN-002-REPORT.hdlp` | | 苏白TTS配音 | ✅ 工程测试通过 | `outputs/tests/TEST-TTS-001-SUBAI-RUN-001-REPORT.hdlp` | | 模型/成本路线 | ✅ 已建立 | `knowledge/D144-MODEL-COST-ROUTE.hdlp` | @@ -213,6 +214,8 @@ preview-003: 暂不生成。 - [x] 调整字幕默认风格为纯白无黑底/无阴影 → `outputs/tests/TEST-SUBTITLE-003-CLEAN-WHITE-RUN002-REPORT.hdlp` - [x] 调整字幕默认风格为粗白短剧字幕 → `outputs/tests/TEST-SUBTITLE-004-SHORT-DRAMA-BOLD-REPORT.hdlp` - [x] 建立字幕样式标准 → `knowledge/SUBTITLE-STYLE-STANDARD.hdlp` +- [x] 建立商用字幕工具链开发规格 → `plans/D144-SUBTITLE-PRODUCTION-TOOLCHAIN.hdlp` +- [ ] 开发 reference-subtitle-analyzer / ASS渲染 / 字体管理 / 安全区QC 字幕工具链 - [x] 重定性 RUN-002: 牌匾一致性失败,但百宗会人群氛围可用 - [x] 测试苏白Edge-TTS工程配音 → `outputs/tests/TEST-TTS-001-SUBAI-RUN-001-REPORT.hdlp` - [x] 建立模型/成本路线 → `knowledge/D144-MODEL-COST-ROUTE.hdlp` diff --git a/video-ai-system/plans/D144-SUBTITLE-PRODUCTION-TOOLCHAIN.hdlp b/video-ai-system/plans/D144-SUBTITLE-PRODUCTION-TOOLCHAIN.hdlp new file mode 100644 index 0000000..ece6c51 --- /dev/null +++ b/video-ai-system/plans/D144-SUBTITLE-PRODUCTION-TOOLCHAIN.hdlp @@ -0,0 +1,477 @@ +# D144 · 商用短剧字幕生产工具链 + +> HLDP://video-ai-system/plans/D144-SUBTITLE-PRODUCTION-TOOLCHAIN +> 类型: 字幕工具开发规格 · 对标样片标准 +> 日期: 2026-06-24 +> 铸渊 ICE-GL-ZY001 + +--- + +## 纠偏 + +``` +当前 subtitle-renderer.py 是工程测试工具,不是商用字幕工具。 +用 Pillow 画 PNG 再 overlay,只能验证“能烧字幕”,不能保证样片级字幕观感。 +继续手调字号/位置是在凑合。 +``` + +正确路线: + +``` +以样片字幕为标准 → 建立字幕规范 → 开发专业渲染工具链 → 每条视频自动质检。 +``` + +--- + +## 样片字幕标准 · 目标 + +用户提供样片字幕特征: + +``` +白色主体字 +黑色描边清楚 +无黑色字幕底板 +无明显投影 +字体厚实,不飘,不发灰 +字号中等,不抢画面 +位置在视频画面内部底部 +不贴边 +不遮挡人物脸、胸口主体表演 +居中 +最多两行 +``` + +我们要做的是: + +``` +做出同一套字幕标准。 +不是“接近”,而是按样片规范复刻。 +``` + +--- + +## 必须开发的软件/工具 + +### 1. reference-subtitle-analyzer.py + +路径建议: + +``` +video-ai-system/tools/reference-subtitle-analyzer.py +``` + +用途: + +``` +从样片截图/抽帧中测量字幕标准。 +``` + +输入: + +``` +sample_frame.jpg +可选: 手动标注字幕框 bbox +``` + +输出: + +``` +video_frame_width +video_frame_height +subtitle_bbox +subtitle_center_x +subtitle_baseline_y +bottom_margin_px +font_height_px +font_height_ratio +stroke_width_px +stroke_ratio +subtitle_width_ratio +line_count +style_report.hdlp +``` + +验收: + +``` +能把样片字幕量化成参数,而不是靠肉眼猜。 +``` + +--- + +### 2. subtitle-style.json + +路径建议: + +``` +video-ai-system/config/subtitle-style.reference-drama.json +``` + +内容: + +``` +style_id +font_family +font_size_ratio +font_weight +font_color +stroke_color +stroke_width_ratio +shadow +background +alignment +bottom_margin_ratio +max_width_ratio +max_lines +line_spacing +safe_area +``` + +验收: + +``` +任何视频分辨率都能按比例得到同一字幕观感。 +横屏/竖屏不能共用死字号。 +``` + +--- + +### 3. ass-subtitle-renderer.py + +路径建议: + +``` +video-ai-system/engines/ass-subtitle-renderer.py +``` + +为什么要开发: + +``` +商用字幕不应该靠Pillow临时画PNG。 +应该生成ASS字幕,让libass/FFmpeg按字幕标准渲染。 +ASS天然支持字体、粗体、描边、边距、对齐、换行、位置。 +``` + +输入: + +``` +srt_path +style_json +video_path +output_path +``` + +输出: + +``` +styled.ass +burned_video.mp4 +render_report.hdlp +``` + +推荐实现: + +``` +SRT → ASS +ASS Style: + Fontname + Fontsize + PrimaryColour + OutlineColour + Bold + Outline + Shadow=0 + Alignment=2 + MarginL/MarginR/MarginV +FFmpeg subtitles/ass filter 或 libass 渲染 +``` + +注意: + +``` +如果当前FFmpeg没有 subtitles/ass filter,则工具必须检测并报错。 +不要静默降级到Pillow。 +``` + +验收: + +``` +同一句字幕在样片截图上视觉接近样片标准。 +字体不虚、不灰、不飘。 +``` + +--- + +### 4. subtitle-font-manager.py + +路径建议: + +``` +video-ai-system/tools/subtitle-font-manager.py +video-ai-system/assets/fonts/subtitle/ +``` + +用途: + +``` +管理字幕字体。 +``` + +原因: + +``` +系统字体不稳定。 +不同机器字体不同,字幕观感会变。 +必须固定项目字幕字体。 +``` + +任务: + +``` +列出本机中文字体 +测试字体是否支持中文 +生成字体预览图 +选择/复制批准字体到 assets/fonts/subtitle/ +记录字体许可证/来源 +``` + +候选方向: + +``` +思源黑体 Heavy/Bold +阿里巴巴普惠体 Bold +可商用中文黑体 +``` + +验收: + +``` +字幕使用项目字体,不再依赖系统默认字体。 +``` + +--- + +### 5. subtitle-safe-area-qc.py + +路径建议: + +``` +video-ai-system/tools/subtitle-safe-area-qc.py +``` + +用途: + +``` +检查字幕位置是否遮挡人物或关键画面。 +``` + +输入: + +``` +video_path +subtitle_ass_or_srt +sample_frames +可选: 人物bbox/手动主体区域 +``` + +输出: + +``` +subtitle_bbox_per_frame +bottom_margin +overlap_with_character_bbox +overlap_with_key_prop_bbox +readability_score +qc_report.hdlp +contact_sheet.jpg +``` + +最小实现: + +``` +先用抽帧 + 人工标注主体bbox。 +后续再接自动人物检测。 +``` + +硬失败: + +``` +遮脸 +遮主要台词人物胸口表演 +遮关键道具文字 +贴到底边 +超出安全区 +背景太亮导致看不清 +``` + +--- + +### 6. subtitle-preview-contact-sheet.py + +路径建议: + +``` +video-ai-system/tools/subtitle-preview-contact-sheet.py +``` + +用途: + +``` +每次烧字幕后自动抽关键帧,让人一眼判断字幕是不是跳戏。 +``` + +输出: + +``` +contact_sheet.jpg +frame_0001.jpg +frame_0002.jpg +frame_0003.jpg +``` + +验收: + +``` +不再只打开视频靠用户暂停截图。 +系统自己产出检查图。 +``` + +--- + +### 7. subtitle-style-ab-test.py + +路径建议: + +``` +video-ai-system/tools/subtitle-style-ab-test.py +``` + +用途: + +``` +同一底片一次生成多种字幕版本,横向对比。 +``` + +输入: + +``` +video_path +srt_path +style_json_list +``` + +输出: + +``` +版本A/B/C视频 +对比contact sheet +评分表 +``` + +验收: + +``` +字幕风格不要再一版一版盲调。 +一次对比,选最像样片的。 +``` + +--- + +### 8. script-to-srt-with-timing.py + +路径建议: + +``` +video-ai-system/tools/script-to-srt-with-timing.py +``` + +用途: + +``` +从剧本原文和角色对白音频生成正式SRT。 +``` + +输入: + +``` +script line +voice audio +shot duration +``` + +输出: + +``` +line.srt +timing_report.hdlp +``` + +验收: + +``` +字幕时间跟角色说话同步,不靠手写测试时间。 +``` + +--- + +## 当前工具的处理 + +### subtitle-renderer.py + +定位调整为: + +``` +工程测试工具。 +可用于快速验证。 +不能作为最终商用字幕渲染器。 +``` + +必须追加警告: + +``` +如用于最终样片,需经过 subtitle-safe-area-qc。 +推荐最终走 ass-subtitle-renderer.py。 +``` + +--- + +## 腾讯AI人格体开发顺序 + +``` +1. subtitle-font-manager.py +2. reference-subtitle-analyzer.py +3. subtitle-style.reference-drama.json +4. ass-subtitle-renderer.py +5. subtitle-preview-contact-sheet.py +6. subtitle-style-ab-test.py +7. subtitle-safe-area-qc.py +8. script-to-srt-with-timing.py +``` + +每完成一个工具必须提交: + +``` +README +命令示例 +测试输入 +测试输出 +失败边界 +是否已推送仓库 +``` + +--- + +## 验收口径 + +一个字幕工具链算完成,必须满足: + +``` +拿用户提供的样片截图,能量化字幕参数。 +拿我们的测试视频,能生成同标准字幕。 +输出前自动抽帧。 +不遮挡主体。 +不发灰、不发虚、不跳戏。 +能固定字体。 +能在不同分辨率按比例保持观感。 +``` + diff --git a/video-ai-system/plans/D144-TENCENT-AI-DEV-HANDOFF.hdlp b/video-ai-system/plans/D144-TENCENT-AI-DEV-HANDOFF.hdlp index 2abfa40..e07f804 100644 --- a/video-ai-system/plans/D144-TENCENT-AI-DEV-HANDOFF.hdlp +++ b/video-ai-system/plans/D144-TENCENT-AI-DEV-HANDOFF.hdlp @@ -163,27 +163,33 @@ referenceAudios: string[] ``` subtitle-renderer.py 已可 SRT→PNG→FFmpeg overlay 合成。 +但它只是工程测试工具,不是最终商用字幕工具。 ``` 还需补: ``` -config/subtitle-styles.json -tools/script-to-srt.py -tools/burn-subtitles.py -safe-area检查 -字幕不遮脸/不遮关键道具检查 +完整开发规格见: +video-ai-system/plans/D144-SUBTITLE-PRODUCTION-TOOLCHAIN.hdlp + +必须开发: +reference-subtitle-analyzer.py +subtitle-style.reference-drama.json +ass-subtitle-renderer.py +subtitle-font-manager.py +subtitle-safe-area-qc.py +subtitle-preview-contact-sheet.py +subtitle-style-ab-test.py +script-to-srt-with-timing.py ``` 验收: ``` -EP01可从原文台词生成SRT。 -可按角色对白时间轴烧字幕。 -中文不乱码。 -竖屏底部安全区可控。 -必须检查base_video是否为已通过视觉QC的底片。 -禁止使用已标记失败的视频作为展示样片。 +对标用户提供样片字幕标准。 +不是“接近”,而是按样片规范复刻。 +字体固定、黑描边稳定、字号/位置按比例计算。 +不遮挡主体,不发灰,不跳戏。 ``` ### 5. AUDIO-MIXER