异构拼接的画布与时间归一化
入口和参数见 Media README。ConcatenateAsync 解码、归一化并重新编码全部片段,单输入和重复输入也走同一路径,不按容器扩展名推断可以直接 stream copy。
画布与帧网格
每个输入须有已知正容器时长。默认画布取首段方向校正后的栅格并补为偶数;默认 fps 取首段有效平均帧率,未知时要求显式值。
缩放按实际显示宽高比 DAR(含 SAR 和方向)计算,保证两边都不超过已检查画布,再设置方形像素并居中补黑。避免先生成很大的中间栅格再缩回预算。偶数尺寸量化会造成少量比例近似,输入、目标与补齐外框均检查尺寸/像素上限。
片段目标时长为 ceil(duration × fps) / fps,视频和音频使用同一值。缺少视频尾帧时延长末帧,音频不足时补静音;每段最多因量化增加一帧停留,防止长音轨下下一段画面过早开始。最终统一 CFR,有损音频仍可能增加编码器填充。
视频与音频分别以 PTS-STARTPTS 归零,不保留输入刻意设置的音画起始偏移。例如音轨晚 0.2 秒开始,其首样本会移到片段起点,再补齐尾部。此入口是片段归一化,不是原时间线复制。
音轨与编码
任一片段有声音时,各段只取第一音轨并显式重采样/混音为 48 kHz 立体声,无音轨段补有限静音;全部无音轨时输出也无音轨。额外音轨、字幕、章节与业务元数据不属于保留契约。
编码复用视频基础的 H.264/AAC 与 VP9/Opus 配置。过滤链尾部删除已应用的 DISPLAYMATRIX,输出探测要求旋转为零;不能只依赖清空 rotate tag。解码和复杂过滤图各使用一个线程,输出编码按所选编码器运行,像素预算不是全部线程/native 内存的硬配额。
验收与回归
输入列表先检查数量,规范化后每个路径都须与输出不同。编码后核对实际画布、音轨存在性和零旋转;有音轨时进一步解码计数并验证 48 kHz/双声道。通过后才使用共享发布移动暂存文件,失败只清理本次结果。
VideoConcatenationTests 覆盖不同分辨率、帧率、编码、静音混合、音画时长差、起始偏移、SAR、旋转、VFR 和重复输入,并检查实际颜色及音频内容。真实 FFmpeg 测试显式设置 RUN_MEDIA_FFMPEG_TESTS=true,未知时长或帧率的拒绝路径仍需保留。