fix: 视频时间语义修正 — 绝对时间戳偏移换算 + mtime 起点修正 + 直传超时
三处时间语义 bug(时区统一排查的延伸发现): 1. NVIDIA 集锦偏移语义: frame_timestamps 是绝对时间 'YYYY-MM-DD HH:MM:SS'(当日秒 77474s)被直接当视频内偏移用, seek 超出 30 分钟视频 → 0 帧 → 集锦恒为空 → 视频模式永远降级。 修复: analyze_video 增加 event_start_time 参数,偏移 = 帧时间 - 视频开始时间(跨午夜 +86400);orchestrator 两处 调用点透传。另加 ffprobe 时长过滤跳过超界片段(日志明示), fps=15 统一 CFR 输出。 2. NAS dispatcher event_start_time: 原用文件 mtime(=录制结束 时刻),真实开始时间应为 mtime - 视频时长,事件时间整体偏移 一个视频周期(~30min)。新增 _probe_duration 用 ffmpeg 解析 Duration(NAS 无独立 ffprobe)。 3. 直传超时: 压缩后 ~19MB 略低于 20MB 分块阈值走直传, timeout(10,120) 在 1Mbps 下传 19MB 需 ~152s 必超时(task 42 三连败 FAILED)。加大到 (10, 300)。 测试数据陷阱记录: 两轮 0KB/9.47s 集锦异常均为测试时间戳超出 视频时长所致(1801s>1800s),单输入/多输入 concat 行为本身正常。
This commit is contained in:
@@ -17,6 +17,7 @@ Dispatcher - 30s 轮询 PENDING 任务,上传视频至 Edge 异步队列
|
||||
"""
|
||||
import os
|
||||
import io
|
||||
import re
|
||||
import time
|
||||
import math
|
||||
import shutil
|
||||
@@ -90,6 +91,22 @@ class Dispatcher:
|
||||
return False
|
||||
return True
|
||||
|
||||
def _probe_duration(self, video_path):
|
||||
"""用 ffmpeg 解析视频时长(NAS 无独立 ffprobe),失败返回 0"""
|
||||
if not self.ffmpeg:
|
||||
return 0
|
||||
try:
|
||||
r = subprocess.run(
|
||||
[self.ffmpeg, '-i', video_path],
|
||||
capture_output=True, timeout=30)
|
||||
m = re.search(r'Duration:\s*(\d+):(\d+):(\d+(?:\.\d+)?)',
|
||||
r.stderr.decode('utf-8', 'ignore'))
|
||||
if m:
|
||||
return int(m.group(1)) * 3600 + int(m.group(2)) * 60 + float(m.group(3))
|
||||
except (subprocess.TimeoutExpired, OSError):
|
||||
pass
|
||||
return 0
|
||||
|
||||
def _build_payload(self, task):
|
||||
"""构建推送元数据,注入已知成员清单与事件时间"""
|
||||
video_path = task['video_path']
|
||||
@@ -102,7 +119,9 @@ class Dispatcher:
|
||||
}
|
||||
try:
|
||||
mtime = os.path.getmtime(video_path)
|
||||
start_dt = datetime.fromtimestamp(mtime)
|
||||
# mtime 是录制结束时刻,开始时间 = 结束时间 - 视频时长
|
||||
duration = self._probe_duration(video_path)
|
||||
start_dt = datetime.fromtimestamp(mtime - duration)
|
||||
payload["event_start_time"] = start_dt.strftime('%Y-%m-%d %H:%M:%S')
|
||||
except OSError:
|
||||
pass
|
||||
@@ -238,7 +257,7 @@ class Dispatcher:
|
||||
self.edge_url,
|
||||
data=payload,
|
||||
files={'video': (os.path.basename(video_path), fh, 'video/mp4')},
|
||||
timeout=(10, 120)
|
||||
timeout=(10, 300)
|
||||
)
|
||||
except requests.RequestException as e:
|
||||
logger.error(f"[task_id={task_id}] 上传失败: {e}")
|
||||
|
||||
Reference in New Issue
Block a user