Files
video-ai-analysis/video_ai_analysis_poc/frames.py
2026-06-17 11:33:54 +08:00

60 lines
1.9 KiB
Python

from __future__ import annotations
from pathlib import Path
from typing import Any, Iterable
from .timeline import DEFAULT_TIMEZONE, format_beijing_time
def seconds_to_timecode(seconds: float | int | None) -> str | None:
if seconds is None:
return None
total_seconds = int(float(seconds))
hours = total_seconds // 3600
minutes = (total_seconds % 3600) // 60
remaining_seconds = total_seconds % 60
return f"{hours:02d}:{minutes:02d}:{remaining_seconds:02d}"
def build_frame_records(
video_id: str,
output_dir: str | Path,
frame_paths: Iterable[str | Path],
*,
frame_fps: float,
timeline_start_epoch: float | int | str | None = None,
timezone_name: str = DEFAULT_TIMEZONE,
) -> list[dict[str, Any]]:
base_dir = Path(output_dir).expanduser().resolve(strict=False)
records = []
for index, frame_path in enumerate(sorted(Path(path) for path in frame_paths), start=1):
offset_seconds = round((index - 1) / frame_fps, 6)
record = {
"video_id": video_id,
"frame_id": f"{video_id}_f{index:06d}",
"frame_path": _relative_frame_path(frame_path, base_dir),
"offset_seconds": offset_seconds,
"timecode": seconds_to_timecode(offset_seconds),
"pts_time": offset_seconds,
"status": "sampled",
"retry_count": 0,
"last_error": None,
}
beijing_time = format_beijing_time(
timeline_start_epoch,
offset_seconds=offset_seconds,
timezone_name=timezone_name,
)
if beijing_time is not None:
record["beijing_time"] = beijing_time
records.append(record)
return records
def _relative_frame_path(frame_path: Path, base_dir: Path) -> str:
resolved = frame_path.expanduser().resolve(strict=False)
try:
return resolved.relative_to(base_dir).as_posix()
except ValueError:
return resolved.as_posix()