清单格式
manifest.json 是系统两半之间唯一的接口。应用在导入时严格校验,并拒绝任何存在歧义的内容。
通常您无需手工编写 —— 它由准备脚本生成。本页用于排查导入错误,或供自建工具参考。
{ "schema_version": 1, "sport": "badminton_singles", "source": { "id": "2026-08-10-club-a", "filename": "IMG_4471.MOV", "fps": 119.88, "width": 1920, "height": 1080, "recorded_at": "2026-08-10T19:22:00+08:00", "camera": { "viewpoint": "receiver", "height_m": 1.7, "notes": "中线,底线后 0.8 m" }, "opponent_id": "opp_003", "consent": true }, "shots": [ { "id": "s_0001", "contact_frame": 4127, "contact_time_ms": 34426.09, "zone": "BL", "shot_type": "clear", "detector": { "source": "manual", "confidence": 1.0, "confirmed_by_human": false }, "clip": { "path": "clips/s_0001.mp4", "duration_ms": 2500, "lead_in_ms": 2500 } } ]}source
Section titled “source”| 字段 | 说明 |
|---|---|
id | 标识一组素材。显示在应用的素材列表中 |
fps | 从容器元数据读取的精确帧率,浮点数。须在 1–1000 之间 |
recorded_at | ISO 8601 格式 |
camera.viewpoint | receiver | side | corner | other。非 receiver 会触发警告 |
opponent_id | 可选 |
consent | 缺失视为 false 并给出警告 |
shots[]
Section titled “shots[]”| 字段 | 说明 |
|---|---|
id | 在清单内唯一 |
contact_frame | 球拍击球时刻的整数帧号 |
contact_time_ms | 必须等于 contact_frame / fps × 1000,误差在一帧以内 |
zone | 必须是该项目配置中定义的区域代码 |
shot_type | 可选、可为空,不参与分析 |
detector.source | tracknet_v3 | tracknet_v4 | manual |
detector.confirmed_by_human | 在应用中完成标注后置为 true |
clip.path | 相对于清单的路径。绝对路径与 .. 会被拒绝 |
clip.duration_ms | 必须大于 0。片段终止于击球帧 |
clip.lead_in_ms | 不得超过 duration_ms |
每个片段都精确终止于其击球帧。 遮蔽是提前停止播放,绝不是裁剪文件。
contact_time_ms 必须与 contact_frame 在声明帧率下相符。 应用会校验这一点;若二者相差超过一帧则拒绝导入 —— 不一致意味着其中之一是错的,而没有任何安全的方式去猜测是哪一个。
H.264,帧率与源相同,CRF 20,-g 15(短 GOP),faststart,去除音频。
短 GOP 很关键:它让解码行为可预测,从而使播放器能在每个试次前可靠地完成预缓冲。
出现以下情况时应用会报错并中止导入:
| 错误 | 原因 |
|---|---|
| 清单架构版本不受支持 | 脚本与应用版本不一致。请用匹配版本重新切分 |
| 清单项目为 “X”,但期望 “Y” | 切分时 --sport 参数有误 |
| 区域代码未定义 | 区域代码与项目不匹配 |
| contact_time_ms 与 contact_frame 不符 | 帧率是假定的而非读取的 |
| 击球 id / 片段路径重复 | 击球清单有误 |
| 该视频已导入 | 请先删除已有素材 |