feat: use lossless FFV1 and PCM for analysis clips
This commit is contained in:
1 parent
0ba475ac87
commit
13c60a8d48
2 files changed
+245
-8
No files matched your search
+22
-7
@@ -23,6 +23,22 @@ for input_file in inputs:
|
||||
DURATION = 90 # 1.5 minutes in seconds
|
||||
OUT_DIR = os.path.join(os.path.dirname(os.path.abspath(__file__)), "extracted")
|
||||
|
||||
# ─── Analysis-friendly codecs (NOT GPU) ───
|
||||
# Video: FFV1 (lossless, intra-only) in MKV. Every frame stands alone, no
|
||||
# P/B-frame prediction, no blocking artifacts -> exact frames for similarity
|
||||
# (SSIM/pHash/features) + fast random access. Decoded with -pix_fmt yuv444p
|
||||
# to avoid 4:2:0 chroma-subsampling noise.
|
||||
# Audio: PCM float32 WAV, 48 kHz mono. Bit-exact waveform preserves phase for
|
||||
# cross-correlation / GCC-PHAT. Never MP3/AAC/Opus here (MDCT + padding
|
||||
# smears transients and shifts correlation peaks). FLAC is the only
|
||||
# acceptable compressed alternative (lossless).
|
||||
# GPU (RX 7900 XTX via VAAPI/AMF: h264_vaapi/hevc_vaapi/h264_amf): deliberately
|
||||
# NOT used. Those encoders are lossy delivery codecs, lower quality per bit,
|
||||
# inter-frame only, and FFV1/PCM/ProRes/DNxHR have no GPU implementation.
|
||||
# GPU only makes sense for preview proxies, not for measurement. CPU encode
|
||||
# of 90 s clips is fast enough and bit-exact.
|
||||
VIDEO_CODEC = ["-c:v", "ffv1", "-level", "3", "-pix_fmt", "yuv444p"]
|
||||
AUDIO_CODEC = ["-c:a", "pcm_f32le", "-ar", "48000", "-ac", "1"]
|
||||
# ─── Check ffmpeg ───
|
||||
if shutil.which(f"ffmpeg") is None:
|
||||
sys.exit(f"ERROR: 'ffmpeg' not found on PATH. Install it and try again.")
|
||||
@@ -34,22 +50,22 @@ for INPUT_FILE in INPUT_FILES:
|
||||
|
||||
# ─── Derive output filenames ───
|
||||
stem = os.path.splitext(os.path.basename(INPUT_FILE))[0]
|
||||
video_out = os.path.join(OUT_DIR, f"{stem}_video.mkv")
|
||||
audio_out = os.path.join(OUT_DIR, f"{stem}_audio.mp3")
|
||||
video_out = os.path.join(OUT_DIR, f"{stem}_video.mkv") # FFV1
|
||||
audio_out = os.path.join(OUT_DIR, f"{stem}_audio.wav") # PCM f32
|
||||
|
||||
print(f"Input : {INPUT_FILE}")
|
||||
print(f"Video → {video_out}")
|
||||
print(f"Audio → {audio_out}")
|
||||
print(f"-" * 50)
|
||||
|
||||
# ─── Extract video-only (first 90s, no audio) ───
|
||||
# ─── Extract video-only (first 90s, no audio, CPU FFV1 re-encode) ───
|
||||
cmd_video = [
|
||||
"ffmpeg",
|
||||
"-y", # overwrite output
|
||||
"-i", INPUT_FILE,
|
||||
"-t", str(DURATION),
|
||||
"-an", # no audio
|
||||
"-c:v", "copy", # copy video stream (no re-encode = fast + lossless)
|
||||
*VIDEO_CODEC, # ffv1 lossless intra-only, CPU (no GPU equiv.)
|
||||
video_out
|
||||
]
|
||||
print(f"[video: {stem}] running ffmpeg…")
|
||||
@@ -58,15 +74,14 @@ for INPUT_FILE in INPUT_FILES:
|
||||
sys.exit(f"ffmpeg (video) failed:\n{r.stderr}")
|
||||
print(f"[video: {stem}] done ✔")
|
||||
|
||||
# ─── Extract audio-only (first 90s, no video) ───
|
||||
# ─── Extract audio-only (first 90s, no video, CPU PCM re-encode) ───
|
||||
cmd_audio = [
|
||||
"ffmpeg",
|
||||
"-y",
|
||||
"-i", INPUT_FILE,
|
||||
"-t", str(DURATION),
|
||||
"-vn", # no video
|
||||
"-c:a", "libmp3lame",
|
||||
"-b:a", "192k", # 192 kbps
|
||||
*AUDIO_CODEC, # pcm_f32le 48kHz mono, CPU (no GPU equiv.)
|
||||
audio_out
|
||||
]
|
||||
print(f"[audio: {stem}] running ffmpeg…")
|
||||
|
||||
Reference in new issue
Block a user