feat: add config-driven extraction and audio sync tooling
This commit is contained in:
1 parent
476b2543d1
commit
3a18a8b2c2
5 files changed
+798
-10
No files matched your search
+55
-10
@@ -12,16 +12,53 @@ import os
|
||||
import sys
|
||||
import shutil
|
||||
|
||||
# ─── Hardcoded input (relative to this script's directory) ───
|
||||
inputs = [
|
||||
"/home/honney/Videos/Drachenzähmen/Drachenzaehmen.mp4",
|
||||
"/home/honney/Videos/Drachenzähmen/How to Train Your Dragon.mkv"
|
||||
]
|
||||
# ─── Input / config (config.toml is base config, fallback to hardcoded) ───
|
||||
CONFIG_PATH = os.path.join(os.path.dirname(os.path.abspath(__file__)), "config.toml")
|
||||
_cfg_inputs = None
|
||||
_cfg_duration = 90
|
||||
_cfg_start = 0.0
|
||||
_cfg_out_dir = os.path.join(os.path.dirname(os.path.abspath(__file__)), "extracted")
|
||||
_cfg_target_fps = "24000/1001"
|
||||
_cfg_eps = 0.02
|
||||
try:
|
||||
try:
|
||||
import tomllib # py3.11+
|
||||
except ModuleNotFoundError:
|
||||
import tomli as tomllib # type: ignore
|
||||
if os.path.exists(CONFIG_PATH):
|
||||
with open(CONFIG_PATH, "rb") as _f:
|
||||
_cfg = tomllib.load(_f)
|
||||
_ex = _cfg.get("extract", {})
|
||||
if _ex.get("file_a") or _ex.get("file_b"):
|
||||
_cfg_inputs = [p for p in [_ex.get("file_a"), _ex.get("file_b")] if p]
|
||||
_cfg_duration = int(_ex.get("duration", _cfg_duration))
|
||||
_cfg_start = float(_ex.get("start", _cfg_start))
|
||||
_cfg_out_dir = _ex.get("out_dir", _cfg_out_dir)
|
||||
if _ex.get("target_fps"):
|
||||
_cfg_target_fps = str(_ex["target_fps"])
|
||||
if _ex.get("target_fps_eps") is not None:
|
||||
try:
|
||||
_cfg_eps = float(_ex["target_fps_eps"])
|
||||
except Exception:
|
||||
pass
|
||||
if _cfg_inputs:
|
||||
print(f"[config] loaded {CONFIG_PATH}: duration={_cfg_duration}s start={_cfg_start}s target_fps={_cfg_target_fps}")
|
||||
except Exception as _e:
|
||||
print(f"[config] warn: failed to load {CONFIG_PATH}: {_e}", file=sys.stderr)
|
||||
|
||||
if _cfg_inputs is not None:
|
||||
inputs = _cfg_inputs
|
||||
else:
|
||||
inputs = [
|
||||
"/home/honney/Videos/Drachenzähmen/Drachenzaehmen.mp4",
|
||||
"/home/honney/Videos/Drachenzähmen/How to Train Your Dragon.mkv"
|
||||
]
|
||||
INPUT_FILES = []
|
||||
for input_file in inputs:
|
||||
INPUT_FILES.append(os.path.join(os.path.dirname(os.path.abspath(__file__)), input_file))
|
||||
DURATION = 90 # 1.5 minutes in seconds
|
||||
OUT_DIR = os.path.join(os.path.dirname(os.path.abspath(__file__)), "extracted")
|
||||
DURATION = _cfg_duration
|
||||
START_SEC = _cfg_start # for ffmpeg -ss (0 = file start)
|
||||
OUT_DIR = os.path.join(os.path.dirname(os.path.abspath(__file__)), _cfg_out_dir) if not os.path.isabs(_cfg_out_dir) else _cfg_out_dir
|
||||
|
||||
# ─── Analysis-friendly codecs (NOT GPU) ───
|
||||
# Video: FFV1 (lossless, intra-only) in MKV. Every frame stands alone, no
|
||||
@@ -39,9 +76,14 @@ OUT_DIR = os.path.join(os.path.dirname(os.path.abspath(__file__)), "extracted
|
||||
# of 90 s clips is fast enough and bit-exact.
|
||||
VIDEO_CODEC_BASE = ["-c:v", "ffv1", "-level", "3", "-pix_fmt", "yuv444p"]
|
||||
AUDIO_CODEC = ["-c:a", "pcm_f32le", "-ar", "48000", "-ac", "1"]
|
||||
TARGET_FPS = "24000/1001" # Blu-ray film = 23.976023... (shown as 23.98)
|
||||
TARGET_FPS_FLOAT = 24000 / 1001
|
||||
FPS_EPS = 0.02 # tolerance for float comparison
|
||||
# target fps may be overridden via config.toml
|
||||
TARGET_FPS = _cfg_target_fps # default "24000/1001"
|
||||
try:
|
||||
_n, _d = TARGET_FPS.split("/") if "/" in TARGET_FPS else (TARGET_FPS, "1")
|
||||
TARGET_FPS_FLOAT = float(_n) / float(_d)
|
||||
except Exception:
|
||||
TARGET_FPS_FLOAT = 24000 / 1001
|
||||
FPS_EPS = _cfg_eps # tolerance for float comparison
|
||||
|
||||
def _parse_rate(s: str) -> float | None:
|
||||
s = s.strip()
|
||||
@@ -135,9 +177,11 @@ for INPUT_FILE in INPUT_FILES:
|
||||
if not needs_fps:
|
||||
video_codec = VIDEO_CODEC_BASE + ["-vf", f"fps={TARGET_FPS}:round=near", "-fps_mode", "cfr"]
|
||||
|
||||
ss_args = ["-ss", str(START_SEC)] if START_SEC and START_SEC != 0 else []
|
||||
cmd_video = [
|
||||
"ffmpeg",
|
||||
"-y", # overwrite output
|
||||
*ss_args, # seek before -i (fast, frame-accurate with re-encode)
|
||||
"-i", INPUT_FILE,
|
||||
"-t", str(DURATION),
|
||||
"-an", # no audio
|
||||
@@ -154,6 +198,7 @@ for INPUT_FILE in INPUT_FILES:
|
||||
cmd_audio = [
|
||||
"ffmpeg",
|
||||
"-y",
|
||||
*ss_args,
|
||||
"-i", INPUT_FILE,
|
||||
"-t", str(DURATION),
|
||||
"-vn", # no video
|
||||
|
||||
Reference in new issue
Block a user