"""灰度对比测试场景定义 — 覆盖典型渲染场景. 每个场景对应一个 EditPlan,用于新旧引擎对比。 覆盖场景: 1. 简单直通(单clip无特效) 2. 多clip转场(fade + slide) 3. 画中画(main + overlay) 4. 字幕渲染(ASS字幕) 5. 独立音频轨(主视频 + BGM) 6. 多图层混合(main + broll + overlay + audio) 7. 背景图片 + 主视频(图片背景无音频) 8. 无音频视频(纯画面,验证无音轨防御) 9. 长视频(10+ clip,压力测试) 10. 分辨率非标(竖屏9:16,验证scale策略) """ from __future__ import annotations from dataclasses import dataclass, field from typing import Any @dataclass class CompareScenario: """对比测试场景.""" id: str name: str description: str priority: str # P0 / P1 / P2 plan_payload: dict[str, Any] # EditPlan JSON payload(提交给 API 的数据) expected: dict[str, Any] = field(default_factory=dict) # 预期结果 SCENARIOS: list[CompareScenario] = [ CompareScenario( id="simple_pass_through", name="简单直通", description="单主clip,无转场无特效,验证直通优化路径", priority="P0", plan_payload={ "width": 1280, "height": 720, "fps": 25, "clips": [ { "clip_type": "main", "asset_id": "sample_5s.mp4", "duration": 5.0, "order": 0, } ], }, ), CompareScenario( id="multi_clip_transition", name="多clip转场", description="3个clip,fade + slideleft 转场", priority="P0", plan_payload={ "width": 1280, "height": 720, "fps": 25, "clips": [ { "clip_type": "main", "asset_id": "sample_5s.mp4", "duration": 3.0, "order": 0, "transition_effect": "cut", }, { "clip_type": "main", "asset_id": "sample_5s.mp4", "duration": 3.0, "order": 1, "transition_effect": "fade", }, { "clip_type": "main", "asset_id": "sample_5s.mp4", "duration": 3.0, "order": 2, "transition_effect": "slideleft", }, ], }, ), CompareScenario( id="picture_in_picture", name="画中画", description="主视频 + 角落小窗(corner_voice)", priority="P1", plan_payload={ "width": 1280, "height": 720, "fps": 25, "clips": [ {"clip_type": "main", "asset_id": "sample_5s.mp4", "duration": 5.0, "order": 0}, {"clip_type": "corner_voice", "asset_id": "sample_5s.mp4", "duration": 5.0, "order": 0}, ], }, ), CompareScenario( id="subtitle_rendering", name="字幕渲染", description="主视频 + ASS字幕", priority="P0", plan_payload={ "width": 1280, "height": 720, "fps": 25, "clips": [ { "clip_type": "main", "asset_id": "sample_5s.mp4", "duration": 5.0, "order": 0, "config": {"subtitles": [{"text": "测试字幕 Test Subtitle", "start_time": 0, "end_time": 5.0}]}, } ], }, ), CompareScenario( id="independent_audio_track", name="独立音频轨", description="主视频(带音频)+ 独立BGM轨,验证音频混音", priority="P0", plan_payload={ "width": 1280, "height": 720, "fps": 25, "clips": [ {"clip_type": "main", "asset_id": "sample_5s.mp4", "duration": 5.0, "order": 0}, { "clip_type": "main", "asset_id": "sample_bgm.mp3", "duration": 5.0, "order": 0, "config": {"role": "audio", "volume": 0.5}, }, ], }, ), CompareScenario( id="multi_layer_mix", name="多图层混合", description="main + broll + overlay + audio 四图层", priority="P1", plan_payload={ "width": 1280, "height": 720, "fps": 25, "clips": [ { "clip_type": "main", "asset_id": "sample_5s.mp4", "duration": 4.0, "order": 0, "transition_effect": "fade", }, { "clip_type": "main", "asset_id": "sample_5s.mp4", "duration": 4.0, "order": 1, "transition_effect": "slideup", }, {"clip_type": "broll", "asset_id": "sample_broll.mp4", "duration": 8.0, "order": 0}, {"clip_type": "overlay", "asset_id": "sample_overlay.png", "duration": 8.0, "order": 0}, { "clip_type": "main", "asset_id": "sample_bgm.mp3", "duration": 8.0, "order": 0, "config": {"role": "audio", "volume": 0.3}, }, ], }, ), CompareScenario( id="image_background", name="图片背景", description="background图片层 + 主视频,验证背景层无音频", priority="P1", plan_payload={ "width": 1280, "height": 720, "fps": 25, "clips": [ {"clip_type": "background", "asset_id": "sample_bg.jpg", "duration": 5.0, "order": 0}, {"clip_type": "main", "asset_id": "sample_5s.mp4", "duration": 5.0, "order": 0}, ], }, ), CompareScenario( id="no_audio_video", name="无音轨视频", description="源视频无音频流,验证无音轨防御逻辑", priority="P0", plan_payload={ "width": 1280, "height": 720, "fps": 25, "clips": [ {"clip_type": "main", "asset_id": "sample_silent_5s.mp4", "duration": 5.0, "order": 0}, ], }, ), CompareScenario( id="long_video_stress", name="长视频压力", description="10个clip + 多种转场,性能压力测试", priority="P2", plan_payload={ "width": 1280, "height": 720, "fps": 25, "clips": [ { "clip_type": "main", "asset_id": "sample_5s.mp4", "duration": 3.0, "order": i, "transition_effect": ["cut", "fade", "slideleft", "slidedown", "dissolve"][i % 5], } for i in range(10) ], }, ), CompareScenario( id="vertical_portrait", name="竖屏9:16", description="竖屏分辨率,验证scale策略(铺满裁剪)", priority="P2", plan_payload={ "width": 720, "height": 1280, "fps": 25, "clips": [ {"clip_type": "main", "asset_id": "sample_5s.mp4", "duration": 5.0, "order": 0}, ], }, ), ] def get_scenarios_by_priority(min_priority: str = "P2") -> list[CompareScenario]: """按优先级过滤场景. P0 包含 P0 P1 包含 P0 + P1 P2 包含全部 """ priority_order = {"P0": 0, "P1": 1, "P2": 2} threshold = priority_order.get(min_priority, 2) return [s for s in SCENARIOS if priority_order.get(s.priority, 2) <= threshold]