视频转码、抽帧与时间定位的一致性
同一视频在事件单次定位和循环定位中得到不同的首个结果,未必来自模型随机性。若一个接口读取原文件,另一个先通过 FFmpeg 转码,即便画面肉眼一致,时间戳和抽帧网格也可能变化。
归档排查中,循环定位第一轮使用临时转码文件,单次定位使用原文件。让第一轮复用原视频后,首个结果恢复一致;后续轮次才裁剪剩余时间段。
一、模型看到的是采样序列
视频 VLM 通常不处理每帧,而是读取按时间规则采样的图像。输入由解码画面、帧顺序、时间信息和采样参数共同决定。转码可能改变帧率、PTS 起点和可变帧率结构,从而选中不同画面。
ffprobe -v error -select_streams v:0 \
-show_entries stream=r_frame_rate,avg_frame_rate,time_base,start_time,duration \
-of json video.mp4元信息可以解释差异,最终应记录实际采样时间和图像哈希。平均帧率相同也不保证采样画面相同。
1.1 帧编号不是时间戳
对恒定帧率、时间轴连续且起点已知的视频,可以用帧编号近似计算时间;对可变帧率视频,帧间隔并不固定,直接使用 frame_index / avg_fps 会累积偏差。time_base 表示时间戳的单位,PTS 乘以这个单位才是相应时间。DTS 用于解码调度,含有 B 帧的视频中,它与画面展示时间可能不同。
要核对实际画面的时间,继续查看解码帧,而不只看容器声明的帧率:
ffprobe -v error -select_streams v:0 -show_frames \
-show_entries frame=pts_time,best_effort_timestamp_time,key_frame \
-of json video.mp4 > frame_timestamps.json视频较长时可先检查局部,但 seek 后实际读到的起点仍需核对。best_effort_timestamp_time 是解码器推导的展示时间;原流时间戳缺失或异常时,也应记录这种情况,不能把推导值当作完整原始记录。
1.2 转码会影响哪些输入条件
重新编码可能改变像素、帧率及时间轴。fps 滤镜会通过丢帧或复制帧构造固定帧率序列,其输出时间点不一定就是被选中源帧的原始 PTS。输出端的帧同步设置也需要纳入对照。即使使用 -copyts,封装器和同步处理仍可能调整最终时间戳,不能把它视为保持输入完全一致的开关。
例如原始视频某帧在 10.04 秒,而处理后采样网格在 10.00 秒附近选中了相邻画面;模型看到的动作阶段可能已经不同。如果再把采样后第 20 帧直接解释为原视频 10.00 秒,就同时混淆了采样目标时间和源帧展示时间。这只是说明机制的例子,不是归档实验中已测得的具体数值。
若必须统一编码格式,应让单次定位和循环定位复用同一份标准化媒体及采样配置。若目标是严格比较模型输入,更容易复核的做法是复用同一批解码帧,再把帧序号、源时间和传给模型的时间信息一同保存。
比对图像哈希时要固定比较对象。文件哈希只能判断文件字节是否相同;帧哈希应基于一致的像素格式、尺寸和颜色转换。经过有损转码后,画面肉眼相似而哈希不同是正常现象,需要继续检查视觉差异,不能仅凭哈希不一致就认定存在时间错位。
二、循环定位的基线
| 轮次 | 输入 | 时间映射 |
|---|---|---|
| 第一轮 | 原始媒体 | 原始时间轴 |
| 后续轮 | 剩余区间或其裁剪 | 局部时间+明确偏移 |
| 最终结果 | 原媒体区间 | 校验边界与递增关系 |
裁剪后保留局部时间到原时间的映射。模型返回的结束时间应推动下一轮起点,并防止重复命中或零进展循环。不能丢掉转码产生的起点偏移。
2.1 区分请求起点与实际首帧
裁剪请求从 30 秒开始,不代表输出文件的第一帧一定恰好对应原视频 30 秒。FFmpeg 输入端的 -ss 通常先定位到此前的可寻址点;转码且启用默认精确寻址时,会解码并丢弃前面的画面,而 stream copy 不能默认获得相同的裁剪精度。
trim 用于选择帧,本身不重置时间戳;setpts=PTS-STARTPTS 则把保留下来的首帧移到零点。下面的例子只用于说明这两步的区别:
ffmpeg -i video.mp4 -an \
-vf "trim=start=30:end=60,showinfo,setpts=PTS-STARTPTS" \
-c:v libx264 -fps_mode passthrough clip.mp4这里 showinfo 位于重置时间戳之前,可以检查滤镜收到的保留帧时间。FFmpeg 输入处理也可能平移时间戳,需要与原文件的 ffprobe 结果对照,才能还原源时间;原视频若不是从零开始,还需先明确 30 秒是流时间戳还是相对视频起点的时间。这个例子会重新编码,也未保留音轨,不能直接作为音视频联合定位的完整流程。
若源视频起点为
假设请求从 30 秒开始,实际保留首帧为 30.08 秒,局部结果为 2 秒,那么对应源时间是 32.08 秒,而不是 32 秒。若还做了变速、分段拼接或不规则时间重映射,就不能只加一个偏移量,需要保存分段映射关系。
2.2 下一轮怎样推进
循环时应始终用原时间轴维护搜索位置,再从原始媒体选择下一段,避免反复裁剪上一轮生成的临时视频。后者会引入多次有损编码,也让偏移链越来越难核对。
对每轮结果检查 0 <= start < end <= 当前窗口时长,映射回原时间轴后再判断是否有进展。若返回空结果、格式错误或结束位置没有前移,应有限重试或结束,并记录原因;不能无条件再次提交同一个窗口。
若需保留一点上下文,可以让相邻窗口重叠,但也要按时间区间去重。下一轮从上一结果末尾继续搜索,还隐含“目标事件按顺序且不重叠”的假设;存在同时发生的事件时,这种方式可能直接跳过另一条事件,不能将它等同于完整枚举。
三、任务定义与评测
单次定位输出一个区间,循环定位通过多次调用枚举区间。评价循环结果需检查漏检、重复、区间 IoU 和累计偏移,而不只看第一次回答。
可以先把一次排查拆成三组对照:
| 对照 | 固定条件 | 观察差异 |
|---|---|---|
| 两个接口复用同一份帧和时间信息 | 模型、prompt、采样及生成参数 | 接口是否还有额外处理差异 |
| 原文件与转码文件 | 同一抽帧策略和请求区间 | 实际帧、源 PTS 和输入像素是否变化 |
| 后续窗口与原视频对应区间 | 相同源帧及事件标注 | 局部结果映射后是否仍有偏移 |
第一组仍不一致时,再检查视频 processor、最大帧数、视觉分辨率、时间提示和生成设置。随机种子无法抵消输入变化,单次结果一致也不能证明所有视频都已满足同样条件。
评测时将预测与标注放到同一个原始时间轴,再计算区间 IoU:
同时查看起止点的绝对时间误差。对于很短的事件,小幅偏移就可能造成较大的 IoU 损失;对于长事件,相同偏移又容易被 IoU 掩盖。循环输出还应做一对一匹配,重复命中同一标注不能重复算作召回。
对远距离行为识别,应把可观察动作与解释性标签分开。持续静止与反复头部动作可以记录,但直接推断困倦或意图可能超出画面证据。可先生成时间事件描述,再以规则匹配;收益仍需要独立标注数据验证。
若定位结果继续进入持续确认、触发与恢复流程,媒体时间、未知观测和状态复位的处理见 CV 视频场景策略的触发与恢复。
四、时序信息的保存
多帧训练样本要保存实际帧位置、窗口长度和采样策略。均匀采样、事件中心密集采样与运动触发采样代表不同输入分布;去重如果无视这些信息,可能把连续动作中最关键的转折帧删掉。
每个样本至少保留源媒体标识、搜索窗口、实际源帧 PTS、模型输入顺序与时间信息,以及前处理版本。若模型限制最多输入若干帧,还要记录截断或二次采样之后真正送入模型的序列,不能只保存最初计划抽取的列表。
稀疏采样也限制了可观察的时间细节。每秒两帧的输入可能漏掉两次采样之间的短动作;模型输出精确到百分之一秒,并不说明输入提供了同等精度的证据。粗定位之后,可以回到原视频对应区间增加采样密度,再细化起止点。
语义相似图片不一定可以互换。两个几乎相同的姿态,顺序不同可能对应相反事件;标签若依赖动作方向或持续时长,数据构建必须保留顺序和跨度。
评测还可以构造时间反转、移除关键帧与改变跨度的对照。如果模型结论完全不变,应检查它是否只利用静态场景线索,而非已经学到时序判断。
五、一些反思
媒体前处理属于实验条件。固定 prompt 和随机种子仍不足以建立公平对照,必须固定模型实际读取的帧和时间。
时间也是输出契约的一部分。半秒偏移可能来自采样;先校验媒体链路,能够避免把工程差异误判成模型能力问题。