File size: 3,950 Bytes
8e7f21b
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
"""
Build speech segments from transcript, removing silences >= 0.3s and uh/um fillers.
Then execute the ffmpeg trim+concat cut, scaling 4K → 1080p with dense keyframes.
"""
import json, subprocess, sys
from pathlib import Path

TRANSCRIPT = Path(r"D:\PromptEngineer48\In-Progress\P11-Editor\edit\transcripts\Mem0_1.json")
SOURCE     = Path(r"D:\PromptEngineer48\In-Progress\P11-Editor\Mem0_1.mp4")
OUT_BASE   = Path(r"D:\PromptEngineer48\In-Progress\P11-Editor\edit\hf\base_cut.mp4")

THRESHOLD = 0.30   # gaps >= this get cut
PAD       = 0.08   # 80ms padding around each speech segment
FADE_MS   = 30     # ms audio fade at each edge to prevent pops

FILLERS = {"uh", "um"}

data  = json.load(open(TRANSCRIPT, encoding="utf-8"))
words = [w for w in data["words"] if w.get("type") == "word"]

# Remove filler words
clean = [w for w in words if w["text"].strip().lower().rstrip(",.") not in FILLERS]

# Build speech segments by merging words within THRESHOLD
segs = []
s = e = None
for w in clean:
    if s is None:
        s, e = w["start"], w["end"]
    elif w["start"] - e <= THRESHOLD:
        e = w["end"]
    else:
        segs.append((max(0, s - PAD), e + PAD))
        s, e = w["start"], w["end"]
if s is not None:
    segs.append((max(0, s - PAD), e + PAD))

# Clamp and clip overlapping edges
VIDEO_DUR = 805.5
clamped = []
for a, b in segs:
    a = round(max(0.0, a), 4)
    b = round(min(VIDEO_DUR, b), 4)
    if clamped and a < clamped[-1][1]:
        a = clamped[-1][1]   # no overlap
    if b > a:
        clamped.append((a, b))
segs = clamped

total_dur = sum(b - a for a, b in segs)
print(f"Segments: {len(segs)}")
print(f"Total kept: {total_dur:.1f}s = {total_dur/60:.1f}min  (cut {VIDEO_DUR - total_dur:.1f}s)")
for i, (a, b) in enumerate(segs):
    print(f"  [{i:03d}] {a:.3f} -> {b:.3f}  ({b-a:.2f}s)")

# Build ffmpeg filter_complex with trim + concat
# Use select/aselect in PASSES to avoid OOM with 216 between() calls.
# Split segs into 4 time buckets, run one ffmpeg per bucket, concat results.
PASSES = 4
source_dur = VIDEO_DUR
bucket_dur = source_dur / PASSES
tmp_dir = OUT_BASE.parent / "tmp_passes"
tmp_dir.mkdir(exist_ok=True)

tmp_files = []
for p in range(PASSES):
    t_lo = p * bucket_dur
    t_hi = (p + 1) * bucket_dur
    bucket_segs = [(a, b) for a, b in segs if b > t_lo and a < t_hi]
    if not bucket_segs:
        continue
    expr = "+".join(f"between(t,{a},{b})" for a, b in bucket_segs)
    fc = (
        f"[0:v]select='{expr}',setpts=N/30/TB,scale=1920:1080[outv];"
        f"[0:a]aselect='{expr}',asetpts=N/SR/TB[outa]"
    )
    fc_f = tmp_dir / f"fc_pass{p}.txt"
    fc_f.write_text(fc, encoding="utf-8")
    tmp_out = tmp_dir / f"pass{p}.mp4"
    tmp_files.append(tmp_out)
    print(f"Pass {p}: {len(bucket_segs)} segs, source {t_lo:.0f}-{t_hi:.0f}s -> {tmp_out.name}")
    r = subprocess.run([
        "ffmpeg", "-y", "-i", str(SOURCE),
        "-/filter_complex", str(fc_f),
        "-map", "[outv]", "-map", "[outa]",
        "-c:v", "libx264", "-crf", "18", "-preset", "fast",
        "-g", "30", "-keyint_min", "30",
        "-c:a", "aac", "-b:a", "192k",
        str(tmp_out)
    ], capture_output=True, text=True)
    if r.returncode != 0:
        print(f"Pass {p} STDERR:", r.stderr[-2000:])
        sys.exit(1)
    print(f"  Pass {p} done")

# Concat pass outputs with concat demuxer
concat_list = tmp_dir / "concat.txt"
concat_list.write_text(
    "\n".join(f"file '{f.as_posix()}'" for f in tmp_files),
    encoding="utf-8"
)
print(f"\nConcatenating {len(tmp_files)} passes -> {OUT_BASE}")
r = subprocess.run([
    "ffmpeg", "-y", "-f", "concat", "-safe", "0",
    "-i", str(concat_list),
    "-c:v", "libx264", "-crf", "18", "-preset", "fast",
    "-g", "30", "-keyint_min", "30",
    "-c:a", "aac", "-b:a", "192k",
    str(OUT_BASE)
], capture_output=True, text=True)
if r.returncode != 0:
    print("Concat STDERR:", r.stderr[-2000:])
    sys.exit(1)
print(f"Done! -> {OUT_BASE}")